VirtualBox

Changeset 88942 in vbox


Ignore:
Timestamp:
May 8, 2021 11:39:11 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
144277
Message:

DevHda: Split up hdaR3StreamUpdate into Dma and AIO variants. bugref:9890

Location:
trunk/src/VBox/Devices/Audio
Files:
2 edited

Legend:

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

    r88941 r88942  
    4747*********************************************************************************************************************************/
    4848static void hdaR3StreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB);
     49static void hdaR3StreamUpdateDma(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
     50                                 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3);
    4951
    5052
     
    19081910
    19091911    /* Do the work: */
    1910     hdaR3StreamUpdate(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, true /* fInTimer */);
     1912    hdaR3StreamUpdateDma(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
    19111913
    19121914    /* Re-arm the timer if the sink is still active: */
     
    19531955
    19541956/**
    1955  * Updates a HDA stream by doing its required data transfers.
    1956  *
    1957  * The host sink(s) set the overall pace.
    1958  *
    1959  * This routine is called by both, the synchronous and the asynchronous
    1960  * implementations.
    1961  *
    1962  * When running synchronously, the device DMA transfers *and* the mixer sink
    1963  * processing is within the device timer.
    1964  *
    1965  * When running asynchronously, only the device DMA transfers are done in the
    1966  * device timer, whereas the mixer sink processing then is done in the stream's
    1967  * own async I/O thread. This thread also will call this function
    1968  * (with fInTimer set to @c false).
     1957 * Updates a HDA stream by doing DMA transfers.
     1958 *
     1959 * Will do mixer transfers too to try fix an overrun/underrun situation.
     1960 *
     1961 * The host sink(s) set the overall pace (bird: no it doesn't, the DMA timer
     1962 * does - we just hope like heck it matches the speed at which the *backend*
     1963 * host audio driver processes samples).
    19691964 *
    19701965 * @param   pDevIns         The device instance.
     
    19731968 * @param   pStreamShared   HDA stream to update (shared bits).
    19741969 * @param   pStreamR3       HDA stream to update (ring-3 bits).
    1975  * @param   fInTimer        Whether to this function was called from the timer
    1976  *                          context or an asynchronous I/O stream thread (if supported).
    1977  */
    1978 void hdaR3StreamUpdate(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
    1979                        PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fInTimer)
     1970 */
     1971static void hdaR3StreamUpdateDma(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
     1972                                 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)
    19801973{
    19811974    RT_NOREF(pThisCC);
     
    19831976
    19841977    /*
    1985      * Make sure we're running (only when on timer, as the AIO thread needs
    1986      * to properly drain the internal DMA buffer) and got an active mixer sink.
    1987      */
    1988     if (RT_LIKELY(pStreamShared->State.fRunning || !fInTimer))
     1978     * Make sure we're running and got an active mixer sink.
     1979     */
     1980    if (RT_LIKELY(pStreamShared->State.fRunning))
    19891981    { /* likely */ }
    19901982    else
     
    20122004    if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT)
    20132005    {
    2014         bool fDoRead; /* Whether to push data down the driver stack or not.  */
    2015         if (fInTimer)
     2006        /*
     2007         * Check how much room we have in our DMA buffer.  There should be at
     2008         * least one period worth of space there or we're in an overflow situation.
     2009         */
     2010        uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3);
     2011        if (cbStreamFree >= cbPeriod)
     2012        { /* likely */ }
     2013        else
    20162014        {
    2017             /*
    2018              * Check how much room we have in our DMA buffer.  There should be at
    2019              * least one period worth of space there or we're in an overflow situation.
    2020              */
    2021             uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3);
    2022             if (cbStreamFree >= cbPeriod)
    2023             { /* likely */ }
     2015            STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems);
     2016            Log(("hdaR3StreamUpdate: Warning! Stream #%u has insufficient space free: %u bytes, need %u.  Will try move data out of the buffer...\n",
     2017                 pStreamShared->u8SD, cbStreamFree, cbPeriod));
     2018            int rc = AudioMixerSinkTryLock(pSink);
     2019            if (RT_SUCCESS(rc))
     2020            {
     2021                hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, tsNowNs);
     2022                AudioMixerSinkUpdate(pSink);
     2023                AudioMixerSinkUnlock(pSink);
     2024            }
    20242025            else
     2026                RTThreadYield();
     2027            Log(("hdaR3StreamUpdate: Gained %u bytes.\n", hdaR3StreamGetFree(pStreamR3) - cbStreamFree));
     2028
     2029            cbStreamFree = hdaR3StreamGetFree(pStreamR3);
     2030            if (cbStreamFree < cbPeriod)
    20252031            {
    2026                 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems);
    2027                 Log(("hdaR3StreamUpdate: Warning! Stream #%u has insufficient space free: %u bytes, need %u.  Will try move data out of the buffer...\n",
    2028                      pStreamShared->u8SD, cbStreamFree, cbPeriod));
    2029                 int rc = AudioMixerSinkTryLock(pSink);
    2030                 if (RT_SUCCESS(rc))
    2031                 {
    2032                     hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, tsNowNs);
    2033                     AudioMixerSinkUpdate(pSink);
    2034                     AudioMixerSinkUnlock(pSink);
    2035                 }
    2036                 else
    2037                     RTThreadYield();
    2038                 Log(("hdaR3StreamUpdate: Gained %u bytes.\n", hdaR3StreamGetFree(pStreamR3) - cbStreamFree));
    2039 
     2032                /* Unable to make sufficient space.  Drop the whole buffer content.
     2033                 * This is needed in order to keep the device emulation running at a constant rate,
     2034                 * at the cost of losing valid (but too much) data. */
     2035                STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors);
     2036                LogRel2(("HDA: Warning: Hit stream #%RU8 overflow, dropping %u bytes of audio data\n",
     2037                         pStreamShared->u8SD, hdaR3StreamGetUsed(pStreamR3)));
     2038# ifdef HDA_STRICT
     2039                AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamShared->u8SD));
     2040# endif
     2041                RTCircBufReset(pStreamR3->State.pCircBuf);
     2042                pStreamR3->State.offWrite = 0;
     2043                pStreamR3->State.offRead  = 0;
    20402044                cbStreamFree = hdaR3StreamGetFree(pStreamR3);
    2041                 if (cbStreamFree < cbPeriod)
    2042                 {
    2043                     /* Unable to make sufficient space.  Drop the whole buffer content.
    2044                      * This is needed in order to keep the device emulation running at a constant rate,
    2045                      * at the cost of losing valid (but too much) data. */
    2046                     STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors);
    2047                     LogRel2(("HDA: Warning: Hit stream #%RU8 overflow, dropping %u bytes of audio data\n",
    2048                              pStreamShared->u8SD, hdaR3StreamGetUsed(pStreamR3)));
    2049 # ifdef HDA_STRICT
    2050                     AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamShared->u8SD));
    2051 # endif
    2052                     RTCircBufReset(pStreamR3->State.pCircBuf);
    2053                     pStreamR3->State.offWrite = 0;
    2054                     pStreamR3->State.offRead  = 0;
    2055                     cbStreamFree = hdaR3StreamGetFree(pStreamR3);
    2056                 }
    20572045            }
    2058 
    2059             /*
    2060              * Do the DMA transfer.
    2061              */
    2062             rc2 = PDMDevHlpCritSectEnter(pDevIns, &pStreamShared->CritSect, VERR_IGNORED);
     2046        }
     2047
     2048        /*
     2049         * Do the DMA transfer.
     2050         */
     2051        rc2 = PDMDevHlpCritSectEnter(pDevIns, &pStreamShared->CritSect, VERR_IGNORED);
     2052        AssertRC(rc2);
     2053
     2054        uint64_t const offWriteBefore = pStreamR3->State.offWrite;
     2055        hdaR3StreamDoDmaOutput(pDevIns, pThis, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs);
     2056
     2057        rc2 = PDMDevHlpCritSectLeave(pDevIns, &pStreamShared->CritSect);
     2058        AssertRC(rc2);
     2059
     2060        /*
     2061         * Should we push data to down thru the mixer to and to the host drivers?
     2062         *
     2063         * We initially delay this by pThis->msInitialDelay, but after than we'll
     2064         * kick the AIO thread every time we've put more data in the buffer (which is
     2065         * every time) as the host audio device needs to get data in a timely manner.
     2066         *
     2067         * (We used to try only wake up the AIO thread according to pThis->uIoTimer
     2068         * and host wall clock, but that meant we would miss a wakup after the DMA
     2069         * timer was called a little late or if TM entered into catch-up mode.)
     2070         */
     2071        bool fKickAioThread;
     2072        if (!pStreamShared->State.tsAioDelayEnd)
     2073            fKickAioThread = pStreamR3->State.offWrite > offWriteBefore
     2074                          || hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbAvgTransfer * 2;
     2075        else if (PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer) >= pStreamShared->State.tsAioDelayEnd)
     2076        {
     2077            Log3Func(("Initial delay done: Passed tsAioDelayEnd.\n"));
     2078            pStreamShared->State.tsAioDelayEnd = 0;
     2079            fKickAioThread = true;
     2080        }
     2081        else if (hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbAvgTransfer * 2)
     2082        {
     2083            Log3Func(("Initial delay done: Passed running short on buffer.\n"));
     2084            pStreamShared->State.tsAioDelayEnd = 0;
     2085            fKickAioThread = true;
     2086        }
     2087        else
     2088        {
     2089            Log3Func(("Initial delay pending...\n"));
     2090            fKickAioThread = false;
     2091        }
     2092
     2093        Log3Func(("msDelta=%RU64 (vs %u) cbStreamFree=%#x (vs %#x) => fKickAioThread=%RTbool\n",
     2094                  (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS,
     2095                  pStreamShared->State.Cfg.Device.cMsSchedulingHint, cbStreamFree,
     2096                  pStreamShared->State.cbAvgTransfer * 2, fKickAioThread));
     2097
     2098        if (fKickAioThread)
     2099        {
     2100            /* Notify the async I/O worker thread that there's work to do. */
     2101            Log5Func(("Notifying AIO thread\n"));
     2102            rc2 = AudioMixerSinkSignalUpdateJob(pSink);
    20632103            AssertRC(rc2);
    2064 
    2065             uint64_t const offWriteBefore = pStreamR3->State.offWrite;
    2066             hdaR3StreamDoDmaOutput(pDevIns, pThis, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs);
    2067 
    2068             rc2 = PDMDevHlpCritSectLeave(pDevIns, &pStreamShared->CritSect);
    2069             AssertRC(rc2);
    2070 
    2071             /*
    2072              * Should we push data to down thru the mixer to and to the host drivers?
    2073              *
    2074              * We initially delay this by pThis->msInitialDelay, but after than we'll
    2075              * kick the AIO thread every time we've put more data in the buffer (which is
    2076              * every time) as the host audio device needs to get data in a timely manner.
    2077              *
    2078              * (We used to try only wake up the AIO thread according to pThis->uIoTimer
    2079              * and host wall clock, but that meant we would miss a wakup after the DMA
    2080              * timer was called a little late or if TM entered into catch-up mode.)
    2081              */
    2082             if (!pStreamShared->State.tsAioDelayEnd)
    2083                 fDoRead = pStreamR3->State.offWrite > offWriteBefore
    2084                        || hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbAvgTransfer * 2;
    2085             else if (PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer) >= pStreamShared->State.tsAioDelayEnd)
     2104            /* Update last read timestamp for logging/debugging. */
     2105            pStreamShared->State.tsLastReadNs = tsNowNs;
     2106        }
     2107    }
     2108    /*
     2109     * Input stream (SDI).
     2110     */
     2111    else
     2112    {
     2113        Assert(hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_IN);
     2114
     2115        /*
     2116         * See how much data we've got buffered...
     2117         */
     2118        bool     fWriteSilence = false;
     2119        uint32_t cbStreamUsed  = hdaR3StreamGetUsed(pStreamR3);
     2120        if (pStreamShared->State.fInputPreBuffered && cbStreamUsed >= cbPeriod)
     2121        { /*likely*/ }
     2122        /*
     2123         * Because it may take a while for the input stream to get going (at
     2124         * least with pulseaudio), we feed the guest silence till we've
     2125         * pre-buffer a reasonable amount of audio.
     2126         */
     2127        else if (!pStreamShared->State.fInputPreBuffered)
     2128        {
     2129            if (cbStreamUsed < pStreamShared->State.cbInputPreBuffer)
    20862130            {
    2087                 Log3Func(("Initial delay done: Passed tsAioDelayEnd.\n"));
    2088                 pStreamShared->State.tsAioDelayEnd = 0;
    2089                 fDoRead = true;
    2090             }
    2091             else if (hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbAvgTransfer * 2)
    2092             {
    2093                 Log3Func(("Initial delay done: Passed running short on buffer.\n"));
    2094                 pStreamShared->State.tsAioDelayEnd = 0;
    2095                 fDoRead = true;
     2131                Log3(("hdaR3StreamUpdate: Pre-buffering (got %#x out of %#x bytes)...\n",
     2132                      cbStreamUsed, pStreamShared->State.cbInputPreBuffer));
     2133                fWriteSilence = true;
    20962134            }
    20972135            else
    20982136            {
    2099                 Log3Func(("Initial delay pending...\n"));
    2100                 fDoRead = false;
     2137                Log3(("hdaR3StreamUpdate: Completed pre-buffering (got %#x, needed %#x bytes).\n",
     2138                      cbStreamUsed, pStreamShared->State.cbInputPreBuffer));
     2139                pStreamShared->State.fInputPreBuffered = true;
     2140                fWriteSilence = true; /* For now, just do the most conservative thing. */
    21012141            }
    2102 
    2103             Log3Func(("msDelta=%RU64 (vs %u) cbStreamFree=%#x (vs %#x) => fDoRead=%RTbool\n",
    2104                       (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS,
    2105                       pStreamShared->State.Cfg.Device.cMsSchedulingHint, cbStreamFree,
    2106                       pStreamShared->State.cbAvgTransfer * 2, fDoRead));
    2107 
    2108             if (fDoRead)
     2142            cbStreamUsed = cbPeriod;
     2143        }
     2144        /*
     2145         * When we're low on data, we must really try fetch some ourselves
     2146         * as buffer underruns must not happen.
     2147         */
     2148        else
     2149        {
     2150            /** @todo We're ending up here to frequently with pulse audio at least (just
     2151             *        watch the stream stats in the statistcs viewer, and way to often we
     2152             *        have to inject silence bytes.  I suspect part of the problem is
     2153             *        that the HDA device require a much better latency than what the
     2154             *        pulse audio is configured for by default (10 ms vs 150ms). */
     2155            STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems);
     2156            Log(("hdaR3StreamUpdate: Warning! Stream #%u has insufficient data available: %u bytes, need %u.  Will try move pull more data into the buffer...\n",
     2157                 pStreamShared->u8SD, cbStreamUsed, cbPeriod));
     2158            int rc = AudioMixerSinkTryLock(pSink);
     2159            if (RT_SUCCESS(rc))
    21092160            {
    2110                 /* Notify the async I/O worker thread that there's work to do. */
    2111                 Log5Func(("Notifying AIO thread\n"));
    2112                 rc2 = AudioMixerSinkSignalUpdateJob(pSink);
    2113                 AssertRC(rc2);
    2114                 /* Update last read timestamp for logging/debugging. */
    2115                 pStreamShared->State.tsLastReadNs = tsNowNs;
     2161                AudioMixerSinkUpdate(pSink);
     2162                hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink);
     2163                AudioMixerSinkUnlock(pSink);
     2164            }
     2165            else
     2166                RTThreadYield();
     2167            Log(("hdaR3StreamUpdate: Gained %u bytes.\n", hdaR3StreamGetUsed(pStreamR3) - cbStreamUsed));
     2168            cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
     2169            if (cbStreamUsed < cbPeriod)
     2170            {
     2171                /* Unable to find sufficient input data by simple prodding.
     2172                   In order to keep a constant byte stream following thru the DMA
     2173                   engine into the guest, we will try again and then fall back on
     2174                   filling the gap with silence. */
     2175                uint32_t cbSilence = 0;
     2176                do
     2177                {
     2178                    AudioMixerSinkLock(pSink);
     2179
     2180                    cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
     2181                    if (cbStreamUsed < cbPeriod)
     2182                    {
     2183                        hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink);
     2184                        cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
     2185                        while (cbStreamUsed < cbPeriod)
     2186                        {
     2187                            void  *pvDstBuf;
     2188                            size_t cbDstBuf;
     2189                            RTCircBufAcquireWriteBlock(pStreamR3->State.pCircBuf, cbPeriod - cbStreamUsed,
     2190                                                       &pvDstBuf, &cbDstBuf);
     2191                            RT_BZERO(pvDstBuf, cbDstBuf);
     2192                            RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbDstBuf);
     2193                            cbSilence    += (uint32_t)cbDstBuf;
     2194                            cbStreamUsed += (uint32_t)cbDstBuf;
     2195                        }
     2196                    }
     2197
     2198                    AudioMixerSinkUnlock(pSink);
     2199                } while (cbStreamUsed < cbPeriod);
     2200                if (cbSilence > 0)
     2201                {
     2202                    STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors);
     2203                    STAM_REL_COUNTER_ADD(&pStreamR3->State.StatDmaFlowErrorBytes, cbSilence);
     2204                    LogRel2(("HDA: Warning: Stream #%RU8 underrun, added %u bytes of silence (%u us)\n", pStreamShared->u8SD,
     2205                             cbSilence, PDMAudioPropsBytesToMicro(&pStreamR3->State.Mapping.GuestProps, cbSilence)));
     2206                }
    21162207            }
    21172208        }
    21182209
    21192210        /*
    2120          * Move data out of the pStreamR3->State.pCircBuf buffer and to
    2121          * the mixer and in direction of the host audio devices.
     2211         * Do the DMA'ing.
    21222212         */
    2123         else
    2124             hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, tsNowNs);
    2125     }
    2126     /*
    2127      * Input stream (SDI).
    2128      */
    2129     else
    2130     {
    2131         Assert(hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_IN);
     2213        if (cbStreamUsed)
     2214        {
     2215            rc2 = PDMDevHlpCritSectEnter(pDevIns, &pStreamShared->CritSect, VERR_IGNORED);
     2216            AssertRC(rc2);
     2217
     2218            hdaR3StreamDoDmaInput(pDevIns, pThis, pStreamShared, pStreamR3,
     2219                                  RT_MIN(cbStreamUsed, cbPeriod), fWriteSilence, tsNowNs);
     2220
     2221            rc2 = PDMDevHlpCritSectLeave(pDevIns, &pStreamShared->CritSect);
     2222            AssertRC(rc2);
     2223        }
    21322224
    21332225        /*
    2134          * If we're the async I/O worker, or not using AIO, pull bytes
    2135          * from the mixer and into our internal DMA buffer.
     2226         * We should always kick the AIO thread.
    21362227         */
    2137         if (!fInTimer)
    2138             hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink);
    2139         else
    2140         {
    2141             /*
    2142              * See how much data we've got buffered...
    2143              */
    2144             bool     fWriteSilence = false;
    2145             uint32_t cbStreamUsed  = hdaR3StreamGetUsed(pStreamR3);
    2146             if (pStreamShared->State.fInputPreBuffered && cbStreamUsed >= cbPeriod)
    2147             { /*likely*/ }
    2148             /*
    2149              * Because it may take a while for the input stream to get going (at
    2150              * least with pulseaudio), we feed the guest silence till we've
    2151              * pre-buffer a reasonable amount of audio.
    2152              */
    2153             else if (!pStreamShared->State.fInputPreBuffered)
    2154             {
    2155                 if (cbStreamUsed < pStreamShared->State.cbInputPreBuffer)
    2156                 {
    2157                     Log3(("hdaR3StreamUpdate: Pre-buffering (got %#x out of %#x bytes)...\n",
    2158                           cbStreamUsed, pStreamShared->State.cbInputPreBuffer));
    2159                     fWriteSilence = true;
    2160                 }
    2161                 else
    2162                 {
    2163                     Log3(("hdaR3StreamUpdate: Completed pre-buffering (got %#x, needed %#x bytes).\n",
    2164                           cbStreamUsed, pStreamShared->State.cbInputPreBuffer));
    2165                     pStreamShared->State.fInputPreBuffered = true;
    2166                     fWriteSilence = true; /* For now, just do the most conservative thing. */
    2167                 }
    2168                 cbStreamUsed = cbPeriod;
    2169             }
    2170             /*
    2171              * When we're low on data, we must really try fetch some ourselves
    2172              * as buffer underruns must not happen.
    2173              */
    2174             else
    2175             {
    2176                 /** @todo We're ending up here to frequently with pulse audio at least (just
    2177                  *        watch the stream stats in the statistcs viewer, and way to often we
    2178                  *        have to inject silence bytes.  I suspect part of the problem is
    2179                  *        that the HDA device require a much better latency than what the
    2180                  *        pulse audio is configured for by default (10 ms vs 150ms). */
    2181                 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems);
    2182                 Log(("hdaR3StreamUpdate: Warning! Stream #%u has insufficient data available: %u bytes, need %u.  Will try move pull more data into the buffer...\n",
    2183                      pStreamShared->u8SD, cbStreamUsed, cbPeriod));
    2184                 int rc = AudioMixerSinkTryLock(pSink);
    2185                 if (RT_SUCCESS(rc))
    2186                 {
    2187                     AudioMixerSinkUpdate(pSink);
    2188                     hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink);
    2189                     AudioMixerSinkUnlock(pSink);
    2190                 }
    2191                 else
    2192                     RTThreadYield();
    2193                 Log(("hdaR3StreamUpdate: Gained %u bytes.\n", hdaR3StreamGetUsed(pStreamR3) - cbStreamUsed));
    2194                 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
    2195                 if (cbStreamUsed < cbPeriod)
    2196                 {
    2197                     /* Unable to find sufficient input data by simple prodding.
    2198                        In order to keep a constant byte stream following thru the DMA
    2199                        engine into the guest, we will try again and then fall back on
    2200                        filling the gap with silence. */
    2201                     uint32_t cbSilence = 0;
    2202                     do
    2203                     {
    2204                         AudioMixerSinkLock(pSink);
    2205 
    2206                         cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
    2207                         if (cbStreamUsed < cbPeriod)
    2208                         {
    2209                             hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink);
    2210                             cbStreamUsed = hdaR3StreamGetUsed(pStreamR3);
    2211                             while (cbStreamUsed < cbPeriod)
    2212                             {
    2213                                 void  *pvDstBuf;
    2214                                 size_t cbDstBuf;
    2215                                 RTCircBufAcquireWriteBlock(pStreamR3->State.pCircBuf, cbPeriod - cbStreamUsed,
    2216                                                            &pvDstBuf, &cbDstBuf);
    2217                                 RT_BZERO(pvDstBuf, cbDstBuf);
    2218                                 RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbDstBuf);
    2219                                 cbSilence    += (uint32_t)cbDstBuf;
    2220                                 cbStreamUsed += (uint32_t)cbDstBuf;
    2221                             }
    2222                         }
    2223 
    2224                         AudioMixerSinkUnlock(pSink);
    2225                     } while (cbStreamUsed < cbPeriod);
    2226                     if (cbSilence > 0)
    2227                     {
    2228                         STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors);
    2229                         STAM_REL_COUNTER_ADD(&pStreamR3->State.StatDmaFlowErrorBytes, cbSilence);
    2230                         LogRel2(("HDA: Warning: Stream #%RU8 underrun, added %u bytes of silence (%u us)\n", pStreamShared->u8SD,
    2231                                  cbSilence, PDMAudioPropsBytesToMicro(&pStreamR3->State.Mapping.GuestProps, cbSilence)));
    2232                     }
    2233                 }
    2234             }
    2235 
    2236             /*
    2237              * Do the DMA'ing.
    2238              */
    2239             if (cbStreamUsed)
    2240             {
    2241                 rc2 = PDMDevHlpCritSectEnter(pDevIns, &pStreamShared->CritSect, VERR_IGNORED);
    2242                 AssertRC(rc2);
    2243 
    2244                 hdaR3StreamDoDmaInput(pDevIns, pThis, pStreamShared, pStreamR3,
    2245                                       RT_MIN(cbStreamUsed, cbPeriod), fWriteSilence, tsNowNs);
    2246 
    2247                 rc2 = PDMDevHlpCritSectLeave(pDevIns, &pStreamShared->CritSect);
    2248                 AssertRC(rc2);
    2249             }
    2250 
    2251             /*
    2252              * We should always kick the AIO thread.
    2253              */
    2254             /** @todo This isn't entirely ideal.  If we get into an underrun situation,
    2255              *        we ideally want the AIO thread to run right before the DMA timer
    2256              *        rather than right after it ran. */
    2257             Log5Func(("Notifying AIO thread\n"));
    2258             rc2 = AudioMixerSinkSignalUpdateJob(pSink);
    2259             AssertRC(rc2);
    2260             pStreamShared->State.tsLastReadNs = tsNowNs;
    2261         }
    2262     }
    2263 }
    2264 
    2265 
    2266 /**
    2267  * @callback_method_impl{FNRTTHREAD,
    2268  * Asynchronous I/O thread for a HDA stream.
    2269  *
    2270  * This will do the heavy lifting work for us as soon as it's getting notified
    2271  * by the DMA timer callout.}
     2228        /** @todo This isn't entirely ideal.  If we get into an underrun situation,
     2229         *        we ideally want the AIO thread to run right before the DMA timer
     2230         *        rather than right after it ran. */
     2231        Log5Func(("Notifying AIO thread\n"));
     2232        rc2 = AudioMixerSinkSignalUpdateJob(pSink);
     2233        AssertRC(rc2);
     2234        pStreamShared->State.tsLastReadNs = tsNowNs;
     2235    }
     2236}
     2237
     2238
     2239/**
     2240 * @callback_method_impl{FNRTTHREAD, Asynchronous I/O thread for a HDA stream.}
     2241 *
     2242 * For output streams this moves data from the internal DMA buffer (in which
     2243 * hdaR3StreamUpdateDma put it), thru the mixer and to the various backend audio
     2244 * devices.
     2245 *
     2246 * For input streams this pulls data from the backend audio device(s), thru the
     2247 * mixer and puts it in the internal DMA buffer ready for hdaR3StreamUpdateDma
     2248 * to pump into guest memory.
    22722249 */
    22732250DECLCALLBACK(void) hdaR3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser)
     
    22812258    RT_NOREF(pSink);
    22822259
    2283     hdaR3StreamUpdate(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, false /* fInTimer */);
     2260    /*
     2261     * Make sure we haven't change sink and that it's still active (it
     2262     * should be or we wouldn't have been called).
     2263     */
     2264    AssertReturnVoid(pStreamR3->pMixSink && pSink == pStreamR3->pMixSink->pMixSink);
     2265    AssertReturnVoid(AudioMixerSinkIsActive(pSink));
     2266
     2267    /*
     2268     * Output streams (SDO).
     2269     */
     2270    if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT)
     2271        hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, RTTimeNanoTS());
     2272    /*
     2273     * Input stream (SDI).
     2274     */
     2275    else
     2276    {
     2277        Assert(hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_IN);
     2278        hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink);
     2279    }
    22842280}
    22852281
  • trunk/src/VBox/Devices/Audio/DevHdaStream.h

    r88941 r88942  
    343343uint64_t            hdaR3StreamTimerMain(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
    344344                                         PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3);
    345 void                hdaR3StreamUpdate(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
    346                                       PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fInTimer);
    347345DECLCALLBACK(void)  hdaR3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser);
    348346PHDASTREAM          hdaR3StreamR3ToShared(PHDASTREAMR3 pStreamCC);
Note: See TracChangeset for help on using the changeset viewer.

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