Changeset 88706 in vbox
- Timestamp:
- Apr 26, 2021 3:59:11 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144023
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioWasApi.cpp
r88693 r88706 38 38 #include <VBox/vmm/pdmaudiohostenuminline.h> 39 39 40 #include <iprt/rand.h> 40 41 #include <iprt/utf16.h> 41 42 #include <iprt/uuid.h> … … 51 52 /** Max GetCurrentPadding value we accept (to make sure it's safe to convert to bytes). */ 52 53 #define VBOX_WASAPI_MAX_PADDING UINT32_C(0x007fffff) 54 55 /** @name WM_DRVHOSTAUDIOWAS_XXX - Worker thread messages. 56 * @{ */ 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) 62 /** @} */ 53 63 54 64 … … 227 237 RTCRITSECT CritSectCache; 228 238 239 /** The worker thread. */ 240 RTTHREAD hWorkerThread; 241 /** The TID of the worker thread (for posting messages to it). */ 242 DWORD idWorkerThread; 243 /** The fixed wParam value for the worker thread. */ 244 WPARAM uWorkerThreadFixedParam; 245 229 246 } DRVHOSTAUDIOWAS; 230 247 /** Pointer to the data for a WASAPI host audio driver instance. */ … … 275 292 276 293 /********************************************************************************************************************************* 277 * Pre-activated audio device client cache. * 294 * IMMNotificationClient implementation 295 *********************************************************************************************************************************/ 296 /** 297 * Multimedia notification client. 298 * 299 * We want to know when the default device changes so we can switch running 300 * streams to use the new one and so we can pre-activate it in preparation 301 * for new streams. 302 */ 303 class DrvHostAudioWasMmNotifyClient : public IMMNotificationClient 304 { 305 private: 306 /** Reference counter. */ 307 uint32_t volatile m_cRefs; 308 /** The WASAPI host audio driver instance data. 309 * @note This can be NULL. Only access after entering critical section. */ 310 PDRVHOSTAUDIOWAS m_pDrvWas; 311 /** Critical section serializing access to m_pDrvWas. */ 312 RTCRITSECT m_CritSect; 313 314 public: 315 /** 316 * @throws int on critical section init failure. 317 */ 318 DrvHostAudioWasMmNotifyClient(PDRVHOSTAUDIOWAS a_pDrvWas) 319 : m_cRefs(1) 320 , m_pDrvWas(a_pDrvWas) 321 { 322 int rc = RTCritSectInit(&m_CritSect); 323 AssertRCStmt(rc, throw(rc)); 324 } 325 326 virtual ~DrvHostAudioWasMmNotifyClient() RT_NOEXCEPT 327 { 328 RTCritSectDelete(&m_CritSect); 329 } 330 331 /** 332 * Called by drvHostAudioWasDestruct to set m_pDrvWas to NULL. 333 */ 334 void notifyDriverDestroyed() RT_NOEXCEPT 335 { 336 RTCritSectEnter(&m_CritSect); 337 m_pDrvWas = NULL; 338 RTCritSectLeave(&m_CritSect); 339 } 340 341 /** 342 * Enters the notification critsect for getting at the IMMDevice members in 343 * PDMHOSTAUDIOWAS. 344 */ 345 void lockEnter() RT_NOEXCEPT 346 { 347 RTCritSectEnter(&m_CritSect); 348 } 349 350 /** 351 * Leaves the notification critsect. 352 */ 353 void lockLeave() RT_NOEXCEPT 354 { 355 RTCritSectLeave(&m_CritSect); 356 } 357 358 /** @name IUnknown interface 359 * @{ */ 360 IFACEMETHODIMP_(ULONG) AddRef() 361 { 362 uint32_t cRefs = ASMAtomicIncU32(&m_cRefs); 363 AssertMsg(cRefs < 64, ("%#x\n", cRefs)); 364 Log6Func(("returns %u\n", cRefs)); 365 return cRefs; 366 } 367 368 IFACEMETHODIMP_(ULONG) Release() 369 { 370 uint32_t cRefs = ASMAtomicDecU32(&m_cRefs); 371 AssertMsg(cRefs < 64, ("%#x\n", cRefs)); 372 if (cRefs == 0) 373 delete this; 374 Log6Func(("returns %u\n", cRefs)); 375 return cRefs; 376 } 377 378 IFACEMETHODIMP QueryInterface(const IID &rIID, void **ppvInterface) 379 { 380 if (IsEqualIID(rIID, IID_IUnknown)) 381 *ppvInterface = static_cast<IUnknown *>(this); 382 else if (IsEqualIID(rIID, __uuidof(IMMNotificationClient))) 383 *ppvInterface = static_cast<IMMNotificationClient *>(this); 384 else 385 { 386 LogFunc(("Unknown rIID={%RTuuid}\n", &rIID)); 387 *ppvInterface = NULL; 388 return E_NOINTERFACE; 389 } 390 Log6Func(("returns S_OK + %p\n", *ppvInterface)); 391 return S_OK; 392 } 393 /** @} */ 394 395 /** @name IMMNotificationClient interface 396 * @{ */ 397 IFACEMETHODIMP OnDeviceStateChanged(LPCWSTR pwszDeviceId, DWORD dwNewState) 398 { 399 RT_NOREF(pwszDeviceId, dwNewState); 400 Log7Func(("pwszDeviceId=%ls dwNewState=%u (%#x)\n", pwszDeviceId, dwNewState, dwNewState)); 401 return S_OK; 402 } 403 404 IFACEMETHODIMP OnDeviceAdded(LPCWSTR pwszDeviceId) 405 { 406 RT_NOREF(pwszDeviceId); 407 Log7Func(("pwszDeviceId=%ls\n", pwszDeviceId)); 408 409 /* 410 * Is this a device we're interested in? Grab the enumerator if it is. 411 */ 412 bool fOutput = false; 413 IMMDeviceEnumerator *pIEnumerator = NULL; 414 RTCritSectEnter(&m_CritSect); 415 if ( m_pDrvWas != NULL 416 && ( (fOutput = RTUtf16ICmp(m_pDrvWas->pwszOutputDevId, pwszDeviceId) == 0) 417 || RTUtf16ICmp(m_pDrvWas->pwszInputDevId, pwszDeviceId) == 0)) 418 { 419 pIEnumerator = m_pDrvWas->pIEnumerator; 420 if (pIEnumerator /* paranoia */) 421 pIEnumerator->AddRef(); 422 } 423 RTCritSectLeave(&m_CritSect); 424 if (pIEnumerator) 425 { 426 /* 427 * Get the device and update it. 428 */ 429 IMMDevice *pIDevice = NULL; 430 HRESULT hrc = pIEnumerator->GetDevice(pwszDeviceId, &pIDevice); 431 if (SUCCEEDED(hrc)) 432 setDevice(fOutput, pIDevice, pwszDeviceId, __PRETTY_FUNCTION__); 433 else 434 LogRelMax(64, ("WasAPI: Failed to get %s device '%ls' (OnDeviceAdded): %Rhrc\n", 435 fOutput ? "output" : "input", pwszDeviceId, hrc)); 436 pIEnumerator->Release(); 437 } 438 return S_OK; 439 } 440 441 IFACEMETHODIMP OnDeviceRemoved(LPCWSTR pwszDeviceId) 442 { 443 RT_NOREF(pwszDeviceId); 444 Log7Func(("pwszDeviceId=%ls\n", pwszDeviceId)); 445 446 /* 447 * Is this a device we're interested in? Then set it to NULL. 448 */ 449 bool fOutput = false; 450 RTCritSectEnter(&m_CritSect); 451 if ( m_pDrvWas != NULL 452 && ( (fOutput = RTUtf16ICmp(m_pDrvWas->pwszOutputDevId, pwszDeviceId) == 0) 453 || RTUtf16ICmp(m_pDrvWas->pwszInputDevId, pwszDeviceId) == 0)) 454 setDevice(fOutput, NULL, pwszDeviceId, __PRETTY_FUNCTION__); 455 RTCritSectLeave(&m_CritSect); 456 return S_OK; 457 } 458 459 IFACEMETHODIMP OnDefaultDeviceChanged(EDataFlow enmFlow, ERole enmRole, LPCWSTR pwszDefaultDeviceId) 460 { 461 /* 462 * Are we interested in this device? If so grab the enumerator. 463 */ 464 IMMDeviceEnumerator *pIEnumerator = NULL; 465 RTCritSectEnter(&m_CritSect); 466 if ( m_pDrvWas != NULL 467 && ( (enmFlow == eRender && enmRole == eMultimedia && !m_pDrvWas->pwszOutputDevId) 468 || (enmFlow == eCapture && enmRole == eMultimedia && !m_pDrvWas->pwszInputDevId))) 469 { 470 pIEnumerator = m_pDrvWas->pIEnumerator; 471 if (pIEnumerator /* paranoia */) 472 pIEnumerator->AddRef(); 473 } 474 RTCritSectLeave(&m_CritSect); 475 if (pIEnumerator) 476 { 477 /* 478 * Get the device and update it. 479 */ 480 IMMDevice *pIDevice = NULL; 481 HRESULT hrc = pIEnumerator->GetDefaultAudioEndpoint(enmFlow, enmRole, &pIDevice); 482 if (SUCCEEDED(hrc)) 483 setDevice(enmFlow == eRender, pIDevice, pwszDefaultDeviceId, __PRETTY_FUNCTION__); 484 else 485 LogRelMax(64, ("WasAPI: Failed to get default %s device (OnDefaultDeviceChange): %Rhrc\n", 486 enmFlow == eRender ? "output" : "input", hrc)); 487 pIEnumerator->Release(); 488 } 489 490 RT_NOREF(enmFlow, enmRole, pwszDefaultDeviceId); 491 Log7Func(("enmFlow=%d enmRole=%d pwszDefaultDeviceId=%ls\n", enmFlow, enmRole, pwszDefaultDeviceId)); 492 return S_OK; 493 } 494 495 IFACEMETHODIMP OnPropertyValueChanged(LPCWSTR pwszDeviceId, const PROPERTYKEY Key) 496 { 497 RT_NOREF(pwszDeviceId, Key); 498 Log7Func(("pwszDeviceId=%ls Key={%RTuuid, %u (%#x)}\n", pwszDeviceId, &Key.fmtid, Key.pid, Key.pid)); 499 return S_OK; 500 } 501 /** @} */ 502 503 private: 504 /** 505 * Sets DRVHOSTAUDIOWAS::pIDeviceOutput or DRVHOSTAUDIOWAS::pIDeviceInput to @a pIDevice. 506 */ 507 void setDevice(bool fOutput, IMMDevice *pIDevice, LPCWSTR pwszDeviceId, const char *pszCaller) 508 { 509 RT_NOREF(pszCaller, pwszDeviceId); 510 511 RTCritSectEnter(&m_CritSect); 512 if (m_pDrvWas) 513 { 514 if (fOutput) 515 { 516 Log7((LOG_FN_FMT ": Changing output device from %p to %p (%ls)\n", 517 pszCaller, m_pDrvWas->pIDeviceOutput, pIDevice, pwszDeviceId)); 518 if (m_pDrvWas->pIDeviceOutput) 519 m_pDrvWas->pIDeviceOutput->Release(); 520 m_pDrvWas->pIDeviceOutput = pIDevice; 521 } 522 else 523 { 524 Log7((LOG_FN_FMT ": Changing input device from %p to %p (%ls)\n", 525 pszCaller, m_pDrvWas->pIDeviceInput, pIDevice, pwszDeviceId)); 526 if (m_pDrvWas->pIDeviceInput) 527 m_pDrvWas->pIDeviceInput->Release(); 528 m_pDrvWas->pIDeviceInput = pIDevice; 529 } 530 531 /** @todo Invalid/update in-use streams. */ 532 } 533 else if (pIDevice) 534 pIDevice->Release(); 535 RTCritSectLeave(&m_CritSect); 536 } 537 }; 538 539 540 /********************************************************************************************************************************* 541 * Pre-configured audio client cache. * 278 542 *********************************************************************************************************************************/ 279 543 #define WAS_CACHE_MAX_ENTRIES_SAME_DEVICE 2 … … 769 1033 770 1034 1035 static void drvHostWasCacheConfigHinting(PDRVHOSTAUDIOWAS pThis, PPDMAUDIOSTREAMCFG pCfgReq) 1036 { 1037 /* 1038 * Get the device. 1039 */ 1040 pThis->pNotifyClient->lockEnter(); 1041 IMMDevice *pIDevice = pCfgReq->enmDir == PDMAUDIODIR_IN ? pThis->pIDeviceInput : pThis->pIDeviceOutput; 1042 if (pIDevice) 1043 pIDevice->AddRef(); 1044 pThis->pNotifyClient->lockLeave(); 1045 if (pIDevice) 1046 { 1047 /* 1048 * Look up the config and put it back. 1049 */ 1050 PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = drvHostAudioWasCacheLookupOrCreate(pThis, pIDevice, pCfgReq); 1051 LogFlowFunc(("pDevCfg=%p\n")); 1052 if (pDevCfg) 1053 drvHostAudioWasCachePutBack(pThis, pDevCfg); 1054 pIDevice->Release(); 1055 } 1056 } 1057 1058 771 1059 /** 772 1060 * Prefills the cache. … … 822 1110 823 1111 /********************************************************************************************************************************* 824 * IMMNotificationClient implementation1112 * Worker thread * 825 1113 *********************************************************************************************************************************/ 826 /** 827 * Multimedia notification client. 828 * 829 * We want to know when the default device changes so we can switch running 830 * streams to use the new one and so we can pre-activate it in preparation 831 * for new streams. 832 */ 833 class DrvHostAudioWasMmNotifyClient : public IMMNotificationClient 834 { 835 private: 836 /** Reference counter. */ 837 uint32_t volatile m_cRefs; 838 /** The WASAPI host audio driver instance data. 839 * @note This can be NULL. Only access after entering critical section. */ 840 PDRVHOSTAUDIOWAS m_pDrvWas; 841 /** Critical section serializing access to m_pDrvWas. */ 842 RTCRITSECT m_CritSect; 843 844 public: 845 /** 846 * @throws int on critical section init failure. 847 */ 848 DrvHostAudioWasMmNotifyClient(PDRVHOSTAUDIOWAS a_pDrvWas) 849 : m_cRefs(1) 850 , m_pDrvWas(a_pDrvWas) 851 { 852 int rc = RTCritSectInit(&m_CritSect); 853 AssertRCStmt(rc, throw(rc)); 854 } 855 856 virtual ~DrvHostAudioWasMmNotifyClient() RT_NOEXCEPT 857 { 858 RTCritSectDelete(&m_CritSect); 859 } 860 861 /** 862 * Called by drvHostAudioWasDestruct to set m_pDrvWas to NULL. 863 */ 864 void notifyDriverDestroyed() RT_NOEXCEPT 865 { 866 RTCritSectEnter(&m_CritSect); 867 m_pDrvWas = NULL; 868 RTCritSectLeave(&m_CritSect); 869 } 870 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 888 /** @name IUnknown interface 889 * @{ */ 890 IFACEMETHODIMP_(ULONG) AddRef() 891 { 892 uint32_t cRefs = ASMAtomicIncU32(&m_cRefs); 893 AssertMsg(cRefs < 64, ("%#x\n", cRefs)); 894 Log6Func(("returns %u\n", cRefs)); 895 return cRefs; 896 } 897 898 IFACEMETHODIMP_(ULONG) Release() 899 { 900 uint32_t cRefs = ASMAtomicDecU32(&m_cRefs); 901 AssertMsg(cRefs < 64, ("%#x\n", cRefs)); 902 if (cRefs == 0) 903 delete this; 904 Log6Func(("returns %u\n", cRefs)); 905 return cRefs; 906 } 907 908 IFACEMETHODIMP QueryInterface(const IID &rIID, void **ppvInterface) 909 { 910 if (IsEqualIID(rIID, IID_IUnknown)) 911 *ppvInterface = static_cast<IUnknown *>(this); 912 else if (IsEqualIID(rIID, __uuidof(IMMNotificationClient))) 913 *ppvInterface = static_cast<IMMNotificationClient *>(this); 1114 1115 /** 1116 * @callback_method_impl{FNRTTHREAD, 1117 * Asynchronous thread for setting up audio client configs.} 1118 */ 1119 static DECLCALLBACK(int) drvHostWasWorkerThread(RTTHREAD hThreadSelf, void *pvUser) 1120 { 1121 PDRVHOSTAUDIOWAS pThis = (PDRVHOSTAUDIOWAS)pvUser; 1122 1123 /* 1124 * We need to set the thread ID so others can post us thread messages. 1125 * And before we signal that we're ready, make sure we've got a message queue. 1126 */ 1127 pThis->idWorkerThread = GetCurrentThreadId(); 1128 LogFunc(("idWorkerThread=%#x (%u)\n", pThis->idWorkerThread, pThis->idWorkerThread)); 1129 1130 MSG Msg; 1131 PeekMessageW(&Msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); 1132 1133 int rc = RTThreadUserSignal(hThreadSelf); 1134 AssertRC(rc); 1135 1136 /* 1137 * Message loop. 1138 */ 1139 BOOL fRet; 1140 while ((fRet = GetMessageW(&Msg, NULL, 0, 0)) != FALSE) 1141 { 1142 if (fRet != -1) 1143 { 1144 TranslateMessage(&Msg); 1145 Log9Func(("Msg: time=%u: msg=%#x l=%p w=%p for hwnd=%p\n", Msg.time, Msg.message, Msg.lParam, Msg.wParam, Msg.hwnd)); 1146 switch (Msg.message) 1147 { 1148 case WM_DRVHOSTAUDIOWAS_HINT: 1149 { 1150 AssertMsgBreak(Msg.wParam == pThis->uWorkerThreadFixedParam, ("%p\n", Msg.wParam)); 1151 AssertBreak(Msg.hwnd == NULL); 1152 PPDMAUDIOSTREAMCFG pCfgReq = (PPDMAUDIOSTREAMCFG)Msg.lParam; 1153 AssertPtrBreak(pCfgReq); 1154 1155 drvHostWasCacheConfigHinting(pThis, pCfgReq); 1156 RTMemFree(pCfgReq); 1157 break; 1158 } 1159 1160 case WM_DRVHOSTAUDIOWAS_PURGE_CACHE: 1161 { 1162 AssertMsgBreak(Msg.wParam == pThis->uWorkerThreadFixedParam, ("%p\n", Msg.wParam)); 1163 AssertBreak(Msg.hwnd == NULL); 1164 AssertBreak(Msg.lParam == 0); 1165 1166 drvHostAudioWasCachePurge(pThis); 1167 break; 1168 } 1169 1170 default: 1171 break; 1172 } 1173 DispatchMessageW(&Msg); 1174 } 914 1175 else 915 { 916 LogFunc(("Unknown rIID={%RTuuid}\n", &rIID)); 917 *ppvInterface = NULL; 918 return E_NOINTERFACE; 919 } 920 Log6Func(("returns S_OK + %p\n", *ppvInterface)); 921 return S_OK; 922 } 923 /** @} */ 924 925 /** @name IMMNotificationClient interface 926 * @{ */ 927 IFACEMETHODIMP OnDeviceStateChanged(LPCWSTR pwszDeviceId, DWORD dwNewState) 928 { 929 RT_NOREF(pwszDeviceId, dwNewState); 930 Log7Func(("pwszDeviceId=%ls dwNewState=%u (%#x)\n", pwszDeviceId, dwNewState, dwNewState)); 931 return S_OK; 932 } 933 934 IFACEMETHODIMP OnDeviceAdded(LPCWSTR pwszDeviceId) 935 { 936 RT_NOREF(pwszDeviceId); 937 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 } 968 return S_OK; 969 } 970 971 IFACEMETHODIMP OnDeviceRemoved(LPCWSTR pwszDeviceId) 972 { 973 RT_NOREF(pwszDeviceId); 974 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); 986 return S_OK; 987 } 988 989 IFACEMETHODIMP OnDefaultDeviceChanged(EDataFlow enmFlow, ERole enmRole, LPCWSTR pwszDefaultDeviceId) 990 { 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 1020 RT_NOREF(enmFlow, enmRole, pwszDefaultDeviceId); 1021 Log7Func(("enmFlow=%d enmRole=%d pwszDefaultDeviceId=%ls\n", enmFlow, enmRole, pwszDefaultDeviceId)); 1022 return S_OK; 1023 } 1024 1025 IFACEMETHODIMP OnPropertyValueChanged(LPCWSTR pwszDeviceId, const PROPERTYKEY Key) 1026 { 1027 RT_NOREF(pwszDeviceId, Key); 1028 Log7Func(("pwszDeviceId=%ls Key={%RTuuid, %u (%#x)}\n", pwszDeviceId, &Key.fmtid, Key.pid, Key.pid)); 1029 return S_OK; 1030 } 1031 /** @} */ 1032 1033 private: 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 } 1067 }; 1176 AssertMsgFailed(("GetLastError()=%u\n", GetLastError())); 1177 } 1178 1179 LogFlowFunc(("Pre-quit cache purge...\n")); 1180 drvHostAudioWasCachePurge(pThis); 1181 1182 LogFunc(("Quits\n")); 1183 return VINF_SUCCESS; 1184 } 1068 1185 1069 1186 … … 1289 1406 LogFlowFunc(("pCfg=%p\n", pCfg)); 1290 1407 1291 /* 1292 * Get the device. 1293 */ 1294 pThis->pNotifyClient->lockEnter(); 1295 IMMDevice *pIDevice = pCfg->enmDir == PDMAUDIODIR_IN ? pThis->pIDeviceInput : pThis->pIDeviceOutput; 1296 if (pIDevice) 1297 pIDevice->AddRef(); 1298 pThis->pNotifyClient->lockLeave(); 1299 if (pIDevice) 1300 { 1301 /* 1302 * Look up the config and put it back. 1303 */ 1304 PDRVHOSTAUDIOWASCACHEDEVCFG pDevCfg = drvHostAudioWasCacheLookupOrCreate(pThis, pIDevice, pCfg); 1305 LogFlowFunc(("pDevCfg=%p\n")); 1306 if (pDevCfg) 1307 drvHostAudioWasCachePutBack(pThis, pDevCfg); 1308 pIDevice->Release(); 1309 } 1408 if (pThis->hWorkerThread != NIL_RTTHREAD) 1409 { 1410 PPDMAUDIOSTREAMCFG pCfgCopy = PDMAudioStrmCfgDup(pCfg); 1411 if (pCfgCopy) 1412 { 1413 if (PostThreadMessageW(pThis->idWorkerThread, WM_DRVHOSTAUDIOWAS_HINT, 1414 pThis->uWorkerThreadFixedParam, (LPARAM)pCfgCopy)) 1415 LogFlowFunc(("Posted %p to worker thread\n", pCfgCopy)); 1416 else 1417 { 1418 LogRelMax(64, ("WasAPI: PostThreadMessageW failed: %u\n", GetLastError())); 1419 PDMAudioStrmCfgFree(pCfgCopy); 1420 } 1421 } 1422 } 1423 else 1424 drvHostWasCacheConfigHinting(pThis, pCfg); 1310 1425 } 1311 1426 … … 2297 2412 * @callback_method_impl{FNPDMDRVDESTRUCT, pfnDestruct} 2298 2413 */ 2414 static DECLCALLBACK(void) drvHostAudioWasPowerOff(PPDMDRVINS pDrvIns) 2415 { 2416 PDRVHOSTAUDIOWAS pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTAUDIOWAS); 2417 2418 if (pThis->hWorkerThread != NIL_RTTHREAD) 2419 { 2420 BOOL fRc = PostThreadMessageW(pThis->idWorkerThread, WM_DRVHOSTAUDIOWAS_PURGE_CACHE, pThis->uWorkerThreadFixedParam, 0); 2421 LogFlowFunc(("Posted WM_DRVHOSTAUDIOWAS_PURGE_CACHE: %d\n", fRc)); 2422 Assert(fRc); RT_NOREF(fRc); 2423 } 2424 } 2425 2426 2427 /** 2428 * @callback_method_impl{FNPDMDRVDESTRUCT, pfnDestruct} 2429 */ 2299 2430 static DECLCALLBACK(void) drvHostAudioWasDestruct(PPDMDRVINS pDrvIns) 2300 2431 { … … 2310 2441 } 2311 2442 2443 if (pThis->hWorkerThread != NIL_RTTHREAD) 2444 { 2445 BOOL fRc = PostThreadMessageW(pThis->idWorkerThread, WM_QUIT, 0, 0); 2446 Assert(fRc); RT_NOREF(fRc); 2447 2448 int rc = RTThreadWait(pThis->hWorkerThread, RT_MS_15SEC, NULL); 2449 AssertRC(rc); 2450 } 2451 2312 2452 if (RTCritSectIsInitialized(&pThis->CritSectCache)) 2313 2453 { … … 2333 2473 pThis->pIDeviceInput = NULL; 2334 2474 } 2475 2335 2476 2336 2477 if (RTCritSectRwIsInitialized(&pThis->CritSectStreamList)) … … 2355 2496 pThis->pDrvIns = pDrvIns; 2356 2497 pThis->hDrainTimer = NIL_TMTIMERHANDLE; 2498 pThis->hWorkerThread = NIL_RTTHREAD; 2499 pThis->idWorkerThread = 0; 2357 2500 RTListInit(&pThis->StreamHead); 2358 2501 RTListInit(&pThis->CacheHead); … … 2384 2527 /** @todo make it possible to override the default device selection. */ 2385 2528 2529 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER, 2530 ("Configuration error: Not possible to attach anything to this driver!\n"), 2531 VERR_PDM_DRVINS_NO_ATTACH); 2532 2386 2533 /* 2387 2534 * Initialize the critical sections early. … … 2494 2641 "WasAPI drain", &pThis->hDrainTimer); 2495 2642 AssertRCReturn(rc, rc); 2643 2644 /* 2645 * Create the worker thread. This thread has a message loop and will be 2646 * signalled by DrvHostAudioWasMmNotifyClient while the VM is paused/whatever, 2647 * so better make it a regular thread rather than PDM thread. 2648 */ 2649 pThis->uWorkerThreadFixedParam = (WPARAM)RTRandU64(); 2650 rc = RTThreadCreateF(&pThis->hWorkerThread, drvHostWasWorkerThread, pThis, 0 /*cbStack*/, RTTHREADTYPE_DEFAULT, 2651 RTTHREADFLAGS_WAITABLE | RTTHREADFLAGS_COM_MTA, "WasWork%u", pDrvIns->iInstance); 2652 AssertRCReturn(rc, rc); 2653 2654 rc = RTThreadUserWait(pThis->hWorkerThread, RT_MS_10SEC); 2655 AssertRC(rc); 2496 2656 2497 2657 /* … … 2548 2708 NULL, 2549 2709 /* pfnPowerOff */ 2550 NULL,2710 drvHostAudioWasPowerOff, 2551 2711 /* pfnSoftReset */ 2552 2712 NULL,
Note:
See TracChangeset
for help on using the changeset viewer.