- Timestamp:
- May 13, 2021 12:13:17 AM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioCoreAudio.cpp
r89024 r89025 234 234 /** Pointer to host audio interface. */ 235 235 PDMIHOSTAUDIO IHostAudio; 236 /** Critical section to serialize access. */237 RTCRITSECT CritSect;238 236 /** Current (last reported) device enumeration. */ 239 237 PDMAUDIOHOSTENUM Devices; … … 250 248 /** Indicates whether we've registered default output device change listener. */ 251 249 bool fRegisteredDefaultOutputListener; 250 /** Critical section to serialize access. */ 251 RTCRITSECT CritSect; 252 252 } DRVHOSTCOREAUDIO; 253 253 … … 267 267 DECLHIDDEN(int) coreAudioInputPermissionCheck(void); /* DrvHostAudioCoreAudioAuth.mm */ 268 268 static int drvHostCoreAudioStreamControlInternal(PCOREAUDIOSTREAM pStreamCA, PDMAUDIOSTREAMCMD enmStreamCmd); 269 static DECLCALLBACK(void) coreAudioInputQueueCb(void *pvUser, AudioQueueRef hAudioQueue, AudioQueueBufferRef audioBuffer,270 const AudioTimeStamp *pAudioTS, UInt32 cPacketDesc,271 const AudioStreamPacketDescription *paPacketDesc);272 static DECLCALLBACK(void) coreAudioOutputQueueCb(void *pvUser, AudioQueueRef hAudioQueue, AudioQueueBufferRef audioBuffer);273 269 274 270 … … 438 434 } 439 435 440 #endif /* VBOX_WITH_AUDIO_CA_CONVERTER */441 442 443 /**444 * Propagates an audio device status to all its connected Core Audio streams.445 *446 * @return IPRT status code.447 * @param pDev Audio device to propagate status for.448 * @param enmSts Status to propagate.449 */450 static int coreAudioDevicePropagateStatus(PCOREAUDIODEVICEDATA pDev, COREAUDIOINITSTATE enmSts)451 {452 AssertPtrReturn(pDev, VERR_INVALID_POINTER);453 454 455 /* Sanity. */456 AssertPtr(pDev->pDrv);457 458 LogFlowFunc(("pDev=%p enmSts=%RU32\n", pDev, enmSts));459 460 PCOREAUDIOSTREAM pStreamCA;461 RTListForEach(&pDev->lstStreams, pStreamCA, COREAUDIOSTREAM, Node)462 {463 LogFlowFunc(("pStreamCA=%p\n", pStreamCA));464 465 /* We move the reinitialization to the next output event.466 * This make sure this thread isn't blocked and the467 * reinitialization is done when necessary only. */468 ASMAtomicWriteU32(&pStreamCA->enmInitState, enmSts);469 }470 471 return VINF_SUCCESS;472 }473 474 475 static DECLCALLBACK(OSStatus) coreAudioDeviceStateChangedCb(AudioObjectID propertyID,476 UInt32 nAddresses,477 const AudioObjectPropertyAddress properties[],478 void *pvUser)479 {480 RT_NOREF(propertyID, nAddresses, properties);481 482 LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));483 484 PCOREAUDIODEVICEDATA pDev = (PCOREAUDIODEVICEDATA)pvUser;485 AssertPtr(pDev);486 487 PDRVHOSTCOREAUDIO pThis = pDev->pDrv;488 AssertPtr(pThis);489 490 int rc2 = RTCritSectEnter(&pThis->CritSect);491 AssertRC(rc2);492 493 UInt32 uAlive = 1;494 UInt32 uSize = sizeof(UInt32);495 496 AudioObjectPropertyAddress PropAddr =497 {498 kAudioDevicePropertyDeviceIsAlive,499 kAudioObjectPropertyScopeGlobal,500 kAudioObjectPropertyElementMaster501 };502 503 AudioDeviceID deviceID = pDev->deviceID;504 505 OSStatus err = AudioObjectGetPropertyData(deviceID, &PropAddr, 0, NULL, &uSize, &uAlive);506 507 bool fIsDead = false;508 509 if (err == kAudioHardwareBadDeviceError)510 fIsDead = true; /* Unplugged. */511 else if ((err == kAudioHardwareNoError) && (!RT_BOOL(uAlive)))512 fIsDead = true; /* Something else happened. */513 514 if (fIsDead)515 {516 LogRel2(("CoreAudio: Device '%s' stopped functioning\n", pDev->Core.szName));517 518 /* Mark device as dead. */519 rc2 = coreAudioDevicePropagateStatus(pDev, COREAUDIOINITSTATE_UNINIT);520 AssertRC(rc2);521 }522 523 rc2 = RTCritSectLeave(&pThis->CritSect);524 AssertRC(rc2);525 526 return noErr;527 }528 529 /* Callback for getting notified when the default recording/playback device has been changed. */530 /** @todo r=bird: Why DECLCALLBACK? */531 static DECLCALLBACK(OSStatus) coreAudioDefaultDeviceChangedCb(AudioObjectID propertyID,532 UInt32 nAddresses,533 const AudioObjectPropertyAddress properties[],534 void *pvUser)535 {536 RT_NOREF(propertyID, nAddresses);537 538 LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));539 540 PDRVHOSTCOREAUDIO pThis = (PDRVHOSTCOREAUDIO)pvUser;541 AssertPtr(pThis);542 543 int rc2 = RTCritSectEnter(&pThis->CritSect);544 AssertRC(rc2);545 546 for (UInt32 idxAddress = 0; idxAddress < nAddresses; idxAddress++)547 {548 PCOREAUDIODEVICEDATA pDev = NULL;549 550 /*551 * Check if the default input / output device has been changed.552 */553 const AudioObjectPropertyAddress *pProperty = &properties[idxAddress];554 switch (pProperty->mSelector)555 {556 case kAudioHardwarePropertyDefaultInputDevice:557 LogFlowFunc(("kAudioHardwarePropertyDefaultInputDevice\n"));558 pDev = pThis->pDefaultDevIn;559 break;560 561 case kAudioHardwarePropertyDefaultOutputDevice:562 LogFlowFunc(("kAudioHardwarePropertyDefaultOutputDevice\n"));563 pDev = pThis->pDefaultDevOut;564 break;565 566 default:567 /* Skip others. */568 break;569 }570 571 LogFlowFunc(("pDev=%p\n", pDev));572 }573 574 /* Make sure to leave the critical section before notify higher drivers/devices. */575 rc2 = RTCritSectLeave(&pThis->CritSect);576 AssertRC(rc2);577 578 /* Notify the driver/device above us about possible changes in devices. */579 if (pThis->pIHostAudioPort)580 pThis->pIHostAudioPort->pfnNotifyDevicesChanged(pThis->pIHostAudioPort);581 582 return noErr;583 }584 585 586 #ifdef VBOX_WITH_AUDIO_CA_CONVERTER587 436 /* Callback to convert audio input data from one format to another. */ 588 static DECLCALLBACK(OSStatus)coreAudioConverterCb(AudioConverterRef inAudioConverter,589 590 591 592 437 static OSStatus coreAudioConverterCb(AudioConverterRef inAudioConverter, 438 UInt32 *ioNumberDataPackets, 439 AudioBufferList *ioData, 440 AudioStreamPacketDescription **ppASPD, 441 void *pvUser) 593 442 { 594 443 RT_NOREF(inAudioConverter); … … 646 495 ioData->mBuffers[0].mData = pvAvail; 647 496 648 # ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA497 # ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA 649 498 RTFILE fh; 650 499 int rc = RTFileOpen(&fh,VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "caConverterCbInput.pcm", … … 657 506 else 658 507 AssertFailed(); 659 # endif508 # endif 660 509 pConvCbCtx->uPacketIdx += cNumberDataPackets; 661 510 Assert(pConvCbCtx->uPacketIdx <= pConvCbCtx->uPacketCnt); … … 670 519 return noErr; 671 520 } 521 672 522 #endif /* VBOX_WITH_AUDIO_CA_CONVERTER */ 523 524 525 /********************************************************************************************************************************* 526 * Device Change Notification Callbacks * 527 *********************************************************************************************************************************/ 528 529 /** 530 * Called when the kAudioDevicePropertyNominalSampleRate or 531 * kAudioDeviceProcessorOverload properties changes on a default device. 532 * 533 * Registered on default devices after device enumeration. 534 * Not sure on which thread/runloop this runs. 535 * 536 * (See AudioObjectPropertyListenerProc in the SDK headers.) 537 */ 538 static OSStatus drvHostAudioCaDevicePropertyChangedCallback(AudioObjectID idObject, UInt32 cAddresses, 539 const AudioObjectPropertyAddress paAddresses[], void *pvUser) 540 { 541 PCOREAUDIODEVICEDATA pDev = (PCOREAUDIODEVICEDATA)pvUser; 542 AssertPtr(pDev); 543 RT_NOREF(pDev, cAddresses, paAddresses); 544 545 LogFlowFunc(("idObject=%#x (%u) cAddresses=%u pDev=%p\n", idObject, idObject, cAddresses, pDev)); 546 for (UInt32 idx = 0; idx < cAddresses; idx++) 547 LogFlowFunc((" #%u: sel=%#x scope=%#x element=%#x\n", 548 idx, paAddresses[idx].mSelector, paAddresses[idx].mScope, paAddresses[idx].mElement)); 549 550 /** @todo r=bird: What's the plan here exactly? */ 551 switch (idObject) 552 { 553 case kAudioDeviceProcessorOverload: 554 LogFunc(("Processor overload detected!\n")); 555 break; 556 case kAudioDevicePropertyNominalSampleRate: 557 LogFunc(("kAudioDevicePropertyNominalSampleRate!\n")); 558 break; 559 default: 560 /* Just skip. */ 561 break; 562 } 563 564 return noErr; 565 } 566 567 568 /** 569 * Propagates an audio device status to all its Core Audio streams. 570 * 571 * @param pDev Audio device to propagate status for. 572 * @param enmSts Status to propagate. 573 */ 574 static void drvHostAudioCaDevicePropagateStatus(PCOREAUDIODEVICEDATA pDev, COREAUDIOINITSTATE enmSts) 575 { 576 /* Sanity. */ 577 AssertPtr(pDev); 578 AssertPtr(pDev->pDrv); 579 580 LogFlowFunc(("pDev=%p enmSts=%RU32\n", pDev, enmSts)); 581 582 PCOREAUDIOSTREAM pStreamCA; 583 RTListForEach(&pDev->lstStreams, pStreamCA, COREAUDIOSTREAM, Node) 584 { 585 LogFlowFunc(("pStreamCA=%p\n", pStreamCA)); 586 587 /* We move the reinitialization to the next output event. 588 * This make sure this thread isn't blocked and the 589 * reinitialization is done when necessary only. */ 590 /** @todo r=bird: This is now extremely bogus, see comment in caller. */ 591 ASMAtomicWriteU32(&pStreamCA->enmInitState, enmSts); 592 } 593 } 594 595 596 /** 597 * Called when the kAudioDevicePropertyDeviceIsAlive property changes on a 598 * default device. 599 * 600 * Registered on default devices after device enumeration. 601 * Not sure on which thread/runloop this runs. 602 * 603 * (See AudioObjectPropertyListenerProc in the SDK headers.) 604 */ 605 static OSStatus drvHostAudioCaDeviceIsAliveChangedCallback(AudioObjectID idObject, UInt32 cAddresses, 606 const AudioObjectPropertyAddress paAddresses[], void *pvUser) 607 { 608 PCOREAUDIODEVICEDATA pDev = (PCOREAUDIODEVICEDATA)pvUser; 609 AssertPtr(pDev); 610 PDRVHOSTCOREAUDIO pThis = pDev->pDrv; 611 AssertPtr(pThis); 612 RT_NOREF(idObject, cAddresses, paAddresses); 613 614 LogFlowFunc(("idObject=%#x (%u) cAddresses=%u pDev=%p\n", idObject, idObject, cAddresses, pDev)); 615 for (UInt32 idx = 0; idx < cAddresses; idx++) 616 LogFlowFunc((" #%u: sel=%#x scope=%#x element=%#x\n", 617 idx, paAddresses[idx].mSelector, paAddresses[idx].mScope, paAddresses[idx].mElement)); 618 619 int rc = RTCritSectEnter(&pThis->CritSect); 620 AssertRC(rc); 621 622 UInt32 uAlive = 1; 623 UInt32 uSize = sizeof(UInt32); 624 625 AudioObjectPropertyAddress PropAddr = 626 { 627 kAudioDevicePropertyDeviceIsAlive, 628 kAudioObjectPropertyScopeGlobal, 629 kAudioObjectPropertyElementMaster 630 }; 631 632 OSStatus err = AudioObjectGetPropertyData(pDev->deviceID, &PropAddr, 0, NULL, &uSize, &uAlive); 633 634 bool fIsDead = false; 635 if (err == kAudioHardwareBadDeviceError) 636 fIsDead = true; /* Unplugged. */ 637 else if (err == kAudioHardwareNoError && !RT_BOOL(uAlive)) 638 fIsDead = true; /* Something else happened. */ 639 640 if (fIsDead) 641 { 642 LogRel2(("CoreAudio: Device '%s' stopped functioning\n", pDev->Core.szName)); 643 644 /* Mark device as dead. */ 645 /** @todo r=bird: This is certifiably insane given how StreamDestroy does absolutely _nothing_ unless the init state is INIT. 646 * The queue thread will be running and trashing random heap if it tries to modify anything in the stream structure. */ 647 drvHostAudioCaDevicePropagateStatus(pDev, COREAUDIOINITSTATE_UNINIT); 648 } 649 650 RTCritSectLeave(&pThis->CritSect); 651 return noErr; 652 } 653 654 655 /** 656 * Called when the default recording or playback device has changed. 657 * 658 * Registered by the constructor. Not sure on which thread/runloop this runs. 659 * 660 * (See AudioObjectPropertyListenerProc in the SDK headers.) 661 */ 662 static OSStatus drvHostAudioCaDefaultDeviceChangedCallback(AudioObjectID idObject, UInt32 cAddresses, 663 const AudioObjectPropertyAddress *paAddresses, void *pvUser) 664 665 { 666 PDRVHOSTCOREAUDIO pThis = (PDRVHOSTCOREAUDIO)pvUser; 667 AssertPtr(pThis); 668 LogFunc(("idObject=%#x (%u) cAddresses=%u\n", idObject, idObject, cAddresses)); 669 RT_NOREF(idObject); 670 671 //int rc2 = RTCritSectEnter(&pThis->CritSect); 672 //AssertRC(rc2); 673 674 for (UInt32 idxAddress = 0; idxAddress < cAddresses; idxAddress++) 675 { 676 /// @todo r=bird: what's the plan here? PCOREAUDIODEVICEDATA pDev = NULL; 677 678 /* 679 * Check if the default input / output device has been changed. 680 */ 681 const AudioObjectPropertyAddress *pProperty = &paAddresses[idxAddress]; 682 switch (pProperty->mSelector) 683 { 684 case kAudioHardwarePropertyDefaultInputDevice: 685 LogFlowFunc(("#%u: sel=kAudioHardwarePropertyDefaultInputDevice scope=%#x element=%#x\n", 686 idxAddress, pProperty->mScope, pProperty->mElement)); 687 //pDev = pThis->pDefaultDevIn; 688 break; 689 690 case kAudioHardwarePropertyDefaultOutputDevice: 691 LogFlowFunc(("#%u: sel=kAudioHardwarePropertyDefaultOutputDevice scope=%#x element=%#x\n", 692 idxAddress, pProperty->mScope, pProperty->mElement)); 693 //pDev = pThis->pDefaultDevOut; 694 break; 695 696 default: 697 LogFlowFunc(("#%u: sel=%#x scope=%#x element=%#x\n", 698 idxAddress, pProperty->mSelector, pProperty->mScope, pProperty->mElement)); 699 break; 700 } 701 } 702 703 /* Make sure to leave the critical section before notify higher drivers/devices. */ 704 //rc2 = RTCritSectLeave(&pThis->CritSect); 705 //AssertRC(rc2); 706 707 /* 708 * Notify the driver/device above us about possible changes in devices. 709 */ 710 if (pThis->pIHostAudioPort) 711 pThis->pIHostAudioPort->pfnNotifyDevicesChanged(pThis->pIHostAudioPort); 712 713 return noErr; 714 } 715 716 717 /********************************************************************************************************************************* 718 * Queue Thread * 719 *********************************************************************************************************************************/ 720 721 /** 722 * Processes output data of a Core Audio stream into an audio queue buffer. 723 * 724 * @returns IPRT status code. 725 * @param pStreamCA Core Audio stream to process output data for. 726 * @param audioBuffer Audio buffer to store data into. 727 */ 728 static int coreAudioOutputQueueProcBuffer(PCOREAUDIOSTREAM pStreamCA, AudioQueueBufferRef audioBuffer) 729 { 730 AssertPtr(pStreamCA); 731 732 PRTCIRCBUF pCircBuf = pStreamCA->pCircBuf; 733 AssertPtr(pCircBuf); 734 735 size_t cbRead = 0; 736 737 UInt8 *pvSrc = NULL; 738 UInt8 *pvDst = (UInt8 *)audioBuffer->mAudioData; 739 740 size_t cbToRead = RT_MIN(RTCircBufUsed(pCircBuf), audioBuffer->mAudioDataBytesCapacity); 741 size_t cbLeft = cbToRead; 742 743 while (cbLeft) 744 { 745 /* Try to acquire the necessary block from the ring buffer. */ 746 RTCircBufAcquireReadBlock(pCircBuf, cbLeft, (void **)&pvSrc, &cbToRead); 747 748 if (cbToRead) 749 { 750 /* Copy the data from our ring buffer to the core audio buffer. */ 751 memcpy((UInt8 *)pvDst + cbRead, pvSrc, cbToRead); 752 } 753 754 /* Release the read buffer, so it could be used for new data. */ 755 RTCircBufReleaseReadBlock(pCircBuf, cbToRead); 756 757 if (!cbToRead) 758 break; 759 760 /* Move offset. */ 761 cbRead += cbToRead; 762 Assert(cbRead <= audioBuffer->mAudioDataBytesCapacity); 763 764 Assert(cbToRead <= cbLeft); 765 cbLeft -= cbToRead; 766 } 767 768 audioBuffer->mAudioDataByteSize = cbRead; 769 770 if (audioBuffer->mAudioDataByteSize < audioBuffer->mAudioDataBytesCapacity) 771 { 772 RT_BZERO((UInt8 *)audioBuffer->mAudioData + audioBuffer->mAudioDataByteSize, 773 audioBuffer->mAudioDataBytesCapacity - audioBuffer->mAudioDataByteSize); 774 775 audioBuffer->mAudioDataByteSize = audioBuffer->mAudioDataBytesCapacity; 776 } 777 778 Log3Func(("pStreamCA=%p, cbCapacity=%RU32, cbRead=%zu\n", 779 pStreamCA, audioBuffer->mAudioDataBytesCapacity, cbRead)); 780 781 return VINF_SUCCESS; 782 } 783 784 785 /** 786 * Output audio queue callback. 787 * 788 * Called whenever an audio queue is ready to process more output data. 789 * 790 * @param pvUser User argument. 791 * @param hAudioQueue Audio queue to process output data for. 792 * @param audioBuffer Audio buffer to store output data in. Must be part of audio queue. 793 * 794 * @thread queue thread. 795 */ 796 static void coreAudioOutputQueueCb(void *pvUser, AudioQueueRef hAudioQueue, AudioQueueBufferRef audioBuffer) 797 { 798 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pvUser; 799 AssertPtr(pStreamCA); 800 801 int rc = RTCritSectEnter(&pStreamCA->CritSect); 802 AssertRC(rc); 803 804 rc = coreAudioOutputQueueProcBuffer(pStreamCA, audioBuffer); 805 if (RT_SUCCESS(rc)) 806 AudioQueueEnqueueBuffer(hAudioQueue, audioBuffer, 0, NULL); 807 808 rc = RTCritSectLeave(&pStreamCA->CritSect); 809 AssertRC(rc); 810 } 811 812 813 /** 814 * Processes input data of an audio queue buffer and stores it into a Core Audio stream. 815 * 816 * @returns IPRT status code. 817 * @param pStreamCA Core Audio stream to store input data into. 818 * @param audioBuffer Audio buffer to process input data from. 819 */ 820 static int coreAudioInputQueueProcBuffer(PCOREAUDIOSTREAM pStreamCA, AudioQueueBufferRef audioBuffer) 821 { 822 PRTCIRCBUF pCircBuf = pStreamCA->pCircBuf; 823 AssertPtr(pCircBuf); 824 825 UInt8 *pvSrc = (UInt8 *)audioBuffer->mAudioData; 826 UInt8 *pvDst = NULL; 827 828 size_t cbWritten = 0; 829 830 size_t cbToWrite = audioBuffer->mAudioDataByteSize; 831 size_t cbLeft = RT_MIN(cbToWrite, RTCircBufFree(pCircBuf)); 832 833 while (cbLeft) 834 { 835 /* Try to acquire the necessary block from the ring buffer. */ 836 RTCircBufAcquireWriteBlock(pCircBuf, cbLeft, (void **)&pvDst, &cbToWrite); 837 838 if (!cbToWrite) 839 break; 840 841 /* Copy the data from our ring buffer to the core audio buffer. */ 842 /** @todo r=bird: WTF is the (UInt8 *) cast for? Despite the 'pv' prefix, pvDst 843 * is a UInt8 pointer. Whoever wrote this crap needs to check his/her 844 * medication. I shouldn't have to wast my time fixing crap like this! */ 845 memcpy((UInt8 *)pvDst, pvSrc + cbWritten, cbToWrite); 846 847 /* Release the read buffer, so it could be used for new data. */ 848 RTCircBufReleaseWriteBlock(pCircBuf, cbToWrite); 849 850 cbWritten += cbToWrite; 851 852 Assert(cbLeft >= cbToWrite); 853 cbLeft -= cbToWrite; 854 } 855 856 Log3Func(("pStreamCA=%p, cbBuffer=%RU32/%zu, cbWritten=%zu\n", 857 pStreamCA, audioBuffer->mAudioDataByteSize, audioBuffer->mAudioDataBytesCapacity, cbWritten)); 858 859 return VINF_SUCCESS; 860 } 861 862 863 /** 864 * Input audio queue callback. 865 * 866 * Called whenever input data from the audio queue becomes available. 867 * 868 * @param pvUser User argument. 869 * @param hAudioQueue Audio queue to process input data from. 870 * @param audioBuffer Audio buffer to process input data from. Must be part of audio queue. 871 * @param pAudioTS Audio timestamp. 872 * @param cPacketDesc Number of packet descriptors. 873 * @param paPacketDesc Array of packet descriptors. 874 */ 875 static void coreAudioInputQueueCb(void *pvUser, AudioQueueRef hAudioQueue, AudioQueueBufferRef audioBuffer, 876 const AudioTimeStamp *pAudioTS, 877 UInt32 cPacketDesc, const AudioStreamPacketDescription *paPacketDesc) 878 { 879 RT_NOREF(pAudioTS, cPacketDesc, paPacketDesc); 880 881 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pvUser; 882 AssertPtr(pStreamCA); 883 884 int rc = RTCritSectEnter(&pStreamCA->CritSect); 885 AssertRC(rc); 886 887 rc = coreAudioInputQueueProcBuffer(pStreamCA, audioBuffer); 888 if (RT_SUCCESS(rc)) 889 AudioQueueEnqueueBuffer(hAudioQueue, audioBuffer, 0, NULL); 890 891 rc = RTCritSectLeave(&pStreamCA->CritSect); 892 AssertRC(rc); 893 } 673 894 674 895 … … 752 973 LogRel(("CoreAudio: Failed to associate device with queue: %#x (%d)\n", orc, orc)); 753 974 754 AudioQueueDispose(pStreamCA->hAudioQueue, 1);975 AudioQueueDispose(pStreamCA->hAudioQueue, TRUE /*inImmediate*/); 755 976 } 756 977 else … … 763 984 } 764 985 765 /**766 * Processes input data of an audio queue buffer and stores it into a Core Audio stream.767 *768 * @returns IPRT status code.769 * @param pStreamCA Core Audio stream to store input data into.770 * @param audioBuffer Audio buffer to process input data from.771 */772 static int coreAudioInputQueueProcBuffer(PCOREAUDIOSTREAM pStreamCA, AudioQueueBufferRef audioBuffer)773 {774 PRTCIRCBUF pCircBuf = pStreamCA->pCircBuf;775 AssertPtr(pCircBuf);776 777 UInt8 *pvSrc = (UInt8 *)audioBuffer->mAudioData;778 UInt8 *pvDst = NULL;779 780 size_t cbWritten = 0;781 782 size_t cbToWrite = audioBuffer->mAudioDataByteSize;783 size_t cbLeft = RT_MIN(cbToWrite, RTCircBufFree(pCircBuf));784 785 while (cbLeft)786 {787 /* Try to acquire the necessary block from the ring buffer. */788 RTCircBufAcquireWriteBlock(pCircBuf, cbLeft, (void **)&pvDst, &cbToWrite);789 790 if (!cbToWrite)791 break;792 793 /* Copy the data from our ring buffer to the core audio buffer. */794 /** @todo r=bird: WTF is the (UInt8 *) cast for? Despite the 'pv' prefix, pvDst795 * is a UInt8 pointer. Whoever wrote this crap needs to check his/her796 * medication. I shouldn't have to wast my time fixing crap like this! */797 memcpy((UInt8 *)pvDst, pvSrc + cbWritten, cbToWrite);798 799 /* Release the read buffer, so it could be used for new data. */800 RTCircBufReleaseWriteBlock(pCircBuf, cbToWrite);801 802 cbWritten += cbToWrite;803 804 Assert(cbLeft >= cbToWrite);805 cbLeft -= cbToWrite;806 }807 808 Log3Func(("pStreamCA=%p, cbBuffer=%RU32/%zu, cbWritten=%zu\n",809 pStreamCA, audioBuffer->mAudioDataByteSize, audioBuffer->mAudioDataBytesCapacity, cbWritten));810 811 return VINF_SUCCESS;812 }813 814 /**815 * Input audio queue callback. Called whenever input data from the audio queue becomes available.816 *817 * @param pvUser User argument.818 * @param hAudioQueue Audio queue to process input data from.819 * @param audioBuffer Audio buffer to process input data from. Must be part of audio queue.820 * @param pAudioTS Audio timestamp.821 * @param cPacketDesc Number of packet descriptors.822 * @param paPacketDesc Array of packet descriptors.823 */824 static DECLCALLBACK(void) coreAudioInputQueueCb(void *pvUser, AudioQueueRef hAudioQueue, AudioQueueBufferRef audioBuffer,825 const AudioTimeStamp *pAudioTS,826 UInt32 cPacketDesc, const AudioStreamPacketDescription *paPacketDesc)827 {828 RT_NOREF(pAudioTS, cPacketDesc, paPacketDesc);829 830 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pvUser;831 AssertPtr(pStreamCA);832 833 int rc = RTCritSectEnter(&pStreamCA->CritSect);834 AssertRC(rc);835 836 rc = coreAudioInputQueueProcBuffer(pStreamCA, audioBuffer);837 if (RT_SUCCESS(rc))838 AudioQueueEnqueueBuffer(hAudioQueue, audioBuffer, 0, NULL);839 840 rc = RTCritSectLeave(&pStreamCA->CritSect);841 AssertRC(rc);842 }843 844 /**845 * Processes output data of a Core Audio stream into an audio queue buffer.846 *847 * @returns IPRT status code.848 * @param pStreamCA Core Audio stream to process output data for.849 * @param audioBuffer Audio buffer to store data into.850 */851 int coreAudioOutputQueueProcBuffer(PCOREAUDIOSTREAM pStreamCA, AudioQueueBufferRef audioBuffer)852 {853 AssertPtr(pStreamCA);854 855 PRTCIRCBUF pCircBuf = pStreamCA->pCircBuf;856 AssertPtr(pCircBuf);857 858 size_t cbRead = 0;859 860 UInt8 *pvSrc = NULL;861 UInt8 *pvDst = (UInt8 *)audioBuffer->mAudioData;862 863 size_t cbToRead = RT_MIN(RTCircBufUsed(pCircBuf), audioBuffer->mAudioDataBytesCapacity);864 size_t cbLeft = cbToRead;865 866 while (cbLeft)867 {868 /* Try to acquire the necessary block from the ring buffer. */869 RTCircBufAcquireReadBlock(pCircBuf, cbLeft, (void **)&pvSrc, &cbToRead);870 871 if (cbToRead)872 {873 /* Copy the data from our ring buffer to the core audio buffer. */874 memcpy((UInt8 *)pvDst + cbRead, pvSrc, cbToRead);875 }876 877 /* Release the read buffer, so it could be used for new data. */878 RTCircBufReleaseReadBlock(pCircBuf, cbToRead);879 880 if (!cbToRead)881 break;882 883 /* Move offset. */884 cbRead += cbToRead;885 Assert(cbRead <= audioBuffer->mAudioDataBytesCapacity);886 887 Assert(cbToRead <= cbLeft);888 cbLeft -= cbToRead;889 }890 891 audioBuffer->mAudioDataByteSize = cbRead;892 893 if (audioBuffer->mAudioDataByteSize < audioBuffer->mAudioDataBytesCapacity)894 {895 RT_BZERO((UInt8 *)audioBuffer->mAudioData + audioBuffer->mAudioDataByteSize,896 audioBuffer->mAudioDataBytesCapacity - audioBuffer->mAudioDataByteSize);897 898 audioBuffer->mAudioDataByteSize = audioBuffer->mAudioDataBytesCapacity;899 }900 901 Log3Func(("pStreamCA=%p, cbCapacity=%RU32, cbRead=%zu\n",902 pStreamCA, audioBuffer->mAudioDataBytesCapacity, cbRead));903 904 return VINF_SUCCESS;905 }906 907 /**908 * Output audio queue callback. Called whenever an audio queue is ready to process more output data.909 *910 * @param pvUser User argument.911 * @param hAudioQueue Audio queue to process output data for.912 * @param audioBuffer Audio buffer to store output data in. Must be part of audio queue.913 */914 static DECLCALLBACK(void) coreAudioOutputQueueCb(void *pvUser, AudioQueueRef hAudioQueue, AudioQueueBufferRef audioBuffer)915 {916 PCOREAUDIOSTREAM pStreamCA = (PCOREAUDIOSTREAM)pvUser;917 AssertPtr(pStreamCA);918 919 int rc = RTCritSectEnter(&pStreamCA->CritSect);920 AssertRC(rc);921 922 rc = coreAudioOutputQueueProcBuffer(pStreamCA, audioBuffer);923 if (RT_SUCCESS(rc))924 AudioQueueEnqueueBuffer(hAudioQueue, audioBuffer, 0, NULL);925 926 rc = RTCritSectLeave(&pStreamCA->CritSect);927 AssertRC(rc);928 }929 986 930 987 /** … … 965 1022 966 1023 return rc; 967 }968 969 970 /* Callback for getting notified when some of the properties of an audio device have changed. */971 static DECLCALLBACK(OSStatus) coreAudioDevPropChgCb(AudioObjectID propertyID,972 UInt32 cAddresses,973 const AudioObjectPropertyAddress properties[],974 void *pvUser)975 {976 RT_NOREF(cAddresses, properties, pvUser);977 978 PCOREAUDIODEVICEDATA pDev = (PCOREAUDIODEVICEDATA)pvUser;979 AssertPtr(pDev);980 981 LogFlowFunc(("propertyID=%u, nAddresses=%u, pDev=%p\n", propertyID, cAddresses, pDev));982 983 switch (propertyID)984 {985 #ifdef DEBUG986 case kAudioDeviceProcessorOverload:987 {988 LogFunc(("Processor overload detected!\n"));989 break;990 }991 #endif /* DEBUG */992 case kAudioDevicePropertyNominalSampleRate:993 {994 RT_NOREF(pDev);995 break;996 }997 998 default:999 /* Just skip. */1000 break;1001 }1002 1003 return noErr;1004 1024 } 1005 1025 … … 1479 1499 kAudioObjectPropertyElementMaster 1480 1500 }; 1481 OSStatus err = AudioObjectAddPropertyListener(deviceID, &PropAddr, coreAudioDeviceStateChangedCb, pDev /* pvUser */); 1501 OSStatus err = AudioObjectAddPropertyListener(deviceID, &PropAddr, 1502 drvHostAudioCaDeviceIsAliveChangedCallback, pDev /*pvUser*/); 1482 1503 if ( err != noErr 1483 1504 && err != kAudioHardwareIllegalOperationError) … … 1486 1507 PropAddr.mSelector = kAudioDeviceProcessorOverload; 1487 1508 PropAddr.mScope = kAudioUnitScope_Global; 1488 err = AudioObjectAddPropertyListener(deviceID, &PropAddr, coreAudioDevPropChgCb, pDev /* pvUser */);1509 err = AudioObjectAddPropertyListener(deviceID, &PropAddr, drvHostAudioCaDevicePropertyChangedCallback, pDev /* pvUser */); 1489 1510 if (err != noErr) 1490 1511 LogRel(("CoreAudio: Failed to register processor overload listener (%RI32)\n", err)); … … 1492 1513 PropAddr.mSelector = kAudioDevicePropertyNominalSampleRate; 1493 1514 PropAddr.mScope = kAudioUnitScope_Global; 1494 err = AudioObjectAddPropertyListener(deviceID, &PropAddr, coreAudioDevPropChgCb, pDev /* pvUser */);1515 err = AudioObjectAddPropertyListener(deviceID, &PropAddr, drvHostAudioCaDevicePropertyChangedCallback, pDev /* pvUser */); 1495 1516 if (err != noErr) 1496 1517 LogRel(("CoreAudio: Failed to register sample rate changed listener (%RI32)\n", err)); … … 1530 1551 kAudioObjectPropertyElementMaster 1531 1552 }; 1532 OSStatus err = AudioObjectRemovePropertyListener(deviceID, &PropAddr, coreAudioDevPropChgCb, pDev /* pvUser */);1553 OSStatus err = AudioObjectRemovePropertyListener(deviceID, &PropAddr, drvHostAudioCaDevicePropertyChangedCallback, pDev /* pvUser */); 1533 1554 if ( err != noErr 1534 1555 && err != kAudioHardwareBadObjectError) … … 1536 1557 1537 1558 PropAddr.mSelector = kAudioDevicePropertyNominalSampleRate; 1538 err = AudioObjectRemovePropertyListener(deviceID, &PropAddr, coreAudioDevPropChgCb, pDev /* pvUser */);1559 err = AudioObjectRemovePropertyListener(deviceID, &PropAddr, drvHostAudioCaDevicePropertyChangedCallback, pDev /* pvUser */); 1539 1560 if ( err != noErr 1540 1561 && err != kAudioHardwareBadObjectError) … … 1542 1563 1543 1564 PropAddr.mSelector = kAudioDevicePropertyDeviceIsAlive; 1544 err = AudioObjectRemovePropertyListener(deviceID, &PropAddr, coreAudioDeviceStateChangedCb, pDev /* pvUser */);1565 err = AudioObjectRemovePropertyListener(deviceID, &PropAddr, drvHostAudioCaDeviceIsAliveChangedCallback, pDev /* pvUser */); 1545 1566 if ( err != noErr 1546 1567 && err != kAudioHardwareBadObjectError) … … 2178 2199 if (pThis->fRegisteredDefaultInputListener) 2179 2200 { 2180 orc = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &PropAddr, coreAudioDefaultDeviceChangedCb, pThis);2201 orc = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &PropAddr, drvHostAudioCaDefaultDeviceChangedCallback, pThis); 2181 2202 if ( orc != noErr 2182 2203 && orc != kAudioHardwareBadObjectError) … … 2189 2210 2190 2211 PropAddr.mSelector = kAudioHardwarePropertyDefaultOutputDevice; 2191 orc = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &PropAddr, coreAudioDefaultDeviceChangedCb, pThis);2212 orc = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &PropAddr, drvHostAudioCaDefaultDeviceChangedCallback, pThis); 2192 2213 if ( orc != noErr 2193 2214 && orc != kAudioHardwareBadObjectError) … … 2283 2304 }; 2284 2305 2285 OSStatus orc = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &PropAddr, coreAudioDefaultDeviceChangedCb, pThis);2306 OSStatus orc = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &PropAddr, drvHostAudioCaDefaultDeviceChangedCallback, pThis); 2286 2307 pThis->fRegisteredDefaultInputListener = orc == noErr; 2287 2308 if ( orc != noErr … … 2290 2311 2291 2312 PropAddr.mSelector = kAudioHardwarePropertyDefaultOutputDevice; 2292 orc = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &PropAddr, coreAudioDefaultDeviceChangedCb, pThis);2313 orc = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &PropAddr, drvHostAudioCaDefaultDeviceChangedCallback, pThis); 2293 2314 pThis->fRegisteredDefaultOutputListener = orc == noErr; 2294 2315 if ( orc != noErr
Note:
See TracChangeset
for help on using the changeset viewer.