VirtualBox

Changeset 88819 in vbox for trunk/src/VBox


Ignore:
Timestamp:
May 3, 2021 10:26:28 AM (4 years ago)
Author:
vboxsync
Message:

Audio: Added geberuc asynchronous init to DrvAudio for use in WAS (and maybe others). bugref:9890

  • Added optional asynchronous init via a worker thread pool in DrvAudio (pfnStreamInitAsync).
  • Added interface for the backend to use the thread pool from the backend (pfnDoOnWorkerThread).
  • s/PDMIAUDIONOTIFYFROMHOST/PDMIHOSTAUDIOPORT/g
  • New BACKEND_READY state flag (a bit confusing wrt to INITIALIZED, but whatever).
  • Don't RESUME streams which aren't actually paused (on VM resume).
  • Restore the backend state correctly when the per-direction enable flag is changed in DrvAudio. Would enable the streams regardless of actual state.
  • Move more PDMAUDIOSTREAM members from the public structure and into the DRVAUDIOSTREAM.
  • ++
Location:
trunk/src/VBox
Files:
14 edited

Legend:

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

    r88763 r88819  
    3333#include <iprt/assert.h>
    3434#include <iprt/circbuf.h>
     35#include <iprt/req.h>
    3536#include <iprt/string.h>
     37#include <iprt/thread.h>
    3638#include <iprt/uuid.h>
    3739
     
    99101{
    100102    /** The publicly visible bit. */
    101     PDMAUDIOSTREAM      Core;
     103    PDMAUDIOSTREAM          Core;
    102104
    103105    /** Just an extra magic to verify that we allocated the stream rather than some
    104106     * faked up stuff from the device (DRVAUDIOSTREAM_MAGIC). */
    105     uintptr_t           uMagic;
     107    uintptr_t               uMagic;
    106108
    107109    /** List entry in DRVAUDIO::lstStreams. */
    108     RTLISTNODE          ListEntry;
     110    RTLISTNODE              ListEntry;
     111
     112    /** Number of references to this stream.
     113     *  Only can be destroyed when the reference count reaches 0. */
     114    uint32_t volatile       cRefs;
     115    /** Stream status - PDMAUDIOSTREAM_STS_XXX. */
     116    uint32_t                fStatus;
    109117
    110118    /** Data to backend-specific stream data.
     
    112120     *
    113121     *  That way the backends do not have access to the audio connector's data. */
    114     PPDMAUDIOBACKENDSTREAM pBackend;
     122    PPDMAUDIOBACKENDSTREAM  pBackend;
    115123
    116124    /** Do not use the mixing buffers (Guest::MixBuf, Host::MixBuf). */
    117     bool                fNoMixBufs;
    118     bool                afPadding[3];
     125    bool                    fNoMixBufs;
     126    /** Set if pfnStreamCreate returned VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED. */
     127    bool                    fNeedAsyncInit;
     128    bool                    afPadding[2];
    119129
    120130    /** Number of (re-)tries while re-initializing the stream. */
    121     uint32_t            cTriesReInit;
     131    uint32_t                cTriesReInit;
    122132
    123133    /** The backend status at the last play or capture call.
    124134     * This is used to detect state changes.  */
    125     uint32_t            fLastBackendStatus;
     135    uint32_t                fLastBackendStatus;
     136
     137    /** The pfnStreamInitAsync request handle. */
     138    PRTREQ                  hReqInitAsync;
    126139
    127140    /** The guest side of the stream. */
    128     DRVAUDIOSTREAMCTX   Guest;
     141    DRVAUDIOSTREAMCTX       Guest;
    129142    /** The host side of the stream. */
    130     DRVAUDIOSTREAMCTX   Host;
     143    DRVAUDIOSTREAMCTX       Host;
    131144
    132145
    133146    /** Timestamp (in ns) since last trying to re-initialize.
    134147     *  Might be 0 if has not been tried yet. */
    135     uint64_t            nsLastReInit;
     148    uint64_t                nsLastReInit;
    136149    /** Timestamp (in ns) since last iteration. */
    137     uint64_t            nsLastIterated;
     150    uint64_t                nsLastIterated;
    138151    /** Timestamp (in ns) since last playback / capture. */
    139     uint64_t            nsLastPlayedCaptured;
     152    uint64_t                nsLastPlayedCaptured;
    140153    /** Timestamp (in ns) since last read (input streams) or
    141154     *  write (output streams). */
    142     uint64_t            nsLastReadWritten;
     155    uint64_t                nsLastReadWritten;
    143156    /** Internal stream position (as per pfnStreamWrite/Read). */
    144     uint64_t            offInternal;
    145 
     157    uint64_t                offInternal;
    146158
    147159    /** Union for input/output specifics depending on enmDir. */
     
    275287    PDMIAUDIOCONNECTOR      IAudioConnector;
    276288    /** Interface used by the host backend. */
    277     PDMIAUDIONOTIFYFROMHOST IAudioNotifyFromHost;
     289    PDMIHOSTAUDIOPORT       IHostAudioPort;
    278290    /** Pointer to the driver instance. */
    279291    PPDMDRVINS              pDrvIns;
     
    309321    } Out;
    310322
     323    /** Request pool if the backend needs it for async stream creation. */
     324    RTREQPOOL               hReqPool;
     325
    311326    /** Handle to the disable-iteration timer. */
    312327    TMTIMERHANDLE           hTimer;
     
    338353static int drvAudioStreamControlInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, PDMAUDIOSTREAMCMD enmStreamCmd);
    339354static int drvAudioStreamUninitInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx);
     355static uint32_t drvAudioStreamReleaseInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, bool fMayDestroy);
    340356static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx);
    341357
    342 
    343 #ifdef LOG_ENABLED
    344 
    345358/** Buffer size for dbgAudioStreamStatusToStr.  */
    346 # define DRVAUDIO_STATUS_STR_MAX sizeof("INITIALIZED ENABLED PAUSED PENDING_DISABLED NEED_REINIT PREPARING_SWITCH 0x12345678")
     359# define DRVAUDIO_STATUS_STR_MAX sizeof("INITIALIZED ENABLED PAUSED PENDING_DISABLED NEED_REINIT BACKEND_READY PREPARING_SWITCH 0x12345678")
    347360
    348361/**
     
    368381        { RT_STR_TUPLE("PENDING_DISABLE "),  PDMAUDIOSTREAM_STS_PENDING_DISABLE  },
    369382        { RT_STR_TUPLE("NEED_REINIT "),      PDMAUDIOSTREAM_STS_NEED_REINIT      },
     383        { RT_STR_TUPLE("BACKEND_READY "),    PDMAUDIOSTREAM_STS_BACKEND_READY    },
    370384        { RT_STR_TUPLE("PREPARING_SWITCH "), PDMAUDIOSTREAM_STS_PREPARING_SWITCH },
    371385    };
     
    393407}
    394408
    395 #endif /* defined(LOG_ENABLED) */
    396409
    397410/**
     
    426439DECLINLINE(uint32_t) drvAudioStreamGetBackendStatus(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx)
    427440{
    428     Assert(pThis->pHostDrvAudio);
    429     uint32_t fBackendStatus = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pStreamEx->pBackend);
     441    uint32_t fBackendStatus = pThis->pHostDrvAudio
     442                            ? pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pStreamEx->pBackend)
     443                            : 0;
    430444    PDMAUDIOSTREAM_STS_ASSERT_VALID_BACKEND(fBackendStatus);
    431445    return fBackendStatus;
     
    518532    PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector);
    519533    AssertPtr(pThis);
    520 
     534    LogFlowFunc(("enmDir=%s fEnable=%d\n", PDMAudioDirGetName(enmDir), fEnable));
     535
     536    /*
     537     * Figure which status flag variable is being updated.
     538     */
    521539    bool *pfEnabled;
    522540    if (enmDir == PDMAUDIODIR_IN)
     
    527545        AssertFailedReturn(VERR_INVALID_PARAMETER);
    528546
     547    /*
     548     * Grab the driver wide lock and check it.  Ignore call if no change.
     549     */
    529550    int rc = RTCritSectEnter(&pThis->CritSect);
    530551    AssertRCReturn(rc, rc);
     
    535556                fEnable ? "Enabling" : "Disabling", enmDir == PDMAUDIODIR_IN ? "input" : "output", pThis->szName));
    536557
    537         /* Update the status first, as this will be checked for in drvAudioStreamControlInternalBackend() below. */
    538         *pfEnabled = fEnable;
    539 
     558        /*
     559         * When enabling, we must update flag before calling drvAudioStreamControlInternalBackend.
     560         */
     561        if (fEnable)
     562            *pfEnabled = true;
     563
     564        /*
     565         * Update the backend status for the streams in the given direction.
     566         *
     567         * The pThis->Out.fEnable / pThis->In.fEnable status flags only reflect in the
     568         * direction of the backend, drivers and devices above us in the chain does not
     569         * know about this.  When disabled playback goes to /dev/null and we capture
     570         * only silence.  This means pStreamEx->fStatus holds the nominal status
     571         * and we'll use it to restore the operation.  (See also @bugref{9882}.)
     572         */
    540573        PDRVAUDIOSTREAM pStreamEx;
    541574        RTListForEach(&pThis->lstStreams, pStreamEx, DRVAUDIOSTREAM, ListEntry)
    542575        {
    543             if (pStreamEx->Core.enmDir != enmDir) /* Skip unwanted streams. */
    544                 continue;
    545 
    546             /* Note: Only enable / disable the backend, do *not* change the stream's internal status.
    547              *       Callers (device emulation, mixer, ...) from outside will not see any status or behavior change,
    548              *       to not confuse the rest of the state machine.
    549              *
    550              *       When disabling:
    551              *          - playing back audo data would go to /dev/null
    552              *          - recording audio data would return silence instead
    553              *
    554              * See @bugref{9882}.
    555              */
    556             int rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx,
    557                                                            fEnable ? PDMAUDIOSTREAMCMD_ENABLE : PDMAUDIOSTREAMCMD_DISABLE);
    558             if (RT_FAILURE(rc2))
     576            if (pStreamEx->Core.enmDir == enmDir)
    559577            {
    560                 if (rc2 == VERR_AUDIO_STREAM_NOT_READY)
    561                     LogRel(("Audio: Stream '%s' not available\n", pStreamEx->Core.szName));
    562                 else
    563                     LogRel(("Audio: Failed to %s %s stream '%s', rc=%Rrc\n", fEnable ? "enable" : "disable",
    564                             enmDir == PDMAUDIODIR_IN ? "input" : "output", pStreamEx->Core.szName, rc2));
    565             }
    566             else
    567             {
    568                 /* When (re-)enabling a stream, clear the disabled warning bit again. */
     578                /*
     579                 * When (re-)enabling a stream, clear the disabled warning bit again.
     580                 */
    569581                if (fEnable)
    570582                    pStreamEx->Core.fWarningsShown &= ~PDMAUDIOSTREAM_WARN_FLAGS_DISABLED;
     583
     584                /*
     585                 * We don't need to do anything unless the stream is enabled.
     586                 * Paused includes enabled, as does draining, but we only want the former.
     587                 */
     588                uint32_t const fStatus = pStreamEx->fStatus;
     589                if (fStatus & PDMAUDIOSTREAM_STS_ENABLED)
     590                {
     591                    const char *pszOperation;
     592                    int         rc2;
     593                    if (fEnable)
     594                    {
     595                        if (!(fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE))
     596                        {
     597                            rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_ENABLE);
     598                            pszOperation = "enable";
     599                            if (RT_SUCCESS(rc2) && (fStatus & PDMAUDIOSTREAM_STS_PAUSED))
     600                            {
     601                                rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_PAUSE);
     602                                pszOperation = "pause";
     603                            }
     604                        }
     605                        else
     606                        {
     607                            rc2 = VINF_SUCCESS;
     608                            pszOperation = NULL;
     609                        }
     610                    }
     611                    else
     612                    {
     613                        rc2 = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE);
     614                        pszOperation = "disable";
     615                    }
     616                    if (RT_FAILURE(rc2))
     617                    {
     618                        LogRel(("Audio: Failed to %s %s stream '%s': %Rrc\n",
     619                                pszOperation, enmDir == PDMAUDIODIR_IN ? "input" : "output", pStreamEx->Core.szName, rc2));
     620                        if (RT_SUCCESS(rc))
     621                            rc = rc2;  /** @todo r=bird: This isn't entirely helpful to the caller since we'll update the status
     622                                        * regardless of the status code we return.  And anyway, there is nothing that can be done
     623                                        * about individual stream by the caller... */
     624                    }
     625                }
    571626            }
    572 
    573             if (RT_SUCCESS(rc))
    574                 rc = rc2;
    575 
    576             /* Keep going. */
    577         }
     627        }
     628
     629        /*
     630         * When disabling, we must update the status flag after the
     631         * drvAudioStreamControlInternalBackend(DISABLE) calls.
     632         */
     633        *pfEnabled = fEnable;
    578634    }
    579635
     
    840896 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamConfigHint}
    841897 */
     898static DECLCALLBACK(void) drvAudioStreamConfigHintWorker(PPDMIHOSTAUDIO pHostDrvAudio, PPDMAUDIOSTREAMCFG pCfg)
     899{
     900    LogFlowFunc(("pHostDrvAudio=%p pCfg=%p\n", pHostDrvAudio, pCfg));
     901    AssertPtrReturnVoid(pCfg);
     902    AssertPtrReturnVoid(pHostDrvAudio);
     903    AssertPtrReturnVoid(pHostDrvAudio->pfnStreamConfigHint);
     904
     905    pHostDrvAudio->pfnStreamConfigHint(pHostDrvAudio, pCfg);
     906    PDMAudioStrmCfgFree(pCfg);
     907    LogFlowFunc(("returns\n"));
     908}
     909
     910
     911/**
     912 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamConfigHint}
     913 */
    842914static DECLCALLBACK(void) drvAudioStreamConfigHint(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAMCFG pCfg)
    843915{
     
    863935            AssertLogRelRC(rc);
    864936            if (RT_SUCCESS(rc))
    865                 pThis->pHostDrvAudio->pfnStreamConfigHint(pThis->pHostDrvAudio, pCfg);
     937            {
     938                rc = VERR_CALLBACK_RETURN;
     939                if (pThis->BackendCfg.fFlags & PDMAUDIOBACKEND_F_ASYNC_HINT)
     940                {
     941                    PPDMAUDIOSTREAMCFG pDupCfg = PDMAudioStrmCfgDup(pCfg);
     942                    if (pDupCfg)
     943                    {
     944                        rc = RTReqPoolCallVoidNoWait(pThis->hReqPool, (PFNRT)drvAudioStreamConfigHintWorker,
     945                                                     2, pThis->pHostDrvAudio, pDupCfg);
     946                        if (RT_SUCCESS(rc))
     947                            LogFlowFunc(("Asynchronous call running on worker thread.\n"));
     948                        else
     949                            PDMAudioStrmCfgFree(pDupCfg);
     950                    }
     951                }
     952                if (RT_FAILURE_NP(rc))
     953                {
     954                    LogFlowFunc(("Doing synchronous call...\n"));
     955                    pThis->pHostDrvAudio->pfnStreamConfigHint(pThis->pHostDrvAudio, pCfg);
     956                }
     957            }
    866958        }
    867959        else
     
    872964
    873965    RTCritSectLeave(&pThis->CritSect);
     966}
     967
     968
     969/**
     970 * For performing PDMIHOSTAUDIO::pfnStreamInitAsync on a worker thread.
     971 *
     972 * @param   pThis       Pointer to the DrvAudio instance data.
     973 * @param   pStreamEx   The stream.  One reference for us to release.
     974 */
     975static DECLCALLBACK(void) drvAudioStreamInitAsync(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx)
     976{
     977    LogFlow(("pThis=%p pStreamEx=%p (%s)\n", pThis, pStreamEx->Core.szName));
     978
     979    /*
     980     * Do the init job.
     981     *
     982     * This critsect entering and leaving here isn't really necessary,
     983     * but well, I'm a bit paranoid, so sue me.
     984     */
     985    RTCritSectEnter(&pThis->CritSect);
     986    PPDMIHOSTAUDIO pIHostDrvAudio = pThis->pHostDrvAudio;
     987    RTCritSectLeave(&pThis->CritSect);
     988    AssertPtr(pIHostDrvAudio);
     989    int rc;
     990    bool fDestroyed;
     991    if (pIHostDrvAudio && pIHostDrvAudio->pfnStreamInitAsync)
     992    {
     993        fDestroyed = pStreamEx->cRefs <= 1;
     994        rc = pIHostDrvAudio->pfnStreamInitAsync(pIHostDrvAudio, pStreamEx->pBackend, fDestroyed);
     995        LogFlow(("pfnStreamInitAsync returns %Rrc (on %p, fDestroyed=%d)\n", rc, pStreamEx, fDestroyed));
     996    }
     997    else
     998    {
     999        fDestroyed = true;
     1000        rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
     1001    }
     1002
     1003    /*
     1004     * On success, update the backend on the stream status and mark it ready for business.
     1005     */
     1006    RTCritSectEnter(&pThis->CritSect);
     1007    if (RT_SUCCESS(rc) && !fDestroyed)
     1008    {
     1009
     1010        /*
     1011         * Update the backend state.
     1012         */
     1013        pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_BACKEND_READY; /* before the backend control call! */
     1014
     1015        if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED)
     1016        {
     1017            rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_ENABLE);
     1018            if (RT_SUCCESS(rc))
     1019            {
     1020                if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PAUSED)
     1021                {
     1022                    rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_PAUSE);
     1023                    if (RT_FAILURE(rc))
     1024                        LogRelMax(64, ("Audio: Failed to pause stream '%s' after initialization completed: %Rrc\n",
     1025                                       pStreamEx->Core.szName, rc));
     1026                }
     1027            }
     1028            else
     1029                LogRelMax(64, ("Audio: Failed to enable stream '%s' after initialization completed: %Rrc\n",
     1030                               pStreamEx->Core.szName, rc));
     1031        }
     1032
     1033        /*
     1034         * Modify the play state if output stream.
     1035         */
     1036        if (pStreamEx->Core.enmDir == PDMAUDIODIR_OUT)
     1037        {
     1038            DRVAUDIOPLAYSTATE const enmPlayState = pStreamEx->Out.enmPlayState;
     1039            switch (enmPlayState)
     1040            {
     1041                case DRVAUDIOPLAYSTATE_PREBUF:
     1042                case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING:
     1043                    break;
     1044                case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE:
     1045                    pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_COMMITTING;
     1046                    break;
     1047                case DRVAUDIOPLAYSTATE_NOPLAY:
     1048                    pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF;
     1049                    break;
     1050                case DRVAUDIOPLAYSTATE_PLAY:
     1051                case DRVAUDIOPLAYSTATE_PLAY_PREBUF:
     1052                case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING:
     1053                    AssertFailedBreak();
     1054                /* no default */
     1055                case DRVAUDIOPLAYSTATE_END:
     1056                case DRVAUDIOPLAYSTATE_INVALID:
     1057                    break;
     1058            }
     1059            LogFunc(("enmPlayState: %s -> %s\n", drvAudioPlayStateName(enmPlayState),
     1060                     drvAudioPlayStateName(pStreamEx->Out.enmPlayState) ));
     1061        }
     1062
     1063        /*
     1064         * Tweak the last backend status to asserting in
     1065         * drvAudioStreamPlayProcessBackendStateChange().
     1066         */
     1067        pStreamEx->fLastBackendStatus |=   drvAudioStreamGetBackendStatus(pThis, pStreamEx)
     1068                                         & PDMAUDIOSTREAM_STS_INITIALIZED;
     1069    }
     1070    /*
     1071     * Don't quite know what to do on failure...
     1072     */
     1073    else if (!fDestroyed)
     1074    {
     1075        LogRelMax(64, ("Audio: Failed to initialize stream '%s': %Rrc\n", pStreamEx->Core.szName, rc));
     1076    }
     1077
     1078    /*
     1079     * Release the request handle, must be done while inside the critical section.
     1080     */
     1081    if (pStreamEx->hReqInitAsync != NIL_RTREQ)
     1082    {
     1083        LogFlowFunc(("Releasing hReqInitAsync=%p\n", pStreamEx->hReqInitAsync));
     1084        RTReqRelease(pStreamEx->hReqInitAsync);
     1085        pStreamEx->hReqInitAsync = NIL_RTREQ;
     1086    }
     1087
     1088    RTCritSectLeave(&pThis->CritSect);
     1089
     1090    /*
     1091     * Release our stream reference.
     1092     */
     1093    uint32_t cRefs = drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/);
     1094    LogFlowFunc(("returns (fDestroyed=%d, cRefs=%u)\n", fDestroyed, cRefs)); RT_NOREF(cRefs);
    8741095}
    8751096
     
    8961117                                               PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    8971118{
    898     AssertMsg((pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_INITIALIZED) == 0,
     1119    AssertMsg((pStreamEx->fStatus & PDMAUDIOSTREAM_STS_INITIALIZED) == 0,
    8991120              ("Stream '%s' already initialized in backend\n", pStreamEx->Core.szName));
    9001121
     
    9221143     * Call the host driver to create the stream.
    9231144     */
    924     AssertPtr(pThis->pHostDrvAudio);
    925     if (pThis->pHostDrvAudio)
    926         rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pStreamEx->pBackend, pCfgReq, pCfgAcq);
     1145    AssertLogRelMsgReturn(RT_VALID_PTR(pThis->pHostDrvAudio), ("Audio: %p\n", pThis->pHostDrvAudio), VERR_PDM_NO_ATTACHED_DRIVER);
     1146    rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pStreamEx->pBackend, pCfgReq, pCfgAcq);
     1147    if (RT_SUCCESS(rc))
     1148    {
     1149        AssertLogRelReturn(pStreamEx->pBackend->uMagic  == PDMAUDIOBACKENDSTREAM_MAGIC, VERR_INTERNAL_ERROR_3);
     1150        AssertLogRelReturn(pStreamEx->pBackend->pStream == &pStreamEx->Core, VERR_INTERNAL_ERROR_3);
     1151
     1152        /* Must set the backend-initialized flag now or the backend won't be
     1153           destroyed (this used to be done at the end of this function, with
     1154           several possible early return paths before it). */
     1155        pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_INITIALIZED;
     1156
     1157        pStreamEx->fLastBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx);
     1158        PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus);
     1159    }
    9271160    else
    928         rc = VERR_PDM_NO_ATTACHED_DRIVER;
    929     if (RT_FAILURE(rc))
    9301161    {
    9311162        if (rc == VERR_NOT_SUPPORTED)
     
    9371168        return rc;
    9381169    }
    939     AssertLogRelReturn(pStreamEx->pBackend->uMagic  == PDMAUDIOBACKENDSTREAM_MAGIC, VERR_INTERNAL_ERROR_3);
    940     AssertLogRelReturn(pStreamEx->pBackend->pStream == &pStreamEx->Core, VERR_INTERNAL_ERROR_3);
     1170
     1171    /* Remember if we need to call pfnStreamInitAsync. */
     1172    pStreamEx->fNeedAsyncInit = rc == VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED;
     1173    AssertStmt(rc != VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED || pThis->pHostDrvAudio->pfnStreamInitAsync != NULL,
     1174               pStreamEx->fNeedAsyncInit = false);
     1175    Assert(rc != VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED || !(pStreamEx->fLastBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED));
    9411176
    9421177    /* Validate acquired configuration. */
     
    9831218                    ("Acquired pre-buffering size must be smaller or as big as the buffer size\n"),
    9841219                    VERR_INVALID_PARAMETER);
    985 
    986     pStreamEx->fLastBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx);
    987     pStreamEx->Core.fStatus      |= PDMAUDIOSTREAM_STS_INITIALIZED;
    988     PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus);
    9891220
    9901221    return VINF_SUCCESS;
     
    12951526        if (pStreamEx)
    12961527        {
    1297             /* Retrieve host driver name for easier identification. */
     1528            /* Make a unqiue stream name including the host (backend) driver name. */
    12981529            AssertPtr(pThis->pHostDrvAudio);
    1299             RTStrPrintf(pStreamEx->Core.szName, RT_ELEMENTS(pStreamEx->Core.szName), "[%s] %s",
    1300                         pThis->BackendCfg.szName, pCfgHost->szName[0] != '\0' ? pCfgHost->szName : "<Untitled>");
     1530            size_t cchName = RTStrPrintf(pStreamEx->Core.szName, RT_ELEMENTS(pStreamEx->Core.szName), "[%s] %s:0",
     1531                                         pThis->BackendCfg.szName, pCfgHost->szName[0] != '\0' ? pCfgHost->szName : "<Untitled>");
     1532            if (cchName < sizeof(pStreamEx->Core.szName))
     1533            {
     1534                for (uint32_t i = 0; i < 256; i++)
     1535                {
     1536                    bool fDone = true;
     1537                    PDRVAUDIOSTREAM pIt;
     1538                    RTListForEach(&pThis->lstStreams, pIt, DRVAUDIOSTREAM, ListEntry)
     1539                    {
     1540                        if (strcmp(pIt->Core.szName, pStreamEx->Core.szName) == 0)
     1541                        {
     1542                            RTStrPrintf(pStreamEx->Core.szName, RT_ELEMENTS(pStreamEx->Core.szName), "[%s] %s:%u",
     1543                                        pThis->BackendCfg.szName, pCfgHost->szName[0] != '\0' ? pCfgHost->szName : "<Untitled>",
     1544                                        i);
     1545                            fDone = false;
     1546                            break;
     1547                        }
     1548                    }
     1549                    if (fDone)
     1550                        break;
     1551                }
     1552            }
    13011553
    13021554            PPDMAUDIOBACKENDSTREAM pBackend = (PPDMAUDIOBACKENDSTREAM)(pStreamEx + 1);
     
    13071559            pStreamEx->Core.cbBackend   = (uint32_t)cbHstStrm;
    13081560            pStreamEx->fNoMixBufs       = RT_BOOL(fFlags & PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF);
     1561            pStreamEx->hReqInitAsync    = NIL_RTREQ;
    13091562            pStreamEx->uMagic           = DRVAUDIOSTREAM_MAGIC;
    13101563
     
    13161569            {
    13171570                /* Set initial reference counts. */
    1318                 pStreamEx->Core.cRefs = 1;
     1571                pStreamEx->cRefs = pStreamEx->fNeedAsyncInit ? 2 : 1;
    13191572
    13201573                /* Decrement the free stream counter. */
     
    13521605                    }
    13531606                }
     1607
     1608                /*
     1609                 * Kick off the asynchronous init.
     1610                 */
     1611                if (!pStreamEx->fNeedAsyncInit)
     1612                {
     1613                    pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_BACKEND_READY;
     1614                    PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus);
     1615                }
     1616                else
     1617                {
     1618                    int rc2 = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, &pStreamEx->hReqInitAsync,
     1619                                              RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
     1620                                              (PFNRT)drvAudioStreamInitAsync, 2, pThis, pStreamEx);
     1621                    LogFlowFunc(("hReqInitAsync=%p rc2=%Rrc\n", pStreamEx->hReqInitAsync, rc2));
     1622                    AssertRCStmt(rc2, drvAudioStreamInitAsync(pThis, pStreamEx));
     1623                }
    13541624            }
    13551625            else
     
    13911661    char szStreamSts[DRVAUDIO_STATUS_STR_MAX];
    13921662#endif
    1393     LogFunc(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->Core.fStatus)));
    1394 
    1395     if (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_INITIALIZED)
     1663    LogFunc(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus)));
     1664
     1665    if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_INITIALIZED)
    13961666    {
    13971667        AssertPtr(pStreamEx->pBackend);
     
    14021672            rc = pThis->pHostDrvAudio->pfnStreamDestroy(pThis->pHostDrvAudio, pStreamEx->pBackend);
    14031673
    1404         pStreamEx->Core.fStatus &= ~PDMAUDIOSTREAM_STS_INITIALIZED;
    1405         PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus);
     1674        pStreamEx->fStatus &= ~(PDMAUDIOSTREAM_STS_INITIALIZED | PDMAUDIOSTREAM_STS_BACKEND_READY);
     1675        PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus);
    14061676    }
    14071677
     
    14241694{
    14251695    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    1426     AssertMsgReturn(pStreamEx->Core.cRefs <= 1,
    1427                     ("Stream '%s' still has %RU32 references held when uninitializing\n", pStreamEx->Core.szName, pStreamEx->Core.cRefs),
     1696    AssertMsgReturn(pStreamEx->cRefs <= 1,
     1697                    ("Stream '%s' still has %RU32 references held when uninitializing\n", pStreamEx->Core.szName, pStreamEx->cRefs),
    14281698                    VERR_WRONG_ORDER);
    1429     LogFlowFunc(("[%s] cRefs=%RU32\n", pStreamEx->Core.szName, pStreamEx->Core.cRefs));
     1699    LogFlowFunc(("[%s] cRefs=%RU32\n", pStreamEx->Core.szName, pStreamEx->cRefs));
    14301700
    14311701    /*
     
    14541724    {
    14551725#ifdef LOG_ENABLED
    1456         if (pStreamEx->Core.fStatus != PDMAUDIOSTREAM_STS_NONE)
     1726        if (pStreamEx->fStatus != PDMAUDIOSTREAM_STS_NONE)
    14571727        {
    14581728            char szStreamSts[DRVAUDIO_STATUS_STR_MAX];
    14591729            LogFunc(("[%s] Warning: Still has %s set when uninitializing\n",
    1460                      pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->Core.fStatus)));
     1730                     pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus)));
    14611731        }
    14621732#endif
    1463         pStreamEx->Core.fStatus = PDMAUDIOSTREAM_STS_NONE;
     1733        pStreamEx->fStatus = PDMAUDIOSTREAM_STS_NONE;
    14641734    }
    14651735
     
    14961766
    14971767/**
    1498  * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamDestroy}
    1499  */
    1500 static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
    1501 {
    1502     PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector);
    1503     AssertPtr(pThis);
    1504 
    1505     if (!pStream)
    1506         return VINF_SUCCESS;
    1507     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    1508     PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream;   /* Note! Do not touch pStream after this! */
    1509     Assert(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC);
    1510     Assert(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC);
    1511     Assert(pStreamEx->pBackend && pStreamEx->pBackend->uMagic == PDMAUDIOBACKENDSTREAM_MAGIC);
    1512 
    1513     int rc = RTCritSectEnter(&pThis->CritSect);
    1514     AssertRCReturn(rc, rc);
    1515 
    1516     LogRel2(("Audio: Destroying stream '%s'\n", pStreamEx->Core.szName));
    1517 
    1518     LogFlowFunc(("[%s] cRefs=%RU32\n", pStreamEx->Core.szName, pStreamEx->Core.cRefs));
    1519     AssertMsg(pStreamEx->Core.cRefs <= 1, ("%u %s\n", pStreamEx->Core.cRefs, pStreamEx->Core.szName));
    1520     if (pStreamEx->Core.cRefs <= 1)
    1521     {
     1768 * Internal release function.
     1769 *
     1770 * @returns New reference count, UINT32_MAX if bad stream.
     1771 * @param   pThis           Pointer to the DrvAudio instance data.
     1772 * @param   pStreamEx       The stream to reference.
     1773 * @param   fMayDestroy     Whether the caller is allowed to implicitly destroy
     1774 *                          the stream or not.
     1775 */
     1776static uint32_t drvAudioStreamReleaseInternal(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, bool fMayDestroy)
     1777{
     1778    AssertPtrReturn(pStreamEx, UINT32_MAX);
     1779    AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, UINT32_MAX);
     1780    AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, UINT32_MAX);
     1781
     1782    uint32_t cRefs = ASMAtomicDecU32(&pStreamEx->cRefs);
     1783    if (cRefs != 0)
     1784        Assert(cRefs < _1K);
     1785    else if (fMayDestroy)
     1786    {
     1787/** @todo r=bird: Caching one stream in each direction for some time,
     1788 * depending on the time it took to create it.  drvAudioStreamCreate can use it
     1789 * if the configuration matches, otherwise it'll throw it away.  This will
     1790 * provide a general speedup independ of device (HDA used to do this, but
     1791 * doesn't) and backend implementation.  Ofc, the backend probably needs an
     1792 * opt-out here. */
     1793        int rc = RTCritSectEnter(&pThis->CritSect);
     1794        AssertRC(rc);
     1795
    15221796        rc = drvAudioStreamUninitInternal(pThis, pStreamEx);
    15231797        if (RT_SUCCESS(rc))
     
    15311805
    15321806            drvAudioStreamFree(pStreamEx);
    1533             pStreamEx = NULL;
    1534             pStream = NULL;
    15351807        }
    15361808        else
     1809        {
    15371810            LogRel(("Audio: Uninitializing stream '%s' failed with %Rrc\n", pStreamEx->Core.szName, rc));
     1811            /** @todo r=bird: What's the plan now? */
     1812        }
     1813
     1814        RTCritSectLeave(&pThis->CritSect);
    15381815    }
    15391816    else
    1540         rc = VERR_WRONG_ORDER;
     1817    {
     1818        cRefs = ASMAtomicIncU32(&pStreamEx->cRefs);
     1819        AssertFailed();
     1820    }
     1821
     1822    Log12Func(("returns %u (%s)\n", cRefs, cRefs > 0 ? pStreamEx->Core.szName : "destroyed"));
     1823    return cRefs;
     1824}
     1825
     1826
     1827/**
     1828 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamDestroy}
     1829 */
     1830static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
     1831{
     1832    PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector);
     1833    AssertPtr(pThis);
     1834
     1835    /* Ignore NULL streams. */
     1836    if (!pStream)
     1837        return VINF_SUCCESS;
     1838
     1839    PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream;   /* Note! Do not touch pStream after this! */
     1840    AssertPtrReturn(pStreamEx, VERR_INVALID_POINTER);
     1841    LogFlowFunc(("ENTER - %p %s\n", pStreamEx, pStreamEx->Core.szName));
     1842    AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC);
     1843    AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC);
     1844    AssertReturn(pStreamEx->pBackend && pStreamEx->pBackend->uMagic == PDMAUDIOBACKENDSTREAM_MAGIC, VERR_INVALID_MAGIC);
     1845
     1846    /*
     1847     * The main difference from a regular release is that this will disable
     1848     * (or drain if we could) the stream and we can cancel any pending
     1849     * pfnStreamInitAsync call.
     1850     */
     1851    int rc = RTCritSectEnter(&pThis->CritSect);
     1852    AssertRCReturn(rc, rc);
     1853
     1854    if (pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC)
     1855    {
     1856        if (pStreamEx->cRefs > 0 && pStreamEx->cRefs < UINT32_MAX / 4)
     1857        {
     1858            char szStatus[DRVAUDIO_STATUS_STR_MAX], szBackendStatus[DRVAUDIO_STATUS_STR_MAX];
     1859            LogRel2(("Audio: Destroying stream '%s': cRefs=%u; status: %s; backend: %s; hReqInitAsync=%p\n",
     1860                     pStreamEx->Core.szName, pStreamEx->cRefs, dbgAudioStreamStatusToStr(szStatus, pStreamEx->fStatus),
     1861                     dbgAudioStreamStatusToStr(szBackendStatus, drvAudioStreamGetBackendStatus(pThis, pStreamEx)),
     1862                     pStreamEx->hReqInitAsync));
     1863
     1864            /* Try cancel pending async init request and release the it. */
     1865            if (pStreamEx->hReqInitAsync != NIL_RTREQ)
     1866            {
     1867                Assert(pStreamEx->cRefs >= 2);
     1868                int rc2 = RTReqCancel(pStreamEx->hReqInitAsync);
     1869                if (RT_SUCCESS(rc2))
     1870                {
     1871                    LogFlowFunc(("Successfully cancelled pending pfnStreamInitAsync call (hReqInitAsync=%p).\n",
     1872                                 pStreamEx->hReqInitAsync));
     1873                    drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/);
     1874                }
     1875                else
     1876                {
     1877                    LogFlowFunc(("Failed to cancel pending pfnStreamInitAsync call (hReqInitAsync=%p): %Rrc\n",
     1878                                 pStreamEx->hReqInitAsync, rc2));
     1879                    Assert(rc2 == VERR_RT_REQUEST_STATE);
     1880                }
     1881
     1882                RTReqRelease(pStreamEx->hReqInitAsync);
     1883                pStreamEx->hReqInitAsync = NIL_RTREQ;
     1884            }
     1885
     1886            /* We don't really care about the status here as we'll release a reference regardless of the state. */
     1887            /** @todo can we somehow drain it instead? */
     1888            int rc2 = drvAudioStreamControlInternal(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE);
     1889            AssertRC(rc2);
     1890
     1891            drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/);
     1892        }
     1893        else
     1894            AssertLogRelMsgFailedStmt(("%p cRefs=%#x\n", pStreamEx, pStreamEx->cRefs), rc = VERR_CALLER_NO_REFERENCE);
     1895    }
     1896    else
     1897        AssertLogRelMsgFailedStmt(("%p uMagic=%#x\n", pStreamEx, pStreamEx->uMagic), rc = VERR_INVALID_MAGIC);
    15411898
    15421899    RTCritSectLeave(&pThis->CritSect);
     
    16001957     * Gather current stream status.
    16011958     */
    1602     const bool fIsEnabled = RT_BOOL(pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED); /* Stream is enabled? */
     1959    const bool fIsEnabled = RT_BOOL(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED); /* Stream is enabled? */
    16031960
    16041961/** @todo r=bird: this is retried a bit too indiscriminately for my taste ... */
     
    16251982    }
    16261983
     1984/** @todo r=bird: Why do we do the dropping and re-enabling of the stream
     1985 *        regardless of how the above went?  It'll overwrite any above
     1986 *        failures for starters... */
    16271987    /* Drop all old data. */
    16281988    drvAudioStreamDropInternal(pStreamEx);
     
    16311991     * Restore previous stream state.
    16321992     */
     1993    /** @todo this isn't taking PAUSED or PENDING_DISABLE into consideration.   */
    16331994    if (fIsEnabled)
    16341995        rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_ENABLE);
     
    16522013    AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC);
    16532014    AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC);
    1654     AssertReturn(pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT, VERR_INVALID_STATE);
     2015    AssertReturn(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT, VERR_INVALID_STATE);
    16552016    LogFlowFunc(("\n"));
    16562017
     
    16582019    AssertRCReturn(rc, rc);
    16592020
    1660     if (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT)
     2021    if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT)
    16612022    {
    16622023        const unsigned cMaxTries = 3; /** @todo Make this configurable? */
    16632024        const uint64_t tsNowNs   = RTTimeNanoTS();
     2025
     2026/** @todo r=bird: Must postpone if hReqInitAsync isn't NIL or cancellable. */
    16642027
    16652028        /* Throttle re-initializing streams on failure. */
     
    16912054            {
    16922055                /* Remove the pending re-init flag on success. */
    1693                 pStreamEx->Core.fStatus &= ~PDMAUDIOSTREAM_STS_NEED_REINIT;
    1694                 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus);
     2056                pStreamEx->fStatus &= ~PDMAUDIOSTREAM_STS_NEED_REINIT;
     2057                PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus);
    16952058            }
    16962059            else
     
    17122075                /* Don't try to re-initialize anymore and mark as disabled. */
    17132076                /** @todo should mark it as not-initialized too, shouldn't we?   */
    1714                 pStreamEx->Core.fStatus &= ~(PDMAUDIOSTREAM_STS_NEED_REINIT | PDMAUDIOSTREAM_STS_ENABLED);
    1715                 PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus);
     2077                pStreamEx->fStatus &= ~(PDMAUDIOSTREAM_STS_NEED_REINIT | PDMAUDIOSTREAM_STS_ENABLED);
     2078                PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus);
    17162079
    17172080                /* Note: Further writes to this stream go to / will be read from the bit bucket (/dev/null) from now on. */
     
    17222085        char szStreamSts[DRVAUDIO_STATUS_STR_MAX];
    17232086#endif
    1724         Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->Core.fStatus)));
     2087        Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus)));
    17252088    }
    17262089    else
     
    17372100
    17382101/**
     2102 * Internal retain function.
     2103 *
     2104 * @returns New reference count, UINT32_MAX if bad stream.
     2105 * @param   pStreamEx           The stream to reference.
     2106 */
     2107static uint32_t drvAudioStreamRetainInternal(PDRVAUDIOSTREAM pStreamEx)
     2108{
     2109    AssertPtrReturn(pStreamEx, UINT32_MAX);
     2110    AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, UINT32_MAX);
     2111    AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, UINT32_MAX);
     2112
     2113    uint32_t const cRefs = ASMAtomicIncU32(&pStreamEx->cRefs);
     2114    Assert(cRefs > 1);
     2115    Assert(cRefs < _1K);
     2116
     2117    Log12Func(("returns %u (%s)\n", cRefs, pStreamEx->Core.szName));
     2118    return cRefs;
     2119}
     2120
     2121
     2122/**
    17392123 * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamRetain}
    17402124 */
    17412125static DECLCALLBACK(uint32_t) drvAudioStreamRetain(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
    17422126{
    1743    AssertPtrReturn(pInterface, UINT32_MAX);
    1744    AssertPtrReturn(pStream,    UINT32_MAX);
    1745    AssertReturn(pStream->uMagic == PDMAUDIOSTREAM_MAGIC, UINT32_MAX);
    1746    AssertReturn(((PDRVAUDIOSTREAM)pStream)->uMagic == DRVAUDIOSTREAM_MAGIC, UINT32_MAX);
    1747    RT_NOREF(pInterface);
    1748 
    1749    uint32_t const cRefs = ASMAtomicIncU32(&pStream->cRefs);
    1750    Assert(cRefs > 1);
    1751    Assert(cRefs < _1K);
    1752 
    1753    return cRefs;
     2127    RT_NOREF(pInterface);
     2128    return drvAudioStreamRetainInternal((PDRVAUDIOSTREAM)pStream);
    17542129}
    17552130
     
    17602135static DECLCALLBACK(uint32_t) drvAudioStreamRelease(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
    17612136{
    1762    AssertPtrReturn(pInterface, UINT32_MAX);
    1763    AssertPtrReturn(pStream,    UINT32_MAX);
    1764    AssertReturn(pStream->uMagic == PDMAUDIOSTREAM_MAGIC, UINT32_MAX);
    1765    AssertReturn(((PDRVAUDIOSTREAM)pStream)->uMagic == DRVAUDIOSTREAM_MAGIC, UINT32_MAX);
    1766    RT_NOREF(pInterface);
    1767 
    1768    uint32_t cRefs = ASMAtomicDecU32(&pStream->cRefs);
    1769    AssertStmt(cRefs >= 1, cRefs = ASMAtomicIncU32(&pStream->cRefs));
    1770    Assert(cRefs < _1K);
    1771 
    1772    return cRefs;
     2137    return drvAudioStreamReleaseInternal(RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector),
     2138                                         (PDRVAUDIOSTREAM)pStream,
     2139                                         false /*fMayDestroy*/);
    17732140}
    17742141
     
    17762143/**
    17772144 * Controls a stream's backend.
    1778  *
    1779  * If the stream has no backend available, VERR_NOT_FOUND is returned
    1780  * (bird: actually the code returns VINF_SUCCESS).
    17812145 *
    17822146 * @returns VBox status code.
     
    17842148 * @param   pStreamEx       Stream to control.
    17852149 * @param   enmStreamCmd    Control command.
     2150 *
     2151 * @note    Caller has entered the critical section.
    17862152 */
    17872153static int drvAudioStreamControlInternalBackend(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, PDMAUDIOSTREAMCMD enmStreamCmd)
     
    17902156    AssertPtr(pStreamEx);
    17912157
    1792 #ifdef LOG_ENABLED
    1793     char szStreamSts[DRVAUDIO_STATUS_STR_MAX];
    1794 #endif
    1795     LogFlowFunc(("[%s] enmStreamCmd=%s, fStatus=%s\n", pStreamEx->Core.szName, PDMAudioStrmCmdGetName(enmStreamCmd),
    1796                  dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->Core.fStatus)));
    1797 
    1798     if (!pThis->pHostDrvAudio) /* If not lower driver is configured, bail out. */
    1799         return VINF_SUCCESS;
    1800 
    1801 
    18022158    /*
    18032159     * Whether to propagate commands down to the backend.
    18042160     *
    1805      * This is needed for critical operations like recording audio if audio input is disabled on a per-driver level.
     2161     *      1. If the stream direction is disabled on the driver level, we should
     2162     *         obviously not call the backend.  Our stream status will reflect the
     2163     *         actual state so drvAudioEnable() can tell the backend if the user
     2164     *         re-enables the stream direction.
    18062165     *
    1807      * Note that not all commands will be covered by this, such as operations like stopping, draining and droppping,
    1808      * which are considered uncritical and sometimes even are required for certain backends (like DirectSound on Windows).
    1809      *
    1810      * The actual stream state will be untouched to not make the state machine handling more complicated than
    1811      * it already is.
    1812      *
    1813      * See @bugref{9882}.
    1814      */
    1815     const bool fEnabled =    (   pStreamEx->Core.enmDir == PDMAUDIODIR_IN
    1816                               && pThis->In.fEnabled)
    1817                           || (   pStreamEx->Core.enmDir == PDMAUDIODIR_OUT
    1818                               && pThis->Out.fEnabled);
    1819 
    1820     LogRel2(("Audio: %s stream '%s' in backend (%s is %s)\n", PDMAudioStrmCmdGetName(enmStreamCmd), pStreamEx->Core.szName,
    1821                                                               PDMAudioDirGetName(pStreamEx->Core.enmDir),
    1822                                                               fEnabled ? "enabled" : "disabled"));
    1823     int rc = VINF_SUCCESS;
    1824     switch (enmStreamCmd)
    1825     {
    1826         case PDMAUDIOSTREAMCMD_ENABLE:
    1827         {
    1828             if (fEnabled)
    1829                 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, PDMAUDIOSTREAMCMD_ENABLE);
    1830             break;
    1831         }
    1832 
    1833         case PDMAUDIOSTREAMCMD_DISABLE:
    1834         {
    1835             rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, PDMAUDIOSTREAMCMD_DISABLE);
    1836             break;
    1837         }
    1838 
    1839         case PDMAUDIOSTREAMCMD_PAUSE:
    1840         {
    1841             if (fEnabled) /* Needed, as resume below also is being checked for. */
    1842                 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, PDMAUDIOSTREAMCMD_PAUSE);
    1843             break;
    1844         }
    1845 
    1846         case PDMAUDIOSTREAMCMD_RESUME:
    1847         {
    1848             if (fEnabled)
    1849                 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, PDMAUDIOSTREAMCMD_RESUME);
    1850             break;
    1851         }
    1852 
    1853         case PDMAUDIOSTREAMCMD_DRAIN:
    1854         {
    1855             rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend, PDMAUDIOSTREAMCMD_DRAIN);
    1856             break;
    1857         }
    1858 
    1859         default:
    1860             AssertMsgFailedReturn(("Command %RU32 not implemented\n", enmStreamCmd), VERR_INTERNAL_ERROR_2);
    1861     }
    1862 
    1863     if (RT_FAILURE(rc))
    1864     {
    1865         if (   rc != VERR_NOT_IMPLEMENTED
    1866             && rc != VERR_NOT_SUPPORTED
    1867             && rc != VERR_AUDIO_STREAM_NOT_READY)
    1868         {
    1869             LogRel(("Audio: %s stream '%s' failed with %Rrc\n", PDMAudioStrmCmdGetName(enmStreamCmd), pStreamEx->Core.szName, rc));
    1870         }
    1871 
    1872         LogFunc(("[%s] %s failed with %Rrc\n", pStreamEx->Core.szName, PDMAudioStrmCmdGetName(enmStreamCmd), rc));
    1873     }
    1874 
     2166     *      2. If the backend hasn't finished initializing yet, don't try call
     2167     *         it to start/stop/pause/whatever the stream.  (Better to do it here
     2168     *         than to replicate this in the relevant backends.)  When the backend
     2169     *         finish initializing the stream, we'll update it about the stream state.
     2170     */
     2171    int             rc             = VINF_SUCCESS;
     2172    uint32_t const  fBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); /* (checks pThis->pHostDrvAudio too) */
     2173    bool const      fDirEnabled    = pStreamEx->Core.enmDir == PDMAUDIODIR_IN ? pThis->In.fEnabled : pThis->Out.fEnabled;
     2174
     2175    char szStreamSts[DRVAUDIO_STATUS_STR_MAX], szBackendStreamSts[DRVAUDIO_STATUS_STR_MAX];
     2176    LogRel2(("Audio: %s stream '%s' backend (%s is %s; status: %s; backend-status: %s)\n",
     2177             PDMAudioStrmCmdGetName(enmStreamCmd), pStreamEx->Core.szName, PDMAudioDirGetName(pStreamEx->Core.enmDir),
     2178             fDirEnabled ? "enabled" : "disabled",  dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus),
     2179             dbgAudioStreamStatusToStr(szBackendStreamSts, fBackendStatus) ));
     2180
     2181    if (fDirEnabled)
     2182    {
     2183        if (   (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY)
     2184            && (fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED))
     2185        {
     2186            /** @todo Backend will change to explicit methods here, so please don't simplify
     2187             *        the switch. */
     2188            switch (enmStreamCmd)
     2189            {
     2190                case PDMAUDIOSTREAMCMD_ENABLE:
     2191                    rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend,
     2192                                                                PDMAUDIOSTREAMCMD_ENABLE);
     2193                    break;
     2194
     2195                case PDMAUDIOSTREAMCMD_DISABLE:
     2196                    rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend,
     2197                                                                PDMAUDIOSTREAMCMD_DISABLE);
     2198                    break;
     2199
     2200                case PDMAUDIOSTREAMCMD_PAUSE:
     2201                    rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend,
     2202                                                                PDMAUDIOSTREAMCMD_PAUSE);
     2203                    break;
     2204
     2205                case PDMAUDIOSTREAMCMD_RESUME:
     2206                    rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend,
     2207                                                                PDMAUDIOSTREAMCMD_RESUME);
     2208                    break;
     2209
     2210                case PDMAUDIOSTREAMCMD_DRAIN:
     2211                    rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pStreamEx->pBackend,
     2212                                                                PDMAUDIOSTREAMCMD_DRAIN);
     2213                    break;
     2214
     2215                default:
     2216                    AssertMsgFailedReturn(("Command %RU32 not implemented\n", enmStreamCmd), VERR_INTERNAL_ERROR_2);
     2217            }
     2218            if (RT_SUCCESS(rc))
     2219                Log2Func(("[%s] %s succeeded (%Rrc)\n", pStreamEx->Core.szName, PDMAudioStrmCmdGetName(enmStreamCmd), rc));
     2220            else
     2221            {
     2222                LogFunc(("[%s] %s failed with %Rrc\n", pStreamEx->Core.szName, PDMAudioStrmCmdGetName(enmStreamCmd), rc));
     2223                if (   rc != VERR_NOT_IMPLEMENTED
     2224                    && rc != VERR_NOT_SUPPORTED
     2225                    && rc != VERR_AUDIO_STREAM_NOT_READY)
     2226                    LogRel(("Audio: %s stream '%s' failed with %Rrc\n", PDMAudioStrmCmdGetName(enmStreamCmd), pStreamEx->Core.szName, rc));
     2227            }
     2228        }
     2229    }
    18752230    return rc;
    18762231}
     
    18882243    LogFunc(("[%s]\n", pStreamEx->Core.szName));
    18892244
    1890     pStreamEx->Core.fStatus        = PDMAUDIOSTREAM_STS_INITIALIZED;
     2245    pStreamEx->fStatus            &= PDMAUDIOSTREAM_STS_INITIALIZED | PDMAUDIOSTREAM_STS_BACKEND_READY;
    18912246    pStreamEx->Core.fWarningsShown = PDMAUDIOSTREAM_WARN_FLAGS_NONE;
    18922247
     
    19272282    {
    19282283        if (   pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC
    1929             && pStreamEx->Core.cRefs >= 1)
    1930         {
    1931             if (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)
     2284            && pStreamEx->cRefs >= 1)
     2285        {
     2286            if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)
    19322287            {
    19332288                drvAudioStreamIterateInternal(pThis, pStreamEx);
    19342289
    1935                 if (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)
     2290                if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)
    19362291                    cMilliesToNext = 10;
    19372292            }
     
    19712326#endif
    19722327    LogFunc(("[%s] enmStreamCmd=%s fStatus=%s\n", pStreamEx->Core.szName, PDMAudioStrmCmdGetName(enmStreamCmd),
    1973              dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->Core.fStatus)));
     2328             dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus)));
    19742329
    19752330    int rc = VINF_SUCCESS;
     
    19782333    {
    19792334        case PDMAUDIOSTREAMCMD_ENABLE:
    1980             if (!(pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED))
     2335            if (!(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED))
    19812336            {
    19822337                /* Is a pending disable outstanding? Then disable first. */
    1983                 if (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)
     2338                if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)
    19842339                    rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE);
    19852340                if (RT_SUCCESS(rc))
     
    19932348                        pStreamEx->Out.enmPlayState  = pStreamEx->Out.cbPreBufThreshold > 0
    19942349                                                     ? DRVAUDIOPLAYSTATE_PREBUF
    1995                                                      : pStreamEx->fLastBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED
     2350                                                     :    (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY)
     2351                                                       && (pStreamEx->fLastBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED)
    19962352                                                     ? DRVAUDIOPLAYSTATE_PLAY
    19972353                                                     : DRVAUDIOPLAYSTATE_NOPLAY;
     
    20052361                    if (RT_SUCCESS(rc))
    20062362                    {
    2007                         pStreamEx->Core.fStatus |= PDMAUDIOSTREAM_STS_ENABLED;
    2008                         PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus);
     2363                        pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_ENABLED;
     2364                        PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus);
    20092365                    }
    20102366                }
     
    20132369
    20142370        case PDMAUDIOSTREAMCMD_DISABLE:
    2015             if (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED)
     2371            if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED)
    20162372            {
    20172373                /*
     
    20232379                {
    20242380                    LogFunc(("[%s] Pending disable/pause\n", pStreamEx->Core.szName));
    2025                     pStreamEx->Core.fStatus |= PDMAUDIOSTREAM_STS_PENDING_DISABLE;
    2026                     PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus);
     2381                    pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_PENDING_DISABLE;
     2382                    PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus);
    20272383
    20282384                    /* Schedule a follow up timer to the pending-disable state.  We cannot rely
     
    20402396
    20412397                /* Can we close the host stream as well (not in pending disable mode)? */
    2042                 if (!(pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE))
     2398                if (!(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE))
    20432399                {
    20442400                    rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE);
     
    20502406
    20512407        case PDMAUDIOSTREAMCMD_PAUSE:
    2052             if (   (pStreamEx->Core.fStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED))
    2053                 ==                             PDMAUDIOSTREAM_STS_ENABLED)
     2408            if ((pStreamEx->fStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED)) == PDMAUDIOSTREAM_STS_ENABLED)
    20542409            {
    20552410                rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_PAUSE);
    20562411                if (RT_SUCCESS(rc))
    20572412                {
    2058                     pStreamEx->Core.fStatus |= PDMAUDIOSTREAM_STS_PAUSED;
    2059                     PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus);
     2413                    pStreamEx->fStatus |= PDMAUDIOSTREAM_STS_PAUSED;
     2414                    PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus);
    20602415                }
    20612416            }
     
    20632418
    20642419        case PDMAUDIOSTREAMCMD_RESUME:
    2065             if (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_PAUSED)
     2420            if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PAUSED)
    20662421            {
    2067                 Assert(pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED);
     2422                Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED);
    20682423                rc = drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_RESUME);
    20692424                if (RT_SUCCESS(rc))
    20702425                {
    2071                     pStreamEx->Core.fStatus &= ~PDMAUDIOSTREAM_STS_PAUSED;
    2072                     PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus);
     2426                    pStreamEx->fStatus &= ~PDMAUDIOSTREAM_STS_PAUSED;
     2427                    PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus);
    20732428                }
    20742429            }
     
    21782533     * Update the pre-buffering size and position.
    21792534     */
    2180     pStreamEx->Out.cbPreBuffered = cbCur;
     2535    pStreamEx->Out.cbPreBuffered = RT_MIN(cbCur, cbMax);
    21812536    pStreamEx->Out.offPreBuf     = offRead;
    21822537    return VINF_SUCCESS;
     
    21842539
    21852540
    2186 #if 0
    2187 /**
    2188  * Worker for drvAudioStreamPlay() and drvAudioStreamIterateInternal().
    2189  *
    2190  * The buffer is NULL and has a zero length when called from the interate
    2191  * function.  This only occures when there is pre-buffered audio data that need
    2192  * to be pushed to the backend due to a pending disabling of the stream.
    2193  *
    2194  * Caller owns the lock.
    2195  */
    2196 static int drvAudioStreamPlayLocked(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx, uint32_t fBackStatus,
    2197                                     const uint8_t *pbBuf, uint32_t cbBuf, uint32_t *pcbWritten)
    2198 {
    2199     Log3Func(("%s: @%#RX64: cbBuf=%#x fBackStatus=%#x\n", pStreamEx->Core.szName, pStreamEx->offInternal, cbBuf, fBackStatus));
    2200     RT_NOREF(fBackStatus);
    2201 
    2202     /*
    2203      * Are we pre-buffering?
    2204      *
    2205      * Note! We do not restart pre-buffering in this version, as we'd
    2206      *       need some kind of cooperation with the backend buffer
    2207      *       managment to correctly detect an underrun.
    2208      */
    2209     bool     fJustStarted = false;
    2210     uint32_t cbWritten = 0;
    2211     int      rc;
    2212     if (   pStreamEx->fThresholdReached
    2213         && pStreamEx->Out.cbPreBuffered == 0)
    2214     {
    2215         /* not-prebuffering, likely after a while at least */
    2216         rc = VINF_SUCCESS;
    2217     }
    2218     else
    2219     {
    2220         /*
    2221          * Copy as much as we can to the pre-buffer.
    2222          */
    2223         uint32_t cbFree = pStreamEx->Out.cbPreBufAlloc - pStreamEx->Out.cbPreBuffered;
    2224         AssertReturn((int32_t)cbFree >= 0, VERR_INTERNAL_ERROR_2);
    2225         if (cbFree > 0 && cbBuf > 0)
    2226         {
    2227             cbWritten = RT_MIN(cbFree, cbBuf);
    2228             cbWritten = PDMAudioPropsFloorBytesToFrame(&pStreamEx->Core.Props, cbWritten);
    2229             if (pStreamEx->Out.offPreBuf == 0)
    2230                 memcpy(&pStreamEx->Out.pbPreBuf[pStreamEx->Out.cbPreBuffered], pbBuf, cbWritten);
    2231             else
    2232             {
    2233 
    2234             }
    2235 
    2236             pStreamEx->Out.cbPreBuffered += cbWritten;
    2237             cbBuf                        -= cbWritten;
    2238             pbBuf                        += cbWritten;
    2239             pStreamEx->offInternal       += cbWritten;
    2240         }
    2241 
    2242         /*
    2243          * Get the special case of buggy backend drivers out of the way.
    2244          * We get here if we couldn't write out all the pre-buffered data when
    2245          * we hit the threshold.
    2246          */
    2247         if (pStreamEx->fThresholdReached)
    2248             LogRel2(("Audio: @%#RX64: Stream '%s' pre-buffering commit problem: cbBuf=%#x cbPreBuffered=%#x\n",
    2249                      pStreamEx->offInternal, pStreamEx->Core.szName, cbBuf, pStreamEx->Out.cbPreBuffered));
    2250         /*
    2251          * Did we reach the backend's playback (pre-buffering) threshold?
    2252          * Can be 0 if no pre-buffering desired.
    2253          */
    2254         else if (pStreamEx->Out.cbPreBuffered + cbBuf >= pStreamEx->Out.cbPreBufThreshold)
    2255         {
    2256             LogRel2(("Audio: @%#RX64: Stream '%s' buffering complete! (%#x + %#x bytes)\n",
    2257                      pStreamEx->offInternal, pStreamEx->Core.szName, pStreamEx->Out.cbPreBuffered, cbBuf));
    2258             pStreamEx->fThresholdReached = fJustStarted = true;
    2259         }
    2260         /*
    2261          * Some audio files are shorter than the pre-buffering level (e.g. the
    2262          * "click" Explorer sounds on some Windows guests), so make sure that we
    2263          * also play those by checking if the stream already is pending disable
    2264          * mode, even if we didn't hit the pre-buffering watermark yet.
    2265          *
    2266          * Try play "Windows Navigation Start.wav" on Windows 7 (2824 samples).
    2267          */
    2268         else if (   (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE)
    2269                  && pStreamEx->Out.cbPreBuffered > 0)
    2270         {
    2271             LogRel2(("Audio: @%#RX64: Stream '%s' buffering complete - short sound! (%#x + %#x bytes)\n",
    2272                      pStreamEx->offInternal, pStreamEx->Core.szName, pStreamEx->Out.cbPreBuffered, cbBuf));
    2273             pStreamEx->fThresholdReached = fJustStarted = true;
    2274         }
    2275         /*
    2276          * Not yet, so still buffering audio data.
    2277          */
    2278         else
    2279         {
    2280             LogRel2(("Audio: @%#RX64: Stream '%s' is buffering (%RU8%% complete)...\n", pStreamEx->offInternal,
    2281                      pStreamEx->Core.szName, (100 * pStreamEx->Out.cbPreBuffered) / pStreamEx->Out.cbPreBufThreshold));
    2282             Assert(cbBuf == 0);
    2283             *pcbWritten = cbWritten;
    2284             return VINF_SUCCESS;
    2285         }
    2286 
    2287         /*
    2288          * Write the pre-buffered chunk.
    2289          */
    2290         uint32_t off = 0;
    2291         uint32_t cbPreBufWritten;
    2292         do
    2293         {
    2294             cbPreBufWritten = 0;
    2295             rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pStreamEx->pBackend, &pStreamEx->Out.pbPreBuf[off],
    2296                                                      pStreamEx->Out.cbPreBuffered - off, &cbPreBufWritten);
    2297             AssertRCBreak(rc);
    2298             off += cbPreBufWritten;
    2299         } while (off < pStreamEx->Out.cbPreBuffered && cbPreBufWritten != 0);
    2300 
    2301         if (off >= pStreamEx->Out.cbPreBuffered)
    2302         {
    2303             Assert(off == pStreamEx->Out.cbPreBuffered);
    2304             LogFunc(("@%#RX64: Wrote all %#x bytes of pre-buffered audio data.\n", pStreamEx->offInternal, off));
    2305             pStreamEx->Out.cbPreBuffered = 0;
    2306         }
    2307         else
    2308         {
    2309             LogRel2(("Audio: @%#RX64: Stream '%s' pre-buffering commit problem: wrote %#x out of %#x + %#x%s - rc=%Rrc *pcbWritten=%#x\n",
    2310                      pStreamEx->offInternal, pStreamEx->Core.szName, off, pStreamEx->Out.cbPreBuffered, cbBuf,
    2311                      fJustStarted ? " (just started)" : "", rc, cbWritten));
    2312             AssertMsg(!fJustStarted || RT_FAILURE(rc),
    2313                       ("Buggy host driver buffer reporting: off=%#x cbPreBuffered=%#x\n", off, pStreamEx->Out.cbPreBuffered));
    2314             if (off > 0)
    2315             {
    2316                 memmove(pStreamEx->Out.pbPreBuf, &pStreamEx->Out.pbPreBuf[off], pStreamEx->Out.cbPreBuffered - off);
    2317                 pStreamEx->Out.cbPreBuffered -= off;
    2318             }
    2319             pStreamEx->nsLastPlayedCaptured = RTTimeNanoTS();
    2320             *pcbWritten = cbWritten;
    2321             return cbWritten ? VINF_SUCCESS : rc;
    2322         }
    2323 
    2324         if (RT_FAILURE(rc))
    2325         {
    2326             *pcbWritten = cbWritten;
    2327             return rc;
    2328         }
    2329     }
    2330 
    2331     /*
    2332      * Do the writing.
    2333      */
    2334     uint32_t cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend);
    2335     pStreamEx->Out.Stats.cbBackendWritableBefore = cbWritable;
    2336 
    2337     uint8_t const cbFrame = PDMAudioPropsFrameSize(&pStreamEx->Core.Props);
    2338     while (cbBuf >= cbFrame && cbWritable >= cbFrame)
    2339     {
    2340         uint32_t const cbToWrite    = PDMAudioPropsFloorBytesToFrame(&pStreamEx->Core.Props, RT_MIN(cbBuf, cbWritable));
    2341         uint32_t       cbWrittenNow = 0;
    2342         rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pStreamEx->pBackend, pbBuf, cbToWrite, &cbWrittenNow);
    2343         if (RT_SUCCESS(rc))
    2344         {
    2345             if (cbWrittenNow != cbToWrite)
    2346                 Log3Func(("%s: @%#RX64: Wrote less bytes than requested: %#x, requested %#x\n",
    2347                           pStreamEx->Core.szName, pStreamEx->offInternal, cbWrittenNow, cbToWrite));
    2348 #ifdef DEBUG_bird
    2349             Assert(cbWrittenNow == cbToWrite);
    2350 #endif
    2351             AssertStmt(cbWrittenNow <= cbToWrite, cbWrittenNow = cbToWrite);
    2352             cbWritten += cbWrittenNow;
    2353             cbBuf     -= cbWrittenNow;
    2354             pbBuf     += cbWrittenNow;
    2355             pStreamEx->offInternal += cbWrittenNow;
    2356         }
    2357         else
    2358         {
    2359             *pcbWritten = cbWritten;
    2360             LogFunc(("%s: @%#RX64: pfnStreamPlay failed writing %#x bytes (%#x previous written, %#x writable): %Rrc\n",
    2361                      pStreamEx->Core.szName, pStreamEx->offInternal, cbToWrite, cbWritten, cbWritable, rc));
    2362             return cbWritten ? VINF_SUCCESS : rc;
    2363         }
    2364         cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend);
    2365     }
    2366 
    2367     *pcbWritten = cbWritten;
    2368     pStreamEx->Out.Stats.cbBackendWritableAfter = cbWritable;
    2369     if (cbWritten)
    2370         pStreamEx->nsLastPlayedCaptured = RTTimeNanoTS();
    2371 
    2372     Log3Func(("%s: @%#RX64: Wrote %#x bytes (%#x bytes left)\n", pStreamEx->Core.szName, pStreamEx->offInternal, cbWritten, cbBuf));
    2373     return rc;
    2374 }
    2375 #endif
    2376 
    2377 
    2378 /**
    2379  * Worker for drvAudioStreamPlay() and drvAudioStreamIterateInternal().
     2541/**
     2542 * Worker for drvAudioStreamPlay() and drvAudioStreamPreBufComitting().
    23802543 *
    23812544 * Caller owns the lock.
     
    24322595
    24332596
     2597/**
     2598 * Worker for drvAudioStreamPlay() and drvAudioStreamPreBufComitting().
     2599 */
    24342600static int drvAudioStreamPlayToPreBuffer(PDRVAUDIOSTREAM pStreamEx, const void *pvBuf, uint32_t cbBuf, uint32_t cbMax,
    24352601                                         uint32_t *pcbWritten)
     
    25632729    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
    25642730
    2565     if (!pThis->pHostDrvAudio)
    2566         return VINF_SUCCESS;
    2567 
    25682731#ifdef LOG_ENABLED
    25692732    char szStreamSts[DRVAUDIO_STATUS_STR_MAX];
    25702733#endif
    2571     Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->Core.fStatus)));
     2734    Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus)));
    25722735
    25732736    /* Not enabled or paused? Skip iteration. */
    2574     if (   !(pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED)
    2575         ||  (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_PAUSED))
    2576     {
     2737    if ((pStreamEx->fStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED)) != PDMAUDIOSTREAM_STS_ENABLED)
    25772738        return VINF_SUCCESS;
    2578     }
    25792739
    25802740    /*
     
    25822742     */
    25832743    int rc = VINF_SUCCESS;
    2584     if (!(pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE))
     2744    if (!(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_PENDING_DISABLE))
    25852745    { /* likely until we get to the end of the stream at least. */ }
    25862746    else
     
    26172777                if (pStreamEx->Out.cbPreBuffered > 0)
    26182778                {
    2619                     uint32_t cbIgnored = 0;
    2620                     drvAudioStreamPreBufComitting(pThis, pStreamEx, NULL, 0, &cbIgnored);
    2621                     cFramesLive = PDMAudioPropsBytesToFrames(&pStreamEx->Core.Props, pStreamEx->Out.cbPreBuffered);
     2779                    /* Must check the backend state here first and only try commit the
     2780                       pre-buffered samples if the backend is in working order. */
     2781                    uint32_t const fBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx); /* (checks pThis->pHostDrvAudio too) */
     2782                    if (   (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY)
     2783                        && (fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED))
     2784                    {
     2785                        uint32_t cbIgnored = 0;
     2786                        drvAudioStreamPreBufComitting(pThis, pStreamEx, NULL, 0, &cbIgnored);
     2787                        cFramesLive = PDMAudioPropsBytesToFrames(&pStreamEx->Core.Props, pStreamEx->Out.cbPreBuffered);
     2788                    }
     2789                    else
     2790                        Log3Func(("[%s] Skipping committing pre-buffered samples, backend not initialized (%#x)!\n",
     2791                                  pStreamEx->Core.szName, fBackendStatus));
    26222792                }
    26232793                break;
     
    26332803            if (rc == VERR_NOT_SUPPORTED) /* Not all backends support draining yet. */
    26342804                rc = VINF_SUCCESS;
     2805            /** @todo r=bird: We could probably just skip this next check, as if drainig
     2806             *        failes, we should definitely try disable the stream.  Maybe the
     2807             *        host audio device was unplugged and we're leaving this stream in a
     2808             *        bogus state. */
    26352809            if (RT_SUCCESS(rc))
    26362810            {
    26372811                /*
    2638                  * Before we disable the stream, check if the backend has
    2639                  * finished playing the buffered data.
     2812                 * Before we disable the stream, check if the backend has finished playing the buffered data.
    26402813                 */
    26412814                uint32_t cbPending;
    2642                 if (!pThis->pHostDrvAudio->pfnStreamGetPending) /* Optional. */
     2815                if (!pThis->pHostDrvAudio || !pThis->pHostDrvAudio->pfnStreamGetPending) /* Optional. */
    26432816                    cbPending = 0;
    26442817                else
     
    26562829                    if (RT_SUCCESS(rc))
    26572830                    {
    2658                         pStreamEx->Core.fStatus &= ~(PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PENDING_DISABLE);
    2659                         PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus);
     2831                        pStreamEx->fStatus &= ~(PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PENDING_DISABLE);
     2832                        PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus);
    26602833                        drvAudioStreamDropInternal(pStreamEx); /* Not a DROP command, just a stream reset. */
    26612834                    }
     2835                    /** @todo r=bird: This log entry sounds a rather fishy to be honest...  Any
     2836                     *        backend which would do that, or genuinely need this?  */
    26622837                    else
    26632838                        LogFunc(("[%s] Backend vetoed against closing pending input stream, rc=%Rrc\n", pStreamEx->Core.szName, rc));
     
    26652840            }
    26662841        }
    2667 
    26682842    }
    26692843
     
    27272901
    27282902    if (   pThis->pHostDrvAudio
    2729         && (   PDMAudioStrmStatusCanRead(pStreamEx->Core.fStatus)
     2903        && (   PDMAudioStrmStatusCanRead(pStreamEx->fStatus)
    27302904            || fDisabled)
    27312905       )
    27322906    {
     2907        uint32_t const fBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx);
     2908
    27332909        if (pStreamEx->fNoMixBufs)
    2734             cbReadable = pThis->pHostDrvAudio
    2735                        ? pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, pStreamEx->pBackend) : 0;
     2910            cbReadable =    pThis->pHostDrvAudio
     2911                         && (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY)
     2912                         && (fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED)
     2913                         && !fDisabled
     2914                       ? pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, pStreamEx->pBackend)
     2915                       : 0;
    27362916        else
    27372917        {
     
    27392919            cbReadable = AUDIOMIXBUF_F2B(&pStreamEx->Guest.MixBuf, cfReadable);
    27402920        }
    2741 
    27422921        if (!cbReadable)
    27432922        {
     
    27502929             * Reading the actual data from a stream then will return silence then.
    27512930             */
    2752             uint32_t fStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx);
    2753             if (   !PDMAudioStrmStatusBackendCanRead(fStatus)
     2931            if (   !PDMAudioStrmStatusBackendCanRead(fBackendStatus)
    27542932                || fDisabled)
    27552933            {
     
    27622940                    else
    27632941                        LogRel(("Audio: Warning: Input for stream '%s' of driver '%s' not ready (current input status is %#x), returning silence\n",
    2764                                 pStreamEx->Core.szName, pThis->szName, fStatus));
     2942                                pStreamEx->Core.szName, pThis->szName, fBackendStatus));
    27652943
    27662944                    pStreamEx->Core.fWarningsShown |= PDMAUDIOSTREAM_WARN_FLAGS_DISABLED;
     
    28032981     */
    28042982    uint32_t cbWritable = 0;
    2805     if (   PDMAudioStrmStatusCanWrite(pStreamEx->Core.fStatus)
     2983    if (   PDMAudioStrmStatusCanWrite(pStreamEx->fStatus)
    28062984        && pThis->pHostDrvAudio != NULL)
    28072985    {
    2808         Assert(pThis->pHostDrvAudio);
    28092986        switch (pStreamEx->Out.enmPlayState)
    28102987        {
     
    28142991            case DRVAUDIOPLAYSTATE_PLAY:
    28152992            case DRVAUDIOPLAYSTATE_PLAY_PREBUF:
     2993                Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY);
     2994                Assert(drvAudioStreamGetBackendStatus(pThis, pStreamEx) & PDMAUDIOSTREAM_STS_INITIALIZED);
    28162995                cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend);
    28172996                break;
     
    28503029                   as long as there is space for it, as we need the pfnStreamWrite call
    28513030                   to move the data. */
     3031                Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY);
     3032                Assert(drvAudioStreamGetBackendStatus(pThis, pStreamEx) & PDMAUDIOSTREAM_STS_INITIALIZED);
    28523033                uint32_t const cbMin = PDMAudioPropsFramesToBytes(&pStreamEx->Core.Props, 8);
    28533034                cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pStreamEx->pBackend);
     
    28993080    AssertRCReturn(rc, PDMAUDIOSTREAM_STS_NONE);
    29003081
    2901     uint32_t fStrmStatus = pStreamEx->Core.fStatus;
     3082    uint32_t fStrmStatus = pStreamEx->fStatus;
    29023083
    29033084    RTCritSectLeave(&pThis->CritSect);
     
    29323113
    29333114
     3115/**
     3116 * Processes backend status change.
     3117 *
     3118 * @todo bird: I'm more and more of the opinion that the backend should
     3119 *       explicitly notify us about these changes, rather that we polling them
     3120 *       via PDMIHOSTAUDIO::pfnStreamGetStatus...
     3121 */
    29343122static void drvAudioStreamPlayProcessBackendStateChange(PDRVAUDIOSTREAM pStreamEx, uint32_t fNewState, uint32_t fOldState)
    29353123{
     
    29433131        if (fOldState & PDMAUDIOSTREAM_STS_INITIALIZED)
    29443132        {
     3133            /* Pulse audio clear INITIALIZED. */
    29453134            switch (enmPlayState)
    29463135            {
     
    29703159        else
    29713160        {
    2972             switch (enmPlayState)
     3161            if (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY)
    29733162            {
    2974                 case DRVAUDIOPLAYSTATE_PREBUF:
    2975                 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING:
    2976                     break;
    2977                 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE:
    2978                     pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_COMMITTING;
    2979                     break;
    2980                 case DRVAUDIOPLAYSTATE_NOPLAY:
    2981                     pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF;
    2982                     break;
    2983                 case DRVAUDIOPLAYSTATE_PLAY:
    2984                 case DRVAUDIOPLAYSTATE_PLAY_PREBUF:
    2985                 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING:
    2986                     AssertFailedBreak();
    2987                 /* no default */
    2988                 case DRVAUDIOPLAYSTATE_END:
    2989                 case DRVAUDIOPLAYSTATE_INVALID:
    2990                     break;
     3163    /** @todo We need to resync the stream status somewhere...  */
     3164                switch (enmPlayState)
     3165                {
     3166                    case DRVAUDIOPLAYSTATE_PREBUF:
     3167                    case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING:
     3168                        break;
     3169                    case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE:
     3170                        pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_COMMITTING;
     3171                        break;
     3172                    case DRVAUDIOPLAYSTATE_NOPLAY:
     3173                        pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF;
     3174                        break;
     3175                    case DRVAUDIOPLAYSTATE_PLAY:
     3176                    case DRVAUDIOPLAYSTATE_PLAY_PREBUF:
     3177                    case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING:
     3178                        AssertFailedBreak();
     3179                    /* no default */
     3180                    case DRVAUDIOPLAYSTATE_END:
     3181                    case DRVAUDIOPLAYSTATE_INVALID:
     3182                        break;
     3183                }
     3184                LogFunc(("PDMAUDIOSTREAM_STS_INITIALIZED was set: %s -> %s\n",
     3185                         drvAudioPlayStateName(enmPlayState), drvAudioPlayStateName(pStreamEx->Out.enmPlayState) ));
    29913186            }
    2992             LogFunc(("PDMAUDIOSTREAM_STS_INITIALIZED was set: %s -> %s\n",
    2993                      drvAudioPlayStateName(enmPlayState), drvAudioPlayStateName(pStreamEx->Out.enmPlayState) ));
     3187            else
     3188                LogFunc(("PDMAUDIOSTREAM_STS_INITIALIZED was set (enmPlayState=%s), but PDMAUDIOSTREAM_STS_BACKEND_READY is not.\n",
     3189                         drvAudioPlayStateName(enmPlayState) ));
    29943190        }
    29953191    }
     
    29993195     *
    30003196     * Note! We don't care if it's cleared as the backend will call
    3001      *       PDMIAUDIONOTIFYFROMHOST::pfnStreamNotifyDeviceChanged when that takes place.
     3197     *       PDMIHOSTAUDIOPORT::pfnStreamNotifyDeviceChanged when that takes place.
    30023198     */
    30033199    if (   !(fOldState & PDMAUDIOSTREAM_STS_PREPARING_SWITCH)
     
    30733269     * whether to just drop the input into the bit bucket.
    30743270     */
    3075     if (PDMAudioStrmStatusIsReady(pStreamEx->Core.fStatus))
     3271    if (PDMAudioStrmStatusIsReady(pStreamEx->fStatus))
    30763272    {
    30773273        if (   pThis->Out.fEnabled /* (see @bugref{9882}) */
     
    30973293             */
    30983294            uint32_t const fBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx);
    3099             Assert(   (fBackendStatus          & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED))
    3100                    == (pStreamEx->Core.fStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED)) );
     3295            Assert(      (fBackendStatus     & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED))
     3296                      == (pStreamEx->fStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED))
     3297                   || !(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY)
     3298                   || !(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED) );
    31013299
    31023300            if (!(  (pStreamEx->fLastBackendStatus ^ fBackendStatus)
     
    31153313            {
    31163314                case DRVAUDIOPLAYSTATE_PLAY:
     3315                    Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY);
     3316                    Assert(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED);
    31173317                    rc = drvAudioStreamPlayLocked(pThis, pStreamEx, (uint8_t const *)pvBuf, cbBuf, pcbWritten);
    31183318                    break;
    31193319
    31203320                case DRVAUDIOPLAYSTATE_PLAY_PREBUF:
     3321                    Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY);
     3322                    Assert(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED);
    31213323                    rc = drvAudioStreamPlayLocked(pThis, pStreamEx, (uint8_t const *)pvBuf, cbBuf, pcbWritten);
    31223324                    drvAudioStreamPreBuffer(pStreamEx, (uint8_t const *)pvBuf, *pcbWritten, pStreamEx->Out.cbPreBufThreshold);
     
    31443346
    31453347                case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE:
     3348                    Assert(!(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY));
    31463349                    Assert(!(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED));
    31473350                    RT_FALL_THRU();
     
    31513354
    31523355                case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING:
     3356                    Assert(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY);
     3357                    Assert(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED);
    31533358                    rc = drvAudioStreamPreBufComitting(pThis, pStreamEx, (uint8_t const *)pvBuf, cbBuf, pcbWritten);
    31543359                    break;
     
    32223427        if (pThis->In.fEnabled) /* Input for this audio driver enabled? See #9822. */
    32233428        {
    3224             if (!PDMAudioStrmStatusCanRead(pStream->fStatus))
     3429            if (!PDMAudioStrmStatusCanRead(pStreamEx->fStatus))
    32253430            {
    32263431                rc = VERR_AUDIO_STREAM_NOT_READY;
     
    33163521     * ...
    33173522     */
    3318     AssertPtr(pThis->pHostDrvAudio->pfnStreamGetReadable);
    33193523    uint32_t cbReadable = pThis->pHostDrvAudio->pfnStreamGetReadable(pThis->pHostDrvAudio, pStreamEx->pBackend);
    33203524    if (!cbReadable)
     
    34943698    char szStreamSts[DRVAUDIO_STATUS_STR_MAX];
    34953699#endif
    3496     Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->Core.fStatus)));
     3700    Log3Func(("[%s] fStatus=%s\n", pStreamEx->Core.szName, dbgAudioStreamStatusToStr(szStreamSts, pStreamEx->fStatus)));
    34973701
    34983702    /*
     
    35093713
    35103714        if (   !pThis->In.fEnabled
    3511             || !PDMAudioStrmStatusCanRead(pStreamEx->Core.fStatus))
     3715            || !PDMAudioStrmStatusCanRead(pStreamEx->fStatus)
     3716            || !(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY))
    35123717        {
    35133718            rc = VERR_AUDIO_STREAM_NOT_READY;
     
    35153720        }
    35163721
    3517         /*
    3518          * Do the actual capturing.
    3519          */
    3520         if (RT_LIKELY(pStreamEx->Host.Cfg.enmLayout == PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED))
    3521             rc = drvAudioStreamCaptureNonInterleaved(pThis, pStreamEx, &cfCaptured);
    3522         else if (pStreamEx->Host.Cfg.enmLayout == PDMAUDIOSTREAMLAYOUT_RAW)
    3523             rc = drvAudioStreamCaptureRaw(pThis, pStreamEx, &cfCaptured);
     3722        uint32_t const fBackendStatus = drvAudioStreamGetBackendStatus(pThis, pStreamEx);
     3723        if (fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED)
     3724        {
     3725            /*
     3726             * Do the actual capturing.
     3727             */
     3728            if (RT_LIKELY(pStreamEx->Host.Cfg.enmLayout == PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED))
     3729                rc = drvAudioStreamCaptureNonInterleaved(pThis, pStreamEx, &cfCaptured);
     3730            else if (pStreamEx->Host.Cfg.enmLayout == PDMAUDIOSTREAMLAYOUT_RAW)
     3731                rc = drvAudioStreamCaptureRaw(pThis, pStreamEx, &cfCaptured);
     3732            else
     3733                AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
     3734
     3735            if (RT_SUCCESS(rc))
     3736            {
     3737                Log3Func(("[%s] %RU32 frames captured, rc=%Rrc\n", pStreamEx->Core.szName, cfCaptured, rc));
     3738
     3739                STAM_COUNTER_ADD(&pThis->Stats.TotalFramesIn,              cfCaptured);
     3740                STAM_COUNTER_ADD(&pStreamEx->In.Stats.TotalFramesCaptured, cfCaptured);
     3741            }
     3742            else if (RT_UNLIKELY(RT_FAILURE(rc)))
     3743                LogRel(("Audio: Capturing stream '%s' failed with %Rrc\n", pStreamEx->Core.szName, rc));
     3744        }
    35243745        else
    3525             AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
    3526 
    3527         if (RT_SUCCESS(rc))
    3528         {
    3529             Log3Func(("[%s] %RU32 frames captured, rc=%Rrc\n", pStreamEx->Core.szName, cfCaptured, rc));
    3530 
    3531             STAM_COUNTER_ADD(&pThis->Stats.TotalFramesIn,              cfCaptured);
    3532             STAM_COUNTER_ADD(&pStreamEx->In.Stats.TotalFramesCaptured, cfCaptured);
    3533         }
    3534         else if (RT_UNLIKELY(RT_FAILURE(rc)))
    3535             LogRel(("Audio: Capturing stream '%s' failed with %Rrc\n", pStreamEx->Core.szName, rc));
     3746            rc = VERR_AUDIO_STREAM_NOT_READY;
    35363747    } while (0);
    35373748
     
    35483759
    35493760/*********************************************************************************************************************************
    3550 *   PDMIAUDIONOTIFYFROMHOST interface implementation.                                                                            *
     3761*   PDMIHOSTAUDIOPORT interface implementation.                                                                                   *
    35513762*********************************************************************************************************************************/
    35523763
    35533764/**
     3765 * Worker for drvAudioHostPort_DoOnWorkerThread with stream argument, called on
     3766 * worker thread.
     3767 */
     3768static DECLCALLBACK(void) drvAudioHostPort_DoOnWorkerThreadStreamWorker(PDRVAUDIO pThis, PDRVAUDIOSTREAM pStreamEx,
     3769                                                                        uintptr_t uUser, void *pvUser)
     3770{
     3771    LogFlowFunc(("pThis=%p uUser=%#zx pvUser=%p\n", pThis, uUser, pvUser));
     3772    AssertPtrReturnVoid(pThis);
     3773    AssertPtrReturnVoid(pStreamEx);
     3774    AssertReturnVoid(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC);
     3775    PPDMIHOSTAUDIO const pIHostDrvAudio = pThis->pHostDrvAudio;
     3776    AssertPtrReturnVoid(pIHostDrvAudio);
     3777    AssertPtrReturnVoid(pIHostDrvAudio->pfnDoOnWorkerThread);
     3778
     3779    pIHostDrvAudio->pfnDoOnWorkerThread(pIHostDrvAudio, pStreamEx->pBackend, uUser, pvUser);
     3780
     3781    drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/);
     3782    LogFlowFunc(("returns\n"));
     3783}
     3784
     3785
     3786/**
     3787 * Worker for drvAudioHostPort_DoOnWorkerThread without stream argument, called
     3788 * on worker thread.
     3789 *
     3790 * This wrapper isn't technically required, but it helps with logging and a few
     3791 * extra sanity checks.
     3792 */
     3793static DECLCALLBACK(void) drvAudioHostPort_DoOnWorkerThreadWorker(PDRVAUDIO pThis, uintptr_t uUser, void *pvUser)
     3794{
     3795    LogFlowFunc(("pThis=%p uUser=%#zx pvUser=%p\n", pThis, uUser, pvUser));
     3796    AssertPtrReturnVoid(pThis);
     3797    PPDMIHOSTAUDIO const pIHostDrvAudio = pThis->pHostDrvAudio;
     3798    AssertPtrReturnVoid(pIHostDrvAudio);
     3799    AssertPtrReturnVoid(pIHostDrvAudio->pfnDoOnWorkerThread);
     3800
     3801    pIHostDrvAudio->pfnDoOnWorkerThread(pIHostDrvAudio, NULL, uUser, pvUser);
     3802
     3803    LogFlowFunc(("returns\n"));
     3804}
     3805
     3806
     3807/**
     3808 * @interface_method_impl{PDMIHOSTAUDIOPORT,pfnDoOnWorkerThread}
     3809 */
     3810static DECLCALLBACK(int) drvAudioHostPort_DoOnWorkerThread(PPDMIHOSTAUDIOPORT pInterface, PPDMAUDIOBACKENDSTREAM pStream,
     3811                                                           uintptr_t uUser, void *pvUser)
     3812{
     3813    PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IHostAudioPort);
     3814    LogFlowFunc(("pStream=%p uUser=%#zx pvUser=%p\n", pStream, uUser, pvUser));
     3815
     3816    /*
     3817     * Assert some sanity and do the work.
     3818     */
     3819    AssertReturn(pThis->pHostDrvAudio, VERR_INTERNAL_ERROR_3);
     3820    AssertReturn(pThis->pHostDrvAudio->pfnDoOnWorkerThread, VERR_INVALID_FUNCTION);
     3821    AssertReturn(pThis->hReqPool != NIL_RTREQPOOL, VERR_INVALID_FUNCTION);
     3822    int rc;
     3823    if (!pStream)
     3824    {
     3825        rc = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, NULL /*phReq*/, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
     3826                             (PFNRT)drvAudioHostPort_DoOnWorkerThreadWorker, 3, pThis, uUser, pvUser);
     3827        AssertRC(rc);
     3828    }
     3829    else
     3830    {
     3831        AssertPtrReturn(pStream, VERR_INVALID_POINTER);
     3832        AssertReturn(pStream->uMagic == PDMAUDIOBACKENDSTREAM_MAGIC, VERR_INVALID_MAGIC);
     3833        PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream->pStream;
     3834        AssertPtrReturn(pStreamEx, VERR_INVALID_POINTER);
     3835        AssertReturn(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC);
     3836        AssertReturn(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC, VERR_INVALID_MAGIC);
     3837
     3838        uint32_t cRefs = drvAudioStreamRetainInternal(pStreamEx);
     3839        if (cRefs != UINT32_MAX)
     3840        {
     3841            rc = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, NULL, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
     3842                                 (PFNRT)drvAudioHostPort_DoOnWorkerThreadStreamWorker,
     3843                                 4, pThis, pStreamEx, uUser, pvUser);
     3844            AssertRC(rc);
     3845            if (RT_FAILURE(rc))
     3846                drvAudioStreamReleaseInternal(pThis, pStreamEx, true /*fMayDestroy*/);
     3847        }
     3848        else
     3849            rc = VERR_INVALID_PARAMETER;
     3850    }
     3851    LogFlowFunc(("returns %Rrc\n", rc));
     3852    return rc;
     3853}
     3854
     3855
     3856/**
    35543857 * Marks a stream for re-init.
    35553858 */
     
    35573860{
    35583861    LogFlow((LOG_FN_FMT ": Flagging %s for re-init.\n", pszCaller, pStreamEx->Core.szName)); RT_NOREF(pszCaller);
    3559     pStreamEx->Core.fStatus |= PDMAUDIOSTREAM_STS_NEED_REINIT;
    3560     PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->Core.fStatus);
     3862    pStreamEx->fStatus      |= PDMAUDIOSTREAM_STS_NEED_REINIT;
     3863    PDMAUDIOSTREAM_STS_ASSERT_VALID(pStreamEx->fStatus);
    35613864    pStreamEx->cTriesReInit  = 0;
    35623865    pStreamEx->nsLastReInit  = 0;
     
    35653868
    35663869/**
    3567  * @interface_method_impl{PDMIAUDIONOTIFYFROMHOST,pfnNotifyDeviceChanged}
    3568  */
    3569 static DECLCALLBACK(void) drvAudioNotifyFromHost_NotifyDeviceChanged(PPDMIAUDIONOTIFYFROMHOST pInterface,
    3570                                                                      PDMAUDIODIR enmDir, void *pvUser)
    3571 {
    3572     PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioNotifyFromHost);
     3870 * @interface_method_impl{PDMIHOSTAUDIOPORT,pfnNotifyDeviceChanged}
     3871 */
     3872static DECLCALLBACK(void) drvAudioHostPort_NotifyDeviceChanged(PPDMIHOSTAUDIOPORT pInterface, PDMAUDIODIR enmDir, void *pvUser)
     3873{
     3874    PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IHostAudioPort);
    35733875    AssertReturnVoid(enmDir == PDMAUDIODIR_IN || enmDir == PDMAUDIODIR_OUT);
    35743876    LogRel(("Audio: The %s device for %s is changing.\n", enmDir == PDMAUDIODIR_IN ? "input" : "output", pThis->szName));
     
    35963898
    35973899/**
    3598  * @interface_method_impl{PDMIAUDIONOTIFYFROMHOST,pfnStreamNotifyDeviceChanged}
    3599  */
    3600 static DECLCALLBACK(void) drvAudioNotifyFromHost_StreamNotifyDeviceChanged(PPDMIAUDIONOTIFYFROMHOST pInterface,
    3601                                                                            PPDMAUDIOBACKENDSTREAM pStream, bool fReInit)
    3602 {
    3603     PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioNotifyFromHost);
     3900 * @interface_method_impl{PDMIHOSTAUDIOPORT,pfnStreamNotifyDeviceChanged}
     3901 */
     3902static DECLCALLBACK(void) drvAudioHostPort_StreamNotifyDeviceChanged(PPDMIHOSTAUDIOPORT pInterface,
     3903                                                                     PPDMAUDIOBACKENDSTREAM pStream, bool fReInit)
     3904{
     3905    PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IHostAudioPort);
    36043906
    36053907    /*
     
    36303932         * know which thread we're on, do we now).
    36313933         */
    3632         AssertStmt(!(pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT),
    3633                    pStreamEx->Core.fStatus &= ~PDMAUDIOSTREAM_STS_NEED_REINIT);
     3934        AssertStmt(!(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_NEED_REINIT),
     3935                   pStreamEx->fStatus &= ~PDMAUDIOSTREAM_STS_NEED_REINIT);
    36343936
    36353937        if (   pStreamEx->Core.enmDir == PDMAUDIODIR_OUT
    3636             && (pStreamEx->Core.fStatus & PDMAUDIOSTREAM_STS_ENABLED))
     3938            && (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED))
    36373939        {
    36383940            DRVAUDIOPLAYSTATE const enmPlayState = pStreamEx->Out.enmPlayState;
     
    36483950
    36493951/**
    3650  * @interface_method_impl{PDMIAUDIONOTIFYFROMHOST,pfnNotifyDevicesChanged}
    3651  */
    3652 static DECLCALLBACK(void) drvAudioNotifyFromHost_NotifyDevicesChanged(PPDMIAUDIONOTIFYFROMHOST pInterface)
    3653 {
    3654     PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioNotifyFromHost);
     3952 * @interface_method_impl{PDMIHOSTAUDIOPORT,pfnNotifyDevicesChanged}
     3953 */
     3954static DECLCALLBACK(void) drvAudioHostPort_NotifyDevicesChanged(PPDMIHOSTAUDIOPORT pInterface)
     3955{
     3956    PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IHostAudioPort);
    36553957    LogRel(("Audio: Device configuration of driver '%s' has changed\n", pThis->szName));
    36563958
     
    36903992    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
    36913993    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIAUDIOCONNECTOR, &pThis->IAudioConnector);
    3692     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIAUDIONOTIFYFROMHOST, &pThis->IAudioNotifyFromHost);
     3994    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIOPORT, &pThis->IHostAudioPort);
    36933995
    36943996    return NULL;
     
    37234025        {
    37244026            drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE);
     4027#if 0 /* This leads to double destruction. Also in the backend when we don't set pHostDrvAudio to NULL below. */
    37254028            drvAudioStreamDestroyInternalBackend(pThis, pStreamEx);
    3726         }
    3727 
     4029#endif
     4030        }
     4031
     4032#if 0 /* Messes up using drvAudioHostPort_DoOnWorkerThread from the backend drivers' power off callback.  */
    37284033        pThis->pHostDrvAudio = NULL;
     4034#endif
    37294035    }
    37304036
     
    37484054    AssertRC(rc);
    37494055
    3750     LogFunc(("%s (detached %p)\n", pThis->szName, pThis->pHostDrvAudio));
     4056    LogFunc(("%s (detached %p, hReqPool=%p)\n", pThis->szName, pThis->pHostDrvAudio, pThis->hReqPool));
     4057
     4058    /*
     4059     * Must first destroy the thread pool first so we are certain no threads
     4060     * are still using the instance being detached.  Release lock while doing
     4061     * this as the thread functions may need to take it to complete.
     4062     */
     4063    if (pThis->pHostDrvAudio && pThis->hReqPool != NIL_RTREQPOOL)
     4064    {
     4065        RTREQPOOL hReqPool = pThis->hReqPool;
     4066        pThis->hReqPool = NIL_RTREQPOOL;
     4067        RTCritSectLeave(&pThis->CritSect);
     4068
     4069        RTReqPoolRelease(hReqPool);
     4070
     4071        RTCritSectEnter(&pThis->CritSect);
     4072    }
     4073
     4074    /*
     4075     * Now we can safely set pHostDrvAudio to NULL.
     4076     */
    37514077    pThis->pHostDrvAudio = NULL;
    37524078
     
    37694095     * mandatory are present.
    37704096     */
    3771     PPDMIHOSTAUDIO pHostDrvAudio = pThis->pHostDrvAudio;
    3772     AssertPtrReturn(pHostDrvAudio, VERR_INVALID_POINTER);
    3773     AssertPtrReturn(pHostDrvAudio->pfnGetConfig, VERR_INVALID_POINTER);
    3774     AssertPtrNullReturn(pHostDrvAudio->pfnGetDevices, VERR_INVALID_POINTER);
    3775     AssertPtrNullReturn(pHostDrvAudio->pfnGetStatus, VERR_INVALID_POINTER);
    3776     AssertPtrNullReturn(pHostDrvAudio->pfnStreamConfigHint, VERR_INVALID_POINTER);
    3777     AssertPtrReturn(pHostDrvAudio->pfnStreamCreate, VERR_INVALID_POINTER);
    3778     AssertPtrReturn(pHostDrvAudio->pfnStreamDestroy, VERR_INVALID_POINTER);
    3779     AssertPtrNullReturn(pHostDrvAudio->pfnStreamNotifyDeviceChanged, VERR_INVALID_POINTER);
    3780     AssertPtrReturn(pHostDrvAudio->pfnStreamControl, VERR_INVALID_POINTER);
    3781     AssertPtrReturn(pHostDrvAudio->pfnStreamGetReadable, VERR_INVALID_POINTER);
    3782     AssertPtrReturn(pHostDrvAudio->pfnStreamGetWritable, VERR_INVALID_POINTER);
    3783     AssertPtrNullReturn(pHostDrvAudio->pfnStreamGetPending, VERR_INVALID_POINTER);
    3784     AssertPtrReturn(pHostDrvAudio->pfnStreamGetStatus, VERR_INVALID_POINTER);
    3785     AssertPtrReturn(pHostDrvAudio->pfnStreamPlay, VERR_INVALID_POINTER);
    3786     AssertPtrReturn(pHostDrvAudio->pfnStreamCapture, VERR_INVALID_POINTER);
     4097    PPDMIHOSTAUDIO pIHostDrvAudio = pThis->pHostDrvAudio;
     4098    AssertPtrReturn(pIHostDrvAudio, VERR_INVALID_POINTER);
     4099    AssertPtrReturn(pIHostDrvAudio->pfnGetConfig, VERR_INVALID_POINTER);
     4100    AssertPtrNullReturn(pIHostDrvAudio->pfnGetDevices, VERR_INVALID_POINTER);
     4101    AssertPtrNullReturn(pIHostDrvAudio->pfnGetStatus, VERR_INVALID_POINTER);
     4102    AssertPtrNullReturn(pIHostDrvAudio->pfnDoOnWorkerThread, VERR_INVALID_POINTER);
     4103    AssertPtrNullReturn(pIHostDrvAudio->pfnStreamConfigHint, VERR_INVALID_POINTER);
     4104    AssertPtrReturn(pIHostDrvAudio->pfnStreamCreate, VERR_INVALID_POINTER);
     4105    AssertPtrNullReturn(pIHostDrvAudio->pfnStreamInitAsync, VERR_INVALID_POINTER);
     4106    AssertPtrReturn(pIHostDrvAudio->pfnStreamDestroy, VERR_INVALID_POINTER);
     4107    AssertPtrNullReturn(pIHostDrvAudio->pfnStreamNotifyDeviceChanged, VERR_INVALID_POINTER);
     4108    AssertPtrReturn(pIHostDrvAudio->pfnStreamControl, VERR_INVALID_POINTER);
     4109    AssertPtrReturn(pIHostDrvAudio->pfnStreamGetReadable, VERR_INVALID_POINTER);
     4110    AssertPtrReturn(pIHostDrvAudio->pfnStreamGetWritable, VERR_INVALID_POINTER);
     4111    AssertPtrNullReturn(pIHostDrvAudio->pfnStreamGetPending, VERR_INVALID_POINTER);
     4112    AssertPtrReturn(pIHostDrvAudio->pfnStreamGetStatus, VERR_INVALID_POINTER);
     4113    AssertPtrReturn(pIHostDrvAudio->pfnStreamPlay, VERR_INVALID_POINTER);
     4114    AssertPtrReturn(pIHostDrvAudio->pfnStreamCapture, VERR_INVALID_POINTER);
    37874115
    37884116    /*
    37894117     * Get the backend configuration.
    37904118     */
    3791     int rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg);
     4119    int rc = pIHostDrvAudio->pfnGetConfig(pIHostDrvAudio, &pThis->BackendCfg);
    37924120    if (RT_FAILURE(rc))
    37934121    {
     
    38084136    if (rc2 != VERR_NOT_SUPPORTED) /* Some backends don't implement device enumeration. */
    38094137        AssertRC(rc2);
    3810 
    3811     RT_NOREF(rc2);
    3812     /* Ignore rc. */
     4138    /* Ignore rc2. */
    38134139#endif
     4140
     4141    /*
     4142     * Create a thread pool if stream creation can be asynchronous.
     4143     *
     4144     * The pool employs no pushback as the caller is typically EMT and
     4145     * shouldn't be delayed.
     4146     *
     4147     * The number of threads limits and the device implementations use
     4148     * of pfnStreamDestroy limits the number of streams pending async
     4149     * init.  We use RTReqCancel in drvAudioStreamDestroy to allow us
     4150     * to release extra reference held by the pfnStreamInitAsync call
     4151     * if successful.  Cancellation will only be possible if the call
     4152     * hasn't been picked up by a worker thread yet, so the max number
     4153     * of threads in the pool defines how many destroyed streams that
     4154     * can be lingering.  (We must keep this under control, otherwise
     4155     * an evil guest could just rapidly trigger stream creation and
     4156     * destruction to consume host heap and hog CPU resources for
     4157     * configuring audio backends.)
     4158     */
     4159    if (   pThis->hReqPool == NIL_RTREQPOOL
     4160        && (   pIHostDrvAudio->pfnStreamInitAsync
     4161            || pIHostDrvAudio->pfnDoOnWorkerThread
     4162            || (pThis->BackendCfg.fFlags & PDMAUDIOBACKEND_F_ASYNC_HINT) ))
     4163    {
     4164        char szName[16];
     4165        RTStrPrintf(szName, sizeof(szName), "Aud%uWr", pThis->pDrvIns->iInstance);
     4166        RTREQPOOL hReqPool = NIL_RTREQPOOL;
     4167        rc = RTReqPoolCreate(3 /*cMaxThreads*/, RT_MS_30SEC /*cMsMinIdle*/, UINT32_MAX /*cThreadsPushBackThreshold*/,
     4168                             1 /*cMsMaxPushBack*/, szName, &hReqPool);
     4169        LogFlowFunc(("Creating thread pool '%s': %Rrc, hReqPool=%p\n", szName, rc, hReqPool));
     4170        AssertRCReturn(rc, rc);
     4171
     4172        rc = RTReqPoolSetCfgVar(hReqPool, RTREQPOOLCFGVAR_THREAD_FLAGS, RTTHREADFLAGS_COM_MTA);
     4173        AssertRCReturnStmt(rc, RTReqPoolRelease(hReqPool), rc);
     4174
     4175        rc = RTReqPoolSetCfgVar(hReqPool, RTREQPOOLCFGVAR_MIN_THREADS, 1);
     4176        AssertRC(rc); /* harmless */
     4177
     4178        pThis->hReqPool = hReqPool;
     4179    }
     4180    else
     4181        LogFlowFunc(("No thread pool.\n"));
    38144182
    38154183    LogFlowFuncLeave();
     
    40224390#endif
    40234391
     4392    if (pThis->hReqPool != NIL_RTREQPOOL)
     4393    {
     4394        uint32_t cRefs = RTReqPoolRelease(pThis->hReqPool);
     4395        Assert(cRefs == 0); RT_NOREF(cRefs);
     4396        pThis->hReqPool = NIL_RTREQPOOL;
     4397    }
     4398
    40244399    LogFlowFuncLeave();
    40254400}
     
    40414416     */
    40424417    RTListInit(&pThis->lstStreams);
     4418    pThis->hReqPool = NIL_RTREQPOOL;
    40434419
    40444420    /*
     
    42214597    pThis->IAudioConnector.pfnStreamRead        = drvAudioStreamRead;
    42224598    pThis->IAudioConnector.pfnStreamCapture     = drvAudioStreamCapture;
    4223     /* IAudioNotifyFromHost */
    4224     pThis->IAudioNotifyFromHost.pfnNotifyDeviceChanged          = drvAudioNotifyFromHost_NotifyDeviceChanged;
    4225     pThis->IAudioNotifyFromHost.pfnStreamNotifyDeviceChanged    = drvAudioNotifyFromHost_StreamNotifyDeviceChanged;
    4226     pThis->IAudioNotifyFromHost.pfnNotifyDevicesChanged         = drvAudioNotifyFromHost_NotifyDevicesChanged;
     4599    /* IHostAudioPort */
     4600    pThis->IHostAudioPort.pfnDoOnWorkerThread           = drvAudioHostPort_DoOnWorkerThread;
     4601    pThis->IHostAudioPort.pfnNotifyDeviceChanged        = drvAudioHostPort_NotifyDeviceChanged;
     4602    pThis->IHostAudioPort.pfnStreamNotifyDeviceChanged  = drvAudioHostPort_StreamNotifyDeviceChanged;
     4603    pThis->IHostAudioPort.pfnNotifyDevicesChanged       = drvAudioHostPort_NotifyDevicesChanged;
    42274604
    42284605    /*
  • trunk/src/VBox/Devices/Audio/DrvHostAudioAlsa.cpp

    r88761 r88819  
    14081408    pThis->IHostAudio.pfnGetDevices                 = drvHostAlsaAudioHA_GetDevices;
    14091409    pThis->IHostAudio.pfnGetStatus                  = drvHostAlsaAudioHA_GetStatus;
     1410    pThis->IHostAudio.pfnDoOnWorkerThread           = NULL;
     1411    pThis->IHostAudio.pfnStreamConfigHint           = NULL;
    14101412    pThis->IHostAudio.pfnStreamCreate               = drvHostAlsaAudioHA_StreamCreate;
     1413    pThis->IHostAudio.pfnStreamInitAsync            = NULL;
    14111414    pThis->IHostAudio.pfnStreamDestroy              = drvHostAlsaAudioHA_StreamDestroy;
    14121415    pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = NULL;
  • trunk/src/VBox/Devices/Audio/DrvHostAudioCoreAudio.cpp

    r88761 r88819  
    25472547    pThis->IHostAudio.pfnGetConfig                  = drvHostCoreAudioHA_GetConfig;
    25482548    pThis->IHostAudio.pfnGetStatus                  = drvHostCoreAudioHA_GetStatus;
     2549    pThis->IHostAudio.pfnDoOnWorkerThread           = NULL;
     2550    pThis->IHostAudio.pfnStreamConfigHint           = NULL;
    25492551    pThis->IHostAudio.pfnStreamCreate               = drvHostCoreAudioHA_StreamCreate;
     2552    pThis->IHostAudio.pfnStreamInitAsync            = NULL;
    25502553    pThis->IHostAudio.pfnStreamDestroy              = drvHostCoreAudioHA_StreamDestroy;
    25512554    pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = NULL;
  • trunk/src/VBox/Devices/Audio/DrvHostAudioDSound.cpp

    r88761 r88819  
    27612761    pThis->IHostAudio.pfnGetDevices                 = drvHostDSoundHA_GetDevices;
    27622762    pThis->IHostAudio.pfnGetStatus                  = drvHostDSoundHA_GetStatus;
     2763    pThis->IHostAudio.pfnDoOnWorkerThread           = NULL;
     2764    pThis->IHostAudio.pfnStreamConfigHint           = NULL;
    27632765    pThis->IHostAudio.pfnStreamCreate               = drvHostDSoundHA_StreamCreate;
     2766    pThis->IHostAudio.pfnStreamInitAsync            = NULL;
    27642767    pThis->IHostAudio.pfnStreamDestroy              = drvHostDSoundHA_StreamDestroy;
    27652768    pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = NULL;
     
    28012804        /* Get the notification interface (from DrvAudio). */
    28022805# ifdef VBOX_WITH_AUDIO_CALLBACKS
    2803         PPDMIAUDIONOTIFYFROMHOST pIAudioNotifyFromHost = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIONOTIFYFROMHOST);
    2804         Assert(pIAudioNotifyFromHost);
     2806        PPDMIHOSTAUDIOPORT pIHostAudioPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIHOSTAUDIOPORT);
     2807        Assert(pIHostAudioPort);
    28052808# else
    2806         PPDMIAUDIONOTIFYFROMHOST pIAudioNotifyFromHost = NULL;
     2809        PPDMIHOSTAUDIOPORT pIHostAudioPort = NULL;
    28072810# endif
    28082811        try
    28092812        {
    2810             pThis->m_pNotificationClient = new DrvHostAudioDSoundMMNotifClient(pIAudioNotifyFromHost);
     2813            pThis->m_pNotificationClient = new DrvHostAudioDSoundMMNotifClient(pIHostAudioPort);
    28112814        }
    28122815        catch (std::bad_alloc &)
  • trunk/src/VBox/Devices/Audio/DrvHostAudioDSoundMMNotifClient.cpp

    r88361 r88819  
    3030
    3131
    32 DrvHostAudioDSoundMMNotifClient::DrvHostAudioDSoundMMNotifClient(PPDMIAUDIONOTIFYFROMHOST pInterface)
     32DrvHostAudioDSoundMMNotifClient::DrvHostAudioDSoundMMNotifClient(PPDMIHOSTAUDIOPORT pInterface)
    3333    : m_fRegisteredClient(false)
    3434    , m_cRef(1)
  • trunk/src/VBox/Devices/Audio/DrvHostAudioDSoundMMNotifClient.h

    r88628 r88819  
    4343public:
    4444
    45     DrvHostAudioDSoundMMNotifClient(PPDMIAUDIONOTIFYFROMHOST pInterface);
     45    DrvHostAudioDSoundMMNotifClient(PPDMIHOSTAUDIOPORT pInterface);
    4646    virtual ~DrvHostAudioDSoundMMNotifClient();
    4747
     
    6464    long                        m_cRef;
    6565
    66     PPDMIAUDIONOTIFYFROMHOST    m_pIAudioNotifyFromHost;
     66    PPDMIHOSTAUDIOPORT           m_pIAudioNotifyFromHost;
    6767
    6868    HRESULT AttachToDefaultEndpoint();
  • trunk/src/VBox/Devices/Audio/DrvHostAudioDebug.cpp

    r88761 r88819  
    438438    pThis->IHostAudio.pfnGetDevices                 = NULL;
    439439    pThis->IHostAudio.pfnGetStatus                  = drvHostDebugAudioHA_GetStatus;
     440    pThis->IHostAudio.pfnDoOnWorkerThread           = NULL;
     441    pThis->IHostAudio.pfnStreamConfigHint           = NULL;
    440442    pThis->IHostAudio.pfnStreamCreate               = drvHostDebugAudioHA_StreamCreate;
     443    pThis->IHostAudio.pfnStreamInitAsync            = NULL;
    441444    pThis->IHostAudio.pfnStreamDestroy              = drvHostDebugAudioHA_StreamDestroy;
    442445    pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = NULL;
  • trunk/src/VBox/Devices/Audio/DrvHostAudioNull.cpp

    r88760 r88819  
    232232    /* .pfnGetDevices                =*/ NULL,
    233233    /* .pfnGetStatus                 =*/ drvHostNullAudioHA_GetStatus,
     234    /* .pfnDoOnWorkerThread          =*/ NULL,
    234235    /* .pfnStreamConfigHint          =*/ NULL,
    235236    /* .pfnStreamCreate              =*/ drvHostNullAudioHA_StreamCreate,
     237    /* .pfnStreamInitAsync           =*/ NULL,
    236238    /* .pfnStreamDestroy             =*/ drvHostNullAudioHA_StreamDestroy,
    237239    /* .pfnStreamNotifyDeviceChanged =*/ NULL,
  • trunk/src/VBox/Devices/Audio/DrvHostAudioOss.cpp

    r88761 r88819  
    861861    pThis->IHostAudio.pfnGetDevices                 = NULL;
    862862    pThis->IHostAudio.pfnGetStatus                  = drvHostOssAudioHA_GetStatus;
     863    pThis->IHostAudio.pfnDoOnWorkerThread           = NULL;
     864    pThis->IHostAudio.pfnStreamConfigHint           = NULL;
    863865    pThis->IHostAudio.pfnStreamCreate               = drvHostOssAudioHA_StreamCreate;
     866    pThis->IHostAudio.pfnStreamInitAsync            = NULL;
    864867    pThis->IHostAudio.pfnStreamDestroy              = drvHostOssAudioHA_StreamDestroy;
    865868    pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = NULL;
  • trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudio.cpp

    r88761 r88819  
    19151915    pThis->IHostAudio.pfnGetDevices                 = drvHostAudioPaHA_GetDevices;
    19161916    pThis->IHostAudio.pfnGetStatus                  = drvHostAudioPaHA_GetStatus;
     1917    pThis->IHostAudio.pfnDoOnWorkerThread           = NULL;
     1918    pThis->IHostAudio.pfnStreamConfigHint           = NULL;
    19171919    pThis->IHostAudio.pfnStreamCreate               = drvHostAudioPaHA_StreamCreate;
     1920    pThis->IHostAudio.pfnStreamInitAsync            = NULL;
    19181921    pThis->IHostAudio.pfnStreamDestroy              = drvHostAudioPaHA_StreamDestroy;
    19191922    pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = NULL;
  • trunk/src/VBox/Devices/Audio/DrvHostAudioValidationKit.cpp

    r88761 r88819  
    435435    pThis->IHostAudio.pfnGetDevices                 = NULL;
    436436    pThis->IHostAudio.pfnGetStatus                  = drvHostValKitAudioHA_GetStatus;
     437    pThis->IHostAudio.pfnDoOnWorkerThread           = NULL;
     438    pThis->IHostAudio.pfnStreamConfigHint           = NULL;
    437439    pThis->IHostAudio.pfnStreamCreate               = drvHostValKitAudioHA_StreamCreate;
     440    pThis->IHostAudio.pfnStreamInitAsync            = NULL;
    438441    pThis->IHostAudio.pfnStreamDestroy              = drvHostValKitAudioHA_StreamDestroy;
    439442    pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = NULL;
  • trunk/src/VBox/Devices/Audio/DrvHostAudioWasApi.cpp

    r88776 r88819  
    5353#define VBOX_WASAPI_MAX_PADDING         UINT32_C(0x007fffff)
    5454
     55#if 0
    5556/** @name WM_DRVHOSTAUDIOWAS_XXX - Worker thread messages.
    5657 * @{ */
    57 /** Adds entry to the cache.
    58  * lParam points to a PDMAUDIOSTREAMCFG structure with the details. RTMemFree
    59  * when done. */
    60 #define WM_DRVHOSTAUDIOWAS_HINT         (WM_APP + 2)
    61 #define WM_DRVHOSTAUDIOWAS_PURGE_CACHE  (WM_APP + 1)
     58#define WM_DRVHOSTAUDIOWAS_PURGE_CACHE  (WM_APP + 3)
     59/** @} */
     60#endif
     61
     62
     63/** @name DRVHOSTAUDIOWAS_DO_XXX - Worker thread operations.
     64 * @{ */
     65#define DRVHOSTAUDIOWAS_DO_PURGE_CACHE      ((uintptr_t)0x49f37300 + 1)
    6266/** @} */
    6367
     
    100104    /** The device/whatever period in frames. */
    101105    uint32_t                    cFramesPeriod;
     106    /** The setup status code.
     107     * This is set to VERR_AUDIO_STREAM_INIT_IN_PROGRESS while the asynchronous
     108     * initialization is still running. */
     109    int volatile                rcSetup;
     110    /** Creation timestamp (just for reference). */
     111    uint64_t                    nsCreated;
     112    /** Init complete timestamp (just for reference). */
     113    uint64_t                    nsInited;
    102114    /** The stringified properties. */
    103115    char                        szProps[32];
     
    207219     * implementing enumeration. */
    208220    IMMDeviceEnumerator            *pIEnumerator;
    209     /** Notification interface.  */
    210     PPDMIAUDIONOTIFYFROMHOST        pIAudioNotifyFromHost;
     221    /** The upwards interface. */
     222    PPDMIHOSTAUDIOPORT              pIHostAudioPort;
    211223    /** The output device ID, NULL for default. */
    212224    PRTUTF16                        pwszOutputDevId;
     
    240252    RTCRITSECT                      CritSectCache;
    241253
     254#if 0
    242255    /** The worker thread. */
    243256    RTTHREAD                        hWorkerThread;
     
    246259    /** The fixed wParam value for the worker thread. */
    247260    WPARAM                          uWorkerThreadFixedParam;
    248 
     261#endif
    249262} DRVHOSTAUDIOWAS;
    250263/** Pointer to the data for a WASAPI host audio driver instance. */
     
    273286    static RTSTRTUPLE const s_aStarted[2] =
    274287    {
    275         RT_STR_TUPLE(" STARTED"),
    276         RT_STR_TUPLE(" STOPPED")
     288        RT_STR_TUPLE(" STOPPED"),
     289        RT_STR_TUPLE(" STARTED")
    277290    };
    278291    pTuple = &s_aStarted[pStreamWas->fStarted];
     
    549562 * Converts from PDM stream config to windows WAVEFORMATEX struct.
    550563 *
    551  * @param   pCfg    The PDM audio stream config to convert from.
     564 * @param   pProps  The PDM audio PCM properties to convert from.
    552565 * @param   pFmt    The windows structure to initialize.
    553566 */
    554 static void drvHostAudioWasWaveFmtExFromCfg(PCPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt)
     567static void drvHostAudioWasWaveFmtExFromProps(PCPDMAUDIOPCMPROPS pProps, PWAVEFORMATEX pFmt)
    555568{
    556569    RT_ZERO(*pFmt);
    557570    pFmt->wFormatTag      = WAVE_FORMAT_PCM;
    558     pFmt->nChannels       = PDMAudioPropsChannels(&pCfg->Props);
    559     pFmt->wBitsPerSample  = PDMAudioPropsSampleBits(&pCfg->Props);
    560     pFmt->nSamplesPerSec  = PDMAudioPropsHz(&pCfg->Props);
    561     pFmt->nBlockAlign     = PDMAudioPropsFrameSize(&pCfg->Props);
    562     pFmt->nAvgBytesPerSec = PDMAudioPropsFramesToBytes(&pCfg->Props, PDMAudioPropsHz(&pCfg->Props));
     571    pFmt->nChannels       = PDMAudioPropsChannels(pProps);
     572    pFmt->wBitsPerSample  = PDMAudioPropsSampleBits(pProps);
     573    pFmt->nSamplesPerSec  = PDMAudioPropsHz(pProps);
     574    pFmt->nBlockAlign     = PDMAudioPropsFrameSize(pProps);
     575    pFmt->nAvgBytesPerSec = PDMAudioPropsFramesToBytes(pProps, PDMAudioPropsHz(pProps));
    563576    pFmt->cbSize          = 0; /* No extra data specified. */
    564577}
    565578
    566579
     580#if 0 /* unused */
    567581/**
    568582 * Converts from windows WAVEFORMATEX and stream props to PDM audio properties.
     
    607621    return VERR_AUDIO_STREAM_COULD_NOT_CREATE;
    608622}
     623#endif
    609624
    610625
     
    714729}
    715730
    716 /**
    717  * Creates a device config entry using the given parameters.
     731
     732/**
     733 * Initializes a device config entry.
    718734 *
    719  * The entry is not added to the cache but returned.
     735 * This is usually done on the worker thread.
    720736 *
    721  * @returns Pointer to the new device config entry. NULL on failure.
    722  * @param   pDevEntry       The device entry it belongs to.
    723  * @param   pCfgReq         The requested configuration.
    724  * @param   pWaveFmtEx      The actual configuration.
    725  * @param   pIAudioClient   The audio client, reference consumed.
    726  */
    727 static PDRVHOSTAUDIOWASCACHEDEVCFG
    728 drvHostAudioWasCacheCreateConfig(PDRVHOSTAUDIOWASCACHEDEV pDevEntry, PCPDMAUDIOSTREAMCFG pCfgReq,
    729                                  WAVEFORMATEX const *pWaveFmtEx, IAudioClient *pIAudioClient)
    730 {
    731     PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = (PDRVHOSTAUDIOWASCACHEDEVCFG)RTMemAllocZ(sizeof(*pDevCfg));
    732     if (pDevCfg)
    733     {
    734         RTListInit(&pDevCfg->ListEntry);
    735         pDevCfg->pDevEntry          = pDevEntry;
    736         pDevCfg->pIAudioClient      = pIAudioClient;
    737         HRESULT hrc;
    738         if (pCfgReq->enmDir == PDMAUDIODIR_IN)
    739             hrc = pIAudioClient->GetService(__uuidof(IAudioCaptureClient), (void **)&pDevCfg->pIAudioCaptureClient);
    740         else
    741             hrc = pIAudioClient->GetService(__uuidof(IAudioRenderClient), (void **)&pDevCfg->pIAudioRenderClient);
    742         Log8Func(("GetService -> %Rhrc + %p\n", hrc, pCfgReq->enmDir == PDMAUDIODIR_IN
    743                   ? (void *)pDevCfg->pIAudioCaptureClient : (void *)pDevCfg->pIAudioRenderClient));
    744         if (SUCCEEDED(hrc))
    745         {
    746             /*
    747              * Obtain the actual stream format and buffer config.
    748              * (A bit ugly structure here to keep it from hitting the right margin. Sorry.)
    749              */
    750             UINT32          cFramesBufferSize       = 0;
    751             REFERENCE_TIME  cDefaultPeriodInNtTicks = 0;
    752             REFERENCE_TIME  cMinimumPeriodInNtTicks = 0;
    753             REFERENCE_TIME  cLatencyinNtTicks       = 0;
    754             hrc = pIAudioClient->GetBufferSize(&cFramesBufferSize);
    755             if (SUCCEEDED(hrc))
    756                 hrc = pIAudioClient->GetDevicePeriod(&cDefaultPeriodInNtTicks, &cMinimumPeriodInNtTicks);
    757             else
    758                 LogRelMax(64, ("WasAPI: GetBufferSize failed: %Rhrc\n", hrc));
    759             if (SUCCEEDED(hrc))
    760                 hrc = pIAudioClient->GetStreamLatency(&cLatencyinNtTicks);
    761             else
    762                 LogRelMax(64, ("WasAPI: GetDevicePeriod failed: %Rhrc\n", hrc));
    763             if (SUCCEEDED(hrc))
    764             {
    765                 LogRel2(("WasAPI: Aquired buffer parameters for %s:\n"
    766                          "WasAPI:   cFramesBufferSize       = %RU32\n"
    767                          "WasAPI:   cDefaultPeriodInNtTicks = %RI64\n"
    768                          "WasAPI:   cMinimumPeriodInNtTicks = %RI64\n"
    769                          "WasAPI:   cLatencyinNtTicks       = %RI64\n",
    770                          pCfgReq->szName, cFramesBufferSize, cDefaultPeriodInNtTicks, cMinimumPeriodInNtTicks, cLatencyinNtTicks));
    771 
    772                 int rc = drvHostAudioWasCacheWaveFmtExToProps(&pDevCfg->Props, pWaveFmtEx, pCfgReq->szName, pDevEntry->wszDevId);
    773                 if (RT_SUCCESS(rc))
    774                 {
    775                     pDevCfg->cFramesBufferSize = cFramesBufferSize;
    776                     pDevCfg->cFramesPeriod     = PDMAudioPropsNanoToFrames(&pDevCfg->Props, cDefaultPeriodInNtTicks * 100);
    777 
    778                     PDMAudioPropsToString(&pDevCfg->Props, pDevCfg->szProps, sizeof(pDevCfg->szProps));
    779                     return pDevCfg;
    780                 }
    781             }
    782             else
    783                 LogRelMax(64, ("WasAPI: GetStreamLatency failed: %Rhrc\n", hrc));
    784 
    785             if (pDevCfg->pIAudioCaptureClient)
    786             {
    787                 pDevCfg->pIAudioCaptureClient->Release();
    788                 pDevCfg->pIAudioCaptureClient = NULL;
    789             }
    790 
    791             if (pDevCfg->pIAudioRenderClient)
    792             {
    793                 pDevCfg->pIAudioRenderClient->Release();
    794                 pDevCfg->pIAudioRenderClient = NULL;
    795             }
    796         }
    797         RTMemFree(pDevCfg);
    798     }
    799     pIAudioClient->Release();
    800     return NULL;
    801 }
    802 
    803 
    804 /**
    805  * Worker for drvHostAudioWasCacheLookupOrCreate.
    806  *
    807  * If lookup fails, a new entry will be created.
    808  *
    809  * @note    Called holding the lock, returning without holding it!
    810  */
    811 static PDRVHOSTAUDIOWASCACHEDEVCFG
    812 drvHostAudioWasCacheLookupOrCreateConfig(PDRVHOSTAUDIOWAS pThis, PDRVHOSTAUDIOWASCACHEDEV pDevEntry, PCPDMAUDIOSTREAMCFG pCfgReq)
    813 {
    814     char szProps[64];
    815     PDMAudioPropsToString(&pCfgReq->Props, szProps, sizeof(szProps));
    816 
    817     /*
    818      * Check if we've got a matching config.
    819      */
    820     PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = drvHostAudioWasCacheLookupLocked(pDevEntry, &pCfgReq->Props);
    821     if (pDevCfg)
    822     {
    823         RTCritSectLeave(&pThis->CritSectCache);
    824         Log8Func(("Config cache hit '%s' (for '%s') on '%ls': %p\n", pDevCfg->szProps, szProps, pDevEntry->wszDevId, pDevCfg));
    825         return pDevCfg;
    826     }
    827 
    828     /*
    829      * We now need an IAudioClient interface for calling IsFormatSupported
     737 * @returns VBox status code.
     738 * @param   pDevCfg         The device configuration entry to initialize.
     739 */
     740static int drvHostAudioWasCacheInitConfig(PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg)
     741{
     742    /*
     743     * Assert some sanity given that we migth be called on the worker thread
     744     * and pDevCfg being a message parameter.
     745     */
     746    AssertPtrReturn(pDevCfg, VERR_INTERNAL_ERROR_2);
     747    AssertReturn(pDevCfg->rcSetup == VERR_AUDIO_STREAM_INIT_IN_PROGRESS, VERR_INTERNAL_ERROR_2);
     748    AssertReturn(pDevCfg->pIAudioClient == NULL, VERR_INTERNAL_ERROR_2);
     749    AssertReturn(pDevCfg->pIAudioCaptureClient == NULL, VERR_INTERNAL_ERROR_2);
     750    AssertReturn(pDevCfg->pIAudioRenderClient == NULL, VERR_INTERNAL_ERROR_2);
     751    AssertReturn(PDMAudioPropsAreValid(&pDevCfg->Props), VERR_INTERNAL_ERROR_2);
     752
     753    PDRVHOSTAUDIOWASCACHEDEV pDevEntry = pDevCfg->pDevEntry;
     754    AssertPtrReturn(pDevEntry, VERR_INTERNAL_ERROR_2);
     755    AssertPtrReturn(pDevEntry->pIDevice, VERR_INTERNAL_ERROR_2);
     756    AssertReturn(pDevEntry->enmDir == PDMAUDIODIR_IN || pDevEntry->enmDir == PDMAUDIODIR_OUT, VERR_INTERNAL_ERROR_2);
     757
     758    /*
     759     * First we need an IAudioClient interface for calling IsFormatSupported
    830760     * on so we can get guidance as to what to do next.
    831761     *
     
    835765     * https://social.msdn.microsoft.com/Forums/en-US/1d974d90-6636-4121-bba3-a8861d9ab92a
    836766     * it is supported, just maybe missing from the SDK or something...
    837      */
    838     RTCritSectLeave(&pThis->CritSectCache);
    839 
    840     REFERENCE_TIME const cBufferSizeInNtTicks = PDMAudioPropsFramesToNtTicks(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize);
    841 
     767     *
     768     * I'll leave the IsFormatSupported call here as it gives us a clue as to
     769     * what exactly the WAS needs to convert our audio stream into/from.
     770     */
    842771    Log8Func(("Activating an IAudioClient for '%ls' ...\n", pDevEntry->wszDevId));
    843772    IAudioClient *pIAudioClient = NULL;
     
    848777    {
    849778        LogRelMax(64, ("WasAPI: Activate(%ls, IAudioClient) failed: %Rhrc\n", pDevEntry->wszDevId, hrc));
    850         return NULL;
     779        pDevCfg->nsInited = RTTimeNanoTS();
     780        return pDevCfg->rcSetup = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
    851781    }
    852782
    853783    WAVEFORMATEX  WaveFmtEx;
    854     drvHostAudioWasWaveFmtExFromCfg(pCfgReq, &WaveFmtEx);
     784    drvHostAudioWasWaveFmtExFromProps(&pDevCfg->Props, &WaveFmtEx);
    855785
    856786    PWAVEFORMATEX pClosestMatch = NULL;
     
    858788
    859789    /*
    860      * If the format is supported, create a cache entry for it.
     790     * If the format is supported, go ahead and initialize the client instance.
    861791     */
    862792    if (SUCCEEDED(hrc))
    863793    {
    864794        if (hrc == S_OK)
    865             Log8Func(("IsFormatSupport(,%s,) -> S_OK + %p: requested format is supported\n", szProps, pClosestMatch));
     795            Log8Func(("IsFormatSupport(,%s,) -> S_OK + %p: requested format is supported\n", pDevCfg->szProps, pClosestMatch));
    866796        else
    867             Log8Func(("IsFormatSupport(,%s,) -> %Rhrc + %p: %uch S%u %uHz\n", szProps, hrc, pClosestMatch,
     797            Log8Func(("IsFormatSupport(,%s,) -> %Rhrc + %p: %uch S%u %uHz\n", pDevCfg->szProps, hrc, pClosestMatch,
    868798                      pClosestMatch ? pClosestMatch->nChannels : 0, pClosestMatch ? pClosestMatch->wBitsPerSample : 0,
    869799                      pClosestMatch ? pClosestMatch->nSamplesPerSec : 0));
    870800
    871         uint32_t fInitFlags = AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
    872                             | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
     801        REFERENCE_TIME const cBufferSizeInNtTicks = PDMAudioPropsFramesToNtTicks(&pDevCfg->Props, pDevCfg->cFramesBufferSize);
     802        uint32_t             fInitFlags           = AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
     803                                                  | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
    873804        hrc = pIAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, fInitFlags, cBufferSizeInNtTicks,
    874805                                        0 /*cPeriodicityInNtTicks*/, &WaveFmtEx, NULL /*pAudioSessionGuid*/);
    875         Log8Func(("Initialize(,%x, %RI64, %s,) -> %Rhrc\n", fInitFlags, cBufferSizeInNtTicks, szProps, hrc));
     806        Log8Func(("Initialize(,%x, %RI64, %s,) -> %Rhrc\n", fInitFlags, cBufferSizeInNtTicks, pDevCfg->szProps, hrc));
    876807        if (SUCCEEDED(hrc))
    877808        {
    878             if (pClosestMatch)
    879                 CoTaskMemFree(pClosestMatch);
    880             Log8Func(("Creating new config for '%s' on '%ls': %p\n", szProps, pDevEntry->wszDevId, pDevCfg));
    881             return drvHostAudioWasCacheCreateConfig(pDevEntry, pCfgReq, &WaveFmtEx, pIAudioClient);
    882         }
    883 
    884         LogRelMax(64, ("WasAPI: IAudioClient::Initialize(%s: %s) failed: %Rhrc\n", pCfgReq->szName, szProps, hrc));
    885 
    886 #if 0 /* later if needed */
    887         /*
    888          * Try lookup or instantiate the closest config.
    889          */
    890         PDMAUDIOSTREAMCFG ClosestCfg = *pCfgReq;
    891         int rc = drvHostAudioWasCacheWaveFmtExToProps(&ClosestCfg.Props, pClosestMatch, pDevEntry->wszDevId);
    892         if (RT_SUCCESS(rc))
    893         {
    894             RTCritSectEnter(&pThis->CritSectCache);
    895             pDevCfg = drvHostAudioWasCacheLookupLocked(pDevEntry, &pCfgReq->Props);
    896             if (pDevCfg)
     809            /*
     810             * The direction specific client interface.
     811             */
     812            if (pDevEntry->enmDir == PDMAUDIODIR_IN)
     813                hrc = pIAudioClient->GetService(__uuidof(IAudioCaptureClient), (void **)&pDevCfg->pIAudioCaptureClient);
     814            else
     815                hrc = pIAudioClient->GetService(__uuidof(IAudioRenderClient), (void **)&pDevCfg->pIAudioRenderClient);
     816            Log8Func(("GetService -> %Rhrc + %p\n", hrc, pDevEntry->enmDir == PDMAUDIODIR_IN
     817                      ? (void *)pDevCfg->pIAudioCaptureClient : (void *)pDevCfg->pIAudioRenderClient));
     818            if (SUCCEEDED(hrc))
    897819            {
    898                 CoTaskMemFree(pClosestMatch);
    899                 Log8Func(("Config cache hit '%s' (for '%s') on '%ls': %p\n", pDevCfg->szProps, szProps, pDevEntry->wszDevId, pDevCfg));
    900                 return pDevCfg;
     820                /*
     821                 * Obtain the actual stream format and buffer config.
     822                 */
     823                UINT32          cFramesBufferSize       = 0;
     824                REFERENCE_TIME  cDefaultPeriodInNtTicks = 0;
     825                REFERENCE_TIME  cMinimumPeriodInNtTicks = 0;
     826                REFERENCE_TIME  cLatencyinNtTicks       = 0;
     827                hrc = pIAudioClient->GetBufferSize(&cFramesBufferSize);
     828                if (SUCCEEDED(hrc))
     829                {
     830                    hrc = pIAudioClient->GetDevicePeriod(&cDefaultPeriodInNtTicks, &cMinimumPeriodInNtTicks);
     831                    if (SUCCEEDED(hrc))
     832                    {
     833                        hrc = pIAudioClient->GetStreamLatency(&cLatencyinNtTicks);
     834                        if (SUCCEEDED(hrc))
     835                        {
     836                            LogRel2(("WasAPI: Aquired buffer parameters for %s:\n"
     837                                     "WasAPI:   cFramesBufferSize       = %RU32\n"
     838                                     "WasAPI:   cDefaultPeriodInNtTicks = %RI64\n"
     839                                     "WasAPI:   cMinimumPeriodInNtTicks = %RI64\n"
     840                                     "WasAPI:   cLatencyinNtTicks       = %RI64\n",
     841                                     pDevCfg->szProps, cFramesBufferSize, cDefaultPeriodInNtTicks,
     842                                     cMinimumPeriodInNtTicks, cLatencyinNtTicks));
     843
     844                            pDevCfg->pIAudioClient      = pIAudioClient;
     845                            pDevCfg->cFramesBufferSize  = cFramesBufferSize;
     846                            pDevCfg->cFramesPeriod      = PDMAudioPropsNanoToFrames(&pDevCfg->Props,
     847                                                                                    cDefaultPeriodInNtTicks * 100);
     848                            pDevCfg->nsInited           = RTTimeNanoTS();
     849                            pDevCfg->rcSetup            = VINF_SUCCESS;
     850
     851                            if (pClosestMatch)
     852                                CoTaskMemFree(pClosestMatch);
     853                            Log8Func(("returns VINF_SUCCESS (%p (%s) inited in %'RU64 ns)\n",
     854                                      pDevCfg, pDevCfg->szProps, pDevCfg->nsInited - pDevCfg->nsCreated));
     855                            return VINF_SUCCESS;
     856                        }
     857                        LogRelMax(64, ("WasAPI: GetStreamLatency failed: %Rhrc\n", hrc));
     858                    }
     859                    else
     860                        LogRelMax(64, ("WasAPI: GetDevicePeriod failed: %Rhrc\n", hrc));
     861                }
     862                else
     863                    LogRelMax(64, ("WasAPI: GetBufferSize failed: %Rhrc\n", hrc));
     864
     865                if (pDevCfg->pIAudioCaptureClient)
     866                {
     867                    pDevCfg->pIAudioCaptureClient->Release();
     868                    pDevCfg->pIAudioCaptureClient = NULL;
     869                }
     870
     871                if (pDevCfg->pIAudioRenderClient)
     872                {
     873                    pDevCfg->pIAudioRenderClient->Release();
     874                    pDevCfg->pIAudioRenderClient = NULL;
     875                }
    901876            }
    902             RTCritSectLeave(&pThis->CritSectCache);
    903         }
    904 #endif
     877            else
     878                LogRelMax(64, ("WasAPI: IAudioClient::GetService(%s) failed: %Rhrc\n", pDevCfg->szProps, hrc));
     879        }
     880        else
     881            LogRelMax(64, ("WasAPI: IAudioClient::Initialize(%s) failed: %Rhrc\n", pDevCfg->szProps, hrc));
    905882    }
    906883    else
    907         LogRelMax(64,("WasAPI: IAudioClient::IsFormatSupport(,%s: %s,) failed: %Rhrc\n", pCfgReq->szName, szProps, hrc));
     884        LogRelMax(64,("WasAPI: IAudioClient::IsFormatSupport(,%s,) failed: %Rhrc\n", pDevCfg->szProps, hrc));
    908885
    909886    pIAudioClient->Release();
    910887    if (pClosestMatch)
    911888        CoTaskMemFree(pClosestMatch);
    912     Log8Func(("returns NULL\n"));
    913     return NULL;
     889    pDevCfg->nsInited = RTTimeNanoTS();
     890    Log8Func(("returns VERR_AUDIO_STREAM_COULD_NOT_CREATE (inited in %'RU64 ns)\n", pDevCfg->nsInited - pDevCfg->nsCreated));
     891    return pDevCfg->rcSetup = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
     892}
     893
     894
     895/**
     896 * Worker for drvHostAudioWasCacheLookupOrCreate.
     897 *
     898 * If lookup fails, a new entry will be created.
     899 *
     900 * @note    Called holding the lock, returning without holding it!
     901 */
     902static int drvHostAudioWasCacheLookupOrCreateConfig(PDRVHOSTAUDIOWAS pThis, PDRVHOSTAUDIOWASCACHEDEV pDevEntry,
     903                                                    PCPDMAUDIOSTREAMCFG pCfgReq, bool fOnWorker,
     904                                                    PDRVHOSTAUDIOWASCACHEDEVCFG *ppDevCfg)
     905{
     906    /*
     907     * Check if we've got a matching config.
     908     */
     909    PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = drvHostAudioWasCacheLookupLocked(pDevEntry, &pCfgReq->Props);
     910    if (pDevCfg)
     911    {
     912        *ppDevCfg = pDevCfg;
     913        RTCritSectLeave(&pThis->CritSectCache);
     914        Log8Func(("Config cache hit '%s' on '%ls': %p\n", pDevCfg->szProps, pDevEntry->wszDevId, pDevCfg));
     915        return VINF_SUCCESS;
     916    }
     917
     918    RTCritSectLeave(&pThis->CritSectCache);
     919
     920    /*
     921     * Allocate an device config entry and hand the creation task over to the
     922     * worker thread, unless we're already on it.
     923     */
     924    pDevCfg = (PDRVHOSTAUDIOWASCACHEDEVCFG)RTMemAllocZ(sizeof(*pDevCfg));
     925    AssertReturn(pDevCfg, VERR_NO_MEMORY);
     926    RTListInit(&pDevCfg->ListEntry);
     927    pDevCfg->pDevEntry         = pDevEntry;
     928    pDevCfg->rcSetup           = VERR_AUDIO_STREAM_INIT_IN_PROGRESS;
     929    pDevCfg->Props             = pCfgReq->Props;
     930    pDevCfg->cFramesBufferSize = pCfgReq->Backend.cFramesBufferSize;
     931    PDMAudioPropsToString(&pDevCfg->Props, pDevCfg->szProps, sizeof(pDevCfg->szProps));
     932    pDevCfg->nsCreated         = RTTimeNanoTS();
     933
     934    if (!fOnWorker)
     935    {
     936        *ppDevCfg = pDevCfg;
     937        LogFlowFunc(("Doing the rest of the work on %p via pfnStreamInitAsync...\n", pDevCfg));
     938        return VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED;
     939    }
     940
     941    /*
     942     * Initialize the entry on the calling thread.
     943     */
     944    int rc = drvHostAudioWasCacheInitConfig(pDevCfg);
     945    AssertRC(pDevCfg->rcSetup == rc);
     946    if (RT_SUCCESS(rc))
     947        rc = pDevCfg->rcSetup; /* paranoia */
     948    if (RT_SUCCESS(rc))
     949    {
     950        *ppDevCfg = pDevCfg;
     951        LogFlowFunc(("Returning %p\n", pDevCfg));
     952        return VINF_SUCCESS;
     953    }
     954    RTMemFree(pDevCfg);
     955    *ppDevCfg = NULL;
     956    return rc;
    914957}
    915958
     
    919962 * if missing.
    920963 *
    921  * @returns Pointer to the requested device config (or closest alternative).
    922  *          NULL on failure (TODO: need to return why).
     964 * @returns VBox status code.
    923965 * @param   pThis       The WASAPI host audio driver instance data.
    924966 * @param   pIDevice    The device to look up.
    925967 * @param   pCfgReq     The configuration to look up.
    926  */
    927 static PDRVHOSTAUDIOWASCACHEDEVCFG
    928 drvHostAudioWasCacheLookupOrCreate(PDRVHOSTAUDIOWAS pThis, IMMDevice *pIDevice, PCPDMAUDIOSTREAMCFG pCfgReq)
    929 {
     968 * @param   fOnWorker   Set if we're on a worker thread, otherwise false.
     969 * @param   ppDevCfg    Where to return the requested device config.
     970 */
     971static int drvHostAudioWasCacheLookupOrCreate(PDRVHOSTAUDIOWAS pThis, IMMDevice *pIDevice, PCPDMAUDIOSTREAMCFG pCfgReq,
     972                                              bool fOnWorker, PDRVHOSTAUDIOWASCACHEDEVCFG *ppDevCfg)
     973{
     974    *ppDevCfg = NULL;
     975
    930976    /*
    931977     * Get the device ID so we can perform the lookup.
    932978     */
     979    int     rc        = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
    933980    LPWSTR  pwszDevId = NULL;
    934981    HRESULT hrc = pIDevice->GetId(&pwszDevId);
     
    950997                CoTaskMemFree(pwszDevId);
    951998                Log8Func(("Cache hit for device '%ls': %p\n", pDevEntry->wszDevId, pDevEntry));
    952                 return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry, pCfgReq);
     999                return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry, pCfgReq, fOnWorker, ppDevCfg);
    9531000            }
    9541001        }
     
    9921039
    9931040                    Log8Func(("Lost race adding device '%ls': %p\n", pDevEntry2->wszDevId, pDevEntry2));
    994                     return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry2, pCfgReq);
     1041                    return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry2, pCfgReq, fOnWorker, ppDevCfg);
    9951042                }
    9961043            }
     
    9981045
    9991046            Log8Func(("Added device '%ls' to cache: %p\n", pDevEntry->wszDevId, pDevEntry));
    1000             return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry, pCfgReq);
     1047            return drvHostAudioWasCacheLookupOrCreateConfig(pThis, pDevEntry, pCfgReq, fOnWorker, ppDevCfg);
    10011048        }
    10021049        CoTaskMemFree(pwszDevId);
     
    10041051    else
    10051052        LogRelMax(64, ("WasAPI: GetId failed (lookup): %Rhrc\n", hrc));
    1006     return NULL;
     1053    return rc;
    10071054}
    10081055
     
    10191066     * Reset the audio client to see that it works and to make sure it's in a sensible state.
    10201067     */
    1021     HRESULT hrc = pDevCfg->pIAudioClient->Reset();
     1068    HRESULT hrc = pDevCfg->pIAudioClient ? pDevCfg->pIAudioClient->Reset()
     1069                : pDevCfg->rcSetup == VERR_AUDIO_STREAM_INIT_IN_PROGRESS ? S_OK : E_FAIL;
    10221070    if (SUCCEEDED(hrc))
    10231071    {
     
    10351083
    10361084
    1037 static void drvHostWasCacheConfigHinting(PDRVHOSTAUDIOWAS pThis, PPDMAUDIOSTREAMCFG pCfgReq)
     1085static void drvHostWasCacheConfigHinting(PDRVHOSTAUDIOWAS pThis, PPDMAUDIOSTREAMCFG pCfgReq, bool fOnWorker)
    10381086{
    10391087    /*
     
    10501098         * Look up the config and put it back.
    10511099         */
    1052         PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = drvHostAudioWasCacheLookupOrCreate(pThis, pIDevice, pCfgReq);
    1053         LogFlowFunc(("pDevCfg=%p\n"));
    1054         if (pDevCfg)
     1100        PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = NULL;
     1101        int rc = drvHostAudioWasCacheLookupOrCreate(pThis, pIDevice, pCfgReq, fOnWorker, &pDevCfg);
     1102        LogFlowFunc(("pDevCfg=%p rc=%Rrc\n", pDevCfg, rc));
     1103        if (pDevCfg && RT_SUCCESS(rc))
    10551104            drvHostAudioWasCachePutBack(pThis, pDevCfg);
    10561105        pIDevice->Release();
     
    11141163*   Worker thread                                                                                                                *
    11151164*********************************************************************************************************************************/
     1165#if 0
    11161166
    11171167/**
     
    11481198            switch (Msg.message)
    11491199            {
    1150                 case WM_DRVHOSTAUDIOWAS_HINT:
    1151                 {
    1152                     AssertMsgBreak(Msg.wParam == pThis->uWorkerThreadFixedParam, ("%p\n", Msg.wParam));
    1153                     AssertBreak(Msg.hwnd == NULL);
    1154                     PPDMAUDIOSTREAMCFG pCfgReq = (PPDMAUDIOSTREAMCFG)Msg.lParam;
    1155                     AssertPtrBreak(pCfgReq);
    1156 
    1157                     drvHostWasCacheConfigHinting(pThis, pCfgReq);
    1158                     RTMemFree(pCfgReq);
    1159                     break;
    1160                 }
    1161 
    11621200                case WM_DRVHOSTAUDIOWAS_PURGE_CACHE:
    11631201                {
     
    11851223    return VINF_SUCCESS;
    11861224}
    1187 
     1225#endif
    11881226
    11891227/*********************************************************************************************************************************
     
    12061244    RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "WasAPI");
    12071245    pBackendCfg->cbStream       = sizeof(DRVHOSTAUDIOWASSTREAM);
    1208     pBackendCfg->fFlags         = 0;
     1246    pBackendCfg->fFlags         = PDMAUDIOBACKEND_F_ASYNC_HINT;
    12091247    pBackendCfg->cMaxStreamsIn  = UINT32_MAX;
    12101248    pBackendCfg->cMaxStreamsOut = UINT32_MAX;
     
    14011439
    14021440/**
     1441 * @interface_method_impl{PDMIHOSTAUDIO,pfnDoOnWorkerThread}
     1442 */
     1443static DECLCALLBACK(void) drvHostAudioWasHA_DoOnWorkerThread(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
     1444                                                             uintptr_t uUser, void *pvUser)
     1445{
     1446    PDRVHOSTAUDIOWAS pThis = RT_FROM_MEMBER(pInterface, DRVHOSTAUDIOWAS, IHostAudio);
     1447    RT_NOREF(pStream, pvUser);
     1448    LogFlowFunc(("uUser=%#zx pStream=%p pvUser=%p\n", uUser, pStream, pvUser));
     1449
     1450    switch (uUser)
     1451    {
     1452        case DRVHOSTAUDIOWAS_DO_PURGE_CACHE:
     1453            Assert(pStream == NULL);
     1454            Assert(pvUser == NULL);
     1455            drvHostAudioWasCachePurge(pThis);
     1456            break;
     1457
     1458        default:
     1459            AssertMsgFailedBreak(("%#zx\n", uUser));
     1460    }
     1461}
     1462
     1463
     1464/**
    14031465 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamConfigHint}
     1466 *
     1467 * @note This is called on a DrvAudio worker thread.
    14041468 */
    14051469static DECLCALLBACK(void) drvHostAudioWasHA_StreamConfigHint(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAMCFG pCfg)
    14061470{
     1471#if 0 /* disable to test async stream creation. */
    14071472    PDRVHOSTAUDIOWAS pThis = RT_FROM_MEMBER(pInterface, DRVHOSTAUDIOWAS, IHostAudio);
    14081473    LogFlowFunc(("pCfg=%p\n", pCfg));
    14091474
    1410     if (pThis->hWorkerThread != NIL_RTTHREAD)
    1411     {
    1412         PPDMAUDIOSTREAMCFG pCfgCopy = PDMAudioStrmCfgDup(pCfg);
    1413         if (pCfgCopy)
    1414         {
    1415             if (PostThreadMessageW(pThis->idWorkerThread, WM_DRVHOSTAUDIOWAS_HINT,
    1416                                    pThis->uWorkerThreadFixedParam, (LPARAM)pCfgCopy))
    1417                 LogFlowFunc(("Posted %p to worker thread\n", pCfgCopy));
    1418             else
    1419             {
    1420                 LogRelMax(64, ("WasAPI: PostThreadMessageW failed: %u\n", GetLastError()));
    1421                 PDMAudioStrmCfgFree(pCfgCopy);
    1422             }
    1423         }
    1424     }
    1425     else
    1426         drvHostWasCacheConfigHinting(pThis, pCfg);
     1475    drvHostWasCacheConfigHinting(pThis, pCfg);
     1476#else
     1477    RT_NOREF(pInterface, pCfg);
     1478#endif
    14271479}
    14281480
     
    14581510     */
    14591511    WAVEFORMATEX WaveFmtX;
    1460     drvHostAudioWasWaveFmtExFromCfg(pCfgReq, &WaveFmtX);
     1512    drvHostAudioWasWaveFmtExFromProps(&pCfgReq->Props, &WaveFmtX);
    14611513    LogRel2(("WasAPI: Requested %s format for '%s':\n"
    14621514             "WasAPI:   wFormatTag      = %RU16\n"
     
    15061558    /** @todo make it return a status code too and retry if the default device
    15071559     *        was invalidated/changed while we where working on it here. */
    1508     int rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
    1509     PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = drvHostAudioWasCacheLookupOrCreate(pThis, pIDevice, pCfgReq);
     1560    PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = NULL;
     1561    int rc = drvHostAudioWasCacheLookupOrCreate(pThis, pIDevice, pCfgReq, false /*fOnWorker*/, &pDevCfg);
    15101562
    15111563    pIDevice->Release();
    15121564    pIDevice = NULL;
    15131565
    1514     if (pDevCfg)
     1566    if (pDevCfg && RT_SUCCESS(rc))
    15151567    {
    15161568        pStreamWas->pDevCfg = pDevCfg;
    15171569
    1518         pCfgAcq->Props = pDevCfg->Props;
     1570        pCfgAcq->Props                       = pDevCfg->Props;
    15191571        pCfgAcq->Backend.cFramesBufferSize   = pDevCfg->cFramesBufferSize;
    15201572        pCfgAcq->Backend.cFramesPeriod       = pDevCfg->cFramesPeriod;
     
    15321584            RTCritSectRwLeaveExcl(&pThis->CritSectStreamList);
    15331585
    1534             LogFlowFunc(("returns VINF_SUCCESS\n", rc));
    1535             return VINF_SUCCESS;
     1586            if (pStreamWas->pDevCfg->pIAudioClient != NULL)
     1587            {
     1588                LogFlowFunc(("returns VINF_SUCCESS\n", rc));
     1589                return VINF_SUCCESS;
     1590            }
     1591            LogFlowFunc(("returns VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED\n", rc));
     1592            return VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED;
    15361593        }
    15371594
     
    15411598    }
    15421599    else
    1543         LogRelMax(64, ("WasAPI: Failed to setup %s on audio device '%ls'.\n", pszStreamType, pwszDevIdDesc));
     1600        LogRelMax(64, ("WasAPI: Failed to setup %s on audio device '%ls' (%Rrc).\n", pszStreamType, pwszDevIdDesc, rc));
    15441601
    15451602    LogFlowFunc(("returns %Rrc\n", rc));
     1603    return rc;
     1604}
     1605
     1606
     1607/**
     1608 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamInitAsync}
     1609 */
     1610static DECLCALLBACK(int) drvHostAudioWasHA_StreamInitAsync(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
     1611                                                           bool fDestroyed)
     1612{
     1613    RT_NOREF(pInterface);
     1614    PDRVHOSTAUDIOWASSTREAM pStreamWas = (PDRVHOSTAUDIOWASSTREAM)pStream;
     1615    AssertPtrReturn(pStreamWas, VERR_INVALID_POINTER);
     1616    LogFlowFunc(("Stream '%s'%s\n", pStreamWas->Cfg.szName, fDestroyed ? " - destroyed!" : ""));
     1617
     1618    /*
     1619     * Assert sane preconditions for this call.
     1620     */
     1621    AssertPtrReturn(pStreamWas->Core.pStream, VERR_INTERNAL_ERROR);
     1622    AssertPtrReturn(pStreamWas->pDevCfg, VERR_INTERNAL_ERROR_2);
     1623    AssertPtrReturn(pStreamWas->pDevCfg->pDevEntry, VERR_INTERNAL_ERROR_3);
     1624    AssertPtrReturn(pStreamWas->pDevCfg->pDevEntry->pIDevice, VERR_INTERNAL_ERROR_4);
     1625    AssertReturn(pStreamWas->pDevCfg->pDevEntry->enmDir == pStreamWas->Core.pStream->enmDir, VERR_INTERNAL_ERROR_4);
     1626    AssertReturn(pStreamWas->pDevCfg->pIAudioClient == NULL, VERR_INTERNAL_ERROR_5);
     1627    AssertReturn(pStreamWas->pDevCfg->pIAudioRenderClient == NULL, VERR_INTERNAL_ERROR_5);
     1628    AssertReturn(pStreamWas->pDevCfg->pIAudioCaptureClient == NULL, VERR_INTERNAL_ERROR_5);
     1629
     1630    /*
     1631     * Do the job.
     1632     */
     1633    int rc;
     1634    if (!fDestroyed)
     1635        rc = drvHostAudioWasCacheInitConfig(pStreamWas->pDevCfg);
     1636    else
     1637    {
     1638        AssertReturn(pStreamWas->pDevCfg->rcSetup == VERR_AUDIO_STREAM_INIT_IN_PROGRESS, VERR_INTERNAL_ERROR_2);
     1639        pStreamWas->pDevCfg->rcSetup = VERR_WRONG_ORDER;
     1640        rc = VINF_SUCCESS;
     1641    }
     1642
     1643    LogFlowFunc(("returns %Rrc (%s)\n", rc, pStreamWas->Cfg.szName));
    15461644    return rc;
    15471645}
     
    20862184    AssertPtrReturn(pStreamWas, PDMAUDIOSTREAM_STS_NONE);
    20872185
    2088     uint32_t fStrmStatus = PDMAUDIOSTREAM_STS_INITIALIZED;
     2186    uint32_t fStrmStatus = 0;
     2187    AssertPtr(pStreamWas->pDevCfg);
     2188    if (pStreamWas->pDevCfg /*paranoia*/)
     2189    {
     2190        if (RT_SUCCESS(pStreamWas->pDevCfg->rcSetup))
     2191            fStrmStatus |= PDMAUDIOSTREAM_STS_INITIALIZED;
     2192        else if (pStreamWas->pDevCfg->rcSetup != VERR_AUDIO_STREAM_INIT_IN_PROGRESS)
     2193        {
     2194            /** @todo trigger device reset? Probably won't help, so what to do?  */
     2195        }
     2196    }
    20892197    if (pStreamWas->fEnabled)
    20902198        fStrmStatus |= PDMAUDIOSTREAM_STS_ENABLED;
     
    24182526    PDRVHOSTAUDIOWAS pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTAUDIOWAS);
    24192527
     2528    /*
     2529     * Start purging the cache asynchronously before we get to destruct.
     2530     * This might speed up VM shutdown a tiny fraction and also stress
     2531     * the shutting down of the thread pool a little.
     2532     */
     2533#if 0
    24202534    if (pThis->hWorkerThread != NIL_RTTHREAD)
    24212535    {
     
    24242538        Assert(fRc); RT_NOREF(fRc);
    24252539    }
     2540#else
     2541    if (!RTListIsEmpty(&pThis->CacheHead) && pThis->pIHostAudioPort)
     2542    {
     2543        int rc = pThis->pIHostAudioPort->pfnDoOnWorkerThread(pThis->pIHostAudioPort, NULL/*pStream*/,
     2544                                                             DRVHOSTAUDIOWAS_DO_PURGE_CACHE, NULL /*pvUser*/);
     2545        AssertRC(rc);
     2546    }
     2547#endif
    24262548}
    24272549
     
    24432565    }
    24442566
     2567#if 0
    24452568    if (pThis->hWorkerThread != NIL_RTTHREAD)
    24462569    {
     
    24512574        AssertRC(rc);
    24522575    }
     2576#endif
    24532577
    24542578    if (RTCritSectIsInitialized(&pThis->CritSectCache))
     
    24982622    pThis->pDrvIns                          = pDrvIns;
    24992623    pThis->hDrainTimer                      = NIL_TMTIMERHANDLE;
     2624#if 0
    25002625    pThis->hWorkerThread                    = NIL_RTTHREAD;
    25012626    pThis->idWorkerThread                   = 0;
     2627#endif
    25022628    RTListInit(&pThis->StreamHead);
    25032629    RTListInit(&pThis->CacheHead);
     
    25082634    pThis->IHostAudio.pfnGetDevices                 = drvHostAudioWasHA_GetDevices;
    25092635    pThis->IHostAudio.pfnGetStatus                  = drvHostAudioWasHA_GetStatus;
     2636    pThis->IHostAudio.pfnDoOnWorkerThread           = drvHostAudioWasHA_DoOnWorkerThread;
    25102637    pThis->IHostAudio.pfnStreamConfigHint           = drvHostAudioWasHA_StreamConfigHint;
    25112638    pThis->IHostAudio.pfnStreamCreate               = drvHostAudioWasHA_StreamCreate;
     2639    pThis->IHostAudio.pfnStreamInitAsync            = drvHostAudioWasHA_StreamInitAsync;
    25122640    pThis->IHostAudio.pfnStreamDestroy              = drvHostAudioWasHA_StreamDestroy;
    25132641    pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = NULL;
     
    25602688     * Resolve the notification interface.
    25612689     */
    2562     pThis->pIAudioNotifyFromHost = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIONOTIFYFROMHOST);
     2690    pThis->pIHostAudioPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIHOSTAUDIOPORT);
    25632691# ifdef VBOX_WITH_AUDIO_CALLBACKS
    2564     AssertPtr(pThis->pIAudioNotifyFromHost);
     2692    AssertPtr(pThis->pIHostAudioPort);
    25652693# endif
    25662694
     
    26452773    AssertRCReturn(rc, rc);
    26462774
     2775#if 0
    26472776    /*
    26482777     * Create the worker thread.  This thread has a message loop and will be
     
    26572786    rc = RTThreadUserWait(pThis->hWorkerThread, RT_MS_10SEC);
    26582787    AssertRC(rc);
     2788#endif
    26592789
    26602790    /*
  • trunk/src/VBox/Main/src-client/DrvAudioRec.cpp

    r88761 r88819  
    11021102    pThis->IHostAudio.pfnGetDevices                 = NULL;
    11031103    pThis->IHostAudio.pfnGetStatus                  = drvAudioVideoRecHA_GetStatus;
     1104    pThis->IHostAudio.pfnDoOnWorkerThread           = NULL;
     1105    pThis->IHostAudio.pfnStreamConfigHint           = NULL;
    11041106    pThis->IHostAudio.pfnStreamCreate               = drvAudioVideoRecHA_StreamCreate;
     1107    pThis->IHostAudio.pfnStreamInitAsync            = NULL;
    11051108    pThis->IHostAudio.pfnStreamDestroy              = drvAudioVideoRecHA_StreamDestroy;
    11061109    pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = NULL;
  • trunk/src/VBox/Main/src-client/DrvAudioVRDE.cpp

    r88761 r88819  
    725725    pThis->IHostAudio.pfnGetDevices                 = NULL;
    726726    pThis->IHostAudio.pfnGetStatus                  = drvAudioVrdeHA_GetStatus;
     727    pThis->IHostAudio.pfnDoOnWorkerThread           = NULL;
     728    pThis->IHostAudio.pfnStreamConfigHint           = NULL;
    727729    pThis->IHostAudio.pfnStreamCreate               = drvAudioVrdeHA_StreamCreate;
     730    pThis->IHostAudio.pfnStreamInitAsync            = NULL;
    728731    pThis->IHostAudio.pfnStreamDestroy              = drvAudioVrdeHA_StreamDestroy;
    729732    pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = NULL;
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