VirtualBox

Changeset 89694 in vbox


Ignore:
Timestamp:
Jun 15, 2021 8:44:33 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
145142
Message:

DevIchAc97: Added pushback and statistics to the input portion of ichac97R3StreamUpdateDma (similar to HDA). bugref:9890

File:
1 edited

Legend:

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

    r89693 r89694  
    3636# include <iprt/string.h>
    3737# include <iprt/uuid.h>
     38# include <iprt/zero.h>
    3839#endif
    3940
     
    378379    /** Set if we've registered the asynchronous update job. */
    379380    bool                    fRegisteredAsyncUpdateJob;
    380     uint8_t                 Padding3;
     381    /** Input streams only: Set when we switch from feeding the guest silence and
     382     *  commits to proving actual audio input bytes. */
     383    bool                    fInputPreBuffered;
    381384    /** (Virtual) clock ticks per transfer. */
    382385    uint64_t                cTransferTicks;
     
    685688static uint32_t           ichac97R3StreamGetFree(PAC97STREAMR3 pStreamCC);
    686689static int                ichac97R3StreamTransfer(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream,
    687                                                   PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax);
     690                                                  PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax, bool fWriteSilence);
    688691static DECLCALLBACK(void) ichac97R3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser);
    689692
     
    10241027    if (fEnable)
    10251028    {
     1029        /* Reset some of the state. */
     1030        pStreamCC->State.fInputPreBuffered = false;
    10261031        if (pStreamCC->State.pCircBuf)
    10271032            RTCircBufReset(pStreamCC->State.pCircBuf);
    10281033
     1034        /* (Re-)Open the steram if necessary. */
    10291035        rc = ichac97R3StreamOpen(pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fForce */);
    10301036
     
    13711377                LogRel2(("AC97: Warning: Hit stream #%RU8 overflow, dropping %u bytes of audio data\n",
    13721378                         pStreamCC->u8SD, ichac97R3StreamGetUsed(pStreamCC)));
    1373 # ifdef HDA_STRICT
     1379# ifdef AC97_STRICT
    13741380                AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamCC->u8SD));
    13751381# endif
     
    13921398                  cbPeriod, PDMAudioPropsBytesToMilli(&pStreamCC->State.Cfg.Props, cbPeriod)));
    13931399
    1394         rc2 = ichac97R3StreamTransfer(pDevIns, pThis, pStream, pStreamCC, RT_MIN(cbStreamFree, cbPeriod));
     1400        rc2 = ichac97R3StreamTransfer(pDevIns, pThis, pStream, pStreamCC, RT_MIN(cbStreamFree, cbPeriod), false /*fWriteSilence*/);
    13951401        AssertRC(rc2);
    13961402
     
    14041410        AssertRC(rc2);
    14051411    }
    1406     else /* Input (SDI). */
    1407     {
    1408 #if 0 /* bird: I just love when crusial code like this with no explanation.  This just causing AIO
    1409    *       skipping a DMA timer cycle if the timer callback is a bit quicker than the 'hint' (see HDA/9890).   */
    1410         const uint64_t tsNowNs = RTTimeNanoTS();
    1411         if (tsNowNs - pStreamCC->State.tsLastUpdateNs >= pStreamCC->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS)
     1412    /*
     1413     * Input stream (SDI).
     1414     */
     1415    else
     1416    {
     1417        /*
     1418         * See how much data we've got buffered...
     1419         */
     1420        bool     fWriteSilence = false;
     1421        uint32_t cbStreamUsed  = ichac97R3StreamGetUsed(pStreamCC);
     1422        if (pStreamCC->State.fInputPreBuffered && cbStreamUsed >= cbPeriod)
     1423        { /*likely*/ }
     1424        /*
     1425         * Because it may take a while for the input stream to get going (at least
     1426         * with pulseaudio), we feed the guest silence till we've pre-buffer a
     1427         * couple of timer Hz periods.  (This avoid lots of bogus buffer underruns
     1428         * when starting an input stream and hogging the timer EMT.)
     1429         */
     1430        else if (!pStreamCC->State.fInputPreBuffered)
    14121431        {
    1413             rc2 = AudioMixerSinkSignalUpdateJob(pSink);
    1414             AssertRC(rc2);
    1415 
    1416             pStreamCC->State.tsLastUpdateNs = tsNowNs;
     1432            uint32_t const cbPreBuffer = PDMAudioPropsNanoToBytes(&pStreamCC->State.Cfg.Props,
     1433                                                                  RT_NS_1SEC / pStreamCC->State.uTimerHz);
     1434            if (cbStreamUsed < cbPreBuffer)
     1435            {
     1436                Log3(("hdaR3StreamUpdateDma: Pre-buffering (got %#x out of %#x bytes)...\n", cbStreamUsed, cbPreBuffer));
     1437                fWriteSilence = true;
     1438                cbStreamUsed  = cbPeriod;
     1439            }
     1440            else
     1441            {
     1442                Log3(("hdaR3StreamUpdateDma: Completed pre-buffering (got %#x, needed %#x bytes).\n", cbStreamUsed, cbPreBuffer));
     1443                pStreamCC->State.fInputPreBuffered = true;
     1444                fWriteSilence = ichac97R3StreamGetFree(pStreamCC) >= cbPreBuffer + cbPreBuffer / 2;
     1445                if (fWriteSilence)
     1446                    cbStreamUsed = cbPeriod;
     1447            }
    14171448        }
    1418 #endif
    1419 
    1420         uint32_t cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC);
    1421         if (cbStreamUsed)
    1422         { /* likey */ }
     1449        /*
     1450         * When we're low on data, we must really try fetch some ourselves
     1451         * as buffer underruns must not happen.
     1452         */
    14231453        else
    14241454        {
    1425             /** @todo Record this as a statistic. Try pull some data into the DMA buffer.*/
     1455            STAM_REL_COUNTER_INC(&pStreamCC->State.StatDmaFlowProblems);
     1456            Log(("ichac97R3StreamUpdateDma: Warning! Stream #%u has insufficient data available: %u bytes, need %u.  Will try move pull more data into the buffer...\n",
     1457                 pStreamCC->u8SD, cbStreamUsed, cbPeriod));
     1458            int rc = AudioMixerSinkTryLock(pSink);
     1459            if (RT_SUCCESS(rc))
     1460            {
     1461                AudioMixerSinkUpdate(pSink, cbStreamUsed, cbPeriod);
     1462                ichac97R3StreamPullFromMixer(pStreamCC, pSink);
     1463                AudioMixerSinkUnlock(pSink);
     1464            }
     1465            else
     1466                RTThreadYield();
     1467            Log(("ichac97R3StreamUpdateDma: Gained %u bytes.\n", ichac97R3StreamGetUsed(pStreamCC) - cbStreamUsed));
     1468            cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC);
     1469            if (cbStreamUsed < cbPeriod)
     1470            {
     1471                /* Unable to find sufficient input data by simple prodding.
     1472                   In order to keep a constant byte stream following thru the DMA
     1473                   engine into the guest, we will try again and then fall back on
     1474                   filling the gap with silence. */
     1475                uint32_t cbSilence = 0;
     1476                do
     1477                {
     1478                    AudioMixerSinkLock(pSink);
     1479
     1480                    cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC);
     1481                    if (cbStreamUsed < cbPeriod)
     1482                    {
     1483                        ichac97R3StreamPullFromMixer(pStreamCC, pSink);
     1484                        cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC);
     1485                        while (cbStreamUsed < cbPeriod)
     1486                        {
     1487                            void  *pvDstBuf;
     1488                            size_t cbDstBuf;
     1489                            RTCircBufAcquireWriteBlock(pStreamCC->State.pCircBuf, cbPeriod - cbStreamUsed,
     1490                                                       &pvDstBuf, &cbDstBuf);
     1491                            RT_BZERO(pvDstBuf, cbDstBuf);
     1492                            RTCircBufReleaseWriteBlock(pStreamCC->State.pCircBuf, cbDstBuf);
     1493                            cbSilence    += (uint32_t)cbDstBuf;
     1494                            cbStreamUsed += (uint32_t)cbDstBuf;
     1495                        }
     1496                    }
     1497
     1498                    AudioMixerSinkUnlock(pSink);
     1499                } while (cbStreamUsed < cbPeriod);
     1500                if (cbSilence > 0)
     1501                {
     1502                    STAM_REL_COUNTER_INC(&pStreamCC->State.StatDmaFlowErrors);
     1503                    STAM_REL_COUNTER_ADD(&pStreamCC->State.StatDmaFlowErrorBytes, cbSilence);
     1504                    LogRel2(("AC97: Warning: Stream #%RU8 underrun, added %u bytes of silence (%u us)\n", pStreamCC->u8SD,
     1505                             cbSilence, PDMAudioPropsBytesToMicro(&pStreamCC->State.Cfg.Props, cbSilence)));
     1506                }
     1507            }
    14261508        }
    14271509
     1510        /*
     1511         * Do the DMA'ing.
     1512         */
    14281513        if (cbStreamUsed)
    14291514        {
    1430             /* When running synchronously, do the DMA data transfers here.
    1431              * Otherwise this will be done in the stream's async I/O thread. */
    1432             rc2 = ichac97R3StreamTransfer(pDevIns, pThis, pStream, pStreamCC, cbStreamUsed);
     1515            rc2 = ichac97R3StreamTransfer(pDevIns, pThis, pStream, pStreamCC, RT_MIN(cbPeriod, cbStreamUsed), fWriteSilence);
    14331516            AssertRC(rc2);
     1517
     1518            pStreamCC->State.tsLastUpdateNs = RTTimeNanoTS();
    14341519        }
    14351520
     
    14431528        rc2 = AudioMixerSinkSignalUpdateJob(pSink);
    14441529        AssertRC(rc2);
    1445         pStreamCC->State.tsLastUpdateNs = RTTimeNanoTS();
    14461530    }
    14471531}
     
    26312715 * @param   pStreamCC           The AC'97 stream to update (ring-3).
    26322716 * @param   cbToProcessMax      Maximum of data (in bytes) to process.
     2717 * @param   fWriteSilence       Whether to write silence if this is an input
     2718 *                              stream (done while waiting for backend to get
     2719 *                              going).
    26332720 */
    26342721static int ichac97R3StreamTransfer(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream,
    2635                                    PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax)
     2722                                   PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax, bool fWriteSilence)
    26362723{
    26372724    if (!cbToProcessMax)
     
    27142801            case AC97SOUNDSOURCE_PO_INDEX: /* Output */
    27152802            {
    2716                 void *pvDst;
    2717                 size_t cbDst;
    2718 
     2803                void  *pvDst = NULL;
     2804                size_t cbDst = NULL;
    27192805                RTCircBufAcquireWriteBlock(pCircBuf, cbChunk, &pvDst, &cbDst);
    27202806
    27212807                if (cbDst)
    27222808                {
    2723                     int rc2 = PDMDevHlpPCIPhysRead(pDevIns, pRegs->bd.addr, (uint8_t *)pvDst, cbDst);
     2809                    int rc2 = PDMDevHlpPCIPhysRead(pDevIns, pRegs->bd.addr, pvDst, cbDst);
    27242810                    AssertRC(rc2);
    27252811
     
    27382824            case AC97SOUNDSOURCE_PI_INDEX: /* Input */
    27392825            case AC97SOUNDSOURCE_MC_INDEX: /* Input */
    2740             {
    2741                 void *pvSrc;
    2742                 size_t cbSrc;
    2743 
    2744                 RTCircBufAcquireReadBlock(pCircBuf, cbChunk, &pvSrc, &cbSrc);
    2745 
    2746                 if (cbSrc)
     2826                if (!fWriteSilence)
    27472827                {
    2748                     int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, (uint8_t *)pvSrc, cbSrc);
     2828                    void  *pvSrc = NULL;
     2829                    size_t cbSrc = NULL;
     2830                    RTCircBufAcquireReadBlock(pCircBuf, cbChunk, &pvSrc, &cbSrc);
     2831
     2832                    if (cbSrc)
     2833                    {
     2834                        int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, pvSrc, cbSrc);
     2835                        AssertRC(rc2);
     2836
     2837                        if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))
     2838                        { /* likely */ }
     2839                        else
     2840                            AudioHlpFileWrite(pStreamCC->Dbg.Runtime.pFileDMA, pvSrc, cbSrc, 0 /* fFlags */);
     2841                    }
     2842
     2843                    RTCircBufReleaseReadBlock(pCircBuf, cbSrc);
     2844
     2845                    cbChunk = (uint32_t)cbSrc; /* Update the current chunk size to what really has been read. */
     2846                }
     2847                else
     2848                {
     2849                    /* Since the format is signed 16-bit or 32-bit integer samples, we can
     2850                       use g_abRTZero64K as source and avoid some unnecessary bzero() work. */
     2851                    cbChunk = RT_MIN(cbChunk, sizeof(g_abRTZero64K));
     2852                    cbChunk = PDMAudioPropsFloorBytesToFrame(&pStreamCC->State.Cfg.Props, cbChunk);
     2853
     2854                    int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, g_abRTZero64K, cbChunk);
    27492855                    AssertRC(rc2);
    2750 
    2751                     if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))
    2752                     { /* likely */ }
    2753                     else
    2754                         AudioHlpFileWrite(pStreamCC->Dbg.Runtime.pFileDMA, pvSrc, cbSrc, 0 /* fFlags */);
    27552856                }
    2756 
    2757                 RTCircBufReleaseReadBlock(pCircBuf, cbSrc);
    2758 
    2759                 cbChunk = (uint32_t)cbSrc; /* Update the current chunk size to what really has been read. */
    27602857                break;
    2761             }
    27622858
    27632859            default:
     
    27722868        if (cbChunk)
    27732869        {
     2870            Assert(PDMAudioPropsIsSizeAligned(&pStreamCC->State.Cfg.Props, cbChunk));
     2871            Assert(cbChunk <= cbLeft);
     2872
    27742873            cbProcessedTotal     += cbChunk;
    27752874            Assert(cbProcessedTotal <= cbToProcessMax);
    2776             Assert(cbLeft >= cbChunk);
    2777             cbLeft      -= cbChunk;
    2778             Assert((cbChunk & 1) == 0); /* Else the following shift won't work */
    2779 
    2780             pRegs->picb    -= (cbChunk >> 1); /** @todo r=andy Assumes 16bit samples. */
    2781             pRegs->bd.addr += cbChunk;
     2875            cbLeft               -= cbChunk;
     2876            pRegs->picb          -= (cbChunk >> 1); /** @todo r=andy Assumes 16bit samples. */
     2877            pRegs->bd.addr       += cbChunk;
    27822878        }
    27832879
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