VirtualBox

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


Ignore:
Timestamp:
Apr 6, 2021 8:31:12 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
143622
Message:

DrvAudio: Arm a timer when entering the PENDING_DISABLE state to work pfnStreamIterate and pfnStreamPlay, otherwise we probably will not get out of this state till the stream is re-enabled. bugref:9890

File:
1 edited

Legend:

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

    r88362 r88375  
    9191    uintptr_t           uMagic;
    9292
    93     /** List entry (some DrvAudio internal list). */
     93    /** List entry in DRVAUDIO::lstStreams. */
    9494    RTLISTNODE          ListEntry;
    9595
     
    314314        STAMCOUNTER         StatsReBuffering;
    315315    } Out;
     316
     317    /** Handle to the disable-iteration timer. */
     318    TMTIMERHANDLE           hTimer;
     319    /** Set if hTimer is armed. */
     320    bool volatile           fTimerArmed;
     321    /** Unique name for the the disable-iteration timer.  */
     322    char                    szTimerName[23];
     323
    316324#ifdef VBOX_WITH_STATISTICS
    317325    /** Statistics for the statistics manager (STAM). */
     
    336344static void drvAudioStreamFree(PDRVAUDIOSTREAM pStream);
    337345static int drvAudioStreamUninitInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx);
    338 static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx);
     346static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, bool fWorkMixBuf);
     347static int drvAudioStreamPlayLocked(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, uint32_t *pcFramesPlayed);
    339348static void drvAudioStreamDropInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx);
    340349static void drvAudioStreamResetInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx);
     
    651660                    LogFunc(("[%s] Pending disable/pause\n", pStreamEx->Core.szName));
    652661                    pStreamEx->Core.fStatus |= PDMAUDIOSTREAMSTS_FLAGS_PENDING_DISABLE;
     662
     663                    /* Schedule a follow up timer to the pending-disable state.  We cannot rely
     664                       on the device to provide further callouts to finish the state transition.
     665                       10ms is taking out of thin air and may be too course grained, we should
     666                       really consider the amount of unplayed buffer in the backend and what not... */
     667                    if (!pThis->fTimerArmed)
     668                    {
     669                        LogFlowFunc(("Arming emergency pending-disable hack...\n"));
     670                        int rc2 = PDMDrvHlpTimerSetMillies(pThis->pDrvIns, pThis->hTimer, 10 /*ms*/);
     671                        AssertRC(rc2);
     672                        pThis->fTimerArmed = true;
     673                    }
    653674                }
    654675
     
    730751        return VINF_SUCCESS;
    731752
    732     int rc = VINF_SUCCESS;
    733753
    734754    /*
     
    753773                                                              PDMAudioDirGetName(pStreamEx->Core.enmDir),
    754774                                                              fEnabled ? "enabled" : "disabled"));
     775    int rc = VINF_SUCCESS;
    755776    switch (enmStreamCmd)
    756777    {
     
    11801201    AssertRCReturn(rc, rc);
    11811202
    1182     rc = drvAudioStreamIterateInternal(pThis, pStreamEx);
     1203    rc = drvAudioStreamIterateInternal(pThis, pStreamEx, false /*fWorkMixBuf*/); /** @todo r=bird: why didn't it work the mixing buffer initially.  We can probably set this to true...  It may cause repeat work though. */
    11831204
    11841205    RTCritSectLeave(&pThis->CritSect);
     
    12641285/**
    12651286 * Does one iteration of an audio stream.
     1287 *
    12661288 * This function gives the backend the chance of iterating / altering data and
    12671289 * does the actual mixing between the guest <-> host mixing buffers.
     
    12701292 * @param   pThis       Pointer to driver instance.
    12711293 * @param   pStreamEx   Stream to iterate.
    1272  */
    1273 static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx)
     1294 * @param   fWorkMixBuf Push data from the mixing buffer to the backend.
     1295 * @todo    r=bird: Don't know why the default behavior isn't to push data into
     1296 *          the backend...  We'll never get out of the pending-disable state if
     1297 *          the mixing buffer doesn't empty out.
     1298 */
     1299static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, bool fWorkMixBuf)
    12741300{
    12751301    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     
    13081334            /* No audio frames to transfer from guest to host (anymore)?
    13091335             * Then try closing this stream if marked so in the next block. */
    1310             const uint32_t cFramesLive = AudioMixBufLive(&pStreamEx->Host.MixBuf);
     1336            uint32_t cFramesLive = AudioMixBufLive(&pStreamEx->Host.MixBuf);
     1337            if (cFramesLive && fWorkMixBuf)
     1338            {
     1339                uint32_t cIgnored = 0;
     1340                drvAudioStreamPlayLocked(pThis, pStreamEx, &cIgnored);
     1341
     1342                cFramesLive = AudioMixBufLive(&pStreamEx->Host.MixBuf);
     1343            }
     1344
    13111345            fTryClosePending = cFramesLive == 0;
    13121346            Log3Func(("[%s] fTryClosePending=%RTbool, cFramesLive=%RU32\n", pStreamEx->Core.szName, fTryClosePending, cFramesLive));
     
    13581392
    13591393    return rc;
     1394}
     1395
     1396/**
     1397 * @callback_method_impl{FNTMTIMERDRV}
     1398 */
     1399static DECLCALLBACK(void) drvAudioEmergencyIterateTimer(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, void *pvUser)
     1400{
     1401    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
     1402    RT_NOREF(hTimer, pvUser);
     1403    RTCritSectEnter(&pThis->CritSect);
     1404
     1405    /*
     1406     * Iterate any stream with the pending-disable flag set.
     1407     */
     1408    uint32_t        cMilliesToNext = 0;
     1409    PDRVAUDIOSTREAM pStreamEx, pStreamExNext;
     1410    RTListForEachSafe(&pThis->lstStreams, pStreamEx, pStreamExNext, DRVAUDIOSTREAM, ListEntry)
     1411    {
     1412        if (   pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC
     1413            && pStreamEx->Core.cRefs >= 1)
     1414        {
     1415            if (pStreamEx->Core.fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_DISABLE)
     1416            {
     1417                drvAudioStreamIterateInternal(pThis, pStreamEx, true /*fWorkMixBuf*/);
     1418
     1419                if (pStreamEx->Core.fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_DISABLE)
     1420                    cMilliesToNext = 10;
     1421            }
     1422        }
     1423    }
     1424
     1425    /*
     1426     * Re-arm the timer if we still got streams in the pending state.
     1427     */
     1428    if (cMilliesToNext)
     1429    {
     1430        pThis->fTimerArmed = true;
     1431        PDMDrvHlpTimerSetMillies(pDrvIns, pThis->hTimer, cMilliesToNext);
     1432    }
     1433    else
     1434        pThis->fTimerArmed = false;
     1435
     1436    RTCritSectLeave(&pThis->CritSect);
    13601437}
    13611438
     
    38333910                                 STAMUNIT_NS_PER_CALL, "Profiling of output data processing.");
    38343911#endif
     3912
     3913    /*
     3914     * Create a timer to do finish closing output streams in PENDING_DISABLE state.
     3915     *
     3916     * The device won't call us again after it has disabled a the stream and this is
     3917     * a real problem for truely cyclic buffer backends like DSound which will just
     3918     * continue to loop and loop if not stopped.
     3919     */
     3920    RTStrPrintf(pThis->szTimerName, sizeof(pThis->szTimerName), "AudioIterate-%u", pDrvIns->iInstance);
     3921    rc = PDMDrvHlpTMTimerCreate(pDrvIns, TMCLOCK_VIRTUAL, drvAudioEmergencyIterateTimer, NULL /*pvUser*/,
     3922                                0 /*fFlags*/, pThis->szTimerName, &pThis->hTimer);
     3923    AssertRCReturn(rc, rc);
    38353924
    38363925    /*
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