VirtualBox

Changeset 89008 in vbox


Ignore:
Timestamp:
May 12, 2021 12:37:56 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
144347
Message:

DrvHostAudioCoreAudio: Re-ordered functions a bit. Some cleanups. bugref:9890

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DrvHostAudioCoreAudio.cpp

    r88959 r89008  
    425425*   Internal Functions                                                                                                           *
    426426*********************************************************************************************************************************/
    427 static int coreAudioStreamInit(PCOREAUDIOSTREAM pCAStream, PDRVHOSTCOREAUDIO pThis, PCOREAUDIODEVICEDATA pDev);
    428427#ifndef VBOX_WITH_AUDIO_CALLBACKS
    429428static int coreAudioStreamReinit(PDRVHOSTCOREAUDIO pThis, PCOREAUDIOSTREAM pCAStream, PCOREAUDIODEVICEDATA pDev);
     
    432431
    433432static int coreAudioStreamControl(PDRVHOSTCOREAUDIO pThis, PCOREAUDIOSTREAM pCAStream, PDMAUDIOSTREAMCMD enmStreamCmd);
    434 
    435 static void coreAudioDeviceDataInit(PCOREAUDIODEVICEDATA pDevData, AudioDeviceID deviceID, bool fIsInput, PDRVHOSTCOREAUDIO pDrv);
    436 
    437 static DECLCALLBACK(OSStatus) coreAudioDevPropChgCb(AudioObjectID propertyID, UInt32 nAddresses,
    438                                                     const AudioObjectPropertyAddress properties[], void *pvUser);
    439433
    440434static int coreAudioStreamInitQueue(PCOREAUDIOSTREAM pCAStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq);
     
    501495
    502496#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
     497
     498
     499/**
     500 * Propagates an audio device status to all its connected Core Audio streams.
     501 *
     502 * @return IPRT status code.
     503 * @param  pDev                 Audio device to propagate status for.
     504 * @param  enmSts               Status to propagate.
     505 */
     506static int coreAudioDevicePropagateStatus(PCOREAUDIODEVICEDATA pDev, COREAUDIOSTATUS enmSts)
     507{
     508    AssertPtrReturn(pDev, VERR_INVALID_POINTER);
     509
     510
     511    /* Sanity. */
     512    AssertPtr(pDev->pDrv);
     513
     514    LogFlowFunc(("pDev=%p enmSts=%RU32\n", pDev, enmSts));
     515
     516    PCOREAUDIOSTREAM pCAStream;
     517    RTListForEach(&pDev->lstStreams, pCAStream, COREAUDIOSTREAM, Node)
     518    {
     519        LogFlowFunc(("pCAStream=%p\n", pCAStream));
     520
     521        /* We move the reinitialization to the next output event.
     522         * This make sure this thread isn't blocked and the
     523         * reinitialization is done when necessary only. */
     524        ASMAtomicXchgU32(&pCAStream->enmStatus, enmSts);
     525    }
     526
     527    return VINF_SUCCESS;
     528}
     529
     530
     531static DECLCALLBACK(OSStatus) coreAudioDeviceStateChangedCb(AudioObjectID propertyID,
     532                                                            UInt32 nAddresses,
     533                                                            const AudioObjectPropertyAddress properties[],
     534                                                            void *pvUser)
     535{
     536    RT_NOREF(propertyID, nAddresses, properties);
     537
     538    LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));
     539
     540    PCOREAUDIODEVICEDATA pDev = (PCOREAUDIODEVICEDATA)pvUser;
     541    AssertPtr(pDev);
     542
     543    PDRVHOSTCOREAUDIO pThis = pDev->pDrv;
     544    AssertPtr(pThis);
     545
     546    int rc2 = RTCritSectEnter(&pThis->CritSect);
     547    AssertRC(rc2);
     548
     549    UInt32 uAlive = 1;
     550    UInt32 uSize  = sizeof(UInt32);
     551
     552    AudioObjectPropertyAddress PropAddr =
     553    {
     554        kAudioDevicePropertyDeviceIsAlive,
     555        kAudioObjectPropertyScopeGlobal,
     556        kAudioObjectPropertyElementMaster
     557    };
     558
     559    AudioDeviceID deviceID = pDev->deviceID;
     560
     561    OSStatus err = AudioObjectGetPropertyData(deviceID, &PropAddr, 0, NULL, &uSize, &uAlive);
     562
     563    bool fIsDead = false;
     564
     565    if (err == kAudioHardwareBadDeviceError)
     566        fIsDead = true; /* Unplugged. */
     567    else if ((err == kAudioHardwareNoError) && (!RT_BOOL(uAlive)))
     568        fIsDead = true; /* Something else happened. */
     569
     570    if (fIsDead)
     571    {
     572        LogRel2(("CoreAudio: Device '%s' stopped functioning\n", pDev->Core.szName));
     573
     574        /* Mark device as dead. */
     575        rc2 = coreAudioDevicePropagateStatus(pDev, COREAUDIOSTATUS_UNINIT);
     576        AssertRC(rc2);
     577    }
     578
     579    rc2 = RTCritSectLeave(&pThis->CritSect);
     580    AssertRC(rc2);
     581
     582    return noErr;
     583}
     584
     585/* Callback for getting notified when the default recording/playback device has been changed. */
     586/** @todo r=bird: Why DECLCALLBACK? */
     587static DECLCALLBACK(OSStatus) coreAudioDefaultDeviceChangedCb(AudioObjectID propertyID,
     588                                                              UInt32 nAddresses,
     589                                                              const AudioObjectPropertyAddress properties[],
     590                                                              void *pvUser)
     591{
     592    RT_NOREF(propertyID, nAddresses);
     593
     594    LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));
     595
     596    PDRVHOSTCOREAUDIO pThis = (PDRVHOSTCOREAUDIO)pvUser;
     597    AssertPtr(pThis);
     598
     599    int rc2 = RTCritSectEnter(&pThis->CritSect);
     600    AssertRC(rc2);
     601
     602    for (UInt32 idxAddress = 0; idxAddress < nAddresses; idxAddress++)
     603    {
     604        PCOREAUDIODEVICEDATA pDev = NULL;
     605
     606        /*
     607         * Check if the default input / output device has been changed.
     608         */
     609        const AudioObjectPropertyAddress *pProperty = &properties[idxAddress];
     610        switch (pProperty->mSelector)
     611        {
     612            case kAudioHardwarePropertyDefaultInputDevice:
     613                LogFlowFunc(("kAudioHardwarePropertyDefaultInputDevice\n"));
     614                pDev = pThis->pDefaultDevIn;
     615                break;
     616
     617            case kAudioHardwarePropertyDefaultOutputDevice:
     618                LogFlowFunc(("kAudioHardwarePropertyDefaultOutputDevice\n"));
     619                pDev = pThis->pDefaultDevOut;
     620                break;
     621
     622            default:
     623                /* Skip others. */
     624                break;
     625        }
     626
     627        LogFlowFunc(("pDev=%p\n", pDev));
     628
     629#ifndef VBOX_WITH_AUDIO_CALLBACKS
     630        if (pDev)
     631        {
     632            /* This listener is called on every change of the hardware
     633             * device. So check if the default device has really changed. */
     634            UInt32 uSize = sizeof(AudioDeviceID);
     635            UInt32 uResp = 0;
     636
     637            OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, pProperty, 0, NULL, &uSize, &uResp);
     638            if (err == noErr)
     639            {
     640                if (pDev->deviceID != uResp) /* Has the device ID changed? */
     641                {
     642                    rc2 = coreAudioDevicePropagateStatus(pDev, COREAUDIOSTATUS_REINIT);
     643                    AssertRC(rc2);
     644                }
     645            }
     646        }
     647#endif /* VBOX_WITH_AUDIO_CALLBACKS */
     648    }
     649
     650    /* Make sure to leave the critical section before notify higher drivers/devices. */
     651    rc2 = RTCritSectLeave(&pThis->CritSect);
     652    AssertRC(rc2);
     653
     654#ifdef VBOX_WITH_AUDIO_CALLBACKS
     655    /* Notify the driver/device above us about possible changes in devices. */
     656    if (pThis->pIHostAudioPort)
     657        pThis->pIHostAudioPort->pfnNotifyDevicesChanged(pThis->pIHostAudioPort);
     658#endif
     659
     660    return noErr;
     661}
     662
     663#ifndef VBOX_WITH_AUDIO_CALLBACKS
     664
     665/**
     666 * Re-initializes a Core Audio stream with a specific audio device and stream configuration.
     667 *
     668 * @return IPRT status code.
     669 * @param  pThis                Driver instance.
     670 * @param  pCAStream            Audio stream to re-initialize.
     671 * @param  pDev                 Audio device to use for re-initialization.
     672 * @param  pCfg                 Stream configuration to use for re-initialization.
     673 */
     674static int coreAudioStreamReinitEx(PDRVHOSTCOREAUDIO pThis, PCOREAUDIOSTREAM pCAStream,
     675                                   PCOREAUDIODEVICEDATA pDev, PPDMAUDIOSTREAMCFG pCfg)
     676{
     677    LogFunc(("pCAStream=%p\n", pCAStream));
     678
     679    int rc = coreAudioStreamUninit(pCAStream);
     680    if (RT_SUCCESS(rc))
     681    {
     682        rc = coreAudioStreamInit(pCAStream, pThis, pDev);
     683        if (RT_SUCCESS(rc))
     684        {
     685            rc = coreAudioStreamInitQueue(pCAStream, pCfg /* pCfgReq */, NULL /* pCfgAcq */);
     686            if (RT_SUCCESS(rc))
     687                rc = coreAudioStreamControl(pCAStream->pDrv, pCAStream, PDMAUDIOSTREAMCMD_ENABLE);
     688
     689            if (RT_FAILURE(rc))
     690            {
     691                int rc2 = coreAudioStreamUninit(pCAStream);
     692                AssertRC(rc2);
     693            }
     694        }
     695    }
     696
     697    if (RT_FAILURE(rc))
     698        LogRel(("CoreAudio: Unable to re-init stream: %Rrc\n", rc));
     699
     700    return rc;
     701}
     702
     703/**
     704 * Re-initializes a Core Audio stream with a specific audio device.
     705 *
     706 * @return IPRT status code.
     707 * @param  pThis                Driver instance.
     708 * @param  pCAStream            Audio stream to re-initialize.
     709 * @param  pDev                 Audio device to use for re-initialization.
     710 */
     711static int coreAudioStreamReinit(PDRVHOSTCOREAUDIO pThis, PCOREAUDIOSTREAM pCAStream, PCOREAUDIODEVICEDATA pDev)
     712{
     713    int rc = coreAudioStreamUninit(pCAStream);
     714    if (RT_SUCCESS(rc))
     715    {
     716        /* Use the acquired stream configuration from the former initialization to
     717         * re-initialize the stream. */
     718        PDMAUDIOSTREAMCFG CfgAcq;
     719        rc = coreAudioASBDToStreamCfg(&pCAStream->Unit.streamFmt, &CfgAcq);
     720        if (RT_SUCCESS(rc))
     721            rc = coreAudioStreamReinitEx(pThis, pCAStream, pDev, &CfgAcq);
     722    }
     723
     724    return rc;
     725}
     726
     727#endif /* !VBOX_WITH_AUDIO_CALLBACKS */
     728
     729#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
     730/* Callback to convert audio input data from one format to another. */
     731static DECLCALLBACK(OSStatus) coreAudioConverterCb(AudioConverterRef              inAudioConverter,
     732                                                   UInt32                        *ioNumberDataPackets,
     733                                                   AudioBufferList               *ioData,
     734                                                   AudioStreamPacketDescription **ppASPD,
     735                                                   void                          *pvUser)
     736{
     737    RT_NOREF(inAudioConverter);
     738
     739    AssertPtrReturn(ioNumberDataPackets, caConverterEOFDErr);
     740    AssertPtrReturn(ioData,              caConverterEOFDErr);
     741
     742    PCOREAUDIOCONVCBCTX pConvCbCtx = (PCOREAUDIOCONVCBCTX)pvUser;
     743    AssertPtr(pConvCbCtx);
     744
     745    /* Initialize values. */
     746    ioData->mBuffers[0].mNumberChannels = 0;
     747    ioData->mBuffers[0].mDataByteSize   = 0;
     748    ioData->mBuffers[0].mData           = NULL;
     749
     750    if (ppASPD)
     751    {
     752        Log3Func(("Handling packet description not implemented\n"));
     753    }
     754    else
     755    {
     756        /** @todo Check converter ID? */
     757
     758        /** @todo Handled non-interleaved data by going through the full buffer list,
     759         *        not only through the first buffer like we do now. */
     760        Log3Func(("ioNumberDataPackets=%RU32\n", *ioNumberDataPackets));
     761
     762        UInt32 cNumberDataPackets = *ioNumberDataPackets;
     763        Assert(pConvCbCtx->uPacketIdx + cNumberDataPackets <= pConvCbCtx->uPacketCnt);
     764
     765        if (cNumberDataPackets)
     766        {
     767            AssertPtr(pConvCbCtx->pBufLstSrc);
     768            Assert(pConvCbCtx->pBufLstSrc->mNumberBuffers == 1); /* Only one buffer for the source supported atm. */
     769
     770            AudioStreamBasicDescription *pSrcASBD = &pConvCbCtx->asbdSrc;
     771            AudioBuffer                 *pSrcBuf  = &pConvCbCtx->pBufLstSrc->mBuffers[0];
     772
     773            size_t cbOff   = pConvCbCtx->uPacketIdx * pSrcASBD->mBytesPerPacket;
     774
     775            cNumberDataPackets = RT_MIN((pSrcBuf->mDataByteSize - cbOff) / pSrcASBD->mBytesPerPacket,
     776                                        cNumberDataPackets);
     777
     778            void  *pvAvail = (uint8_t *)pSrcBuf->mData + cbOff;
     779            size_t cbAvail = RT_MIN(pSrcBuf->mDataByteSize - cbOff, cNumberDataPackets * pSrcASBD->mBytesPerPacket);
     780
     781            Log3Func(("cNumberDataPackets=%RU32, cbOff=%zu, cbAvail=%zu\n", cNumberDataPackets, cbOff, cbAvail));
     782
     783            /* Set input data for the converter to use.
     784             * Note: For VBR (Variable Bit Rates) or interleaved data handling we need multiple buffers here. */
     785            ioData->mNumberBuffers = 1;
     786
     787            ioData->mBuffers[0].mNumberChannels = pSrcBuf->mNumberChannels;
     788            ioData->mBuffers[0].mDataByteSize   = cbAvail;
     789            ioData->mBuffers[0].mData           = pvAvail;
     790
     791#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
     792            RTFILE fh;
     793            int rc = RTFileOpen(&fh,VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "caConverterCbInput.pcm",
     794                                RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
     795            if (RT_SUCCESS(rc))
     796            {
     797                RTFileWrite(fh, pvAvail, cbAvail, NULL);
     798                RTFileClose(fh);
     799            }
     800            else
     801                AssertFailed();
     802#endif
     803            pConvCbCtx->uPacketIdx += cNumberDataPackets;
     804            Assert(pConvCbCtx->uPacketIdx <= pConvCbCtx->uPacketCnt);
     805
     806            *ioNumberDataPackets = cNumberDataPackets;
     807        }
     808    }
     809
     810    Log3Func(("%RU32 / %RU32 -> ioNumberDataPackets=%RU32\n",
     811              pConvCbCtx->uPacketIdx, pConvCbCtx->uPacketCnt, *ioNumberDataPackets));
     812
     813    return noErr;
     814}
     815#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
     816
     817
     818/**
     819 * Thread for a Core Audio stream's audio queue handling.
     820 *
     821 * This thread is required per audio queue to pump data to/from the Core Audio
     822 * stream and handling its callbacks.
     823 *
     824 * @returns IPRT status code.
     825 * @param   hThreadSelf         Thread handle.
     826 * @param   pvUser              User argument.
     827 */
     828static DECLCALLBACK(int) coreAudioQueueThread(RTTHREAD hThreadSelf, void *pvUser)
     829{
     830    RT_NOREF(hThreadSelf);
     831
     832    PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
     833    AssertPtr(pCAStream);
     834    AssertPtr(pCAStream->pCfg);
     835
     836    const bool fIn = pCAStream->pCfg->enmDir == PDMAUDIODIR_IN;
     837
     838    LogFunc(("Thread started for pCAStream=%p, fIn=%RTbool\n", pCAStream, fIn));
     839
     840    /*
     841     * Create audio queue.
     842     */
     843    OSStatus err;
     844    if (fIn)
     845        err = AudioQueueNewInput(&pCAStream->asbdStream, coreAudioInputQueueCb, pCAStream /* pvData */,
     846                                 CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &pCAStream->audioQueue);
     847    else
     848        err = AudioQueueNewOutput(&pCAStream->asbdStream, coreAudioOutputQueueCb, pCAStream /* pvData */,
     849                                  CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &pCAStream->audioQueue);
     850
     851    if (err != noErr)
     852        return VERR_GENERAL_FAILURE; /** @todo Fudge! */
     853
     854    /*
     855     * Assign device to queue.
     856     */
     857    PCOREAUDIODEVICEDATA pDev = (PCOREAUDIODEVICEDATA)pCAStream->Unit.pDevice;
     858    AssertPtr(pDev);
     859
     860    UInt32 uSize = sizeof(pDev->UUID);
     861    err = AudioQueueSetProperty(pCAStream->audioQueue, kAudioQueueProperty_CurrentDevice, &pDev->UUID, uSize);
     862    if (err != noErr)
     863        return VERR_GENERAL_FAILURE; /** @todo Fudge! */
     864
     865    const size_t cbBufSize = PDMAudioPropsFramesToBytes(&pCAStream->pCfg->Props, pCAStream->pCfg->Backend.cFramesPeriod);
     866
     867    /*
     868     * Allocate audio buffers.
     869     */
     870    for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++)
     871    {
     872        err = AudioQueueAllocateBuffer(pCAStream->audioQueue, cbBufSize, &pCAStream->audioBuffer[i]);
     873        if (err != noErr)
     874            break;
     875    }
     876
     877    if (err != noErr)
     878        return VERR_GENERAL_FAILURE; /** @todo Fudge! */
     879
     880    /* Signal the main thread before entering the main loop. */
     881    RTThreadUserSignal(RTThreadSelf());
     882
     883    /*
     884     * Enter the main loop.
     885     */
     886    while (!ASMAtomicReadBool(&pCAStream->fShutdown))
     887    {
     888        CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
     889    }
     890
     891    /*
     892     * Cleanup.
     893     */
     894    if (fIn)
     895    {
     896        AudioQueueStop(pCAStream->audioQueue, 1);
     897    }
     898    else
     899    {
     900        AudioQueueStop(pCAStream->audioQueue, 0);
     901    }
     902
     903    for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++)
     904    {
     905        if (pCAStream->audioBuffer[i])
     906            AudioQueueFreeBuffer(pCAStream->audioQueue, pCAStream->audioBuffer[i]);
     907    }
     908
     909    AudioQueueDispose(pCAStream->audioQueue, 1);
     910
     911    LogFunc(("Thread ended for pCAStream=%p, fIn=%RTbool\n", pCAStream, fIn));
     912    return VINF_SUCCESS;
     913}
     914
     915/**
     916 * Processes input data of an audio queue buffer and stores it into a Core Audio stream.
     917 *
     918 * @returns IPRT status code.
     919 * @param   pCAStream           Core Audio stream to store input data into.
     920 * @param   audioBuffer         Audio buffer to process input data from.
     921 */
     922static int coreAudioInputQueueProcBuffer(PCOREAUDIOSTREAM pCAStream, AudioQueueBufferRef audioBuffer)
     923{
     924    PRTCIRCBUF pCircBuf = pCAStream->pCircBuf;
     925    AssertPtr(pCircBuf);
     926
     927    UInt8 *pvSrc = (UInt8 *)audioBuffer->mAudioData;
     928    UInt8 *pvDst = NULL;
     929
     930    size_t cbWritten = 0;
     931
     932    size_t cbToWrite = audioBuffer->mAudioDataByteSize;
     933    size_t cbLeft    = RT_MIN(cbToWrite, RTCircBufFree(pCircBuf));
     934
     935    while (cbLeft)
     936    {
     937        /* Try to acquire the necessary block from the ring buffer. */
     938        RTCircBufAcquireWriteBlock(pCircBuf, cbLeft, (void **)&pvDst, &cbToWrite);
     939
     940        if (!cbToWrite)
     941            break;
     942
     943        /* Copy the data from our ring buffer to the core audio buffer. */
     944        memcpy((UInt8 *)pvDst, pvSrc + cbWritten, cbToWrite);
     945
     946        /* Release the read buffer, so it could be used for new data. */
     947        RTCircBufReleaseWriteBlock(pCircBuf, cbToWrite);
     948
     949        cbWritten += cbToWrite;
     950
     951        Assert(cbLeft >= cbToWrite);
     952        cbLeft -= cbToWrite;
     953    }
     954
     955    Log3Func(("pCAStream=%p, cbBuffer=%RU32/%zu, cbWritten=%zu\n",
     956              pCAStream, audioBuffer->mAudioDataByteSize, audioBuffer->mAudioDataBytesCapacity, cbWritten));
     957
     958    return VINF_SUCCESS;
     959}
     960
     961/**
     962 * Input audio queue callback. Called whenever input data from the audio queue becomes available.
     963 *
     964 * @param   pvUser              User argument.
     965 * @param   audioQueue          Audio queue to process input data from.
     966 * @param   audioBuffer         Audio buffer to process input data from. Must be part of audio queue.
     967 * @param   pAudioTS            Audio timestamp.
     968 * @param   cPacketDesc         Number of packet descriptors.
     969 * @param   paPacketDesc        Array of packet descriptors.
     970 */
     971static DECLCALLBACK(void) coreAudioInputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer,
     972                                                const AudioTimeStamp *pAudioTS,
     973                                                UInt32 cPacketDesc, const AudioStreamPacketDescription *paPacketDesc)
     974{
     975    RT_NOREF(audioQueue, pAudioTS, cPacketDesc, paPacketDesc);
     976
     977    PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
     978    AssertPtr(pCAStream);
     979
     980    int rc = RTCritSectEnter(&pCAStream->CritSect);
     981    AssertRC(rc);
     982
     983    rc = coreAudioInputQueueProcBuffer(pCAStream, audioBuffer);
     984    if (RT_SUCCESS(rc))
     985        AudioQueueEnqueueBuffer(audioQueue, audioBuffer, 0, NULL);
     986
     987    rc = RTCritSectLeave(&pCAStream->CritSect);
     988    AssertRC(rc);
     989}
     990
     991/**
     992 * Processes output data of a Core Audio stream into an audio queue buffer.
     993 *
     994 * @returns IPRT status code.
     995 * @param   pCAStream           Core Audio stream to process output data for.
     996 * @param   audioBuffer         Audio buffer to store data into.
     997 */
     998int coreAudioOutputQueueProcBuffer(PCOREAUDIOSTREAM pCAStream, AudioQueueBufferRef audioBuffer)
     999{
     1000    AssertPtr(pCAStream);
     1001
     1002    PRTCIRCBUF pCircBuf = pCAStream->pCircBuf;
     1003    AssertPtr(pCircBuf);
     1004
     1005    size_t cbRead = 0;
     1006
     1007    UInt8 *pvSrc = NULL;
     1008    UInt8 *pvDst = (UInt8 *)audioBuffer->mAudioData;
     1009
     1010    size_t cbToRead = RT_MIN(RTCircBufUsed(pCircBuf), audioBuffer->mAudioDataBytesCapacity);
     1011    size_t cbLeft   = cbToRead;
     1012
     1013    while (cbLeft)
     1014    {
     1015        /* Try to acquire the necessary block from the ring buffer. */
     1016        RTCircBufAcquireReadBlock(pCircBuf, cbLeft, (void **)&pvSrc, &cbToRead);
     1017
     1018        if (cbToRead)
     1019        {
     1020            /* Copy the data from our ring buffer to the core audio buffer. */
     1021            memcpy((UInt8 *)pvDst + cbRead, pvSrc, cbToRead);
     1022        }
     1023
     1024        /* Release the read buffer, so it could be used for new data. */
     1025        RTCircBufReleaseReadBlock(pCircBuf, cbToRead);
     1026
     1027        if (!cbToRead)
     1028            break;
     1029
     1030        /* Move offset. */
     1031        cbRead += cbToRead;
     1032        Assert(cbRead <= audioBuffer->mAudioDataBytesCapacity);
     1033
     1034        Assert(cbToRead <= cbLeft);
     1035        cbLeft -= cbToRead;
     1036    }
     1037
     1038    audioBuffer->mAudioDataByteSize = cbRead;
     1039
     1040    if (audioBuffer->mAudioDataByteSize < audioBuffer->mAudioDataBytesCapacity)
     1041    {
     1042        RT_BZERO((UInt8 *)audioBuffer->mAudioData + audioBuffer->mAudioDataByteSize,
     1043                 audioBuffer->mAudioDataBytesCapacity - audioBuffer->mAudioDataByteSize);
     1044
     1045        audioBuffer->mAudioDataByteSize = audioBuffer->mAudioDataBytesCapacity;
     1046    }
     1047
     1048    Log3Func(("pCAStream=%p, cbCapacity=%RU32, cbRead=%zu\n",
     1049              pCAStream, audioBuffer->mAudioDataBytesCapacity, cbRead));
     1050
     1051    return VINF_SUCCESS;
     1052}
     1053
     1054/**
     1055 * Output audio queue callback. Called whenever an audio queue is ready to process more output data.
     1056 *
     1057 * @param   pvUser              User argument.
     1058 * @param   audioQueue          Audio queue to process output data for.
     1059 * @param   audioBuffer         Audio buffer to store output data in. Must be part of audio queue.
     1060 */
     1061static DECLCALLBACK(void) coreAudioOutputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer)
     1062{
     1063    RT_NOREF(audioQueue);
     1064
     1065    PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
     1066    AssertPtr(pCAStream);
     1067
     1068    int rc = RTCritSectEnter(&pCAStream->CritSect);
     1069    AssertRC(rc);
     1070
     1071    rc = coreAudioOutputQueueProcBuffer(pCAStream, audioBuffer);
     1072    if (RT_SUCCESS(rc))
     1073        AudioQueueEnqueueBuffer(audioQueue, audioBuffer, 0, NULL);
     1074
     1075    rc = RTCritSectLeave(&pCAStream->CritSect);
     1076    AssertRC(rc);
     1077}
     1078
     1079/**
     1080 * Invalidates a Core Audio stream's audio queue.
     1081 *
     1082 * @returns IPRT status code.
     1083 * @param   pCAStream           Core Audio stream to invalidate its queue for.
     1084 */
     1085static int coreAudioStreamInvalidateQueue(PCOREAUDIOSTREAM pCAStream)
     1086{
     1087    int rc = VINF_SUCCESS;
     1088
     1089    Log3Func(("pCAStream=%p\n", pCAStream));
     1090
     1091    for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++)
     1092    {
     1093        AudioQueueBufferRef pBuf = pCAStream->audioBuffer[i];
     1094
     1095        if (pCAStream->pCfg->enmDir == PDMAUDIODIR_IN)
     1096        {
     1097            int rc2 = coreAudioInputQueueProcBuffer(pCAStream, pBuf);
     1098            if (RT_SUCCESS(rc2))
     1099            {
     1100                AudioQueueEnqueueBuffer(pCAStream->audioQueue, pBuf, 0, NULL);
     1101            }
     1102        }
     1103        else if (pCAStream->pCfg->enmDir == PDMAUDIODIR_OUT)
     1104        {
     1105            int rc2 = coreAudioOutputQueueProcBuffer(pCAStream, pBuf);
     1106            if (   RT_SUCCESS(rc2)
     1107                && pBuf->mAudioDataByteSize)
     1108            {
     1109                AudioQueueEnqueueBuffer(pCAStream->audioQueue, pBuf, 0, NULL);
     1110            }
     1111
     1112            if (RT_SUCCESS(rc))
     1113                rc = rc2;
     1114        }
     1115        else
     1116            AssertFailed();
     1117    }
     1118
     1119    return rc;
     1120}
     1121
     1122
     1123/* Callback for getting notified when some of the properties of an audio device have changed. */
     1124static DECLCALLBACK(OSStatus) coreAudioDevPropChgCb(AudioObjectID                     propertyID,
     1125                                                    UInt32                            cAddresses,
     1126                                                    const AudioObjectPropertyAddress  properties[],
     1127                                                    void                             *pvUser)
     1128{
     1129    RT_NOREF(cAddresses, properties, pvUser);
     1130
     1131    PCOREAUDIODEVICEDATA pDev = (PCOREAUDIODEVICEDATA)pvUser;
     1132    AssertPtr(pDev);
     1133
     1134    LogFlowFunc(("propertyID=%u, nAddresses=%u, pDev=%p\n", propertyID, cAddresses, pDev));
     1135
     1136    switch (propertyID)
     1137    {
     1138#ifdef DEBUG
     1139       case kAudioDeviceProcessorOverload:
     1140        {
     1141            LogFunc(("Processor overload detected!\n"));
     1142            break;
     1143        }
     1144#endif /* DEBUG */
     1145        case kAudioDevicePropertyNominalSampleRate:
     1146        {
     1147#ifndef VBOX_WITH_AUDIO_CALLBACKS
     1148            int rc2 = coreAudioDevicePropagateStatus(pDev, COREAUDIOSTATUS_REINIT);
     1149            AssertRC(rc2);
     1150#else
     1151            RT_NOREF(pDev);
     1152#endif
     1153            break;
     1154        }
     1155
     1156        default:
     1157            /* Just skip. */
     1158            break;
     1159    }
     1160
     1161    return noErr;
     1162}
     1163
     1164
     1165/*********************************************************************************************************************************
     1166*   PDMIHOSTAUDIO                                                                                                                *
     1167*********************************************************************************************************************************/
     1168
     1169/**
     1170 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
     1171 */
     1172static DECLCALLBACK(int) drvHostCoreAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
     1173{
     1174    PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
     1175    AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
     1176
     1177    /*
     1178     * Fill in the config structure.
     1179     */
     1180    RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "Core Audio");
     1181    pBackendCfg->cbStream       = sizeof(COREAUDIOSTREAM);
     1182    pBackendCfg->fFlags         = 0;
     1183    /* For Core Audio we provide one stream per device for now. */
     1184    pBackendCfg->cMaxStreamsIn  = PDMAudioHostEnumCountMatching(&pThis->Devices, PDMAUDIODIR_IN);
     1185    pBackendCfg->cMaxStreamsOut = PDMAudioHostEnumCountMatching(&pThis->Devices, PDMAUDIODIR_OUT);
     1186
     1187    LogFlowFunc(("Returning %Rrc\n", VINF_SUCCESS));
     1188    return VINF_SUCCESS;
     1189}
     1190
     1191
     1192/**
     1193 * Initializes a Core Audio-specific device data structure.
     1194 *
     1195 * @returns IPRT status code.
     1196 * @param   pDevData            Device data structure to initialize.
     1197 * @param   deviceID            Core Audio device ID to assign this structure to.
     1198 * @param   fIsInput            Whether this is an input device or not.
     1199 * @param   pDrv                Driver instance to use.
     1200 */
     1201static void coreAudioDeviceDataInit(PCOREAUDIODEVICEDATA pDevData, AudioDeviceID deviceID, bool fIsInput, PDRVHOSTCOREAUDIO pDrv)
     1202{
     1203    AssertPtrReturnVoid(pDevData);
     1204    AssertPtrReturnVoid(pDrv);
     1205
     1206    pDevData->deviceID = deviceID;
     1207    pDevData->pDrv     = pDrv;
     1208
     1209    /* Get the device UUID. */
     1210    AudioObjectPropertyAddress PropAddrDevUUID =
     1211    {
     1212        kAudioDevicePropertyDeviceUID,
     1213        fIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
     1214        kAudioObjectPropertyElementMaster
     1215    };
     1216    UInt32 uSize = sizeof(pDevData->UUID);
     1217    OSStatus err = AudioObjectGetPropertyData(pDevData->deviceID, &PropAddrDevUUID, 0, NULL, &uSize, &pDevData->UUID);
     1218    if (err != noErr)
     1219        LogRel(("CoreAudio: Failed to retrieve device UUID for device %RU32 (%RI32)\n", deviceID, err));
     1220
     1221    RTListInit(&pDevData->lstStreams);
     1222}
     1223
    5031224
    5041225/**
     
    8851606
    8861607/**
    887  * Initializes a Core Audio-specific device data structure.
     1608 * Registers callbacks for a specific Core Audio device.
     1609 *
     1610 * @return IPRT status code.
     1611 * @param  pThis                Host audio driver instance.
     1612 * @param  pDev                 Audio device to use for the registered callbacks.
     1613 */
     1614static int coreAudioDeviceRegisterCallbacks(PDRVHOSTCOREAUDIO pThis, PCOREAUDIODEVICEDATA pDev)
     1615{
     1616    RT_NOREF(pThis);
     1617
     1618    AudioDeviceID deviceID = kAudioDeviceUnknown;
     1619    Assert(pDev && pDev->Core.cbSelf == sizeof(*pDev));
     1620    if (pDev && pDev->Core.cbSelf == sizeof(*pDev)) /* paranoia or actually needed? */
     1621        deviceID = pDev->deviceID;
     1622
     1623    if (deviceID != kAudioDeviceUnknown)
     1624    {
     1625        LogFunc(("deviceID=%RU32\n", deviceID));
     1626
     1627        /*
     1628         * Register device callbacks.
     1629         */
     1630        AudioObjectPropertyAddress PropAddr =
     1631        {
     1632            kAudioDevicePropertyDeviceIsAlive,
     1633            kAudioObjectPropertyScopeGlobal,
     1634            kAudioObjectPropertyElementMaster
     1635        };
     1636        OSStatus err = AudioObjectAddPropertyListener(deviceID, &PropAddr, coreAudioDeviceStateChangedCb, pDev /* pvUser */);
     1637        if (   err != noErr
     1638            && err != kAudioHardwareIllegalOperationError)
     1639            LogRel(("CoreAudio: Failed to add the recording device state changed listener (%RI32)\n", err));
     1640
     1641        PropAddr.mSelector = kAudioDeviceProcessorOverload;
     1642        PropAddr.mScope    = kAudioUnitScope_Global;
     1643        err = AudioObjectAddPropertyListener(deviceID, &PropAddr, coreAudioDevPropChgCb, pDev /* pvUser */);
     1644        if (err != noErr)
     1645            LogRel(("CoreAudio: Failed to register processor overload listener (%RI32)\n", err));
     1646
     1647        PropAddr.mSelector = kAudioDevicePropertyNominalSampleRate;
     1648        PropAddr.mScope    = kAudioUnitScope_Global;
     1649        err = AudioObjectAddPropertyListener(deviceID, &PropAddr, coreAudioDevPropChgCb, pDev /* pvUser */);
     1650        if (err != noErr)
     1651            LogRel(("CoreAudio: Failed to register sample rate changed listener (%RI32)\n", err));
     1652    }
     1653
     1654    return VINF_SUCCESS;
     1655}
     1656
     1657
     1658/**
     1659 * Unregisters all formerly registered callbacks of a Core Audio device again.
     1660 *
     1661 * @return IPRT status code.
     1662 * @param  pThis                Host audio driver instance.
     1663 * @param  pDev                 Audio device to use for the registered callbacks.
     1664 */
     1665static int coreAudioDeviceUnregisterCallbacks(PDRVHOSTCOREAUDIO pThis, PCOREAUDIODEVICEDATA pDev)
     1666{
     1667    RT_NOREF(pThis);
     1668
     1669    AudioDeviceID deviceID = kAudioDeviceUnknown;
     1670    Assert(pDev && pDev->Core.cbSelf == sizeof(*pDev));
     1671    if (pDev && pDev->Core.cbSelf == sizeof(*pDev)) /* paranoia or actually needed? */
     1672        deviceID = pDev->deviceID;
     1673
     1674    if (deviceID != kAudioDeviceUnknown)
     1675    {
     1676        LogFunc(("deviceID=%RU32\n", deviceID));
     1677
     1678        /*
     1679         * Unregister per-device callbacks.
     1680         */
     1681        AudioObjectPropertyAddress PropAddr =
     1682        {
     1683            kAudioDeviceProcessorOverload,
     1684            kAudioObjectPropertyScopeGlobal,
     1685            kAudioObjectPropertyElementMaster
     1686        };
     1687        OSStatus err = AudioObjectRemovePropertyListener(deviceID, &PropAddr, coreAudioDevPropChgCb, pDev /* pvUser */);
     1688        if (   err != noErr
     1689            && err != kAudioHardwareBadObjectError)
     1690            LogRel(("CoreAudio: Failed to remove the recording processor overload listener (%RI32)\n", err));
     1691
     1692        PropAddr.mSelector = kAudioDevicePropertyNominalSampleRate;
     1693        err = AudioObjectRemovePropertyListener(deviceID, &PropAddr, coreAudioDevPropChgCb, pDev /* pvUser */);
     1694        if (   err != noErr
     1695            && err != kAudioHardwareBadObjectError)
     1696            LogRel(("CoreAudio: Failed to remove the sample rate changed listener (%RI32)\n", err));
     1697
     1698        PropAddr.mSelector = kAudioDevicePropertyDeviceIsAlive;
     1699        err = AudioObjectRemovePropertyListener(deviceID, &PropAddr, coreAudioDeviceStateChangedCb, pDev /* pvUser */);
     1700        if (   err != noErr
     1701            && err != kAudioHardwareBadObjectError)
     1702            LogRel(("CoreAudio: Failed to remove the device alive listener (%RI32)\n", err));
     1703    }
     1704
     1705    return VINF_SUCCESS;
     1706}
     1707
     1708
     1709/**
     1710 * Enumerates all available host audio devices internally.
    8881711 *
    8891712 * @returns IPRT status code.
    890  * @param   pDevData            Device data structure to initialize.
    891  * @param   deviceID            Core Audio device ID to assign this structure to.
    892  * @param   fIsInput            Whether this is an input device or not.
    893  * @param   pDrv                Driver instance to use.
    894  */
    895 static void coreAudioDeviceDataInit(PCOREAUDIODEVICEDATA pDevData, AudioDeviceID deviceID, bool fIsInput, PDRVHOSTCOREAUDIO pDrv)
    896 {
    897     AssertPtrReturnVoid(pDevData);
    898     AssertPtrReturnVoid(pDrv);
    899 
    900     pDevData->deviceID = deviceID;
    901     pDevData->pDrv     = pDrv;
    902 
    903     /* Get the device UUID. */
    904     AudioObjectPropertyAddress PropAddrDevUUID =
    905     {
    906         kAudioDevicePropertyDeviceUID,
    907         fIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
    908         kAudioObjectPropertyElementMaster
    909     };
    910     UInt32 uSize = sizeof(pDevData->UUID);
    911     OSStatus err = AudioObjectGetPropertyData(pDevData->deviceID, &PropAddrDevUUID, 0, NULL, &uSize, &pDevData->UUID);
    912     if (err != noErr)
    913         LogRel(("CoreAudio: Failed to retrieve device UUID for device %RU32 (%RI32)\n", deviceID, err));
    914 
    915     RTListInit(&pDevData->lstStreams);
    916 }
    917 
    918 
    919 /**
    920  * Propagates an audio device status to all its connected Core Audio streams.
    921  *
    922  * @return IPRT status code.
    923  * @param  pDev                 Audio device to propagate status for.
    924  * @param  enmSts               Status to propagate.
    925  */
    926 static int coreAudioDevicePropagateStatus(PCOREAUDIODEVICEDATA pDev, COREAUDIOSTATUS enmSts)
    927 {
    928     AssertPtrReturn(pDev, VERR_INVALID_POINTER);
    929 
    930 
    931     /* Sanity. */
    932     AssertPtr(pDev->pDrv);
    933 
    934     LogFlowFunc(("pDev=%p enmSts=%RU32\n", pDev, enmSts));
    935 
    936     PCOREAUDIOSTREAM pCAStream;
    937     RTListForEach(&pDev->lstStreams, pCAStream, COREAUDIOSTREAM, Node)
    938     {
    939         LogFlowFunc(("pCAStream=%p\n", pCAStream));
    940 
    941         /* We move the reinitialization to the next output event.
    942          * This make sure this thread isn't blocked and the
    943          * reinitialization is done when necessary only. */
    944         ASMAtomicXchgU32(&pCAStream->enmStatus, enmSts);
    945     }
    946 
    947     return VINF_SUCCESS;
    948 }
    949 
    950 
    951 static DECLCALLBACK(OSStatus) coreAudioDeviceStateChangedCb(AudioObjectID propertyID,
    952                                                             UInt32 nAddresses,
    953                                                             const AudioObjectPropertyAddress properties[],
    954                                                             void *pvUser)
    955 {
    956     RT_NOREF(propertyID, nAddresses, properties);
    957 
    958     LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));
    959 
    960     PCOREAUDIODEVICEDATA pDev = (PCOREAUDIODEVICEDATA)pvUser;
    961     AssertPtr(pDev);
    962 
    963     PDRVHOSTCOREAUDIO pThis = pDev->pDrv;
    964     AssertPtr(pThis);
    965 
    966     int rc2 = RTCritSectEnter(&pThis->CritSect);
    967     AssertRC(rc2);
    968 
    969     UInt32 uAlive = 1;
    970     UInt32 uSize  = sizeof(UInt32);
    971 
    972     AudioObjectPropertyAddress PropAddr =
    973     {
    974         kAudioDevicePropertyDeviceIsAlive,
    975         kAudioObjectPropertyScopeGlobal,
    976         kAudioObjectPropertyElementMaster
    977     };
    978 
    979     AudioDeviceID deviceID = pDev->deviceID;
    980 
    981     OSStatus err = AudioObjectGetPropertyData(deviceID, &PropAddr, 0, NULL, &uSize, &uAlive);
    982 
    983     bool fIsDead = false;
    984 
    985     if (err == kAudioHardwareBadDeviceError)
    986         fIsDead = true; /* Unplugged. */
    987     else if ((err == kAudioHardwareNoError) && (!RT_BOOL(uAlive)))
    988         fIsDead = true; /* Something else happened. */
    989 
    990     if (fIsDead)
    991     {
    992         LogRel2(("CoreAudio: Device '%s' stopped functioning\n", pDev->Core.szName));
    993 
    994         /* Mark device as dead. */
    995         rc2 = coreAudioDevicePropagateStatus(pDev, COREAUDIOSTATUS_UNINIT);
    996         AssertRC(rc2);
    997     }
    998 
    999     rc2 = RTCritSectLeave(&pThis->CritSect);
    1000     AssertRC(rc2);
    1001 
    1002     return noErr;
    1003 }
    1004 
    1005 /* Callback for getting notified when the default recording/playback device has been changed. */
    1006 /** @todo r=bird: Why DECLCALLBACK? */
    1007 static DECLCALLBACK(OSStatus) coreAudioDefaultDeviceChangedCb(AudioObjectID propertyID,
    1008                                                               UInt32 nAddresses,
    1009                                                               const AudioObjectPropertyAddress properties[],
    1010                                                               void *pvUser)
    1011 {
    1012     RT_NOREF(propertyID, nAddresses);
    1013 
    1014     LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));
    1015 
    1016     PDRVHOSTCOREAUDIO pThis = (PDRVHOSTCOREAUDIO)pvUser;
    1017     AssertPtr(pThis);
    1018 
    1019     int rc2 = RTCritSectEnter(&pThis->CritSect);
    1020     AssertRC(rc2);
    1021 
    1022     for (UInt32 idxAddress = 0; idxAddress < nAddresses; idxAddress++)
    1023     {
    1024         PCOREAUDIODEVICEDATA pDev = NULL;
    1025 
     1713 * @param   pThis               Host audio driver instance.
     1714 */
     1715static int coreAudioEnumerateDevices(PDRVHOSTCOREAUDIO pThis)
     1716{
     1717    LogFlowFuncEnter();
     1718
     1719    /*
     1720     * Unregister old default devices, if any.
     1721     */
     1722    if (pThis->pDefaultDevIn)
     1723    {
     1724        coreAudioDeviceUnregisterCallbacks(pThis, pThis->pDefaultDevIn);
     1725        pThis->pDefaultDevIn = NULL;
     1726    }
     1727
     1728    if (pThis->pDefaultDevOut)
     1729    {
     1730        coreAudioDeviceUnregisterCallbacks(pThis, pThis->pDefaultDevOut);
     1731        pThis->pDefaultDevOut = NULL;
     1732    }
     1733
     1734    /* Remove old / stale device entries. */
     1735    PDMAudioHostEnumDelete(&pThis->Devices);
     1736
     1737    /* Enumerate all devices internally. */
     1738    int rc = coreAudioDevicesEnumerateAll(pThis, &pThis->Devices);
     1739    if (RT_SUCCESS(rc))
     1740    {
    10261741        /*
    1027          * Check if the default input / output device has been changed.
     1742         * Default input device.
    10281743         */
    1029         const AudioObjectPropertyAddress *pProperty = &properties[idxAddress];
    1030         switch (pProperty->mSelector)
    1031         {
    1032             case kAudioHardwarePropertyDefaultInputDevice:
    1033                 LogFlowFunc(("kAudioHardwarePropertyDefaultInputDevice\n"));
    1034                 pDev = pThis->pDefaultDevIn;
    1035                 break;
    1036 
    1037             case kAudioHardwarePropertyDefaultOutputDevice:
    1038                 LogFlowFunc(("kAudioHardwarePropertyDefaultOutputDevice\n"));
    1039                 pDev = pThis->pDefaultDevOut;
    1040                 break;
    1041 
    1042             default:
    1043                 /* Skip others. */
    1044                 break;
     1744        pThis->pDefaultDevIn = (PCOREAUDIODEVICEDATA)PDMAudioHostEnumGetDefault(&pThis->Devices, PDMAUDIODIR_IN);
     1745        if (pThis->pDefaultDevIn)
     1746        {
     1747            LogRel2(("CoreAudio: Default capturing device is '%s'\n", pThis->pDefaultDevIn->Core.szName));
     1748            LogFunc(("pDefaultDevIn=%p, ID=%RU32\n", pThis->pDefaultDevIn, pThis->pDefaultDevIn->deviceID));
     1749            rc = coreAudioDeviceRegisterCallbacks(pThis, pThis->pDefaultDevIn);
    10451750        }
    1046 
    1047         LogFlowFunc(("pDev=%p\n", pDev));
    1048 
    1049 #ifndef VBOX_WITH_AUDIO_CALLBACKS
    1050         if (pDev)
    1051         {
    1052             /* This listener is called on every change of the hardware
    1053              * device. So check if the default device has really changed. */
    1054             UInt32 uSize = sizeof(AudioDeviceID);
    1055             UInt32 uResp = 0;
    1056 
    1057             OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, pProperty, 0, NULL, &uSize, &uResp);
    1058             if (err == noErr)
     1751        else
     1752            LogRel2(("CoreAudio: No default capturing device found\n"));
     1753
     1754        /*
     1755         * Default output device.
     1756         */
     1757        pThis->pDefaultDevOut = (PCOREAUDIODEVICEDATA)PDMAudioHostEnumGetDefault(&pThis->Devices, PDMAUDIODIR_OUT);
     1758        if (pThis->pDefaultDevOut)
     1759        {
     1760            LogRel2(("CoreAudio: Default playback device is '%s'\n", pThis->pDefaultDevOut->Core.szName));
     1761            LogFunc(("pDefaultDevOut=%p, ID=%RU32\n", pThis->pDefaultDevOut, pThis->pDefaultDevOut->deviceID));
     1762            rc = coreAudioDeviceRegisterCallbacks(pThis, pThis->pDefaultDevOut);
     1763        }
     1764        else
     1765            LogRel2(("CoreAudio: No default playback device found\n"));
     1766    }
     1767
     1768    LogFunc(("Returning %Rrc\n", rc));
     1769    return rc;
     1770}
     1771
     1772
     1773/**
     1774 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetDevices}
     1775 */
     1776static DECLCALLBACK(int) drvHostCoreAudioHA_GetDevices(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHOSTENUM pDeviceEnum)
     1777{
     1778    AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
     1779    AssertPtrReturn(pDeviceEnum, VERR_INVALID_POINTER);
     1780
     1781    PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
     1782
     1783    int rc = RTCritSectEnter(&pThis->CritSect);
     1784    if (RT_SUCCESS(rc))
     1785    {
     1786        rc = coreAudioEnumerateDevices(pThis);
     1787        if (RT_SUCCESS(rc))
     1788        {
     1789            if (pDeviceEnum)
    10591790            {
    1060                 if (pDev->deviceID != uResp) /* Has the device ID changed? */
    1061                 {
    1062                     rc2 = coreAudioDevicePropagateStatus(pDev, COREAUDIOSTATUS_REINIT);
    1063                     AssertRC(rc2);
    1064                 }
     1791                /* Return a copy with only PDMAUDIOHOSTDEV, none of the extra bits in COREAUDIODEVICEDATA. */
     1792                PDMAudioHostEnumInit(pDeviceEnum);
     1793                rc = PDMAudioHostEnumCopy(pDeviceEnum, &pThis->Devices, PDMAUDIODIR_INVALID /*all*/, true /*fOnlyCoreData*/);
     1794                if (RT_FAILURE(rc))
     1795                    PDMAudioHostEnumDelete(pDeviceEnum);
    10651796            }
    10661797        }
    1067 #endif /* VBOX_WITH_AUDIO_CALLBACKS */
    1068     }
    1069 
    1070     /* Make sure to leave the critical section before notify higher drivers/devices. */
    1071     rc2 = RTCritSectLeave(&pThis->CritSect);
    1072     AssertRC(rc2);
    1073 
    1074 #ifdef VBOX_WITH_AUDIO_CALLBACKS
    1075     /* Notify the driver/device above us about possible changes in devices. */
    1076     if (pThis->pIHostAudioPort)
    1077         pThis->pIHostAudioPort->pfnNotifyDevicesChanged(pThis->pIHostAudioPort);
    1078 #endif
    1079 
    1080     return noErr;
    1081 }
    1082 
    1083 #ifndef VBOX_WITH_AUDIO_CALLBACKS
    1084 
    1085 /**
    1086  * Re-initializes a Core Audio stream with a specific audio device and stream configuration.
    1087  *
    1088  * @return IPRT status code.
    1089  * @param  pThis                Driver instance.
    1090  * @param  pCAStream            Audio stream to re-initialize.
    1091  * @param  pDev                 Audio device to use for re-initialization.
    1092  * @param  pCfg                 Stream configuration to use for re-initialization.
    1093  */
    1094 static int coreAudioStreamReinitEx(PDRVHOSTCOREAUDIO pThis, PCOREAUDIOSTREAM pCAStream,
    1095                                    PCOREAUDIODEVICEDATA pDev, PPDMAUDIOSTREAMCFG pCfg)
    1096 {
    1097     LogFunc(("pCAStream=%p\n", pCAStream));
    1098 
    1099     int rc = coreAudioStreamUninit(pCAStream);
    1100     if (RT_SUCCESS(rc))
    1101     {
    1102         rc = coreAudioStreamInit(pCAStream, pThis, pDev);
    1103         if (RT_SUCCESS(rc))
    1104         {
    1105             rc = coreAudioStreamInitQueue(pCAStream, pCfg /* pCfgReq */, NULL /* pCfgAcq */);
    1106             if (RT_SUCCESS(rc))
    1107                 rc = coreAudioStreamControl(pCAStream->pDrv, pCAStream, PDMAUDIOSTREAMCMD_ENABLE);
    1108 
    1109             if (RT_FAILURE(rc))
    1110             {
    1111                 int rc2 = coreAudioStreamUninit(pCAStream);
    1112                 AssertRC(rc2);
    1113             }
    1114         }
    1115     }
    1116 
    1117     if (RT_FAILURE(rc))
    1118         LogRel(("CoreAudio: Unable to re-init stream: %Rrc\n", rc));
    1119 
     1798
     1799        int rc2 = RTCritSectLeave(&pThis->CritSect);
     1800        AssertRC(rc2);
     1801    }
     1802
     1803    LogFlowFunc(("Returning %Rrc\n", rc));
    11201804    return rc;
    11211805}
    11221806
    1123 /**
    1124  * Re-initializes a Core Audio stream with a specific audio device.
    1125  *
    1126  * @return IPRT status code.
    1127  * @param  pThis                Driver instance.
    1128  * @param  pCAStream            Audio stream to re-initialize.
    1129  * @param  pDev                 Audio device to use for re-initialization.
    1130  */
    1131 static int coreAudioStreamReinit(PDRVHOSTCOREAUDIO pThis, PCOREAUDIOSTREAM pCAStream, PCOREAUDIODEVICEDATA pDev)
    1132 {
    1133     int rc = coreAudioStreamUninit(pCAStream);
    1134     if (RT_SUCCESS(rc))
    1135     {
    1136         /* Use the acquired stream configuration from the former initialization to
    1137          * re-initialize the stream. */
    1138         PDMAUDIOSTREAMCFG CfgAcq;
    1139         rc = coreAudioASBDToStreamCfg(&pCAStream->Unit.streamFmt, &CfgAcq);
    1140         if (RT_SUCCESS(rc))
    1141             rc = coreAudioStreamReinitEx(pThis, pCAStream, pDev, &CfgAcq);
    1142     }
    1143 
    1144     return rc;
    1145 }
    1146 
    1147 #endif /* !VBOX_WITH_AUDIO_CALLBACKS */
    1148 
    1149 #ifdef VBOX_WITH_AUDIO_CA_CONVERTER
    1150 /* Callback to convert audio input data from one format to another. */
    1151 static DECLCALLBACK(OSStatus) coreAudioConverterCb(AudioConverterRef              inAudioConverter,
    1152                                                    UInt32                        *ioNumberDataPackets,
    1153                                                    AudioBufferList               *ioData,
    1154                                                    AudioStreamPacketDescription **ppASPD,
    1155                                                    void                          *pvUser)
    1156 {
    1157     RT_NOREF(inAudioConverter);
    1158 
    1159     AssertPtrReturn(ioNumberDataPackets, caConverterEOFDErr);
    1160     AssertPtrReturn(ioData,              caConverterEOFDErr);
    1161 
    1162     PCOREAUDIOCONVCBCTX pConvCbCtx = (PCOREAUDIOCONVCBCTX)pvUser;
    1163     AssertPtr(pConvCbCtx);
    1164 
    1165     /* Initialize values. */
    1166     ioData->mBuffers[0].mNumberChannels = 0;
    1167     ioData->mBuffers[0].mDataByteSize   = 0;
    1168     ioData->mBuffers[0].mData           = NULL;
    1169 
    1170     if (ppASPD)
    1171     {
    1172         Log3Func(("Handling packet description not implemented\n"));
    1173     }
    1174     else
    1175     {
    1176         /** @todo Check converter ID? */
    1177 
    1178         /** @todo Handled non-interleaved data by going through the full buffer list,
    1179          *        not only through the first buffer like we do now. */
    1180         Log3Func(("ioNumberDataPackets=%RU32\n", *ioNumberDataPackets));
    1181 
    1182         UInt32 cNumberDataPackets = *ioNumberDataPackets;
    1183         Assert(pConvCbCtx->uPacketIdx + cNumberDataPackets <= pConvCbCtx->uPacketCnt);
    1184 
    1185         if (cNumberDataPackets)
    1186         {
    1187             AssertPtr(pConvCbCtx->pBufLstSrc);
    1188             Assert(pConvCbCtx->pBufLstSrc->mNumberBuffers == 1); /* Only one buffer for the source supported atm. */
    1189 
    1190             AudioStreamBasicDescription *pSrcASBD = &pConvCbCtx->asbdSrc;
    1191             AudioBuffer                 *pSrcBuf  = &pConvCbCtx->pBufLstSrc->mBuffers[0];
    1192 
    1193             size_t cbOff   = pConvCbCtx->uPacketIdx * pSrcASBD->mBytesPerPacket;
    1194 
    1195             cNumberDataPackets = RT_MIN((pSrcBuf->mDataByteSize - cbOff) / pSrcASBD->mBytesPerPacket,
    1196                                         cNumberDataPackets);
    1197 
    1198             void  *pvAvail = (uint8_t *)pSrcBuf->mData + cbOff;
    1199             size_t cbAvail = RT_MIN(pSrcBuf->mDataByteSize - cbOff, cNumberDataPackets * pSrcASBD->mBytesPerPacket);
    1200 
    1201             Log3Func(("cNumberDataPackets=%RU32, cbOff=%zu, cbAvail=%zu\n", cNumberDataPackets, cbOff, cbAvail));
    1202 
    1203             /* Set input data for the converter to use.
    1204              * Note: For VBR (Variable Bit Rates) or interleaved data handling we need multiple buffers here. */
    1205             ioData->mNumberBuffers = 1;
    1206 
    1207             ioData->mBuffers[0].mNumberChannels = pSrcBuf->mNumberChannels;
    1208             ioData->mBuffers[0].mDataByteSize   = cbAvail;
    1209             ioData->mBuffers[0].mData           = pvAvail;
    1210 
    1211 #ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
    1212             RTFILE fh;
    1213             int rc = RTFileOpen(&fh,VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "caConverterCbInput.pcm",
    1214                                 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
    1215             if (RT_SUCCESS(rc))
    1216             {
    1217                 RTFileWrite(fh, pvAvail, cbAvail, NULL);
    1218                 RTFileClose(fh);
    1219             }
    1220             else
    1221                 AssertFailed();
    1222 #endif
    1223             pConvCbCtx->uPacketIdx += cNumberDataPackets;
    1224             Assert(pConvCbCtx->uPacketIdx <= pConvCbCtx->uPacketCnt);
    1225 
    1226             *ioNumberDataPackets = cNumberDataPackets;
    1227         }
    1228     }
    1229 
    1230     Log3Func(("%RU32 / %RU32 -> ioNumberDataPackets=%RU32\n",
    1231               pConvCbCtx->uPacketIdx, pConvCbCtx->uPacketCnt, *ioNumberDataPackets));
    1232 
    1233     return noErr;
    1234 }
    1235 #endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
    1236 
    1237 
    1238 /**
    1239  * Initializes a Core Audio stream.
    1240  *
    1241  * @return IPRT status code.
    1242  * @param  pThis                Driver instance.
    1243  * @param  pCAStream            Stream to initialize.
    1244  * @param  pDev                 Audio device to use for this stream.
    1245  */
    1246 static int coreAudioStreamInit(PCOREAUDIOSTREAM pCAStream, PDRVHOSTCOREAUDIO pThis, PCOREAUDIODEVICEDATA pDev)
    1247 {
    1248     AssertPtrReturn(pCAStream, VERR_INVALID_POINTER);
    1249     AssertPtrReturn(pThis,     VERR_INVALID_POINTER);
    1250     AssertPtrReturn(pDev,      VERR_INVALID_POINTER);
    1251 
    1252     Assert(pCAStream->Unit.pDevice == NULL); /* Make sure no device is assigned yet. */
    1253     Assert(pDev->Core.cbSelf == sizeof(COREAUDIODEVICEDATA));
    1254 
    1255     LogFunc(("pCAStream=%p, pDev=%p ('%s', ID=%RU32)\n", pCAStream, pDev, pDev->Core.szName, pDev->deviceID));
    1256 
    1257     pCAStream->Unit.pDevice = pDev;
    1258     pCAStream->pDrv = pThis;
    1259 
    1260     return VINF_SUCCESS;
    1261 }
    1262 
    1263 # define CA_BREAK_STMT(stmt) \
    1264     stmt; \
    1265     break;
    1266 
    1267 /**
    1268  * Thread for a Core Audio stream's audio queue handling.
    1269  *
    1270  * This thread is required per audio queue to pump data to/from the Core Audio
    1271  * stream and handling its callbacks.
    1272  *
    1273  * @returns IPRT status code.
    1274  * @param   hThreadSelf         Thread handle.
    1275  * @param   pvUser              User argument.
    1276  */
    1277 static DECLCALLBACK(int) coreAudioQueueThread(RTTHREAD hThreadSelf, void *pvUser)
    1278 {
    1279     RT_NOREF(hThreadSelf);
    1280 
    1281     PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
    1282     AssertPtr(pCAStream);
    1283     AssertPtr(pCAStream->pCfg);
    1284 
    1285     const bool fIn = pCAStream->pCfg->enmDir == PDMAUDIODIR_IN;
    1286 
    1287     LogFunc(("Thread started for pCAStream=%p, fIn=%RTbool\n", pCAStream, fIn));
    1288 
    1289     /*
    1290      * Create audio queue.
    1291      */
    1292     OSStatus err;
    1293     if (fIn)
    1294         err = AudioQueueNewInput(&pCAStream->asbdStream, coreAudioInputQueueCb, pCAStream /* pvData */,
    1295                                  CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &pCAStream->audioQueue);
    1296     else
    1297         err = AudioQueueNewOutput(&pCAStream->asbdStream, coreAudioOutputQueueCb, pCAStream /* pvData */,
    1298                                   CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &pCAStream->audioQueue);
    1299 
    1300     if (err != noErr)
    1301         return VERR_GENERAL_FAILURE; /** @todo Fudge! */
    1302 
    1303     /*
    1304      * Assign device to queue.
    1305      */
    1306     PCOREAUDIODEVICEDATA pDev = (PCOREAUDIODEVICEDATA)pCAStream->Unit.pDevice;
    1307     AssertPtr(pDev);
    1308 
    1309     UInt32 uSize = sizeof(pDev->UUID);
    1310     err = AudioQueueSetProperty(pCAStream->audioQueue, kAudioQueueProperty_CurrentDevice, &pDev->UUID, uSize);
    1311     if (err != noErr)
    1312         return VERR_GENERAL_FAILURE; /** @todo Fudge! */
    1313 
    1314     const size_t cbBufSize = PDMAudioPropsFramesToBytes(&pCAStream->pCfg->Props, pCAStream->pCfg->Backend.cFramesPeriod);
    1315 
    1316     /*
    1317      * Allocate audio buffers.
    1318      */
    1319     for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++)
    1320     {
    1321         err = AudioQueueAllocateBuffer(pCAStream->audioQueue, cbBufSize, &pCAStream->audioBuffer[i]);
    1322         if (err != noErr)
    1323             break;
    1324     }
    1325 
    1326     if (err != noErr)
    1327         return VERR_GENERAL_FAILURE; /** @todo Fudge! */
    1328 
    1329     /* Signal the main thread before entering the main loop. */
    1330     RTThreadUserSignal(RTThreadSelf());
    1331 
    1332     /*
    1333      * Enter the main loop.
    1334      */
    1335     while (!ASMAtomicReadBool(&pCAStream->fShutdown))
    1336     {
    1337         CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
    1338     }
    1339 
    1340     /*
    1341      * Cleanup.
    1342      */
    1343     if (fIn)
    1344     {
    1345         AudioQueueStop(pCAStream->audioQueue, 1);
    1346     }
    1347     else
    1348     {
    1349         AudioQueueStop(pCAStream->audioQueue, 0);
    1350     }
    1351 
    1352     for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++)
    1353     {
    1354         if (pCAStream->audioBuffer[i])
    1355             AudioQueueFreeBuffer(pCAStream->audioQueue, pCAStream->audioBuffer[i]);
    1356     }
    1357 
    1358     AudioQueueDispose(pCAStream->audioQueue, 1);
    1359 
    1360     LogFunc(("Thread ended for pCAStream=%p, fIn=%RTbool\n", pCAStream, fIn));
    1361     return VINF_SUCCESS;
    1362 }
    1363 
    1364 /**
    1365  * Processes input data of an audio queue buffer and stores it into a Core Audio stream.
    1366  *
    1367  * @returns IPRT status code.
    1368  * @param   pCAStream           Core Audio stream to store input data into.
    1369  * @param   audioBuffer         Audio buffer to process input data from.
    1370  */
    1371 int coreAudioInputQueueProcBuffer(PCOREAUDIOSTREAM pCAStream, AudioQueueBufferRef audioBuffer)
    1372 {
    1373     PRTCIRCBUF pCircBuf = pCAStream->pCircBuf;
    1374     AssertPtr(pCircBuf);
    1375 
    1376     UInt8 *pvSrc = (UInt8 *)audioBuffer->mAudioData;
    1377     UInt8 *pvDst = NULL;
    1378 
    1379     size_t cbWritten = 0;
    1380 
    1381     size_t cbToWrite = audioBuffer->mAudioDataByteSize;
    1382     size_t cbLeft    = RT_MIN(cbToWrite, RTCircBufFree(pCircBuf));
    1383 
    1384     while (cbLeft)
    1385     {
    1386         /* Try to acquire the necessary block from the ring buffer. */
    1387         RTCircBufAcquireWriteBlock(pCircBuf, cbLeft, (void **)&pvDst, &cbToWrite);
    1388 
    1389         if (!cbToWrite)
    1390             break;
    1391 
    1392         /* Copy the data from our ring buffer to the core audio buffer. */
    1393         memcpy((UInt8 *)pvDst, pvSrc + cbWritten, cbToWrite);
    1394 
    1395         /* Release the read buffer, so it could be used for new data. */
    1396         RTCircBufReleaseWriteBlock(pCircBuf, cbToWrite);
    1397 
    1398         cbWritten += cbToWrite;
    1399 
    1400         Assert(cbLeft >= cbToWrite);
    1401         cbLeft -= cbToWrite;
    1402     }
    1403 
    1404     Log3Func(("pCAStream=%p, cbBuffer=%RU32/%zu, cbWritten=%zu\n",
    1405               pCAStream, audioBuffer->mAudioDataByteSize, audioBuffer->mAudioDataBytesCapacity, cbWritten));
    1406 
    1407     return VINF_SUCCESS;
    1408 }
    1409 
    1410 /**
    1411  * Input audio queue callback. Called whenever input data from the audio queue becomes available.
    1412  *
    1413  * @param   pvUser              User argument.
    1414  * @param   audioQueue          Audio queue to process input data from.
    1415  * @param   audioBuffer         Audio buffer to process input data from. Must be part of audio queue.
    1416  * @param   pAudioTS            Audio timestamp.
    1417  * @param   cPacketDesc         Number of packet descriptors.
    1418  * @param   paPacketDesc        Array of packet descriptors.
    1419  */
    1420 static DECLCALLBACK(void) coreAudioInputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer,
    1421                                                 const AudioTimeStamp *pAudioTS,
    1422                                                 UInt32 cPacketDesc, const AudioStreamPacketDescription *paPacketDesc)
    1423 {
    1424     RT_NOREF(audioQueue, pAudioTS, cPacketDesc, paPacketDesc);
    1425 
    1426     PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
    1427     AssertPtr(pCAStream);
    1428 
    1429     int rc = RTCritSectEnter(&pCAStream->CritSect);
    1430     AssertRC(rc);
    1431 
    1432     rc = coreAudioInputQueueProcBuffer(pCAStream, audioBuffer);
    1433     if (RT_SUCCESS(rc))
    1434         AudioQueueEnqueueBuffer(audioQueue, audioBuffer, 0, NULL);
    1435 
    1436     rc = RTCritSectLeave(&pCAStream->CritSect);
    1437     AssertRC(rc);
    1438 }
    1439 
    1440 /**
    1441  * Processes output data of a Core Audio stream into an audio queue buffer.
    1442  *
    1443  * @returns IPRT status code.
    1444  * @param   pCAStream           Core Audio stream to process output data for.
    1445  * @param   audioBuffer         Audio buffer to store data into.
    1446  */
    1447 int coreAudioOutputQueueProcBuffer(PCOREAUDIOSTREAM pCAStream, AudioQueueBufferRef audioBuffer)
    1448 {
    1449     AssertPtr(pCAStream);
    1450 
    1451     PRTCIRCBUF pCircBuf = pCAStream->pCircBuf;
    1452     AssertPtr(pCircBuf);
    1453 
    1454     size_t cbRead = 0;
    1455 
    1456     UInt8 *pvSrc = NULL;
    1457     UInt8 *pvDst = (UInt8 *)audioBuffer->mAudioData;
    1458 
    1459     size_t cbToRead = RT_MIN(RTCircBufUsed(pCircBuf), audioBuffer->mAudioDataBytesCapacity);
    1460     size_t cbLeft   = cbToRead;
    1461 
    1462     while (cbLeft)
    1463     {
    1464         /* Try to acquire the necessary block from the ring buffer. */
    1465         RTCircBufAcquireReadBlock(pCircBuf, cbLeft, (void **)&pvSrc, &cbToRead);
    1466 
    1467         if (cbToRead)
    1468         {
    1469             /* Copy the data from our ring buffer to the core audio buffer. */
    1470             memcpy((UInt8 *)pvDst + cbRead, pvSrc, cbToRead);
    1471         }
    1472 
    1473         /* Release the read buffer, so it could be used for new data. */
    1474         RTCircBufReleaseReadBlock(pCircBuf, cbToRead);
    1475 
    1476         if (!cbToRead)
    1477             break;
    1478 
    1479         /* Move offset. */
    1480         cbRead += cbToRead;
    1481         Assert(cbRead <= audioBuffer->mAudioDataBytesCapacity);
    1482 
    1483         Assert(cbToRead <= cbLeft);
    1484         cbLeft -= cbToRead;
    1485     }
    1486 
    1487     audioBuffer->mAudioDataByteSize = cbRead;
    1488 
    1489     if (audioBuffer->mAudioDataByteSize < audioBuffer->mAudioDataBytesCapacity)
    1490     {
    1491         RT_BZERO((UInt8 *)audioBuffer->mAudioData + audioBuffer->mAudioDataByteSize,
    1492                  audioBuffer->mAudioDataBytesCapacity - audioBuffer->mAudioDataByteSize);
    1493 
    1494         audioBuffer->mAudioDataByteSize = audioBuffer->mAudioDataBytesCapacity;
    1495     }
    1496 
    1497     Log3Func(("pCAStream=%p, cbCapacity=%RU32, cbRead=%zu\n",
    1498               pCAStream, audioBuffer->mAudioDataBytesCapacity, cbRead));
    1499 
    1500     return VINF_SUCCESS;
    1501 }
    1502 
    1503 /**
    1504  * Output audio queue callback. Called whenever an audio queue is ready to process more output data.
    1505  *
    1506  * @param   pvUser              User argument.
    1507  * @param   audioQueue          Audio queue to process output data for.
    1508  * @param   audioBuffer         Audio buffer to store output data in. Must be part of audio queue.
    1509  */
    1510 static DECLCALLBACK(void) coreAudioOutputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer)
    1511 {
    1512     RT_NOREF(audioQueue);
    1513 
    1514     PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
    1515     AssertPtr(pCAStream);
    1516 
    1517     int rc = RTCritSectEnter(&pCAStream->CritSect);
    1518     AssertRC(rc);
    1519 
    1520     rc = coreAudioOutputQueueProcBuffer(pCAStream, audioBuffer);
    1521     if (RT_SUCCESS(rc))
    1522         AudioQueueEnqueueBuffer(audioQueue, audioBuffer, 0, NULL);
    1523 
    1524     rc = RTCritSectLeave(&pCAStream->CritSect);
    1525     AssertRC(rc);
    1526 }
    1527 
    1528 /**
    1529  * Invalidates a Core Audio stream's audio queue.
    1530  *
    1531  * @returns IPRT status code.
    1532  * @param   pCAStream           Core Audio stream to invalidate its queue for.
    1533  */
    1534 static int coreAudioStreamInvalidateQueue(PCOREAUDIOSTREAM pCAStream)
    1535 {
    1536     int rc = VINF_SUCCESS;
    1537 
    1538     Log3Func(("pCAStream=%p\n", pCAStream));
    1539 
    1540     for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++)
    1541     {
    1542         AudioQueueBufferRef pBuf = pCAStream->audioBuffer[i];
    1543 
    1544         if (pCAStream->pCfg->enmDir == PDMAUDIODIR_IN)
    1545         {
    1546             int rc2 = coreAudioInputQueueProcBuffer(pCAStream, pBuf);
    1547             if (RT_SUCCESS(rc2))
    1548             {
    1549                 AudioQueueEnqueueBuffer(pCAStream->audioQueue, pBuf, 0, NULL);
    1550             }
    1551         }
    1552         else if (pCAStream->pCfg->enmDir == PDMAUDIODIR_OUT)
    1553         {
    1554             int rc2 = coreAudioOutputQueueProcBuffer(pCAStream, pBuf);
    1555             if (   RT_SUCCESS(rc2)
    1556                 && pBuf->mAudioDataByteSize)
    1557             {
    1558                 AudioQueueEnqueueBuffer(pCAStream->audioQueue, pBuf, 0, NULL);
    1559             }
    1560 
    1561             if (RT_SUCCESS(rc))
    1562                 rc = rc2;
    1563         }
    1564         else
    1565             AssertFailed();
    1566     }
    1567 
    1568     return rc;
    1569 }
     1807
     1808/**
     1809 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
     1810 */
     1811static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostCoreAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
     1812{
     1813    RT_NOREF(pInterface, enmDir);
     1814    AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
     1815
     1816    return PDMAUDIOBACKENDSTS_RUNNING;
     1817}
     1818
    15701819
    15711820/**
     
    16341883}
    16351884
    1636 /**
    1637  * Unitializes a Core Audio stream's audio queue.
    1638  *
    1639  * @returns IPRT status code.
    1640  * @param   pCAStream           Core Audio stream to unitialize audio queue for.
    1641  */
    1642 static int coreAudioStreamUninitQueue(PCOREAUDIOSTREAM pCAStream)
    1643 {
    1644     LogFunc(("pCAStream=%p\n", pCAStream));
    1645 
    1646     if (pCAStream->hThread != NIL_RTTHREAD)
    1647     {
    1648         LogFunc(("Waiting for thread ...\n"));
    1649 
    1650         ASMAtomicXchgBool(&pCAStream->fShutdown, true);
    1651 
    1652         int rcThread;
    1653         int rc = RTThreadWait(pCAStream->hThread, 30 * 1000, &rcThread);
    1654         if (RT_FAILURE(rc))
    1655             return rc;
    1656 
    1657         RT_NOREF(rcThread);
    1658         LogFunc(("Thread stopped with %Rrc\n", rcThread));
    1659 
    1660         pCAStream->hThread = NIL_RTTHREAD;
    1661     }
    1662 
    1663     if (pCAStream->pCfg)
    1664     {
    1665         PDMAudioStrmCfgFree(pCAStream->pCfg);
    1666         pCAStream->pCfg = NULL;
    1667     }
    1668 
    1669     if (pCAStream->pCircBuf)
    1670     {
    1671         RTCircBufDestroy(pCAStream->pCircBuf);
    1672         pCAStream->pCircBuf = NULL;
    1673     }
    1674 
    1675     LogFunc(("Returning\n"));
     1885
     1886/**
     1887 * Initializes a Core Audio stream.
     1888 *
     1889 * @return IPRT status code.
     1890 * @param  pThis                Driver instance.
     1891 * @param  pCAStream            Stream to initialize.
     1892 * @param  pDev                 Audio device to use for this stream.
     1893 */
     1894static int coreAudioStreamInit(PCOREAUDIOSTREAM pCAStream, PDRVHOSTCOREAUDIO pThis, PCOREAUDIODEVICEDATA pDev)
     1895{
     1896    AssertPtrReturn(pCAStream, VERR_INVALID_POINTER);
     1897    AssertPtrReturn(pThis,     VERR_INVALID_POINTER);
     1898    AssertPtrReturn(pDev,      VERR_INVALID_POINTER);
     1899
     1900    Assert(pCAStream->Unit.pDevice == NULL); /* Make sure no device is assigned yet. */
     1901    Assert(pDev->Core.cbSelf == sizeof(COREAUDIODEVICEDATA));
     1902
     1903    LogFunc(("pCAStream=%p, pDev=%p ('%s', ID=%RU32)\n", pCAStream, pDev, pDev->Core.szName, pDev->deviceID));
     1904
     1905    pCAStream->Unit.pDevice = pDev;
     1906    pCAStream->pDrv = pThis;
     1907
    16761908    return VINF_SUCCESS;
    16771909}
    16781910
    1679 /**
    1680  * Unitializes a Core Audio stream.
    1681  *
    1682  * @returns IPRT status code.
    1683  * @param   pCAStream           Core Audio stream to uninitialize.
    1684  */
    1685 static int coreAudioStreamUninit(PCOREAUDIOSTREAM pCAStream)
    1686 {
    1687     LogFunc(("pCAStream=%p\n", pCAStream));
    1688 
    1689     int rc = coreAudioStreamUninitQueue(pCAStream);
    1690     if (RT_SUCCESS(rc))
    1691     {
    1692         pCAStream->Unit.pDevice = NULL;
    1693         pCAStream->pDrv         = NULL;
    1694     }
    1695 
    1696     return rc;
    1697 }
    1698 
    1699 /**
    1700  * Registers callbacks for a specific Core Audio device.
    1701  *
    1702  * @return IPRT status code.
    1703  * @param  pThis                Host audio driver instance.
    1704  * @param  pDev                 Audio device to use for the registered callbacks.
    1705  */
    1706 static int coreAudioDeviceRegisterCallbacks(PDRVHOSTCOREAUDIO pThis, PCOREAUDIODEVICEDATA pDev)
    1707 {
    1708     RT_NOREF(pThis);
    1709 
    1710     AudioDeviceID deviceID = kAudioDeviceUnknown;
    1711     Assert(pDev && pDev->Core.cbSelf == sizeof(*pDev));
    1712     if (pDev && pDev->Core.cbSelf == sizeof(*pDev)) /* paranoia or actually needed? */
    1713         deviceID = pDev->deviceID;
    1714 
    1715     if (deviceID != kAudioDeviceUnknown)
    1716     {
    1717         LogFunc(("deviceID=%RU32\n", deviceID));
    1718 
    1719         /*
    1720          * Register device callbacks.
    1721          */
    1722         AudioObjectPropertyAddress PropAddr =
    1723         {
    1724             kAudioDevicePropertyDeviceIsAlive,
    1725             kAudioObjectPropertyScopeGlobal,
    1726             kAudioObjectPropertyElementMaster
    1727         };
    1728         OSStatus err = AudioObjectAddPropertyListener(deviceID, &PropAddr, coreAudioDeviceStateChangedCb, pDev /* pvUser */);
    1729         if (   err != noErr
    1730             && err != kAudioHardwareIllegalOperationError)
    1731             LogRel(("CoreAudio: Failed to add the recording device state changed listener (%RI32)\n", err));
    1732 
    1733         PropAddr.mSelector = kAudioDeviceProcessorOverload;
    1734         PropAddr.mScope    = kAudioUnitScope_Global;
    1735         err = AudioObjectAddPropertyListener(deviceID, &PropAddr, coreAudioDevPropChgCb, pDev /* pvUser */);
    1736         if (err != noErr)
    1737             LogRel(("CoreAudio: Failed to register processor overload listener (%RI32)\n", err));
    1738 
    1739         PropAddr.mSelector = kAudioDevicePropertyNominalSampleRate;
    1740         PropAddr.mScope    = kAudioUnitScope_Global;
    1741         err = AudioObjectAddPropertyListener(deviceID, &PropAddr, coreAudioDevPropChgCb, pDev /* pvUser */);
    1742         if (err != noErr)
    1743             LogRel(("CoreAudio: Failed to register sample rate changed listener (%RI32)\n", err));
    1744     }
    1745 
    1746     return VINF_SUCCESS;
    1747 }
    1748 
    1749 /**
    1750  * Unregisters all formerly registered callbacks of a Core Audio device again.
    1751  *
    1752  * @return IPRT status code.
    1753  * @param  pThis                Host audio driver instance.
    1754  * @param  pDev                 Audio device to use for the registered callbacks.
    1755  */
    1756 static int coreAudioDeviceUnregisterCallbacks(PDRVHOSTCOREAUDIO pThis, PCOREAUDIODEVICEDATA pDev)
    1757 {
    1758     RT_NOREF(pThis);
    1759 
    1760     AudioDeviceID deviceID = kAudioDeviceUnknown;
    1761     Assert(pDev && pDev->Core.cbSelf == sizeof(*pDev));
    1762     if (pDev && pDev->Core.cbSelf == sizeof(*pDev)) /* paranoia or actually needed? */
    1763         deviceID = pDev->deviceID;
    1764 
    1765     if (deviceID != kAudioDeviceUnknown)
    1766     {
    1767         LogFunc(("deviceID=%RU32\n", deviceID));
    1768 
    1769         /*
    1770          * Unregister per-device callbacks.
    1771          */
    1772         AudioObjectPropertyAddress PropAddr =
    1773         {
    1774             kAudioDeviceProcessorOverload,
    1775             kAudioObjectPropertyScopeGlobal,
    1776             kAudioObjectPropertyElementMaster
    1777         };
    1778         OSStatus err = AudioObjectRemovePropertyListener(deviceID, &PropAddr, coreAudioDevPropChgCb, pDev /* pvUser */);
    1779         if (   err != noErr
    1780             && err != kAudioHardwareBadObjectError)
    1781             LogRel(("CoreAudio: Failed to remove the recording processor overload listener (%RI32)\n", err));
    1782 
    1783         PropAddr.mSelector = kAudioDevicePropertyNominalSampleRate;
    1784         err = AudioObjectRemovePropertyListener(deviceID, &PropAddr, coreAudioDevPropChgCb, pDev /* pvUser */);
    1785         if (   err != noErr
    1786             && err != kAudioHardwareBadObjectError)
    1787             LogRel(("CoreAudio: Failed to remove the sample rate changed listener (%RI32)\n", err));
    1788 
    1789         PropAddr.mSelector = kAudioDevicePropertyDeviceIsAlive;
    1790         err = AudioObjectRemovePropertyListener(deviceID, &PropAddr, coreAudioDeviceStateChangedCb, pDev /* pvUser */);
    1791         if (   err != noErr
    1792             && err != kAudioHardwareBadObjectError)
    1793             LogRel(("CoreAudio: Failed to remove the device alive listener (%RI32)\n", err));
    1794     }
    1795 
    1796     return VINF_SUCCESS;
    1797 }
    1798 
    1799 /* Callback for getting notified when some of the properties of an audio device have changed. */
    1800 static DECLCALLBACK(OSStatus) coreAudioDevPropChgCb(AudioObjectID                     propertyID,
    1801                                                     UInt32                            cAddresses,
    1802                                                     const AudioObjectPropertyAddress  properties[],
    1803                                                     void                             *pvUser)
    1804 {
    1805     RT_NOREF(cAddresses, properties, pvUser);
    1806 
    1807     PCOREAUDIODEVICEDATA pDev = (PCOREAUDIODEVICEDATA)pvUser;
    1808     AssertPtr(pDev);
    1809 
    1810     LogFlowFunc(("propertyID=%u, nAddresses=%u, pDev=%p\n", propertyID, cAddresses, pDev));
    1811 
    1812     switch (propertyID)
    1813     {
    1814 #ifdef DEBUG
    1815        case kAudioDeviceProcessorOverload:
    1816         {
    1817             LogFunc(("Processor overload detected!\n"));
    1818             break;
     1911
     1912/**
     1913 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
     1914 */
     1915static DECLCALLBACK(int) drvHostCoreAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
     1916                                                         PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     1917{
     1918    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     1919    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     1920    AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
     1921    AssertPtrReturn(pCfgAcq,    VERR_INVALID_POINTER);
     1922
     1923    PDRVHOSTCOREAUDIO pThis     = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
     1924    PCOREAUDIOSTREAM  pCAStream = (PCOREAUDIOSTREAM)pStream;
     1925
     1926    int rc = RTCritSectInit(&pCAStream->CritSect);
     1927    if (RT_FAILURE(rc))
     1928        return rc;
     1929
     1930    pCAStream->hThread    = NIL_RTTHREAD;
     1931    pCAStream->fRun       = false;
     1932    pCAStream->fIsRunning = false;
     1933    pCAStream->fShutdown  = false;
     1934
     1935    /* Input or output device? */
     1936    bool fIn = pCfgReq->enmDir == PDMAUDIODIR_IN;
     1937
     1938    /* For now, just use the default device available. */
     1939    PCOREAUDIODEVICEDATA pDev = fIn ? pThis->pDefaultDevIn : pThis->pDefaultDevOut;
     1940
     1941    LogFunc(("pStream=%p, pCfgReq=%p, pCfgAcq=%p, fIn=%RTbool, pDev=%p\n", pStream, pCfgReq, pCfgAcq, fIn, pDev));
     1942
     1943    if (pDev) /* (Default) device available? */
     1944    {
     1945        /* Sanity. */
     1946        Assert(pDev->Core.cbSelf == sizeof(*pDev));
     1947
     1948        /* Init the Core Audio stream. */
     1949        rc = coreAudioStreamInit(pCAStream, pThis, pDev);
     1950        if (RT_SUCCESS(rc))
     1951        {
     1952            ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_IN_INIT);
     1953
     1954            rc = coreAudioStreamInitQueue(pCAStream, pCfgReq, pCfgAcq);
     1955            if (RT_SUCCESS(rc))
     1956            {
     1957                ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_INIT);
     1958            }
     1959            else
     1960            {
     1961                ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_IN_UNINIT);
     1962
     1963                int rc2 = coreAudioStreamUninit(pCAStream);
     1964                AssertRC(rc2);
     1965
     1966                ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_UNINIT);
     1967            }
    18191968        }
    1820 #endif /* DEBUG */
    1821         case kAudioDevicePropertyNominalSampleRate:
    1822         {
    1823 #ifndef VBOX_WITH_AUDIO_CALLBACKS
    1824             int rc2 = coreAudioDevicePropagateStatus(pDev, COREAUDIOSTATUS_REINIT);
    1825             AssertRC(rc2);
    1826 #else
    1827             RT_NOREF(pDev);
    1828 #endif
    1829             break;
    1830         }
    1831 
    1832         default:
    1833             /* Just skip. */
    1834             break;
    1835     }
    1836 
    1837     return noErr;
    1838 }
    1839 
    1840 /**
    1841  * Enumerates all available host audio devices internally.
    1842  *
    1843  * @returns IPRT status code.
    1844  * @param   pThis               Host audio driver instance.
    1845  */
    1846 static int coreAudioEnumerateDevices(PDRVHOSTCOREAUDIO pThis)
    1847 {
    1848     LogFlowFuncEnter();
    1849 
    1850     /*
    1851      * Unregister old default devices, if any.
    1852      */
    1853     if (pThis->pDefaultDevIn)
    1854     {
    1855         coreAudioDeviceUnregisterCallbacks(pThis, pThis->pDefaultDevIn);
    1856         pThis->pDefaultDevIn = NULL;
    1857     }
    1858 
    1859     if (pThis->pDefaultDevOut)
    1860     {
    1861         coreAudioDeviceUnregisterCallbacks(pThis, pThis->pDefaultDevOut);
    1862         pThis->pDefaultDevOut = NULL;
    1863     }
    1864 
    1865     /* Remove old / stale device entries. */
    1866     PDMAudioHostEnumDelete(&pThis->Devices);
    1867 
    1868     /* Enumerate all devices internally. */
    1869     int rc = coreAudioDevicesEnumerateAll(pThis, &pThis->Devices);
    1870     if (RT_SUCCESS(rc))
    1871     {
    1872         /*
    1873          * Default input device.
    1874          */
    1875         pThis->pDefaultDevIn = (PCOREAUDIODEVICEDATA)PDMAudioHostEnumGetDefault(&pThis->Devices, PDMAUDIODIR_IN);
    1876         if (pThis->pDefaultDevIn)
    1877         {
    1878             LogRel2(("CoreAudio: Default capturing device is '%s'\n", pThis->pDefaultDevIn->Core.szName));
    1879             LogFunc(("pDefaultDevIn=%p, ID=%RU32\n", pThis->pDefaultDevIn, pThis->pDefaultDevIn->deviceID));
    1880             rc = coreAudioDeviceRegisterCallbacks(pThis, pThis->pDefaultDevIn);
    1881         }
    1882         else
    1883             LogRel2(("CoreAudio: No default capturing device found\n"));
    1884 
    1885         /*
    1886          * Default output device.
    1887          */
    1888         pThis->pDefaultDevOut = (PCOREAUDIODEVICEDATA)PDMAudioHostEnumGetDefault(&pThis->Devices, PDMAUDIODIR_OUT);
    1889         if (pThis->pDefaultDevOut)
    1890         {
    1891             LogRel2(("CoreAudio: Default playback device is '%s'\n", pThis->pDefaultDevOut->Core.szName));
    1892             LogFunc(("pDefaultDevOut=%p, ID=%RU32\n", pThis->pDefaultDevOut, pThis->pDefaultDevOut->deviceID));
    1893             rc = coreAudioDeviceRegisterCallbacks(pThis, pThis->pDefaultDevOut);
    1894         }
    1895         else
    1896             LogRel2(("CoreAudio: No default playback device found\n"));
    1897     }
     1969    }
     1970    else
     1971        rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
    18981972
    18991973    LogFunc(("Returning %Rrc\n", rc));
     
    19011975}
    19021976
    1903 /**
    1904  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
    1905  */
    1906 static DECLCALLBACK(int) drvHostCoreAudioHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
    1907                                                           void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
    1908 {
    1909     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    1910     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    1911     AssertPtrReturn(pcbRead, VERR_INVALID_POINTER);
    1912 
    1913     PCOREAUDIOSTREAM  pCAStream = (PCOREAUDIOSTREAM)pStream;
    1914     PDRVHOSTCOREAUDIO pThis     = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
    1915 
    1916 #ifndef VBOX_WITH_AUDIO_CALLBACKS
    1917     /* Check if the audio device should be reinitialized. If so do it. */
    1918     if (ASMAtomicReadU32(&pCAStream->enmStatus) == COREAUDIOSTATUS_REINIT)
    1919     {
    1920         /* For now re just re-initialize with the current input device. */
    1921         if (pThis->pDefaultDevIn)
    1922         {
    1923             int rc2 = coreAudioStreamReinit(pThis, pCAStream, pThis->pDefaultDevIn);
    1924             if (RT_FAILURE(rc2))
    1925                 return VERR_NOT_AVAILABLE;
    1926         }
    1927         else
    1928             return VERR_NOT_AVAILABLE;
    1929     }
    1930 #else
    1931     RT_NOREF(pThis);
    1932 #endif
    1933 
    1934     if (ASMAtomicReadU32(&pCAStream->enmStatus) != COREAUDIOSTATUS_INIT)
    1935     {
    1936         *pcbRead = 0;
    1937         return VINF_SUCCESS;
    1938     }
    1939 
    1940     int rc = VINF_SUCCESS;
    1941 
    1942     uint32_t cbReadTotal = 0;
    1943 
    1944     rc = RTCritSectEnter(&pCAStream->CritSect);
    1945     AssertRC(rc);
    1946 
    1947     do
    1948     {
    1949         size_t cbToWrite = RT_MIN(cbBuf, RTCircBufUsed(pCAStream->pCircBuf));
    1950 
    1951         uint8_t *pvChunk;
    1952         size_t   cbChunk;
    1953 
    1954         Log3Func(("cbToWrite=%zu/%zu\n", cbToWrite, RTCircBufSize(pCAStream->pCircBuf)));
    1955 
    1956         while (cbToWrite)
    1957         {
    1958             /* Try to acquire the necessary block from the ring buffer. */
    1959             RTCircBufAcquireReadBlock(pCAStream->pCircBuf, cbToWrite, (void **)&pvChunk, &cbChunk);
    1960             if (cbChunk)
    1961                 memcpy((uint8_t *)pvBuf + cbReadTotal, pvChunk, cbChunk);
    1962 
    1963             /* Release the read buffer, so it could be used for new data. */
    1964             RTCircBufReleaseReadBlock(pCAStream->pCircBuf, cbChunk);
    1965 
    1966             if (RT_FAILURE(rc))
    1967                 break;
    1968 
    1969             Assert(cbToWrite >= cbChunk);
    1970             cbToWrite      -= cbChunk;
    1971 
    1972             cbReadTotal    += cbChunk;
    1973         }
    1974     }
    1975     while (0);
    1976 
    1977     int rc2 = RTCritSectLeave(&pCAStream->CritSect);
    1978     AssertRC(rc2);
    1979 
    1980     if (RT_SUCCESS(rc))
    1981         *pcbRead = cbReadTotal;
    1982 
    1983     return rc;
    1984 }
    1985 
    1986 /**
    1987  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
    1988  */
    1989 static DECLCALLBACK(int) drvHostCoreAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
    1990                                                        const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
    1991 {
    1992     PDRVHOSTCOREAUDIO pThis     = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
    1993     PCOREAUDIOSTREAM  pCAStream = (PCOREAUDIOSTREAM)pStream;
    1994 
    1995 #ifndef VBOX_WITH_AUDIO_CALLBACKS
    1996     /* Check if the audio device should be reinitialized. If so do it. */
    1997     if (ASMAtomicReadU32(&pCAStream->enmStatus) == COREAUDIOSTATUS_REINIT)
    1998     {
    1999         if (pThis->pDefaultDevOut)
    2000         {
    2001             /* For now re just re-initialize with the current output device. */
    2002             int rc2 = coreAudioStreamReinit(pThis, pCAStream, pThis->pDefaultDevOut);
    2003             if (RT_FAILURE(rc2))
    2004                 return VERR_NOT_AVAILABLE;
    2005         }
    2006         else
    2007             return VERR_NOT_AVAILABLE;
    2008     }
    2009 #else
    2010     RT_NOREF(pThis);
    2011 #endif
    2012 
    2013     if (ASMAtomicReadU32(&pCAStream->enmStatus) != COREAUDIOSTATUS_INIT)
    2014     {
    2015         *pcbWritten = 0;
    2016         return VINF_SUCCESS;
    2017     }
    2018 
    2019     uint32_t cbWrittenTotal = 0;
    2020 
    2021     int rc = VINF_SUCCESS;
    2022 
    2023     rc = RTCritSectEnter(&pCAStream->CritSect);
    2024     AssertRC(rc);
    2025 
    2026     size_t cbToWrite = RT_MIN(cbBuf, RTCircBufFree(pCAStream->pCircBuf));
    2027     Log3Func(("cbToWrite=%zu\n", cbToWrite));
    2028 
    2029     uint8_t *pvChunk;
    2030     size_t   cbChunk;
    2031 
    2032     while (cbToWrite)
    2033     {
    2034         /* Try to acquire the necessary space from the ring buffer. */
    2035         RTCircBufAcquireWriteBlock(pCAStream->pCircBuf, cbToWrite, (void **)&pvChunk, &cbChunk);
    2036         if (!cbChunk)
    2037         {
    2038             RTCircBufReleaseWriteBlock(pCAStream->pCircBuf, cbChunk);
    2039             break;
    2040         }
    2041 
    2042         Assert(cbChunk <= cbToWrite);
    2043         Assert(cbWrittenTotal + cbChunk <= cbBuf);
    2044 
    2045         memcpy(pvChunk, (uint8_t *)pvBuf + cbWrittenTotal, cbChunk);
    2046 
    2047 #ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
    2048         RTFILE fh;
    2049         rc = RTFileOpen(&fh,VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "caPlayback.pcm",
    2050                         RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
    2051         if (RT_SUCCESS(rc))
    2052         {
    2053             RTFileWrite(fh, pvChunk, cbChunk, NULL);
    2054             RTFileClose(fh);
    2055         }
    2056         else
    2057             AssertFailed();
    2058 #endif
    2059 
    2060         /* Release the ring buffer, so the read thread could start reading this data. */
    2061         RTCircBufReleaseWriteBlock(pCAStream->pCircBuf, cbChunk);
    2062 
    2063         if (RT_FAILURE(rc))
    2064             break;
    2065 
    2066         Assert(cbToWrite >= cbChunk);
    2067         cbToWrite      -= cbChunk;
    2068 
    2069         cbWrittenTotal += cbChunk;
    2070     }
    2071 
    2072     if (    RT_SUCCESS(rc)
    2073         &&  pCAStream->fRun
    2074         && !pCAStream->fIsRunning)
    2075     {
    2076         rc = coreAudioStreamInvalidateQueue(pCAStream);
    2077         if (RT_SUCCESS(rc))
    2078         {
    2079             AudioQueueStart(pCAStream->audioQueue, NULL);
    2080             pCAStream->fRun       = false;
    2081             pCAStream->fIsRunning = true;
    2082         }
    2083     }
    2084 
    2085     int rc2 = RTCritSectLeave(&pCAStream->CritSect);
    2086     AssertRC(rc2);
    2087 
    2088     if (RT_SUCCESS(rc))
    2089         *pcbWritten = cbWrittenTotal;
    2090 
    2091     return rc;
    2092 }
    20931977
    20941978static int coreAudioStreamControl(PDRVHOSTCOREAUDIO pThis, PCOREAUDIOSTREAM pCAStream, PDMAUDIOSTREAMCMD enmStreamCmd)
     
    21652049
    21662050/**
    2167  * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
    2168  */
    2169 static DECLCALLBACK(int) drvHostCoreAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
    2170 {
    2171     PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
    2172     AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
    2173 
    2174     /*
    2175      * Fill in the config structure.
    2176      */
    2177     RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "Core Audio");
    2178     pBackendCfg->cbStream       = sizeof(COREAUDIOSTREAM);
    2179     pBackendCfg->fFlags         = 0;
    2180     /* For Core Audio we provide one stream per device for now. */
    2181     pBackendCfg->cMaxStreamsIn  = PDMAudioHostEnumCountMatching(&pThis->Devices, PDMAUDIODIR_IN);
    2182     pBackendCfg->cMaxStreamsOut = PDMAudioHostEnumCountMatching(&pThis->Devices, PDMAUDIODIR_OUT);
    2183 
    2184     LogFlowFunc(("Returning %Rrc\n", VINF_SUCCESS));
     2051 * Unitializes a Core Audio stream's audio queue.
     2052 *
     2053 * @returns IPRT status code.
     2054 * @param   pCAStream           Core Audio stream to unitialize audio queue for.
     2055 */
     2056static int coreAudioStreamUninitQueue(PCOREAUDIOSTREAM pCAStream)
     2057{
     2058    LogFunc(("pCAStream=%p\n", pCAStream));
     2059
     2060    if (pCAStream->hThread != NIL_RTTHREAD)
     2061    {
     2062        LogFunc(("Waiting for thread ...\n"));
     2063
     2064        ASMAtomicXchgBool(&pCAStream->fShutdown, true);
     2065
     2066        int rcThread;
     2067        int rc = RTThreadWait(pCAStream->hThread, 30 * 1000, &rcThread);
     2068        if (RT_FAILURE(rc))
     2069            return rc;
     2070
     2071        RT_NOREF(rcThread);
     2072        LogFunc(("Thread stopped with %Rrc\n", rcThread));
     2073
     2074        pCAStream->hThread = NIL_RTTHREAD;
     2075    }
     2076
     2077    if (pCAStream->pCfg)
     2078    {
     2079        PDMAudioStrmCfgFree(pCAStream->pCfg);
     2080        pCAStream->pCfg = NULL;
     2081    }
     2082
     2083    if (pCAStream->pCircBuf)
     2084    {
     2085        RTCircBufDestroy(pCAStream->pCircBuf);
     2086        pCAStream->pCircBuf = NULL;
     2087    }
     2088
     2089    LogFunc(("Returning\n"));
    21852090    return VINF_SUCCESS;
    21862091}
     
    21882093
    21892094/**
    2190  * @interface_method_impl{PDMIHOSTAUDIO,pfnGetDevices}
    2191  */
    2192 static DECLCALLBACK(int) drvHostCoreAudioHA_GetDevices(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHOSTENUM pDeviceEnum)
    2193 {
    2194     AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
    2195     AssertPtrReturn(pDeviceEnum, VERR_INVALID_POINTER);
    2196 
    2197     PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
    2198 
    2199     int rc = RTCritSectEnter(&pThis->CritSect);
     2095 * Unitializes a Core Audio stream.
     2096 *
     2097 * @returns IPRT status code.
     2098 * @param   pCAStream           Core Audio stream to uninitialize.
     2099 */
     2100static int coreAudioStreamUninit(PCOREAUDIOSTREAM pCAStream)
     2101{
     2102    LogFunc(("pCAStream=%p\n", pCAStream));
     2103
     2104    int rc = coreAudioStreamUninitQueue(pCAStream);
    22002105    if (RT_SUCCESS(rc))
    22012106    {
    2202         rc = coreAudioEnumerateDevices(pThis);
    2203         if (RT_SUCCESS(rc))
    2204         {
    2205             if (pDeviceEnum)
    2206             {
    2207                 /* Return a copy with only PDMAUDIOHOSTDEV, none of the extra bits in COREAUDIODEVICEDATA. */
    2208                 PDMAudioHostEnumInit(pDeviceEnum);
    2209                 rc = PDMAudioHostEnumCopy(pDeviceEnum, &pThis->Devices, PDMAUDIODIR_INVALID /*all*/, true /*fOnlyCoreData*/);
    2210                 if (RT_FAILURE(rc))
    2211                     PDMAudioHostEnumDelete(pDeviceEnum);
    2212             }
    2213         }
    2214 
    2215         int rc2 = RTCritSectLeave(&pThis->CritSect);
    2216         AssertRC(rc2);
    2217     }
    2218 
    2219     LogFlowFunc(("Returning %Rrc\n", rc));
    2220     return rc;
    2221 }
    2222 
    2223 
    2224 /**
    2225  * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
    2226  */
    2227 static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostCoreAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
    2228 {
    2229     RT_NOREF(pInterface, enmDir);
    2230     AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
    2231 
    2232     return PDMAUDIOBACKENDSTS_RUNNING;
    2233 }
    2234 
    2235 
    2236 /**
    2237  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
    2238  */
    2239 static DECLCALLBACK(int) drvHostCoreAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
    2240                                                          PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    2241 {
    2242     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    2243     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    2244     AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
    2245     AssertPtrReturn(pCfgAcq,    VERR_INVALID_POINTER);
    2246 
    2247     PDRVHOSTCOREAUDIO pThis     = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
    2248     PCOREAUDIOSTREAM  pCAStream = (PCOREAUDIOSTREAM)pStream;
    2249 
    2250     int rc = RTCritSectInit(&pCAStream->CritSect);
    2251     if (RT_FAILURE(rc))
    2252         return rc;
    2253 
    2254     pCAStream->hThread    = NIL_RTTHREAD;
    2255     pCAStream->fRun       = false;
    2256     pCAStream->fIsRunning = false;
    2257     pCAStream->fShutdown  = false;
    2258 
    2259     /* Input or output device? */
    2260     bool fIn = pCfgReq->enmDir == PDMAUDIODIR_IN;
    2261 
    2262     /* For now, just use the default device available. */
    2263     PCOREAUDIODEVICEDATA pDev = fIn ? pThis->pDefaultDevIn : pThis->pDefaultDevOut;
    2264 
    2265     LogFunc(("pStream=%p, pCfgReq=%p, pCfgAcq=%p, fIn=%RTbool, pDev=%p\n", pStream, pCfgReq, pCfgAcq, fIn, pDev));
    2266 
    2267     if (pDev) /* (Default) device available? */
    2268     {
    2269         /* Sanity. */
    2270         Assert(pDev->Core.cbSelf == sizeof(*pDev));
    2271 
    2272         /* Init the Core Audio stream. */
    2273         rc = coreAudioStreamInit(pCAStream, pThis, pDev);
    2274         if (RT_SUCCESS(rc))
    2275         {
    2276             ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_IN_INIT);
    2277 
    2278             rc = coreAudioStreamInitQueue(pCAStream, pCfgReq, pCfgAcq);
    2279             if (RT_SUCCESS(rc))
    2280             {
    2281                 ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_INIT);
    2282             }
    2283             else
    2284             {
    2285                 ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_IN_UNINIT);
    2286 
    2287                 int rc2 = coreAudioStreamUninit(pCAStream);
    2288                 AssertRC(rc2);
    2289 
    2290                 ASMAtomicXchgU32(&pCAStream->enmStatus, COREAUDIOSTATUS_UNINIT);
    2291             }
    2292         }
    2293     }
    2294     else
    2295         rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
    2296 
    2297     LogFunc(("Returning %Rrc\n", rc));
     2107        pCAStream->Unit.pDevice = NULL;
     2108        pCAStream->pDrv         = NULL;
     2109    }
     2110
    22982111    return rc;
    22992112}
     
    24462259}
    24472260
     2261/**
     2262 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
     2263 */
     2264static DECLCALLBACK(int) drvHostCoreAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
     2265                                                       const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
     2266{
     2267    PDRVHOSTCOREAUDIO pThis     = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
     2268    PCOREAUDIOSTREAM  pCAStream = (PCOREAUDIOSTREAM)pStream;
     2269
     2270#ifndef VBOX_WITH_AUDIO_CALLBACKS
     2271    /* Check if the audio device should be reinitialized. If so do it. */
     2272    if (ASMAtomicReadU32(&pCAStream->enmStatus) == COREAUDIOSTATUS_REINIT)
     2273    {
     2274        if (pThis->pDefaultDevOut)
     2275        {
     2276            /* For now re just re-initialize with the current output device. */
     2277            int rc2 = coreAudioStreamReinit(pThis, pCAStream, pThis->pDefaultDevOut);
     2278            if (RT_FAILURE(rc2))
     2279                return VERR_NOT_AVAILABLE;
     2280        }
     2281        else
     2282            return VERR_NOT_AVAILABLE;
     2283    }
     2284#else
     2285    RT_NOREF(pThis);
     2286#endif
     2287
     2288    if (ASMAtomicReadU32(&pCAStream->enmStatus) != COREAUDIOSTATUS_INIT)
     2289    {
     2290        *pcbWritten = 0;
     2291        return VINF_SUCCESS;
     2292    }
     2293
     2294    uint32_t cbWrittenTotal = 0;
     2295
     2296    int rc = VINF_SUCCESS;
     2297
     2298    rc = RTCritSectEnter(&pCAStream->CritSect);
     2299    AssertRC(rc);
     2300
     2301    size_t cbToWrite = RT_MIN(cbBuf, RTCircBufFree(pCAStream->pCircBuf));
     2302    Log3Func(("cbToWrite=%zu\n", cbToWrite));
     2303
     2304    uint8_t *pvChunk;
     2305    size_t   cbChunk;
     2306
     2307    while (cbToWrite)
     2308    {
     2309        /* Try to acquire the necessary space from the ring buffer. */
     2310        RTCircBufAcquireWriteBlock(pCAStream->pCircBuf, cbToWrite, (void **)&pvChunk, &cbChunk);
     2311        if (!cbChunk)
     2312        {
     2313            RTCircBufReleaseWriteBlock(pCAStream->pCircBuf, cbChunk);
     2314            break;
     2315        }
     2316
     2317        Assert(cbChunk <= cbToWrite);
     2318        Assert(cbWrittenTotal + cbChunk <= cbBuf);
     2319
     2320        memcpy(pvChunk, (uint8_t *)pvBuf + cbWrittenTotal, cbChunk);
     2321
     2322#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
     2323        RTFILE fh;
     2324        rc = RTFileOpen(&fh,VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "caPlayback.pcm",
     2325                        RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
     2326        if (RT_SUCCESS(rc))
     2327        {
     2328            RTFileWrite(fh, pvChunk, cbChunk, NULL);
     2329            RTFileClose(fh);
     2330        }
     2331        else
     2332            AssertFailed();
     2333#endif
     2334
     2335        /* Release the ring buffer, so the read thread could start reading this data. */
     2336        RTCircBufReleaseWriteBlock(pCAStream->pCircBuf, cbChunk);
     2337
     2338        if (RT_FAILURE(rc))
     2339            break;
     2340
     2341        Assert(cbToWrite >= cbChunk);
     2342        cbToWrite      -= cbChunk;
     2343
     2344        cbWrittenTotal += cbChunk;
     2345    }
     2346
     2347    if (    RT_SUCCESS(rc)
     2348        &&  pCAStream->fRun
     2349        && !pCAStream->fIsRunning)
     2350    {
     2351        rc = coreAudioStreamInvalidateQueue(pCAStream);
     2352        if (RT_SUCCESS(rc))
     2353        {
     2354            AudioQueueStart(pCAStream->audioQueue, NULL);
     2355            pCAStream->fRun       = false;
     2356            pCAStream->fIsRunning = true;
     2357        }
     2358    }
     2359
     2360    int rc2 = RTCritSectLeave(&pCAStream->CritSect);
     2361    AssertRC(rc2);
     2362
     2363    if (RT_SUCCESS(rc))
     2364        *pcbWritten = cbWrittenTotal;
     2365
     2366    return rc;
     2367}
     2368
     2369
     2370/**
     2371 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
     2372 */
     2373static DECLCALLBACK(int) drvHostCoreAudioHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
     2374                                                          void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
     2375{
     2376    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     2377    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
     2378    AssertPtrReturn(pcbRead, VERR_INVALID_POINTER);
     2379
     2380    PCOREAUDIOSTREAM  pCAStream = (PCOREAUDIOSTREAM)pStream;
     2381    PDRVHOSTCOREAUDIO pThis     = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
     2382
     2383#ifndef VBOX_WITH_AUDIO_CALLBACKS
     2384    /* Check if the audio device should be reinitialized. If so do it. */
     2385    if (ASMAtomicReadU32(&pCAStream->enmStatus) == COREAUDIOSTATUS_REINIT)
     2386    {
     2387        /* For now re just re-initialize with the current input device. */
     2388        if (pThis->pDefaultDevIn)
     2389        {
     2390            int rc2 = coreAudioStreamReinit(pThis, pCAStream, pThis->pDefaultDevIn);
     2391            if (RT_FAILURE(rc2))
     2392                return VERR_NOT_AVAILABLE;
     2393        }
     2394        else
     2395            return VERR_NOT_AVAILABLE;
     2396    }
     2397#else
     2398    RT_NOREF(pThis);
     2399#endif
     2400
     2401    if (ASMAtomicReadU32(&pCAStream->enmStatus) != COREAUDIOSTATUS_INIT)
     2402    {
     2403        *pcbRead = 0;
     2404        return VINF_SUCCESS;
     2405    }
     2406
     2407    int rc = RTCritSectEnter(&pCAStream->CritSect);
     2408    AssertRCReturn(rc, rc);
     2409
     2410    size_t cbToWrite = RT_MIN(cbBuf, RTCircBufUsed(pCAStream->pCircBuf));
     2411    Log3Func(("cbToWrite=%zu/%zu\n", cbToWrite, RTCircBufSize(pCAStream->pCircBuf)));
     2412
     2413    uint32_t cbReadTotal = 0;
     2414    while (cbToWrite > 0)
     2415    {
     2416        void    *pvChunk = NULL;
     2417        size_t   cbChunk = 0;
     2418        RTCircBufAcquireReadBlock(pCAStream->pCircBuf, cbToWrite, &pvChunk, &cbChunk);
     2419
     2420        AssertStmt(cbChunk <= cbToWrite, cbChunk = cbToWrite);
     2421        memcpy((uint8_t *)pvBuf + cbReadTotal, pvChunk, cbChunk);
     2422
     2423        RTCircBufReleaseReadBlock(pCAStream->pCircBuf, cbChunk);
     2424
     2425        cbToWrite      -= cbChunk;
     2426        cbReadTotal    += cbChunk;
     2427    }
     2428
     2429    *pcbRead = cbReadTotal;
     2430
     2431    RTCritSectLeave(&pCAStream->CritSect);
     2432    return VINF_SUCCESS;
     2433}
     2434
     2435
     2436/*********************************************************************************************************************************
     2437*   PDMIBASE                                                                                                                     *
     2438*********************************************************************************************************************************/
    24482439
    24492440/**
     
    24602451    return NULL;
    24612452}
     2453
     2454
     2455/*********************************************************************************************************************************
     2456*   PDMDRVREG                                                                                                                    *
     2457*********************************************************************************************************************************/
    24622458
    24632459/**
     
    25482544    /* IHostAudio */
    25492545    pThis->IHostAudio.pfnGetConfig                  = drvHostCoreAudioHA_GetConfig;
     2546    pThis->IHostAudio.pfnGetDevices                 = drvHostCoreAudioHA_GetDevices;
    25502547    pThis->IHostAudio.pfnGetStatus                  = drvHostCoreAudioHA_GetStatus;
    25512548    pThis->IHostAudio.pfnDoOnWorkerThread           = NULL;
     
    25622559    pThis->IHostAudio.pfnStreamPlay                 = drvHostCoreAudioHA_StreamPlay;
    25632560    pThis->IHostAudio.pfnStreamCapture              = drvHostCoreAudioHA_StreamCapture;
    2564     pThis->IHostAudio.pfnGetDevices                 = drvHostCoreAudioHA_GetDevices;
    25652561
    25662562    int rc = RTCritSectInit(&pThis->CritSect);
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette