VirtualBox

Changeset 61523 in vbox


Ignore:
Timestamp:
Jun 7, 2016 9:47:21 AM (8 years ago)
Author:
vboxsync
Message:

Audio: Update.

Location:
trunk
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/pdmaudioifs.h

    r61413 r61523  
    173173    /** Interleaved access, where the data can be
    174174     *  mixed together with data of other audio streams. */
    175     PDMAUDIOSTREAMLAYOUT_INTERLEAVED
     175    PDMAUDIOSTREAMLAYOUT_INTERLEAVED,
     176    /** Hack to blow the type up to 32-bit. */
     177    PDMAUDIOSTREAMLAYOUT_32BIT_HACK = 0x7fffffff
    176178} PDMAUDIOSTREAMLAYOUT, *PPDMAUDIOSTREAMLAYOUT;
    177179
     
    716718
    717719    /**
    718      * Plays (transfers) all available audio samples of a an output stream via the connected host backend.
     720     * Plays (transfers) available audio samples via the host backend. Only works with output streams.
    719721     *
    720722     * @returns VBox status code.
     
    723725     */
    724726    DECLR3CALLBACKMEMBER(int, pfnStreamPlay, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesPlayed));
     727
     728    /**
     729     * Captures (transfers) available audio samples from the host backend. Only works with input streams.
     730     *
     731     * @returns VBox status code.
     732     * @param   pInterface           Pointer to the interface structure containing the called function pointer.
     733     * @param   pcSamplesCaptured    Number of samples captured. Optional.
     734     */
     735    DECLR3CALLBACKMEMBER(int, pfnStreamCapture, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesCaptured));
    725736
    726737#ifdef VBOX_WITH_AUDIO_CALLBACKS
     
    732743
    733744/** PDMIAUDIOCONNECTOR interface ID. */
    734 #define PDMIAUDIOCONNECTOR_IID                  "9C097435-3276-4D88-A49A-A4FE671D86F8"
     745#define PDMIAUDIOCONNECTOR_IID                  "D1B6465D-E3DD-455B-9E05-FB6D56F7D472"
    735746
    736747
  • trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp

    r61409 r61523  
    2121#ifdef DEBUG_andy
    2222/*
    23  * DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
    24  * to a file on the host. Be sure to adjust DEBUG_DUMP_PCM_DATA_PATH
     23 * AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
     24 * to a file on the host. Be sure to adjust AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH
    2525 * to your needs before using this!
    2626 */
     
    243243                       pIter->pszName, pIter->cMixed, pIter->cMixed - cSamplesToClear));
    244244
    245         Assert(cSamplesToClear <= pIter->cMixed);
    246245        pIter->cMixed -= RT_MIN(pIter->cMixed, cSamplesToClear);
    247246    }
  • trunk/src/VBox/Devices/Audio/AudioMixer.cpp

    r61386 r61523  
    341341    }
    342342    else
    343     {
    344         AssertMsgFailed(("Direction not implemented\n"));
    345         rc = VERR_NOT_IMPLEMENTED;
    346     }
     343        AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
    347344#else
    348345    rc = VINF_SUCCESS;
     
    455452}
    456453
    457 int AudioMixerSinkCtl(PAUDMIXSINK pSink, AUDMIXSINKCMD enmCmd)
     454int AudioMixerSinkCtl(PAUDMIXSINK pSink, AUDMIXSINKCMD enmSinkCmd)
    458455{
    459456    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
    460457
    461     PDMAUDIOSTREAMCMD enmCmdStream = audioMixerSinkToStreamCmd(enmCmd);
     458    PDMAUDIOSTREAMCMD enmCmdStream = audioMixerSinkToStreamCmd(enmSinkCmd);
    462459    if (enmCmdStream == PDMAUDIOSTREAMCMD_UNKNOWN)
    463460        return VERR_NOT_SUPPORTED;
     
    474471    }
    475472
    476     LogFlowFunc(("[%s]: enmCmd=%ld, rc=%Rrc\n", pSink->pszName, enmCmd, rc));
     473    /* Remove dirty bit in any case. */
     474    pSink->fStatus &= ~AUDMIXSINK_STS_DIRTY;
     475
     476    if (enmSinkCmd == AUDMIXSINKCMD_ENABLE)
     477        pSink->fStatus |= AUDMIXSINK_STS_RUNNING;
     478    else if (enmSinkCmd == AUDMIXSINKCMD_DISABLE)
     479        pSink->fStatus &= ~AUDMIXSINK_STS_RUNNING;
     480
     481    LogFlowFunc(("[%s]: enmCmd=%ld, fStatus=0x%x, rc=%Rrc\n", pSink->pszName, enmSinkCmd, pSink->fStatus, rc));
    477482    return rc;
    478483}
     
    557562}
    558563
     564AUDMIXSINKSTS AudioMixerSinkGetStatus(PAUDMIXSINK pSink)
     565{
     566    if (!pSink)
     567        return false;
     568
     569    LogFlowFunc(("[%s]: fStatus=0x%x\n", pSink->pszName, pSink->fStatus));
     570
     571    /* If the dirty flag is set, there is unprocessed data in the sink. */
     572    return pSink->fStatus;
     573}
     574
    559575uint8_t AudioMixerSinkGetStreamCount(PAUDMIXSINK pSink)
    560576{
     
    563579
    564580    return pSink->cStreams;
    565 }
    566 
    567 bool AudioMixerSinkHasData(PAUDMIXSINK pSink)
    568 {
    569     if (!pSink)
    570         return false;
    571 
    572     LogFlowFunc(("[%s]: %RTbool\n", pSink->pszName, (pSink->fFlags & AUDMIXSINK_FLAG_DIRTY)));
    573 
    574     /* If the dirty flag is set, there is unprocessed data in the sink. */
    575     return (pSink->fFlags & AUDMIXSINK_FLAG_DIRTY);
    576581}
    577582
     
    588593              ("Can't read from a sink which is not an input sink\n"));
    589594
     595#ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF
    590596    uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbBuf);
    591597    if (!pvMixBuf)
    592598        return VERR_NO_MEMORY;
     599#endif
    593600
    594601    int rc = VERR_NOT_FOUND;
    595602    uint32_t cbRead = 0;
    596603
     604    /* Flag indicating whether this sink is in a 'clean' state,
     605     * e.g. there is no more data to read from. */
     606    bool fClean = true;
     607
    597608    PAUDMIXSTREAM pMixStream;
    598609    RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
     
    602613
    603614        uint32_t cbTotalRead = 0;
    604         uint32_t cbToRead = cbBuf;
     615        uint32_t cbToRead    = cbBuf;
    605616
    606617        while (cbToRead)
     
    608619            uint32_t cbReadStrm;
    609620            AssertPtr(pMixStream->pConn);
     621#ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF
    610622            rc = pMixStream->pConn->pfnStreamRead(pMixStream->pConn, pMixStream->pStream,
    611623                                                  (uint8_t *)pvMixBuf + cbTotalRead, cbToRead, &cbReadStrm);
     624#endif
    612625            if (   RT_FAILURE(rc)
    613626                || !cbReadStrm)
     
    625638
    626639        cbRead = RT_MAX(cbRead, cbTotalRead);
     640
     641        PDMAUDIOSTRMSTS strmSts = pMixStream->pConn->pfnStreamGetStatus(pMixStream->pConn, pMixStream->pStream);
     642        fClean &= !(strmSts & PDMAUDIOSTRMSTS_FLAG_DATA_READABLE);
    627643    }
    628644
    629645    if (RT_SUCCESS(rc))
    630646    {
    631         memcpy(pvBuf, pvMixBuf, cbRead); /* @todo Use an intermediate mixing buffer per sink! */
    632 
     647        if (fClean)
     648            pSink->fStatus &= ~AUDMIXSINK_STS_DIRTY;
     649
     650#ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF
     651        if (cbRead)
     652            memcpy(pvBuf, pvMixBuf, cbRead);
     653#endif
    633654        if (pcbRead)
    634655            *pcbRead = cbRead;
    635656    }
    636657
     658#ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF
    637659    RTMemFree(pvMixBuf);
    638 
    639     Log3Func(("[%s]: cbRead=%RU32, rc=%Rrc\n", pSink->pszName, cbRead, rc));
     660#endif
     661
     662    Log3Func(("[%s]: cbRead=%RU32, fStatus=0x%x, rc=%Rrc\n", pSink->pszName, cbRead, pSink->fStatus, rc));
    640663    return rc;
    641664}
     
    644667{
    645668    AssertPtrReturn(pSink, VERR_INVALID_PARAMETER);
    646     if (!pStream)
     669    if (   !pStream
     670        || !pStream->pSink) /* Not part of a sink anymore? */
     671    {
    647672        return VERR_NOT_FOUND;
     673    }
    648674
    649675    AssertMsgReturn(pStream->pSink == pSink, ("Stream '%s' is not part of sink '%s'\n",
    650                                                pStream->pszName, pSink->pszName), VERR_NOT_FOUND);
     676                                              pStream->pszName, pSink->pszName), VERR_NOT_FOUND);
    651677
    652678    LogFlowFunc(("[%s]: (Stream = %s), cStreams=%RU8\n",
     
    660686    /* Remove stream from sink. */
    661687    RTListNodeRemove(&pStream->Node);
    662     Assert(pSink->cStreams);
    663     pSink->cStreams--;
    664688
    665689    /* Set sink to NULL so that we know we're not part of any sink anymore. */
     
    671695void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
    672696{
    673     audioMixerSinkRemoveStreamInternal(pSink, pStream);
     697    int rc = audioMixerSinkRemoveStreamInternal(pSink, pStream);
     698    if (RT_SUCCESS(rc))
     699    {
     700        Assert(pSink->cStreams);
     701        pSink->cStreams--;
     702    }
    674703}
    675704
     
    763792}
    764793
    765 void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed, uint32_t *pcbData)
     794void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed)
    766795{
    767796    AssertPtrReturnVoid(pSink);
    768     /* pcbData is optional. */
    769797
    770798    /* Note: cTimerTicks / cTicksElapsed = Hz elapsed. */
    771799
    772     LogFlowFunc(("[%s]: cTimerTicks=%RU64, cTicksElapsed=%RU64\n", pSink->pszName, cTimerTicks, cTicksElapsed));
    773 
    774 //    uint32_t cSamplesMin  = (uint32_t)((2 * cTicksElapsed * pSink->PCMProps.uHz + cTimerTicks) / cTimerTicks / 2);
    775    uint32_t cSamplesMin  = (cTicksElapsed / pSink->PCMProps.uHz) * pSink->PCMProps.cChannels;
    776   //  cSamplesMin = (uint32_t)((2 * cTicksElapsed * 44100 + cTimerTicks) / cTimerTicks / 2);
    777     uint32_t cbSamplesMin = _4K; //cSamplesMin << pSink->PCMProps.cShift;
    778 
    779     //Assert((cbSamplesMin % 2 == 0));
    780 
    781 //LogFlowFunc(("[%s]: cSamplesMin=%RU32 (%RU32 bytes, %RU32Hz)\n", pSink->pszName, cSamplesMin, cbSamplesMin, pSink->PCMProps.uHz));
    782 
    783     uint32_t cbData = cbSamplesMin;
    784 
    785     if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
    786     {
    787 //        uint32_t cSinkSamplesLive = AudioMixBufAvail(&pSink->MixBuf);
    788 //        if (!cSinkSamplesLive)
    789 //            cbData = AUDIOMIXBUF_S2B_RATIO(&pSink->MixBuf, AudioMixBufFree(&pSink->MixBufGuest));
    790     }
     800    LogFlowFunc(("[%s]: cTimerTicks=%RU64, cTicksElapsed=%RU64 -> %zuHz\n",
     801                 pSink->pszName, cTimerTicks, cTicksElapsed, cTimerTicks / cTicksElapsed));
    791802
    792803    audioMixerSinkUpdateInternal(pSink);
    793 
    794     if (pcbData)
    795         *pcbData = cbData;
    796804}
    797805
     
    810818        AssertPtr(pStream);
    811819
    812         uint32_t cPlayed = 0;
    813 
    814         rc = pMixStream->pConn->pfnStreamIterate(pMixStream->pConn, pStream);
    815         if (RT_SUCCESS(rc))
     820        uint32_t cPlayed   = 0;
     821        uint32_t cCaptured = 0;
     822
     823        int rc2 = pMixStream->pConn->pfnStreamIterate(pMixStream->pConn, pStream);
     824        if (RT_SUCCESS(rc2))
    816825        {
    817826            if (pStream->enmDir == PDMAUDIODIR_IN)
    818827            {
    819                 /** @todo Implement this! */
    820 #if 0
    821                 rc = pStream->pConn->pfnStreamCapture(pStream->pConn, NULL /* pcSamplesCaptured */);
    822 #endif
     828                rc = pMixStream->pConn->pfnStreamCapture(pMixStream->pConn, pMixStream->pStream, &cCaptured);
     829                if (RT_FAILURE(rc2))
     830                {
     831                    LogFlowFunc(("%s: Failed capture stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
     832                    if (RT_SUCCESS(rc))
     833                        rc = rc2;
     834                }
     835
     836                if (cCaptured)
     837                    pSink->fStatus |= AUDMIXSINK_STS_DIRTY;
     838            }
     839            else if (pStream->enmDir == PDMAUDIODIR_OUT)
     840            {
     841                rc2 = pMixStream->pConn->pfnStreamPlay(pMixStream->pConn, pMixStream->pStream, &cPlayed);
     842                if (RT_FAILURE(rc2))
     843                {
     844                    LogFlowFunc(("%s: Failed playing stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
     845                    if (RT_SUCCESS(rc))
     846                        rc = rc2;
     847                }
    823848            }
    824849            else
    825             {
    826                 rc = pMixStream->pConn->pfnStreamPlay(pMixStream->pConn, pMixStream->pStream, &cPlayed);
    827                 if (RT_FAILURE(rc))
    828                     LogFlowFunc(("%s: Failed playing stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc));
    829             }
     850                AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
    830851        }
    831852
    832         Log3Func(("\t%s: cPlayed=%RU32, rc=%Rrc\n", pMixStream->pStream->szName, cPlayed, rc));
    833     }
     853        Log3Func(("\t%s: cPlayed=%RU32, cCaptured=%RU32\n", pMixStream->pStream->szName, cPlayed, cCaptured));
     854    }
     855
     856    if (RT_FAILURE(rc))
     857        LogFlowFunc(("Failed with rc=%Rrc\n", rc));
    834858
    835859    return rc;
     
    914938    }
    915939
    916     /* Set dirty bit. */
    917     pSink->fFlags |= AUDMIXSINK_FLAG_DIRTY;
     940    if (cbBuf)
     941    {
     942        /* Set dirty bit. */
     943        pSink->fStatus |= AUDMIXSINK_STS_DIRTY;
     944    }
    918945
    919946    if (pcbWritten)
     
    9751002    int rc;
    9761003
    977     if (pMixStream->pSink)
     1004    if (pMixStream->pSink) /* Is the stream part of a sink? */
    9781005    {
    9791006        /* Save sink pointer, as after audioMixerSinkRemoveStreamInternal() the
     
    9811008        PAUDMIXSINK pSink = pMixStream->pSink;
    9821009
    983         rc = audioMixerSinkRemoveStreamInternal(pMixStream->pSink, pMixStream);
     1010        rc = audioMixerSinkRemoveStreamInternal(pSink, pMixStream);
    9841011        if (RT_SUCCESS(rc))
    9851012        {
    986             AssertPtr(pSink);
    9871013            Assert(pSink->cStreams);
    9881014            pSink->cStreams--;
     
    9941020    if (RT_SUCCESS(rc))
    9951021        audioMixerStreamDestroyInternal(pMixStream);
     1022
     1023    LogFlowFunc(("Returning %Rrc\n", rc));
    9961024}
    9971025
  • trunk/src/VBox/Devices/Audio/AudioMixer.h

    r61166 r61523  
    6868} AUDMIXSTREAM, *PAUDMIXSTREAM;
    6969
    70 /** No flags specified. */
    71 #define AUDMIXSINK_FLAG_NONE                  0
    72 /** Dirty flag. */
    73 #define AUDMIXSINK_FLAG_DIRTY                 RT_BIT(0)
     70/** Defines an audio sink's current status. */
     71#define AUDMIXSINKSTS uint32_t
     72
     73/** No status specified. */
     74#define AUDMIXSINK_STS_NONE                  0
     75/** The sink is active and running. */
     76#define AUDMIXSINK_STS_RUNNING               RT_BIT(0)
     77/** Dirty flag.
     78 *  For output sinks this means that there is data in the
     79 *  sink which has not been played yet.
     80 *  For input sinks this means that there is data in the
     81 *  sink which has been recorded but not transferred to the
     82 *  destination yet. */
     83#define AUDMIXSINK_STS_DIRTY                 RT_BIT(1)
    7484
    7585/**
     
    117127     *  if this sink handles input or output. */
    118128    AUDMIXSINKDIR           enmDir;
    119     /** Sink flags of type AUDMIXSINK_FLAG_. */
    120     uint32_t                fFlags;
     129    /** Sink status of type AUDMIXSINK_STS_XXX. */
     130    AUDMIXSINKSTS           fStatus;
    121131    /** The sink's PCM format. */
    122132    PDMPCMPROPS             PCMProps;
     
    170180AUDMIXSINKDIR AudioMixerSinkGetDir(PAUDMIXSINK pSink);
    171181PAUDMIXSTREAM AudioMixerSinkGetStream(PAUDMIXSINK pSink, uint8_t uIndex);
     182AUDMIXSINKSTS AudioMixerSinkGetStatus(PAUDMIXSINK pSink);
    172183uint8_t AudioMixerSinkGetStreamCount(PAUDMIXSINK pSink);
    173 bool AudioMixerSinkHasData(PAUDMIXSINK pSink);
    174184int AudioMixerSinkRead(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
    175185void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
     
    177187int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PPDMPCMPROPS pPCMProps);
    178188int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol);
    179 void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed, uint32_t *pcbData);
     189void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed);
    180190int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
    181191int AudioMixerSinkUpdate(PAUDMIXSINK pSink);
  • trunk/src/VBox/Devices/Audio/DevIchAc97.cpp

    r61399 r61523  
    4646*********************************************************************************************************************************/
    4747
    48 #ifdef DEBUG
    49 //#define DEBUG_LUN
    50 # ifdef DEBUG_LUN
    51 #  define DEBUG_LUN_NUM 1
     48#ifdef DEBUG_andy
     49/*
     50 * AC97_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
     51 * to a file on the host. Be sure to adjust AC97_DEBUG_DUMP_PCM_DATA_PATH
     52 * to your needs before using this!
     53 */
     54# define AC97_DEBUG_DUMP_PCM_DATA
     55# ifdef RT_OS_WINDOWS
     56#  define AC97_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
     57# else
     58#  define AC97_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
    5259# endif
    53 #endif /* DEBUG */
     60#endif /* DEBUG_andy */
    5461
    5562#define AC97_SSM_VERSION 1
     
    7683#define CR_IOCE  RT_BIT(4)         /* rw,   Interrupt On Completion Enable. */
    7784#define CR_FEIE  RT_BIT(3)         /* rw    FIFO Error Interrupt Enable. */
    78 #define CR_LVBIE RT_BIT(2)         /* rw    */
    79 #define CR_RR    RT_BIT(1)         /* rw */
    80 #define CR_RPBM  RT_BIT(0)         /* rw */
     85#define CR_LVBIE RT_BIT(2)         /* rw    Last Valid Buffer Interrupt Enable. */
     86#define CR_RR    RT_BIT(1)         /* rw    Reset Registers. */
     87#define CR_RPBM  RT_BIT(0)         /* rw    Run/Pause Bus Master. */
    8188#define CR_VALID_MASK (RT_BIT(5) - 1)
    8289#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
     
    263270    uint8_t  lvi;               /** rw 0, Last valid index. */
    264271    uint16_t sr;                /** rw 1, Status register. */
    265     uint16_t picb;              /** ro 0, Position in current buffer. */
     272    uint16_t picb;              /** ro 0, Position in current buffer (in samples). */
    266273    uint8_t  piv;               /** ro 0, Prefetched index value. */
    267274    uint8_t  cr;                /** rw 0, Control register. */
     
    423430static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
    424431#endif
    425 static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbElapsed);
     432static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream);
    426433
    427434static void ichac97WarmReset(PAC97STATE pThis)
     
    532539    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    533540
    534     bool fActive = AudioMixerSinkHasData(ichac97IndexToSink(pThis, pStream->u8Strm));
     541    bool fActive = AudioMixerSinkGetStatus(ichac97IndexToSink(pThis, pStream->u8Strm));
    535542
    536543    LogFlowFunc(("SD=%RU8, fActive=%RTbool\n", pStream->u8Strm, fActive));
     
    11451152 * @param   pcbWritten
    11461153 */
    1147 static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbMax, uint32_t *pcbWritten)
     1154static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
    11481155{
    11491156    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    11501157    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    1151     AssertReturn(cbMax,      VERR_INVALID_PARAMETER);
     1158    AssertReturn(cbToWrite,  VERR_INVALID_PARAMETER);
    11521159    /* pcbWritten is optional. */
    11531160
     
    11581165    uint32_t    cbWrittenTotal = 0;
    11591166
    1160     Log3Func(("PICB=%RU16, cbMax=%RU32\n", pRegs->picb, cbMax));
    1161 
    1162     uint32_t cbToWrite = RT_MIN((uint32_t)(pRegs->picb << 1), cbMax); /** @todo r=andy Assumes 16bit sample size. */
     1167    Log3Func(("PICB=%RU16, cbMax=%RU32\n", pRegs->picb, cbToWrite));
     1168
     1169    cbToWrite = RT_MIN((uint32_t)(pRegs->picb << 1), cbToWrite); /** @todo r=andy Assumes 16bit sample size. */
    11631170    if (!cbToWrite)
    11641171    {
     
    11701177    int rc = VINF_SUCCESS;
    11711178
    1172     LogFlowFunc(("pReg=%p, cbMax=%RU32, cbToWrite=%RU32\n", pRegs, cbMax, cbToWrite));
     1179    LogFlowFunc(("pRegs=%p, cbMax=%RU32, cbToWrite=%RU32\n", pRegs, cbToWrite, cbToWrite));
    11731180
    11741181    Assert(pStream->State.offFIFOW <= pStream->State.cbFIFOW);
     
    11821189        PDMDevHlpPhysRead(pDevIns, addr, pu8FIFOW, cbToRead); /** @todo r=andy Check rc? */
    11831190
    1184 #if defined (RT_OS_LINUX) && defined(DEBUG_andy)
     1191#ifdef AC97_DEBUG_DUMP_PCM_DATA
    11851192        RTFILE fh;
    1186         RTFileOpen(&fh, "/tmp/ac97WriteAudio.pcm",
     1193        RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97WriteAudio.pcm",
    11871194                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
    11881195        RTFileWrite(fh, pu8FIFOW, cbToRead, NULL);
     
    12341241static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
    12351242{
     1243    LogFlowFunc(("cbElapsed=%RU32\n", cbElapsed));
     1244
    12361245    if (!(pThis->bup_flag & BUP_SET))
    12371246    {
     
    12401249            unsigned int i;
    12411250            uint32_t *p = (uint32_t*)pThis->silence;
    1242             for (i = 0; i < sizeof(pThis->silence) / 4; i++)
     1251            for (i = 0; i < sizeof(pThis->silence) / 4; i++) /** @todo r=andy Assumes 16-bit samples, stereo. */
    12431252                *p++ = pThis->last_samp;
    12441253        }
     
    12691278}
    12701279
    1271 static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbMax, uint32_t *pcbRead)
     1280static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)
    12721281{
    12731282    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    12741283    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    1275     AssertReturn(cbMax,      VERR_INVALID_PARAMETER);
     1284    AssertReturn(cbToRead,   VERR_INVALID_PARAMETER);
    12761285    /* pcbRead is optional. */
    12771286
     
    12851294
    12861295    uint32_t cbRead   = 0;
    1287     uint32_t cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1),
    1288                                RT_MIN(pStream->State.cbFIFOW, cbMax)); /** @todo r=andy Assumes 16bit samples. */
     1296
     1297    cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1),
     1298                      RT_MIN(pStream->State.cbFIFOW, cbToRead)); /** @todo r=andy Assumes 16bit samples. */
    12891299
    12901300    if (!cbToRead)
     
    13651375    uint64_t cTicksPerSec  = TMTimerGetFreq(pTimer);
    13661376
     1377    LogFlowFuncEnter();
     1378
    13671379    /* Update current time timestamp. */
    13681380    pThis->uTimerTS = cTicksNow;
    13691381
    1370     LogFlowFuncEnter();
    1371 
    1372     uint32_t cbLineIn;
    1373     AudioMixerSinkTimerUpdate(pThis->pSinkLineIn, pThis->cTimerTicks, cTicksPerSec, &cbLineIn);
    1374     if (cbLineIn)
    1375         ichac97TransferAudio(pThis, &pThis->StreamLineIn, cbLineIn);
    1376 
    1377     uint32_t cbMicIn;
    1378     AudioMixerSinkTimerUpdate(pThis->pSinkMicIn , pThis->cTimerTicks, cTicksPerSec, &cbMicIn);
    1379     if (cbMicIn)
    1380         ichac97TransferAudio(pThis, &pThis->StreamMicIn, cbMicIn);
    1381 
    1382     uint32_t cbOut;
    1383     AudioMixerSinkTimerUpdate(pThis->pSinkOutput, pThis->cTimerTicks, cTicksPerSec, &cbOut);
    1384     if (cbOut)
    1385         ichac97TransferAudio(pThis, &pThis->StreamOut, cbOut);
     1382    /* Flag indicating whether to kick the timer again for a
     1383     * new data processing round. */
     1384    bool fKickTimer = false;
     1385
     1386    AudioMixerSinkTimerUpdate(pThis->pSinkLineIn, pThis->cTimerTicks, cTicksPerSec);
     1387    ichac97TransferAudio(pThis, &pThis->StreamLineIn);
     1388
     1389    fKickTimer = AudioMixerSinkGetStatus(pThis->pSinkLineIn) & AUDMIXSINK_STS_DIRTY;
     1390
     1391    AudioMixerSinkTimerUpdate(pThis->pSinkMicIn , pThis->cTimerTicks, cTicksPerSec);
     1392    ichac97TransferAudio(pThis, &pThis->StreamMicIn);
     1393
     1394    fKickTimer = AudioMixerSinkGetStatus(pThis->pSinkMicIn) & AUDMIXSINK_STS_DIRTY;
     1395
     1396    AudioMixerSinkTimerUpdate(pThis->pSinkOutput, pThis->cTimerTicks, cTicksPerSec);
     1397    ichac97TransferAudio(pThis, &pThis->StreamOut);
     1398
     1399    fKickTimer = AudioMixerSinkGetStatus(pThis->pSinkOutput) & AUDMIXSINK_STS_DIRTY;
    13861400
    13871401    if (   ASMAtomicReadBool(&pThis->fTimerActive)
    1388         || AudioMixerSinkHasData(pThis->pSinkLineIn)
    1389         || AudioMixerSinkHasData(pThis->pSinkMicIn)
    1390         || AudioMixerSinkHasData(pThis->pSinkOutput))
     1402        || fKickTimer)
    13911403    {
    13921404        /* Kick the timer again. */
     
    14011413#endif /* !VBOX_WITH_AUDIO_CALLBACKS */
    14021414
    1403 static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbElapsed)
    1404 {
    1405     Log3Func(("SD=%RU8, cbElapsed=%RU32\n", pStream->u8Strm , cbElapsed));
     1415static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream)
     1416{
     1417    Log3Func(("SD=%RU8\n", pStream->u8Strm));
    14061418
    14071419    PAC97BMREGS pRegs = &pStream->Regs;
     
    14091421    if (pRegs->sr & SR_DCH) /* Controller halted? */
    14101422    {
    1411         if (pRegs->cr & CR_RPBM)
     1423        if (pRegs->cr & CR_RPBM) /* Bus master operation starts. */
    14121424        {
    14131425            switch (pStream->u8Strm)
    14141426            {
    14151427                case PO_INDEX:
    1416                     ichac97WriteBUP(pThis, cbElapsed);
     1428                    ichac97WriteBUP(pThis, (uint32_t)(pRegs->picb << 1));
    14171429                    break;
    14181430
     
    14321444    uint32_t cbWrittenTotal = 0;
    14331445
    1434     while (cbElapsed >> 1) /** @todo r=andy This assumes (hardcodes) 16bit sample size.*/
     1446    do
    14351447    {
    14361448        if (!pRegs->bd_valid)
     
    14461458            if (pRegs->civ == pRegs->lvi)
    14471459            {
    1448                 pRegs->sr |= SR_DCH; /* CELV? */
     1460                pRegs->sr |= SR_DCH; /** @todo r=andy Also set CELV? */
    14491461                pThis->bup_flag = 0;
    14501462
     
    14611473        }
    14621474
    1463         uint32_t cbTransferred;
     1475        uint32_t cbToTransfer, cbTransferred;
    14641476        switch (pStream->u8Strm)
    14651477        {
    14661478            case PO_INDEX:
    14671479            {
    1468                 rc = ichac97WriteAudio(pThis, pStream, cbElapsed, &cbTransferred);
     1480                cbToTransfer = (uint32_t)(pRegs->picb << 1);
     1481
     1482                rc = ichac97WriteAudio(pThis, pStream, cbToTransfer, &cbTransferred);
    14691483                if (   RT_SUCCESS(rc)
    14701484                    && cbTransferred)
    14711485                {
    14721486                    cbWrittenTotal += cbTransferred;
    1473                     Assert(cbElapsed >= cbTransferred);
    1474                     cbElapsed      -= cbTransferred;
    1475                     Assert((cbTransferred & 1) == 0);    /* Else the following shift won't work */
     1487                    Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
    14761488                    pRegs->picb    -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
    14771489                }
     
    14821494            case MC_INDEX:
    14831495            {
    1484                 rc = ichac97ReadAudio(pThis, pStream, cbElapsed, &cbTransferred);
     1496                cbToTransfer = (uint32_t)(pRegs->picb << 1);
     1497
     1498                rc = ichac97ReadAudio(pThis, pStream, cbToTransfer, &cbTransferred);
    14851499                if (   RT_SUCCESS(rc)
    14861500                    && cbTransferred)
    14871501                {
    1488                     Assert(cbElapsed >= cbTransferred);
    1489                     cbElapsed   -= cbTransferred;
    1490                     Assert((cbTransferred & 1) == 0);    /* Else the following shift won't work */
     1502                    Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
    14911503                    pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
    14921504                }
     
    15321544        }
    15331545
    1534         if (   RT_FAILURE(rc)
    1535             || rc == VINF_EOF) /* All data processed? */
    1536         {
    1537             break;
    1538         }
    1539     }
     1546        if (rc == VINF_EOF) /* All data processed? */
     1547            break;
     1548
     1549    } while (RT_SUCCESS(rc));
    15401550
    15411551    LogFlowFuncLeaveRC(rc);
     
    15491559                                               uint32_t *pu32Val, unsigned cbVal)
    15501560{
    1551     PAC97STATE pThis    = (PAC97STATE)pvUser;
     1561    PAC97STATE pThis = (PAC97STATE)pvUser;
    15521562
    15531563    /* Get the index of the NABMBAR port. */
  • trunk/src/VBox/Devices/Audio/DevIchHda.cpp

    r61417 r61523  
    5858
    5959#ifdef DEBUG_andy
     60/*
     61 * HDA_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
     62 * to a file on the host. Be sure to adjust HDA_DEBUG_DUMP_PCM_DATA_PATH
     63 * to your needs before using this!
     64 */
     65# define HDA_DEBUG_DUMP_PCM_DATA
     66# ifdef RT_OS_WINDOWS
     67#  define HDA_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
     68# else
     69#  define HDA_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
     70# endif
     71
    6072/* Enables experimental support for separate mic-in handling.
    6173   Do not enable this yet for regular builds, as this needs more testing first! */
     
    930942static int hdaStreamStop(PHDASTREAM pStream);
    931943static int hdaStreamWaitForStateChange(PHDASTREAM pStream, RTMSINTERVAL msTimeout);
    932 static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed);
     944static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream);
    933945#endif
    934946
     
    17561768    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    17571769
    1758     bool fActive = false;
    1759 
    1760     AssertPtr(pStream->pMixSink);
    1761     if (pStream->pMixSink->pMixSink)
    1762         fActive = AudioMixerSinkHasData(pStream->pMixSink->pMixSink);
     1770    bool fActive = pStream->State.fActive;
     1771
     1772    if (!fActive)
     1773    {
     1774        AssertPtr(pStream->pMixSink);
     1775        if (pStream->pMixSink->pMixSink)
     1776            fActive = AudioMixerSinkGetStatus(pStream->pMixSink->pMixSink) & AUDMIXSINK_STS_DIRTY;
     1777    }
    17631778
    17641779    LogFlowFunc(("SD=%RU8, fActive=%RTbool\n", pStream->u8SD, fActive));
     
    17801795                         ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
    17811796
    1782     /* First, enable or disable the stream's sink, if any. */
     1797    /* First, enable or disable the stream and the stream's sink, if any. */
    17831798    if (pStream->pMixSink->pMixSink)
    17841799        AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
     1800
     1801    pStream->State.fActive = fActive;
    17851802
    17861803    /* Second, see if we need to start or stop the timer. */
     
    27232740    AssertReturn(pCfg->enmDir == PDMAUDIODIR_IN, VERR_INVALID_PARAMETER);
    27242741
    2725     LogFlowFunc(("Stream=%s\n", pCfg->szName));
     2742    LogFlowFunc(("Stream=%s, Source=%ld\n", pCfg->szName, pCfg->DestSource.Source));
    27262743
    27272744    int rc;
     
    27312748        case PDMAUDIORECSOURCE_LINE:
    27322749        {
    2733             pCfg->DestSource.Source = PDMAUDIORECSOURCE_LINE;
    2734             pCfg->cChannels         = 2;
    27352750            rc = hdaCodecRemoveStream(pThis->pCodec,  PDMAUDIOMIXERCTL_LINE_IN);
    27362751            if (RT_SUCCESS(rc))
     
    27412756        case PDMAUDIORECSOURCE_MIC:
    27422757        {
    2743             pCfg->DestSource.Source = PDMAUDIORECSOURCE_MIC;
    2744             pCfg->cChannels         = 2;
    27452758            rc = hdaCodecRemoveStream(pThis->pCodec,  PDMAUDIOMIXERCTL_MIC_IN);
    27462759            if (RT_SUCCESS(rc))
     
    27852798    /* Set audio direction. */
    27862799    strmCfg.enmDir = hdaGetDirFromSD(pStream->u8SD);
     2800    switch (strmCfg.enmDir)
     2801    {
     2802        case PDMAUDIODIR_IN:
     2803#ifdef VBOX_WITH_HDA_MIC_IN
     2804# error "Implement me!"
     2805#else
     2806            strmCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
     2807#endif
     2808            break;
     2809
     2810        case PDMAUDIODIR_OUT:
     2811            /* Destination(s) will be set in hdaAddStreamOut(),
     2812             * based on the channels / stream layout. */
     2813            break;
     2814
     2815        default:
     2816            rc = VERR_NOT_SUPPORTED;
     2817            break;
     2818    }
    27872819
    27882820    /*
     
    27942826     * number of channels in a single audio stream.
    27952827     */
    2796     rc = hdaStreamMapInit(&pStream->State.Mapping, &strmCfg);
    2797     AssertRC(rc);
     2828    if (RT_SUCCESS(rc))
     2829    {
     2830        rc = hdaStreamMapInit(&pStream->State.Mapping, &strmCfg);
     2831        AssertRC(rc);
     2832    }
    27982833
    27992834    if (RT_SUCCESS(rc))
     
    31693204
    31703205        /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */
    3171      //   cbFree = RT_MIN(cbFree, uint32_t(pStream->u16FIFOS));
     3206        cbFree = RT_MIN(cbFree, uint32_t(pStream->u16FIFOS));
    31723207
    31733208        /* Make sure we only transfer as many bytes as requested. */
     
    34473482 *       but "reports bytes" when all conditions are met (FIFOW).
    34483483 */
    3449 static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbMax, uint32_t *pcbRead)
     3484static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
    34503485{
    34513486    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    34523487    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    3453     /* pcbRead is optional. */
     3488    /* pcbProcessed is optional. */
    34543489
    34553490    int rc;
     
    34603495        PHDABDLE pBDLE = &pStream->State.BDLE;
    34613496
    3462         uint32_t cbBuf = hdaStreamGetTransferSize(pThis, pStream, cbMax);
    3463         Log3Func(("cbBuf=%RU32, %R[bdle]\n", cbBuf, pBDLE));
    3464 
    3465         if (!cbBuf)
     3497        if (!cbToProcess)
    34663498        {
    34673499            rc = VINF_EOF;
     
    34713503        AssertPtr(pStream->pMixSink);
    34723504        AssertPtr(pStream->pMixSink->pMixSink);
    3473         rc = AudioMixerSinkRead(pStream->pMixSink->pMixSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbBuf, &cbRead);
     3505        rc = AudioMixerSinkRead(pStream->pMixSink->pMixSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbToProcess, &cbRead);
    34743506        if (RT_FAILURE(rc))
    34753507            break;
     
    34823514
    34833515        /* Sanity checks. */
    3484         Assert(cbRead <= cbBuf);
     3516        Assert(cbRead <= cbToProcess);
     3517        Assert(cbRead <= sizeof(pBDLE->State.au8FIFO));
    34853518        Assert(cbRead <= pBDLE->u32BufSize - pBDLE->State.u32BufOff);
    34863519
     
    35153548    if (RT_SUCCESS(rc))
    35163549    {
    3517         if (pcbRead)
    3518             *pcbRead = cbRead;
    3519     }
    3520 
    3521     Log3Func(("Returning cbRead=%RU32, rc=%Rrc\n", cbRead, rc));
     3550        if (pcbProcessed)
     3551            *pcbProcessed = cbRead;
     3552    }
     3553
     3554    if (RT_FAILURE(rc))
     3555        LogFlowFunc(("Failed with %Rrc\n", rc));
     3556
    35223557    return rc;
    35233558}
    35243559
    3525 static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbMax, uint32_t *pcbWritten)
     3560static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
    35263561{
    35273562    AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
    35283563    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    3529     AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
    35303564    /* pcbWritten is optional. */
    35313565
     
    35333567
    35343568    uint32_t cbWritten = 0;
    3535     uint32_t cbToWrite = hdaStreamGetTransferSize(pThis, pStream, cbMax);
    3536 
    3537     Log3Func(("cbToWrite=%RU32, %R[bdle]\n", cbToWrite, pBDLE));
    35383569
    35393570    /*
     
    35423573     */
    35433574    int rc;
    3544     if (!cbToWrite)
     3575    if (!cbToProcess)
    35453576    {
    35463577        rc = VINF_EOF;
     
    35493580    {
    35503581        void    *pvBuf = pBDLE->State.au8FIFO + pBDLE->State.cbBelowFIFOW;
    3551         Assert(cbToWrite >= pBDLE->State.cbBelowFIFOW);
    3552         uint32_t cbBuf = cbToWrite - pBDLE->State.cbBelowFIFOW;
     3582        Assert(cbToProcess >= pBDLE->State.cbBelowFIFOW);
     3583        uint32_t cbBuf = cbToProcess - pBDLE->State.cbBelowFIFOW;
    35533584
    35543585        /*
     
    35593590                               pvBuf, cbBuf);
    35603591        AssertRC(rc);
    3561 #if defined (RT_OS_LINUX) && defined(DEBUG_andy)
     3592
     3593#ifdef HDA_DEBUG_DUMP_PCM_DATA
    35623594        RTFILE fh;
    3563         RTFileOpen(&fh, "/tmp/hdaWriteAudio-hda.pcm",
     3595        RTFileOpen(&fh, HDA_DEBUG_DUMP_PCM_DATA_PATH "hdaWriteAudio-hda.pcm",
    35643596                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
    35653597        RTFileWrite(fh, pvBuf, cbBuf, NULL);
     
    36423674            /* Always report all data as being written;
    36433675             * backends who were not able to catch up have to deal with it themselves. */
    3644             cbWritten = cbToWrite;
    3645 
    3646             hdaBDLEUpdate(pBDLE, cbToWrite, cbWritten);
     3676            cbWritten = cbToProcess;
     3677
     3678            hdaBDLEUpdate(pBDLE, cbToProcess, cbWritten);
    36473679        }
    36483680        else
     
    36633695    if (RT_SUCCESS(rc))
    36643696    {
    3665         if (pcbWritten)
    3666             *pcbWritten = cbWritten;
    3667     }
    3668 
    3669     Log3Func(("Returning cbMax=%RU32, cbWritten=%RU32, rc=%Rrc\n", cbMax, cbWritten, rc));
     3697        if (pcbProcessed)
     3698            *pcbProcessed = cbWritten;
     3699    }
     3700
     3701    if (RT_FAILURE(rc))
     3702        LogFlowFunc(("Failed with %Rrc\n", rc));
     3703
    36703704    return rc;
    36713705}
     
    39043938            }
    39053939
    3906             if (pMixStream)
    3907             {
    3908                 AudioMixerSinkRemoveStream(pSink->pMixSink, pMixStream);
    3909                 AudioMixerStreamDestroy(pMixStream);
    3910             }
     3940            AssertPtr(pMixStream);
     3941
     3942            AudioMixerSinkRemoveStream(pSink->pMixSink, pMixStream);
     3943            AudioMixerStreamDestroy(pMixStream);
    39113944        }
    39123945
     
    40684101    uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTS;
    40694102
     4103    LogFlowFuncEnter();
     4104
    40704105    /* Update current time timestamp. */
    40714106    pThis->uTimerTS = cTicksNow;
     4107
     4108    /* Flag indicating whether to kick the timer again for a
     4109     * new data processing round. */
     4110    bool fKickTimer = false;
    40724111
    40734112    PHDASTREAM pStreamLineIn  = hdaGetStreamFromSink(pThis, &pThis->SinkLineIn);
     
    40804119#endif
    40814120
    4082     uint32_t cbLineIn;
    4083     AudioMixerSinkTimerUpdate(pThis->SinkLineIn.pMixSink,    pThis->cTimerTicks, cTicksElapsed, &cbLineIn);
    4084     if (cbLineIn)
    4085         hdaTransfer(pThis, pStreamLineIn, cbLineIn, NULL); /** @todo Add rc! */
     4121    AudioMixerSinkTimerUpdate(pThis->SinkLineIn.pMixSink, pThis->cTimerTicks, cTicksElapsed);
     4122    hdaTransfer(pThis, pStreamLineIn);
     4123
     4124    if (AudioMixerSinkGetStatus(pThis->SinkLineIn.pMixSink) & AUDMIXSINK_STS_DIRTY)
     4125        fKickTimer = true;
    40864126
    40874127#ifdef VBOX_WITH_HDA_MIC_IN
    4088     uint32_t cbMicIn;
    4089     AudioMixerSinkTimerUpdate(pThis->SinkMicIn.pMixSink ,    pThis->cTimerTicks, cTicksElapsed, &cbMicIn);
    4090 #endif
    4091 
    4092     uint32_t cbFront;
    4093     AudioMixerSinkTimerUpdate(pThis->SinkFront.pMixSink,     pThis->cTimerTicks, cTicksElapsed, &cbFront);
     4128    AudioMixerSinkTimerUpdate(pThis->SinkMicIn.pMixSink, pThis->cTimerTicks, cTicksElapsed);
     4129    hdaTransfer(pThis, pStreamMicIn);
     4130
     4131    if (AudioMixerSinkGetStatus(pThis->SinkLineIn.pMixSink) & AUDMIXSINK_STS_DIRTY)
     4132        fKickTimer = true;
     4133#endif
     4134
     4135    AudioMixerSinkTimerUpdate(pThis->SinkFront.pMixSink,     pThis->cTimerTicks, cTicksElapsed);
     4136    hdaTransfer(pThis, pStreamFront);
     4137
     4138    if (AudioMixerSinkGetStatus(pThis->SinkFront.pMixSink) & AUDMIXSINK_STS_DIRTY)
     4139        fKickTimer = true;
     4140
    40944141#ifdef VBOX_WITH_HDA_51_SURROUND
    4095     uint32_t cbCenterLFE;
    4096     AudioMixerSinkTimerUpdate(pThis->SinkCenterLFE.pMixSink, pThis->cTimerTicks, cTicksElapsed, &cbCenterLFE);
    4097     uint32_t cbRear;
    4098     AudioMixerSinkTimerUpdate(pThis->SinkRear.pMixSink,      pThis->cTimerTicks, cTicksElapsed, &cbRear);
    4099 #endif
    4100 
    4101     if (cbFront)
    4102         hdaTransfer(pThis, pStreamFront, cbFront, NULL);  /** @todo Add rc! */
     4142    AudioMixerSinkTimerUpdate(pThis->SinkCenterLFE.pMixSink, pThis->cTimerTicks, cTicksElapsed);
     4143    AudioMixerSinkTimerUpdate(pThis->SinkRear.pMixSink,      pThis->cTimerTicks, cTicksElapsed);
     4144
     4145    /** @todo Check for stream interleaving and only call hdaTransfer() if required! */
     4146#endif
     4147
    41034148#ifdef VBOX_WITH_HDA_51_SURROUND
    41044149    /*
     
    41104155
    41114156    if (   ASMAtomicReadBool(&pThis->fTimerActive)
    4112         || AudioMixerSinkHasData(pThis->SinkFront.pMixSink)
    4113 #ifdef VBOX_WITH_HDA_51_SURROUND
    4114         || AudioMixerSinkHasData(pThis->SinkCenterLFE.pMixSink)
    4115         || AudioMixerSinkHasData(pThis->SinkRear.pMixSink)
    4116 #endif
    4117         || AudioMixerSinkHasData(pThis->SinkLineIn.pMixSink))
     4157        || fKickTimer)
    41184158    {
    41194159        /* Kick the timer again. */
     
    41224162        TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
    41234163    }
     4164
     4165    LogFlowFuncLeave();
    41244166
    41254167    STAM_PROFILE_STOP(&pThis->StatTimer, a);
     
    41764218#endif /* VBOX_WITH_AUDIO_CALLBACKS */
    41774219
    4178 static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
     4220static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream)
    41794221{
    41804222    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    41814223    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    4182     /* pcbProcessed is optional. */
    41834224
    41844225    if (ASMAtomicReadBool(&pThis->fInReset)) /* HDA controller in reset mode? Bail out. */
    41854226    {
    4186         LogFlowFunc(("In reset mode, skipping\n"));
    4187 
    4188         if (pcbProcessed)
    4189             *pcbProcessed = 0;
     4227        LogFlowFunc(("HDA in reset mode, skipping\n"));
    41904228        return VINF_SUCCESS;
    41914229    }
     
    41964234        return rc;
    41974235
     4236    Log3Func(("[SD%RU8] fActive=%RTbool\n", pStream->u8SD, pStream->State.fActive));
     4237
    41984238    /* Stop request received? */
    4199     if (pStream->State.fDoStop)
     4239    if (   !pStream->State.fActive
     4240        || pStream->State.fDoStop)
    42004241    {
    42014242        pStream->State.fActive = false;
     
    42094250    else if (!(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)))
    42104251        fProceed = false;
    4211     /* Nothing to process? */
    4212     else if (!cbToProcess)
    4213         fProceed = false;
    42144252
    42154253    if ((HDA_STREAM_REG(pThis, STS, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))
     
    42214259    if (!fProceed)
    42224260    {
    4223         Log3Func(("[SD%RU8] Skipping\n", pStream->u8SD));
     4261        Log3Func(("[SD%RU8]: Skipping\n", pStream->u8SD));
    42244262
    42254263        rc = RTSemMutexRelease(pStream->State.hMtx);
    42264264        AssertRC(rc);
    42274265
    4228         if (pcbProcessed)
    4229             *pcbProcessed = 0;
    42304266        return VINF_SUCCESS;
    42314267    }
     
    42424278    Assert(u32LPIB <= pStream->u32CBL);
    42434279
    4244     uint32_t cbLeft  = cbToProcess;
    4245     uint32_t cbTotal = 0;
    4246 
    42474280    bool fInterrupt = false;
    42484281
    4249     Log3Func(("cbLeft=%RU32\n", cbLeft));
    4250 
    4251 #define FOO
    4252 
    4253 #ifdef FOO
     4282#ifdef DEBUG_andy
     4283# define DEBUG_SIMPLE
     4284#endif
     4285
     4286#ifdef DEBUG_SIMPLE
    42544287    uint8_t u8FIFO[_16K+1];
    42554288    size_t u8FIFOff = 0;
    42564289#endif
    42574290
     4291    uint32_t cbToProcess      = 0;
     4292    uint32_t cbProcessed      = 0;
     4293    uint32_t cbProcessedTotal = 0;
     4294
    42584295    /* Set the FIFORDY bit on the stream while doing the transfer. */
    42594296    HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
    42604297
    4261     while (cbLeft)
     4298    do
    42624299    {
    42634300        /* Do we need to fetch the next Buffer Descriptor Entry (BDLE)? */
     
    42694306        }
    42704307
    4271         uint32_t cbProcessed = 0;
     4308        cbToProcess = hdaStreamGetTransferSize(pThis, pStream, _4K /** @todo Fix this */);
     4309        cbProcessed = 0;
     4310
    42724311        if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)
    4273             rc = hdaReadAudio (pThis, pStream, cbLeft, &cbProcessed);
     4312            rc = hdaReadAudio(pThis, pStream, cbToProcess, &cbProcessed);
    42744313        else
    42754314        {
    4276 #ifndef FOO
    4277             rc = hdaWriteAudio(pThis, pStream, cbLeft, &cbProcessed);
     4315#ifndef DEBUG_SIMPLE
     4316            rc = hdaWriteAudio(pThis, pStream, cbToProcess, &cbProcessed);
    42784317#else
    4279             uint32_t cbToWrite = hdaStreamGetTransferSize(pThis, pStream, cbLeft);
     4318            uint32_t cbToWrite = hdaStreamGetTransferSize(pThis, pStream, cbToProcess);
    42804319
    42814320            void    *pvBuf = u8FIFO + u8FIFOff;
     
    42904329            hdaBDLEUpdate(pBDLE, cbToWrite, cbToWrite);
    42914330
    4292             LogFlowFunc(("u8FIFOff=%zu, cbLeft=%RU32, cbToWrite=%RU32\n", u8FIFOff, cbLeft, cbToWrite));
    4293 
    42944331            u8FIFOff += cbToWrite;
     4332            Assert((u8FIFOff & 1) == 0);
    42954333            Assert(u8FIFOff <= sizeof(u8FIFO));
    42964334
     
    43044342        hdaStreamTransferUpdate(pThis, pStream, cbProcessed);
    43054343
    4306         Assert(cbLeft >= cbProcessed);
    4307         cbLeft  -= cbProcessed;
    4308         cbTotal += cbProcessed;
    4309 
    4310         LogFlowFunc(("cbProcessed=%RU32, cbLeft=%RU32, cbTotal=%RU32, rc=%Rrc\n",
    4311                      cbProcessed, cbLeft, cbTotal, rc));
     4344        cbProcessedTotal += cbProcessed;
    43124345
    43134346        if (rc == VINF_EOF)
     
    43164349        if (hdaStreamTransferIsComplete(pThis, pStream, &fInterrupt))
    43174350            break;
    4318     }
     4351
     4352    } while (RT_SUCCESS(rc));
    43194353
    43204354    /* Remove the FIFORDY bit again. */
    43214355    HDA_STREAM_REG(pThis, STS, pStream->u8SD) &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
    43224356
    4323 #ifdef FOO
    4324     #if defined (RT_OS_LINUX) && defined(DEBUG_andy)
     4357    LogFlowFunc(("[SD%RU8]: %RU32 / %RU32, rc=%Rrc\n", pStream->u8SD, cbProcessedTotal, cbToProcess, rc));
     4358
     4359#ifdef DEBUG_SIMPLE
     4360# ifdef HDA_DEBUG_DUMP_PCM_DATA
    43254361        RTFILE fh;
    4326         RTFileOpen(&fh, "/tmp/hdaWriteAudio.pcm",
     4362        RTFileOpen(&fh, HDA_DEBUG_DUMP_PCM_DATA_PATH "hdaWriteAudio.pcm",
    43274363                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
    43284364        RTFileWrite(fh, u8FIFO, u8FIFOff, NULL);
    43294365        RTFileClose(fh);
    4330     #endif
    4331 #if 1
     4366# endif
     4367
    43324368     AudioMixerSinkWrite(pThis->SinkFront.pMixSink, AUDMIXOP_COPY, u8FIFO, u8FIFOff,
    43334369                         NULL /* pcbWritten */);
    4334 #endif
    4335 #endif
    4336 
    4337 #ifdef FOO
     4370#endif /* DEBUG_SIMPLE */
     4371
    43384372    if (fInterrupt)
    43394373    {
     
    43524386
    43534387        hdaProcessInterrupt(pThis);
    4354     }
    4355 #endif
    4356 
    4357     Log3Func(("Written %RU32 / %RU32 (left: %RU32), rc=%Rrc\n", cbTotal, cbToProcess, cbLeft, rc));
    4358 
    4359     if (RT_SUCCESS(rc))
    4360     {
    4361         if (pcbProcessed)
    4362             *pcbProcessed = cbTotal;
    43634388    }
    43644389
  • trunk/src/VBox/Devices/Audio/DevIchHdaCodec.cpp

    r61126 r61523  
    267267#define CODEC_AMP_NUM_STEPS                                0x7F
    268268/** The initial gain offset (and when doing a node reset). */
    269 #define CODEC_AMP_OFF_INITIAL                              0x40
     269#define CODEC_AMP_OFF_INITIAL                              0x7F
    270270/** The amplifier's gain step size. */
    271271#define CODEC_AMP_STEP_SIZE                                0x2
     
    928928            /* Default input amplifier capabilities. */
    929929            pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(CODEC_AMP_CAP_MUTE,
    930                                                                 0 /* Step size */,
     930                                                                CODEC_AMP_STEP_SIZE,
    931931                                                                CODEC_AMP_NUM_STEPS,
    932                                                                 0 /* Initial offset */);
     932                                                                CODEC_AMP_OFF_INITIAL);
    933933            /* Default output amplifier capabilities. */
    934934            pNode->node.au32F00_param[0x12] = CODEC_MAKE_F00_12(CODEC_AMP_CAP_MUTE,
     
    10031003            pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 Set: D3 */
    10041004
    1005             pNode->adc.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 13, 0)
     1005            pNode->adc.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0)
    10061006                                               | CODEC_F00_09_CAP_POWER_CTRL
    10071007                                               | CODEC_F00_09_CAP_CONNECTION_LIST
     
    10621062        case STAC9220_NID_PIN_HEADPHONE0: /* Port A: Headphone in/out (front). */
    10631063        {
    1064             pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(false /*fPresent*/, CODEC_F09_ANALOG_NA);
     1064            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0 /*fPresent*/, CODEC_F09_ANALOG_NA);
    10651065
    10661066            pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
     
    10871087        case STAC9220_NID_PIN_B: /* Port B: Rear CLFE (Center / Subwoofer). */
    10881088        {
    1089             pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(true /*fPresent*/, CODEC_F09_ANALOG_NA);
     1089            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
    10901090
    10911091            pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
     
    11111111        case STAC9220_NID_PIN_C: /* Rear Speaker. */
    11121112        {
    1113             pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(true /*fPresent*/, CODEC_F09_ANALOG_NA);
     1113            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
    11141114
    11151115            pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
     
    11351135        case STAC9220_NID_PIN_HEADPHONE1: /* Also known as PIN_D. */
    11361136        {
    1137             pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(false /*fPresent*/, CODEC_F09_ANALOG_NA);
     1137            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
    11381138
    11391139            pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
  • trunk/src/VBox/Devices/Audio/DrvAudio.cpp

    r61398 r61523  
    1818 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
    1919 * --------------------------------------------------------------------
    20  *
    21  * This code is based on: audio.c from QEMU AUDIO subsystem.
    22  *
    23  * QEMU Audio subsystem
    24  *
    25  * Copyright (c) 2003-2005 Vassili Karpov (malc)
    26  *
    27  * Permission is hereby granted, free of charge, to any person obtaining a copy
    28  * of this software and associated documentation files (the "Software"), to deal
    29  * in the Software without restriction, including without limitation the rights
    30  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    31  * copies of the Software, and to permit persons to whom the Software is
    32  * furnished to do so, subject to the following conditions:
    33  *
    34  * The above copyright notice and this permission notice shall be included in
    35  * all copies or substantial portions of the Software.
    36  *
    37  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    38  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    39  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    40  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    41  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    42  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    43  * THE SOFTWARE.
    4420 */
    4521#define LOG_GROUP LOG_GROUP_DRV_AUDIO
     
    148124}
    149125
     126/**
     127 * Returns the host stream part of an audio stream pair, or NULL
     128 * if no host stream has been assigned / is not available.
     129 *
     130 * @returns IPRT status code.
     131 * @param   pStream             Audio stream to retrieve host stream part for.
     132 */
    150133inline PPDMAUDIOSTREAM drvAudioGetHostStream(PPDMAUDIOSTREAM pStream)
    151134{
     
    448431}
    449432
    450 #if 1
    451433/**
    452434 * Writes VM audio output data from the guest stream into the host stream.
     
    479461    }
    480462
     463    AssertMsg(pStream->enmDir == PDMAUDIODIR_OUT,
     464              ("Stream '%s' is not an output stream and therefore cannot be written to (direction is 0x%x)\n",
     465               pStream->szName, pStream->enmDir));
     466
    481467    LogFlowFunc(("[%s]: cbBuf=%RU32\n", pStream->szName, cbBuf));
    482468
     
    516502    }
    517503
    518 #if 0
    519     uint32_t cMixed = 0;
    520     if (RT_SUCCESS(rc))
    521     {
    522         /* Mix just written guest stream samples to the host immediately. */
    523         rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cWritten, &cMixed);
    524     }
    525 #endif
    526 
    527 #if 0
    528     uint32_t cPlayed = 0;
    529     if (RT_SUCCESS(rc))
    530     {
    531         PDMAUDIOSTRMSTS strmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
    532         if (strmSts & PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE)
    533             rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pHstStream, &cPlayed);
    534     }
    535 #endif
    536 
    537 #ifdef DEBUG_andy
    538     AssertRC(rc);
    539 #endif
    540 
    541 #if 0
    542     /*
    543      * Second, mix the guest mixing buffer with the host mixing
    544      * buffer so that the host backend can play the data lateron.
    545      */
    546     uint32_t cMixed;
    547     if (   RT_SUCCESS(rc)
    548         && cWritten)
    549     {
    550         rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cWritten, &cMixed);
    551     }
    552     else
    553         cMixed = 0;
    554 
    555     if (RT_SUCCESS(rc))
    556     {
    557         /*
    558          * Return the number of samples which actually have been mixed
    559          * down to the parent, regardless how much samples were written
    560          * into the children buffer.
    561          */
    562         if (pcbWritten)
    563             *pcbWritten = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cMixed);
    564     }
    565 #else
    566504    if (RT_SUCCESS(rc))
    567505    {
     
    569507            *pcbWritten = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cWritten);
    570508    }
    571 #endif
    572509
    573510    LogFlowFunc(("cWritten=%RU32 (%RU32 bytes), cMixed=%RU32, rc=%Rrc\n",
     
    580517    return rc;
    581518}
    582 #else
    583 static DECLCALLBACK(int) drvAudioWrite(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut,
    584                                        const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
    585 {
    586     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    587     AssertPtrReturn(pThis, VERR_INVALID_POINTER);
    588 
    589     AssertPtrReturn(pGstStrmOut, VERR_INVALID_POINTER);
    590     AssertPtrReturn(pvBuf,       VERR_INVALID_POINTER);
    591     AssertReturn(cbBuf,          VERR_INVALID_PARAMETER);
    592     /* pcbWritten is optional. */
    593 
    594     int rc = RTCritSectEnter(&pThis->CritSect);
    595     if (RT_FAILURE(rc))
    596         return rc;
    597 
    598     if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))
    599     {
    600         rc = RTCritSectLeave(&pThis->CritSect);
    601         AssertRC(rc);
    602 
    603         return VERR_NOT_AVAILABLE;
    604     }
    605 
    606     PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
    607     AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
    608 
    609     AssertMsg(pGstStrmOut->pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
    610               ("Writing to disabled host output stream \"%s\" not possible\n",
    611               pHstStrmOut->MixBuf.pszName));
    612 
    613     if (!AudioMixBufFreeBytes(&pGstStrmOut->MixBuf))
    614     {
    615         if (pcbWritten)
    616             *pcbWritten = 0;
    617 
    618         return RTCritSectLeave(&pThis->CritSect);
    619     }
    620 
    621     /*
    622      * First, write data from the device emulation into our
    623      * guest mixing buffer.
    624      */
    625     uint32_t cWritten;
    626     //rc = AudioMixBufWriteAt(&pGstStrmOut->MixBuf, 0 /* Offset in samples */, pvBuf, cbBuf, &cWritten);
    627     rc = AudioMixBufWriteCirc(&pGstStrmOut->MixBuf, pvBuf, cbBuf, &cWritten);
    628     if (rc == VINF_BUFFER_OVERFLOW)
    629         LogRel(("Audio: Lost audio samples from guest, expect stuttering audio output\n"));
    630 
    631     /*
    632      * Second, mix the guest mixing buffer with the host mixing
    633      * buffer so that the host backend can play the data lateron.
    634      */
    635     uint32_t cMixed;
    636     if (   RT_SUCCESS(rc)
    637         && cWritten)
    638     {
    639         rc = AudioMixBufMixToParent(&pGstStrmOut->MixBuf, cWritten, &cMixed);
    640     }
    641     else
    642         cMixed = 0;
    643 
    644     if (RT_SUCCESS(rc))
    645     {
    646         /*
    647          * Return the number of samples which actually have been mixed
    648          * down to the parent, regardless how much samples were written
    649          * into the children buffer.
    650          */
    651         if (pcbWritten)
    652             *pcbWritten = AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cMixed);
    653     }
    654 
    655     LogFlowFunc(("%s -> %s: cbBuf=%RU32, cWritten=%RU32 (%RU32 bytes), cMixed=%RU32, rc=%Rrc\n",
    656                  pGstStrmOut->MixBuf.pszName, pHstStrmOut->MixBuf.pszName, cbBuf, cWritten,
    657                  AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cWritten), cMixed, rc));
    658 
    659     int rc2 = RTCritSectLeave(&pThis->CritSect);
    660     if (RT_SUCCESS(rc))
    661         rc = rc2;
    662 
    663     return rc;
    664 }
    665 #endif
    666519
    667520static DECLCALLBACK(uint32_t) drvAudioStreamAddRef(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
     
    688541}
    689542
    690 #if 1
    691543static DECLCALLBACK(int) drvAudioStreamIterate(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
    692544{
     
    725577
    726578    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
     579    AssertPtr(pHstStream);
    727580    PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
     581    AssertPtr(pGstStream);
    728582
    729583    int rc = VINF_SUCCESS;
     
    731585    do
    732586    {
    733         /*if (!(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
    734             break;*/
     587        uint32_t cSamplesMixed = 0;
    735588
    736589        PDMAUDIOSTRMSTS hstStrmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
     
    738591        if (pHstStream->enmDir == PDMAUDIODIR_IN)
    739592        {
    740             /* Call the host backend to capture the audio input data. */
    741             uint32_t cSamplesCaptured;
    742             rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pHstStream, &cSamplesCaptured);
    743             if (RT_FAILURE(rc))
    744                 break;
    745 
    746             //cbData = AUDIOMIXBUF_S2B(&pStream->MixBuf, AudioMixBufMixed(&pStream->MixBuf)));
    747 
    748         }
    749         else /* PDMAUDIODIR_OUT */
    750         {
    751             uint32_t cSamplesMixed = 0;
     593            uint32_t cSamplesToCapture = AudioMixBufFree(&pGstStream->MixBuf);
     594            if (cSamplesToCapture)
     595            {
     596                if (hstStrmSts & PDMAUDIOSTRMSTS_FLAG_DATA_READABLE)
     597                {
     598                    uint32_t cSamplesCaptured = 0;
     599
     600                    /* Call the host backend to capture the audio input data. */
     601                    rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pHstStream, &cSamplesCaptured);
     602                    if (RT_FAILURE(rc))
     603                        break;
     604
     605                    LogFlowFunc(("%s: %RU32 samples captured, rc=%Rrc\n", pHstStream->szName, cSamplesCaptured, rc));
     606                }
     607            }
     608        }
     609        else if (pHstStream->enmDir == PDMAUDIODIR_OUT)
     610        {
    752611            uint32_t cSamplesToMix = AudioMixBufUsed(&pGstStream->MixBuf);
    753612
     
    757616                if (hstStrmSts & PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE)
    758617                {
    759             /*    int rc2 = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pHstStream, &cSamplesPlayed);
    760                 if (RT_SUCCESS(rc))
    761                     rc = rc2;
    762             }*/
    763 
    764618                    rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cSamplesToMix, &cSamplesMixed);
    765619
    766                     LogFlowFunc(("%s: %RU32/%RU32 samples mixed, rc=%Rrc\n",
     620                    LogFlowFunc(("%s: %RU32/%RU32 playback samples mixed, rc=%Rrc\n",
    767621                                 pHstStream->szName, cSamplesMixed, cSamplesToMix, rc));
    768622                }
    769623            }
    770624        }
     625        else
     626            AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
    771627
    772628        if (RT_SUCCESS(rc))
     
    775631    } while (0);
    776632
     633    if (RT_FAILURE(rc))
     634        LogFunc(("Failed with %Rrc\n", rc));
     635
    777636    return rc;
    778637}
    779 #else
    780 static DECLCALLBACK(int) drvAudioGetDataIn(PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcbAvailIn)
    781 {
    782     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    783     /* pcbAvailIn is optional. */
    784 
    785     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    786 
    787     int rc = RTCritSectEnter(&pThis->CritSect);
    788     if (RT_FAILURE(rc))
    789         return rc;
    790 
    791     uint32_t cbAvailIn = 0;
    792 
    793     PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
    794     while ((pHstStrmIn = drvAudioFindAnyHstIn(pThis, pHstStrmIn)))
    795     {
    796         /* Disabled? Skip it! */
    797         if (!(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
    798             continue;
    799 
    800         /* Call the host backend to capture the audio input data. */
    801         uint32_t cSamplesCaptured;
    802         int rc2 = pThis->pHostDrvAudio->pfnCaptureIn(pThis->pHostDrvAudio, pHstStrmIn,
    803                                                      &cSamplesCaptured);
    804         if (RT_FAILURE(rc2))
    805             continue;
    806 
    807         PPDMAUDIOGSTSTRMIN pGstStrmIn = pHstStrmIn->pGstStrmIn;
    808         AssertPtrBreak(pGstStrmIn);
    809 
    810         if (pGstStrmIn->State.fActive)
    811         {
    812             cbAvailIn = RT_MAX(cbAvailIn, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf,
    813                                                           AudioMixBufMixed(&pHstStrmIn->MixBuf)));
    814 #ifdef DEBUG_andy
    815             LogFlowFunc(("\t[%s] cbAvailIn=%RU32\n", pHstStrmIn->MixBuf.pszName, cbAvailIn));
    816 #endif
    817         }
    818     }
    819 
    820     if (RT_SUCCESS(rc))
    821     {
    822         if (pcbAvailIn)
    823             *pcbAvailIn = cbAvailIn;
    824     }
    825 
    826     int rc2 = RTCritSectLeave(&pThis->CritSect);
    827     if (RT_SUCCESS(rc))
    828         rc = rc2;
    829 
    830     if (RT_FAILURE(rc))
    831         LogFlowFuncLeaveRC(rc);
    832 
    833     return rc;
    834 }
    835 
    836 static DECLCALLBACK(int) drvAudioGetDataOut(PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcbFreeOut, uint32_t *pcSamplesLive)
    837 {
    838     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    839     /* pcbFreeOut is optional. */
    840     /* pcSamplesLive is optional. */
    841 
    842     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    843 
    844     int rc = RTCritSectEnter(&pThis->CritSect);
    845     if (RT_FAILURE(rc))
    846         return rc;
    847 
    848     static uint64_t s_tsLast = 0;
    849 
    850 
    851     uint64_t s_tsDelta = RTTimeNanoTS() - s_tsLast;
    852     LogFlowFunc(("delta=%RU64 (%RU64ms) -> ", s_tsDelta, s_tsDelta / 1000 / 1000));
    853 
    854     #if 0
    855     PPDMAUDIOHSTSTRMOUT pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, NULL);
    856     uint64_t ns = s_tsDelta / pHstStrmOut->Props.uHz;
    857 
    858 
    859 
    860     uint32_t cSamplesMin  = (cTicksElapsed / pSink->PCMProps.uHz) * pSink->PCMProps.cChannels;
    861     #endif
    862 
    863     s_tsLast = RTTimeNanoTS();
    864 
    865     /*
    866      * Playback.
    867      */
    868     uint32_t cSamplesLive = 0;
    869     uint32_t cbFreeOut    = UINT32_MAX;
    870 
    871     PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
    872     while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
    873     {
    874         cSamplesLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
    875 
    876         /* Has this stream marked as disabled but there still were guest streams relying
    877          * on it? Check if this stream now can be closed and do so, if possible. */
    878         if (   (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
    879             && !cSamplesLive)
    880         {
    881             /* Stop playing the current (pending) stream. */
    882             int rc2 = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
    883             if (RT_SUCCESS(rc2))
    884             {
    885                 pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
    886 
    887                 LogFunc(("[%s] Disabling stream\n", pHstStrmOut->MixBuf.pszName));
    888             }
    889             else
    890                 LogFunc(("[%s] Backend vetoed against closing output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc2));
    891 
    892             continue;
    893         }
    894 
    895         LogFlowFunc(("[%s] cSamplesLive=%RU32\n", pHstStrmOut->MixBuf.pszName, cSamplesLive));
    896 
    897         /*
    898          * No live samples to play at the moment?
    899          *
    900          * Tell the device emulation for each connected guest stream how many
    901          * bytes are free so that the device emulation can continue writing data to
    902          * these streams.
    903          */
    904         PPDMAUDIOGSTSTRMOUT pGstStrmOut;
    905         uint32_t cbFree2 = UINT32_MAX;
    906         RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
    907         {
    908             if (pGstStrmOut->State.fActive)
    909             {
    910                 /* Tell the sound device emulation how many samples are free
    911                  * so that it can start writing PCM data to us. */
    912                 cbFree2 = RT_MIN(cbFree2, AUDIOMIXBUF_S2B_RATIO(&pGstStrmOut->MixBuf,
    913                                                                 AudioMixBufFree(&pGstStrmOut->MixBuf)));
    914 #ifdef DEBUG_andy
    915                 LogFlowFunc(("\t[%s] cbFreeOut=%RU32\n", pGstStrmOut->MixBuf.pszName, cbFree2));
    916 #endif
    917             }
    918         }
    919 
    920         cbFreeOut = RT_MIN(cbFreeOut, cbFree2);
    921     }
    922 
    923     if (RT_SUCCESS(rc))
    924     {
    925         if (cbFreeOut == UINT32_MAX)
    926             cbFreeOut = 0;
    927 
    928         if (pcbFreeOut)
    929             *pcbFreeOut = cbFreeOut;
    930 
    931         if (pcSamplesLive)
    932             *pcSamplesLive = cSamplesLive;
    933     }
    934 
    935     int rc2 = RTCritSectLeave(&pThis->CritSect);
    936     if (RT_SUCCESS(rc))
    937         rc = rc2;
    938 
    939     if (RT_FAILURE(rc))
    940         LogFlowFuncLeaveRC(rc);
    941 
    942     return rc;
    943 }
    944 #endif
    945 
    946 #if 1
    947 static DECLCALLBACK(int) drvAudioStreamPlay(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesPlayed)
     638
     639static DECLCALLBACK(int) drvAudioStreamPlay(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream,
     640                                            uint32_t *pcSamplesPlayed)
    948641{
    949642    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     
    951644    /* pcSamplesPlayed is optional. */
    952645
     646    AssertMsg(pStream->enmDir == PDMAUDIODIR_OUT,
     647              ("Stream '%s' is not an output stream and therefore cannot be played back (direction is 0x%x)\n",
     648               pStream->szName, pStream->enmDir));
     649
    953650    AssertMsg(pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED,
    954651              ("Unable to play stream '%s' (status is 0x%x)\n", pStream->szName, pStream->fStatus));
     
    981678
    982679        PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
     680        AssertPtr(pHstStream);
    983681        PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
    984682        AssertPtr(pGstStream);
     
    1021719            }
    1022720        }
    1023     #if 0
    1024             if (pStream->pPair)
    1025             {
    1026                 bool fIsEmpty = AudioMixBufIsEmpty(&pStream->pPair->MixBuf);
    1027 
    1028                 if (   !pPair->State.fActive
    1029                     && fIsEmpty)
    1030                     continue;
    1031 
    1032                 if ()
    1033                 {
    1034                     pGstStrmOut->State.fEmpty = true;
    1035                     fNeedsCleanup |= !pGstStrmOut->State.fActive;
    1036                 }
    1037             }
    1038 
    1039             if (fNeedsCleanup)
    1040             {
    1041                 RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
    1042                 {
    1043                     if (!pGstStrmOut->State.fActive)
    1044                         drvAudioDestroyGstOut(pThis, pGstStrmOut);
    1045                 }
    1046             }
    1047     #endif
     721
    1048722    } while (0);
    1049723
     
    1063737    return rc;
    1064738}
    1065 #else
    1066 static DECLCALLBACK(int) drvAudioPlayOut(PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcSamplesPlayed)
    1067 {
    1068     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    1069     /* pcSamplesPlayed is optional. */
     739
     740static DECLCALLBACK(int) drvAudioStreamCapture(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream,
     741                                               uint32_t *pcSamplesCaptured)
     742{
     743    AssertMsg(pStream->enmDir == PDMAUDIODIR_IN,
     744              ("Stream '%s' is not an input stream and therefore cannot be captured (direction is 0x%x)\n",
     745               pStream->szName, pStream->enmDir));
     746
     747    AssertMsg(pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED,
     748              ("Unable to capture stream '%s' (status is 0x%x)\n", pStream->szName, pStream->fStatus));
    1070749
    1071750    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
     
    1075754        return rc;
    1076755
    1077     /* Backend output (temporarily) disabled / unavailable? */
    1078     if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))
    1079     {
    1080         rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
    1081         AssertRC(rc);
    1082 
    1083         if (   !pThis->BackendCfg.cSinks
    1084             || !pThis->BackendCfg.cMaxStreamsOut)
    1085         {
    1086             int rc2 = RTCritSectLeave(&pThis->CritSect);
    1087             AssertRC(rc2);
    1088 
    1089             return VERR_NOT_AVAILABLE;
    1090         }
    1091     }
    1092 
    1093     /*
    1094      * Process all enabled host output streams.
    1095      */
    1096     uint32_t            cSamplesPlayedMax = 0;
    1097     PPDMAUDIOHSTSTRMOUT pHstStrmOut       = NULL;
    1098     while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
    1099     {
    1100 #if 0
    1101         uint32_t cStreamsLive;
    1102         uint32_t cSamplesLive = drvAudioHstOutSamplesLive(pHstStrmOut, &cStreamsLive);
    1103         if (!cStreamsLive)
    1104             cSamplesLive = 0;
    1105 
    1106         /* Has this stream marked as disabled but there still were guest streams relying
    1107          * on it? Check if this stream now can be closed and do so, if possible. */
    1108         if (   pHstStrmOut->fPendingDisable
    1109             && !cStreamsLive)
    1110         {
    1111             /* Stop playing the current (pending) stream. */
    1112             int rc2 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut,
    1113                                                           PDMAUDIOSTREAMCMD_DISABLE);
    1114             if (RT_SUCCESS(rc2))
    1115             {
    1116                 pHstStrmOut->fEnabled        = false;
    1117                 pHstStrmOut->fPendingDisable = false;
    1118 
    1119                 LogFunc(("\t%p: Disabling stream\n", pHstStrmOut));
    1120             }
    1121             else
    1122                 LogFunc(("\t%p: Backend vetoed against closing output stream, rc=%Rrc\n",
    1123                          pHstStrmOut, rc2));
    1124 
    1125             continue;
    1126         }
    1127 #endif
    1128         uint32_t cSamplesPlayed = 0;
    1129         int rc2 = pThis->pHostDrvAudio->pfnPlayOut(pThis->pHostDrvAudio, pHstStrmOut, &cSamplesPlayed);
    1130         if (RT_FAILURE(rc2))
    1131         {
    1132             int rc3 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
    1133             AssertRC(rc3);
    1134         }
    1135         else
    1136             cSamplesPlayedMax = RT_MAX(cSamplesPlayed, cSamplesPlayedMax);
    1137 
    1138         LogFlowFunc(("\t[%s] cSamplesPlayed=%RU32, cSamplesPlayedMax=%RU32, rc=%Rrc\n",
    1139                      pHstStrmOut->MixBuf.pszName, cSamplesPlayed, cSamplesPlayedMax, rc2));
    1140 
    1141         bool fNeedsCleanup = false;
    1142 
    1143         PPDMAUDIOGSTSTRMOUT pGstStrmOut;
    1144         RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
    1145         {
    1146             if (   !pGstStrmOut->State.fActive
    1147                 && pGstStrmOut->State.fEmpty)
    1148                 continue;
    1149 
    1150             if (AudioMixBufIsEmpty(&pGstStrmOut->MixBuf))
    1151             {
    1152                 pGstStrmOut->State.fEmpty = true;
    1153                 fNeedsCleanup |= !pGstStrmOut->State.fActive;
    1154             }
    1155         }
    1156 
    1157         if (fNeedsCleanup)
    1158         {
    1159             RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
    1160             {
    1161                 if (!pGstStrmOut->State.fActive)
    1162                     drvAudioDestroyGstOut(pThis, pGstStrmOut);
    1163             }
    1164         }
    1165     }
    1166 
    1167     if (RT_SUCCESS(rc))
    1168     {
    1169         if (pcSamplesPlayed)
    1170             *pcSamplesPlayed = cSamplesPlayedMax;
     756    LogFlowFunc(("[%s]\n", pStream->szName));
     757
     758    uint32_t cSamplesCaptured = 0;
     759
     760    do
     761    {
     762        /* Backend input (temporarily) disabled / unavailable? */
     763        if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING)
     764        {
     765            rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg);
     766            AssertRC(rc);
     767
     768            if (   !pThis->BackendCfg.cSources
     769                || !pThis->BackendCfg.cMaxStreamsIn)
     770            {
     771                rc = VERR_NOT_AVAILABLE;
     772                break;
     773            }
     774        }
     775
     776        PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
     777        AssertPtr(pHstStream);
     778        PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
     779        AssertPtr(pGstStream);
     780
     781        uint32_t cSamplesLive = AudioMixBufUsed(&pHstStream->MixBuf);
     782        if (cSamplesLive)
     783        {
     784            PDMAUDIOSTRMSTS strmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
     785            if (strmSts & PDMAUDIOSTRMSTS_FLAG_DATA_READABLE)
     786            {
     787                rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pHstStream, &cSamplesCaptured);
     788                if (RT_FAILURE(rc))
     789                    drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
     790            }
     791
     792            LogFlowFunc(("[%s] strmSts=0x%x, cSamplesCaptured=%RU32, rc=%Rrc\n", pStream->szName, strmSts, cSamplesCaptured, rc));
     793
     794            if (RT_SUCCESS(rc))
     795            {
     796                rc = drvAudioStreamIterateInternal(pThis, pStream);
     797                if (RT_SUCCESS(rc))
     798                    cSamplesLive = AudioMixBufUsed(&pHstStream->MixBuf);
     799            }
     800        }
     801
     802        if (!cSamplesLive)
     803        {
     804            /* Has the host stream marked as disabled but there still were guest streams relying
     805             * on it? Check if the stream now can be closed and do so, if possible. */
     806            if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
     807            {
     808                LogFunc(("%s: Closing pending stream\n", pHstStream->szName));
     809                rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
     810                if (RT_SUCCESS(rc))
     811                {
     812                    pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
     813                }
     814                else
     815                    LogFunc(("%s: Backend vetoed against closing input stream, rc=%Rrc\n", pHstStream->szName, rc));
     816            }
     817        }
     818
     819    } while (0);
     820
     821    if (RT_SUCCESS(rc))
     822    {
     823        if (pcSamplesCaptured)
     824            *pcSamplesCaptured = cSamplesCaptured;
    1171825    }
    1172826
     
    1180834    return rc;
    1181835}
    1182 #endif
    1183836
    1184837#ifdef VBOX_WITH_AUDIO_CALLBACKS
     
    13781031    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
    13791032    LogFlowFunc(("pThis=%p, pDrvIns=%p\n", pThis, pDrvIns));
     1033
     1034    int rc = RTCritSectInit(&pThis->CritSect);
     1035
     1036    /** @todo Add audio driver options. */
     1037
     1038    /*
     1039     * If everything went well, initialize the lower driver.
     1040     */
     1041    if (RT_SUCCESS(rc))
     1042        rc = drvAudioHostInit(pCfgHandle, pThis);
     1043
     1044    LogFlowFuncLeaveRC(rc);
     1045    return rc;
     1046}
     1047
     1048static DECLCALLBACK(int) drvAudioStreamRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream,
     1049                                            void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
     1050{
     1051    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
     1052    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     1053
     1054    if (!pStream)
     1055    {
     1056        if (pcbRead)
     1057            *pcbRead = 0;
     1058        return VINF_SUCCESS;
     1059    }
     1060
     1061    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
     1062    AssertReturn(cbBuf,    VERR_INVALID_PARAMETER);
     1063    /* pcbWritten is optional. */
     1064
     1065    int rc = RTCritSectEnter(&pThis->CritSect);
     1066    if (RT_FAILURE(rc))
     1067        return rc;
     1068
     1069    AssertMsg(pStream->enmDir == PDMAUDIODIR_IN,
     1070              ("Stream '%s' is not an input stream and therefore cannot be read from (direction is 0x%x)\n",
     1071               pStream->szName, pStream->enmDir));
     1072
     1073    if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING)
     1074    {
     1075        if (pcbRead)
     1076            *pcbRead = 0;
     1077
     1078        return RTCritSectLeave(&pThis->CritSect);
     1079    }
     1080
     1081    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
     1082    PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
     1083
     1084    AssertMsg(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
     1085              ("Reading from disabled host input stream '%s' not possible\n", pHstStream->szName));
     1086
     1087    Log3Func(("%s\n", pStream->szName));
     1088
     1089    /*
     1090     * Read from the parent buffer (that is, the guest buffer) which
     1091     * should have the audio data in the format the guest needs.
     1092     */
     1093    uint32_t cRead;
     1094    rc = AudioMixBufReadCirc(&pGstStream->MixBuf, pvBuf, cbBuf, &cRead);
     1095    if (RT_SUCCESS(rc))
     1096    {
     1097        if (cRead)
     1098            AudioMixBufFinish(&pGstStream->MixBuf, cRead);
     1099
     1100        if (pcbRead)
     1101            *pcbRead = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cRead);
     1102    }
     1103
     1104    LogFlowFunc(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n",
     1105                 cRead, AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cRead), rc));
     1106
     1107    int rc2 = RTCritSectLeave(&pThis->CritSect);
     1108    if (RT_SUCCESS(rc))
     1109        rc = rc2;
     1110
     1111    return rc;
     1112}
     1113
     1114static DECLCALLBACK(int) drvAudioStreamCreate(PPDMIAUDIOCONNECTOR pInterface,
     1115                                              PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest,
     1116                                              PPDMAUDIOSTREAM *ppStream)
     1117{
     1118    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     1119    AssertPtrReturn(pCfgHost,   VERR_INVALID_POINTER);
     1120    AssertPtrReturn(pCfgGuest,  VERR_INVALID_POINTER);
     1121    AssertPtrReturn(ppStream,   VERR_INVALID_POINTER);
     1122
     1123    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
     1124
     1125    int rc = RTCritSectEnter(&pThis->CritSect);
     1126    if (RT_FAILURE(rc))
     1127        return rc;
     1128
     1129    LogFlowFunc(("Host=%s, Guest=%s\n", pCfgHost->szName, pCfgGuest->szName));
     1130#ifdef DEBUG
     1131    DrvAudioHlpStreamCfgPrint(pCfgHost);
     1132    DrvAudioHlpStreamCfgPrint(pCfgGuest);
     1133#endif
     1134
     1135    /*
     1136     * The guest stream always will get the audio stream configuration told
     1137     * by the device emulation (which in turn was/could be set by the guest OS).
     1138     */
     1139    PPDMAUDIOSTREAM pGstStrm = NULL;
     1140
     1141    /** @todo Docs! */
     1142    PPDMAUDIOSTREAM pHstStrm = NULL;
     1143
     1144#define RC_BREAK(x) { rc = x; break; }
     1145
     1146    do
     1147    {
     1148        if (   !DrvAudioHlpStreamCfgIsValid(pCfgHost)
     1149            || !DrvAudioHlpStreamCfgIsValid(pCfgGuest))
     1150        {
     1151            RC_BREAK(VERR_INVALID_PARAMETER);
     1152        }
     1153
     1154        /* Make sure that both configurations actually intend the same thing. */
     1155        if (pCfgHost->enmDir != pCfgGuest->enmDir)
     1156        {
     1157            AssertMsgFailed(("Stream configuration directions do not match\n"));
     1158            RC_BREAK(VERR_INVALID_PARAMETER);
     1159        }
     1160
     1161        /* Note: cbHstStrm will contain sizeof(PDMAUDIOSTREAM) + additional data
     1162         *       which the host backend will need. */
     1163        size_t cbHstStrm;
     1164        if (pCfgHost->enmDir == PDMAUDIODIR_IN)
     1165        {
     1166            if (!pThis->cStreamsFreeIn)
     1167            {
     1168                LogFlowFunc(("No more input streams free to use, bailing out\n"));
     1169                RC_BREAK(VERR_AUDIO_NO_FREE_INPUT_STREAMS);
     1170            }
     1171
     1172            /* Validate backend configuration. */
     1173            if (!pThis->BackendCfg.cbStreamIn)
     1174            {
     1175                LogFlowFunc(("Backend input configuration not valid, bailing out\n"));
     1176                RC_BREAK(VERR_INVALID_PARAMETER);
     1177            }
     1178
     1179            cbHstStrm = pThis->BackendCfg.cbStreamIn;
     1180        }
     1181        else /* Out */
     1182        {
     1183            if (!pThis->cStreamsFreeOut)
     1184            {
     1185                LogFlowFunc(("Maximum number of host output streams reached\n"));
     1186                RC_BREAK(VERR_AUDIO_NO_FREE_OUTPUT_STREAMS);
     1187            }
     1188
     1189            /* Validate backend configuration. */
     1190            if (!pThis->BackendCfg.cbStreamOut)
     1191            {
     1192                LogFlowFunc(("Backend output configuration invalid, bailing out\n"));
     1193                RC_BREAK(VERR_INVALID_PARAMETER);
     1194            }
     1195
     1196            cbHstStrm = pThis->BackendCfg.cbStreamOut;
     1197        }
     1198
     1199        pHstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(cbHstStrm);
     1200        AssertPtrBreakStmt(pHstStrm, rc = VERR_NO_MEMORY);
     1201
     1202        pHstStrm->enmCtx = PDMAUDIOSTREAMCTX_HOST;
     1203        pHstStrm->enmDir = pCfgHost->enmDir;
     1204
     1205        pGstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(sizeof(PDMAUDIOSTREAM));
     1206        AssertPtrBreakStmt(pGstStrm, rc = VERR_NO_MEMORY);
     1207
     1208        pGstStrm->enmCtx = PDMAUDIOSTREAMCTX_GUEST;
     1209        pGstStrm->enmDir = pCfgGuest->enmDir;
     1210
     1211        /*
     1212         * Create host stream.
     1213         */
     1214
     1215        RTStrPrintf(pHstStrm->szName, RT_ELEMENTS(pHstStrm->szName), "%s (Host)",
     1216                    strlen(pCfgHost->szName) ? pCfgHost->szName : "<Untitled>");
     1217
     1218        /* Note: Direction is always from child -> parent. */
     1219        uint32_t cSamples = 0;
     1220        rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pHstStrm, pCfgHost, &cSamples);
     1221        if (RT_FAILURE(rc))
     1222        {
     1223            LogFlowFunc(("Initializing host backend failed with rc=%Rrc\n", rc));
     1224            break;
     1225        }
     1226
     1227        pHstStrm->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
     1228        pHstStrm->pPair    = pGstStrm;
     1229
     1230        rc = DrvAudioHlpStreamCfgToProps(pCfgHost, &pHstStrm->Props);
     1231        AssertRCBreak(rc);
     1232
     1233        rc = AudioMixBufInit(&pHstStrm->MixBuf, pHstStrm->szName, &pHstStrm->Props, cSamples * 4);
     1234        AssertRCBreak(rc);
     1235
     1236        /*
     1237         * Create guest stream.
     1238         */
     1239
     1240        RTStrPrintf(pGstStrm->szName, RT_ELEMENTS(pGstStrm->szName), "%s (Guest)",
     1241                    strlen(pCfgGuest->szName) ? pCfgGuest->szName : "<Untitled>");
     1242
     1243        rc = DrvAudioHlpStreamCfgToProps(pCfgGuest, &pGstStrm->Props);
     1244        AssertRCBreak(rc);
     1245
     1246        rc = AudioMixBufInit(&pGstStrm->MixBuf, pGstStrm->szName, &pGstStrm->Props, cSamples * 2);
     1247        if (RT_SUCCESS(rc))
     1248        {
     1249            if (pCfgGuest->enmDir == PDMAUDIODIR_IN)
     1250            {
     1251                /* Host (Parent) -> Guest (Child). */
     1252                rc = AudioMixBufLinkTo(&pHstStrm->MixBuf, &pGstStrm->MixBuf);
     1253            }
     1254            else
     1255            {
     1256                /* Guest (Parent) -> Host (Child). */
     1257                rc = AudioMixBufLinkTo(&pGstStrm->MixBuf, &pHstStrm->MixBuf);
     1258            }
     1259        }
     1260
     1261        pGstStrm->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
     1262        pGstStrm->pPair    = pHstStrm;
     1263
     1264        AssertRCBreak(rc);
     1265
     1266    } while (0);
     1267
     1268#undef RC_BREAK
     1269
     1270    if (RT_FAILURE(rc))
     1271    {
     1272        drvAudioStreamDestroyInternal(pThis, pGstStrm);
     1273        pGstStrm = NULL;
     1274
     1275        drvAudioStreamDestroyInternal(pThis, pHstStrm);
     1276        pHstStrm = NULL;
     1277    }
     1278    else
     1279    {
     1280        /* Set initial reference counts. */
     1281        RTListAppend(&pThis->lstGstStreams, &pGstStrm->Node);
     1282        pGstStrm->cRefs = 1;
     1283
     1284        RTListAppend(&pThis->lstHstStreams, &pHstStrm->Node);
     1285        pHstStrm->cRefs = 1;
     1286
     1287        if (pCfgHost->enmDir == PDMAUDIODIR_IN)
     1288        {
     1289            Assert(pThis->cStreamsFreeIn);
     1290            pThis->cStreamsFreeIn--;
     1291        }
     1292        else /* Out */
     1293        {
     1294            Assert(pThis->cStreamsFreeOut);
     1295            pThis->cStreamsFreeOut--;
     1296        }
     1297
     1298        /* Always return the guest-side part to the device emulation. */
     1299        *ppStream = pGstStrm;
     1300    }
     1301
     1302    int rc2 = RTCritSectLeave(&pThis->CritSect);
     1303    if (RT_SUCCESS(rc))
     1304        rc = rc2;
     1305
     1306    LogFlowFuncLeaveRC(rc);
     1307    return rc;
     1308}
     1309
     1310#if 1
     1311static DECLCALLBACK(int) drvAudioGetConfig(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg)
     1312{
     1313    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     1314    AssertPtrReturn(pCfg,       VERR_INVALID_POINTER);
     1315
     1316    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
     1317
     1318    int rc = RTCritSectEnter(&pThis->CritSect);
     1319    if (RT_FAILURE(rc))
     1320        return rc;
     1321
     1322    rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, pCfg);
     1323
     1324    int rc2 = RTCritSectLeave(&pThis->CritSect);
     1325    if (RT_SUCCESS(rc))
     1326        rc = rc2;
     1327
     1328    LogFlowFuncLeaveRC(rc);
     1329    return rc;
     1330}
     1331
     1332static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioGetStatus(PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir)
     1333{
     1334    AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
     1335
     1336    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
     1337
     1338    int rc = RTCritSectEnter(&pThis->CritSect);
     1339    if (RT_FAILURE(rc))
     1340        return PDMAUDIOBACKENDSTS_UNKNOWN;
     1341
     1342    PDMAUDIOBACKENDSTS backendSts = pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, enmDir);
     1343
     1344    int rc2 = RTCritSectLeave(&pThis->CritSect);
     1345    if (RT_SUCCESS(rc))
     1346        rc = rc2;
     1347
     1348    LogFlowFuncLeaveRC(rc);
     1349    return backendSts;
     1350}
     1351
     1352static DECLCALLBACK(PDMAUDIOSTRMSTS) drvAudioStreamGetStatus(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
     1353{
     1354    AssertPtrReturn(pInterface, false);
     1355
     1356    if (!pStream)
     1357        return PDMAUDIOSTRMSTS_FLAG_NONE;
     1358
     1359    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
     1360
     1361    int rc2 = RTCritSectEnter(&pThis->CritSect);
     1362    AssertRC(rc2);
     1363
     1364    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
     1365    PDMAUDIOSTRMSTS strmSts    = pHstStream->fStatus;
     1366
     1367    LogFlowFunc(("%s: strmSts=0x%x\n", pHstStream->szName, strmSts));
     1368    rc2 = RTCritSectLeave(&pThis->CritSect);
     1369    AssertRC(rc2);
     1370
     1371    return strmSts;
     1372}
     1373
     1374static DECLCALLBACK(int) drvAudioStreamSetVolume(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOVOLUME pVol)
     1375{
     1376    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     1377    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     1378    AssertPtrReturn(pVol,       VERR_INVALID_POINTER);
     1379
     1380    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
     1381
     1382    LogFlowFunc(("%s: volL=%RU32, volR=%RU32, fMute=%RTbool\n", pStream->szName, pVol->uLeft, pVol->uRight, pVol->fMuted));
     1383
     1384    AudioMixBufSetVolume(&pStream->MixBuf, pVol);
     1385
     1386    return VINF_SUCCESS;
     1387}
     1388#endif
     1389
     1390static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
     1391{
     1392    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     1393    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     1394
     1395    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
     1396
     1397    int rc = RTCritSectEnter(&pThis->CritSect);
     1398    AssertRC(rc);
     1399
     1400    PDMAUDIODIR enmDir = pStream->enmDir;
     1401
     1402    LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));
     1403    if (pStream->cRefs > 1)
     1404        rc = VERR_WRONG_ORDER;
     1405
     1406    if (RT_SUCCESS(rc))
     1407    {
     1408        PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
     1409        PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream;
     1410
     1411        LogFlowFunc(("\tHost : %s\n", pHstStream ? pHstStream->szName : "<None>"));
     1412        LogFlowFunc(("\tGuest: %s\n", pGstStream ? pGstStream->szName : "<None>"));
     1413
     1414        /* Should prevent double frees. */
     1415        Assert(pHstStream != pGstStream);
     1416
     1417        if (pHstStream)
     1418        {
     1419            pHstStream->pPair = NULL;
     1420            RTListNodeRemove(&pHstStream->Node);
     1421        }
     1422
     1423        if (pGstStream)
     1424        {
     1425            pGstStream->pPair = NULL;
     1426            RTListNodeRemove(&pGstStream->Node);
     1427        }
     1428
     1429        if (pHstStream)
     1430        {
     1431            rc = drvAudioStreamDestroyInternal(pThis, pHstStream);
     1432            AssertRC(rc);
     1433
     1434            pHstStream = NULL;
     1435        }
     1436
     1437        if (pGstStream)
     1438        {
     1439            rc = drvAudioStreamDestroyInternal(pThis, pGstStream);
     1440            AssertRC(rc);
     1441
     1442            pGstStream = NULL;
     1443        }
     1444    }
     1445
     1446    if (RT_SUCCESS(rc))
     1447    {
     1448        if (enmDir == PDMAUDIODIR_IN)
     1449        {
     1450            pThis->cStreamsFreeIn++;
     1451        }
     1452        else /* Out */
     1453        {
     1454            pThis->cStreamsFreeOut++;
     1455        }
     1456    }
     1457
     1458    int rc2 = RTCritSectLeave(&pThis->CritSect);
     1459    if (RT_SUCCESS(rc))
     1460        rc = rc2;
     1461
     1462    LogFlowFuncLeaveRC(rc);
     1463    return rc;
     1464}
     1465
     1466static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream)
     1467{
     1468    AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
     1469    AssertPtrReturn(pHstStream, VERR_INVALID_POINTER);
     1470
     1471    AssertMsg(pHstStream->enmCtx == PDMAUDIOSTREAMCTX_HOST,
     1472              ("Stream '%s' is not a host stream and therefore has no backend\n", pHstStream->szName));
     1473
     1474    int rc = VINF_SUCCESS;
     1475
     1476    LogFlowFunc(("%s: fStatus=0x%x\n", pHstStream->szName, pHstStream->fStatus));
     1477
     1478    if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
     1479    {
     1480        if (pThis->pHostDrvAudio)
     1481            rc = pThis->pHostDrvAudio->pfnStreamDestroy(pThis->pHostDrvAudio, pHstStream);
     1482        if (RT_SUCCESS(rc))
     1483            pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
     1484    }
     1485
     1486    LogFlowFunc(("%s: Returning %Rrc\n", pHstStream->szName, rc));
     1487    return rc;
     1488}
     1489
     1490static int drvAudioStreamDestroyInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream)
     1491{
     1492    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     1493    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
     1494
     1495    LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));
     1496
     1497    if (pStream->cRefs > 1)
     1498        return VERR_WRONG_ORDER;
     1499
     1500    int rc = VINF_SUCCESS;
     1501
     1502    if (pStream->enmCtx == PDMAUDIOSTREAMCTX_GUEST)
     1503    {
     1504        if (pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
     1505        {
     1506            rc = drvAudioStreamControlInternal(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE);
     1507            if (RT_SUCCESS(rc))
     1508                pStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
     1509        }
     1510    }
     1511    else if (pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST)
     1512    {
     1513        rc = drvAudioStreamDestroyInternalBackend(pThis, pStream);
     1514    }
     1515    else
     1516        AssertFailedReturn(VERR_NOT_IMPLEMENTED);
     1517
     1518    if (RT_SUCCESS(rc))
     1519    {
     1520        /* Destroy mixing buffer. */
     1521        AudioMixBufDestroy(&pStream->MixBuf);
     1522
     1523        if (pStream)
     1524        {
     1525            RTMemFree(pStream);
     1526            pStream = NULL;
     1527        }
     1528    }
     1529
     1530    LogFlowFunc(("Returning %Rrc\n", rc));
     1531    return rc;
     1532}
     1533
     1534/********************************************************************/
     1535
     1536/**
     1537 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
     1538 */
     1539static DECLCALLBACK(void *) drvAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
     1540{
     1541    LogFlowFunc(("pInterface=%p, pszIID=%s\n", pInterface, pszIID));
     1542
     1543    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
     1544    PDRVAUDIO  pThis   = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
     1545
     1546    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
     1547    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIAUDIOCONNECTOR, &pThis->IAudioConnector);
     1548
     1549    return NULL;
     1550}
     1551
     1552/**
     1553 * Power Off notification.
     1554 *
     1555 * @param   pDrvIns     The driver instance data.
     1556 */
     1557static DECLCALLBACK(void) drvAudioPowerOff(PPDMDRVINS pDrvIns)
     1558{
     1559    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
     1560
     1561    LogFlowFuncEnter();
     1562
     1563    /* Just destroy the host stream on the backend side.
     1564     * The rest will either be destructed by the device emulation or
     1565     * in drvAudioDestruct(). */
     1566    PPDMAUDIOSTREAM pStream;
     1567    RTListForEach(&pThis->lstHstStreams, pStream, PDMAUDIOSTREAM, Node)
     1568        drvAudioStreamDestroyInternalBackend(pThis, pStream);
     1569
     1570    /*
     1571     * Last call for the driver below us.
     1572     * Let it know that we reached end of life.
     1573     */
     1574    if (pThis->pHostDrvAudio->pfnShutdown)
     1575        pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio);
     1576
     1577    pThis->pHostDrvAudio = NULL;
     1578
     1579    LogFlowFuncLeave();
     1580}
     1581
     1582/**
     1583 * Constructs an audio driver instance.
     1584 *
     1585 * @copydoc FNPDMDRVCONSTRUCT
     1586 */
     1587static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
     1588{
     1589    LogFlowFunc(("pDrvIns=%#p, pCfgHandle=%#p, fFlags=%x\n", pDrvIns, pCfgHandle, fFlags));
     1590
     1591    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
     1592    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
    13801593
    13811594    RTListInit(&pThis->lstHstStreams);
     
    13851598    RTListInit(&pThis->lstCBOut);
    13861599#endif
    1387 
    1388     int rc = RTCritSectInit(&pThis->CritSect);
    1389 
    1390     /** @todo Add audio driver options. */
    1391 
    1392     /*
    1393      * If everything went well, initialize the lower driver.
    1394      */
    1395     if (RT_SUCCESS(rc))
    1396         rc = drvAudioHostInit(pCfgHandle, pThis);
    1397 
    1398     LogFlowFuncLeaveRC(rc);
    1399     return rc;
    1400 }
    1401 
    1402 #if 1
    1403 static DECLCALLBACK(int) drvAudioStreamRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream,
    1404                                             void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
    1405 {
    1406     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    1407     AssertPtrReturn(pThis, VERR_INVALID_POINTER);
    1408 
    1409     if (!pStream)
    1410     {
    1411         if (pcbRead)
    1412             *pcbRead = 0;
    1413         return VINF_SUCCESS;
    1414     }
    1415 
    1416     AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
    1417     AssertReturn(cbBuf,    VERR_INVALID_PARAMETER);
    1418     /* pcbWritten is optional. */
    1419 
    1420     int rc = RTCritSectEnter(&pThis->CritSect);
    1421     if (RT_FAILURE(rc))
    1422         return rc;
    1423 
    1424     if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING)
    1425     {
    1426         if (pcbRead)
    1427             *pcbRead = 0;
    1428 
    1429         return RTCritSectLeave(&pThis->CritSect);
    1430     }
    1431 
    1432     PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
    1433 
    1434     AssertMsg(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
    1435               ("Reading from disabled host input stream '%s' not possible\n", pHstStream->szName));
    1436 
    1437     /*
    1438      * Read from the parent buffer (that is, the guest buffer) which
    1439      * should have the audio data in the format the guest needs.
    1440      */
    1441     uint32_t cRead;
    1442     rc = AudioMixBufReadCirc(&pStream->MixBuf, pvBuf, cbBuf, &cRead);
    1443     if (RT_SUCCESS(rc))
    1444     {
    1445         AudioMixBufFinish(&pStream->MixBuf, cRead);
    1446 
    1447         if (pcbRead)
    1448             *pcbRead = AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead);
    1449     }
    1450 
    1451     LogFlowFunc(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n",
    1452                  cRead, AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead), rc));
    1453 
    1454     int rc2 = RTCritSectLeave(&pThis->CritSect);
    1455     if (RT_SUCCESS(rc))
    1456         rc = rc2;
    1457 
    1458     return rc;
    1459 }
    1460 #else
    1461 static DECLCALLBACK(int) drvAudioRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn,
    1462                                       void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
    1463 {
    1464     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    1465     AssertPtrReturn(pThis, VERR_INVALID_POINTER);
    1466 
    1467     if (!pGstStrmIn)
    1468         return VERR_NOT_AVAILABLE;
    1469 
    1470     AssertPtrReturn(pvBuf,      VERR_INVALID_POINTER);
    1471     AssertReturn(cbBuf,         VERR_INVALID_PARAMETER);
    1472     /* pcbWritten is optional. */
    1473 
    1474     int rc = RTCritSectEnter(&pThis->CritSect);
    1475     if (RT_FAILURE(rc))
    1476         return rc;
    1477 
    1478     if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_IN))
    1479     {
    1480         if (pcbRead)
    1481             *pcbRead = 0;
    1482 
    1483         return RTCritSectLeave(&pThis->CritSect);
    1484     }
    1485 
    1486     PPDMAUDIOHSTSTRMIN pHstStrmIn = pGstStrmIn->pHstStrmIn;
    1487     AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
    1488 
    1489     AssertMsg(pGstStrmIn->pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
    1490               ("Reading from disabled host input stream \"%s\" not possible\n", pGstStrmIn->MixBuf.pszName));
    1491 
    1492     /*
    1493      * Read from the parent buffer (that is, the guest buffer) which
    1494      * should have the audio data in the format the guest needs.
    1495      */
    1496     uint32_t cRead;
    1497     rc = AudioMixBufReadCirc(&pGstStrmIn->MixBuf, pvBuf, cbBuf, &cRead);
    1498     if (RT_SUCCESS(rc))
    1499     {
    1500         AudioMixBufFinish(&pGstStrmIn->MixBuf, cRead);
    1501 
    1502         if (pcbRead)
    1503             *pcbRead = AUDIOMIXBUF_S2B(&pGstStrmIn->MixBuf, cRead);
    1504     }
    1505 
    1506     LogFlowFunc(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n",
    1507                  cRead, AUDIOMIXBUF_S2B(&pGstStrmIn->MixBuf, cRead), rc));
    1508 
    1509     int rc2 = RTCritSectLeave(&pThis->CritSect);
    1510     if (RT_SUCCESS(rc))
    1511         rc = rc2;
    1512 
    1513     return rc;
    1514 }
    1515 #endif
    1516 
    1517 #if 0
    1518 static DECLCALLBACK(int) drvAudioEnableOut(PPDMIAUDIOCONNECTOR pInterface,
    1519                                            PPDMAUDIOGSTSTRMOUT pGstStrmOut, bool fEnable)
    1520 {
    1521     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    1522 
    1523     if (!pGstStrmOut)
    1524         return VERR_NOT_AVAILABLE;
    1525 
    1526     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    1527 
    1528     int rc = VINF_SUCCESS;
    1529 
    1530     PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
    1531     AssertPtr(pHstStrmOut);
    1532 
    1533     if (fEnable)
    1534     {
    1535         /* Is a pending disable outstanding? Then disable first. */
    1536         if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
    1537         {
    1538             rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
    1539             if (RT_SUCCESS(rc))
    1540                 pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
    1541         }
    1542 
    1543         if (RT_SUCCESS(rc))
    1544             rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);
    1545 
    1546         if (RT_SUCCESS(rc))
    1547             pGstStrmOut->State.fActive = fEnable;
    1548     }
    1549     else /* Disable */
    1550     {
    1551         if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
    1552         {
    1553             size_t cGstStrmsActive = 0;
    1554 
    1555             /*
    1556              * Check if there are any active guest streams assigned
    1557              * to this host stream which still are being marked as active.
    1558              *
    1559              * In that case we have to defer closing the host stream and
    1560              * wait until all guest streams have been finished.
    1561              */
    1562             PPDMAUDIOGSTSTRMOUT pIter;
    1563             RTListForEach(&pHstStrmOut->lstGstStrmOut, pIter, PDMAUDIOGSTSTRMOUT, Node)
    1564             {
    1565                 if (pIter->State.fActive)
    1566                 {
    1567                     cGstStrmsActive++;
    1568                     break; /* At least one assigned & active guest stream is enough. */
    1569                 }
    1570             }
    1571 
    1572             /* Do we need to defer closing the host stream? */
    1573             if (cGstStrmsActive)
    1574             {
    1575                 LogFlowFunc(("Closing stream deferred: %zu guest stream(s) active\n", cGstStrmsActive));
    1576                 pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
    1577 
    1578                 rc = VERR_AUDIO_STREAM_PENDING_DISABLE;
    1579             }
    1580             else
    1581             {
    1582                 rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
    1583                 if (RT_SUCCESS(rc))
    1584                     pGstStrmOut->State.fActive = fEnable;
    1585             }
    1586         }
    1587     }
    1588 
    1589     LogFlowFunc(("%s: fEnable=%RTbool, fStatus=0x%x, rc=%Rrc\n",
    1590                  pGstStrmOut->MixBuf.pszName, fEnable, pHstStrmOut->fStatus, rc));
    1591 
    1592     return rc;
    1593 }
    1594 #endif
    1595 
    1596 static DECLCALLBACK(int) drvAudioStreamCreate(PPDMIAUDIOCONNECTOR pInterface,
    1597                                               PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest,
    1598                                               PPDMAUDIOSTREAM *ppStream)
    1599 {
    1600     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    1601     AssertPtrReturn(pCfgHost,   VERR_INVALID_POINTER);
    1602     AssertPtrReturn(pCfgGuest,  VERR_INVALID_POINTER);
    1603     AssertPtrReturn(ppStream,   VERR_INVALID_POINTER);
    1604 
    1605     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    1606 
    1607     int rc = RTCritSectEnter(&pThis->CritSect);
    1608     if (RT_FAILURE(rc))
    1609         return rc;
    1610 
    1611     LogFlowFunc(("Host=%s, Guest=%s\n", pCfgHost->szName, pCfgGuest->szName));
    1612 #ifdef DEBUG
    1613     DrvAudioHlpStreamCfgPrint(pCfgHost);
    1614     DrvAudioHlpStreamCfgPrint(pCfgGuest);
    1615 #endif
    1616 
    1617     /*
    1618      * The guest stream always will get the audio stream configuration told
    1619      * by the device emulation (which in turn was/could be set by the guest OS).
    1620      */
    1621     PPDMAUDIOSTREAM pGstStrm = NULL;
    1622 
    1623     /** @todo Docs! */
    1624     PPDMAUDIOSTREAM pHstStrm = NULL;
    1625 
    1626 #define RC_BREAK(x) { rc = x; break; }
    1627 
    1628     do
    1629     {
    1630         if (   !DrvAudioHlpStreamCfgIsValid(pCfgHost)
    1631             || !DrvAudioHlpStreamCfgIsValid(pCfgGuest))
    1632         {
    1633             RC_BREAK(VERR_INVALID_PARAMETER);
    1634         }
    1635 
    1636         /* Make sure that both configurations actually intend the same thing. */
    1637         if (pCfgHost->enmDir != pCfgGuest->enmDir)
    1638         {
    1639             AssertMsgFailed(("Stream configuration directions do not match\n"));
    1640             RC_BREAK(VERR_INVALID_PARAMETER);
    1641         }
    1642 
    1643         /* Note: cbHstStrm will contain sizeof(PDMAUDIOSTREAM) + additional data
    1644          *       which the host backend will need. */
    1645         size_t cbHstStrm;
    1646         if (pCfgHost->enmDir == PDMAUDIODIR_IN)
    1647         {
    1648             if (!pThis->cStreamsFreeIn)
    1649             {
    1650                 LogFlowFunc(("No more input streams free to use, bailing out\n"));
    1651                 RC_BREAK(VERR_AUDIO_NO_FREE_INPUT_STREAMS);
    1652             }
    1653 
    1654             /* Validate backend configuration. */
    1655             if (!pThis->BackendCfg.cbStreamIn)
    1656             {
    1657                 LogFlowFunc(("Backend input configuration not valid, bailing out\n"));
    1658                 RC_BREAK(VERR_INVALID_PARAMETER);
    1659             }
    1660 
    1661             cbHstStrm = pThis->BackendCfg.cbStreamIn;
    1662         }
    1663         else /* Out */
    1664         {
    1665             if (!pThis->cStreamsFreeOut)
    1666             {
    1667                 LogFlowFunc(("Maximum number of host output streams reached\n"));
    1668                 RC_BREAK(VERR_AUDIO_NO_FREE_OUTPUT_STREAMS);
    1669             }
    1670 
    1671             /* Validate backend configuration. */
    1672             if (!pThis->BackendCfg.cbStreamOut)
    1673             {
    1674                 LogFlowFunc(("Backend output configuration invalid, bailing out\n"));
    1675                 RC_BREAK(VERR_INVALID_PARAMETER);
    1676             }
    1677 
    1678             cbHstStrm = pThis->BackendCfg.cbStreamOut;
    1679         }
    1680 
    1681         pHstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(cbHstStrm);
    1682         AssertPtrBreakStmt(pHstStrm, rc = VERR_NO_MEMORY);
    1683 
    1684         pHstStrm->enmCtx = PDMAUDIOSTREAMCTX_HOST;
    1685         pHstStrm->enmDir = pCfgHost->enmDir;
    1686 
    1687         RTListAppend(&pThis->lstHstStreams, &pHstStrm->Node);
    1688 
    1689         pGstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(sizeof(PDMAUDIOSTREAM));
    1690         AssertPtrBreakStmt(pGstStrm, rc = VERR_NO_MEMORY);
    1691 
    1692         pGstStrm->enmCtx = PDMAUDIOSTREAMCTX_GUEST;
    1693         pGstStrm->enmDir = pCfgGuest->enmDir;
    1694 
    1695         RTListAppend(&pThis->lstGstStreams, &pGstStrm->Node);
    1696 
    1697         /*
    1698          * Create host stream.
    1699          */
    1700 
    1701         RTStrPrintf(pHstStrm->szName, RT_ELEMENTS(pHstStrm->szName), "%s (Host)",
    1702                     strlen(pCfgHost->szName) ? pCfgHost->szName : "<Untitled>");
    1703 
    1704         /* Note: Direction is always from child -> parent. */
    1705         uint32_t cSamples = 0;
    1706         rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pHstStrm, pCfgHost, &cSamples);
    1707         if (RT_FAILURE(rc))
    1708         {
    1709             LogFlowFunc(("Initializing host backend failed with rc=%Rrc\n", rc));
    1710             break;
    1711         }
    1712 
    1713         pHstStrm->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
    1714         pHstStrm->pPair    = pGstStrm;
    1715 
    1716         rc = DrvAudioHlpStreamCfgToProps(pCfgHost, &pHstStrm->Props);
    1717         AssertRCBreak(rc);
    1718 
    1719         rc = AudioMixBufInit(&pHstStrm->MixBuf, pHstStrm->szName, &pHstStrm->Props, cSamples * 4);
    1720         AssertRCBreak(rc);
    1721 
    1722         /*
    1723          * Create guest stream.
    1724          */
    1725 
    1726         RTStrPrintf(pGstStrm->szName, RT_ELEMENTS(pGstStrm->szName), "%s (Guest)",
    1727                     strlen(pCfgGuest->szName) ? pCfgGuest->szName : "<Untitled>");
    1728 
    1729         rc = DrvAudioHlpStreamCfgToProps(pCfgGuest, &pGstStrm->Props);
    1730         AssertRCBreak(rc);
    1731 
    1732         rc = AudioMixBufInit(&pGstStrm->MixBuf, pGstStrm->szName, &pGstStrm->Props, cSamples * 2);
    1733         if (RT_SUCCESS(rc))
    1734         {
    1735             if (pCfgGuest->enmDir == PDMAUDIODIR_IN)
    1736             {
    1737                 /* Host (Parent) -> Guest (Child). */
    1738                 rc = AudioMixBufLinkTo(&pHstStrm->MixBuf, &pGstStrm->MixBuf);
    1739             }
    1740             else
    1741             {
    1742                 /* Guest (Parent) -> Host (Child). */
    1743                 rc = AudioMixBufLinkTo(&pGstStrm->MixBuf, &pHstStrm->MixBuf);
    1744             }
    1745         }
    1746 
    1747         pGstStrm->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
    1748         pGstStrm->pPair    = pHstStrm;
    1749 
    1750         AssertRCBreak(rc);
    1751 
    1752     } while (0);
    1753 
    1754 #undef RC_BREAK
    1755 
    1756     if (RT_FAILURE(rc))
    1757     {
    1758         drvAudioStreamDestroyInternal(pThis, pGstStrm);
    1759         pGstStrm = NULL;
    1760 
    1761         drvAudioStreamDestroyInternal(pThis, pHstStrm);
    1762         pHstStrm = NULL;
    1763     }
    1764     else
    1765     {
    1766         /* Set initial reference counts. */
    1767         pGstStrm->cRefs = 1;
    1768         pHstStrm->cRefs = 1;
    1769 
    1770         if (pCfgHost->enmDir == PDMAUDIODIR_IN)
    1771         {
    1772             Assert(pThis->cStreamsFreeIn);
    1773             pThis->cStreamsFreeIn--;
    1774         }
    1775         else /* Out */
    1776         {
    1777             Assert(pThis->cStreamsFreeOut);
    1778             pThis->cStreamsFreeOut--;
    1779         }
    1780 
    1781         /* Always return the guest-side part to the device emulation. */
    1782         *ppStream = pGstStrm;
    1783     }
    1784 
    1785     int rc2 = RTCritSectLeave(&pThis->CritSect);
    1786     if (RT_SUCCESS(rc))
    1787         rc = rc2;
    1788 
    1789     LogFlowFuncLeaveRC(rc);
    1790     return rc;
    1791 }
    1792 
    1793 #if 1
    1794 static DECLCALLBACK(int) drvAudioGetConfig(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg)
    1795 {
    1796     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    1797     AssertPtrReturn(pCfg,       VERR_INVALID_POINTER);
    1798 
    1799     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    1800 
    1801     int rc = RTCritSectEnter(&pThis->CritSect);
    1802     if (RT_FAILURE(rc))
    1803         return rc;
    1804 
    1805     rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, pCfg);
    1806 
    1807     int rc2 = RTCritSectLeave(&pThis->CritSect);
    1808     if (RT_SUCCESS(rc))
    1809         rc = rc2;
    1810 
    1811     LogFlowFuncLeaveRC(rc);
    1812     return rc;
    1813 }
    1814 
    1815 static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioGetStatus(PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir)
    1816 {
    1817     AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
    1818 
    1819     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    1820 
    1821     int rc = RTCritSectEnter(&pThis->CritSect);
    1822     if (RT_FAILURE(rc))
    1823         return PDMAUDIOBACKENDSTS_UNKNOWN;
    1824 
    1825     PDMAUDIOBACKENDSTS backendSts = pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, enmDir);
    1826 
    1827     int rc2 = RTCritSectLeave(&pThis->CritSect);
    1828     if (RT_SUCCESS(rc))
    1829         rc = rc2;
    1830 
    1831     LogFlowFuncLeaveRC(rc);
    1832     return backendSts;
    1833 }
    1834 
    1835 static DECLCALLBACK(PDMAUDIOSTRMSTS) drvAudioStreamGetStatus(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
    1836 {
    1837     AssertPtrReturn(pInterface, false);
    1838 
    1839     if (!pStream)
    1840         return PDMAUDIOSTRMSTS_FLAG_NONE;
    1841 
    1842     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    1843 
    1844     int rc2 = RTCritSectEnter(&pThis->CritSect);
    1845     AssertRC(rc2);
    1846 
    1847     PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
    1848     PDMAUDIOSTRMSTS strmSts    = pHstStream->fStatus;
    1849 
    1850     LogFlowFunc(("%s: strmSts=0x%x\n", pHstStream->szName, strmSts));
    1851     rc2 = RTCritSectLeave(&pThis->CritSect);
    1852     AssertRC(rc2);
    1853 
    1854     return strmSts;
    1855 }
    1856 
    1857 static DECLCALLBACK(int) drvAudioStreamSetVolume(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOVOLUME pVol)
    1858 {
    1859     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    1860     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    1861     AssertPtrReturn(pVol,       VERR_INVALID_POINTER);
    1862 
    1863     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    1864 
    1865     LogFlowFunc(("%s: volL=%RU32, volR=%RU32, fMute=%RTbool\n", pStream->szName, pVol->uLeft, pVol->uRight, pVol->fMuted));
    1866 
    1867     AudioMixBufSetVolume(&pStream->MixBuf, pVol);
    1868 
    1869     return VINF_SUCCESS;
    1870 }
    1871 #endif
    1872 
    1873 static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
    1874 {
    1875     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    1876     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    1877 
    1878     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    1879 
    1880     int rc = RTCritSectEnter(&pThis->CritSect);
    1881     AssertRC(rc);
    1882 
    1883     PDMAUDIODIR enmDir = pStream->enmDir;
    1884 
    1885     LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));
    1886     if (pStream->cRefs > 1)
    1887         rc = VERR_WRONG_ORDER;
    1888 
    1889     if (RT_SUCCESS(rc))
    1890     {
    1891         PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
    1892         PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream;
    1893 
    1894         LogFlowFunc(("\tHost : %s\n", pHstStream ? pHstStream->szName : "<None>"));
    1895         LogFlowFunc(("\tGuest: %s\n", pGstStream ? pGstStream->szName : "<None>"));
    1896 
    1897         /* Should prevent double frees. */
    1898         Assert(pHstStream != pGstStream);
    1899 
    1900         if (pHstStream)
    1901         {
    1902             pHstStream->pPair = NULL;
    1903             RTListNodeRemove(&pHstStream->Node);
    1904         }
    1905 
    1906         if (pGstStream)
    1907         {
    1908             pGstStream->pPair = NULL;
    1909             RTListNodeRemove(&pGstStream->Node);
    1910         }
    1911 
    1912         if (pHstStream)
    1913         {
    1914             rc = drvAudioStreamDestroyInternal(pThis, pHstStream);
    1915             AssertRC(rc);
    1916 
    1917             pHstStream = NULL;
    1918         }
    1919 
    1920         if (pGstStream)
    1921         {
    1922             rc = drvAudioStreamDestroyInternal(pThis, pGstStream);
    1923             AssertRC(rc);
    1924 
    1925             pGstStream = NULL;
    1926         }
    1927     }
    1928 
    1929     if (RT_SUCCESS(rc))
    1930     {
    1931         if (enmDir == PDMAUDIODIR_IN)
    1932         {
    1933             pThis->cStreamsFreeIn++;
    1934         }
    1935         else /* Out */
    1936         {
    1937             pThis->cStreamsFreeOut++;
    1938         }
    1939     }
    1940 
    1941     int rc2 = RTCritSectLeave(&pThis->CritSect);
    1942     if (RT_SUCCESS(rc))
    1943         rc = rc2;
    1944 
    1945     LogFlowFuncLeaveRC(rc);
    1946     return rc;
    1947 }
    1948 
    1949 static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream)
    1950 {
    1951     AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
    1952     AssertPtrReturn(pHstStream, VERR_INVALID_POINTER);
    1953 
    1954     AssertMsg(pHstStream->enmCtx == PDMAUDIOSTREAMCTX_HOST,
    1955               ("Stream '%s' is not a host stream and therefore has no backend\n", pHstStream->szName));
    1956 
    1957     int rc = VINF_SUCCESS;
    1958 
    1959     LogFlowFunc(("%s: fStatus=0x%x\n", pHstStream->szName, pHstStream->fStatus));
    1960 
    1961     if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
    1962     {
    1963         if (pThis->pHostDrvAudio)
    1964             rc = pThis->pHostDrvAudio->pfnStreamDestroy(pThis->pHostDrvAudio, pHstStream);
    1965         if (RT_SUCCESS(rc))
    1966             pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
    1967     }
    1968 
    1969     LogFlowFunc(("%s: Returning %Rrc\n", pHstStream->szName, rc));
    1970     return rc;
    1971 }
    1972 
    1973 static int drvAudioStreamDestroyInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream)
    1974 {
    1975     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    1976     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    1977 
    1978     LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));
    1979 
    1980     if (pStream->cRefs > 1)
    1981         return VERR_WRONG_ORDER;
    1982 
    1983     int rc = VINF_SUCCESS;
    1984 
    1985     if (pStream->enmCtx == PDMAUDIOSTREAMCTX_GUEST)
    1986     {
    1987         if (pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
    1988         {
    1989             rc = drvAudioStreamControlInternal(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE);
    1990             if (RT_SUCCESS(rc))
    1991                 pStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
    1992         }
    1993     }
    1994     else if (pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST)
    1995     {
    1996         rc = drvAudioStreamDestroyInternalBackend(pThis, pStream);
    1997     }
    1998     else
    1999         AssertFailedReturn(VERR_NOT_IMPLEMENTED);
    2000 
    2001     if (RT_SUCCESS(rc))
    2002     {
    2003         /* Destroy mixing buffer. */
    2004         AudioMixBufDestroy(&pStream->MixBuf);
    2005 
    2006         if (pStream)
    2007         {
    2008             RTMemFree(pStream);
    2009             pStream = NULL;
    2010         }
    2011     }
    2012 
    2013     LogFlowFunc(("Returning %Rrc\n", rc));
    2014     return rc;
    2015 }
    2016 
    2017 /********************************************************************/
    2018 
    2019 /**
    2020  * @interface_method_impl{PDMIBASE,pfnQueryInterface}
    2021  */
    2022 static DECLCALLBACK(void *) drvAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
    2023 {
    2024     LogFlowFunc(("pInterface=%p, pszIID=%s\n", pInterface, pszIID));
    2025 
    2026     PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
    2027     PDRVAUDIO  pThis   = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
    2028 
    2029     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
    2030     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIAUDIOCONNECTOR, &pThis->IAudioConnector);
    2031 
    2032     return NULL;
    2033 }
    2034 
    2035 /**
    2036  * Power Off notification.
    2037  *
    2038  * @param   pDrvIns     The driver instance data.
    2039  */
    2040 static DECLCALLBACK(void) drvAudioPowerOff(PPDMDRVINS pDrvIns)
    2041 {
    2042     PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
    2043 
    2044     LogFlowFuncEnter();
    2045 
    2046     /* Just destroy the host stream on the backend side.
    2047      * The rest will either be destructed by the device emulation or
    2048      * in drvAudioDestruct(). */
    2049     PPDMAUDIOSTREAM pStream;
    2050     RTListForEach(&pThis->lstHstStreams, pStream, PDMAUDIOSTREAM, Node)
    2051         drvAudioStreamDestroyInternalBackend(pThis, pStream);
    2052 
    2053     /*
    2054      * Last call for the driver below us.
    2055      * Let it know that we reached end of life.
    2056      */
    2057     if (pThis->pHostDrvAudio->pfnShutdown)
    2058         pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio);
    2059 
    2060     pThis->pHostDrvAudio = NULL;
    2061 
    2062     LogFlowFuncLeave();
    2063 }
    2064 
    2065 /**
    2066  * Constructs an audio driver instance.
    2067  *
    2068  * @copydoc FNPDMDRVCONSTRUCT
    2069  */
    2070 static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
    2071 {
    2072     LogFlowFunc(("pDrvIns=%#p, pCfgHandle=%#p, fFlags=%x\n", pDrvIns, pCfgHandle, fFlags));
    2073 
    2074     PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
    2075     PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
    20761600
    20771601    /*
     
    20951619    pThis->IAudioConnector.pfnStreamSetVolume   = drvAudioStreamSetVolume;
    20961620    pThis->IAudioConnector.pfnStreamPlay        = drvAudioStreamPlay;
     1621    pThis->IAudioConnector.pfnStreamCapture     = drvAudioStreamCapture;
    20971622#ifdef VBOX_WITH_AUDIO_CALLBACKS
    20981623    pThis->IAudioConnector.pfnRegisterCallbacks = drvAudioRegisterCallbacks;
     
    21451670    int rc2 = RTCritSectEnter(&pThis->CritSect);
    21461671    AssertRC(rc2);
     1672
     1673    PPDMAUDIOSTREAM pStream, pStreamNext;
     1674    RTListForEachSafe(&pThis->lstHstStreams, pStream, pStreamNext, PDMAUDIOSTREAM, Node)
     1675        drvAudioStreamDestroyInternal(pThis, pStream);
     1676
     1677    RTListForEachSafe(&pThis->lstGstStreams, pStream, pStreamNext, PDMAUDIOSTREAM, Node)
     1678        drvAudioStreamDestroyInternal(pThis, pStream);
    21471679
    21481680    /*
  • trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp

    r61332 r61523  
    9494    void               *pvBuf;
    9595    size_t              cbBuf;
     96    /** Minimum samples required for ALSA to play data. */
     97    uint32_t            cSamplesMin;
    9698} ALSAAUDIOSTREAMOUT, *PALSAAUDIOSTREAMOUT;
    9799
     
    171173typedef struct ALSAAUDIOSTREAMCFG
    172174{
    173     unsigned int freq;
    174     snd_pcm_format_t fmt;
    175     int nchannels;
    176     unsigned long buffer_size;
    177     unsigned long period_size;
    178     snd_pcm_uframes_t samples;
     175    unsigned int        freq;
     176    /** PCM sound format. */
     177    snd_pcm_format_t    fmt;
     178    /** PCM data access type. */
     179    snd_pcm_access_t    access;
     180    /** Whether resampling should be performed by alsalib or not. */
     181    int                 resample;
     182    int                 nchannels;
     183    unsigned long       buffer_size;
     184    unsigned long       period_size;
     185    snd_pcm_uframes_t   samples;
    179186} ALSAAUDIOSTREAMCFG, *PALSAAUDIOSTREAMCFG;
    180187
     
    348355        }
    349356
     357        err = snd_pcm_sw_params_set_avail_min(phPCM, pSWParms, 512);
     358        if (err < 0)
     359        {
     360            LogRel(("ALSA: Failed to set available minimum to %ld: %s\n",
     361                    threshold, snd_strerror(err)));
     362            rc = VERR_ACCESS_DENIED;
     363            break;
     364        }
     365
    350366        err = snd_pcm_sw_params(phPCM, pSWParms);
    351367        if (err < 0)
     
    385401    return rc;
    386402}
     403
     404#if 0 /* After Beta. */
     405static int alsaSetHWParams(snd_pcm_t *phPCM, PALSAAUDIOSTREAMCFG pCfg)
     406{
     407    int rc;
     408    snd_pcm_hw_params_t *pParams = NULL;
     409
     410    do
     411    {
     412        snd_pcm_hw_params_alloca(&pParams);
     413        if (!pParams)
     414        {
     415            rc = VERR_NO_MEMORY;
     416            break;
     417        }
     418
     419        unsigned int rrate;
     420        snd_pcm_uframes_t size;
     421        int dir;
     422
     423        /* choose all parameters */
     424        int err = snd_pcm_hw_params_any(phPCM, pParams);
     425        if (err < 0)
     426        {
     427            LogRel(("ALSA: Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)));
     428            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     429            break;
     430        }
     431        /* set hardware resampling */
     432        err = snd_pcm_hw_params_set_rate_resample(phPCM, pParams, pCfg->resample);
     433        if (err < 0)
     434        {
     435            LogRel(("ALSA: Resampling setup failed for playback: %s\n", snd_strerror(err)));
     436            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     437            break;
     438        }
     439        /* set the interleaved read/write format */
     440        err = snd_pcm_hw_params_set_access(phPCM, pParams, pCfg->access);
     441        if (err < 0)
     442        {
     443            LogRel(("ALSA: Access type not available for playback: %s\n", snd_strerror(err)));
     444            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     445            break;
     446        }
     447        /* set the sample format */
     448        err = snd_pcm_hw_params_set_format(phPCM, pParams, pCfg->fmt);
     449        if (err < 0)
     450        {
     451            LogRel(("ALSA: Sample format not available for playback: %s\n", snd_strerror(err)));
     452            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     453            break;
     454        }
     455        /* set the count of channels */
     456        err = snd_pcm_hw_params_set_channels(phPCM, pParams, pCfg->nchannels);
     457        if (err < 0)
     458        {
     459            LogRel(("ALSA: Channels count (%d) not available for playbacks: %s\n", pCfg->nchannels, snd_strerror(err)));
     460            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     461            break;
     462        }
     463        /* set the stream rate */
     464        rrate = pCfg->freq;
     465        err = snd_pcm_hw_params_set_rate_near(phPCM, pParams, &rrate, 0);
     466        if (err < 0)
     467        {
     468            LogRel(("ALSA: Rate %uHz not available for playback: %s\n", pCfg->freq, snd_strerror(err)));
     469            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     470            break;
     471        }
     472        if (rrate != pCfg->freq)
     473        {
     474            LogRel(("ALSA: Rate doesn't match (requested %iHz, get %uHz)\n", pCfg->freq, err));
     475            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     476            break;
     477        }
     478        /* set the buffer time */
     479        err = snd_pcm_hw_params_set_buffer_time_near(phPCM, pParams, &pCfg->buffer_time, &dir);
     480        if (err < 0)
     481        {
     482            LogRel(("ALSA: Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err)));
     483            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     484            break;
     485        }
     486        err = snd_pcm_hw_params_get_buffer_size(pParams, &size);
     487        if (err < 0)
     488        {
     489            LogRel(("ALSA: Unable to get buffer size for playback: %s\n", snd_strerror(err)));
     490            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     491            break;
     492        }
     493        buffer_size = size;
     494        /* set the period time */
     495        err = snd_pcm_hw_params_set_period_time_near(phPCM, pParams, &period_time, &dir);
     496        if (err < 0)
     497        {
     498            LogRel(("ALSA: Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err)));
     499            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     500            break;
     501        }
     502        err = snd_pcm_hw_params_get_period_size(pParams, &size, &dir);
     503        if (err < 0)
     504        {
     505            LogRel(("ALSA: Unable to get period size for playback: %s\n", snd_strerror(err)));
     506            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     507            break;
     508        }
     509        period_size = size;
     510        /* write the parameters to device */
     511        err = snd_pcm_hw_params(phPCM, pParams);
     512        if (err < 0)
     513        {
     514            LogRel(("ALSA: Unable to set hw params for playback: %s\n", snd_strerror(err)));
     515            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     516            break;
     517        }
     518
     519        rc = VINF_SUCCESS;
     520
     521    } while (0);
     522
     523    if (pParams)
     524    {
     525        snd_pcm_hw_params_free(pParams);
     526        pParams = NULL;
     527    }
     528
     529    LogFlowFuncLeaveRC(rc);
     530    return rc;
     531}
     532static int alsaSetSWParams(snd_pcm_t *phPCM, PALSAAUDIOCFG pCfg)
     533{
     534    int rc;
     535    snd_pcm_sw_params_t *pParams = NULL;
     536
     537    do
     538    {
     539        snd_pcm_sw_params_alloca(&pParams);
     540        if (!pParams)
     541        {
     542            rc = VERR_NO_MEMORY;
     543            break;
     544        }
     545        /* get the current swparams */
     546        int err = snd_pcm_sw_params_current(phPCM, pParams);
     547        if (err < 0)
     548        {
     549            LogRel(("ALSA: Unable to determine current swparams for playback: %s\n", snd_strerror(err)));
     550            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     551            break;
     552        }
     553        /* start the transfer when the buffer is almost full: */
     554        /* (buffer_size / avail_min) * avail_min */
     555        err = snd_pcm_sw_params_set_start_threshold(phPCM, pParams, (buffer_size / period_size) * period_size);
     556        if (err < 0)
     557        {
     558            LogRel(("ALSA: Unable to set start threshold mode for playback: %s\n", snd_strerror(err)));
     559            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     560            break;
     561        }
     562        /* allow the transfer when at least period_size samples can be processed */
     563        /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
     564        err = snd_pcm_sw_params_set_avail_min(phPCM, pParams, period_size);
     565        if (err < 0)
     566        {
     567            LogRel(("ALSA: Unable to set avail min for playback: %s\n", snd_strerror(err)));
     568            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     569            break;
     570        }
     571        /* write the parameters to the playback device */
     572        err = snd_pcm_sw_params(phPCM, pParams);
     573        if (err < 0)
     574        {
     575            LogRel(("ALSA: Unable to set sw params for playback: %s\n", snd_strerror(err)));
     576            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
     577            break;
     578        }
     579
     580        rc = VINF_SUCCESS;
     581
     582    } while (0);
     583
     584    if (pParams)
     585    {
     586        snd_pcm_sw_params_free(pParams);
     587        pParams = NULL;
     588    }
     589
     590    LogFlowFuncLeaveRC(rc);
     591    return rc;
     592}
     593#endif
    387594
    388595static int alsaStreamOpen(bool fIn, PALSAAUDIOSTREAMCFG pCfgReq, PALSAAUDIOSTREAMCFG pCfgObt, snd_pcm_t **pphPCM)
     
    614821        }
    615822
     823        LogFunc(("Buffer sample size is: %RU32\n", obt_buffer_size));
     824
    616825        snd_pcm_uframes_t obt_period_size;
    617826        int dir = 0;
     
    9831192                        case 0:
    9841193                        {
    985                             LogFunc(("Failed to write %RI32 frames\n", cRead));
     1194                            LogFunc(("Failed to write %RU32 samples\n", cRead));
    9861195                            rc = VERR_ACCESS_DENIED;
    9871196                            break;
     
    11491358
    11501359        if (pcSamples)
    1151             *pcSamples = obt.samples;
     1360            *pcSamples = obt.samples * 4;
    11521361    }
    11531362    while (0);
     
    14451654        snd_pcm_sframes_t cAvail;
    14461655        int rc2 = alsaStreamGetAvail(pStreamOut->phPCM, &cAvail);
    1447         if (   RT_SUCCESS(rc2)
    1448             && cAvail >= 1024) /** @todo !!! HACK ALERT !!! Use bufsize. */
     1656        if (RT_SUCCESS(rc2))
    14491657        {
    14501658            LogFlowFunc(("cAvail=%ld\n", cAvail));
    1451             strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
     1659            if (cAvail >= pStreamOut->cSamplesMin)
     1660                strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
    14521661        }
    14531662    }
  • trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp

    r61386 r61523  
    14171417                             | PDMAUDIOSTRMSTS_FLAG_ENABLED;
    14181418
     1419    pa_threaded_mainloop_lock(pThis->pMainLoop);
     1420
    14191421    pa_context_state_t ctxState = pa_context_get_state(pThis->pContext);
    14201422
     
    14221424        && pa_stream_get_state(pStrm->pPAStream) == PA_STREAM_READY)
    14231425    {
     1426        size_t cbSize;
     1427
    14241428        if (pStream->enmDir == PDMAUDIODIR_IN)
    14251429        {
    1426 
     1430            cbSize = pa_stream_readable_size(pStrm->pPAStream);
     1431
     1432            if (cbSize)
     1433                strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_READABLE;
    14271434        }
    14281435        else
    14291436        {
    1430             size_t cbSize = pa_stream_writable_size(pStrm->pPAStream);
    1431             LogFlowFunc(("cbSize=%zu\n", cbSize));
     1437            cbSize = pa_stream_writable_size(pStrm->pPAStream);
    14321438
    14331439            if (cbSize >= pStrm->BufAttr.minreq)
    1434             {
    14351440                strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
    1436             }
    1437         }
    1438     }
     1441        }
     1442
     1443        LogFlowFunc(("cbSize=%zu\n", cbSize));
     1444    }
     1445
     1446    pa_threaded_mainloop_unlock(pThis->pMainLoop);
    14391447
    14401448    return strmSts;
  • trunk/src/VBox/Devices/Audio/alsa_mangling.h

    r59987 r61523  
    5656#define snd_pcm_sw_params_current               ALSA_MANGLER(snd_pcm_sw_params_current)
    5757#define snd_pcm_sw_params_set_start_threshold   ALSA_MANGLER(snd_pcm_sw_params_set_start_threshold)
     58#define snd_pcm_sw_params_set_avail_min         ALSA_MANGLER(snd_pcm_sw_params_set_avail_min)
    5859
    5960#endif /* !AUDIO_ALSA_MANGLING_H */
  • trunk/src/VBox/Devices/Audio/alsa_stubs.c

    r59987 r61523  
    116116           (pcm, params))
    117117PROXY_STUB(snd_pcm_sw_params_set_start_threshold, int,
     118           (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val),
     119           (pcm, params, val))
     120PROXY_STUB(snd_pcm_sw_params_set_avail_min, int,
    118121           (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val),
    119122           (pcm, params, val))
     
    162165    ELEMENT(snd_pcm_sw_params_current),
    163166    ELEMENT(snd_pcm_sw_params_set_start_threshold),
     167    ELEMENT(snd_pcm_sw_params_set_avail_min)
    164168};
    165169#undef ELEMENT
Note: See TracChangeset for help on using the changeset viewer.

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