blob: 638c60b300b2fe7d50fa01633a1e843e1fe06f8c [file] [log] [blame]
bellard1d14ffa2005-10-30 18:58:22 +00001/*
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
Peter Maydell6086a562016-01-18 17:33:52 +000025#include "qemu/osdep.h"
bellard1d14ffa2005-10-30 18:58:22 +000026#include <CoreAudio/CoreAudio.h>
bellard1d14ffa2005-10-30 18:58:22 +000027#include <pthread.h> /* pthread_X */
28
pbrook749bc4b2007-11-17 17:35:54 +000029#include "qemu-common.h"
30#include "audio.h"
bellard1d14ffa2005-10-30 18:58:22 +000031
32#define AUDIO_CAP "coreaudio"
33#include "audio_int.h"
34
Peter Maydell624d1fc2015-11-28 21:55:21 +000035#ifndef MAC_OS_X_VERSION_10_6
36#define MAC_OS_X_VERSION_10_6 1060
37#endif
38
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +020039typedef struct {
bellard1d14ffa2005-10-30 18:58:22 +000040 int buffer_frames;
bellarde59c1132005-11-20 18:53:42 +000041 int nbuffers;
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +020042} CoreaudioConf;
bellard1d14ffa2005-10-30 18:58:22 +000043
44typedef struct coreaudioVoiceOut {
45 HWVoiceOut hw;
46 pthread_mutex_t mutex;
47 AudioDeviceID outputDeviceID;
bellard5e941d42005-11-20 16:24:09 +000048 UInt32 audioDevicePropertyBufferFrameSize;
bellard1d14ffa2005-10-30 18:58:22 +000049 AudioStreamBasicDescription outputStreamBasicDescription;
Peter Maydell2f79a182015-11-28 21:55:24 +000050 AudioDeviceIOProcID ioprocid;
bellard1d14ffa2005-10-30 18:58:22 +000051 int live;
52 int decr;
53 int rpos;
54} coreaudioVoiceOut;
55
Peter Maydell624d1fc2015-11-28 21:55:21 +000056#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
57/* The APIs used here only become available from 10.6 */
58
59static OSStatus coreaudio_get_voice(AudioDeviceID *id)
60{
61 UInt32 size = sizeof(*id);
62 AudioObjectPropertyAddress addr = {
63 kAudioHardwarePropertyDefaultOutputDevice,
64 kAudioObjectPropertyScopeGlobal,
65 kAudioObjectPropertyElementMaster
66 };
67
68 return AudioObjectGetPropertyData(kAudioObjectSystemObject,
69 &addr,
70 0,
71 NULL,
72 &size,
73 id);
74}
Peter Maydell2d99f622015-11-28 21:55:23 +000075
76static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
77 AudioValueRange *framerange)
78{
79 UInt32 size = sizeof(*framerange);
80 AudioObjectPropertyAddress addr = {
81 kAudioDevicePropertyBufferFrameSizeRange,
82 kAudioDevicePropertyScopeOutput,
83 kAudioObjectPropertyElementMaster
84 };
85
86 return AudioObjectGetPropertyData(id,
87 &addr,
88 0,
89 NULL,
90 &size,
91 framerange);
92}
93
94static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
95{
96 UInt32 size = sizeof(*framesize);
97 AudioObjectPropertyAddress addr = {
98 kAudioDevicePropertyBufferFrameSize,
99 kAudioDevicePropertyScopeOutput,
100 kAudioObjectPropertyElementMaster
101 };
102
103 return AudioObjectGetPropertyData(id,
104 &addr,
105 0,
106 NULL,
107 &size,
108 framesize);
109}
110
111static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
112{
113 UInt32 size = sizeof(*framesize);
114 AudioObjectPropertyAddress addr = {
115 kAudioDevicePropertyBufferFrameSize,
116 kAudioDevicePropertyScopeOutput,
117 kAudioObjectPropertyElementMaster
118 };
119
120 return AudioObjectSetPropertyData(id,
121 &addr,
122 0,
123 NULL,
124 size,
125 framesize);
126}
127
128static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
129 AudioStreamBasicDescription *d)
130{
131 UInt32 size = sizeof(*d);
132 AudioObjectPropertyAddress addr = {
133 kAudioDevicePropertyStreamFormat,
134 kAudioDevicePropertyScopeOutput,
135 kAudioObjectPropertyElementMaster
136 };
137
138 return AudioObjectGetPropertyData(id,
139 &addr,
140 0,
141 NULL,
142 &size,
143 d);
144}
145
146static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
147 AudioStreamBasicDescription *d)
148{
149 UInt32 size = sizeof(*d);
150 AudioObjectPropertyAddress addr = {
151 kAudioDevicePropertyStreamFormat,
152 kAudioDevicePropertyScopeOutput,
153 kAudioObjectPropertyElementMaster
154 };
155
156 return AudioObjectSetPropertyData(id,
157 &addr,
158 0,
159 NULL,
160 size,
161 d);
162}
163
164static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
165{
166 UInt32 size = sizeof(*result);
167 AudioObjectPropertyAddress addr = {
168 kAudioDevicePropertyDeviceIsRunning,
169 kAudioDevicePropertyScopeOutput,
170 kAudioObjectPropertyElementMaster
171 };
172
173 return AudioObjectGetPropertyData(id,
174 &addr,
175 0,
176 NULL,
177 &size,
178 result);
179}
Peter Maydell624d1fc2015-11-28 21:55:21 +0000180#else
181/* Legacy versions of functions using deprecated APIs */
182
Peter Maydell88a0f832015-11-28 21:55:20 +0000183static OSStatus coreaudio_get_voice(AudioDeviceID *id)
184{
185 UInt32 size = sizeof(*id);
186
187 return AudioHardwareGetProperty(
188 kAudioHardwarePropertyDefaultOutputDevice,
189 &size,
190 id);
191}
192
Peter Maydell95a860f2015-11-28 21:55:22 +0000193static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
194 AudioValueRange *framerange)
195{
196 UInt32 size = sizeof(*framerange);
197
198 return AudioDeviceGetProperty(
199 id,
200 0,
201 0,
202 kAudioDevicePropertyBufferFrameSizeRange,
203 &size,
204 framerange);
205}
206
207static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
208{
209 UInt32 size = sizeof(*framesize);
210
211 return AudioDeviceGetProperty(
212 id,
213 0,
214 false,
215 kAudioDevicePropertyBufferFrameSize,
216 &size,
217 framesize);
218}
219
220static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
221{
222 UInt32 size = sizeof(*framesize);
223
224 return AudioDeviceSetProperty(
225 id,
226 NULL,
227 0,
228 false,
229 kAudioDevicePropertyBufferFrameSize,
230 size,
231 framesize);
232}
233
234static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
235 AudioStreamBasicDescription *d)
236{
237 UInt32 size = sizeof(*d);
238
239 return AudioDeviceGetProperty(
240 id,
241 0,
242 false,
243 kAudioDevicePropertyStreamFormat,
244 &size,
245 d);
246}
247
248static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
249 AudioStreamBasicDescription *d)
250{
251 UInt32 size = sizeof(*d);
252
253 return AudioDeviceSetProperty(
254 id,
255 0,
256 0,
257 0,
258 kAudioDevicePropertyStreamFormat,
259 size,
260 d);
261}
262
263static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
264{
265 UInt32 size = sizeof(*result);
266
267 return AudioDeviceGetProperty(
268 id,
269 0,
270 0,
271 kAudioDevicePropertyDeviceIsRunning,
272 &size,
273 result);
274}
Peter Maydell2d99f622015-11-28 21:55:23 +0000275#endif
Peter Maydell95a860f2015-11-28 21:55:22 +0000276
bellard1d14ffa2005-10-30 18:58:22 +0000277static void coreaudio_logstatus (OSStatus status)
278{
Alexandre Raymondd9cbb0f2011-05-27 13:22:28 -0400279 const char *str = "BUG";
bellard1d14ffa2005-10-30 18:58:22 +0000280
281 switch(status) {
282 case kAudioHardwareNoError:
283 str = "kAudioHardwareNoError";
284 break;
285
286 case kAudioHardwareNotRunningError:
287 str = "kAudioHardwareNotRunningError";
288 break;
289
290 case kAudioHardwareUnspecifiedError:
291 str = "kAudioHardwareUnspecifiedError";
292 break;
293
294 case kAudioHardwareUnknownPropertyError:
295 str = "kAudioHardwareUnknownPropertyError";
296 break;
297
298 case kAudioHardwareBadPropertySizeError:
299 str = "kAudioHardwareBadPropertySizeError";
300 break;
301
302 case kAudioHardwareIllegalOperationError:
303 str = "kAudioHardwareIllegalOperationError";
304 break;
305
306 case kAudioHardwareBadDeviceError:
307 str = "kAudioHardwareBadDeviceError";
308 break;
309
310 case kAudioHardwareBadStreamError:
311 str = "kAudioHardwareBadStreamError";
312 break;
313
314 case kAudioHardwareUnsupportedOperationError:
315 str = "kAudioHardwareUnsupportedOperationError";
316 break;
317
318 case kAudioDeviceUnsupportedFormatError:
319 str = "kAudioDeviceUnsupportedFormatError";
320 break;
321
322 case kAudioDevicePermissionsError:
323 str = "kAudioDevicePermissionsError";
324 break;
325
326 default:
Andreas Färber744d3642011-06-23 16:24:45 +0200327 AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
bellard1d14ffa2005-10-30 18:58:22 +0000328 return;
329 }
330
331 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
332}
333
334static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
335 OSStatus status,
336 const char *fmt,
337 ...
338 )
339{
340 va_list ap;
341
342 va_start (ap, fmt);
343 AUD_log (AUDIO_CAP, fmt, ap);
344 va_end (ap);
345
346 coreaudio_logstatus (status);
347}
348
349static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
350 OSStatus status,
351 const char *typ,
352 const char *fmt,
353 ...
354 )
355{
356 va_list ap;
357
bellardc0fe3822005-11-05 18:55:28 +0000358 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
bellard1d14ffa2005-10-30 18:58:22 +0000359
360 va_start (ap, fmt);
361 AUD_vlog (AUDIO_CAP, fmt, ap);
362 va_end (ap);
363
364 coreaudio_logstatus (status);
365}
366
bellard5e941d42005-11-20 16:24:09 +0000367static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
368{
369 OSStatus status;
370 UInt32 result = 0;
Peter Maydell95a860f2015-11-28 21:55:22 +0000371 status = coreaudio_get_isrunning(outputDeviceID, &result);
bellard5e941d42005-11-20 16:24:09 +0000372 if (status != kAudioHardwareNoError) {
373 coreaudio_logerr(status,
374 "Could not determine whether Device is playing\n");
375 }
376 return result;
377}
378
bellard1d14ffa2005-10-30 18:58:22 +0000379static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
380{
381 int err;
382
383 err = pthread_mutex_lock (&core->mutex);
384 if (err) {
bellardc0fe3822005-11-05 18:55:28 +0000385 dolog ("Could not lock voice for %s\nReason: %s\n",
bellard1d14ffa2005-10-30 18:58:22 +0000386 fn_name, strerror (err));
387 return -1;
388 }
389 return 0;
390}
391
392static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
393{
394 int err;
395
396 err = pthread_mutex_unlock (&core->mutex);
397 if (err) {
bellardc0fe3822005-11-05 18:55:28 +0000398 dolog ("Could not unlock voice for %s\nReason: %s\n",
bellard1d14ffa2005-10-30 18:58:22 +0000399 fn_name, strerror (err));
400 return -1;
401 }
402 return 0;
403}
404
malcbdff2532009-09-18 11:37:39 +0400405static int coreaudio_run_out (HWVoiceOut *hw, int live)
bellard1d14ffa2005-10-30 18:58:22 +0000406{
malcbdff2532009-09-18 11:37:39 +0400407 int decr;
bellard1d14ffa2005-10-30 18:58:22 +0000408 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
409
410 if (coreaudio_lock (core, "coreaudio_run_out")) {
411 return 0;
412 }
413
bellard1d14ffa2005-10-30 18:58:22 +0000414 if (core->decr > live) {
415 ldebug ("core->decr %d live %d core->live %d\n",
416 core->decr,
417 live,
418 core->live);
419 }
420
421 decr = audio_MIN (core->decr, live);
422 core->decr -= decr;
423
424 core->live = live - decr;
425 hw->rpos = core->rpos;
426
427 coreaudio_unlock (core, "coreaudio_run_out");
428 return decr;
429}
430
431/* callback to feed audiooutput buffer */
432static OSStatus audioDeviceIOProc(
433 AudioDeviceID inDevice,
434 const AudioTimeStamp* inNow,
435 const AudioBufferList* inInputData,
436 const AudioTimeStamp* inInputTime,
437 AudioBufferList* outOutputData,
438 const AudioTimeStamp* inOutputTime,
439 void* hwptr)
440{
bellard5e941d42005-11-20 16:24:09 +0000441 UInt32 frame, frameCount;
bellard1d14ffa2005-10-30 18:58:22 +0000442 float *out = outOutputData->mBuffers[0].mData;
443 HWVoiceOut *hw = hwptr;
444 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
445 int rpos, live;
malc1ea879e2008-12-03 22:48:44 +0000446 struct st_sample *src;
bellard1d14ffa2005-10-30 18:58:22 +0000447#ifndef FLOAT_MIXENG
448#ifdef RECIPROCAL
449 const float scale = 1.f / UINT_MAX;
450#else
451 const float scale = UINT_MAX;
452#endif
453#endif
454
455 if (coreaudio_lock (core, "audioDeviceIOProc")) {
456 inInputTime = 0;
457 return 0;
458 }
459
bellard5e941d42005-11-20 16:24:09 +0000460 frameCount = core->audioDevicePropertyBufferFrameSize;
bellard1d14ffa2005-10-30 18:58:22 +0000461 live = core->live;
462
463 /* if there are not enough samples, set signal and return */
464 if (live < frameCount) {
465 inInputTime = 0;
466 coreaudio_unlock (core, "audioDeviceIOProc(empty)");
467 return 0;
468 }
469
470 rpos = core->rpos;
471 src = hw->mix_buf + rpos;
472
473 /* fill buffer */
474 for (frame = 0; frame < frameCount; frame++) {
475#ifdef FLOAT_MIXENG
476 *out++ = src[frame].l; /* left channel */
477 *out++ = src[frame].r; /* right channel */
478#else
479#ifdef RECIPROCAL
480 *out++ = src[frame].l * scale; /* left channel */
481 *out++ = src[frame].r * scale; /* right channel */
482#else
483 *out++ = src[frame].l / scale; /* left channel */
484 *out++ = src[frame].r / scale; /* right channel */
485#endif
486#endif
487 }
488
bellard1d14ffa2005-10-30 18:58:22 +0000489 rpos = (rpos + frameCount) % hw->samples;
bellard5e941d42005-11-20 16:24:09 +0000490 core->decr += frameCount;
bellard1d14ffa2005-10-30 18:58:22 +0000491 core->rpos = rpos;
492
493 coreaudio_unlock (core, "audioDeviceIOProc");
494 return 0;
495}
496
497static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
498{
499 return audio_pcm_sw_write (sw, buf, len);
500}
501
Kővágó, Zoltán5706db12015-06-03 23:03:47 +0200502static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
503 void *drv_opaque)
bellard1d14ffa2005-10-30 18:58:22 +0000504{
505 OSStatus status;
506 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
bellard1d14ffa2005-10-30 18:58:22 +0000507 int err;
bellard5e941d42005-11-20 16:24:09 +0000508 const char *typ = "playback";
509 AudioValueRange frameRange;
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +0200510 CoreaudioConf *conf = drv_opaque;
bellard1d14ffa2005-10-30 18:58:22 +0000511
512 /* create mutex */
513 err = pthread_mutex_init(&core->mutex, NULL);
514 if (err) {
bellardc0fe3822005-11-05 18:55:28 +0000515 dolog("Could not create mutex\nReason: %s\n", strerror (err));
bellard1d14ffa2005-10-30 18:58:22 +0000516 return -1;
517 }
518
bellardd929eba2006-07-04 21:47:22 +0000519 audio_pcm_init_info (&hw->info, as);
bellard1d14ffa2005-10-30 18:58:22 +0000520
Peter Maydell88a0f832015-11-28 21:55:20 +0000521 status = coreaudio_get_voice(&core->outputDeviceID);
bellard1d14ffa2005-10-30 18:58:22 +0000522 if (status != kAudioHardwareNoError) {
523 coreaudio_logerr2 (status, typ,
bellardc0fe3822005-11-05 18:55:28 +0000524 "Could not get default output Device\n");
bellard1d14ffa2005-10-30 18:58:22 +0000525 return -1;
526 }
527 if (core->outputDeviceID == kAudioDeviceUnknown) {
bellardc0fe3822005-11-05 18:55:28 +0000528 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
bellard1d14ffa2005-10-30 18:58:22 +0000529 return -1;
530 }
531
bellard5e941d42005-11-20 16:24:09 +0000532 /* get minimum and maximum buffer frame sizes */
Peter Maydell95a860f2015-11-28 21:55:22 +0000533 status = coreaudio_get_framesizerange(core->outputDeviceID,
534 &frameRange);
bellard5e941d42005-11-20 16:24:09 +0000535 if (status != kAudioHardwareNoError) {
536 coreaudio_logerr2 (status, typ,
537 "Could not get device buffer frame range\n");
538 return -1;
539 }
540
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +0200541 if (frameRange.mMinimum > conf->buffer_frames) {
bellard5e941d42005-11-20 16:24:09 +0000542 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
543 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
544 }
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +0200545 else if (frameRange.mMaximum < conf->buffer_frames) {
bellard5e941d42005-11-20 16:24:09 +0000546 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
547 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
548 }
549 else {
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +0200550 core->audioDevicePropertyBufferFrameSize = conf->buffer_frames;
bellard5e941d42005-11-20 16:24:09 +0000551 }
552
553 /* set Buffer Frame Size */
Peter Maydell95a860f2015-11-28 21:55:22 +0000554 status = coreaudio_set_framesize(core->outputDeviceID,
555 &core->audioDevicePropertyBufferFrameSize);
bellard1d14ffa2005-10-30 18:58:22 +0000556 if (status != kAudioHardwareNoError) {
557 coreaudio_logerr2 (status, typ,
Andreas Färbercbc36cb2011-06-23 16:24:46 +0200558 "Could not set device buffer frame size %" PRIu32 "\n",
559 (uint32_t)core->audioDevicePropertyBufferFrameSize);
bellard1d14ffa2005-10-30 18:58:22 +0000560 return -1;
561 }
562
bellard5e941d42005-11-20 16:24:09 +0000563 /* get Buffer Frame Size */
Peter Maydell95a860f2015-11-28 21:55:22 +0000564 status = coreaudio_get_framesize(core->outputDeviceID,
565 &core->audioDevicePropertyBufferFrameSize);
bellard1d14ffa2005-10-30 18:58:22 +0000566 if (status != kAudioHardwareNoError) {
bellard5e941d42005-11-20 16:24:09 +0000567 coreaudio_logerr2 (status, typ,
568 "Could not get device buffer frame size\n");
bellard1d14ffa2005-10-30 18:58:22 +0000569 return -1;
570 }
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +0200571 hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize;
bellard1d14ffa2005-10-30 18:58:22 +0000572
573 /* get StreamFormat */
Peter Maydell95a860f2015-11-28 21:55:22 +0000574 status = coreaudio_get_streamformat(core->outputDeviceID,
575 &core->outputStreamBasicDescription);
bellard1d14ffa2005-10-30 18:58:22 +0000576 if (status != kAudioHardwareNoError) {
577 coreaudio_logerr2 (status, typ,
bellardc0fe3822005-11-05 18:55:28 +0000578 "Could not get Device Stream properties\n");
bellard1d14ffa2005-10-30 18:58:22 +0000579 core->outputDeviceID = kAudioDeviceUnknown;
580 return -1;
581 }
582
583 /* set Samplerate */
bellard5e941d42005-11-20 16:24:09 +0000584 core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
Peter Maydell95a860f2015-11-28 21:55:22 +0000585 status = coreaudio_set_streamformat(core->outputDeviceID,
586 &core->outputStreamBasicDescription);
bellard1d14ffa2005-10-30 18:58:22 +0000587 if (status != kAudioHardwareNoError) {
bellard575b5dc2005-11-11 00:03:20 +0000588 coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
589 as->freq);
bellard1d14ffa2005-10-30 18:58:22 +0000590 core->outputDeviceID = kAudioDeviceUnknown;
591 return -1;
592 }
593
594 /* set Callback */
Peter Maydell2f79a182015-11-28 21:55:24 +0000595 core->ioprocid = NULL;
596 status = AudioDeviceCreateIOProcID(core->outputDeviceID,
597 audioDeviceIOProc,
598 hw,
599 &core->ioprocid);
600 if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
bellardc0fe3822005-11-05 18:55:28 +0000601 coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
bellard1d14ffa2005-10-30 18:58:22 +0000602 core->outputDeviceID = kAudioDeviceUnknown;
603 return -1;
604 }
605
606 /* start Playback */
bellard5e941d42005-11-20 16:24:09 +0000607 if (!isPlaying(core->outputDeviceID)) {
Peter Maydell2f79a182015-11-28 21:55:24 +0000608 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
bellard1d14ffa2005-10-30 18:58:22 +0000609 if (status != kAudioHardwareNoError) {
bellardc0fe3822005-11-05 18:55:28 +0000610 coreaudio_logerr2 (status, typ, "Could not start playback\n");
Peter Maydell2f79a182015-11-28 21:55:24 +0000611 AudioDeviceDestroyIOProcID(core->outputDeviceID, core->ioprocid);
bellard1d14ffa2005-10-30 18:58:22 +0000612 core->outputDeviceID = kAudioDeviceUnknown;
613 return -1;
614 }
bellard1d14ffa2005-10-30 18:58:22 +0000615 }
616
617 return 0;
618}
619
620static void coreaudio_fini_out (HWVoiceOut *hw)
621{
622 OSStatus status;
623 int err;
624 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
625
Marc-André Lureaua384c202016-08-01 15:23:43 +0400626 if (!audio_is_cleaning_up()) {
bellard5e941d42005-11-20 16:24:09 +0000627 /* stop playback */
628 if (isPlaying(core->outputDeviceID)) {
Peter Maydell2f79a182015-11-28 21:55:24 +0000629 status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
bellard5e941d42005-11-20 16:24:09 +0000630 if (status != kAudioHardwareNoError) {
631 coreaudio_logerr (status, "Could not stop playback\n");
632 }
bellard1d14ffa2005-10-30 18:58:22 +0000633 }
bellard1d14ffa2005-10-30 18:58:22 +0000634
bellard5e941d42005-11-20 16:24:09 +0000635 /* remove callback */
Peter Maydell2f79a182015-11-28 21:55:24 +0000636 status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
637 core->ioprocid);
bellard5e941d42005-11-20 16:24:09 +0000638 if (status != kAudioHardwareNoError) {
639 coreaudio_logerr (status, "Could not remove IOProc\n");
640 }
bellard1d14ffa2005-10-30 18:58:22 +0000641 }
642 core->outputDeviceID = kAudioDeviceUnknown;
643
644 /* destroy mutex */
645 err = pthread_mutex_destroy(&core->mutex);
646 if (err) {
bellardc0fe3822005-11-05 18:55:28 +0000647 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
bellard1d14ffa2005-10-30 18:58:22 +0000648 }
649}
650
651static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
652{
653 OSStatus status;
654 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
655
656 switch (cmd) {
657 case VOICE_ENABLE:
658 /* start playback */
bellard5e941d42005-11-20 16:24:09 +0000659 if (!isPlaying(core->outputDeviceID)) {
Peter Maydell2f79a182015-11-28 21:55:24 +0000660 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
bellard1d14ffa2005-10-30 18:58:22 +0000661 if (status != kAudioHardwareNoError) {
bellard5e941d42005-11-20 16:24:09 +0000662 coreaudio_logerr (status, "Could not resume playback\n");
bellard1d14ffa2005-10-30 18:58:22 +0000663 }
bellard1d14ffa2005-10-30 18:58:22 +0000664 }
665 break;
666
667 case VOICE_DISABLE:
668 /* stop playback */
Marc-André Lureaua384c202016-08-01 15:23:43 +0400669 if (!audio_is_cleaning_up()) {
bellard5e941d42005-11-20 16:24:09 +0000670 if (isPlaying(core->outputDeviceID)) {
Peter Maydell2f79a182015-11-28 21:55:24 +0000671 status = AudioDeviceStop(core->outputDeviceID,
672 core->ioprocid);
bellard5e941d42005-11-20 16:24:09 +0000673 if (status != kAudioHardwareNoError) {
674 coreaudio_logerr (status, "Could not pause playback\n");
675 }
bellard1d14ffa2005-10-30 18:58:22 +0000676 }
bellard1d14ffa2005-10-30 18:58:22 +0000677 }
678 break;
679 }
680 return 0;
681}
682
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +0200683static CoreaudioConf glob_conf = {
684 .buffer_frames = 512,
685 .nbuffers = 4,
686};
687
bellard1d14ffa2005-10-30 18:58:22 +0000688static void *coreaudio_audio_init (void)
689{
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +0200690 CoreaudioConf *conf = g_malloc(sizeof(CoreaudioConf));
691 *conf = glob_conf;
692
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +0200693 return conf;
bellard1d14ffa2005-10-30 18:58:22 +0000694}
695
696static void coreaudio_audio_fini (void *opaque)
697{
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +0200698 g_free(opaque);
bellard1d14ffa2005-10-30 18:58:22 +0000699}
700
701static struct audio_option coreaudio_options[] = {
malc98f9f482009-08-11 20:48:02 +0400702 {
703 .name = "BUFFER_SIZE",
704 .tag = AUD_OPT_INT,
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +0200705 .valp = &glob_conf.buffer_frames,
malc98f9f482009-08-11 20:48:02 +0400706 .descr = "Size of the buffer in frames"
707 },
708 {
709 .name = "BUFFER_COUNT",
710 .tag = AUD_OPT_INT,
Kővágó, Zoltánd1f52a12015-06-03 23:03:54 +0200711 .valp = &glob_conf.nbuffers,
malc98f9f482009-08-11 20:48:02 +0400712 .descr = "Number of buffers"
713 },
Juan Quintela2700efa2009-08-11 02:31:16 +0200714 { /* End of list */ }
bellard1d14ffa2005-10-30 18:58:22 +0000715};
716
blueswir135f4b582008-10-06 18:08:30 +0000717static struct audio_pcm_ops coreaudio_pcm_ops = {
Juan Quintela1dd3e4d2009-08-11 02:31:15 +0200718 .init_out = coreaudio_init_out,
719 .fini_out = coreaudio_fini_out,
720 .run_out = coreaudio_run_out,
721 .write = coreaudio_write,
722 .ctl_out = coreaudio_ctl_out
bellard1d14ffa2005-10-30 18:58:22 +0000723};
724
Gerd Hoffmannd3893a32018-03-06 08:40:47 +0100725static struct audio_driver coreaudio_audio_driver = {
Juan Quintelabee37f32009-08-11 02:31:14 +0200726 .name = "coreaudio",
727 .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
728 .options = coreaudio_options,
729 .init = coreaudio_audio_init,
730 .fini = coreaudio_audio_fini,
731 .pcm_ops = &coreaudio_pcm_ops,
732 .can_be_default = 1,
733 .max_voices_out = 1,
734 .max_voices_in = 0,
735 .voice_size_out = sizeof (coreaudioVoiceOut),
736 .voice_size_in = 0
bellard1d14ffa2005-10-30 18:58:22 +0000737};
Gerd Hoffmannd3893a32018-03-06 08:40:47 +0100738
739static void register_audio_coreaudio(void)
740{
741 audio_driver_register(&coreaudio_audio_driver);
742}
743type_init(register_audio_coreaudio);