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