VirtualBox

Changeset 88861 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
May 4, 2021 4:00:36 PM (4 years ago)
Author:
vboxsync
Message:

DrvAudio,DrvHostAudioWasApi: Implemented the smoother default device changing. Added a PDMIHOSTAUDIOPORT::pfnStreamNotifyPreparingDeviceSwitch to explicitly tell DrvAudio about PDMAUDIOSTREAM_STS_PREPARING_SWITCH being set, rather than polling for it in the play function. Fixed a cache purge at power-off race in the destructor (WasApi). bugref:9890

Location:
trunk/src/VBox/Devices/Audio
Files:
2 edited

Legend:

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

    r88853 r88861  
    24992499 * Copy data to the pre-buffer, ring-buffer style.
    25002500 *
    2501  * This is used in two slightly different situations:
    2502  *
    2503  *      -# When the stream is started (enabled) and we only want to prebuffer up
    2504  *         to the threshold before pushing the data to the backend.  We
    2505  *         typically use the max buffer size for this situation.
    2506  *
    2507  *      -# When the backend sets the PDMAUDIOSTREAM_STS_PREPARING_SWITCH
    2508  *         status bit and we're preparing for a smooth switch over to a
    2509  *         different audio device.  Most of the pre-buffered data should not be
    2510  *         played on the old device prior to the switch, due to the prebuffering
    2511  *         at the start of the stream.  We only use the threshold size for this
    2512  *         case.
     2501 * The @a cbMax parameter is almost always set to the threshold size, the
     2502 * exception is when commiting the buffer and we want to top it off to reduce
     2503 * the number of transfers to the backend (the first transfer may start
     2504 * playback, so more data is better).
    25132505 */
    25142506static int drvAudioStreamPreBuffer(PDRVAUDIOSTREAM pStreamEx, const uint8_t *pbBuf, uint32_t cbBuf, uint32_t cbMax)
     
    32183210        }
    32193211    }
    3220 
    3221     /*
    3222      * Deal with PDMAUDIOSTREAM_STS_PREPARING_SWITCH being set.
    3223      *
    3224      * Note! We don't care if it's cleared as the backend will call
    3225      *       PDMIHOSTAUDIOPORT::pfnStreamNotifyDeviceChanged when that takes place.
    3226      */
    3227     if (   !(fOldState & PDMAUDIOSTREAM_STS_PREPARING_SWITCH)
    3228         && (fNewState  & PDMAUDIOSTREAM_STS_PREPARING_SWITCH))
    3229     {
    3230         if (pStreamEx->Out.cbPreBufThreshold > 0)
    3231         {
    3232             switch (enmPlayState)
    3233             {
    3234                 case DRVAUDIOPLAYSTATE_PREBUF:
    3235                 case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE:
    3236                 case DRVAUDIOPLAYSTATE_NOPLAY:
    3237                 case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: /* simpler */
    3238                     pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_SWITCHING;
    3239                     break;
    3240                 case DRVAUDIOPLAYSTATE_PLAY:
    3241                     pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PLAY_PREBUF;
    3242                     break;
    3243                 case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING:
    3244                 case DRVAUDIOPLAYSTATE_PLAY_PREBUF:
    3245                     break;
    3246                 /* no default */
    3247                 case DRVAUDIOPLAYSTATE_END:
    3248                 case DRVAUDIOPLAYSTATE_INVALID:
    3249                     break;
    3250             }
    3251             LogFunc(("PDMAUDIOSTREAM_STS_INITIALIZED was set: %s -> %s\n",
    3252                      drvAudioPlayStateName(enmPlayState), drvAudioPlayStateName(pStreamEx->Out.enmPlayState) ));
    3253         }
    3254         else
    3255             LogFunc(("PDMAUDIOSTREAM_STS_PREPARING_SWITCH was set, but no pre-buffering configured.\n"));
    3256     }
    32573212}
    32583213
     
    33243279                      == (pStreamEx->fStatus & (PDMAUDIOSTREAM_STS_ENABLED | PDMAUDIOSTREAM_STS_PAUSED))
    33253280                   || !(pStreamEx->fStatus & PDMAUDIOSTREAM_STS_BACKEND_READY)
    3326                    || !(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED) );
    3327 
    3328             if (!(  (pStreamEx->fLastBackendStatus ^ fBackendStatus)
    3329                   & (PDMAUDIOSTREAM_STS_INITIALIZED | PDMAUDIOSTREAM_STS_PREPARING_SWITCH)))
     3281                   || !(fBackendStatus & PDMAUDIOSTREAM_STS_INITIALIZED));
     3282
     3283            if (!((pStreamEx->fLastBackendStatus ^ fBackendStatus) & PDMAUDIOSTREAM_STS_INITIALIZED))
    33303284            { /* no relevant change - likely */ }
    33313285            else
     
    39273881
    39283882/**
     3883 * @interface_method_impl{PDMIHOSTAUDIOPORT,pfnStreamNotifyPreparingDeviceSwitch}
     3884 */
     3885static DECLCALLBACK(void) drvAudioHostPort_StreamNotifyPreparingDeviceSwitch(PPDMIHOSTAUDIOPORT pInterface,
     3886                                                                             PPDMAUDIOBACKENDSTREAM pStream)
     3887{
     3888    PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IHostAudioPort);
     3889
     3890    /*
     3891     * Backend stream to validated DrvAudio stream:
     3892     */
     3893    AssertPtrReturnVoid(pStream);
     3894    AssertReturnVoid(pStream->uMagic == PDMAUDIOBACKENDSTREAM_MAGIC);
     3895    PDRVAUDIOSTREAM pStreamEx = (PDRVAUDIOSTREAM)pStream->pStream;
     3896    AssertPtrReturnVoid(pStreamEx);
     3897    AssertReturnVoid(pStreamEx->Core.uMagic == PDMAUDIOSTREAM_MAGIC);
     3898    AssertReturnVoid(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC);
     3899    LogFlowFunc(("pStreamEx=%p '%s'\n", pStreamEx, pStreamEx->Guest.Cfg.szName));
     3900
     3901    /*
     3902     * Grab the lock and do switch the state (only needed for output streams for now).
     3903     */
     3904    RTCritSectEnter(&pThis->CritSect);
     3905    AssertReturnVoidStmt(pStreamEx->uMagic == DRVAUDIOSTREAM_MAGIC, RTCritSectLeave(&pThis->CritSect)); /* paranoia */
     3906
     3907    if (pStreamEx->Core.enmDir == PDMAUDIODIR_OUT)
     3908    {
     3909        if (pStreamEx->Out.cbPreBufThreshold > 0)
     3910        {
     3911            DRVAUDIOPLAYSTATE const enmPlayState = pStreamEx->Out.enmPlayState;
     3912            switch (enmPlayState)
     3913            {
     3914                case DRVAUDIOPLAYSTATE_PREBUF:
     3915                case DRVAUDIOPLAYSTATE_PREBUF_OVERDUE:
     3916                case DRVAUDIOPLAYSTATE_NOPLAY:
     3917                case DRVAUDIOPLAYSTATE_PREBUF_COMMITTING: /* simpler */
     3918                    pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF_SWITCHING;
     3919                    break;
     3920                case DRVAUDIOPLAYSTATE_PLAY:
     3921                    pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PLAY_PREBUF;
     3922                    break;
     3923                case DRVAUDIOPLAYSTATE_PREBUF_SWITCHING:
     3924                case DRVAUDIOPLAYSTATE_PLAY_PREBUF:
     3925                    break;
     3926                /* no default */
     3927                case DRVAUDIOPLAYSTATE_END:
     3928                case DRVAUDIOPLAYSTATE_INVALID:
     3929                    break;
     3930            }
     3931            LogFunc(("%s -> %s\n", drvAudioPlayStateName(enmPlayState), drvAudioPlayStateName(pStreamEx->Out.enmPlayState) ));
     3932        }
     3933        else
     3934            LogFunc(("No pre-buffering configured.\n"));
     3935    }
     3936    else
     3937        LogFunc(("input stream, nothing to do.\n"));
     3938
     3939    RTCritSectLeave(&pThis->CritSect);
     3940}
     3941
     3942
     3943/**
    39293944 * @interface_method_impl{PDMIHOSTAUDIOPORT,pfnStreamNotifyDeviceChanged}
    39303945 */
     
    39643979                   pStreamEx->fStatus &= ~PDMAUDIOSTREAM_STS_NEED_REINIT);
    39653980
    3966         if (   pStreamEx->Core.enmDir == PDMAUDIODIR_OUT
    3967             && (pStreamEx->fStatus & PDMAUDIOSTREAM_STS_ENABLED))
     3981
     3982        if (pStreamEx->Core.enmDir == PDMAUDIODIR_OUT)
    39683983        {
    39693984            DRVAUDIOPLAYSTATE const enmPlayState = pStreamEx->Out.enmPlayState;
    39703985            pStreamEx->Out.enmPlayState = DRVAUDIOPLAYSTATE_PREBUF;
    39713986            LogFunc(("%s: %s -> %s\n", pStreamEx->Core.szName, drvAudioPlayStateName(enmPlayState),
    3972                      drvAudioPlayStateName(pStreamEx->Out.enmPlayState) )); RT_NOREF(enmPlayState);
    3973         }
     3987                     drvAudioPlayStateName(pStreamEx->Out.enmPlayState) ));
     3988            RT_NOREF(enmPlayState);
     3989        }
     3990
     3991        /* Disable and then fully resync. */
     3992        /** @todo This doesn't work quite reliably if we're in draining mode
     3993         * (PENDING_DISABLE, so the backend needs to take care of that prior to calling
     3994         * us.  Sigh.  The idea was to avoid extra state mess in the backend... */
     3995        drvAudioStreamControlInternalBackend(pThis, pStreamEx, PDMAUDIOSTREAMCMD_DISABLE);
     3996        drvAudioStreamUpdateBackendOnStatus(pThis, pStreamEx, "device changed");
    39743997    }
    39753998
     
    46594682    pThis->IAudioConnector.pfnStreamCapture     = drvAudioStreamCapture;
    46604683    /* IHostAudioPort */
    4661     pThis->IHostAudioPort.pfnDoOnWorkerThread           = drvAudioHostPort_DoOnWorkerThread;
    4662     pThis->IHostAudioPort.pfnNotifyDeviceChanged        = drvAudioHostPort_NotifyDeviceChanged;
    4663     pThis->IHostAudioPort.pfnStreamNotifyDeviceChanged  = drvAudioHostPort_StreamNotifyDeviceChanged;
    4664     pThis->IHostAudioPort.pfnNotifyDevicesChanged       = drvAudioHostPort_NotifyDevicesChanged;
     4684    pThis->IHostAudioPort.pfnDoOnWorkerThread                   = drvAudioHostPort_DoOnWorkerThread;
     4685    pThis->IHostAudioPort.pfnNotifyDeviceChanged                = drvAudioHostPort_NotifyDeviceChanged;
     4686    pThis->IHostAudioPort.pfnStreamNotifyPreparingDeviceSwitch  = drvAudioHostPort_StreamNotifyPreparingDeviceSwitch;
     4687    pThis->IHostAudioPort.pfnStreamNotifyDeviceChanged          = drvAudioHostPort_StreamNotifyDeviceChanged;
     4688    pThis->IHostAudioPort.pfnNotifyDevicesChanged               = drvAudioHostPort_NotifyDevicesChanged;
    46654689
    46664690    /*
  • trunk/src/VBox/Devices/Audio/DrvHostAudioWasApi.cpp

    r88853 r88861  
    3939
    4040#include <iprt/rand.h>
     41#include <iprt/semaphore.h>
    4142#include <iprt/utf16.h>
    4243#include <iprt/uuid.h>
     
    6364/** @name DRVHOSTAUDIOWAS_DO_XXX - Worker thread operations.
    6465 * @{ */
    65 #define DRVHOSTAUDIOWAS_DO_PURGE_CACHE      ((uintptr_t)0x49f37300 + 1)
     66#define DRVHOSTAUDIOWAS_DO_PURGE_CACHE          ((uintptr_t)0x49f37300 + 1)
     67#define DRVHOSTAUDIOWAS_DO_STREAM_DEV_SWITCH    ((uintptr_t)0x49f37300 + 2)
    6668/** @} */
    6769
     
    168170    /** Set if we should restart the stream on resume (saved pause state). */
    169171    bool                        fRestartOnResume;
     172    /** Set if we're switching to a new output/input device. */
     173    bool                        fSwitchingDevice;
    170174
    171175    /** The RTTimeMilliTS() deadline for the draining of this stream (output). */
     
    251255    /** Serializing access to CacheHead. */
    252256    RTCRITSECT                      CritSectCache;
     257    /** Semaphore for signalling that cache purge is done and that the destructor
     258     *  can do cleanups. */
     259    RTSEMEVENTMULTI                 hEvtCachePurge;
    253260
    254261#if 0
     
    578585                m_pDrvWas->pIDeviceInput = pIDevice;
    579586            }
    580 
    581             /** @todo Invalid/update in-use streams. */
    582587        }
    583588        else if (pIDevice)
     
    778783 * Purges all the entries in the cache.
    779784 */
    780 static void drvHostAudioWasCachePurge(PDRVHOSTAUDIOWAS pThis)
     785static void drvHostAudioWasCachePurge(PDRVHOSTAUDIOWAS pThis, bool fOnWorker)
    781786{
    782787    for (;;)
     
    788793            break;
    789794        drvHostAudioWasCacheDestroyDevEntry(pDevEntry);
     795    }
     796
     797    if (fOnWorker)
     798    {
     799        int rc = RTSemEventMultiSignal(pThis->hEvtCachePurge);
     800        AssertRC(rc);
    790801    }
    791802}
     
    10491060 *
    10501061 * @returns VBox status code.
     1062 * @retval  VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED if @a fOnWorker is @c false and
     1063 *          we created a new entry that needs initalization by calling
     1064 *          drvHostAudioWasCacheInitConfig() on it.
    10511065 * @param   pThis       The WASAPI host audio driver instance data.
    10521066 * @param   pIDevice    The device to look up.
    10531067 * @param   pCfgReq     The configuration to look up.
    1054  * @param   fOnWorker   Set if we're on a worker thread, otherwise false.
     1068 * @param   fOnWorker   Set if we're on a worker thread, otherwise false.  When
     1069 *                      set to @c true, VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED will
     1070 *                      not be returned and a new entry will be fully
     1071 *                      initialized before returning.
    10551072 * @param   ppDevCfg    Where to return the requested device config.
    10561073 */
     
    12901307                    AssertBreak(Msg.lParam == 0);
    12911308
    1292                     drvHostAudioWasCachePurge(pThis);
     1309                    drvHostAudioWasCachePurge(pThis, false /*fOnWorker*/);
    12931310                    break;
    12941311                }
     
    13041321
    13051322    LogFlowFunc(("Pre-quit cache purge...\n"));
    1306     drvHostAudioWasCachePurge(pThis);
     1323    drvHostAudioWasCachePurge(pThis, false /*fOnWorker*/);
    13071324
    13081325    LogFunc(("Quits\n"));
     
    15261543
    15271544/**
     1545 * Performs the actual switching of device config.
     1546 *
     1547 * Worker for drvHostAudioWasDoStreamDevSwitch() and
     1548 * drvHostAudioWasHA_StreamNotifyDeviceChanged().
     1549 */
     1550static void drvHostAudioWasCompleteStreamDevSwitch(PDRVHOSTAUDIOWAS pThis, PDRVHOSTAUDIOWASSTREAM pStreamWas,
     1551                                                   PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg)
     1552{
     1553    RTCritSectEnter(&pStreamWas->CritSect);
     1554
     1555    /* Do the switch. */
     1556    PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfgOld = pStreamWas->pDevCfg;
     1557    pStreamWas->pDevCfg = pDevCfg;
     1558
     1559    /* The new stream is neither started nor draining. */
     1560    pStreamWas->fStarted         = false;
     1561    pStreamWas->fDraining        = false;
     1562
     1563    /* Device switching is done now. */
     1564    pStreamWas->fSwitchingDevice = false;
     1565
     1566    /* Stop the old stream or Reset() will fail when putting it back into the cache. */
     1567    if (pStreamWas->fEnabled && pDevCfgOld->pIAudioClient)
     1568        pDevCfgOld->pIAudioClient->Stop();
     1569
     1570    RTCritSectLeave(&pStreamWas->CritSect);
     1571
     1572    /* Notify DrvAudio. */
     1573    pThis->pIHostAudioPort->pfnStreamNotifyDeviceChanged(pThis->pIHostAudioPort, &pStreamWas->Core, false /*fReInit*/);
     1574
     1575    /* Put the old config back into the cache. */
     1576    drvHostAudioWasCachePutBack(pThis, pDevCfgOld);
     1577
     1578    LogFlowFunc(("returns with '%s' state: %s\n", pStreamWas->Cfg.szName, drvHostWasStreamStatusString(pStreamWas) ));
     1579}
     1580
     1581
     1582/**
     1583 * Called on a worker thread to initialize a new device config and switch the
     1584 * given stream to using it.
     1585 *
     1586 * @sa  drvHostAudioWasHA_StreamNotifyDeviceChanged
     1587 */
     1588static void drvHostAudioWasDoStreamDevSwitch(PDRVHOSTAUDIOWAS pThis, PDRVHOSTAUDIOWASSTREAM pStreamWas,
     1589                                             PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg)
     1590{
     1591    /*
     1592     * Do the initializing.
     1593     */
     1594    int rc = drvHostAudioWasCacheInitConfig(pDevCfg);
     1595    if (RT_SUCCESS(rc))
     1596        drvHostAudioWasCompleteStreamDevSwitch(pThis, pStreamWas, pDevCfg);
     1597    else
     1598    {
     1599        LogRelMax(64, ("WasAPI: Failed to set up new device config '%ls:%s' for stream '%s': %Rrc\n",
     1600                       pDevCfg->pDevEntry->wszDevId, pDevCfg->szProps, pStreamWas->Cfg.szName, rc));
     1601        drvHostAudioWasCacheDestroyDevConfig(pDevCfg);
     1602        pThis->pIHostAudioPort->pfnStreamNotifyDeviceChanged(pThis->pIHostAudioPort, &pStreamWas->Core, true /*fReInit*/);
     1603    }
     1604}
     1605
     1606
     1607/**
    15281608 * @interface_method_impl{PDMIHOSTAUDIO,pfnDoOnWorkerThread}
    15291609 */
     
    15321612{
    15331613    PDRVHOSTAUDIOWAS pThis = RT_FROM_MEMBER(pInterface, DRVHOSTAUDIOWAS, IHostAudio);
    1534     RT_NOREF(pStream, pvUser);
    15351614    LogFlowFunc(("uUser=%#zx pStream=%p pvUser=%p\n", uUser, pStream, pvUser));
    15361615
     
    15401619            Assert(pStream == NULL);
    15411620            Assert(pvUser == NULL);
    1542             drvHostAudioWasCachePurge(pThis);
     1621            drvHostAudioWasCachePurge(pThis, true /*fOnWorker*/);
     1622            break;
     1623
     1624        case DRVHOSTAUDIOWAS_DO_STREAM_DEV_SWITCH:
     1625            AssertPtr(pStream);
     1626            AssertPtr(pvUser);
     1627            drvHostAudioWasDoStreamDevSwitch(pThis, (PDRVHOSTAUDIOWASSTREAM)pStream, (PDRVHOSTAUDIOWASCACHEDEVCFG)pvUser);
    15431628            break;
    15441629
     
    17771862    LogFlowFunc(("returns\n"));
    17781863    return VINF_SUCCESS;
     1864}
     1865
     1866
     1867/**
     1868 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamNotifyDeviceChanged}
     1869 */
     1870static DECLCALLBACK(void) drvHostAudioWasHA_StreamNotifyDeviceChanged(PPDMIHOSTAUDIO pInterface,
     1871                                                                      PPDMAUDIOBACKENDSTREAM pStream, void *pvUser)
     1872{
     1873    PDRVHOSTAUDIOWAS        pThis      = RT_FROM_MEMBER(pInterface, DRVHOSTAUDIOWAS, IHostAudio);
     1874    PDRVHOSTAUDIOWASSTREAM  pStreamWas = (PDRVHOSTAUDIOWASSTREAM)pStream;
     1875    LogFlowFunc(("pStreamWas=%p (%s)\n", pStreamWas, pStreamWas->Cfg.szName));
     1876    RT_NOREF(pvUser);
     1877
     1878    /*
     1879     * See if we've got a cached config for the new device around.
     1880     * We ignore this entirely, for now at least, if the device was
     1881     * disconnected and there is no replacement.
     1882     */
     1883    pThis->pNotifyClient->lockEnter();
     1884    IMMDevice *pIDevice = pStreamWas->Cfg.enmDir == PDMAUDIODIR_IN ? pThis->pIDeviceInput : pThis->pIDeviceOutput;
     1885    if (pIDevice)
     1886        pIDevice->AddRef();
     1887    pThis->pNotifyClient->lockLeave();
     1888    if (pIDevice)
     1889    {
     1890        PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = NULL;
     1891        int rc = drvHostAudioWasCacheLookupOrCreate(pThis, pIDevice, &pStreamWas->Cfg, false /*fOnWorker*/, &pDevCfg);
     1892
     1893        pIDevice->Release();
     1894        pIDevice = NULL;
     1895
     1896        /*
     1897         * If we have a working audio client, just do the switch.
     1898         */
     1899        if (RT_SUCCESS(rc) && pDevCfg->pIAudioClient)
     1900        {
     1901            LogFlowFunc(("New device config is ready already!\n"));
     1902            Assert(rc == VINF_SUCCESS);
     1903            drvHostAudioWasCompleteStreamDevSwitch(pThis, pStreamWas, pDevCfg);
     1904        }
     1905        /*
     1906         * Otherwise create one asynchronously on a worker thread.
     1907         */
     1908        else if (RT_SUCCESS(rc))
     1909        {
     1910            LogFlowFunc(("New device config needs async init ...\n"));
     1911            Assert(rc == VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED);
     1912
     1913            RTCritSectEnter(&pStreamWas->CritSect);
     1914            pStreamWas->fSwitchingDevice = true;
     1915            RTCritSectLeave(&pStreamWas->CritSect);
     1916
     1917            pThis->pIHostAudioPort->pfnStreamNotifyPreparingDeviceSwitch(pThis->pIHostAudioPort, &pStreamWas->Core);
     1918
     1919            rc = pThis->pIHostAudioPort->pfnDoOnWorkerThread(pThis->pIHostAudioPort, &pStreamWas->Core,
     1920                                                             DRVHOSTAUDIOWAS_DO_STREAM_DEV_SWITCH, pDevCfg);
     1921            AssertRCStmt(rc, drvHostAudioWasDoStreamDevSwitch(pThis, pStreamWas, pDevCfg));
     1922        }
     1923        else
     1924        {
     1925            LogRelMax(64, ("WasAPI: Failed to create new device config '%ls:%s' for stream '%s': %Rrc\n",
     1926                           pDevCfg->pDevEntry->wszDevId, pDevCfg->szProps, pStreamWas->Cfg.szName, rc));
     1927
     1928            pThis->pIHostAudioPort->pfnStreamNotifyDeviceChanged(pThis->pIHostAudioPort, &pStreamWas->Core, true /*fReInit*/);
     1929        }
     1930    }
     1931    else
     1932        LogFlowFunc(("no new device, leaving it as-is\n"));
    17791933}
    17801934
     
    22832437    }
    22842438    if (pStreamWas->fEnabled)
     2439    {
    22852440        fStrmStatus |= PDMAUDIOSTREAM_STS_ENABLED;
    2286     if (pStreamWas->fDraining)
    2287         fStrmStatus |= PDMAUDIOSTREAM_STS_PENDING_DISABLE;
    2288     if (pStreamWas->fRestartOnResume)
    2289         fStrmStatus |= PDMAUDIOSTREAM_STS_PAUSED;
     2441        if (pStreamWas->fDraining)
     2442            fStrmStatus |= PDMAUDIOSTREAM_STS_PENDING_DISABLE;
     2443        if (pStreamWas->fRestartOnResume)
     2444            fStrmStatus |= PDMAUDIOSTREAM_STS_PAUSED;
     2445    }
     2446    if (pStreamWas->fSwitchingDevice)
     2447        fStrmStatus |= PDMAUDIOSTREAM_STS_PREPARING_SWITCH;
    22902448
    22912449    LogFlowFunc(("returns %#x for '%s' {%s}\n", fStrmStatus, pStreamWas->Cfg.szName, drvHostWasStreamStatusString(pStreamWas)));
     
    26282786    if (!RTListIsEmpty(&pThis->CacheHead) && pThis->pIHostAudioPort)
    26292787    {
    2630         int rc = pThis->pIHostAudioPort->pfnDoOnWorkerThread(pThis->pIHostAudioPort, NULL/*pStream*/,
     2788        int rc = RTSemEventMultiCreate(&pThis->hEvtCachePurge);
     2789        if (RT_SUCCESS(rc))
     2790        {
     2791            rc = pThis->pIHostAudioPort->pfnDoOnWorkerThread(pThis->pIHostAudioPort, NULL/*pStream*/,
    26312792                                                             DRVHOSTAUDIOWAS_DO_PURGE_CACHE, NULL /*pvUser*/);
    2632         AssertRC(rc);
     2793            AssertRC(rc);
     2794        }
    26332795    }
    26342796#endif
     
    26572819    LogFlowFuncEnter();
    26582820
     2821    /*
     2822     * Release the notification client first.
     2823     */
    26592824    if (pThis->pNotifyClient)
    26602825    {
     
    26782843    if (RTCritSectIsInitialized(&pThis->CritSectCache))
    26792844    {
    2680         drvHostAudioWasCachePurge(pThis);
     2845        drvHostAudioWasCachePurge(pThis, false /*fOnWorker*/);
     2846        if (pThis->hEvtCachePurge != NIL_RTSEMEVENTMULTI)
     2847            RTSemEventMultiWait(pThis->hEvtCachePurge, RT_MS_30SEC);
    26812848        RTCritSectDelete(&pThis->CritSectCache);
     2849    }
     2850
     2851    if (pThis->hEvtCachePurge != NIL_RTSEMEVENTMULTI)
     2852    {
     2853        RTSemEventMultiDestroy(pThis->hEvtCachePurge);
     2854        pThis->hEvtCachePurge = NIL_RTSEMEVENTMULTI;
    26822855    }
    26832856
     
    27222895    pThis->pDrvIns                          = pDrvIns;
    27232896    pThis->hDrainTimer                      = NIL_TMTIMERHANDLE;
     2897    pThis->hEvtCachePurge                   = NIL_RTSEMEVENTMULTI;
    27242898#if 0
    27252899    pThis->hWorkerThread                    = NIL_RTTHREAD;
     
    27392913    pThis->IHostAudio.pfnStreamInitAsync            = drvHostAudioWasHA_StreamInitAsync;
    27402914    pThis->IHostAudio.pfnStreamDestroy              = drvHostAudioWasHA_StreamDestroy;
    2741     pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = NULL;
     2915    pThis->IHostAudio.pfnStreamNotifyDeviceChanged  = drvHostAudioWasHA_StreamNotifyDeviceChanged;
    27422916    pThis->IHostAudio.pfnStreamControl              = drvHostAudioWasHA_StreamControl;
    27432917    pThis->IHostAudio.pfnStreamGetReadable          = drvHostAudioWasHA_StreamGetReadable;
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