Statistics
| Branch: | Revision:

root / audio / coreaudio.c @ 197bc219

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 1d14ffa9 bellard
static int coreaudio_run_out (HWVoiceOut *hw)
194 1d14ffa9 bellard
{
195 1d14ffa9 bellard
    int live, 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
    live = audio_pcm_hw_get_live_out (hw);
203 1d14ffa9 bellard
204 1d14ffa9 bellard
    if (core->decr > live) {
205 1d14ffa9 bellard
        ldebug ("core->decr %d live %d core->live %d\n",
206 1d14ffa9 bellard
                core->decr,
207 1d14ffa9 bellard
                live,
208 1d14ffa9 bellard
                core->live);
209 1d14ffa9 bellard
    }
210 1d14ffa9 bellard
211 1d14ffa9 bellard
    decr = audio_MIN (core->decr, live);
212 1d14ffa9 bellard
    core->decr -= decr;
213 1d14ffa9 bellard
214 1d14ffa9 bellard
    core->live = live - decr;
215 1d14ffa9 bellard
    hw->rpos = core->rpos;
216 1d14ffa9 bellard
217 1d14ffa9 bellard
    coreaudio_unlock (core, "coreaudio_run_out");
218 1d14ffa9 bellard
    return decr;
219 1d14ffa9 bellard
}
220 1d14ffa9 bellard
221 1d14ffa9 bellard
/* callback to feed audiooutput buffer */
222 1d14ffa9 bellard
static OSStatus audioDeviceIOProc(
223 1d14ffa9 bellard
    AudioDeviceID inDevice,
224 1d14ffa9 bellard
    const AudioTimeStamp* inNow,
225 1d14ffa9 bellard
    const AudioBufferList* inInputData,
226 1d14ffa9 bellard
    const AudioTimeStamp* inInputTime,
227 1d14ffa9 bellard
    AudioBufferList* outOutputData,
228 1d14ffa9 bellard
    const AudioTimeStamp* inOutputTime,
229 1d14ffa9 bellard
    void* hwptr)
230 1d14ffa9 bellard
{
231 5e941d4b bellard
    UInt32 frame, frameCount;
232 1d14ffa9 bellard
    float *out = outOutputData->mBuffers[0].mData;
233 1d14ffa9 bellard
    HWVoiceOut *hw = hwptr;
234 1d14ffa9 bellard
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
235 1d14ffa9 bellard
    int rpos, live;
236 1ea879e5 malc
    struct st_sample *src;
237 1d14ffa9 bellard
#ifndef FLOAT_MIXENG
238 1d14ffa9 bellard
#ifdef RECIPROCAL
239 1d14ffa9 bellard
    const float scale = 1.f / UINT_MAX;
240 1d14ffa9 bellard
#else
241 1d14ffa9 bellard
    const float scale = UINT_MAX;
242 1d14ffa9 bellard
#endif
243 1d14ffa9 bellard
#endif
244 1d14ffa9 bellard
245 1d14ffa9 bellard
    if (coreaudio_lock (core, "audioDeviceIOProc")) {
246 1d14ffa9 bellard
        inInputTime = 0;
247 1d14ffa9 bellard
        return 0;
248 1d14ffa9 bellard
    }
249 1d14ffa9 bellard
250 5e941d4b bellard
    frameCount = core->audioDevicePropertyBufferFrameSize;
251 1d14ffa9 bellard
    live = core->live;
252 1d14ffa9 bellard
253 1d14ffa9 bellard
    /* if there are not enough samples, set signal and return */
254 1d14ffa9 bellard
    if (live < frameCount) {
255 1d14ffa9 bellard
        inInputTime = 0;
256 1d14ffa9 bellard
        coreaudio_unlock (core, "audioDeviceIOProc(empty)");
257 1d14ffa9 bellard
        return 0;
258 1d14ffa9 bellard
    }
259 1d14ffa9 bellard
260 1d14ffa9 bellard
    rpos = core->rpos;
261 1d14ffa9 bellard
    src = hw->mix_buf + rpos;
262 1d14ffa9 bellard
263 1d14ffa9 bellard
    /* fill buffer */
264 1d14ffa9 bellard
    for (frame = 0; frame < frameCount; frame++) {
265 1d14ffa9 bellard
#ifdef FLOAT_MIXENG
266 1d14ffa9 bellard
        *out++ = src[frame].l; /* left channel */
267 1d14ffa9 bellard
        *out++ = src[frame].r; /* right channel */
268 1d14ffa9 bellard
#else
269 1d14ffa9 bellard
#ifdef RECIPROCAL
270 1d14ffa9 bellard
        *out++ = src[frame].l * scale; /* left channel */
271 1d14ffa9 bellard
        *out++ = src[frame].r * scale; /* right channel */
272 1d14ffa9 bellard
#else
273 1d14ffa9 bellard
        *out++ = src[frame].l / scale; /* left channel */
274 1d14ffa9 bellard
        *out++ = src[frame].r / scale; /* right channel */
275 1d14ffa9 bellard
#endif
276 1d14ffa9 bellard
#endif
277 1d14ffa9 bellard
    }
278 1d14ffa9 bellard
279 1d14ffa9 bellard
    rpos = (rpos + frameCount) % hw->samples;
280 5e941d4b bellard
    core->decr += frameCount;
281 1d14ffa9 bellard
    core->rpos = rpos;
282 1d14ffa9 bellard
283 1d14ffa9 bellard
    coreaudio_unlock (core, "audioDeviceIOProc");
284 1d14ffa9 bellard
    return 0;
285 1d14ffa9 bellard
}
286 1d14ffa9 bellard
287 1d14ffa9 bellard
static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
288 1d14ffa9 bellard
{
289 1d14ffa9 bellard
    return audio_pcm_sw_write (sw, buf, len);
290 1d14ffa9 bellard
}
291 1d14ffa9 bellard
292 1ea879e5 malc
static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
293 1d14ffa9 bellard
{
294 1d14ffa9 bellard
    OSStatus status;
295 1d14ffa9 bellard
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
296 1d14ffa9 bellard
    UInt32 propertySize;
297 1d14ffa9 bellard
    int err;
298 5e941d4b bellard
    const char *typ = "playback";
299 5e941d4b bellard
    AudioValueRange frameRange;
300 1d14ffa9 bellard
301 1d14ffa9 bellard
    /* create mutex */
302 1d14ffa9 bellard
    err = pthread_mutex_init(&core->mutex, NULL);
303 1d14ffa9 bellard
    if (err) {
304 c0fe3827 bellard
        dolog("Could not create mutex\nReason: %s\n", strerror (err));
305 1d14ffa9 bellard
        return -1;
306 1d14ffa9 bellard
    }
307 1d14ffa9 bellard
308 d929eba5 bellard
    audio_pcm_init_info (&hw->info, as);
309 1d14ffa9 bellard
310 1d14ffa9 bellard
    /* open default output device */
311 1d14ffa9 bellard
    propertySize = sizeof(core->outputDeviceID);
312 1d14ffa9 bellard
    status = AudioHardwareGetProperty(
313 1d14ffa9 bellard
        kAudioHardwarePropertyDefaultOutputDevice,
314 1d14ffa9 bellard
        &propertySize,
315 1d14ffa9 bellard
        &core->outputDeviceID);
316 1d14ffa9 bellard
    if (status != kAudioHardwareNoError) {
317 1d14ffa9 bellard
        coreaudio_logerr2 (status, typ,
318 c0fe3827 bellard
                           "Could not get default output Device\n");
319 1d14ffa9 bellard
        return -1;
320 1d14ffa9 bellard
    }
321 1d14ffa9 bellard
    if (core->outputDeviceID == kAudioDeviceUnknown) {
322 c0fe3827 bellard
        dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
323 1d14ffa9 bellard
        return -1;
324 1d14ffa9 bellard
    }
325 1d14ffa9 bellard
326 5e941d4b bellard
    /* get minimum and maximum buffer frame sizes */
327 5e941d4b bellard
    propertySize = sizeof(frameRange);
328 5e941d4b bellard
    status = AudioDeviceGetProperty(
329 5e941d4b bellard
        core->outputDeviceID,
330 5e941d4b bellard
        0,
331 5e941d4b bellard
        0,
332 5e941d4b bellard
        kAudioDevicePropertyBufferFrameSizeRange,
333 5e941d4b bellard
        &propertySize,
334 5e941d4b bellard
        &frameRange);
335 5e941d4b bellard
    if (status != kAudioHardwareNoError) {
336 5e941d4b bellard
        coreaudio_logerr2 (status, typ,
337 5e941d4b bellard
                           "Could not get device buffer frame range\n");
338 5e941d4b bellard
        return -1;
339 5e941d4b bellard
    }
340 5e941d4b bellard
341 5e941d4b bellard
    if (frameRange.mMinimum > conf.buffer_frames) {
342 5e941d4b bellard
        core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
343 5e941d4b bellard
        dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
344 5e941d4b bellard
    }
345 5e941d4b bellard
    else if (frameRange.mMaximum < conf.buffer_frames) {
346 5e941d4b bellard
        core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
347 5e941d4b bellard
        dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
348 5e941d4b bellard
    }
349 5e941d4b bellard
    else {
350 5e941d4b bellard
        core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
351 5e941d4b bellard
    }
352 5e941d4b bellard
353 5e941d4b bellard
    /* set Buffer Frame Size */
354 5e941d4b bellard
    propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
355 1d14ffa9 bellard
    status = AudioDeviceSetProperty(
356 1d14ffa9 bellard
        core->outputDeviceID,
357 1d14ffa9 bellard
        NULL,
358 1d14ffa9 bellard
        0,
359 1d14ffa9 bellard
        false,
360 5e941d4b bellard
        kAudioDevicePropertyBufferFrameSize,
361 1d14ffa9 bellard
        propertySize,
362 5e941d4b bellard
        &core->audioDevicePropertyBufferFrameSize);
363 1d14ffa9 bellard
    if (status != kAudioHardwareNoError) {
364 1d14ffa9 bellard
        coreaudio_logerr2 (status, typ,
365 5e941d4b bellard
                           "Could not set device buffer frame size %ld\n",
366 5e941d4b bellard
                           core->audioDevicePropertyBufferFrameSize);
367 1d14ffa9 bellard
        return -1;
368 1d14ffa9 bellard
    }
369 1d14ffa9 bellard
370 5e941d4b bellard
    /* get Buffer Frame Size */
371 5e941d4b bellard
    propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
372 1d14ffa9 bellard
    status = AudioDeviceGetProperty(
373 1d14ffa9 bellard
        core->outputDeviceID,
374 1d14ffa9 bellard
        0,
375 1d14ffa9 bellard
        false,
376 5e941d4b bellard
        kAudioDevicePropertyBufferFrameSize,
377 1d14ffa9 bellard
        &propertySize,
378 5e941d4b bellard
        &core->audioDevicePropertyBufferFrameSize);
379 1d14ffa9 bellard
    if (status != kAudioHardwareNoError) {
380 5e941d4b bellard
        coreaudio_logerr2 (status, typ,
381 5e941d4b bellard
                           "Could not get device buffer frame size\n");
382 1d14ffa9 bellard
        return -1;
383 1d14ffa9 bellard
    }
384 e59c1139 bellard
    hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
385 1d14ffa9 bellard
386 1d14ffa9 bellard
    /* get StreamFormat */
387 1d14ffa9 bellard
    propertySize = sizeof(core->outputStreamBasicDescription);
388 1d14ffa9 bellard
    status = AudioDeviceGetProperty(
389 1d14ffa9 bellard
        core->outputDeviceID,
390 1d14ffa9 bellard
        0,
391 1d14ffa9 bellard
        false,
392 1d14ffa9 bellard
        kAudioDevicePropertyStreamFormat,
393 1d14ffa9 bellard
        &propertySize,
394 1d14ffa9 bellard
        &core->outputStreamBasicDescription);
395 1d14ffa9 bellard
    if (status != kAudioHardwareNoError) {
396 1d14ffa9 bellard
        coreaudio_logerr2 (status, typ,
397 c0fe3827 bellard
                           "Could not get Device Stream properties\n");
398 1d14ffa9 bellard
        core->outputDeviceID = kAudioDeviceUnknown;
399 1d14ffa9 bellard
        return -1;
400 1d14ffa9 bellard
    }
401 1d14ffa9 bellard
402 1d14ffa9 bellard
    /* set Samplerate */
403 5e941d4b bellard
    core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
404 1d14ffa9 bellard
    propertySize = sizeof(core->outputStreamBasicDescription);
405 1d14ffa9 bellard
    status = AudioDeviceSetProperty(
406 1d14ffa9 bellard
        core->outputDeviceID,
407 1d14ffa9 bellard
        0,
408 1d14ffa9 bellard
        0,
409 1d14ffa9 bellard
        0,
410 1d14ffa9 bellard
        kAudioDevicePropertyStreamFormat,
411 1d14ffa9 bellard
        propertySize,
412 1d14ffa9 bellard
        &core->outputStreamBasicDescription);
413 1d14ffa9 bellard
    if (status != kAudioHardwareNoError) {
414 575b5dc4 bellard
        coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
415 575b5dc4 bellard
                           as->freq);
416 1d14ffa9 bellard
        core->outputDeviceID = kAudioDeviceUnknown;
417 1d14ffa9 bellard
        return -1;
418 1d14ffa9 bellard
    }
419 1d14ffa9 bellard
420 1d14ffa9 bellard
    /* set Callback */
421 1d14ffa9 bellard
    status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
422 1d14ffa9 bellard
    if (status != kAudioHardwareNoError) {
423 c0fe3827 bellard
        coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
424 1d14ffa9 bellard
        core->outputDeviceID = kAudioDeviceUnknown;
425 1d14ffa9 bellard
        return -1;
426 1d14ffa9 bellard
    }
427 1d14ffa9 bellard
428 1d14ffa9 bellard
    /* start Playback */
429 5e941d4b bellard
    if (!isPlaying(core->outputDeviceID)) {
430 1d14ffa9 bellard
        status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
431 1d14ffa9 bellard
        if (status != kAudioHardwareNoError) {
432 c0fe3827 bellard
            coreaudio_logerr2 (status, typ, "Could not start playback\n");
433 1d14ffa9 bellard
            AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
434 1d14ffa9 bellard
            core->outputDeviceID = kAudioDeviceUnknown;
435 1d14ffa9 bellard
            return -1;
436 1d14ffa9 bellard
        }
437 1d14ffa9 bellard
    }
438 1d14ffa9 bellard
439 1d14ffa9 bellard
    return 0;
440 1d14ffa9 bellard
}
441 1d14ffa9 bellard
442 1d14ffa9 bellard
static void coreaudio_fini_out (HWVoiceOut *hw)
443 1d14ffa9 bellard
{
444 1d14ffa9 bellard
    OSStatus status;
445 1d14ffa9 bellard
    int err;
446 1d14ffa9 bellard
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
447 1d14ffa9 bellard
448 5e941d4b bellard
    if (!conf.isAtexit) {
449 5e941d4b bellard
        /* stop playback */
450 5e941d4b bellard
        if (isPlaying(core->outputDeviceID)) {
451 5e941d4b bellard
            status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
452 5e941d4b bellard
            if (status != kAudioHardwareNoError) {
453 5e941d4b bellard
                coreaudio_logerr (status, "Could not stop playback\n");
454 5e941d4b bellard
            }
455 1d14ffa9 bellard
        }
456 1d14ffa9 bellard
457 5e941d4b bellard
        /* remove callback */
458 5e941d4b bellard
        status = AudioDeviceRemoveIOProc(core->outputDeviceID,
459 5e941d4b bellard
                                         audioDeviceIOProc);
460 5e941d4b bellard
        if (status != kAudioHardwareNoError) {
461 5e941d4b bellard
            coreaudio_logerr (status, "Could not remove IOProc\n");
462 5e941d4b bellard
        }
463 1d14ffa9 bellard
    }
464 1d14ffa9 bellard
    core->outputDeviceID = kAudioDeviceUnknown;
465 1d14ffa9 bellard
466 1d14ffa9 bellard
    /* destroy mutex */
467 1d14ffa9 bellard
    err = pthread_mutex_destroy(&core->mutex);
468 1d14ffa9 bellard
    if (err) {
469 c0fe3827 bellard
        dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
470 1d14ffa9 bellard
    }
471 1d14ffa9 bellard
}
472 1d14ffa9 bellard
473 1d14ffa9 bellard
static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
474 1d14ffa9 bellard
{
475 1d14ffa9 bellard
    OSStatus status;
476 1d14ffa9 bellard
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
477 1d14ffa9 bellard
478 1d14ffa9 bellard
    switch (cmd) {
479 1d14ffa9 bellard
    case VOICE_ENABLE:
480 1d14ffa9 bellard
        /* start playback */
481 5e941d4b bellard
        if (!isPlaying(core->outputDeviceID)) {
482 1d14ffa9 bellard
            status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
483 1d14ffa9 bellard
            if (status != kAudioHardwareNoError) {
484 5e941d4b bellard
                coreaudio_logerr (status, "Could not resume playback\n");
485 1d14ffa9 bellard
            }
486 1d14ffa9 bellard
        }
487 1d14ffa9 bellard
        break;
488 1d14ffa9 bellard
489 1d14ffa9 bellard
    case VOICE_DISABLE:
490 1d14ffa9 bellard
        /* stop playback */
491 5e941d4b bellard
        if (!conf.isAtexit) {
492 5e941d4b bellard
            if (isPlaying(core->outputDeviceID)) {
493 5e941d4b bellard
                status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
494 5e941d4b bellard
                if (status != kAudioHardwareNoError) {
495 5e941d4b bellard
                    coreaudio_logerr (status, "Could not pause playback\n");
496 5e941d4b bellard
                }
497 1d14ffa9 bellard
            }
498 1d14ffa9 bellard
        }
499 1d14ffa9 bellard
        break;
500 1d14ffa9 bellard
    }
501 1d14ffa9 bellard
    return 0;
502 1d14ffa9 bellard
}
503 1d14ffa9 bellard
504 1d14ffa9 bellard
static void *coreaudio_audio_init (void)
505 1d14ffa9 bellard
{
506 5e941d4b bellard
    atexit(coreaudio_atexit);
507 1d14ffa9 bellard
    return &coreaudio_audio_init;
508 1d14ffa9 bellard
}
509 1d14ffa9 bellard
510 1d14ffa9 bellard
static void coreaudio_audio_fini (void *opaque)
511 1d14ffa9 bellard
{
512 1d14ffa9 bellard
    (void) opaque;
513 1d14ffa9 bellard
}
514 1d14ffa9 bellard
515 1d14ffa9 bellard
static struct audio_option coreaudio_options[] = {
516 98f9f48c malc
    {
517 98f9f48c malc
        .name  = "BUFFER_SIZE",
518 98f9f48c malc
        .tag   = AUD_OPT_INT,
519 98f9f48c malc
        .valp  = &conf.buffer_frames,
520 98f9f48c malc
        .descr = "Size of the buffer in frames"
521 98f9f48c malc
    },
522 98f9f48c malc
    {
523 98f9f48c malc
        .name  = "BUFFER_COUNT",
524 98f9f48c malc
        .tag   = AUD_OPT_INT,
525 98f9f48c malc
        .valp  = &conf.nbuffers,
526 98f9f48c malc
        .descr = "Number of buffers"
527 98f9f48c malc
    },
528 2700efa3 Juan Quintela
    { /* End of list */ }
529 1d14ffa9 bellard
};
530 1d14ffa9 bellard
531 35f4b58c blueswir1
static struct audio_pcm_ops coreaudio_pcm_ops = {
532 1dd3e4d1 Juan Quintela
    .init_out = coreaudio_init_out,
533 1dd3e4d1 Juan Quintela
    .fini_out = coreaudio_fini_out,
534 1dd3e4d1 Juan Quintela
    .run_out  = coreaudio_run_out,
535 1dd3e4d1 Juan Quintela
    .write    = coreaudio_write,
536 1dd3e4d1 Juan Quintela
    .ctl_out  = coreaudio_ctl_out
537 1d14ffa9 bellard
};
538 1d14ffa9 bellard
539 1d14ffa9 bellard
struct audio_driver coreaudio_audio_driver = {
540 bee37f32 Juan Quintela
    .name           = "coreaudio",
541 bee37f32 Juan Quintela
    .descr          = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
542 bee37f32 Juan Quintela
    .options        = coreaudio_options,
543 bee37f32 Juan Quintela
    .init           = coreaudio_audio_init,
544 bee37f32 Juan Quintela
    .fini           = coreaudio_audio_fini,
545 bee37f32 Juan Quintela
    .pcm_ops        = &coreaudio_pcm_ops,
546 bee37f32 Juan Quintela
    .can_be_default = 1,
547 bee37f32 Juan Quintela
    .max_voices_out = 1,
548 bee37f32 Juan Quintela
    .max_voices_in  = 0,
549 bee37f32 Juan Quintela
    .voice_size_out = sizeof (coreaudioVoiceOut),
550 bee37f32 Juan Quintela
    .voice_size_in  = 0
551 1d14ffa9 bellard
};