VirtualBox

Changeset 88667 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Apr 23, 2021 12:00:17 AM (4 years ago)
Author:
vboxsync
Message:

DrvHostAudioWasApi: Always keep IMMDevice pointer to the input and output devices we're using around. Saves ~2ms when setting up a stream. The change notification client keeps them up to date. bugref:9890

File:
1 edited

Legend:

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

    r88663 r88667  
    201201    PRTUTF16                        pwszInputDevId;
    202202
     203    /** Pointer to the MM notification client instance. */
     204    DrvHostAudioWasMmNotifyClient  *pNotifyClient;
     205    /** The input device to use.  This can be NULL if there wasn't a suitable one
     206     * around when we last looked or if it got removed/disabled/whatever.
     207    * All access must be done inside the pNotifyClient critsect. */
     208    IMMDevice                      *pIDeviceInput;
     209    /** The output device to use.  This can be NULL if there wasn't a suitable one
     210     * around when we last looked or if it got removed/disabled/whatever.
     211     * All access must be done inside the pNotifyClient critsect. */
     212    IMMDevice                      *pIDeviceOutput;
     213
    203214    /** A drain stop timer that makes sure a draining stream will be properly
    204215     * stopped (mainly for clean state and to reduce resource usage). */
     
    210221    RTCRITSECTRW                    CritSectStreamList;
    211222
    212     /** Pointer to the MM notification client instance. */
    213     DrvHostAudioWasMmNotifyClient  *pNotifyClient;
    214223    /** List of cached devices (DRVHOSTAUDIOWASCACHEDEV).
    215224     * Protected by CritSectCache  */
     
    860869    }
    861870
     871    /**
     872     * Enters the notification critsect for getting at the IMMDevice members in
     873     * PDMHOSTAUDIOWAS.
     874     */
     875    void lockEnter() RT_NOEXCEPT
     876    {
     877        RTCritSectEnter(&m_CritSect);
     878    }
     879
     880    /**
     881     * Leaves the notification critsect.
     882     */
     883    void lockLeave() RT_NOEXCEPT
     884    {
     885        RTCritSectLeave(&m_CritSect);
     886    }
     887
    862888    /** @name IUnknown interface
    863889     * @{ */
     
    910936        RT_NOREF(pwszDeviceId);
    911937        Log7Func(("pwszDeviceId=%ls\n", pwszDeviceId));
     938
     939        /*
     940         * Is this a device we're interested in?  Grab the enumerator if it is.
     941         */
     942        bool                 fOutput      = false;
     943        IMMDeviceEnumerator *pIEnumerator = NULL;
     944        RTCritSectEnter(&m_CritSect);
     945        if (   m_pDrvWas != NULL
     946            && (   (fOutput = RTUtf16ICmp(m_pDrvWas->pwszOutputDevId, pwszDeviceId) == 0)
     947                || RTUtf16ICmp(m_pDrvWas->pwszInputDevId, pwszDeviceId) == 0))
     948        {
     949            pIEnumerator = m_pDrvWas->pIEnumerator;
     950            if (pIEnumerator /* paranoia */)
     951                pIEnumerator->AddRef();
     952        }
     953        RTCritSectLeave(&m_CritSect);
     954        if (pIEnumerator)
     955        {
     956            /*
     957             * Get the device and update it.
     958             */
     959            IMMDevice *pIDevice = NULL;
     960            HRESULT hrc = pIEnumerator->GetDevice(pwszDeviceId, &pIDevice);
     961            if (SUCCEEDED(hrc))
     962                setDevice(fOutput, pIDevice, pwszDeviceId, __PRETTY_FUNCTION__);
     963            else
     964                LogRelMax(64, ("WasAPI: Failed to get %s device '%ls' (OnDeviceAdded): %Rhrc\n",
     965                               fOutput ? "output" : "input", pwszDeviceId, hrc));
     966            pIEnumerator->Release();
     967        }
    912968        return S_OK;
    913969    }
     
    917973        RT_NOREF(pwszDeviceId);
    918974        Log7Func(("pwszDeviceId=%ls\n", pwszDeviceId));
     975
     976        /*
     977         * Is this a device we're interested in?  Then set it to NULL.
     978         */
     979        bool fOutput = false;
     980        RTCritSectEnter(&m_CritSect);
     981        if (   m_pDrvWas != NULL
     982            && (   (fOutput = RTUtf16ICmp(m_pDrvWas->pwszOutputDevId, pwszDeviceId) == 0)
     983                || RTUtf16ICmp(m_pDrvWas->pwszInputDevId, pwszDeviceId) == 0))
     984            setDevice(fOutput, NULL, pwszDeviceId, __PRETTY_FUNCTION__);
     985        RTCritSectLeave(&m_CritSect);
    919986        return S_OK;
    920987    }
     
    922989    IFACEMETHODIMP OnDefaultDeviceChanged(EDataFlow enmFlow, ERole enmRole, LPCWSTR pwszDefaultDeviceId)
    923990    {
     991        /*
     992         * Are we interested in this device?  If so grab the enumerator.
     993         */
     994        IMMDeviceEnumerator *pIEnumerator = NULL;
     995        RTCritSectEnter(&m_CritSect);
     996        if (    m_pDrvWas != NULL
     997            && (   (enmFlow == eRender  && enmRole == eMultimedia && !m_pDrvWas->pwszOutputDevId)
     998                || (enmFlow == eCapture && enmRole == eMultimedia && !m_pDrvWas->pwszInputDevId)))
     999        {
     1000            pIEnumerator = m_pDrvWas->pIEnumerator;
     1001            if (pIEnumerator /* paranoia */)
     1002                pIEnumerator->AddRef();
     1003        }
     1004        RTCritSectLeave(&m_CritSect);
     1005        if (pIEnumerator)
     1006        {
     1007            /*
     1008             * Get the device and update it.
     1009             */
     1010            IMMDevice *pIDevice = NULL;
     1011            HRESULT hrc = pIEnumerator->GetDefaultAudioEndpoint(enmFlow, enmRole, &pIDevice);
     1012            if (SUCCEEDED(hrc))
     1013                setDevice(enmFlow == eRender, pIDevice, pwszDefaultDeviceId, __PRETTY_FUNCTION__);
     1014            else
     1015                LogRelMax(64, ("WasAPI: Failed to get default %s device (OnDefaultDeviceChange): %Rhrc\n",
     1016                               enmFlow == eRender ? "output" : "input", hrc));
     1017            pIEnumerator->Release();
     1018        }
     1019
    9241020        RT_NOREF(enmFlow, enmRole, pwszDefaultDeviceId);
    9251021        Log7Func(("enmFlow=%d enmRole=%d pwszDefaultDeviceId=%ls\n", enmFlow, enmRole, pwszDefaultDeviceId));
     
    9341030    }
    9351031    /** @} */
     1032
     1033private:
     1034    /**
     1035     * Sets DRVHOSTAUDIOWAS::pIDeviceOutput or DRVHOSTAUDIOWAS::pIDeviceInput to @a pIDevice.
     1036     */
     1037    void setDevice(bool fOutput, IMMDevice *pIDevice, LPCWSTR pwszDeviceId, const char *pszCaller)
     1038    {
     1039        RT_NOREF(pszCaller, pwszDeviceId);
     1040
     1041        RTCritSectEnter(&m_CritSect);
     1042        if (m_pDrvWas)
     1043        {
     1044            if (fOutput)
     1045            {
     1046                Log7((LOG_FN_FMT ": Changing output device from %p to %p (%ls)\n",
     1047                      pszCaller, m_pDrvWas->pIDeviceOutput, pIDevice, pwszDeviceId));
     1048                if (m_pDrvWas->pIDeviceOutput)
     1049                    m_pDrvWas->pIDeviceOutput->Release();
     1050                m_pDrvWas->pIDeviceOutput = pIDevice;
     1051            }
     1052            else
     1053            {
     1054                Log7((LOG_FN_FMT ": Changing input device from %p to %p (%ls)\n",
     1055                      pszCaller, m_pDrvWas->pIDeviceInput, pIDevice, pwszDeviceId));
     1056                if (m_pDrvWas->pIDeviceInput)
     1057                    m_pDrvWas->pIDeviceInput->Release();
     1058                m_pDrvWas->pIDeviceInput = pIDevice;
     1059            }
     1060
     1061            /** @todo Invalid/update in-use streams. */
     1062        }
     1063        else if (pIDevice)
     1064            pIDevice->Release();
     1065        RTCritSectLeave(&m_CritSect);
     1066    }
    9361067};
    9371068
     
    11961327    /*
    11971328     * Get the device we're supposed to use.
    1198      */
    1199     PRTUTF16        pwszDevId = pCfgReq->enmDir == PDMAUDIODIR_IN ? pThis->pwszInputDevId : pThis->pwszOutputDevId;
    1200     IMMDevice      *pIDevice  = NULL;
    1201     HRESULT         hrc;
    1202     if (pwszDevId)
    1203         hrc = pThis->pIEnumerator->GetDevice(pwszDevId, &pIDevice);
    1204     else
    1205     {
    1206         /** @todo this takes about 2ms. Cache it and update it using the
    1207          *        notification client. */
    1208         hrc = pThis->pIEnumerator->GetDefaultAudioEndpoint(pCfgReq->enmDir == PDMAUDIODIR_IN ? eCapture : eRender,
    1209                                                            eMultimedia, &pIDevice);
    1210         pwszDevId = pCfgReq->enmDir == PDMAUDIODIR_IN ? L"{Default-In}" : L"{Default-Out}";
    1211     }
    1212     LogFlowFunc(("Got device %p (%Rhrc)\n", pIDevice, hrc));
    1213     if (FAILED(hrc))
    1214     {
    1215         LogRelMax(64, ("WasAPI: Failed to open audio %s device '%ls': %Rhrc\n", pszStreamType, pwszDevId, hrc));
    1216         return VERR_AUDIO_STREAM_COULD_NOT_CREATE;
     1329     * (We cache this as it takes ~2ms to get the default device on a random W10 19042 system.)
     1330     */
     1331    pThis->pNotifyClient->lockEnter();
     1332    IMMDevice *pIDevice = pCfgReq->enmDir == PDMAUDIODIR_IN ? pThis->pIDeviceInput : pThis->pIDeviceOutput;
     1333    if (pIDevice)
     1334        pIDevice->AddRef();
     1335    pThis->pNotifyClient->lockLeave();
     1336
     1337    PRTUTF16       pwszDevId     = pCfgReq->enmDir == PDMAUDIODIR_IN ? pThis->pwszInputDevId : pThis->pwszOutputDevId;
     1338    PRTUTF16 const pwszDevIdDesc = pwszDevId ? pwszDevId : pCfgReq->enmDir == PDMAUDIODIR_IN ? L"{Default-In}" : L"{Default-Out}";
     1339    if (!pIDevice)
     1340    {
     1341        /** @todo we can eliminate this too...   */
     1342        HRESULT hrc;
     1343        if (pwszDevId)
     1344            hrc = pThis->pIEnumerator->GetDevice(pwszDevId, &pIDevice);
     1345        else
     1346            hrc = pThis->pIEnumerator->GetDefaultAudioEndpoint(pCfgReq->enmDir == PDMAUDIODIR_IN ? eCapture : eRender,
     1347                                                               eMultimedia, &pIDevice);
     1348        LogFlowFunc(("Got device %p (%Rhrc)\n", pIDevice, hrc));
     1349        if (FAILED(hrc))
     1350        {
     1351            LogRelMax(64, ("WasAPI: Failed to open audio %s device '%ls': %Rhrc\n", pszStreamType, pwszDevIdDesc, hrc));
     1352            return VERR_AUDIO_STREAM_COULD_NOT_CREATE;
     1353        }
    12171354    }
    12181355
     
    12521389        }
    12531390
    1254         LogRelMax(64, ("WasAPI: Failed to create critical section for stream.\n", hrc));
     1391        LogRelMax(64, ("WasAPI: Failed to create critical section for stream.\n"));
    12551392        drvHostAudioWasCachePutBack(pThis, pDevCfg);
    12561393        pStreamWas->pDevCfg = NULL;
    12571394    }
    12581395    else
    1259         LogRelMax(64, ("WasAPI: Failed to activate %s audio device '%ls': %Rhrc\n", pszStreamType, pwszDevId, hrc));
     1396        LogRelMax(64, ("WasAPI: Failed to setup %s on audio device '%ls'.\n", pszStreamType, pwszDevIdDesc));
    12601397
    12611398    LogFlowFunc(("returns %Rrc\n", rc));
     
    21562293    }
    21572294
     2295    if (pThis->pIDeviceOutput)
     2296    {
     2297        pThis->pIDeviceOutput->Release();
     2298        pThis->pIDeviceOutput = NULL;
     2299    }
     2300
     2301    if (pThis->pIDeviceInput)
     2302    {
     2303        pThis->pIDeviceInput->Release();
     2304        pThis->pIDeviceInput = NULL;
     2305    }
     2306
    21582307    if (RTCritSectRwIsInitialized(&pThis->CritSectStreamList))
    21592308        RTCritSectRwDelete(&pThis->CritSectStreamList);
     
    22682417        pThis->pNotifyClient = NULL;
    22692418    }
     2419
     2420    /*
     2421     * Retrieve the input and output device.
     2422     */
     2423    IMMDevice *pIDeviceInput = NULL;
     2424    if (pThis->pwszInputDevId)
     2425        hrc = pThis->pIEnumerator->GetDevice(pThis->pwszInputDevId, &pIDeviceInput);
     2426    else
     2427        hrc = pThis->pIEnumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &pIDeviceInput);
     2428    if (SUCCEEDED(hrc))
     2429        LogFlowFunc(("pIDeviceInput=%p\n", pIDeviceInput));
     2430    else
     2431    {
     2432        LogRel(("WasAPI: Failed to get audio input device '%ls': %Rhrc\n",
     2433                pThis->pwszInputDevId ? pThis->pwszInputDevId : L"{Default}", hrc));
     2434        pIDeviceInput = NULL;
     2435    }
     2436
     2437    IMMDevice *pIDeviceOutput = NULL;
     2438    if (pThis->pwszOutputDevId)
     2439        hrc = pThis->pIEnumerator->GetDevice(pThis->pwszOutputDevId, &pIDeviceOutput);
     2440    else
     2441        hrc = pThis->pIEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pIDeviceOutput);
     2442    if (SUCCEEDED(hrc))
     2443        LogFlowFunc(("pIDeviceOutput=%p\n", pIDeviceOutput));
     2444    else
     2445    {
     2446        LogRel(("WasAPI: Failed to get audio output device '%ls': %Rhrc\n",
     2447                pThis->pwszOutputDevId ? pThis->pwszOutputDevId : L"{Default}", hrc));
     2448        pIDeviceOutput = NULL;
     2449    }
     2450
     2451    /* Carefully place them in the instance data:  */
     2452    pThis->pNotifyClient->lockEnter();
     2453
     2454    if (pThis->pIDeviceInput)
     2455        pThis->pIDeviceInput->Release();
     2456    pThis->pIDeviceInput = pIDeviceInput;
     2457
     2458    if (pThis->pIDeviceOutput)
     2459        pThis->pIDeviceOutput->Release();
     2460    pThis->pIDeviceOutput = pIDeviceOutput;
     2461
     2462    pThis->pNotifyClient->lockLeave();
    22702463
    22712464    /*
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