Merge tag 'v9.0.0-rc3'
[qemu/ar7.git] / audio / coreaudio.m
blobab632b9bbbbdc1757c4d1fd41703fac53b18baab
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  */
25 #include "qemu/osdep.h"
26 #include <CoreAudio/CoreAudio.h>
27 #include <pthread.h>            /* pthread_X */
29 #include "qemu/main-loop.h"
30 #include "qemu/module.h"
31 #include "audio.h"
33 #define AUDIO_CAP "coreaudio"
34 #include "audio_int.h"
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;
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
52 static const AudioObjectPropertyAddress voice_addr = {
53     kAudioHardwarePropertyDefaultOutputDevice,
54     kAudioObjectPropertyScopeGlobal,
55     kAudioObjectPropertyElementMain
58 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
60     UInt32 size = sizeof(*id);
62     return AudioObjectGetPropertyData(kAudioObjectSystemObject,
63                                       &voice_addr,
64                                       0,
65                                       NULL,
66                                       &size,
67                                       id);
70 static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
71                                              AudioValueRange *framerange)
73     UInt32 size = sizeof(*framerange);
74     AudioObjectPropertyAddress addr = {
75         kAudioDevicePropertyBufferFrameSizeRange,
76         kAudioDevicePropertyScopeOutput,
77         kAudioObjectPropertyElementMain
78     };
80     return AudioObjectGetPropertyData(id,
81                                       &addr,
82                                       0,
83                                       NULL,
84                                       &size,
85                                       framerange);
88 static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
90     UInt32 size = sizeof(*framesize);
91     AudioObjectPropertyAddress addr = {
92         kAudioDevicePropertyBufferFrameSize,
93         kAudioDevicePropertyScopeOutput,
94         kAudioObjectPropertyElementMain
95     };
97     return AudioObjectGetPropertyData(id,
98                                       &addr,
99                                       0,
100                                       NULL,
101                                       &size,
102                                       framesize);
105 static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
107     UInt32 size = sizeof(*framesize);
108     AudioObjectPropertyAddress addr = {
109         kAudioDevicePropertyBufferFrameSize,
110         kAudioDevicePropertyScopeOutput,
111         kAudioObjectPropertyElementMain
112     };
114     return AudioObjectSetPropertyData(id,
115                                       &addr,
116                                       0,
117                                       NULL,
118                                       size,
119                                       framesize);
122 static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
123                                            AudioStreamBasicDescription *d)
125     UInt32 size = sizeof(*d);
126     AudioObjectPropertyAddress addr = {
127         kAudioDevicePropertyStreamFormat,
128         kAudioDevicePropertyScopeOutput,
129         kAudioObjectPropertyElementMain
130     };
132     return AudioObjectSetPropertyData(id,
133                                       &addr,
134                                       0,
135                                       NULL,
136                                       size,
137                                       d);
140 static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
142     UInt32 size = sizeof(*result);
143     AudioObjectPropertyAddress addr = {
144         kAudioDevicePropertyDeviceIsRunning,
145         kAudioDevicePropertyScopeOutput,
146         kAudioObjectPropertyElementMain
147     };
149     return AudioObjectGetPropertyData(id,
150                                       &addr,
151                                       0,
152                                       NULL,
153                                       &size,
154                                       result);
157 static void coreaudio_logstatus (OSStatus status)
159     const char *str = "BUG";
161     switch (status) {
162     case kAudioHardwareNoError:
163         str = "kAudioHardwareNoError";
164         break;
166     case kAudioHardwareNotRunningError:
167         str = "kAudioHardwareNotRunningError";
168         break;
170     case kAudioHardwareUnspecifiedError:
171         str = "kAudioHardwareUnspecifiedError";
172         break;
174     case kAudioHardwareUnknownPropertyError:
175         str = "kAudioHardwareUnknownPropertyError";
176         break;
178     case kAudioHardwareBadPropertySizeError:
179         str = "kAudioHardwareBadPropertySizeError";
180         break;
182     case kAudioHardwareIllegalOperationError:
183         str = "kAudioHardwareIllegalOperationError";
184         break;
186     case kAudioHardwareBadDeviceError:
187         str = "kAudioHardwareBadDeviceError";
188         break;
190     case kAudioHardwareBadStreamError:
191         str = "kAudioHardwareBadStreamError";
192         break;
194     case kAudioHardwareUnsupportedOperationError:
195         str = "kAudioHardwareUnsupportedOperationError";
196         break;
198     case kAudioDeviceUnsupportedFormatError:
199         str = "kAudioDeviceUnsupportedFormatError";
200         break;
202     case kAudioDevicePermissionsError:
203         str = "kAudioDevicePermissionsError";
204         break;
206     default:
207         AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
208         return;
209     }
211     AUD_log (AUDIO_CAP, "Reason: %s\n", str);
214 static void G_GNUC_PRINTF (2, 3) coreaudio_logerr (
215     OSStatus status,
216     const char *fmt,
217     ...
218     )
220     va_list ap;
222     va_start (ap, fmt);
223     AUD_log (AUDIO_CAP, fmt, ap);
224     va_end (ap);
226     coreaudio_logstatus (status);
229 static void G_GNUC_PRINTF (3, 4) coreaudio_logerr2 (
230     OSStatus status,
231     const char *typ,
232     const char *fmt,
233     ...
234     )
236     va_list ap;
238     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
240     va_start (ap, fmt);
241     AUD_vlog (AUDIO_CAP, fmt, ap);
242     va_end (ap);
244     coreaudio_logstatus (status);
247 #define coreaudio_playback_logerr(status, ...) \
248     coreaudio_logerr2(status, "playback", __VA_ARGS__)
250 static int coreaudio_buf_lock (coreaudioVoiceOut *core, const char *fn_name)
252     int err;
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;
263 static int coreaudio_buf_unlock (coreaudioVoiceOut *core, const char *fn_name)
265     int err;
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;
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
302  * callback to feed audiooutput buffer. called without BQL.
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)
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;
320     if (coreaudio_buf_lock (core, "audioDeviceIOProc")) {
321         inInputTime = 0;
322         return 0;
323     }
325     if (inDevice != core->outputDeviceID) {
326         coreaudio_buf_unlock (core, "audioDeviceIOProc(old device)");
327         return 0;
328     }
330     frameCount = core->audioDevicePropertyBufferFrameSize;
331     pending_frames = hw->pending_emul / hw->info.bytes_per_frame;
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     }
340     len = frameCount * hw->info.bytes_per_frame;
341     while (len) {
342         size_t write_len, start;
344         start = audio_ring_posb(hw->pos_emul, hw->pending_emul, hw->size_emul);
345         assert(start < hw->size_emul);
347         write_len = MIN(MIN(hw->pending_emul, len),
348                         hw->size_emul - start);
350         memcpy(out, hw->buf_emul + start, write_len);
351         hw->pending_emul -= write_len;
352         len -= write_len;
353         out += write_len;
354     }
356     coreaudio_buf_unlock (core, "audioDeviceIOProc");
357     return 0;
360 static OSStatus init_out_device(coreaudioVoiceOut *core)
362     OSStatus status;
363     AudioValueRange frameRange;
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     };
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     }
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     }
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     }
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     }
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;
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     }
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     }
473     return 0;
476 static void fini_out_device(coreaudioVoiceOut *core)
478     OSStatus status;
479     UInt32 isrunning;
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         }
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     }
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;
506 static void update_device_playback_state(coreaudioVoiceOut *core)
508     OSStatus status;
509     UInt32 isrunning;
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         }
518         return;
519     }
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     }
541 /* called without BQL. */
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)
548     coreaudioVoiceOut *core = in_client_data;
550     bql_lock();
552     if (core->outputDeviceID) {
553         fini_out_device(core);
554     }
556     if (!init_out_device(core)) {
557         update_device_playback_state(core);
558     }
560     bql_unlock();
561     return 0;
564 static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
565                               void *drv_opaque)
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;
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     }
581     obt_as = *as;
582     as = &obt_as;
583     as->fmt = AUDIO_FORMAT_F32;
584     audio_pcm_init_info (&hw->info, as);
586     core->frameSizeSetting = audio_buffer_frames(
587         qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
589     core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4;
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     }
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         }
610         return -1;
611     }
613     return 0;
616 static void coreaudio_fini_out (HWVoiceOut *hw)
618     OSStatus status;
619     int err;
620     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
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     }
630     fini_out_device(core);
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     }
639 static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)
641     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
643     core->enabled = enable;
644     update_device_playback_state(core);
647 static void *coreaudio_audio_init(Audiodev *dev, Error **errp)
649     return dev;
652 static void coreaudio_audio_fini (void *opaque)
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
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     .max_voices_out = 1,
677     .max_voices_in  = 0,
678     .voice_size_out = sizeof (coreaudioVoiceOut),
679     .voice_size_in  = 0
682 static void register_audio_coreaudio(void)
684     audio_driver_register(&coreaudio_audio_driver);
686 type_init(register_audio_coreaudio);