VirtualBox

Changeset 87159 in vbox


Ignore:
Timestamp:
Jan 4, 2021 11:38:37 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
142072
Message:

Audio: Enable/disable streams using PDMIAUDIOCONNECTOR::pfnStreamControl() instead of PDMIAUDIOCONNECTOR::pfnEnable(). bugref:9882

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/pdmaudioifs.h

    r86565 r87159  
    13921392     * Associated input streams then return silence when read from those.
    13931393     *
     1394     * Warning: Use this function carefully, as this could violate / run against the (global) VM settings. See #9882.
     1395     *
    13941396     * @returns VBox status code.
    13951397     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
  • trunk/src/VBox/Devices/Audio/AudioMixer.cpp

    r82968 r87159  
    15321532    int rc;
    15331533
    1534     if (pSink->In.pStreamRecSource) /* First, disable old recording source, if any set. */
    1535     {
    1536         const PPDMIAUDIOCONNECTOR pConn = pSink->In.pStreamRecSource->pConn;
    1537         AssertPtr(pConn);
    1538         rc = pConn->pfnEnable(pConn, PDMAUDIODIR_IN, false /* Disable */);
     1534    /*
     1535     * Warning: Do *not* use pfnConn->pfnEnable() for enabling/disabling streams here, as this will unconditionally (re-)enable
     1536     *          streams, which would violate / run against the (global) VM settings. See #9882.
     1537     */
     1538
     1539    /* Get pointers of current recording source to make code easier to read below. */
     1540    PAUDMIXSTREAM       pCurRecSrc       = pSink->In.pStreamRecSource; /* Can be NULL. */
     1541    PPDMIAUDIOCONNECTOR pCurRecSrcConn   = NULL;
     1542    PPDMAUDIOSTREAM     pCurRecSrcStream = NULL;
     1543
     1544    if (pCurRecSrc) /* First, disable old recording source, if any is set. */
     1545    {
     1546        pCurRecSrcConn   = pSink->In.pStreamRecSource->pConn;
     1547        AssertPtrReturn(pCurRecSrcConn, VERR_INVALID_POINTER);
     1548        pCurRecSrcStream = pCurRecSrc->pStream;
     1549        AssertPtrReturn(pCurRecSrcStream, VERR_INVALID_POINTER);
     1550
     1551        rc = pCurRecSrcConn->pfnStreamControl(pCurRecSrcConn, pCurRecSrcStream, PDMAUDIOSTREAMCMD_DISABLE);
    15391552    }
    15401553    else
     
    15481561            AssertMsg(pStream->pStream->enmDir == PDMAUDIODIR_IN, ("Specified stream is not an input stream\n"));
    15491562            AssertPtr(pStream->pConn);
    1550             rc = pStream->pConn->pfnEnable(pStream->pConn, PDMAUDIODIR_IN, true /* Enable */);
     1563            rc = pStream->pConn->pfnStreamControl(pStream->pConn, pStream->pStream, PDMAUDIOSTREAMCMD_ENABLE);
    15511564            if (RT_SUCCESS(rc))
    1552                 pSink->In.pStreamRecSource = pStream;
    1553             else if (pSink->In.pStreamRecSource) /* Stay with the current recording source (if any) and re-enable it. */
    15541565            {
    1555                 const PPDMIAUDIOCONNECTOR pConn = pSink->In.pStreamRecSource->pConn;
    1556                 AssertPtr(pConn);
    1557                 rc = pConn->pfnEnable(pConn, PDMAUDIODIR_IN, true /* Enable */);
     1566                pCurRecSrc = pStream;
    15581567            }
     1568            else if (pCurRecSrc) /* Stay with the current recording source (if any) and re-enable it. */
     1569            {
     1570                rc = pCurRecSrcConn->pfnStreamControl(pCurRecSrcConn, pCurRecSrcStream, PDMAUDIOSTREAMCMD_ENABLE);
     1571            }
    15591572        }
    15601573        else
    1561             pSink->In.pStreamRecSource = NULL; /* Unsetting, see audioMixerSinkRemoveStreamInternal. */
    1562     }
     1574            pCurRecSrc = NULL; /* Unsetting, see audioMixerSinkRemoveStreamInternal. */
     1575    }
     1576
     1577    /* Invalidate pointers. */
     1578    pSink->In.pStreamRecSource = pCurRecSrc;
    15631579
    15641580    LogFunc(("[%s] Recording source is now '%s', rc=%Rrc\n",
  • trunk/src/VBox/Devices/Audio/DrvAudio.cpp

    r86595 r87159  
    448448        return VINF_SUCCESS;
    449449
    450     LogRel2(("Audio: %s stream '%s'\n", DrvAudioHlpStreamCmdToStr(enmStreamCmd), pStream->szName));
    451 
    452450    int rc = VINF_SUCCESS;
    453451
     452    /*
     453     * Whether to propagate commands down to the backend.
     454     *
     455     * This is needed for critical operations like recording audio if audio input is disabled on a per-driver level.
     456     *
     457     * Note that not all commands will be covered by this, such as operations like stopping, draining and droppping,
     458     * which are considered uncritical and sometimes even are required for certain backends (like DirectSound on Windows).
     459     *
     460     * The actual stream state will be untouched to not make the state machine handling more complicated than
     461     * it already is.
     462     *
     463     * See #9882.
     464     */
     465    const bool fEnabled =    (   pStream->enmDir == PDMAUDIODIR_IN
     466                              && pThis->In.fEnabled)
     467                          || (   pStream->enmDir == PDMAUDIODIR_OUT
     468                              && pThis->Out.fEnabled);
     469
     470    LogRel2(("Audio: %s stream '%s' in backend (%s is %s)\n", DrvAudioHlpStreamCmdToStr(enmStreamCmd), pStream->szName,
     471                                                              DrvAudioHlpAudDirToStr(pStream->enmDir),
     472                                                              fEnabled ? "enabled" : "disabled"));
    454473    switch (enmStreamCmd)
    455474    {
    456475        case PDMAUDIOSTREAMCMD_ENABLE:
    457476        {
    458             rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStream->pvBackend, PDMAUDIOSTREAMCMD_ENABLE);
     477            if (fEnabled)
     478                rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStream->pvBackend, PDMAUDIOSTREAMCMD_ENABLE);
    459479            break;
    460480        }
     
    468488        case PDMAUDIOSTREAMCMD_PAUSE:
    469489        {
    470             rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStream->pvBackend, PDMAUDIOSTREAMCMD_PAUSE);
     490            if (fEnabled) /* Needed, as resume below also is being checked for. */
     491                rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStream->pvBackend, PDMAUDIOSTREAMCMD_PAUSE);
    471492            break;
    472493        }
     
    474495        case PDMAUDIOSTREAMCMD_RESUME:
    475496        {
    476             rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStream->pvBackend, PDMAUDIOSTREAMCMD_RESUME);
     497            if (fEnabled)
     498                rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStream->pvBackend, PDMAUDIOSTREAMCMD_RESUME);
    477499            break;
    478500        }
     
    939961    do
    940962    {
    941         if (   !pThis->Out.fEnabled
    942             || !DrvAudioHlpStreamStatusIsReady(pStream->fStatus))
     963        if (!DrvAudioHlpStreamStatusIsReady(pStream->fStatus))
    943964        {
    944965            rc = VERR_AUDIO_STREAM_NOT_READY;
     966            break;
     967        }
     968
     969        /* If output is disabled on a per-driver level, send data to the bit bucket instead. See #9882. */
     970        if (!pThis->Out.fEnabled)
     971        {
     972            fToBitBucket = true;
    945973            break;
    946974        }
     
    23902418    do
    23912419    {
    2392         if (   !pThis->In.fEnabled
    2393             || !DrvAudioHlpStreamStatusCanRead(pStream->fStatus))
    2394         {
    2395             rc = VERR_AUDIO_STREAM_NOT_READY;
    2396             break;
    2397         }
    2398 
    2399         /*
    2400          * Read from the parent buffer (that is, the guest buffer) which
    2401          * should have the audio data in the format the guest needs.
    2402          */
    24032420        uint32_t cfReadTotal = 0;
    24042421
    24052422        const uint32_t cfBuf = AUDIOMIXBUF_B2F(&pStream->Guest.MixBuf, cbBuf);
    24062423
    2407         uint32_t cfToRead = RT_MIN(cfBuf, AudioMixBufLive(&pStream->Guest.MixBuf));
    2408         while (cfToRead)
    2409         {
    2410             uint32_t cfRead;
    2411             rc = AudioMixBufAcquireReadBlock(&pStream->Guest.MixBuf,
    2412                                              (uint8_t *)pvBuf + AUDIOMIXBUF_F2B(&pStream->Guest.MixBuf, cfReadTotal),
    2413                                              AUDIOMIXBUF_F2B(&pStream->Guest.MixBuf, cfToRead), &cfRead);
    2414             if (RT_FAILURE(rc))
     2424        if (pThis->In.fEnabled) /* Input for this audio driver enabled? See #9822. */
     2425        {
     2426            if (!DrvAudioHlpStreamStatusCanRead(pStream->fStatus))
     2427            {
     2428                rc = VERR_AUDIO_STREAM_NOT_READY;
    24152429                break;
     2430            }
     2431
     2432            /*
     2433             * Read from the parent buffer (that is, the guest buffer) which
     2434             * should have the audio data in the format the guest needs.
     2435             */
     2436            uint32_t cfToRead = RT_MIN(cfBuf, AudioMixBufLive(&pStream->Guest.MixBuf));
     2437            while (cfToRead)
     2438            {
     2439                uint32_t cfRead;
     2440                rc = AudioMixBufAcquireReadBlock(&pStream->Guest.MixBuf,
     2441                                                 (uint8_t *)pvBuf + AUDIOMIXBUF_F2B(&pStream->Guest.MixBuf, cfReadTotal),
     2442                                                 AUDIOMIXBUF_F2B(&pStream->Guest.MixBuf, cfToRead), &cfRead);
     2443                if (RT_FAILURE(rc))
     2444                    break;
    24162445
    24172446#ifdef VBOX_WITH_STATISTICS
    2418             const uint32_t cbRead = AUDIOMIXBUF_F2B(&pStream->Guest.MixBuf, cfRead);
    2419 
    2420             STAM_COUNTER_ADD(&pThis->Stats.TotalBytesRead,       cbRead);
    2421 
    2422             STAM_COUNTER_ADD(&pStream->In.Stats.TotalFramesRead, cfRead);
    2423             STAM_COUNTER_INC(&pStream->In.Stats.TotalTimesRead);
     2447                const uint32_t cbRead = AUDIOMIXBUF_F2B(&pStream->Guest.MixBuf, cfRead);
     2448
     2449                STAM_COUNTER_ADD(&pThis->Stats.TotalBytesRead,       cbRead);
     2450
     2451                STAM_COUNTER_ADD(&pStream->In.Stats.TotalFramesRead, cfRead);
     2452                STAM_COUNTER_INC(&pStream->In.Stats.TotalTimesRead);
    24242453#endif
    2425             Assert(cfToRead >= cfRead);
    2426             cfToRead -= cfRead;
    2427 
    2428             cfReadTotal += cfRead;
    2429 
    2430             AudioMixBufReleaseReadBlock(&pStream->Guest.MixBuf, cfRead);
    2431         }
    2432 
    2433         if (cfReadTotal)
    2434         {
    2435             if (pThis->In.Cfg.Dbg.fEnabled)
    2436                 DrvAudioHlpFileWrite(pStream->In.Dbg.pFileStreamRead,
    2437                                      pvBuf, AUDIOMIXBUF_F2B(&pStream->Guest.MixBuf, cfReadTotal), 0 /* fFlags */);
    2438 
    2439             AudioMixBufFinish(&pStream->Guest.MixBuf, cfReadTotal);
     2454                Assert(cfToRead >= cfRead);
     2455                cfToRead -= cfRead;
     2456
     2457                cfReadTotal += cfRead;
     2458
     2459                AudioMixBufReleaseReadBlock(&pStream->Guest.MixBuf, cfRead);
     2460            }
     2461
     2462            if (cfReadTotal)
     2463            {
     2464                if (pThis->In.Cfg.Dbg.fEnabled)
     2465                    DrvAudioHlpFileWrite(pStream->In.Dbg.pFileStreamRead,
     2466                                         pvBuf, AUDIOMIXBUF_F2B(&pStream->Guest.MixBuf, cfReadTotal), 0 /* fFlags */);
     2467
     2468                AudioMixBufFinish(&pStream->Guest.MixBuf, cfReadTotal);
     2469            }
    24402470        }
    24412471
     
    27192749                fEnable ? "Enabling" : "Disabling", enmDir == PDMAUDIODIR_IN ? "input" : "output", pThis->szName));
    27202750
     2751        /* Update the status first, as this will be checked for in drvAudioStreamControlInternalBackend() below. */
     2752        *pfEnabled = fEnable;
     2753
    27212754        PPDMAUDIOSTREAM pStream;
    27222755        RTListForEach(&pThis->lstStreams, pStream, PDMAUDIOSTREAM, Node)
     
    27252758                continue;
    27262759
    2727             int rc2 = drvAudioStreamControlInternal(pThis, pStream,
    2728                                                     fEnable ? PDMAUDIOSTREAMCMD_ENABLE : PDMAUDIOSTREAMCMD_DISABLE);
     2760            /* Note: Only enable / disable the backend, do *not* change the stream's internal status.
     2761             *       Callers (device emulation, mixer, ...) from outside will not see any status or behavior change,
     2762             *       to not confuse the rest of the state machine.
     2763             *
     2764             *       When disabling:
     2765             *          - playing back audo data would go to /dev/null
     2766             *          - recording audio data would return silence instead
     2767             *
     2768             * See #9882.
     2769             */
     2770            int rc2 = drvAudioStreamControlInternalBackend(pThis, pStream,
     2771                                                           fEnable ? PDMAUDIOSTREAMCMD_ENABLE : PDMAUDIOSTREAMCMD_DISABLE);
    27292772            if (RT_FAILURE(rc2))
    27302773            {
     
    27432786            /* Keep going. */
    27442787        }
    2745 
    2746         *pfEnabled = fEnable;
    27472788    }
    27482789
     
    28642905    uint32_t cbReadable = 0;
    28652906
     2907    /* All input streams for this driver disabled? See #9882. */
     2908    const bool fDisabled = !pThis->In.fEnabled;
     2909
    28662910    if (   pThis->pHostDrvAudio
    2867         && DrvAudioHlpStreamStatusCanRead(pStream->fStatus))
     2911        && (   DrvAudioHlpStreamStatusCanRead(pStream->fStatus)
     2912            || fDisabled)
     2913       )
    28682914    {
    28692915        const uint32_t cfReadable = AudioMixBufLive(&pStream->Guest.MixBuf);
     
    28812927             * Reading the actual data from a stream then will return silence then.
    28822928             */
    2883             if (!DrvAudioHlpStreamStatusCanRead(
    2884                 pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pStream->pvBackend)))
     2929            if (  !DrvAudioHlpStreamStatusCanRead(
     2930                      pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pStream->pvBackend)
     2931                || fDisabled))
    28852932            {
    28862933                cbReadable = DrvAudioHlpNanoToBytes(RTTimeNanoTS() - pStream->tsLastReadWrittenNs,
    28872934                                                    &pStream->Host.Cfg.Props);
    2888                 Log3Func(("[%s] Backend stream not ready, returning silence\n", pStream->szName));
     2935                Log3Func(("[%s] Backend stream not ready or driver has disabled audio input, returning silence\n", pStream->szName));
    28892936            }
    28902937        }
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