]> git.proxmox.com Git - mirror_qemu.git/blame - audio/coreaudio.c
monitor: fix crash when leaving qemu with spice audio
[mirror_qemu.git] / audio / coreaudio.c
CommitLineData
1d14ffa9
FB
1/*
2 * QEMU OS X CoreAudio audio driver
3 *
4 * Copyright (c) 2005 Mike Kronenberg
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
6086a565 25#include "qemu/osdep.h"
1d14ffa9 26#include <CoreAudio/CoreAudio.h>
1d14ffa9
FB
27#include <pthread.h> /* pthread_X */
28
749bc4bf
PB
29#include "qemu-common.h"
30#include "audio.h"
1d14ffa9
FB
31
32#define AUDIO_CAP "coreaudio"
33#include "audio_int.h"
34
624d1fc3
PM
35#ifndef MAC_OS_X_VERSION_10_6
36#define MAC_OS_X_VERSION_10_6 1060
37#endif
38
d1f52a1d
KZ
39static int isAtexit;
40
41typedef struct {
1d14ffa9 42 int buffer_frames;
e59c1139 43 int nbuffers;
d1f52a1d 44} CoreaudioConf;
1d14ffa9
FB
45
46typedef struct coreaudioVoiceOut {
47 HWVoiceOut hw;
48 pthread_mutex_t mutex;
49 AudioDeviceID outputDeviceID;
5e941d4b 50 UInt32 audioDevicePropertyBufferFrameSize;
1d14ffa9 51 AudioStreamBasicDescription outputStreamBasicDescription;
2f79a18f 52 AudioDeviceIOProcID ioprocid;
1d14ffa9
FB
53 int live;
54 int decr;
55 int rpos;
56} coreaudioVoiceOut;
57
624d1fc3
PM
58#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
59/* The APIs used here only become available from 10.6 */
60
61static OSStatus coreaudio_get_voice(AudioDeviceID *id)
62{
63 UInt32 size = sizeof(*id);
64 AudioObjectPropertyAddress addr = {
65 kAudioHardwarePropertyDefaultOutputDevice,
66 kAudioObjectPropertyScopeGlobal,
67 kAudioObjectPropertyElementMaster
68 };
69
70 return AudioObjectGetPropertyData(kAudioObjectSystemObject,
71 &addr,
72 0,
73 NULL,
74 &size,
75 id);
76}
2d99f629
PM
77
78static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
79 AudioValueRange *framerange)
80{
81 UInt32 size = sizeof(*framerange);
82 AudioObjectPropertyAddress addr = {
83 kAudioDevicePropertyBufferFrameSizeRange,
84 kAudioDevicePropertyScopeOutput,
85 kAudioObjectPropertyElementMaster
86 };
87
88 return AudioObjectGetPropertyData(id,
89 &addr,
90 0,
91 NULL,
92 &size,
93 framerange);
94}
95
96static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
97{
98 UInt32 size = sizeof(*framesize);
99 AudioObjectPropertyAddress addr = {
100 kAudioDevicePropertyBufferFrameSize,
101 kAudioDevicePropertyScopeOutput,
102 kAudioObjectPropertyElementMaster
103 };
104
105 return AudioObjectGetPropertyData(id,
106 &addr,
107 0,
108 NULL,
109 &size,
110 framesize);
111}
112
113static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
114{
115 UInt32 size = sizeof(*framesize);
116 AudioObjectPropertyAddress addr = {
117 kAudioDevicePropertyBufferFrameSize,
118 kAudioDevicePropertyScopeOutput,
119 kAudioObjectPropertyElementMaster
120 };
121
122 return AudioObjectSetPropertyData(id,
123 &addr,
124 0,
125 NULL,
126 size,
127 framesize);
128}
129
130static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
131 AudioStreamBasicDescription *d)
132{
133 UInt32 size = sizeof(*d);
134 AudioObjectPropertyAddress addr = {
135 kAudioDevicePropertyStreamFormat,
136 kAudioDevicePropertyScopeOutput,
137 kAudioObjectPropertyElementMaster
138 };
139
140 return AudioObjectGetPropertyData(id,
141 &addr,
142 0,
143 NULL,
144 &size,
145 d);
146}
147
148static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
149 AudioStreamBasicDescription *d)
150{
151 UInt32 size = sizeof(*d);
152 AudioObjectPropertyAddress addr = {
153 kAudioDevicePropertyStreamFormat,
154 kAudioDevicePropertyScopeOutput,
155 kAudioObjectPropertyElementMaster
156 };
157
158 return AudioObjectSetPropertyData(id,
159 &addr,
160 0,
161 NULL,
162 size,
163 d);
164}
165
166static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
167{
168 UInt32 size = sizeof(*result);
169 AudioObjectPropertyAddress addr = {
170 kAudioDevicePropertyDeviceIsRunning,
171 kAudioDevicePropertyScopeOutput,
172 kAudioObjectPropertyElementMaster
173 };
174
175 return AudioObjectGetPropertyData(id,
176 &addr,
177 0,
178 NULL,
179 &size,
180 result);
181}
624d1fc3
PM
182#else
183/* Legacy versions of functions using deprecated APIs */
184
88a0f830
PM
185static OSStatus coreaudio_get_voice(AudioDeviceID *id)
186{
187 UInt32 size = sizeof(*id);
188
189 return AudioHardwareGetProperty(
190 kAudioHardwarePropertyDefaultOutputDevice,
191 &size,
192 id);
193}
194
95a860f6
PM
195static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
196 AudioValueRange *framerange)
197{
198 UInt32 size = sizeof(*framerange);
199
200 return AudioDeviceGetProperty(
201 id,
202 0,
203 0,
204 kAudioDevicePropertyBufferFrameSizeRange,
205 &size,
206 framerange);
207}
208
209static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
210{
211 UInt32 size = sizeof(*framesize);
212
213 return AudioDeviceGetProperty(
214 id,
215 0,
216 false,
217 kAudioDevicePropertyBufferFrameSize,
218 &size,
219 framesize);
220}
221
222static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
223{
224 UInt32 size = sizeof(*framesize);
225
226 return AudioDeviceSetProperty(
227 id,
228 NULL,
229 0,
230 false,
231 kAudioDevicePropertyBufferFrameSize,
232 size,
233 framesize);
234}
235
236static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
237 AudioStreamBasicDescription *d)
238{
239 UInt32 size = sizeof(*d);
240
241 return AudioDeviceGetProperty(
242 id,
243 0,
244 false,
245 kAudioDevicePropertyStreamFormat,
246 &size,
247 d);
248}
249
250static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
251 AudioStreamBasicDescription *d)
252{
253 UInt32 size = sizeof(*d);
254
255 return AudioDeviceSetProperty(
256 id,
257 0,
258 0,
259 0,
260 kAudioDevicePropertyStreamFormat,
261 size,
262 d);
263}
264
265static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
266{
267 UInt32 size = sizeof(*result);
268
269 return AudioDeviceGetProperty(
270 id,
271 0,
272 0,
273 kAudioDevicePropertyDeviceIsRunning,
274 &size,
275 result);
276}
2d99f629 277#endif
95a860f6 278
1d14ffa9
FB
279static void coreaudio_logstatus (OSStatus status)
280{
d9cbb0f3 281 const char *str = "BUG";
1d14ffa9
FB
282
283 switch(status) {
284 case kAudioHardwareNoError:
285 str = "kAudioHardwareNoError";
286 break;
287
288 case kAudioHardwareNotRunningError:
289 str = "kAudioHardwareNotRunningError";
290 break;
291
292 case kAudioHardwareUnspecifiedError:
293 str = "kAudioHardwareUnspecifiedError";
294 break;
295
296 case kAudioHardwareUnknownPropertyError:
297 str = "kAudioHardwareUnknownPropertyError";
298 break;
299
300 case kAudioHardwareBadPropertySizeError:
301 str = "kAudioHardwareBadPropertySizeError";
302 break;
303
304 case kAudioHardwareIllegalOperationError:
305 str = "kAudioHardwareIllegalOperationError";
306 break;
307
308 case kAudioHardwareBadDeviceError:
309 str = "kAudioHardwareBadDeviceError";
310 break;
311
312 case kAudioHardwareBadStreamError:
313 str = "kAudioHardwareBadStreamError";
314 break;
315
316 case kAudioHardwareUnsupportedOperationError:
317 str = "kAudioHardwareUnsupportedOperationError";
318 break;
319
320 case kAudioDeviceUnsupportedFormatError:
321 str = "kAudioDeviceUnsupportedFormatError";
322 break;
323
324 case kAudioDevicePermissionsError:
325 str = "kAudioDevicePermissionsError";
326 break;
327
328 default:
744d3644 329 AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
1d14ffa9
FB
330 return;
331 }
332
333 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
334}
335
336static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
337 OSStatus status,
338 const char *fmt,
339 ...
340 )
341{
342 va_list ap;
343
344 va_start (ap, fmt);
345 AUD_log (AUDIO_CAP, fmt, ap);
346 va_end (ap);
347
348 coreaudio_logstatus (status);
349}
350
351static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
352 OSStatus status,
353 const char *typ,
354 const char *fmt,
355 ...
356 )
357{
358 va_list ap;
359
c0fe3827 360 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
1d14ffa9
FB
361
362 va_start (ap, fmt);
363 AUD_vlog (AUDIO_CAP, fmt, ap);
364 va_end (ap);
365
366 coreaudio_logstatus (status);
367}
368
5e941d4b
FB
369static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
370{
371 OSStatus status;
372 UInt32 result = 0;
95a860f6 373 status = coreaudio_get_isrunning(outputDeviceID, &result);
5e941d4b
FB
374 if (status != kAudioHardwareNoError) {
375 coreaudio_logerr(status,
376 "Could not determine whether Device is playing\n");
377 }
378 return result;
379}
380
381static void coreaudio_atexit (void)
382{
d1f52a1d 383 isAtexit = 1;
5e941d4b
FB
384}
385
1d14ffa9
FB
386static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
387{
388 int err;
389
390 err = pthread_mutex_lock (&core->mutex);
391 if (err) {
c0fe3827 392 dolog ("Could not lock voice for %s\nReason: %s\n",
1d14ffa9
FB
393 fn_name, strerror (err));
394 return -1;
395 }
396 return 0;
397}
398
399static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
400{
401 int err;
402
403 err = pthread_mutex_unlock (&core->mutex);
404 if (err) {
c0fe3827 405 dolog ("Could not unlock voice for %s\nReason: %s\n",
1d14ffa9
FB
406 fn_name, strerror (err));
407 return -1;
408 }
409 return 0;
410}
411
bdff253c 412static int coreaudio_run_out (HWVoiceOut *hw, int live)
1d14ffa9 413{
bdff253c 414 int decr;
1d14ffa9
FB
415 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
416
417 if (coreaudio_lock (core, "coreaudio_run_out")) {
418 return 0;
419 }
420
1d14ffa9
FB
421 if (core->decr > live) {
422 ldebug ("core->decr %d live %d core->live %d\n",
423 core->decr,
424 live,
425 core->live);
426 }
427
428 decr = audio_MIN (core->decr, live);
429 core->decr -= decr;
430
431 core->live = live - decr;
432 hw->rpos = core->rpos;
433
434 coreaudio_unlock (core, "coreaudio_run_out");
435 return decr;
436}
437
438/* callback to feed audiooutput buffer */
439static OSStatus audioDeviceIOProc(
440 AudioDeviceID inDevice,
441 const AudioTimeStamp* inNow,
442 const AudioBufferList* inInputData,
443 const AudioTimeStamp* inInputTime,
444 AudioBufferList* outOutputData,
445 const AudioTimeStamp* inOutputTime,
446 void* hwptr)
447{
5e941d4b 448 UInt32 frame, frameCount;
1d14ffa9
FB
449 float *out = outOutputData->mBuffers[0].mData;
450 HWVoiceOut *hw = hwptr;
451 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
452 int rpos, live;
1ea879e5 453 struct st_sample *src;
1d14ffa9
FB
454#ifndef FLOAT_MIXENG
455#ifdef RECIPROCAL
456 const float scale = 1.f / UINT_MAX;
457#else
458 const float scale = UINT_MAX;
459#endif
460#endif
461
462 if (coreaudio_lock (core, "audioDeviceIOProc")) {
463 inInputTime = 0;
464 return 0;
465 }
466
5e941d4b 467 frameCount = core->audioDevicePropertyBufferFrameSize;
1d14ffa9
FB
468 live = core->live;
469
470 /* if there are not enough samples, set signal and return */
471 if (live < frameCount) {
472 inInputTime = 0;
473 coreaudio_unlock (core, "audioDeviceIOProc(empty)");
474 return 0;
475 }
476
477 rpos = core->rpos;
478 src = hw->mix_buf + rpos;
479
480 /* fill buffer */
481 for (frame = 0; frame < frameCount; frame++) {
482#ifdef FLOAT_MIXENG
483 *out++ = src[frame].l; /* left channel */
484 *out++ = src[frame].r; /* right channel */
485#else
486#ifdef RECIPROCAL
487 *out++ = src[frame].l * scale; /* left channel */
488 *out++ = src[frame].r * scale; /* right channel */
489#else
490 *out++ = src[frame].l / scale; /* left channel */
491 *out++ = src[frame].r / scale; /* right channel */
492#endif
493#endif
494 }
495
1d14ffa9 496 rpos = (rpos + frameCount) % hw->samples;
5e941d4b 497 core->decr += frameCount;
1d14ffa9
FB
498 core->rpos = rpos;
499
500 coreaudio_unlock (core, "audioDeviceIOProc");
501 return 0;
502}
503
504static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
505{
506 return audio_pcm_sw_write (sw, buf, len);
507}
508
5706db1d
KZ
509static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
510 void *drv_opaque)
1d14ffa9
FB
511{
512 OSStatus status;
513 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
1d14ffa9 514 int err;
5e941d4b
FB
515 const char *typ = "playback";
516 AudioValueRange frameRange;
d1f52a1d 517 CoreaudioConf *conf = drv_opaque;
1d14ffa9
FB
518
519 /* create mutex */
520 err = pthread_mutex_init(&core->mutex, NULL);
521 if (err) {
c0fe3827 522 dolog("Could not create mutex\nReason: %s\n", strerror (err));
1d14ffa9
FB
523 return -1;
524 }
525
d929eba5 526 audio_pcm_init_info (&hw->info, as);
1d14ffa9 527
88a0f830 528 status = coreaudio_get_voice(&core->outputDeviceID);
1d14ffa9
FB
529 if (status != kAudioHardwareNoError) {
530 coreaudio_logerr2 (status, typ,
c0fe3827 531 "Could not get default output Device\n");
1d14ffa9
FB
532 return -1;
533 }
534 if (core->outputDeviceID == kAudioDeviceUnknown) {
c0fe3827 535 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
1d14ffa9
FB
536 return -1;
537 }
538
5e941d4b 539 /* get minimum and maximum buffer frame sizes */
95a860f6
PM
540 status = coreaudio_get_framesizerange(core->outputDeviceID,
541 &frameRange);
5e941d4b
FB
542 if (status != kAudioHardwareNoError) {
543 coreaudio_logerr2 (status, typ,
544 "Could not get device buffer frame range\n");
545 return -1;
546 }
547
d1f52a1d 548 if (frameRange.mMinimum > conf->buffer_frames) {
5e941d4b
FB
549 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
550 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
551 }
d1f52a1d 552 else if (frameRange.mMaximum < conf->buffer_frames) {
5e941d4b
FB
553 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
554 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
555 }
556 else {
d1f52a1d 557 core->audioDevicePropertyBufferFrameSize = conf->buffer_frames;
5e941d4b
FB
558 }
559
560 /* set Buffer Frame Size */
95a860f6
PM
561 status = coreaudio_set_framesize(core->outputDeviceID,
562 &core->audioDevicePropertyBufferFrameSize);
1d14ffa9
FB
563 if (status != kAudioHardwareNoError) {
564 coreaudio_logerr2 (status, typ,
cbc36cb0
AF
565 "Could not set device buffer frame size %" PRIu32 "\n",
566 (uint32_t)core->audioDevicePropertyBufferFrameSize);
1d14ffa9
FB
567 return -1;
568 }
569
5e941d4b 570 /* get Buffer Frame Size */
95a860f6
PM
571 status = coreaudio_get_framesize(core->outputDeviceID,
572 &core->audioDevicePropertyBufferFrameSize);
1d14ffa9 573 if (status != kAudioHardwareNoError) {
5e941d4b
FB
574 coreaudio_logerr2 (status, typ,
575 "Could not get device buffer frame size\n");
1d14ffa9
FB
576 return -1;
577 }
d1f52a1d 578 hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize;
1d14ffa9
FB
579
580 /* get StreamFormat */
95a860f6
PM
581 status = coreaudio_get_streamformat(core->outputDeviceID,
582 &core->outputStreamBasicDescription);
1d14ffa9
FB
583 if (status != kAudioHardwareNoError) {
584 coreaudio_logerr2 (status, typ,
c0fe3827 585 "Could not get Device Stream properties\n");
1d14ffa9
FB
586 core->outputDeviceID = kAudioDeviceUnknown;
587 return -1;
588 }
589
590 /* set Samplerate */
5e941d4b 591 core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
95a860f6
PM
592 status = coreaudio_set_streamformat(core->outputDeviceID,
593 &core->outputStreamBasicDescription);
1d14ffa9 594 if (status != kAudioHardwareNoError) {
575b5dc4
FB
595 coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
596 as->freq);
1d14ffa9
FB
597 core->outputDeviceID = kAudioDeviceUnknown;
598 return -1;
599 }
600
601 /* set Callback */
2f79a18f
PM
602 core->ioprocid = NULL;
603 status = AudioDeviceCreateIOProcID(core->outputDeviceID,
604 audioDeviceIOProc,
605 hw,
606 &core->ioprocid);
607 if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
c0fe3827 608 coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
1d14ffa9
FB
609 core->outputDeviceID = kAudioDeviceUnknown;
610 return -1;
611 }
612
613 /* start Playback */
5e941d4b 614 if (!isPlaying(core->outputDeviceID)) {
2f79a18f 615 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
1d14ffa9 616 if (status != kAudioHardwareNoError) {
c0fe3827 617 coreaudio_logerr2 (status, typ, "Could not start playback\n");
2f79a18f 618 AudioDeviceDestroyIOProcID(core->outputDeviceID, core->ioprocid);
1d14ffa9
FB
619 core->outputDeviceID = kAudioDeviceUnknown;
620 return -1;
621 }
1d14ffa9
FB
622 }
623
624 return 0;
625}
626
627static void coreaudio_fini_out (HWVoiceOut *hw)
628{
629 OSStatus status;
630 int err;
631 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
632
d1f52a1d 633 if (!isAtexit) {
5e941d4b
FB
634 /* stop playback */
635 if (isPlaying(core->outputDeviceID)) {
2f79a18f 636 status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
5e941d4b
FB
637 if (status != kAudioHardwareNoError) {
638 coreaudio_logerr (status, "Could not stop playback\n");
639 }
1d14ffa9 640 }
1d14ffa9 641
5e941d4b 642 /* remove callback */
2f79a18f
PM
643 status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
644 core->ioprocid);
5e941d4b
FB
645 if (status != kAudioHardwareNoError) {
646 coreaudio_logerr (status, "Could not remove IOProc\n");
647 }
1d14ffa9
FB
648 }
649 core->outputDeviceID = kAudioDeviceUnknown;
650
651 /* destroy mutex */
652 err = pthread_mutex_destroy(&core->mutex);
653 if (err) {
c0fe3827 654 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
1d14ffa9
FB
655 }
656}
657
658static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
659{
660 OSStatus status;
661 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
662
663 switch (cmd) {
664 case VOICE_ENABLE:
665 /* start playback */
5e941d4b 666 if (!isPlaying(core->outputDeviceID)) {
2f79a18f 667 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
1d14ffa9 668 if (status != kAudioHardwareNoError) {
5e941d4b 669 coreaudio_logerr (status, "Could not resume playback\n");
1d14ffa9 670 }
1d14ffa9
FB
671 }
672 break;
673
674 case VOICE_DISABLE:
675 /* stop playback */
d1f52a1d 676 if (!isAtexit) {
5e941d4b 677 if (isPlaying(core->outputDeviceID)) {
2f79a18f
PM
678 status = AudioDeviceStop(core->outputDeviceID,
679 core->ioprocid);
5e941d4b
FB
680 if (status != kAudioHardwareNoError) {
681 coreaudio_logerr (status, "Could not pause playback\n");
682 }
1d14ffa9 683 }
1d14ffa9
FB
684 }
685 break;
686 }
687 return 0;
688}
689
d1f52a1d
KZ
690static CoreaudioConf glob_conf = {
691 .buffer_frames = 512,
692 .nbuffers = 4,
693};
694
1d14ffa9
FB
695static void *coreaudio_audio_init (void)
696{
d1f52a1d
KZ
697 CoreaudioConf *conf = g_malloc(sizeof(CoreaudioConf));
698 *conf = glob_conf;
699
5e941d4b 700 atexit(coreaudio_atexit);
d1f52a1d 701 return conf;
1d14ffa9
FB
702}
703
704static void coreaudio_audio_fini (void *opaque)
705{
d1f52a1d 706 g_free(opaque);
1d14ffa9
FB
707}
708
709static struct audio_option coreaudio_options[] = {
98f9f48c 710 {
711 .name = "BUFFER_SIZE",
712 .tag = AUD_OPT_INT,
d1f52a1d 713 .valp = &glob_conf.buffer_frames,
98f9f48c 714 .descr = "Size of the buffer in frames"
715 },
716 {
717 .name = "BUFFER_COUNT",
718 .tag = AUD_OPT_INT,
d1f52a1d 719 .valp = &glob_conf.nbuffers,
98f9f48c 720 .descr = "Number of buffers"
721 },
2700efa3 722 { /* End of list */ }
1d14ffa9
FB
723};
724
35f4b58c 725static struct audio_pcm_ops coreaudio_pcm_ops = {
1dd3e4d1
JQ
726 .init_out = coreaudio_init_out,
727 .fini_out = coreaudio_fini_out,
728 .run_out = coreaudio_run_out,
729 .write = coreaudio_write,
730 .ctl_out = coreaudio_ctl_out
1d14ffa9
FB
731};
732
733struct audio_driver coreaudio_audio_driver = {
bee37f32
JQ
734 .name = "coreaudio",
735 .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
736 .options = coreaudio_options,
737 .init = coreaudio_audio_init,
738 .fini = coreaudio_audio_fini,
739 .pcm_ops = &coreaudio_pcm_ops,
740 .can_be_default = 1,
741 .max_voices_out = 1,
742 .max_voices_in = 0,
743 .voice_size_out = sizeof (coreaudioVoiceOut),
744 .voice_size_in = 0
1d14ffa9 745};