VirtualBox

Changeset 89640 in vbox for trunk/src/VBox/Devices/Audio


Ignore:
Timestamp:
Jun 11, 2021 11:04:20 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
145085
Message:

DevIchAc97: Scan the buffer list to determin a more sensible internal DMA buffer size, and more importantly, make sure to re-create it when the buffer config changes since the previous stream run. bugref:9890

File:
1 edited

Legend:

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

    r89639 r89640  
    309309    /** Location of data buffer (bits 31:1). */
    310310    uint32_t                addr;
    311     /** Flags (bits 31 + 30) and length (bits 15:0) of data buffer (in audio samples). */
     311    /** Flags (bits 31 + 30) and length (bits 15:0) of data buffer (in audio samples).
     312     * @todo split up into two 16-bit fields.  */
    312313    uint32_t                ctl_len;
    313314} AC97BDLE;
     
    18101811
    18111812    /*
     1813     * Read the buffer descriptors and check what the max distance between
     1814     * interrupts are, so we can more correctly size the internal DMA buffer.
     1815     *
     1816     * Note! The buffer list are not fixed once the stream starts running as
     1817     *       with HDA, so this is just a general idea of what the guest is
     1818     *       up to and we cannot really make much of a plan out of it.
     1819     */
     1820    AC97BDLE aBdl[AC97_MAX_BDLE];
     1821    RT_ZERO(aBdl);
     1822    unsigned const cBuffers = pStream->Regs.lvi + 1;
     1823    PDMDevHlpPCIPhysRead(pDevIns, pStream->Regs.bdbar, aBdl, sizeof(aBdl[0]) * cBuffers);
     1824
     1825    uint32_t cSamplesMax   = 0;
     1826    uint32_t cSamplesMin   = UINT32_MAX;
     1827    uint32_t cSamplesCur   = 0;
     1828    uint32_t cSamplesTotal = 0;
     1829    for (unsigned i = 0; i < cBuffers; i++)
     1830    {
     1831        cSamplesCur   += aBdl[0].ctl_len & AC97_BD_LEN_MASK;
     1832        cSamplesTotal += aBdl[0].ctl_len & AC97_BD_LEN_MASK;
     1833        if (aBdl[0].ctl_len & AC97_BD_IOC)
     1834        {
     1835            if (cSamplesCur > cSamplesMax)
     1836                cSamplesMax = cSamplesCur;
     1837            if (cSamplesCur < cSamplesMin)
     1838                cSamplesMin = cSamplesCur;
     1839            cSamplesCur = 0;
     1840        }
     1841    }
     1842
     1843    if (cSamplesCur && cSamplesMax != 0)
     1844    {
     1845        LogFlowFunc(("Tail buffer w/o IOC, loops.\n"));
     1846        for (unsigned i = 0; i < cBuffers; i++)
     1847        {
     1848            cSamplesCur += aBdl[0].ctl_len & AC97_BD_LEN_MASK;
     1849            if (aBdl[0].ctl_len & AC97_BD_IOC)
     1850            {
     1851                if (cSamplesCur > cSamplesMax)
     1852                    cSamplesMax = cSamplesCur;
     1853                if (cSamplesCur < cSamplesMin)
     1854                    cSamplesMin = cSamplesCur;
     1855                cSamplesCur = 0;
     1856                break;
     1857            }
     1858        }
     1859    }
     1860
     1861    uint32_t const cbDmaMinBuf  = cSamplesMax * PDMAudioPropsSampleSize(&Cfg.Props) * 3; /* see further down */
     1862    uint32_t const cMsDmaMinBuf = PDMAudioPropsBytesToMilli(&Cfg.Props, cbDmaMinBuf);
     1863    LogRel3(("AC97: [SD%RU8] buffer length stats: total=%#x in %u buffers, min=%#x, max=%#x => min DMA buffer %u ms / %#x bytes\n",
     1864                 pStream->u8SD, cSamplesTotal, cBuffers, cSamplesMin, cSamplesMax, cMsDmaMinBuf, cbDmaMinBuf));
     1865
     1866    /*
    18121867     * Only (re-)create the stream (and driver chain) if we really have to.
    18131868     * Otherwise avoid this and just reuse it, as this costs performance.
    18141869     */
    18151870    int rc = VINF_SUCCESS;
    1816     if (   !PDMAudioStrmCfgMatchesProps(&Cfg, &pStreamCC->State.Cfg.Props)
    1817         || fForce)
     1871    if (   fForce
     1872        || !PDMAudioStrmCfgMatchesProps(&Cfg, &pStreamCC->State.Cfg.Props)
     1873        || !pStreamCC->State.pCircBuf
     1874        || cbDmaMinBuf > RTCircBufSize(pStreamCC->State.pCircBuf))
    18181875    {
    18191876        LogRel2(("AC97: (Re-)Opening stream '%s' (%RU32Hz, %RU8 channels, %s%RU8)\n", Cfg.szName, Cfg.Props.uHz,
     
    18621919             * the minimums here.  The less buffer the less possible delay can build when
    18631920             * TM is doing catch up.
    1864              *
    1865              * Unlike the HDA code, we currently do not have any knowledge of the buffer
    1866              * timinings, so we only have the scheduling hint to work with.
    18671921             */
    1868             uint32_t const cMsCircBuf = RT_MAX(Cfg.enmDir == PDMAUDIODIR_IN ? pThis->cMsCircBufIn : pThis->cMsCircBufOut,
    1869                                                Cfg.Device.cMsSchedulingHint * 3);
    1870             uint32_t const cbCircBuf  = PDMAudioPropsMilliToBytes(&Cfg.Props, cMsCircBuf);
     1922            uint32_t cMsCircBuf = Cfg.enmDir == PDMAUDIODIR_IN ? pThis->cMsCircBufIn : pThis->cMsCircBufOut;
     1923            cMsCircBuf = RT_MAX(cMsCircBuf, cMsDmaMinBuf);
     1924            cMsCircBuf = RT_MAX(cMsCircBuf, Cfg.Device.cMsSchedulingHint * 3);
     1925            cMsCircBuf = RT_MIN(cMsCircBuf, RT_MS_1SEC * 2); /** @todo make sure the DMA timer doesn't go over 500ms (use uTimerHz as max, really). */
     1926            uint32_t const cbCircBuf = PDMAudioPropsMilliToBytes(&Cfg.Props, cMsCircBuf);
    18711927
    18721928            if (pStreamCC->State.pCircBuf && RTCircBufSize(pStreamCC->State.pCircBuf) == cbCircBuf)
     
    18741930            else
    18751931            {
    1876                 LogFlowFunc(("Re-creating circular buffer with size %u ms / %#x bytes (was %#x)\n",
    1877                              cMsCircBuf, cbCircBuf, pStreamCC->State.StatDmaBufSize));
     1932                LogFlowFunc(("Re-creating circular buffer with size %u ms / %#x bytes (was %#x); cMsSchedulingHint=%u cMsDmaMinBuf=%u cMsCircBufXxx=%u\n",
     1933                             cMsCircBuf, cbCircBuf, pStreamCC->State.StatDmaBufSize, Cfg.Device.cMsSchedulingHint, cMsDmaMinBuf,
     1934                             Cfg.enmDir == PDMAUDIODIR_IN ? pThis->cMsCircBufIn : pThis->cMsCircBufOut));
    18781935                if (pStreamCC->State.pCircBuf)
    18791936                    RTCircBufDestroy(pStreamCC->State.pCircBuf);
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