Statistics
| Branch: | Revision:

root / audio / coreaudio.c @ 6276c767

History | View | Annotate | Download (15.3 kB)

1 1d14ffa9 bellard
/*
2 1d14ffa9 bellard
 * QEMU OS X CoreAudio audio driver
3 1d14ffa9 bellard
 *
4 1d14ffa9 bellard
 * Copyright (c) 2005 Mike Kronenberg
5 1d14ffa9 bellard
 *
6 1d14ffa9 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 1d14ffa9 bellard
 * of this software and associated documentation files (the "Software"), to deal
8 1d14ffa9 bellard
 * in the Software without restriction, including without limitation the rights
9 1d14ffa9 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 1d14ffa9 bellard
 * copies of the Software, and to permit persons to whom the Software is
11 1d14ffa9 bellard
 * furnished to do so, subject to the following conditions:
12 1d14ffa9 bellard
 *
13 1d14ffa9 bellard
 * The above copyright notice and this permission notice shall be included in
14 1d14ffa9 bellard
 * all copies or substantial portions of the Software.
15 1d14ffa9 bellard
 *
16 1d14ffa9 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 1d14ffa9 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 1d14ffa9 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 1d14ffa9 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 1d14ffa9 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 1d14ffa9 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 1d14ffa9 bellard
 * THE SOFTWARE.
23 1d14ffa9 bellard
 */
24 1d14ffa9 bellard
25 1d14ffa9 bellard
#include <CoreAudio/CoreAudio.h>
26 1d14ffa9 bellard
#include <string.h>             /* strerror */
27 1d14ffa9 bellard
#include <pthread.h>            /* pthread_X */
28 1d14ffa9 bellard
29 1d14ffa9 bellard
#include "vl.h"
30 1d14ffa9 bellard
31 1d14ffa9 bellard
#define AUDIO_CAP "coreaudio"
32 1d14ffa9 bellard
#include "audio_int.h"
33 1d14ffa9 bellard
34 1d14ffa9 bellard
struct {
35 1d14ffa9 bellard
    int buffer_frames;
36 e59c1139 bellard
    int nbuffers;
37 5e941d4b bellard
    int isAtexit;
38 1d14ffa9 bellard
} conf = {
39 5e941d4b bellard
    .buffer_frames = 512,
40 e59c1139 bellard
    .nbuffers = 4,
41 5e941d4b bellard
    .isAtexit = 0
42 1d14ffa9 bellard
};
43 1d14ffa9 bellard
44 1d14ffa9 bellard
typedef struct coreaudioVoiceOut {
45 1d14ffa9 bellard
    HWVoiceOut hw;
46 1d14ffa9 bellard
    pthread_mutex_t mutex;
47 5e941d4b bellard
    int isAtexit;
48 1d14ffa9 bellard
    AudioDeviceID outputDeviceID;
49 5e941d4b bellard
    UInt32 audioDevicePropertyBufferFrameSize;
50 1d14ffa9 bellard
    AudioStreamBasicDescription outputStreamBasicDescription;
51 1d14ffa9 bellard
    int live;
52 1d14ffa9 bellard
    int decr;
53 1d14ffa9 bellard
    int rpos;
54 1d14ffa9 bellard
} coreaudioVoiceOut;
55 1d14ffa9 bellard
56 1d14ffa9 bellard
static void coreaudio_logstatus (OSStatus status)
57 1d14ffa9 bellard
{
58 1d14ffa9 bellard
    char *str = "BUG";
59 1d14ffa9 bellard
60 1d14ffa9 bellard
    switch(status) {
61 1d14ffa9 bellard
    case kAudioHardwareNoError:
62 1d14ffa9 bellard
        str = "kAudioHardwareNoError";
63 1d14ffa9 bellard
        break;
64 1d14ffa9 bellard
65 1d14ffa9 bellard
    case kAudioHardwareNotRunningError:
66 1d14ffa9 bellard
        str = "kAudioHardwareNotRunningError";
67 1d14ffa9 bellard
        break;
68 1d14ffa9 bellard
69 1d14ffa9 bellard
    case kAudioHardwareUnspecifiedError:
70 1d14ffa9 bellard
        str = "kAudioHardwareUnspecifiedError";
71 1d14ffa9 bellard
        break;
72 1d14ffa9 bellard
73 1d14ffa9 bellard
    case kAudioHardwareUnknownPropertyError:
74 1d14ffa9 bellard
        str = "kAudioHardwareUnknownPropertyError";
75 1d14ffa9 bellard
        break;
76 1d14ffa9 bellard
77 1d14ffa9 bellard
    case kAudioHardwareBadPropertySizeError:
78 1d14ffa9 bellard
        str = "kAudioHardwareBadPropertySizeError";
79 1d14ffa9 bellard
        break;
80 1d14ffa9 bellard
81 1d14ffa9 bellard
    case kAudioHardwareIllegalOperationError:
82 1d14ffa9 bellard
        str = "kAudioHardwareIllegalOperationError";
83 1d14ffa9 bellard
        break;
84 1d14ffa9 bellard
85 1d14ffa9 bellard
    case kAudioHardwareBadDeviceError:
86 1d14ffa9 bellard
        str = "kAudioHardwareBadDeviceError";
87 1d14ffa9 bellard
        break;
88 1d14ffa9 bellard
89 1d14ffa9 bellard
    case kAudioHardwareBadStreamError:
90 1d14ffa9 bellard
        str = "kAudioHardwareBadStreamError";
91 1d14ffa9 bellard
        break;
92 1d14ffa9 bellard
93 1d14ffa9 bellard
    case kAudioHardwareUnsupportedOperationError:
94 1d14ffa9 bellard
        str = "kAudioHardwareUnsupportedOperationError";
95 1d14ffa9 bellard
        break;
96 1d14ffa9 bellard
97 1d14ffa9 bellard
    case kAudioDeviceUnsupportedFormatError:
98 1d14ffa9 bellard
        str = "kAudioDeviceUnsupportedFormatError";
99 1d14ffa9 bellard
        break;
100 1d14ffa9 bellard
101 1d14ffa9 bellard
    case kAudioDevicePermissionsError:
102 1d14ffa9 bellard
        str = "kAudioDevicePermissionsError";
103 1d14ffa9 bellard
        break;
104 1d14ffa9 bellard
105 1d14ffa9 bellard
    default:
106 1d14ffa9 bellard
        AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
107 1d14ffa9 bellard
        return;
108 1d14ffa9 bellard
    }
109 1d14ffa9 bellard
110 1d14ffa9 bellard
    AUD_log (AUDIO_CAP, "Reason: %s\n", str);
111 1d14ffa9 bellard
}
112 1d14ffa9 bellard
113 1d14ffa9 bellard
static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
114 1d14ffa9 bellard
    OSStatus status,
115 1d14ffa9 bellard
    const char *fmt,
116 1d14ffa9 bellard
    ...
117 1d14ffa9 bellard
    )
118 1d14ffa9 bellard
{
119 1d14ffa9 bellard
    va_list ap;
120 1d14ffa9 bellard
121 1d14ffa9 bellard
    va_start (ap, fmt);
122 1d14ffa9 bellard
    AUD_log (AUDIO_CAP, fmt, ap);
123 1d14ffa9 bellard
    va_end (ap);
124 1d14ffa9 bellard
125 1d14ffa9 bellard
    coreaudio_logstatus (status);
126 1d14ffa9 bellard
}
127 1d14ffa9 bellard
128 1d14ffa9 bellard
static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
129 1d14ffa9 bellard
    OSStatus status,
130 1d14ffa9 bellard
    const char *typ,
131 1d14ffa9 bellard
    const char *fmt,
132 1d14ffa9 bellard
    ...
133 1d14ffa9 bellard
    )
134 1d14ffa9 bellard
{
135 1d14ffa9 bellard
    va_list ap;
136 1d14ffa9 bellard
137 c0fe3827 bellard
    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
138 1d14ffa9 bellard
139 1d14ffa9 bellard
    va_start (ap, fmt);
140 1d14ffa9 bellard
    AUD_vlog (AUDIO_CAP, fmt, ap);
141 1d14ffa9 bellard
    va_end (ap);
142 1d14ffa9 bellard
143 1d14ffa9 bellard
    coreaudio_logstatus (status);
144 1d14ffa9 bellard
}
145 1d14ffa9 bellard
146 5e941d4b bellard
static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
147 5e941d4b bellard
{
148 5e941d4b bellard
    OSStatus status;
149 5e941d4b bellard
    UInt32 result = 0;
150 5e941d4b bellard
    UInt32 propertySize = sizeof(outputDeviceID);
151 5e941d4b bellard
    status = AudioDeviceGetProperty(
152 5e941d4b bellard
        outputDeviceID, 0, 0,
153 5e941d4b bellard
        kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
154 5e941d4b bellard
    if (status != kAudioHardwareNoError) {
155 5e941d4b bellard
        coreaudio_logerr(status,
156 5e941d4b bellard
                         "Could not determine whether Device is playing\n");
157 5e941d4b bellard
    }
158 5e941d4b bellard
    return result;
159 5e941d4b bellard
}
160 5e941d4b bellard
161 5e941d4b bellard
static void coreaudio_atexit (void)
162 5e941d4b bellard
{
163 5e941d4b bellard
    conf.isAtexit = 1;
164 5e941d4b bellard
}
165 5e941d4b bellard
166 1d14ffa9 bellard
static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
167 1d14ffa9 bellard
{
168 1d14ffa9 bellard
    int err;
169 1d14ffa9 bellard
170 1d14ffa9 bellard
    err = pthread_mutex_lock (&core->mutex);
171 1d14ffa9 bellard
    if (err) {
172 c0fe3827 bellard
        dolog ("Could not lock voice for %s\nReason: %s\n",
173 1d14ffa9 bellard
               fn_name, strerror (err));
174 1d14ffa9 bellard
        return -1;
175 1d14ffa9 bellard
    }
176 1d14ffa9 bellard
    return 0;
177 1d14ffa9 bellard
}
178 1d14ffa9 bellard
179 1d14ffa9 bellard
static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
180 1d14ffa9 bellard
{
181 1d14ffa9 bellard
    int err;
182 1d14ffa9 bellard
183 1d14ffa9 bellard
    err = pthread_mutex_unlock (&core->mutex);
184 1d14ffa9 bellard
    if (err) {
185 c0fe3827 bellard
        dolog ("Could not unlock voice for %s\nReason: %s\n",
186 1d14ffa9 bellard
               fn_name, strerror (err));
187 1d14ffa9 bellard
        return -1;
188 1d14ffa9 bellard
    }
189 1d14ffa9 bellard
    return 0;
190 1d14ffa9 bellard
}
191 1d14ffa9 bellard
192 1d14ffa9 bellard
static int coreaudio_run_out (HWVoiceOut *hw)
193 1d14ffa9 bellard
{
194 1d14ffa9 bellard
    int live, decr;
195 1d14ffa9 bellard
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
196 1d14ffa9 bellard
197 1d14ffa9 bellard
    if (coreaudio_lock (core, "coreaudio_run_out")) {
198 1d14ffa9 bellard
        return 0;
199 1d14ffa9 bellard
    }
200 1d14ffa9 bellard
201 1d14ffa9 bellard
    live = audio_pcm_hw_get_live_out (hw);
202 1d14ffa9 bellard
203 1d14ffa9 bellard
    if (core->decr > live) {
204 1d14ffa9 bellard
        ldebug ("core->decr %d live %d core->live %d\n",
205 1d14ffa9 bellard
                core->decr,
206 1d14ffa9 bellard
                live,
207 1d14ffa9 bellard
                core->live);
208 1d14ffa9 bellard
    }
209 1d14ffa9 bellard
210 1d14ffa9 bellard
    decr = audio_MIN (core->decr, live);
211 1d14ffa9 bellard
    core->decr -= decr;
212 1d14ffa9 bellard
213 1d14ffa9 bellard
    core->live = live - decr;
214 1d14ffa9 bellard
    hw->rpos = core->rpos;
215 1d14ffa9 bellard
216 1d14ffa9 bellard
    coreaudio_unlock (core, "coreaudio_run_out");
217 1d14ffa9 bellard
    return decr;
218 1d14ffa9 bellard
}
219 1d14ffa9 bellard
220 1d14ffa9 bellard
/* callback to feed audiooutput buffer */
221 1d14ffa9 bellard
static OSStatus audioDeviceIOProc(
222 1d14ffa9 bellard
    AudioDeviceID inDevice,
223 1d14ffa9 bellard
    const AudioTimeStamp* inNow,
224 1d14ffa9 bellard
    const AudioBufferList* inInputData,
225 1d14ffa9 bellard
    const AudioTimeStamp* inInputTime,
226 1d14ffa9 bellard
    AudioBufferList* outOutputData,
227 1d14ffa9 bellard
    const AudioTimeStamp* inOutputTime,
228 1d14ffa9 bellard
    void* hwptr)
229 1d14ffa9 bellard
{
230 5e941d4b bellard
    UInt32 frame, frameCount;
231 1d14ffa9 bellard
    float *out = outOutputData->mBuffers[0].mData;
232 1d14ffa9 bellard
    HWVoiceOut *hw = hwptr;
233 1d14ffa9 bellard
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
234 1d14ffa9 bellard
    int rpos, live;
235 1d14ffa9 bellard
    st_sample_t *src;
236 1d14ffa9 bellard
#ifndef FLOAT_MIXENG
237 1d14ffa9 bellard
#ifdef RECIPROCAL
238 1d14ffa9 bellard
    const float scale = 1.f / UINT_MAX;
239 1d14ffa9 bellard
#else
240 1d14ffa9 bellard
    const float scale = UINT_MAX;
241 1d14ffa9 bellard
#endif
242 1d14ffa9 bellard
#endif
243 1d14ffa9 bellard
244 1d14ffa9 bellard
    if (coreaudio_lock (core, "audioDeviceIOProc")) {
245 1d14ffa9 bellard
        inInputTime = 0;
246 1d14ffa9 bellard
        return 0;
247 1d14ffa9 bellard
    }
248 1d14ffa9 bellard
249 5e941d4b bellard
    frameCount = core->audioDevicePropertyBufferFrameSize;
250 1d14ffa9 bellard
    live = core->live;
251 1d14ffa9 bellard
252 1d14ffa9 bellard
    /* if there are not enough samples, set signal and return */
253 1d14ffa9 bellard
    if (live < frameCount) {
254 1d14ffa9 bellard
        inInputTime = 0;
255 1d14ffa9 bellard
        coreaudio_unlock (core, "audioDeviceIOProc(empty)");
256 1d14ffa9 bellard
        return 0;
257 1d14ffa9 bellard
    }
258 1d14ffa9 bellard
259 1d14ffa9 bellard
    rpos = core->rpos;
260 1d14ffa9 bellard
    src = hw->mix_buf + rpos;
261 1d14ffa9 bellard
262 1d14ffa9 bellard
    /* fill buffer */
263 1d14ffa9 bellard
    for (frame = 0; frame < frameCount; frame++) {
264 1d14ffa9 bellard
#ifdef FLOAT_MIXENG
265 1d14ffa9 bellard
        *out++ = src[frame].l; /* left channel */
266 1d14ffa9 bellard
        *out++ = src[frame].r; /* right channel */
267 1d14ffa9 bellard
#else
268 1d14ffa9 bellard
#ifdef RECIPROCAL
269 1d14ffa9 bellard
        *out++ = src[frame].l * scale; /* left channel */
270 1d14ffa9 bellard
        *out++ = src[frame].r * scale; /* right channel */
271 1d14ffa9 bellard
#else
272 1d14ffa9 bellard
        *out++ = src[frame].l / scale; /* left channel */
273 1d14ffa9 bellard
        *out++ = src[frame].r / scale; /* right channel */
274 1d14ffa9 bellard
#endif
275 1d14ffa9 bellard
#endif
276 1d14ffa9 bellard
    }
277 1d14ffa9 bellard
278 1d14ffa9 bellard
    rpos = (rpos + frameCount) % hw->samples;
279 5e941d4b bellard
    core->decr += frameCount;
280 1d14ffa9 bellard
    core->rpos = rpos;
281 1d14ffa9 bellard
282 1d14ffa9 bellard
    coreaudio_unlock (core, "audioDeviceIOProc");
283 1d14ffa9 bellard
    return 0;
284 1d14ffa9 bellard
}
285 1d14ffa9 bellard
286 1d14ffa9 bellard
static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
287 1d14ffa9 bellard
{
288 1d14ffa9 bellard
    return audio_pcm_sw_write (sw, buf, len);
289 1d14ffa9 bellard
}
290 1d14ffa9 bellard
291 c0fe3827 bellard
static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
292 1d14ffa9 bellard
{
293 1d14ffa9 bellard
    OSStatus status;
294 1d14ffa9 bellard
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
295 1d14ffa9 bellard
    UInt32 propertySize;
296 1d14ffa9 bellard
    int err;
297 5e941d4b bellard
    const char *typ = "playback";
298 5e941d4b bellard
    AudioValueRange frameRange;
299 1d14ffa9 bellard
300 1d14ffa9 bellard
    /* create mutex */
301 1d14ffa9 bellard
    err = pthread_mutex_init(&core->mutex, NULL);
302 1d14ffa9 bellard
    if (err) {
303 c0fe3827 bellard
        dolog("Could not create mutex\nReason: %s\n", strerror (err));
304 1d14ffa9 bellard
        return -1;
305 1d14ffa9 bellard
    }
306 1d14ffa9 bellard
307 d929eba5 bellard
    audio_pcm_init_info (&hw->info, as);
308 1d14ffa9 bellard
309 1d14ffa9 bellard
    /* open default output device */
310 1d14ffa9 bellard
    propertySize = sizeof(core->outputDeviceID);
311 1d14ffa9 bellard
    status = AudioHardwareGetProperty(
312 1d14ffa9 bellard
        kAudioHardwarePropertyDefaultOutputDevice,
313 1d14ffa9 bellard
        &propertySize,
314 1d14ffa9 bellard
        &core->outputDeviceID);
315 1d14ffa9 bellard
    if (status != kAudioHardwareNoError) {
316 1d14ffa9 bellard
        coreaudio_logerr2 (status, typ,
317 c0fe3827 bellard
                           "Could not get default output Device\n");
318 1d14ffa9 bellard
        return -1;
319 1d14ffa9 bellard
    }
320 1d14ffa9 bellard
    if (core->outputDeviceID == kAudioDeviceUnknown) {
321 c0fe3827 bellard
        dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
322 1d14ffa9 bellard
        return -1;
323 1d14ffa9 bellard
    }
324 1d14ffa9 bellard
325 5e941d4b bellard
    /* get minimum and maximum buffer frame sizes */
326 5e941d4b bellard
    propertySize = sizeof(frameRange);
327 5e941d4b bellard
    status = AudioDeviceGetProperty(
328 5e941d4b bellard
        core->outputDeviceID,
329 5e941d4b bellard
        0,
330 5e941d4b bellard
        0,
331 5e941d4b bellard
        kAudioDevicePropertyBufferFrameSizeRange,
332 5e941d4b bellard
        &propertySize,
333 5e941d4b bellard
        &frameRange);
334 5e941d4b bellard
    if (status != kAudioHardwareNoError) {
335 5e941d4b bellard
        coreaudio_logerr2 (status, typ,
336 5e941d4b bellard
                           "Could not get device buffer frame range\n");
337 5e941d4b bellard
        return -1;
338 5e941d4b bellard
    }
339 5e941d4b bellard
340 5e941d4b bellard
    if (frameRange.mMinimum > conf.buffer_frames) {
341 5e941d4b bellard
        core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
342 5e941d4b bellard
        dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
343 5e941d4b bellard
    }
344 5e941d4b bellard
    else if (frameRange.mMaximum < conf.buffer_frames) {
345 5e941d4b bellard
        core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
346 5e941d4b bellard
        dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
347 5e941d4b bellard
    }
348 5e941d4b bellard
    else {
349 5e941d4b bellard
        core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
350 5e941d4b bellard
    }
351 5e941d4b bellard
352 5e941d4b bellard
    /* set Buffer Frame Size */
353 5e941d4b bellard
    propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
354 1d14ffa9 bellard
    status = AudioDeviceSetProperty(
355 1d14ffa9 bellard
        core->outputDeviceID,
356 1d14ffa9 bellard
        NULL,
357 1d14ffa9 bellard
        0,
358 1d14ffa9 bellard
        false,
359 5e941d4b bellard
        kAudioDevicePropertyBufferFrameSize,
360 1d14ffa9 bellard
        propertySize,
361 5e941d4b bellard
        &core->audioDevicePropertyBufferFrameSize);
362 1d14ffa9 bellard
    if (status != kAudioHardwareNoError) {
363 1d14ffa9 bellard
        coreaudio_logerr2 (status, typ,
364 5e941d4b bellard
                           "Could not set device buffer frame size %ld\n",
365 5e941d4b bellard
                           core->audioDevicePropertyBufferFrameSize);
366 1d14ffa9 bellard
        return -1;
367 1d14ffa9 bellard
    }
368 1d14ffa9 bellard
369 5e941d4b bellard
    /* get Buffer Frame Size */
370 5e941d4b bellard
    propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
371 1d14ffa9 bellard
    status = AudioDeviceGetProperty(
372 1d14ffa9 bellard
        core->outputDeviceID,
373 1d14ffa9 bellard
        0,
374 1d14ffa9 bellard
        false,
375 5e941d4b bellard
        kAudioDevicePropertyBufferFrameSize,
376 1d14ffa9 bellard
        &propertySize,
377 5e941d4b bellard
        &core->audioDevicePropertyBufferFrameSize);
378 1d14ffa9 bellard
    if (status != kAudioHardwareNoError) {
379 5e941d4b bellard
        coreaudio_logerr2 (status, typ,
380 5e941d4b bellard
                           "Could not get device buffer frame size\n");
381 1d14ffa9 bellard
        return -1;
382 1d14ffa9 bellard
    }
383 e59c1139 bellard
    hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
384 1d14ffa9 bellard
385 1d14ffa9 bellard
    /* get StreamFormat */
386 1d14ffa9 bellard
    propertySize = sizeof(core->outputStreamBasicDescription);
387 1d14ffa9 bellard
    status = AudioDeviceGetProperty(
388 1d14ffa9 bellard
        core->outputDeviceID,
389 1d14ffa9 bellard
        0,
390 1d14ffa9 bellard
        false,
391 1d14ffa9 bellard
        kAudioDevicePropertyStreamFormat,
392 1d14ffa9 bellard
        &propertySize,
393 1d14ffa9 bellard
        &core->outputStreamBasicDescription);
394 1d14ffa9 bellard
    if (status != kAudioHardwareNoError) {
395 1d14ffa9 bellard
        coreaudio_logerr2 (status, typ,
396 c0fe3827 bellard
                           "Could not get Device Stream properties\n");
397 1d14ffa9 bellard
        core->outputDeviceID = kAudioDeviceUnknown;
398 1d14ffa9 bellard
        return -1;
399 1d14ffa9 bellard
    }
400 1d14ffa9 bellard
401 1d14ffa9 bellard
    /* set Samplerate */
402 5e941d4b bellard
    core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
403 1d14ffa9 bellard
    propertySize = sizeof(core->outputStreamBasicDescription);
404 1d14ffa9 bellard
    status = AudioDeviceSetProperty(
405 1d14ffa9 bellard
        core->outputDeviceID,
406 1d14ffa9 bellard
        0,
407 1d14ffa9 bellard
        0,
408 1d14ffa9 bellard
        0,
409 1d14ffa9 bellard
        kAudioDevicePropertyStreamFormat,
410 1d14ffa9 bellard
        propertySize,
411 1d14ffa9 bellard
        &core->outputStreamBasicDescription);
412 1d14ffa9 bellard
    if (status != kAudioHardwareNoError) {
413 575b5dc4 bellard
        coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
414 575b5dc4 bellard
                           as->freq);
415 1d14ffa9 bellard
        core->outputDeviceID = kAudioDeviceUnknown;
416 1d14ffa9 bellard
        return -1;
417 1d14ffa9 bellard
    }
418 1d14ffa9 bellard
419 1d14ffa9 bellard
    /* set Callback */
420 1d14ffa9 bellard
    status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
421 1d14ffa9 bellard
    if (status != kAudioHardwareNoError) {
422 c0fe3827 bellard
        coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
423 1d14ffa9 bellard
        core->outputDeviceID = kAudioDeviceUnknown;
424 1d14ffa9 bellard
        return -1;
425 1d14ffa9 bellard
    }
426 1d14ffa9 bellard
427 1d14ffa9 bellard
    /* start Playback */
428 5e941d4b bellard
    if (!isPlaying(core->outputDeviceID)) {
429 1d14ffa9 bellard
        status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
430 1d14ffa9 bellard
        if (status != kAudioHardwareNoError) {
431 c0fe3827 bellard
            coreaudio_logerr2 (status, typ, "Could not start playback\n");
432 1d14ffa9 bellard
            AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
433 1d14ffa9 bellard
            core->outputDeviceID = kAudioDeviceUnknown;
434 1d14ffa9 bellard
            return -1;
435 1d14ffa9 bellard
        }
436 1d14ffa9 bellard
    }
437 1d14ffa9 bellard
438 1d14ffa9 bellard
    return 0;
439 1d14ffa9 bellard
}
440 1d14ffa9 bellard
441 1d14ffa9 bellard
static void coreaudio_fini_out (HWVoiceOut *hw)
442 1d14ffa9 bellard
{
443 1d14ffa9 bellard
    OSStatus status;
444 1d14ffa9 bellard
    int err;
445 1d14ffa9 bellard
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
446 1d14ffa9 bellard
447 5e941d4b bellard
    if (!conf.isAtexit) {
448 5e941d4b bellard
        /* stop playback */
449 5e941d4b bellard
        if (isPlaying(core->outputDeviceID)) {
450 5e941d4b bellard
            status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
451 5e941d4b bellard
            if (status != kAudioHardwareNoError) {
452 5e941d4b bellard
                coreaudio_logerr (status, "Could not stop playback\n");
453 5e941d4b bellard
            }
454 1d14ffa9 bellard
        }
455 1d14ffa9 bellard
456 5e941d4b bellard
        /* remove callback */
457 5e941d4b bellard
        status = AudioDeviceRemoveIOProc(core->outputDeviceID,
458 5e941d4b bellard
                                         audioDeviceIOProc);
459 5e941d4b bellard
        if (status != kAudioHardwareNoError) {
460 5e941d4b bellard
            coreaudio_logerr (status, "Could not remove IOProc\n");
461 5e941d4b bellard
        }
462 1d14ffa9 bellard
    }
463 1d14ffa9 bellard
    core->outputDeviceID = kAudioDeviceUnknown;
464 1d14ffa9 bellard
465 1d14ffa9 bellard
    /* destroy mutex */
466 1d14ffa9 bellard
    err = pthread_mutex_destroy(&core->mutex);
467 1d14ffa9 bellard
    if (err) {
468 c0fe3827 bellard
        dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
469 1d14ffa9 bellard
    }
470 1d14ffa9 bellard
}
471 1d14ffa9 bellard
472 1d14ffa9 bellard
static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
473 1d14ffa9 bellard
{
474 1d14ffa9 bellard
    OSStatus status;
475 1d14ffa9 bellard
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
476 1d14ffa9 bellard
477 1d14ffa9 bellard
    switch (cmd) {
478 1d14ffa9 bellard
    case VOICE_ENABLE:
479 1d14ffa9 bellard
        /* start playback */
480 5e941d4b bellard
        if (!isPlaying(core->outputDeviceID)) {
481 1d14ffa9 bellard
            status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
482 1d14ffa9 bellard
            if (status != kAudioHardwareNoError) {
483 5e941d4b bellard
                coreaudio_logerr (status, "Could not resume playback\n");
484 1d14ffa9 bellard
            }
485 1d14ffa9 bellard
        }
486 1d14ffa9 bellard
        break;
487 1d14ffa9 bellard
488 1d14ffa9 bellard
    case VOICE_DISABLE:
489 1d14ffa9 bellard
        /* stop playback */
490 5e941d4b bellard
        if (!conf.isAtexit) {
491 5e941d4b bellard
            if (isPlaying(core->outputDeviceID)) {
492 5e941d4b bellard
                status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
493 5e941d4b bellard
                if (status != kAudioHardwareNoError) {
494 5e941d4b bellard
                    coreaudio_logerr (status, "Could not pause playback\n");
495 5e941d4b bellard
                }
496 1d14ffa9 bellard
            }
497 1d14ffa9 bellard
        }
498 1d14ffa9 bellard
        break;
499 1d14ffa9 bellard
    }
500 1d14ffa9 bellard
    return 0;
501 1d14ffa9 bellard
}
502 1d14ffa9 bellard
503 1d14ffa9 bellard
static void *coreaudio_audio_init (void)
504 1d14ffa9 bellard
{
505 5e941d4b bellard
    atexit(coreaudio_atexit);
506 1d14ffa9 bellard
    return &coreaudio_audio_init;
507 1d14ffa9 bellard
}
508 1d14ffa9 bellard
509 1d14ffa9 bellard
static void coreaudio_audio_fini (void *opaque)
510 1d14ffa9 bellard
{
511 1d14ffa9 bellard
    (void) opaque;
512 1d14ffa9 bellard
}
513 1d14ffa9 bellard
514 1d14ffa9 bellard
static struct audio_option coreaudio_options[] = {
515 1d14ffa9 bellard
    {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
516 1d14ffa9 bellard
     "Size of the buffer in frames", NULL, 0},
517 e59c1139 bellard
    {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
518 e59c1139 bellard
     "Number of buffers", NULL, 0},
519 1d14ffa9 bellard
    {NULL, 0, NULL, NULL, NULL, 0}
520 1d14ffa9 bellard
};
521 1d14ffa9 bellard
522 1d14ffa9 bellard
static struct audio_pcm_ops coreaudio_pcm_ops = {
523 1d14ffa9 bellard
    coreaudio_init_out,
524 1d14ffa9 bellard
    coreaudio_fini_out,
525 1d14ffa9 bellard
    coreaudio_run_out,
526 1d14ffa9 bellard
    coreaudio_write,
527 1d14ffa9 bellard
    coreaudio_ctl_out,
528 1d14ffa9 bellard
529 1d14ffa9 bellard
    NULL,
530 1d14ffa9 bellard
    NULL,
531 1d14ffa9 bellard
    NULL,
532 1d14ffa9 bellard
    NULL,
533 1d14ffa9 bellard
    NULL
534 1d14ffa9 bellard
};
535 1d14ffa9 bellard
536 1d14ffa9 bellard
struct audio_driver coreaudio_audio_driver = {
537 1d14ffa9 bellard
    INIT_FIELD (name           = ) "coreaudio",
538 1d14ffa9 bellard
    INIT_FIELD (descr          = )
539 1d14ffa9 bellard
    "CoreAudio http://developer.apple.com/audio/coreaudio.html",
540 1d14ffa9 bellard
    INIT_FIELD (options        = ) coreaudio_options,
541 1d14ffa9 bellard
    INIT_FIELD (init           = ) coreaudio_audio_init,
542 1d14ffa9 bellard
    INIT_FIELD (fini           = ) coreaudio_audio_fini,
543 1d14ffa9 bellard
    INIT_FIELD (pcm_ops        = ) &coreaudio_pcm_ops,
544 1d14ffa9 bellard
    INIT_FIELD (can_be_default = ) 1,
545 1d14ffa9 bellard
    INIT_FIELD (max_voices_out = ) 1,
546 1d14ffa9 bellard
    INIT_FIELD (max_voices_in  = ) 0,
547 1d14ffa9 bellard
    INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
548 1d14ffa9 bellard
    INIT_FIELD (voice_size_in  = ) 0
549 1d14ffa9 bellard
};