VirtualBox

Changeset 89706 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jun 15, 2021 2:12:56 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
145154
Message:

DevIchAc97: Must recreate the stream when the internal DMA buffer size differs, just just when it's too small. Otherwise we'll end up too much slack space. bugref:9890

File:
1 edited

Legend:

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

    r89694 r89706  
    10321032            RTCircBufReset(pStreamCC->State.pCircBuf);
    10331033
    1034         /* (Re-)Open the steram if necessary. */
     1034        /* (Re-)Open the stream if necessary. */
    10351035        rc = ichac97R3StreamOpen(pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fForce */);
    10361036
     
    20052005    }
    20062006
     2007    /** @todo r=bird: If uHz == 0 then we'll just keep the previous stream, so
     2008     * wonder how that's going to play out if the guest tries to enable it...  This
     2009     * makes no real sense.
     2010     *
     2011     * Comment your code and changes you make, please!  This is frigging tedious.
     2012     *
     2013     * Test added in r127402?  The test is older (before r118166, r113296, r112652,
     2014     * r112463, r107142), but it used to be placed after calling
     2015     * ichac97R3MixerRemoveDrvStreams() since r112652.  Till ~r112463 a zero uHz
     2016     * caused a VERR_INVALID_PARAMETER return. Before r107142 it would disable the
     2017     * stream if uHz was zero. */
     2018    if (Cfg.Props.uHz)
     2019    { /* likely */ }
     2020    else
     2021    {
     2022        LogFlowFunc(("[SD%RU8] Hz is zero!! skipping/ignoring\n"));
     2023        return VINF_SUCCESS;
     2024    }
     2025
    20072026    /*
    20082027     * Read the buffer descriptors and check what the max distance between
     
    20642083
    20652084    /*
     2085     * Calculate the timer Hz / scheduling hint based on the stream frame rate.
     2086     */
     2087    uint32_t uTimerHz;
     2088    if (pThis->uTimerHz == AC97_TIMER_HZ_DEFAULT) /* Make sure that we don't have any custom Hz rate set we want to enforce */
     2089    {
     2090        if (Cfg.Props.uHz > 44100) /* E.g. 48000 Hz. */
     2091            uTimerHz = 200;
     2092        else /* Just take the global Hz rate otherwise. */
     2093            uTimerHz = pThis->uTimerHz;
     2094    }
     2095    else
     2096        uTimerHz = pThis->uTimerHz;
     2097
     2098    if (   uTimerHz >= 10
     2099        && uTimerHz <= 500)
     2100    { /* likely */ }
     2101    else
     2102    {
     2103        LogFunc(("[SD%RU8] Adjusting uTimerHz=%u to %u\n", pStream->u8SD, uTimerHz,
     2104                 Cfg.Props.uHz > 44100 ? 200 : AC97_TIMER_HZ_DEFAULT));
     2105        uTimerHz = Cfg.Props.uHz > 44100 ? 200 : AC97_TIMER_HZ_DEFAULT;
     2106    }
     2107
     2108    /* Translate it to a scheduling hint. */
     2109    uint32_t const cMsSchedulingHint = RT_MS_1SEC / uTimerHz;
     2110
     2111    /*
     2112     * Calculate the circular buffer size so we can decide whether to recreate
     2113     * the stream or not.
     2114     *
     2115     * As mentioned in the HDA code, this should be at least able to hold the
     2116     * data transferred in three DMA periods and in three AIO period (whichever
     2117     * is higher).  However, if we assume that the DMA code will engage the DMA
     2118     * timer thread (currently EMT) if the AIO thread isn't getting schduled to
     2119     * transfer data thru the stack, we don't need to go overboard and double
     2120     * the minimums here.  The less buffer the less possible delay can build when
     2121     * TM is doing catch up.
     2122     */
     2123    uint32_t cMsCircBuf = Cfg.enmDir == PDMAUDIODIR_IN ? pThis->cMsCircBufIn : pThis->cMsCircBufOut;
     2124    cMsCircBuf = RT_MAX(cMsCircBuf, cMsDmaMinBuf);
     2125    cMsCircBuf = RT_MAX(cMsCircBuf, cMsSchedulingHint * 3);
     2126    cMsCircBuf = RT_MIN(cMsCircBuf, RT_MS_1SEC * 2);
     2127    uint32_t const cbCircBuf = PDMAudioPropsMilliToBytes(&Cfg.Props, cMsCircBuf);
     2128
     2129    /*
    20662130     * Only (re-)create the stream (and driver chain) if we really have to.
    20672131     * Otherwise avoid this and just reuse it, as this costs performance.
     
    20712135        || !PDMAudioStrmCfgMatchesProps(&Cfg, &pStreamCC->State.Cfg.Props)
    20722136        || !pStreamCC->State.pCircBuf
    2073         || cbDmaMinBuf > RTCircBufSize(pStreamCC->State.pCircBuf))
     2137        || cbCircBuf != RTCircBufSize(pStreamCC->State.pCircBuf))
    20742138    {
    20752139        LogRel2(("AC97: (Re-)Opening stream '%s' (%RU32Hz, %RU8 channels, %s%RU8)\n", Cfg.szName, Cfg.Props.uHz,
     
    20782142        LogFlowFunc(("[SD%RU8] uHz=%RU32\n", pStream->u8SD, Cfg.Props.uHz));
    20792143
    2080         if (Cfg.Props.uHz)
     2144        Assert(Cfg.enmDir != PDMAUDIODIR_UNKNOWN);
     2145
     2146        /*
     2147         * Set the stream's timer rate and scheduling hint.
     2148         */
     2149        pStreamCC->State.uTimerHz    = uTimerHz;
     2150        Cfg.Device.cMsSchedulingHint = cMsSchedulingHint;
     2151
     2152        /*
     2153         * Re-create the circular buffer if necessary.
     2154         */
     2155        if (pStreamCC->State.pCircBuf && RTCircBufSize(pStreamCC->State.pCircBuf) == cbCircBuf)
     2156            RTCircBufReset(pStreamCC->State.pCircBuf);
     2157        else
    20812158        {
    2082             Assert(Cfg.enmDir != PDMAUDIODIR_UNKNOWN);
    2083 
    2084             /*
    2085              * Set the stream's timer Hz rate, based on the PCM properties Hz rate.
    2086              */
    2087             if (pThis->uTimerHz == AC97_TIMER_HZ_DEFAULT) /* Make sure that we don't have any custom Hz rate set we want to enforce */
    2088             {
    2089                 if (Cfg.Props.uHz > 44100) /* E.g. 48000 Hz. */
    2090                     pStreamCC->State.uTimerHz = 200;
    2091                 else /* Just take the global Hz rate otherwise. */
    2092                     pStreamCC->State.uTimerHz = pThis->uTimerHz;
    2093             }
    2094             else
    2095                 pStreamCC->State.uTimerHz = pThis->uTimerHz;
    2096 
    2097             if (   pStreamCC->State.uTimerHz >= 10
    2098                 && pStreamCC->State.uTimerHz <= 500)
    2099             { /* likely */ }
    2100             else
    2101             {
    2102                 LogFunc(("[SD%RU8] Adjusting uTimerHz=%u to %u\n", pStream->u8SD, pStreamCC->State.uTimerHz,
    2103                          Cfg.Props.uHz > 44100 ? 200 : AC97_TIMER_HZ_DEFAULT));
    2104                 pStreamCC->State.uTimerHz = Cfg.Props.uHz > 44100 ? 200 : AC97_TIMER_HZ_DEFAULT;
    2105             }
    2106 
    2107             /* Set scheduling hint. */
    2108             Cfg.Device.cMsSchedulingHint = RT_MS_1SEC / pStreamCC->State.uTimerHz;
    2109 
    2110             /*
    2111              * Re-create the circular buffer if necessary.
    2112              *
    2113              * As mentioned in the HDA code, this should be at least able to hold the
    2114              * data transferred in three DMA periods and in three AIO period (whichever
    2115              * is higher).  However, if we assume that the DMA code will engage the DMA
    2116              * timer thread (currently EMT) if the AIO thread isn't getting schduled to
    2117              * transfer data thru the stack, we don't need to go overboard and double
    2118              * the minimums here.  The less buffer the less possible delay can build when
    2119              * TM is doing catch up.
    2120              */
    2121             uint32_t cMsCircBuf = Cfg.enmDir == PDMAUDIODIR_IN ? pThis->cMsCircBufIn : pThis->cMsCircBufOut;
    2122             cMsCircBuf = RT_MAX(cMsCircBuf, cMsDmaMinBuf);
    2123             cMsCircBuf = RT_MAX(cMsCircBuf, Cfg.Device.cMsSchedulingHint * 3);
    2124             cMsCircBuf = RT_MIN(cMsCircBuf, RT_MS_1SEC * 2); /** @todo make sure the DMA timer doesn't go over 500ms (use uTimerHz as max, really). */
    2125             uint32_t const cbCircBuf = PDMAudioPropsMilliToBytes(&Cfg.Props, cMsCircBuf);
    2126 
    2127             if (pStreamCC->State.pCircBuf && RTCircBufSize(pStreamCC->State.pCircBuf) == cbCircBuf)
    2128                 RTCircBufReset(pStreamCC->State.pCircBuf);
    2129             else
    2130             {
    2131                 LogFlowFunc(("Re-creating circular buffer with size %u ms / %#x bytes (was %#x); cMsSchedulingHint=%u cMsDmaMinBuf=%u cMsCircBufXxx=%u\n",
    2132                              cMsCircBuf, cbCircBuf, pStreamCC->State.StatDmaBufSize, Cfg.Device.cMsSchedulingHint, cMsDmaMinBuf,
    2133                              Cfg.enmDir == PDMAUDIODIR_IN ? pThis->cMsCircBufIn : pThis->cMsCircBufOut));
    2134                 if (pStreamCC->State.pCircBuf)
    2135                     RTCircBufDestroy(pStreamCC->State.pCircBuf);
    2136 
    2137                 rc = RTCircBufCreate(&pStreamCC->State.pCircBuf, cbCircBuf);
    2138                 AssertRCReturnStmt(rc, pStreamCC->State.pCircBuf = NULL, rc);
    2139 
    2140                 pStreamCC->State.StatDmaBufSize = (uint32_t)RTCircBufSize(pStreamCC->State.pCircBuf);
    2141             }
    2142             Assert(pStreamCC->State.StatDmaBufSize == cbCircBuf);
    2143 
    2144             /*
    2145              * <there should be a comment here>
    2146              */
    2147             ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pMixSink, Cfg.enmDir, Cfg.enmPath);
    2148             rc = ichac97R3MixerAddDrvStreams(pDevIns, pThisCC, pMixSink, &Cfg);
    2149             if (RT_SUCCESS(rc))
    2150                 rc = PDMAudioStrmCfgCopy(&pStreamCC->State.Cfg, &Cfg);
     2159            LogFlowFunc(("Re-creating circular buffer with size %u ms / %#x bytes (was %#x); cMsSchedulingHint=%u cMsDmaMinBuf=%u cMsCircBufXxx=%u\n",
     2160                         cMsCircBuf, cbCircBuf, pStreamCC->State.StatDmaBufSize, Cfg.Device.cMsSchedulingHint, cMsDmaMinBuf,
     2161                         Cfg.enmDir == PDMAUDIODIR_IN ? pThis->cMsCircBufIn : pThis->cMsCircBufOut));
     2162            if (pStreamCC->State.pCircBuf)
     2163                RTCircBufDestroy(pStreamCC->State.pCircBuf);
     2164
     2165            rc = RTCircBufCreate(&pStreamCC->State.pCircBuf, cbCircBuf);
     2166            AssertRCReturnStmt(rc, pStreamCC->State.pCircBuf = NULL, rc);
     2167
     2168            pStreamCC->State.StatDmaBufSize = (uint32_t)RTCircBufSize(pStreamCC->State.pCircBuf);
    21512169        }
     2170        Assert(pStreamCC->State.StatDmaBufSize == cbCircBuf);
     2171
     2172        /*
     2173         * <there should be a comment here>
     2174         */
     2175        ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pMixSink, Cfg.enmDir, Cfg.enmPath);
     2176        rc = ichac97R3MixerAddDrvStreams(pDevIns, pThisCC, pMixSink, &Cfg);
     2177        if (RT_SUCCESS(rc))
     2178            rc = PDMAudioStrmCfgCopy(&pStreamCC->State.Cfg, &Cfg);
     2179
    21522180        LogFlowFunc(("[SD%RU8] rc=%Rrc\n", pStream->u8SD, rc));
    21532181    }
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