VirtualBox

Changeset 88094 in vbox


Ignore:
Timestamp:
Mar 11, 2021 3:00:17 PM (4 years ago)
Author:
vboxsync
Message:

DevHDA: Made the timer thread do something proactive if the internal DMA buffer has insufficient free space. Expose more stream stuff via stats. bugref:9890

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

Legend:

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

    r88077 r88094  
    51805180
    51815181    for (uint8_t idxStream = 0; idxStream < RT_ELEMENTS(pThisCC->aStreams); idxStream++)
     5182    {
     5183        PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowProblems, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
     5184                               "Number of internal DMA buffer problems.",   "Stream%u/DMABufferProblems", idxStream);
    51825185        if (hdaGetDirFromSD(idxStream) == PDMAUDIODIR_OUT)
    51835186            PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
    5184                                    "Number of DMA overflows.",  "Stream%u/DMAOverflows", idxStream);
     5187                                   "Number of internal DMA buffer overflows.",  "Stream%u/DMABufferOverflows", idxStream);
    51855188        else
    51865189            PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
    5187                                    "Number of DMA underflows.", "Stream%u/DMAUnderflows", idxStream);
     5190                                   "Number of internal DMA buffer underuns.", "Stream%u/DMABufferUnderruns", idxStream);
     5191        PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.offRead, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
     5192                               "Virtual internal buffer read position.",    "Stream%u/offRead", idxStream);
     5193        PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.offWrite, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
     5194                               "Virtual internal buffer write position.",   "Stream%u/offWrite", idxStream);
     5195        PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.cbTransferSize, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
     5196                               "Bytes transfered per DMA timer callout.",   "Stream%u/cbTransferSize", idxStream);
     5197        PDMDevHlpSTAMRegisterF(pDevIns, (void*)&pThis->aStreams[idxStream].State.fRunning, STAMTYPE_BOOL, STAMVISIBILITY_USED, STAMUNIT_BYTES,
     5198                               "True if the stream is in RUN mode.",        "Stream%u/fRunning", idxStream);
     5199        PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.uHz, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
     5200                               "The stream frequency.",                     "Stream%u/Cfg/Hz", idxStream);
     5201        PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cChannels, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
     5202                               "The number of channels.",                   "Stream%u/Cfg/Channels", idxStream);
     5203        PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cbSample, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
     5204                               "The size of a sample (per channel).",       "Stream%u/Cfg/cbSample", idxStream);
     5205    }
    51885206
    51895207    return VINF_SUCCESS;
  • trunk/src/VBox/Devices/Audio/HDAStream.cpp

    r88080 r88094  
    11781178    else
    11791179    {
     1180        Assert(hdaGetDirFromSD(uSD) != PDMAUDIODIR_OUT /* Handled by caller */);
    11801181        /** @todo account for this or something so we can try get back in sync
    11811182         *        later... */
     
    16871688
    16881689/**
     1690 * Output streams: Pushes data from to the mixer and host device.
     1691 *
     1692 * @param   pStreamShared   HDA stream to update (shared bits).
     1693 * @param   pStreamR3       HDA stream to update (ring-3 bits).
     1694 * @param   pSink           The mixer sink to push to.
     1695 * @param   nsNow           The current RTTimeNanoTS() value.
     1696 */
     1697static void hdaR3StreamPushToMixer(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, PAUDMIXSINK pSink, uint64_t nsNow)
     1698{
     1699    uint32_t const cbSinkWritable     = AudioMixerSinkGetWritable(pSink);
     1700    uint32_t const cbStreamReadable   = hdaR3StreamGetUsed(pStreamR3);
     1701    uint32_t       cbToReadFromStream = RT_MIN(cbStreamReadable, cbSinkWritable);
     1702    /* Make sure that we always align the number of bytes when reading to the stream's PCM properties. */
     1703    cbToReadFromStream = PDMAudioPropsFloorBytesToFrame(&pStreamR3->State.Mapping.PCMProps, cbToReadFromStream);
     1704
     1705    Assert(nsNow >= pStreamShared->State.tsLastReadNs);
     1706    Log3Func(("[SD%RU8] msDeltaLastRead=%RI64\n",
     1707              pStreamShared->u8SD, (nsNow - pStreamShared->State.tsLastReadNs) / RT_NS_1MS));
     1708    Log3Func(("[SD%RU8] cbSinkWritable=%RU32, cbStreamReadable=%RU32 -> cbToReadFromStream=%RU32\n",
     1709              pStreamShared->u8SD, cbSinkWritable, cbStreamReadable, cbToReadFromStream));
     1710
     1711    if (cbToReadFromStream)
     1712    {
     1713        /* Read (guest output) data and write it to the stream's sink. */
     1714        int rc2 = hdaR3StreamRead(pStreamR3, cbToReadFromStream, NULL /* pcbRead */);
     1715        AssertRC(rc2);
     1716    }
     1717
     1718    /* When running synchronously, update the associated sink here.
     1719     * Otherwise this will be done in the async I/O thread. */
     1720    int rc2 = AudioMixerSinkUpdate(pSink);
     1721    AssertRC(rc2);
     1722}
     1723
     1724/**
    16891725 * The stream's main function when called by the timer.
    16901726 *
     
    17701806    if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */
    17711807    {
    1772         /*
    1773          * Do DMA work.
    1774          */
    1775         bool fDoRead = false; /* Whether to push data down the driver stack or not.  */
     1808        bool fDoRead; /* Whether to push data down the driver stack or not.  */
    17761809# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    17771810        if (fInTimer)
    17781811# endif
    17791812        {
     1813            /*
     1814             * Check how much room we have in our DMA buffer.  There should be at
     1815             * least one period worth of space there or we're in an overflow situation.
     1816             */
    17801817            uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3);
    1781             if (cbStreamFree)
     1818            if (cbStreamFree >= pStreamShared->State.cbTransferSize)
    17821819            { /* likely */ }
    17831820            else
    17841821            {
    1785                 LogRel2(("HDA: Warning: Hit stream #%RU8 overflow, dropping audio data\n", pStreamShared->u8SD));
     1822                STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems);
     1823                Log(("hdaR3StreamUpdate: Warning! Stream #%u has insufficient space free: %u bytes, need %u.  Will try move data out of the buffer...\n",
     1824                     pStreamShared->u8SD, cbStreamFree, pStreamShared->State.cbTransferSize));
     1825# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     1826                int rc = RTCritSectTryEnter(&pStreamR3->State.AIO.CritSect);
     1827                if (RT_SUCCESS(rc))
     1828                {
     1829                    hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, tsNowNs);
     1830                    RTCritSectLeave(&pStreamR3->State.AIO.CritSect);
     1831                }
     1832                else
     1833                    RTThreadYield();
     1834#else
     1835                hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, tsNowNs);
     1836#endif
     1837                Log(("hdaR3StreamUpdate: Gained %u bytes.\n", hdaR3StreamGetFree(pStreamR3) - cbStreamFree));
     1838
     1839                cbStreamFree = hdaR3StreamGetFree(pStreamR3);
     1840                if (cbStreamFree < pStreamShared->State.cbTransferSize)
     1841                {
     1842                    /* Unable to make sufficient space.  Drop the whole buffer content.
     1843                     * This is needed in order to keep the device emulation running at a constant rate,
     1844                     * at the cost of losing valid (but too much) data. */
     1845                    STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors);
     1846                    LogRel2(("HDA: Warning: Hit stream #%RU8 overflow, dropping %u bytes of audio data\n",
     1847                             pStreamShared->u8SD, hdaR3StreamGetUsed(pStreamR3)));
    17861848# ifdef HDA_STRICT
    1787                 AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamShared->u8SD));
     1849                    AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamShared->u8SD));
    17881850# endif
    1789                 /* When hitting an overflow, drop all remaining data to make space for current data.
    1790                  * This is needed in order to keep the device emulation running at a constant rate,
    1791                  * at the cost of losing valid (but too much) data. */
    1792                 RTCircBufReset(pStreamR3->State.pCircBuf);
    1793                 pStreamR3->State.offWrite = 0;
    1794                 pStreamR3->State.offRead  = 0;
    1795                 cbStreamFree = hdaR3StreamGetFree(pStreamR3);
    1796             }
    1797 
    1798             /* Do the DMA transfer. */
     1851                    RTCircBufReset(pStreamR3->State.pCircBuf);
     1852                    pStreamR3->State.offWrite = 0;
     1853                    pStreamR3->State.offRead  = 0;
     1854                    cbStreamFree = hdaR3StreamGetFree(pStreamR3);
     1855                }
     1856            }
     1857
     1858            /*
     1859             * Do the DMA transfer.
     1860            */
    17991861            uint64_t const offWriteBefore = pStreamR3->State.offWrite;
    18001862            rc2 = hdaR3StreamTransfer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, cbStreamFree);
     
    18021864
    18031865            /*
    1804              * Push data to down thru the mixer to and to the host drivers?
     1866             * Should we push data to down thru the mixer to and to the host drivers?
    18051867             *
    18061868             * We initially delay this by pThis->msInitialDelay, but after than we'll
     
    18521914
    18531915        /*
    1854          * <Missing Description>
     1916         * Move data out of the pStreamR3->State.pCircBuf buffer and to
     1917         * the mixer and in direction of the host audio devices.
    18551918         */
    18561919# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    1857         if (!fInTimer) /* In async I/O thread */
     1920        else
    18581921# else
    18591922        if (fDoRead)
    18601923# endif
    1861         {
    1862             uint32_t const cbSinkWritable     = AudioMixerSinkGetWritable(pSink);
    1863             uint32_t const cbStreamReadable   = hdaR3StreamGetUsed(pStreamR3);
    1864             uint32_t       cbToReadFromStream = RT_MIN(cbStreamReadable, cbSinkWritable);
    1865             /* Make sure that we always align the number of bytes when reading to the stream's PCM properties. */
    1866             cbToReadFromStream = PDMAudioPropsFloorBytesToFrame(&pStreamR3->State.Mapping.PCMProps, cbToReadFromStream);
    1867 
    1868             Assert(tsNowNs >= pStreamShared->State.tsLastReadNs);
    1869             Log3Func(("[SD%RU8] msDeltaLastRead=%RI64\n",
    1870                       pStreamShared->u8SD, (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS));
    1871             Log3Func(("[SD%RU8] cbSinkWritable=%RU32, cbStreamReadable=%RU32 -> cbToReadFromStream=%RU32\n",
    1872                       pStreamShared->u8SD, cbSinkWritable, cbStreamReadable, cbToReadFromStream));
    1873 
    1874             if (cbToReadFromStream)
    1875             {
    1876                 /* Read (guest output) data and write it to the stream's sink. */
    1877                 rc2 = hdaR3StreamRead(pStreamR3, cbToReadFromStream, NULL /* pcbRead */);
    1878                 AssertRC(rc2);
    1879             }
    1880 
    1881             /* When running synchronously, update the associated sink here.
    1882              * Otherwise this will be done in the async I/O thread. */
    1883             rc2 = AudioMixerSinkUpdate(pSink);
    1884             AssertRC(rc2);
    1885         }
     1924            hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, tsNowNs);
    18861925    }
    18871926    else /* Input (SDI). */
  • trunk/src/VBox/Devices/Audio/HDAStream.h

    r88080 r88094  
    268268        HDASTREAMSTATEAIO       AIO;
    269269#endif
    270         /** Under/overflow statistics counter.   */
     270        /** Counter for all under/overflows problems. */
     271        STAMCOUNTER             StatDmaFlowProblems;
     272        /** Counter for unresovled under/overflows problems. */
    271273        STAMCOUNTER             StatDmaFlowErrors;
    272274    } State;
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