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