VirtualBox

Ignore:
Timestamp:
Jan 17, 2019 1:58:54 PM (6 years ago)
Author:
vboxsync
Message:

Audio/AC97: Added more code for transfer calculation for helping with A/V synchronization.

File:
1 edited

Legend:

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

    r76854 r76862  
    349349     *  Can be 0 if no next transfer is scheduled. */
    350350    uint64_t              tsTransferNext;
    351     /** Total transfer size (in bytes) of a transfer period. */
    352     uint32_t              cbTransferSize;
    353351    /** Transfer chunk size (in bytes) of a transfer period. */
    354352    uint32_t              cbTransferChunk;
    355     /** How many bytes already have been processed in within
    356      *  the current transfer period. */
    357     uint32_t              cbTransferProcessed;
    358353    /** The stream's timer Hz rate.
    359354     *  This value can can be different from the device's default Hz rate,
     
    362357    uint16_t              uTimerHz;
    363358    uint8_t               Padding3[2];
    364     /** (Virtual) clock ticks per byte. */
    365     uint64_t              cTicksPerByte;
    366359    /** (Virtual) clock ticks per transfer. */
    367360    uint64_t              cTransferTicks;
     
    706699# endif
    707700#endif /* IN_RING3 */
     701bool                      ichac97TimerSet(PAC97STATE pThis, PAC97STREAM pStream, uint64_t tsExpire, bool fForce);
    708702
    709703static void ichac97WarmReset(PAC97STATE pThis)
     
    833827}
    834828
     829/**
     830 * Writes a new value to a stream's status register (SR).
     831 *
     832 * @param   pThis               AC'97 device state.
     833 * @param   pStream             Stream to update SR for.
     834 * @param   u32Val              New value to set the stream's SR to.
     835 */
    835836static void ichac97StreamWriteSR(PAC97STATE pThis, PAC97STREAM pStream, uint32_t u32Val)
    836837{
     
    15061507    int rc2;
    15071508
    1508     if (pStream->u8SD == AC97SOUNDSOURCE_PO_INDEX) /* Output (SDO). */
    1509     {
    1510         /* How much (guest output) data is available at the moment for the AC'97 stream? */
    1511         /* Only read from the AC'97 stream at the given scheduling rate. */
    1512         bool fDoRead = false; /* Whether to read from the AC'97 stream or not. */
    1513 
     1509    if (pStream->State.Cfg.enmDir == PDMAUDIODIR_OUT) /* Output (SDO). */
     1510    {
    15141511# ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
    15151512        if (fInTimer)
    15161513# endif
    15171514        {
    1518             uint32_t cbTransferChunk = (pStream->State.Cfg.Props.uHz / pStream->State.uTimerHz)
    1519                                      * DrvAudioHlpPCMPropsBytesPerFrame(&pStream->State.Cfg.Props);
    1520 
    15211515            const uint32_t cbStreamFree = ichac97R3StreamGetFree(pStream);
    15221516            if (cbStreamFree)
    15231517            {
     1518                Log3Func(("[SD%RU8] PICB=%zu (%RU64ms), cbFree=%zu (%RU64ms), cbTransferChunk=%zu (%RU64ms)\n",
     1519                          pStream->u8SD,
     1520                          (pStream->Regs.picb << 1), DrvAudioHlpBytesToMilli((pStream->Regs.picb << 1), &pStream->State.Cfg.Props),
     1521                          cbStreamFree, DrvAudioHlpBytesToMilli(cbStreamFree, &pStream->State.Cfg.Props),
     1522                          pStream->State.cbTransferChunk, DrvAudioHlpBytesToMilli(pStream->State.cbTransferChunk, &pStream->State.Cfg.Props)));
     1523
    15241524                /* Do the DMA transfer. */
    1525                 rc2 = ichac97R3StreamTransfer(pThis, pStream, RT_MIN(cbStreamFree, cbTransferChunk));
     1525                rc2 = ichac97R3StreamTransfer(pThis, pStream, RT_MIN(pStream->State.cbTransferChunk, cbStreamFree));
    15261526                AssertRC(rc2);
     1527
     1528                pStream->State.tsLastUpdateNs = RTTimeNanoTS();
    15271529            }
    1528 
    1529             /* Only read from the AC'97 stream at the given scheduling rate. */
    1530             const uint64_t tsNowNs = RTTimeNanoTS();
    1531             if (tsNowNs - pStream->State.tsLastUpdateNs >= pStream->State.Cfg.Device.uSchedulingHintMs * RT_NS_1MS)
    1532             {
    1533                 fDoRead = true;
    1534                 pStream->State.tsLastUpdateNs = tsNowNs;
    1535             }
    1536         }
    1537 
    1538         Log3Func(("[SD%RU8] fInTimer=%RTbool, fDoRead=%RTbool\n", pStream->u8SD, fInTimer, fDoRead));
     1530        }
     1531
     1532        Log3Func(("[SD%RU8] fInTimer=%RTbool\n", pStream->u8SD, fInTimer));
    15391533
    15401534# ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
    1541         if (fDoRead)
    1542         {
    1543             rc2 = ichac97R3StreamAsyncIONotify(pThis, pStream);
    1544             AssertRC(rc2);
    1545         }
     1535        rc2 = ichac97R3StreamAsyncIONotify(pThis, pStream);
     1536        AssertRC(rc2);
    15461537# endif
    15471538
    15481539# ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
    15491540        if (!fInTimer) /* In async I/O thread */
    1550         {
    1551 # else
    1552         if (fDoRead)
    15531541        {
    15541542# endif
     
    15651553                AssertRC(rc2);
    15661554            }
    1567         }
    1568 
     1555# ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     1556        }
     1557#endif
    15691558        /* When running synchronously, update the associated sink here.
    15701559         * Otherwise this will be done in the async I/O thread. */
     
    19691958
    19701959/**
     1960 * Calculates and returns the ticks for a specified amount of bytes.
     1961 *
     1962 * @returns Calculated ticks
     1963 * @param   pThis               AC'97 device state.
     1964 * @param   pStream             AC'97 stream to calculate ticks for.
     1965 * @param   cbBytes             Bytes to calculate ticks for.
     1966 */
     1967static uint64_t ichac97R3StreamTransferCalcNext(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbBytes)
     1968{
     1969    if (!cbBytes)
     1970        return 0;
     1971
     1972    AssertReturn(DrvAudioHlpPCMPropsAreValid(&pStream->State.Cfg.Props), 0);
     1973    const uint32_t cbFrame = DrvAudioHlpPCMPropsBytesPerFrame(&pStream->State.Cfg.Props);
     1974
     1975    AssertReturn(cbBytes % cbFrame == 0, 0);
     1976
     1977    const uint64_t cTicksPerHz    = TMTimerGetFreq((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) / pStream->State.uTimerHz;
     1978    const uint64_t cTicksPerByte  = cTicksPerHz / cbBytes;
     1979    Assert(cTicksPerByte);
     1980    const uint64_t cTransferTicks = cbBytes * cTicksPerByte;
     1981
     1982    LogFunc(("[SD%RU8] Timer %uHz (%RU64 ticks per Hz), cTicksPerByte=%RU64, cbBytes=%RU32 -> cTransferTicks=%RU64\n",
     1983             pStream->u8SD, pStream->State.uTimerHz, cTicksPerHz, cTicksPerByte, cbBytes, cTransferTicks));
     1984
     1985    return cTransferTicks;
     1986}
     1987
     1988/**
     1989 * Updates the next transfer based on a specific amount of bytes.
     1990 *
     1991 * @returns IPRT status code.
     1992 * @param   pThis               AC'97 device state.
     1993 * @param   pStream             AC'97 stream to update.
     1994 * @param   cbBytes             Bytes to update next transfer for.
     1995 */
     1996static void ichac97R3StreamTransferUpdate(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbBytes)
     1997{
     1998    if (!cbBytes)
     1999        return;
     2000
     2001    /* Calculate the bytes we need to transfer to / from the stream's DMA per iteration.
     2002     * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. */
     2003    pStream->State.cbTransferChunk = cbBytes;
     2004
     2005    /* Update the transfer ticks. */
     2006    pStream->State.cTransferTicks = ichac97R3StreamTransferCalcNext(pThis, pStream, pStream->State.cbTransferChunk);
     2007    Assert(pStream->State.cTransferTicks); /* Paranoia. */
     2008}
     2009
     2010/**
    19712011 * Opens an AC'97 stream with its current mixer settings.
    19722012 *
     
    19752015 *
    19762016 * @returns IPRT status code.
    1977  * @param   pThis               AC'97 state.
    1978  * @param   pStream             AC'97 Stream to open.
     2017 * @param   pThis               AC'97 device state.
     2018 * @param   pStream             AC'97 stream to open.
    19792019 */
    19802020static int ichac97R3StreamOpen(PAC97STATE pThis, PAC97STREAM pStream)
     
    20792119                        rc = DrvAudioHlpStreamCfgCopy(&pStream->State.Cfg, &Cfg);
    20802120                }
    2081 
    2082                 /*
    2083                  * Set up data transfer stuff.
    2084                  */
    2085 #ifdef LOG_ENABLED
    2086                 ichac97R3BDLEDumpAll(pThis, pStream->Regs.bdbar, pStream->Regs.lvi + 1);
    2087 #endif
    2088                 const uint32_t cbFrame = DrvAudioHlpPCMPropsBytesPerFrame(&Cfg.Props);
    2089 
    2090                 /* Calculate the fragment size the guest OS expects interrupt delivery at. */
    2091                 pStream->State.cbTransferSize = 441 * 4;//pStream->u32CBL / cFragments;
    2092                 Assert(pStream->State.cbTransferSize);
    2093                 Assert(pStream->State.cbTransferSize % cbFrame == 0);
    2094 
    2095                 /* Calculate the bytes we need to transfer to / from the stream's DMA per iteration.
    2096                  * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. */
    2097                 pStream->State.cbTransferChunk = (pStream->State.Cfg.Props.uHz / pStream->State.uTimerHz) * cbFrame;
    2098                 Assert(pStream->State.cbTransferChunk);
    2099                 Assert(pStream->State.cbTransferChunk % cbFrame== 0);
    2100 
    2101                 /* Make sure that the transfer chunk does not exceed the overall transfer size. */
    2102                 if (pStream->State.cbTransferChunk > pStream->State.cbTransferSize)
    2103                     pStream->State.cbTransferChunk = pStream->State.cbTransferSize;
    2104 
    2105                 const uint64_t cTicksPerHz = TMTimerGetFreq((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD))/ pStream->State.uTimerHz;
    2106 
    2107                 /* Calculate the timer ticks per byte for this stream. */
    2108                 pStream->State.cTicksPerByte = cTicksPerHz / pStream->State.cbTransferChunk;
    2109                 Assert(pStream->State.cTicksPerByte);
    2110 
    2111                 /* Calculate timer ticks per transfer. */
    2112                 pStream->State.cTransferTicks     = pStream->State.cbTransferChunk * pStream->State.cTicksPerByte;
    2113                 Assert(pStream->State.cTransferTicks);
    2114 
    2115                 LogFunc(("[SD%RU8] Timer %uHz (%RU64 ticks per Hz), cTicksPerByte=%RU64, cbTransferChunk=%RU32, cTransferTicks=%RU64, " \
    2116                          "cbTransferSize=%RU32\n",
    2117                          pStream->u8SD, pStream->State.uTimerHz, cTicksPerHz, pStream->State.cTicksPerByte,
    2118                          pStream->State.cbTransferChunk, pStream->State.cTransferTicks, pStream->State.cbTransferSize));
    2119 
    21202121            }
    21212122        }
     
    26562657    if (fSinkActive)
    26572658    {
    2658         TMTimerSet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD),
    2659                    TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks);
     2659        ichac97R3StreamTransferUpdate(pThis, pStream, pStream->Regs.picb << 1); /** @todo r=andy Assumes 16-bit samples. */
     2660
     2661        ichac97TimerSet(pThis,pStream,
     2662                        TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks,
     2663                        false /* fForce */);
    26602664    }
    26612665
     
    26642668    STAM_PROFILE_STOP(&pThis->StatTimer, a);
    26652669}
     2670#endif /* IN_RING3 */
    26662671
    26672672/**
     
    26832688 *          Forcing a new expiration time will override the above mechanism.
    26842689 */
    2685 bool ichac97R3TimerSet(PAC97STATE pThis, PAC97STREAM pStream, uint64_t tsExpire, bool fForce)
     2690bool ichac97TimerSet(PAC97STATE pThis, PAC97STREAM pStream, uint64_t tsExpire, bool fForce)
    26862691{
    26872692    AssertPtrReturn(pThis, false);
     
    27052710    return RT_SUCCESS(rc);
    27062711}
     2712
     2713#ifdef IN_RING3
    27072714
    27082715/**
     
    27242731    AssertPtrReturn(pThis,       VERR_INVALID_POINTER);
    27252732    AssertPtrReturn(pStream,     VERR_INVALID_POINTER);
    2726     AssertReturn(cbToProcessMax, VERR_INVALID_PARAMETER);
     2733
     2734    if (!cbToProcessMax)
     2735        return VINF_SUCCESS;
     2736
     2737#ifdef VBOX_STRICT
     2738    const unsigned cbFrame = DrvAudioHlpPCMPropsBytesPerFrame(&pStream->State.Cfg.Props);
     2739#endif
     2740
     2741    /* Make sure to only process an integer number of audio frames. */
     2742    Assert(cbToProcessMax % cbFrame == 0);
    27272743
    27282744    ichac97R3StreamLock(pStream);
     
    27702786    while (cbLeft)
    27712787    {
    2772         if (!pRegs->bd_valid)
    2773         {
    2774             Log3Func(("Invalid buffer descriptor, fetching next one ...\n"));
    2775             ichac97R3StreamFetchBDLE(pThis, pStream);
    2776         }
    2777 
    27782788        if (!pRegs->picb) /* Got a new buffer descriptor, that is, the position is 0? */
    27792789        {
     
    27972807        }
    27982808
    2799         uint32_t cbChunk = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */
    2800         Assert(cbChunk);
     2809        uint32_t cbChunk = cbLeft;
    28012810
    28022811        switch (pStream->u8SD)
     
    31513160                        pRegs->civ = pRegs->piv;
    31523161                        pRegs->piv = (pRegs->piv + 1) % AC97_MAX_BDLE;
    3153 
    3154                         ichac97R3StreamFetchBDLE(pThis, pStream);
    31553162#else
    31563163                        rc = VINF_IOM_R3_IOPORT_WRITE;
     
    32143221
    32153222                            /* Arm the timer for this stream. */
    3216                             int rc2 = ichac97R3TimerSet(pThis, pStream,
    3217                                                         TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks,
    3218                                                         false /* fForce */);
     3223                            int rc2 = ichac97TimerSet(pThis, pStream,
     3224                                                      TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks,
     3225                                                      false /* fForce */);
    32193226                            AssertRC(rc2);
    32203227                        }
     
    37783785        {
    37793786            /* Re-arm the timer for this stream. */
    3780             rc2 = ichac97R3TimerSet(pThis, pStream,
    3781                                     TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks,
    3782                                     false /* fForce */);
     3787            rc2 = ichac97TimerSet(pThis, pStream,
     3788                                  TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks,
     3789                                  false /* fForce */);
    37833790        }
    37843791
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