coreaudio.c (22250B)
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 kAudioObjectPropertyElementMaster 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 kAudioObjectPropertyElementMaster 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 kAudioObjectPropertyElementMaster 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 kAudioObjectPropertyElementMaster 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 kAudioObjectPropertyElementMaster 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 kAudioObjectPropertyElementMaster 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 GCC_FMT_ATTR (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 GCC_FMT_ATTR (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(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size), 287 (hw, size)) 288COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t, 289 (HWVoiceOut *hw, void *buf, size_t size), 290 (hw, buf, size)) 291COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size), 292 (hw, buf, size)) 293#undef COREAUDIO_WRAPPER_FUNC 294 295/* 296 * callback to feed audiooutput buffer. called without iothread lock. 297 * allowed to lock "buf_mutex", but disallowed to have any other locks. 298 */ 299static OSStatus audioDeviceIOProc( 300 AudioDeviceID inDevice, 301 const AudioTimeStamp *inNow, 302 const AudioBufferList *inInputData, 303 const AudioTimeStamp *inInputTime, 304 AudioBufferList *outOutputData, 305 const AudioTimeStamp *inOutputTime, 306 void *hwptr) 307{ 308 UInt32 frameCount, pending_frames; 309 void *out = outOutputData->mBuffers[0].mData; 310 HWVoiceOut *hw = hwptr; 311 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr; 312 size_t len; 313 314 if (coreaudio_buf_lock (core, "audioDeviceIOProc")) { 315 inInputTime = 0; 316 return 0; 317 } 318 319 if (inDevice != core->outputDeviceID) { 320 coreaudio_buf_unlock (core, "audioDeviceIOProc(old device)"); 321 return 0; 322 } 323 324 frameCount = core->audioDevicePropertyBufferFrameSize; 325 pending_frames = hw->pending_emul / hw->info.bytes_per_frame; 326 327 /* if there are not enough samples, set signal and return */ 328 if (pending_frames < frameCount) { 329 inInputTime = 0; 330 coreaudio_buf_unlock (core, "audioDeviceIOProc(empty)"); 331 return 0; 332 } 333 334 len = frameCount * hw->info.bytes_per_frame; 335 while (len) { 336 size_t write_len; 337 ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul; 338 if (start < 0) { 339 start += hw->size_emul; 340 } 341 assert(start >= 0 && start < hw->size_emul); 342 343 write_len = MIN(MIN(hw->pending_emul, len), 344 hw->size_emul - start); 345 346 memcpy(out, hw->buf_emul + start, write_len); 347 hw->pending_emul -= write_len; 348 len -= write_len; 349 out += write_len; 350 } 351 352 coreaudio_buf_unlock (core, "audioDeviceIOProc"); 353 return 0; 354} 355 356static OSStatus init_out_device(coreaudioVoiceOut *core) 357{ 358 OSStatus status; 359 AudioValueRange frameRange; 360 361 AudioStreamBasicDescription streamBasicDescription = { 362 .mBitsPerChannel = core->hw.info.bits, 363 .mBytesPerFrame = core->hw.info.bytes_per_frame, 364 .mBytesPerPacket = core->hw.info.bytes_per_frame, 365 .mChannelsPerFrame = core->hw.info.nchannels, 366 .mFormatFlags = kLinearPCMFormatFlagIsFloat, 367 .mFormatID = kAudioFormatLinearPCM, 368 .mFramesPerPacket = 1, 369 .mSampleRate = core->hw.info.freq 370 }; 371 372 status = coreaudio_get_voice(&core->outputDeviceID); 373 if (status != kAudioHardwareNoError) { 374 coreaudio_playback_logerr (status, 375 "Could not get default output Device\n"); 376 return status; 377 } 378 if (core->outputDeviceID == kAudioDeviceUnknown) { 379 dolog ("Could not initialize playback - Unknown Audiodevice\n"); 380 return status; 381 } 382 383 /* get minimum and maximum buffer frame sizes */ 384 status = coreaudio_get_framesizerange(core->outputDeviceID, 385 &frameRange); 386 if (status == kAudioHardwareBadObjectError) { 387 return 0; 388 } 389 if (status != kAudioHardwareNoError) { 390 coreaudio_playback_logerr (status, 391 "Could not get device buffer frame range\n"); 392 return status; 393 } 394 395 if (frameRange.mMinimum > core->frameSizeSetting) { 396 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum; 397 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum); 398 } else if (frameRange.mMaximum < core->frameSizeSetting) { 399 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum; 400 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum); 401 } else { 402 core->audioDevicePropertyBufferFrameSize = core->frameSizeSetting; 403 } 404 405 /* set Buffer Frame Size */ 406 status = coreaudio_set_framesize(core->outputDeviceID, 407 &core->audioDevicePropertyBufferFrameSize); 408 if (status == kAudioHardwareBadObjectError) { 409 return 0; 410 } 411 if (status != kAudioHardwareNoError) { 412 coreaudio_playback_logerr (status, 413 "Could not set device buffer frame size %" PRIu32 "\n", 414 (uint32_t)core->audioDevicePropertyBufferFrameSize); 415 return status; 416 } 417 418 /* get Buffer Frame Size */ 419 status = coreaudio_get_framesize(core->outputDeviceID, 420 &core->audioDevicePropertyBufferFrameSize); 421 if (status == kAudioHardwareBadObjectError) { 422 return 0; 423 } 424 if (status != kAudioHardwareNoError) { 425 coreaudio_playback_logerr (status, 426 "Could not get device buffer frame size\n"); 427 return status; 428 } 429 core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize; 430 431 /* set Samplerate */ 432 status = coreaudio_set_streamformat(core->outputDeviceID, 433 &streamBasicDescription); 434 if (status == kAudioHardwareBadObjectError) { 435 return 0; 436 } 437 if (status != kAudioHardwareNoError) { 438 coreaudio_playback_logerr (status, 439 "Could not set samplerate %lf\n", 440 streamBasicDescription.mSampleRate); 441 core->outputDeviceID = kAudioDeviceUnknown; 442 return status; 443 } 444 445 /* 446 * set Callback. 447 * 448 * On macOS 11.3.1, Core Audio calls AudioDeviceIOProc after calling an 449 * internal function named HALB_Mutex::Lock(), which locks a mutex in 450 * HALB_IOThread::Entry(void*). HALB_Mutex::Lock() is also called in 451 * AudioObjectGetPropertyData, which is called by coreaudio driver. 452 * Therefore, the specified callback must be designed to avoid a deadlock 453 * with the callers of AudioObjectGetPropertyData. 454 */ 455 core->ioprocid = NULL; 456 status = AudioDeviceCreateIOProcID(core->outputDeviceID, 457 audioDeviceIOProc, 458 &core->hw, 459 &core->ioprocid); 460 if (status == kAudioHardwareBadDeviceError) { 461 return 0; 462 } 463 if (status != kAudioHardwareNoError || core->ioprocid == NULL) { 464 coreaudio_playback_logerr (status, "Could not set IOProc\n"); 465 core->outputDeviceID = kAudioDeviceUnknown; 466 return status; 467 } 468 469 return 0; 470} 471 472static void fini_out_device(coreaudioVoiceOut *core) 473{ 474 OSStatus status; 475 UInt32 isrunning; 476 477 /* stop playback */ 478 status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning); 479 if (status != kAudioHardwareBadObjectError) { 480 if (status != kAudioHardwareNoError) { 481 coreaudio_logerr(status, 482 "Could not determine whether Device is playing\n"); 483 } 484 485 if (isrunning) { 486 status = AudioDeviceStop(core->outputDeviceID, core->ioprocid); 487 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) { 488 coreaudio_logerr(status, "Could not stop playback\n"); 489 } 490 } 491 } 492 493 /* remove callback */ 494 status = AudioDeviceDestroyIOProcID(core->outputDeviceID, 495 core->ioprocid); 496 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) { 497 coreaudio_logerr(status, "Could not remove IOProc\n"); 498 } 499 core->outputDeviceID = kAudioDeviceUnknown; 500} 501 502static void update_device_playback_state(coreaudioVoiceOut *core) 503{ 504 OSStatus status; 505 UInt32 isrunning; 506 507 status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning); 508 if (status != kAudioHardwareNoError) { 509 if (status != kAudioHardwareBadObjectError) { 510 coreaudio_logerr(status, 511 "Could not determine whether Device is playing\n"); 512 } 513 514 return; 515 } 516 517 if (core->enabled) { 518 /* start playback */ 519 if (!isrunning) { 520 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid); 521 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) { 522 coreaudio_logerr (status, "Could not resume playback\n"); 523 } 524 } 525 } else { 526 /* stop playback */ 527 if (isrunning) { 528 status = AudioDeviceStop(core->outputDeviceID, 529 core->ioprocid); 530 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) { 531 coreaudio_logerr(status, "Could not pause playback\n"); 532 } 533 } 534 } 535} 536 537/* called without iothread lock. */ 538static OSStatus handle_voice_change( 539 AudioObjectID in_object_id, 540 UInt32 in_number_addresses, 541 const AudioObjectPropertyAddress *in_addresses, 542 void *in_client_data) 543{ 544 OSStatus status; 545 coreaudioVoiceOut *core = in_client_data; 546 547 qemu_mutex_lock_iothread(); 548 549 if (core->outputDeviceID) { 550 fini_out_device(core); 551 } 552 553 status = init_out_device(core); 554 if (!status) { 555 update_device_playback_state(core); 556 } 557 558 qemu_mutex_unlock_iothread(); 559 return status; 560} 561 562static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as, 563 void *drv_opaque) 564{ 565 OSStatus status; 566 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; 567 int err; 568 Audiodev *dev = drv_opaque; 569 AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out; 570 struct audsettings obt_as; 571 572 /* create mutex */ 573 err = pthread_mutex_init(&core->buf_mutex, NULL); 574 if (err) { 575 dolog("Could not create mutex\nReason: %s\n", strerror (err)); 576 return -1; 577 } 578 579 obt_as = *as; 580 as = &obt_as; 581 as->fmt = AUDIO_FORMAT_F32; 582 audio_pcm_init_info (&hw->info, as); 583 584 core->frameSizeSetting = audio_buffer_frames( 585 qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610); 586 587 core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4; 588 589 status = AudioObjectAddPropertyListener(kAudioObjectSystemObject, 590 &voice_addr, handle_voice_change, 591 core); 592 if (status != kAudioHardwareNoError) { 593 coreaudio_playback_logerr (status, 594 "Could not listen to voice property change\n"); 595 return -1; 596 } 597 598 if (init_out_device(core)) { 599 status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, 600 &voice_addr, 601 handle_voice_change, 602 core); 603 if (status != kAudioHardwareNoError) { 604 coreaudio_playback_logerr(status, 605 "Could not remove voice property change listener\n"); 606 } 607 } 608 609 return 0; 610} 611 612static void coreaudio_fini_out (HWVoiceOut *hw) 613{ 614 OSStatus status; 615 int err; 616 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; 617 618 status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, 619 &voice_addr, 620 handle_voice_change, 621 core); 622 if (status != kAudioHardwareNoError) { 623 coreaudio_logerr(status, "Could not remove voice property change listener\n"); 624 } 625 626 fini_out_device(core); 627 628 /* destroy mutex */ 629 err = pthread_mutex_destroy(&core->buf_mutex); 630 if (err) { 631 dolog("Could not destroy mutex\nReason: %s\n", strerror (err)); 632 } 633} 634 635static void coreaudio_enable_out(HWVoiceOut *hw, bool enable) 636{ 637 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; 638 639 core->enabled = enable; 640 update_device_playback_state(core); 641} 642 643static void *coreaudio_audio_init(Audiodev *dev) 644{ 645 return dev; 646} 647 648static void coreaudio_audio_fini (void *opaque) 649{ 650} 651 652static struct audio_pcm_ops coreaudio_pcm_ops = { 653 .init_out = coreaudio_init_out, 654 .fini_out = coreaudio_fini_out, 655 /* wrapper for audio_generic_write */ 656 .write = coreaudio_write, 657 /* wrapper for audio_generic_get_buffer_out */ 658 .get_buffer_out = coreaudio_get_buffer_out, 659 /* wrapper for audio_generic_put_buffer_out */ 660 .put_buffer_out = coreaudio_put_buffer_out, 661 .enable_out = coreaudio_enable_out 662}; 663 664static struct audio_driver coreaudio_audio_driver = { 665 .name = "coreaudio", 666 .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html", 667 .init = coreaudio_audio_init, 668 .fini = coreaudio_audio_fini, 669 .pcm_ops = &coreaudio_pcm_ops, 670 .can_be_default = 1, 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);