Statistics
| Branch: | Revision:

root / audio / coreaudio.c @ fd5723b3

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