VirtualBox

Ignore:
Timestamp:
Jan 4, 2021 11:38:37 AM (4 years ago)
Author:
vboxsync
Message:

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette