VirtualBox

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


Ignore:
Timestamp:
Jan 13, 2023 1:12:57 PM (2 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
155203
Message:

Audio/DrvAudio: Implemented ability to dynamically destroy and re-create audio backend streams when disabling audio streams or on a device reset. Requires DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION to be set (disabled by default for now). bugref:9558

File:
1 edited

Legend:

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

    r96407 r98075  
    9999
    100100/** @} */
     101
     102/**
     103 * Experimental code for destroying all streams in a disabled direction rather
     104 * than just disabling them.
     105
     106 * Disabled by default for non-Doxygen builds for now.
     107 */
     108#if defined(DOXYGEN_RUNNING) || 0
     109# define DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION
     110#endif
    101111
    102112
     
    432442static int drvAudioStreamControlInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, PDMAUDIOSTREAMCMD enmStreamCmd);
    433443static int drvAudioStreamUninitInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx);
     444#ifdef DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION
     445static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx);
     446static int drvAudioStreamReInitInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx);
     447#endif
    434448static uint32_t drvAudioStreamRetainInternal(PDRVAUDIOSTREAM pStreamEx);
    435449static uint32_t drvAudioStreamReleaseInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, bool fMayDestroy);
     
    597611    if (pThis->pHostDrvAudio)
    598612    {
    599         PDMHOSTAUDIOSTREAMSTATE enmState = pThis->pHostDrvAudio->pfnStreamGetState(pThis->pHostDrvAudio, pStreamEx->pBackend);
    600         Log9Func(("%s: %s\n", pStreamEx->Core.Cfg.szName, PDMHostAudioStreamStateGetName(enmState) ));
    601         Assert(   enmState > PDMHOSTAUDIOSTREAMSTATE_INVALID
    602                && enmState < PDMHOSTAUDIOSTREAMSTATE_END
    603                && (enmState != PDMHOSTAUDIOSTREAMSTATE_DRAINING || pStreamEx->Core.Cfg.enmDir == PDMAUDIODIR_OUT));
    604         return enmState;
     613        /* Don't call if the backend wasn't created for this stream (disabled). */
     614        if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_CREATED)
     615        {
     616            AssertPtrReturn(pThis->pHostDrvAudio->pfnStreamGetState, PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING);
     617            PDMHOSTAUDIOSTREAMSTATE enmState = pThis->pHostDrvAudio->pfnStreamGetState(pThis->pHostDrvAudio, pStreamEx->pBackend);
     618            Log9Func(("%s: %s\n", pStreamEx->Core.Cfg.szName, PDMHostAudioStreamStateGetName(enmState) ));
     619            Assert(   enmState > PDMHOSTAUDIOSTREAMSTATE_INVALID
     620                   && enmState < PDMHOSTAUDIOSTREAMSTATE_END
     621                   && (enmState != PDMHOSTAUDIOSTREAMSTATE_DRAINING || pStreamEx->Core.Cfg.enmDir == PDMAUDIODIR_OUT));
     622            return enmState;
     623        }
    605624    }
    606625    Log9Func(("%s: not-working\n", pStreamEx->Core.Cfg.szName));
     
    843862    {
    844863        LogRel(("Audio: %s %s for driver '%s'\n",
    845                 fEnable ? "Enabling" : "Disabling", enmDir == PDMAUDIODIR_IN ? "input" : "output", pThis->BackendCfg.szName));
     864                fEnable ? "Enabling" : "Disabling", PDMAudioDirGetName(enmDir), pThis->BackendCfg.szName));
    846865
    847866        /*
     
    859878         * only silence.  This means pStreamEx->fStatus holds the nominal status
    860879         * and we'll use it to restore the operation.  (See also @bugref{9882}.)
     880         *
     881         * The DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION build time define
     882         * controls how this is implemented.
    861883         */
    862884        PDRVAUDIOSTREAM pStreamEx;
    863885        RTListForEach(&pThis->LstStreams, pStreamEx, DRVAUDIOSTREAM, ListEntry)
    864886        {
     887            /** @todo duplex streams   */
    865888            if (pStreamEx->Core.Cfg.enmDir == enmDir)
    866889            {
     
    873896                    pStreamEx->Core.fWarningsShown &= ~PDMAUDIOSTREAM_WARN_FLAGS_DISABLED;
    874897
     898#ifdef DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION
     899                /*
     900                 * When enabling, we must make sure the stream has been created with the
     901                 * backend before enabling and maybe pausing it. When disabling we must
     902                 * destroy the stream. Paused includes enabled, as does draining, but we
     903                 * only want the former.
     904                 */
     905#else
    875906                /*
    876907                 * We don't need to do anything unless the stream is enabled.
    877908                 * Paused includes enabled, as does draining, but we only want the former.
    878909                 */
     910#endif
    879911                uint32_t const fStatus = pStreamEx->fStatus;
     912
     913#ifndef DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION
    880914                if (fStatus & PDMAUDIOSTREAM_STS_ENABLED)
     915#endif
    881916                {
    882917                    const char *pszOperation;
     
    886921                        if (!(fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE))
    887922                        {
    888                             /** @todo r=bird: We need to redo pre-buffering OR switch to
    889                              *        DRVAUDIOPLAYSTATE_PREBUF_SWITCHING playback mode when disabling
    890                              *        output streams.  The former is preferred if associated with
    891                              *        reporting the stream as INACTIVE. */
    892                             rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_ENABLE);
    893                             pszOperation = "enable";
    894                             if (RT_SUCCESS(rc2) && (fStatus & PDMAUDIOSTREAM_STS_PAUSED))
     923#ifdef DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION
     924                            /* The backend shouldn't have been created, so do that before enabling
     925                               and possibly pausing the stream. */
     926                            if (!(fStatus & PDMAUDIOSTREAM_STS_BACKEND_CREATED))
     927                                rc2 = drvAudioStreamReInitInternal(pThis, pStreamEx);
     928                            else
     929                                rc2 = VINF_SUCCESS;
     930                            pszOperation = "re-init";
     931                            if (RT_SUCCESS(rc2) && (fStatus & PDMAUDIOSTREAM_STS_ENABLED))
     932#endif
    895933                            {
    896                                 rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_PAUSE);
    897                                 pszOperation = "pause";
     934                                /** @todo r=bird: We need to redo pre-buffering OR switch to
     935                                 *        DRVAUDIOPLAYSTATE_PREBUF_SWITCHING playback mode when disabling
     936                                 *        output streams.  The former is preferred if associated with
     937                                 *        reporting the stream as INACTIVE. */
     938                                rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_ENABLE);
     939                                pszOperation = "enable";
     940                                if (RT_SUCCESS(rc2) && (fStatus & PDMAUDIOSTREAM_STS_PAUSED))
     941                                {
     942                                    rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_PAUSE);
     943                                    pszOperation = "pause";
     944                                }
    898945                            }
    899946                        }
     
    906953                    else
    907954                    {
     955#ifdef DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION
     956                        if (fStatus & PDMAUDIOSTREAM_STS_BACKEND_CREATED)
     957                            rc2 = drvAudioStreamDestroyInternalBackend(pThis, pStreamEx);
     958                        else
     959                            rc2 = VINF_SUCCESS;
     960                        pszOperation = "destroy";
     961#else
    908962                        rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE);
    909963                        pszOperation = "disable";
     964#endif
    910965                    }
    911966                    if (RT_FAILURE(rc2))
    912967                    {
    913968                        LogRel(("Audio: Failed to %s %s stream '%s': %Rrc\n",
    914                                 pszOperation, enmDir == PDMAUDIODIR_IN ? "input" : "output", pStreamEx->Core.Cfg.szName, rc2));
     969                                pszOperation, PDMAudioDirGetName(enmDir), pStreamEx->Core.Cfg.szName, rc2));
    915970                        if (RT_SUCCESS(rc))
    916971                            rc = rc2;  /** @todo r=bird: This isn't entirely helpful to the caller since we'll update the status
     
    12111266
    12121267/**
     1268 * Checks whether a given stream direction is enabled (permitted) or not.
     1269 *
     1270 * Currently there are only per-direction enabling/disabling of audio streams.
     1271 * This lets a user disabling input so it an untrusted VM cannot listen in
     1272 * without the user explicitly allowing it, or disable output so it won't
     1273 * disturb your and cannot communicate with other VMs or machines
     1274 *
     1275 * See @bugref{9882}.
     1276 *
     1277 * @retval  true if the stream configuration is enabled/allowed.
     1278 * @retval  false if not permitted.
     1279 * @param   pThis   Pointer to the DrvAudio instance data.
     1280 * @param   enmDir  The stream direction to check.
     1281 */
     1282DECLINLINE(bool) drvAudioStreamIsDirectionEnabled(PDRVAUDIO pThis, PDMAUDIODIR enmDir)
     1283{
     1284    switch (enmDir)
     1285    {
     1286        case PDMAUDIODIR_IN:
     1287            return pThis->In.fEnabled;
     1288        case PDMAUDIODIR_OUT:
     1289            return pThis->Out.fEnabled;
     1290        case PDMAUDIODIR_DUPLEX:
     1291            return pThis->Out.fEnabled && pThis->In.fEnabled;
     1292        default:
     1293            AssertFailedReturn(false);
     1294    }
     1295}
     1296
     1297
     1298/**
    12131299 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamConfigHint}
    12141300 */
     
    12281314        && pThis->pHostDrvAudio->pfnStreamConfigHint)
    12291315    {
    1230         if (pCfg->enmDir == PDMAUDIODIR_OUT ? pThis->Out.fEnabled : pThis->In.fEnabled)
     1316        if (drvAudioStreamIsDirectionEnabled(pThis, pCfg->enmDir))
    12311317        {
    12321318            /*
     
    14341520              ("Stream '%s' already initialized in backend\n", pStreamEx->Core.Cfg.szName));
    14351521
     1522#ifdef DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION
     1523    /*
     1524     * Check if the stream direction is enabled (permitted).
     1525     */
     1526    if (!drvAudioStreamIsDirectionEnabled(pThis, pStreamEx->Core.Cfg.enmDir))
     1527    {
     1528        LogFunc(("Stream direction is disbled, returning w/o doing anything\n"));
     1529        return VINF_SUCCESS;
     1530    }
     1531#endif
     1532
    14361533    /*
    14371534     * Adjust the stream config, applying defaults and any overriding settings.
     
    18431940                    if (!pStreamEx->fNeedAsyncInit)
    18441941                    {
    1845                         pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_BACKEND_READY;
     1942#ifdef DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION
     1943                        /* drvAudioStreamInitInternal returns success for disable stream directions w/o actually
     1944                           creating a backend, so we need to check that before marking the backend ready.. */
     1945                        if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_CREATED)
     1946#endif
     1947                            pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_BACKEND_READY;
    18461948                        PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus);
    18471949                    }
     
    24972599     *         finish initializing the stream, we'll update it about the stream state.
    24982600     */
    2499     bool const                     fDirEnabled     = pStreamEx->Core.Cfg.enmDir == PDMAUDIODIR_IN
    2500                                                    ? pThis->In.fEnabled : pThis->Out.fEnabled;
     2601    bool const                     fDirEnabled     = drvAudioStreamIsDirectionEnabled(pThis, pStreamEx->Core.Cfg.enmDir);
    25012602    PDMHOSTAUDIOSTREAMSTATE const  enmBackendState = drvAudioStreamGetBackendState(pThis, pStreamEx);
    25022603                                                     /* ^^^ (checks pThis->pHostDrvAudio != NULL too) */
     
    26202721    {
    26212722        case PDMAUDIOSTREAMCMD_ENABLE:
     2723#ifdef DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION
     2724            if (!(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_CREATED))
     2725            {
     2726                rc = drvAudioStreamReInitInternal(pThis, pStreamEx);
     2727                if (RT_FAILURE(rc))
     2728                    break;
     2729            }
     2730#endif /* DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION */
    26222731            if (!(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED))
    26232732            {
     
    27132822
    27142823        case PDMAUDIOSTREAMCMD_DISABLE:
     2824#ifndef DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION
    27152825            if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED)
    27162826            {
     
    27202830                    drvAudioStreamResetOnDisable(pStreamEx);
    27212831            }
     2832#else
     2833            if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_CREATED)
     2834                rc = drvAudioStreamDestroyInternalBackend(pThis, pStreamEx);
     2835#endif /* DRVAUDIO_WITH_STREAM_DESTRUCTION_IN_DISABLED_DIRECTION */
    27222836            break;
    27232837
     
    32543368        {
    32553369            if (   (fStrmStatus & PDMAUDIOSTREAM_STS_ENABLED)
    3256                 && (enmDir == PDMAUDIODIR_IN ? pThis->In.fEnabled : pThis->Out.fEnabled)
     3370                && drvAudioStreamIsDirectionEnabled(pThis, pStreamEx->Core.Cfg.enmDir)
    32573371                && (   enmBackendState == PDMHOSTAUDIOSTREAMSTATE_OKAY
    32583372                    || enmBackendState == PDMHOSTAUDIOSTREAMSTATE_DRAINING
     
    39694083    PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IHostAudioPort);
    39704084    AssertReturnVoid(enmDir == PDMAUDIODIR_IN || enmDir == PDMAUDIODIR_OUT);
    3971     LogRel(("Audio: The %s device for %s is changing.\n", enmDir == PDMAUDIODIR_IN ? "input" : "output", pThis->BackendCfg.szName));
     4085    LogRel(("Audio: The %s device for %s is changing.\n", PDMAudioDirGetName(enmDir), pThis->BackendCfg.szName));
    39724086
    39734087    /*
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