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