]> git.proxmox.com Git - mirror_qemu.git/blob - audio/coreaudio.m
3186b68474d084f2f3318ec13952acdd52dd5cc5
[mirror_qemu.git] / audio / coreaudio.m
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
25 #include "qemu/osdep.h"
26 #include <CoreAudio/CoreAudio.h>
27 #include <pthread.h> /* pthread_X */
28
29 #include "qemu/main-loop.h"
30 #include "qemu/module.h"
31 #include "audio.h"
32
33 #define AUDIO_CAP "coreaudio"
34 #include "audio_int.h"
35
36 typedef struct coreaudioVoiceOut {
37 HWVoiceOut hw;
38 pthread_mutex_t buf_mutex;
39 AudioDeviceID outputDeviceID;
40 int frameSizeSetting;
41 uint32_t bufferCount;
42 UInt32 audioDevicePropertyBufferFrameSize;
43 AudioDeviceIOProcID ioprocid;
44 bool enabled;
45 } coreaudioVoiceOut;
46
47 #if !defined(MAC_OS_VERSION_12_0) \
48 || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_12_0)
49 #define kAudioObjectPropertyElementMain kAudioObjectPropertyElementMaster
50 #endif
51
52 static const AudioObjectPropertyAddress voice_addr = {
53 kAudioHardwarePropertyDefaultOutputDevice,
54 kAudioObjectPropertyScopeGlobal,
55 kAudioObjectPropertyElementMain
56 };
57
58 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
59 {
60 UInt32 size = sizeof(*id);
61
62 return AudioObjectGetPropertyData(kAudioObjectSystemObject,
63 &voice_addr,
64 0,
65 NULL,
66 &size,
67 id);
68 }
69
70 static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
71 AudioValueRange *framerange)
72 {
73 UInt32 size = sizeof(*framerange);
74 AudioObjectPropertyAddress addr = {
75 kAudioDevicePropertyBufferFrameSizeRange,
76 kAudioDevicePropertyScopeOutput,
77 kAudioObjectPropertyElementMain
78 };
79
80 return AudioObjectGetPropertyData(id,
81 &addr,
82 0,
83 NULL,
84 &size,
85 framerange);
86 }
87
88 static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
89 {
90 UInt32 size = sizeof(*framesize);
91 AudioObjectPropertyAddress addr = {
92 kAudioDevicePropertyBufferFrameSize,
93 kAudioDevicePropertyScopeOutput,
94 kAudioObjectPropertyElementMain
95 };
96
97 return AudioObjectGetPropertyData(id,
98 &addr,
99 0,
100 NULL,
101 &size,
102 framesize);
103 }
104
105 static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
106 {
107 UInt32 size = sizeof(*framesize);
108 AudioObjectPropertyAddress addr = {
109 kAudioDevicePropertyBufferFrameSize,
110 kAudioDevicePropertyScopeOutput,
111 kAudioObjectPropertyElementMain
112 };
113
114 return AudioObjectSetPropertyData(id,
115 &addr,
116 0,
117 NULL,
118 size,
119 framesize);
120 }
121
122 static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
123 AudioStreamBasicDescription *d)
124 {
125 UInt32 size = sizeof(*d);
126 AudioObjectPropertyAddress addr = {
127 kAudioDevicePropertyStreamFormat,
128 kAudioDevicePropertyScopeOutput,
129 kAudioObjectPropertyElementMain
130 };
131
132 return AudioObjectSetPropertyData(id,
133 &addr,
134 0,
135 NULL,
136 size,
137 d);
138 }
139
140 static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
141 {
142 UInt32 size = sizeof(*result);
143 AudioObjectPropertyAddress addr = {
144 kAudioDevicePropertyDeviceIsRunning,
145 kAudioDevicePropertyScopeOutput,
146 kAudioObjectPropertyElementMain
147 };
148
149 return AudioObjectGetPropertyData(id,
150 &addr,
151 0,
152 NULL,
153 &size,
154 result);
155 }
156
157 static void coreaudio_logstatus (OSStatus status)
158 {
159 const char *str = "BUG";
160
161 switch (status) {
162 case kAudioHardwareNoError:
163 str = "kAudioHardwareNoError";
164 break;
165
166 case kAudioHardwareNotRunningError:
167 str = "kAudioHardwareNotRunningError";
168 break;
169
170 case kAudioHardwareUnspecifiedError:
171 str = "kAudioHardwareUnspecifiedError";
172 break;
173
174 case kAudioHardwareUnknownPropertyError:
175 str = "kAudioHardwareUnknownPropertyError";
176 break;
177
178 case kAudioHardwareBadPropertySizeError:
179 str = "kAudioHardwareBadPropertySizeError";
180 break;
181
182 case kAudioHardwareIllegalOperationError:
183 str = "kAudioHardwareIllegalOperationError";
184 break;
185
186 case kAudioHardwareBadDeviceError:
187 str = "kAudioHardwareBadDeviceError";
188 break;
189
190 case kAudioHardwareBadStreamError:
191 str = "kAudioHardwareBadStreamError";
192 break;
193
194 case kAudioHardwareUnsupportedOperationError:
195 str = "kAudioHardwareUnsupportedOperationError";
196 break;
197
198 case kAudioDeviceUnsupportedFormatError:
199 str = "kAudioDeviceUnsupportedFormatError";
200 break;
201
202 case kAudioDevicePermissionsError:
203 str = "kAudioDevicePermissionsError";
204 break;
205
206 default:
207 AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
208 return;
209 }
210
211 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
212 }
213
214 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
215 OSStatus status,
216 const char *fmt,
217 ...
218 )
219 {
220 va_list ap;
221
222 va_start (ap, fmt);
223 AUD_log (AUDIO_CAP, fmt, ap);
224 va_end (ap);
225
226 coreaudio_logstatus (status);
227 }
228
229 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
230 OSStatus status,
231 const char *typ,
232 const char *fmt,
233 ...
234 )
235 {
236 va_list ap;
237
238 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
239
240 va_start (ap, fmt);
241 AUD_vlog (AUDIO_CAP, fmt, ap);
242 va_end (ap);
243
244 coreaudio_logstatus (status);
245 }
246
247 #define coreaudio_playback_logerr(status, ...) \
248 coreaudio_logerr2(status, "playback", __VA_ARGS__)
249
250 static int coreaudio_buf_lock (coreaudioVoiceOut *core, const char *fn_name)
251 {
252 int err;
253
254 err = pthread_mutex_lock (&core->buf_mutex);
255 if (err) {
256 dolog ("Could not lock voice for %s\nReason: %s\n",
257 fn_name, strerror (err));
258 return -1;
259 }
260 return 0;
261 }
262
263 static int coreaudio_buf_unlock (coreaudioVoiceOut *core, const char *fn_name)
264 {
265 int err;
266
267 err = pthread_mutex_unlock (&core->buf_mutex);
268 if (err) {
269 dolog ("Could not unlock voice for %s\nReason: %s\n",
270 fn_name, strerror (err));
271 return -1;
272 }
273 return 0;
274 }
275
276 #define COREAUDIO_WRAPPER_FUNC(name, ret_type, args_decl, args) \
277 static ret_type glue(coreaudio_, name)args_decl \
278 { \
279 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; \
280 ret_type ret; \
281 \
282 if (coreaudio_buf_lock(core, "coreaudio_" #name)) { \
283 return 0; \
284 } \
285 \
286 ret = glue(audio_generic_, name)args; \
287 \
288 coreaudio_buf_unlock(core, "coreaudio_" #name); \
289 return ret; \
290 }
291 COREAUDIO_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
292 COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
293 (hw, size))
294 COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
295 (HWVoiceOut *hw, void *buf, size_t size),
296 (hw, buf, size))
297 COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
298 (hw, buf, size))
299 #undef COREAUDIO_WRAPPER_FUNC
300
301 /*
302 * callback to feed audiooutput buffer. called without iothread lock.
303 * allowed to lock "buf_mutex", but disallowed to have any other locks.
304 */
305 static OSStatus audioDeviceIOProc(
306 AudioDeviceID inDevice,
307 const AudioTimeStamp *inNow,
308 const AudioBufferList *inInputData,
309 const AudioTimeStamp *inInputTime,
310 AudioBufferList *outOutputData,
311 const AudioTimeStamp *inOutputTime,
312 void *hwptr)
313 {
314 UInt32 frameCount, pending_frames;
315 void *out = outOutputData->mBuffers[0].mData;
316 HWVoiceOut *hw = hwptr;
317 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
318 size_t len;
319
320 if (coreaudio_buf_lock (core, "audioDeviceIOProc")) {
321 inInputTime = 0;
322 return 0;
323 }
324
325 if (inDevice != core->outputDeviceID) {
326 coreaudio_buf_unlock (core, "audioDeviceIOProc(old device)");
327 return 0;
328 }
329
330 frameCount = core->audioDevicePropertyBufferFrameSize;
331 pending_frames = hw->pending_emul / hw->info.bytes_per_frame;
332
333 /* if there are not enough samples, set signal and return */
334 if (pending_frames < frameCount) {
335 inInputTime = 0;
336 coreaudio_buf_unlock (core, "audioDeviceIOProc(empty)");
337 return 0;
338 }
339
340 len = frameCount * hw->info.bytes_per_frame;
341 while (len) {
342 size_t write_len, start;
343
344 start = audio_ring_posb(hw->pos_emul, hw->pending_emul, hw->size_emul);
345 assert(start < hw->size_emul);
346
347 write_len = MIN(MIN(hw->pending_emul, len),
348 hw->size_emul - start);
349
350 memcpy(out, hw->buf_emul + start, write_len);
351 hw->pending_emul -= write_len;
352 len -= write_len;
353 out += write_len;
354 }
355
356 coreaudio_buf_unlock (core, "audioDeviceIOProc");
357 return 0;
358 }
359
360 static OSStatus init_out_device(coreaudioVoiceOut *core)
361 {
362 OSStatus status;
363 AudioValueRange frameRange;
364
365 AudioStreamBasicDescription streamBasicDescription = {
366 .mBitsPerChannel = core->hw.info.bits,
367 .mBytesPerFrame = core->hw.info.bytes_per_frame,
368 .mBytesPerPacket = core->hw.info.bytes_per_frame,
369 .mChannelsPerFrame = core->hw.info.nchannels,
370 .mFormatFlags = kLinearPCMFormatFlagIsFloat,
371 .mFormatID = kAudioFormatLinearPCM,
372 .mFramesPerPacket = 1,
373 .mSampleRate = core->hw.info.freq
374 };
375
376 status = coreaudio_get_voice(&core->outputDeviceID);
377 if (status != kAudioHardwareNoError) {
378 coreaudio_playback_logerr (status,
379 "Could not get default output Device\n");
380 return status;
381 }
382 if (core->outputDeviceID == kAudioDeviceUnknown) {
383 dolog ("Could not initialize playback - Unknown Audiodevice\n");
384 return status;
385 }
386
387 /* get minimum and maximum buffer frame sizes */
388 status = coreaudio_get_framesizerange(core->outputDeviceID,
389 &frameRange);
390 if (status == kAudioHardwareBadObjectError) {
391 return 0;
392 }
393 if (status != kAudioHardwareNoError) {
394 coreaudio_playback_logerr (status,
395 "Could not get device buffer frame range\n");
396 return status;
397 }
398
399 if (frameRange.mMinimum > core->frameSizeSetting) {
400 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
401 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
402 } else if (frameRange.mMaximum < core->frameSizeSetting) {
403 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
404 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
405 } else {
406 core->audioDevicePropertyBufferFrameSize = core->frameSizeSetting;
407 }
408
409 /* set Buffer Frame Size */
410 status = coreaudio_set_framesize(core->outputDeviceID,
411 &core->audioDevicePropertyBufferFrameSize);
412 if (status == kAudioHardwareBadObjectError) {
413 return 0;
414 }
415 if (status != kAudioHardwareNoError) {
416 coreaudio_playback_logerr (status,
417 "Could not set device buffer frame size %" PRIu32 "\n",
418 (uint32_t)core->audioDevicePropertyBufferFrameSize);
419 return status;
420 }
421
422 /* get Buffer Frame Size */
423 status = coreaudio_get_framesize(core->outputDeviceID,
424 &core->audioDevicePropertyBufferFrameSize);
425 if (status == kAudioHardwareBadObjectError) {
426 return 0;
427 }
428 if (status != kAudioHardwareNoError) {
429 coreaudio_playback_logerr (status,
430 "Could not get device buffer frame size\n");
431 return status;
432 }
433 core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize;
434
435 /* set Samplerate */
436 status = coreaudio_set_streamformat(core->outputDeviceID,
437 &streamBasicDescription);
438 if (status == kAudioHardwareBadObjectError) {
439 return 0;
440 }
441 if (status != kAudioHardwareNoError) {
442 coreaudio_playback_logerr (status,
443 "Could not set samplerate %lf\n",
444 streamBasicDescription.mSampleRate);
445 core->outputDeviceID = kAudioDeviceUnknown;
446 return status;
447 }
448
449 /*
450 * set Callback.
451 *
452 * On macOS 11.3.1, Core Audio calls AudioDeviceIOProc after calling an
453 * internal function named HALB_Mutex::Lock(), which locks a mutex in
454 * HALB_IOThread::Entry(void*). HALB_Mutex::Lock() is also called in
455 * AudioObjectGetPropertyData, which is called by coreaudio driver.
456 * Therefore, the specified callback must be designed to avoid a deadlock
457 * with the callers of AudioObjectGetPropertyData.
458 */
459 core->ioprocid = NULL;
460 status = AudioDeviceCreateIOProcID(core->outputDeviceID,
461 audioDeviceIOProc,
462 &core->hw,
463 &core->ioprocid);
464 if (status == kAudioHardwareBadDeviceError) {
465 return 0;
466 }
467 if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
468 coreaudio_playback_logerr (status, "Could not set IOProc\n");
469 core->outputDeviceID = kAudioDeviceUnknown;
470 return status;
471 }
472
473 return 0;
474 }
475
476 static void fini_out_device(coreaudioVoiceOut *core)
477 {
478 OSStatus status;
479 UInt32 isrunning;
480
481 /* stop playback */
482 status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning);
483 if (status != kAudioHardwareBadObjectError) {
484 if (status != kAudioHardwareNoError) {
485 coreaudio_logerr(status,
486 "Could not determine whether Device is playing\n");
487 }
488
489 if (isrunning) {
490 status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
491 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
492 coreaudio_logerr(status, "Could not stop playback\n");
493 }
494 }
495 }
496
497 /* remove callback */
498 status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
499 core->ioprocid);
500 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
501 coreaudio_logerr(status, "Could not remove IOProc\n");
502 }
503 core->outputDeviceID = kAudioDeviceUnknown;
504 }
505
506 static void update_device_playback_state(coreaudioVoiceOut *core)
507 {
508 OSStatus status;
509 UInt32 isrunning;
510
511 status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning);
512 if (status != kAudioHardwareNoError) {
513 if (status != kAudioHardwareBadObjectError) {
514 coreaudio_logerr(status,
515 "Could not determine whether Device is playing\n");
516 }
517
518 return;
519 }
520
521 if (core->enabled) {
522 /* start playback */
523 if (!isrunning) {
524 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
525 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
526 coreaudio_logerr (status, "Could not resume playback\n");
527 }
528 }
529 } else {
530 /* stop playback */
531 if (isrunning) {
532 status = AudioDeviceStop(core->outputDeviceID,
533 core->ioprocid);
534 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
535 coreaudio_logerr(status, "Could not pause playback\n");
536 }
537 }
538 }
539 }
540
541 /* called without iothread lock. */
542 static OSStatus handle_voice_change(
543 AudioObjectID in_object_id,
544 UInt32 in_number_addresses,
545 const AudioObjectPropertyAddress *in_addresses,
546 void *in_client_data)
547 {
548 coreaudioVoiceOut *core = in_client_data;
549
550 qemu_mutex_lock_iothread();
551
552 if (core->outputDeviceID) {
553 fini_out_device(core);
554 }
555
556 if (!init_out_device(core)) {
557 update_device_playback_state(core);
558 }
559
560 qemu_mutex_unlock_iothread();
561 return 0;
562 }
563
564 static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
565 void *drv_opaque)
566 {
567 OSStatus status;
568 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
569 int err;
570 Audiodev *dev = drv_opaque;
571 AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
572 struct audsettings obt_as;
573
574 /* create mutex */
575 err = pthread_mutex_init(&core->buf_mutex, NULL);
576 if (err) {
577 dolog("Could not create mutex\nReason: %s\n", strerror (err));
578 return -1;
579 }
580
581 obt_as = *as;
582 as = &obt_as;
583 as->fmt = AUDIO_FORMAT_F32;
584 audio_pcm_init_info (&hw->info, as);
585
586 core->frameSizeSetting = audio_buffer_frames(
587 qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
588
589 core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4;
590
591 status = AudioObjectAddPropertyListener(kAudioObjectSystemObject,
592 &voice_addr, handle_voice_change,
593 core);
594 if (status != kAudioHardwareNoError) {
595 coreaudio_playback_logerr (status,
596 "Could not listen to voice property change\n");
597 return -1;
598 }
599
600 if (init_out_device(core)) {
601 status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
602 &voice_addr,
603 handle_voice_change,
604 core);
605 if (status != kAudioHardwareNoError) {
606 coreaudio_playback_logerr(status,
607 "Could not remove voice property change listener\n");
608 }
609
610 return -1;
611 }
612
613 return 0;
614 }
615
616 static void coreaudio_fini_out (HWVoiceOut *hw)
617 {
618 OSStatus status;
619 int err;
620 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
621
622 status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
623 &voice_addr,
624 handle_voice_change,
625 core);
626 if (status != kAudioHardwareNoError) {
627 coreaudio_logerr(status, "Could not remove voice property change listener\n");
628 }
629
630 fini_out_device(core);
631
632 /* destroy mutex */
633 err = pthread_mutex_destroy(&core->buf_mutex);
634 if (err) {
635 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
636 }
637 }
638
639 static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)
640 {
641 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
642
643 core->enabled = enable;
644 update_device_playback_state(core);
645 }
646
647 static void *coreaudio_audio_init(Audiodev *dev)
648 {
649 return dev;
650 }
651
652 static void coreaudio_audio_fini (void *opaque)
653 {
654 }
655
656 static struct audio_pcm_ops coreaudio_pcm_ops = {
657 .init_out = coreaudio_init_out,
658 .fini_out = coreaudio_fini_out,
659 /* wrapper for audio_generic_write */
660 .write = coreaudio_write,
661 /* wrapper for audio_generic_buffer_get_free */
662 .buffer_get_free = coreaudio_buffer_get_free,
663 /* wrapper for audio_generic_get_buffer_out */
664 .get_buffer_out = coreaudio_get_buffer_out,
665 /* wrapper for audio_generic_put_buffer_out */
666 .put_buffer_out = coreaudio_put_buffer_out,
667 .enable_out = coreaudio_enable_out
668 };
669
670 static struct audio_driver coreaudio_audio_driver = {
671 .name = "coreaudio",
672 .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
673 .init = coreaudio_audio_init,
674 .fini = coreaudio_audio_fini,
675 .pcm_ops = &coreaudio_pcm_ops,
676 .can_be_default = 1,
677 .max_voices_out = 1,
678 .max_voices_in = 0,
679 .voice_size_out = sizeof (coreaudioVoiceOut),
680 .voice_size_in = 0
681 };
682
683 static void register_audio_coreaudio(void)
684 {
685 audio_driver_register(&coreaudio_audio_driver);
686 }
687 type_init(register_audio_coreaudio);