Changeset 88853 in vbox
- Timestamp:
- May 4, 2021 8:47:13 AM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144187
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvAudio.cpp
r88852 r88853 279 279 /** Shutdown indicator. */ 280 280 bool fTerminate; 281 #ifdef VBOX_WITH_AUDIO_ENUM282 /** Flag indicating that we need to enumerate and log of the host283 * audio devices again. */284 bool fEnumerateDevices;285 #endif286 281 /** Our audio connector interface. */ 287 282 PDMIAUDIOCONNECTOR IAudioConnector; … … 330 325 /** Unique name for the the disable-iteration timer. */ 331 326 char szTimerName[23]; 327 328 #ifdef VBOX_WITH_AUDIO_ENUM 329 /** Handle to the timer for delayed re-enumeration of backend devices. */ 330 TMTIMERHANDLE hEnumTimer; 331 /** Unique name for the the disable-iteration timer. */ 332 char szEnumTimerName[24]; 333 #endif 332 334 333 335 #ifdef VBOX_WITH_STATISTICS … … 464 466 * @remarks This is currently ONLY used for release logging. 465 467 */ 466 static intdrvAudioDevicesEnumerateInternal(PDRVAUDIO pThis, bool fLog, PPDMAUDIOHOSTENUM pDevEnum)468 static DECLCALLBACK(int) drvAudioDevicesEnumerateInternal(PDRVAUDIO pThis, bool fLog, PPDMAUDIOHOSTENUM pDevEnum) 467 469 { 468 470 AssertReturn(!RTCritSectIsOwner(&pThis->CritSect), VERR_WRONG_ORDER); … … 2115 2117 } 2116 2118 2117 #ifdef VBOX_WITH_AUDIO_ENUM2118 /** @todo do this elsewhere. What if stuff changes when there are no open2119 * streams to re-init? */2120 if (pThis->fEnumerateDevices)2121 {2122 /* Make sure to leave the driver's critical section before enumerating host stuff. */2123 int rc2 = RTCritSectLeave(&pThis->CritSect);2124 AssertRC(rc2);2125 2126 /* Re-enumerate all host devices. */2127 drvAudioDevicesEnumerateInternal(pThis, true /* fLog */, NULL /* pDevEnum */);2128 2129 /* Re-enter the critical section again. */2130 rc2 = RTCritSectEnter(&pThis->CritSect);2131 AssertRC(rc2);2132 2133 pThis->fEnumerateDevices = false;2134 }2135 #endif /* VBOX_WITH_AUDIO_ENUM */2136 2137 2119 RTCritSectLeave(&pThis->CritSect); 2138 2120 … … 3996 3978 3997 3979 3980 #ifdef VBOX_WITH_AUDIO_ENUM 3981 /** 3982 * @callback_method_impl{FNTMTIMERDRV, Re-enumerate backend devices.} 3983 * 3984 * Used to do/trigger re-enumeration of backend devices with a delay after we 3985 * got notification as there can be further notifications following shortly 3986 * after the first one. Also good to get it of random COM/whatever threads. 3987 */ 3988 static DECLCALLBACK(void) drvAudioEnumerateTimer(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, void *pvUser) 3989 { 3990 PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO); 3991 RT_NOREF(hTimer, pvUser); 3992 3993 /* Try push the work over to the thread-pool if we've got one. */ 3994 if (pThis->hReqPool != NIL_RTREQPOOL) 3995 { 3996 int rc = RTReqPoolCallEx(pThis->hReqPool, 0 /*cMillies*/, NULL, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, 3997 (PFNRT)drvAudioDevicesEnumerateInternal, 3998 3, pThis, true /*fLog*/, (PPDMAUDIOHOSTENUM)NULL /*pDevEnum*/); 3999 LogFunc(("RTReqPoolCallEx: %Rrc\n", rc)); 4000 if (RT_SUCCESS(rc)) 4001 return; 4002 } 4003 LogFunc(("Calling drvAudioDevicesEnumerateInternal...\n")); 4004 drvAudioDevicesEnumerateInternal(pThis, true /* fLog */, NULL /* pDevEnum */); 4005 } 4006 #endif /* VBOX_WITH_AUDIO_ENUM */ 4007 4008 3998 4009 /** 3999 4010 * @interface_method_impl{PDMIHOSTAUDIOPORT,pfnNotifyDevicesChanged} … … 4004 4015 LogRel(("Audio: Device configuration of driver '%s' has changed\n", pThis->szName)); 4005 4016 4006 /** @todo Remove legacy behaviour: */ 4007 if (!pThis->pHostDrvAudio->pfnStreamNotifyDeviceChanged) 4008 { 4017 #ifdef RT_OS_DARWIN /** @todo Remove legacy behaviour: */ 4009 4018 /** @todo r=bird: Locking? */ 4010 /* Mark all host streams to re-initialize. */ 4011 PDRVAUDIOSTREAM pStreamEx; 4012 RTListForEach(&pThis->lstStreams, pStreamEx, DRVAUDIOSTREAM, ListEntry) 4013 { 4014 drvAudioStreamMarkNeedReInit(pStreamEx, __PRETTY_FUNCTION__); 4015 } 4016 } 4017 4018 # ifdef VBOX_WITH_AUDIO_ENUM 4019 /* Re-enumerate all host devices as soon as possible. */ 4020 pThis->fEnumerateDevices = true; 4021 # endif 4019 /* Mark all host streams to re-initialize. */ 4020 PDRVAUDIOSTREAM pStreamEx; 4021 RTListForEach(&pThis->lstStreams, pStreamEx, DRVAUDIOSTREAM, ListEntry) 4022 { 4023 drvAudioStreamMarkNeedReInit(pStreamEx, __PRETTY_FUNCTION__); 4024 } 4025 #endif 4026 4027 #ifdef VBOX_WITH_AUDIO_ENUM 4028 /* 4029 * Re-enumerate all host devices with a tiny delay to avoid re-doing this 4030 * when a bunch of changes happens at once (they typically do on windows). 4031 * We'll keep postponing it till it quiesces for a fraction of a second. 4032 */ 4033 int rc = PDMDrvHlpTimerSetMillies(pThis->pDrvIns, pThis->hEnumTimer, RT_MS_1SEC / 3); 4034 AssertRC(rc); 4035 #endif 4022 4036 } 4023 4037 … … 4680 4694 0 /*fFlags*/, pThis->szTimerName, &pThis->hTimer); 4681 4695 AssertRCReturn(rc, rc); 4696 4697 #ifdef VBOX_WITH_AUDIO_ENUM 4698 /* 4699 * Create a timer to trigger delayed device enumeration on device changes. 4700 */ 4701 RTStrPrintf(pThis->szEnumTimerName, sizeof(pThis->szEnumTimerName), "AudioEnum-%u", pDrvIns->iInstance); 4702 rc = PDMDrvHlpTMTimerCreate(pDrvIns, TMCLOCK_REAL, drvAudioEnumerateTimer, NULL /*pvUser*/, 4703 0 /*fFlags*/, pThis->szEnumTimerName, &pThis->hEnumTimer); 4704 AssertRCReturn(rc, rc); 4705 #endif 4682 4706 4683 4707 /* -
trunk/src/VBox/Devices/Audio/DrvHostAudioDSound.cpp
r88819 r88853 2811 2811 try 2812 2812 { 2813 pThis->m_pNotificationClient = new DrvHostAudioDSoundMMNotifClient(pIHostAudioPort); 2813 pThis->m_pNotificationClient = new DrvHostAudioDSoundMMNotifClient(pIHostAudioPort, 2814 pThis->Cfg.pGuidCapture == NULL, 2815 pThis->Cfg.pGuidPlay == NULL); 2814 2816 } 2815 2817 catch (std::bad_alloc &) -
trunk/src/VBox/Devices/Audio/DrvHostAudioDSoundMMNotifClient.cpp
r88819 r88853 30 30 31 31 32 DrvHostAudioDSoundMMNotifClient::DrvHostAudioDSoundMMNotifClient(PPDMIHOSTAUDIOPORT pInterface) 33 : m_fRegisteredClient(false) 32 DrvHostAudioDSoundMMNotifClient::DrvHostAudioDSoundMMNotifClient(PPDMIHOSTAUDIOPORT pInterface, bool fDefaultIn, bool fDefaultOut) 33 : m_fDefaultIn(fDefaultIn) 34 , m_fDefaultOut(fDefaultOut) 35 , m_fRegisteredClient(false) 34 36 , m_cRef(1) 35 37 , m_pIAudioNotifyFromHost(pInterface) … … 48 50 HRESULT hr = m_pEnum->RegisterEndpointNotificationCallback(this); 49 51 if (SUCCEEDED(hr)) 50 {51 52 m_fRegisteredClient = true; 52 53 53 hr = AttachToDefaultEndpoint();54 }55 56 54 return hr; 57 55 } … … 62 60 void DrvHostAudioDSoundMMNotifClient::Unregister(void) 63 61 { 64 DetachFromEndpoint();65 66 62 if (m_fRegisteredClient) 67 63 { … … 87 83 88 84 /** 89 * Stub being called when attaching to the default audio endpoint. 90 * Does nothing at the moment. 91 */ 92 HRESULT DrvHostAudioDSoundMMNotifClient::AttachToDefaultEndpoint(void) 93 { 94 return S_OK; 95 } 96 97 /** 98 * Stub being called when detaching from the default audio endpoint. 99 * Does nothing at the moment. 100 */ 101 void DrvHostAudioDSoundMMNotifClient::DetachFromEndpoint(void) 102 { 103 104 } 105 106 /** 107 * Helper function for invoking the audio connector callback (if any). 108 */ 109 void DrvHostAudioDSoundMMNotifClient::doCallback(void) 110 { 85 * Handler implementation which is called when an audio device state 86 * has been changed. 87 * 88 * @return HRESULT 89 * @param pwstrDeviceId Device ID the state is announced for. 90 * @param dwNewState New state the device is now in. 91 */ 92 STDMETHODIMP DrvHostAudioDSoundMMNotifClient::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) 93 { 94 char *pszState = "unknown"; 95 96 switch (dwNewState) 97 { 98 case DEVICE_STATE_ACTIVE: 99 pszState = "active"; 100 break; 101 case DEVICE_STATE_DISABLED: 102 pszState = "disabled"; 103 break; 104 case DEVICE_STATE_NOTPRESENT: 105 pszState = "not present"; 106 break; 107 case DEVICE_STATE_UNPLUGGED: 108 pszState = "unplugged"; 109 break; 110 default: 111 break; 112 } 113 114 LogRel(("Audio: Device '%ls' has changed state to '%s'\n", pwstrDeviceId, pszState)); 115 111 116 if (m_pIAudioNotifyFromHost) 112 117 m_pIAudioNotifyFromHost->pfnNotifyDevicesChanged(m_pIAudioNotifyFromHost); 113 }114 115 /**116 * Handler implementation which is called when an audio device state117 * has been changed.118 *119 * @return HRESULT120 * @param pwstrDeviceId Device ID the state is announced for.121 * @param dwNewState New state the device is now in.122 */123 STDMETHODIMP DrvHostAudioDSoundMMNotifClient::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState)124 {125 char *pszState = "unknown";126 127 switch (dwNewState)128 {129 case DEVICE_STATE_ACTIVE:130 pszState = "active";131 break;132 case DEVICE_STATE_DISABLED:133 pszState = "disabled";134 break;135 case DEVICE_STATE_NOTPRESENT:136 pszState = "not present";137 break;138 case DEVICE_STATE_UNPLUGGED:139 pszState = "unplugged";140 break;141 default:142 break;143 }144 145 LogRel(("Audio: Device '%ls' has changed state to '%s'\n", pwstrDeviceId, pszState));146 147 doCallback();148 118 149 119 return S_OK; … … 159 129 { 160 130 LogRel(("Audio: Device '%ls' has been added\n", pwstrDeviceId)); 161 131 /* Note! It is hard to properly support non-default devices when the backend is DSound, 132 as DSound talks GUID where-as the pwszDeviceId string we get here is something 133 completely different. So, ignorining that edge case here. The WasApi backend 134 supports this, though. */ 135 if (m_pIAudioNotifyFromHost) 136 m_pIAudioNotifyFromHost->pfnNotifyDevicesChanged(m_pIAudioNotifyFromHost); 162 137 return S_OK; 163 138 } … … 172 147 { 173 148 LogRel(("Audio: Device '%ls' has been removed\n", pwstrDeviceId)); 174 149 if (m_pIAudioNotifyFromHost) 150 m_pIAudioNotifyFromHost->pfnNotifyDevicesChanged(m_pIAudioNotifyFromHost); 175 151 return S_OK; 176 152 } … … 187 163 STDMETHODIMP DrvHostAudioDSoundMMNotifClient::OnDefaultDeviceChanged(EDataFlow eFlow, ERole eRole, LPCWSTR pwstrDefaultDeviceId) 188 164 { 189 RT_NOREF(eRole); 190 191 char *pszRole = "unknown"; 192 193 if (eFlow == eRender) 194 pszRole = "output"; 195 else if (eFlow == eCapture) 196 pszRole = "input"; 197 198 LogRel(("Audio: Default %s device has been changed to '%ls'\n", pszRole, pwstrDefaultDeviceId)); 199 200 doCallback(); 201 165 /* When the user triggers a default device change, we'll typically get two or 166 three notifications. Just pick up the one for the multimedia role for now 167 (dunno if DSound default equals eMultimedia or eConsole, and whether it make 168 any actual difference). */ 169 if (eRole == eMultimedia) 170 { 171 PDMAUDIODIR enmDir = PDMAUDIODIR_INVALID; 172 char *pszRole = "unknown"; 173 if (eFlow == eRender) 174 { 175 pszRole = "output"; 176 if (m_fDefaultOut) 177 enmDir = PDMAUDIODIR_OUT; 178 } 179 else if (eFlow == eCapture) 180 { 181 pszRole = "input"; 182 if (m_fDefaultIn) 183 enmDir = PDMAUDIODIR_IN; 184 } 185 186 LogRel(("Audio: Default %s device has been changed to '%ls'\n", pszRole, pwstrDefaultDeviceId)); 187 188 if (m_pIAudioNotifyFromHost) 189 { 190 if (enmDir != PDMAUDIODIR_INVALID) 191 m_pIAudioNotifyFromHost->pfnNotifyDeviceChanged(m_pIAudioNotifyFromHost, enmDir, NULL); 192 m_pIAudioNotifyFromHost->pfnNotifyDevicesChanged(m_pIAudioNotifyFromHost); 193 } 194 } 202 195 return S_OK; 203 196 } -
trunk/src/VBox/Devices/Audio/DrvHostAudioDSoundMMNotifClient.h
r88819 r88853 43 43 public: 44 44 45 DrvHostAudioDSoundMMNotifClient(PPDMIHOSTAUDIOPORT pInterface );45 DrvHostAudioDSoundMMNotifClient(PPDMIHOSTAUDIOPORT pInterface, bool fDefaultIn, bool fDefaultOut); 46 46 virtual ~DrvHostAudioDSoundMMNotifClient(); 47 47 … … 58 58 private: 59 59 60 bool m_fDefaultIn; 61 bool m_fDefaultOut; 60 62 bool m_fRegisteredClient; 61 63 IMMDeviceEnumerator *m_pEnum; … … 64 66 long m_cRef; 65 67 66 PPDMIHOSTAUDIOPORT m_pIAudioNotifyFromHost; 67 68 HRESULT AttachToDefaultEndpoint(); 69 void DetachFromEndpoint(); 70 71 void doCallback(void); 68 PPDMIHOSTAUDIOPORT m_pIAudioNotifyFromHost; 72 69 73 70 /** @name IMMNotificationClient interface -
trunk/src/VBox/Devices/Audio/DrvHostAudioWasApi.cpp
r88851 r88853 415 415 RT_NOREF(pwszDeviceId, dwNewState); 416 416 Log7Func(("pwszDeviceId=%ls dwNewState=%u (%#x)\n", pwszDeviceId, dwNewState, dwNewState)); 417 418 /* 419 * Just trigger device re-enumeration. 420 */ 421 notifyDeviceChanges(); 422 423 /** @todo do we need to check for our devices here too? Not when using a 424 * default device. But when using a specific device, we could perhaps 425 * re-init the stream when dwNewState indicates precense. We might 426 * also take action when a devices ceases to be operating, but again 427 * only for non-default devices, probably... */ 428 417 429 return S_OK; 418 430 } … … 451 463 fOutput ? "output" : "input", pwszDeviceId, hrc)); 452 464 pIEnumerator->Release(); 465 466 /* 467 * Trigger device re-enumeration. 468 */ 469 notifyDeviceChanges(); 453 470 } 454 471 return S_OK; … … 468 485 && ( (fOutput = RTUtf16ICmp(m_pDrvWas->pwszOutputDevId, pwszDeviceId) == 0) 469 486 || RTUtf16ICmp(m_pDrvWas->pwszInputDevId, pwszDeviceId) == 0)) 487 { 488 RTCritSectLeave(&m_CritSect); 470 489 setDevice(fOutput, NULL, pwszDeviceId, __PRETTY_FUNCTION__); 471 RTCritSectLeave(&m_CritSect); 490 } 491 else 492 RTCritSectLeave(&m_CritSect); 493 494 /* 495 * Trigger device re-enumeration. 496 */ 497 notifyDeviceChanges(); 472 498 return S_OK; 473 499 } … … 502 528 enmFlow == eRender ? "output" : "input", hrc)); 503 529 pIEnumerator->Release(); 504 } 505 506 RT_NOREF(enmFlow, enmRole, pwszDefaultDeviceId); 530 531 /* 532 * Trigger device re-enumeration. 533 */ 534 notifyDeviceChanges(); 535 } 536 507 537 Log7Func(("enmFlow=%d enmRole=%d pwszDefaultDeviceId=%ls\n", enmFlow, enmRole, pwszDefaultDeviceId)); 508 538 return S_OK; … … 577 607 } 578 608 609 RTCritSectLeave(&m_CritSect); 610 } 611 612 /** 613 * Tell DrvAudio to re-enumerate devices when it get a chance. 614 * 615 * We exit the critsect here too before calling DrvAudio just to be on the safe 616 * side (see setDevice()), even though the current DrvAudio code doesn't take 617 * any critsects. 618 */ 619 void notifyDeviceChanges(void) 620 { 621 RTCritSectEnter(&m_CritSect); 622 if (m_pDrvWas) 623 { 624 PPDMIHOSTAUDIOPORT const pIHostAudioPort = m_pDrvWas->pIHostAudioPort; 625 if (pIHostAudioPort) 626 { 627 VMSTATE const enmVmState = PDMDrvHlpVMState(m_pDrvWas->pDrvIns); 628 if (enmVmState < VMSTATE_POWERING_OFF) 629 { 630 RTCritSectLeave(&m_CritSect); 631 pIHostAudioPort->pfnNotifyDevicesChanged(pIHostAudioPort); 632 return; 633 } 634 LogFlowFunc(("Ignoring change: enmVmState=%d\n", enmVmState)); 635 } 636 } 579 637 RTCritSectLeave(&m_CritSect); 580 638 } … … 2575 2633 } 2576 2634 #endif 2635 2636 /* 2637 * Deregister the notification client to reduce the risk of notifications 2638 * comming in while we're being detatched or the VM is being destroyed. 2639 */ 2640 if (pThis->pNotifyClient) 2641 { 2642 pThis->pNotifyClient->notifyDriverDestroyed(); 2643 pThis->pIEnumerator->UnregisterEndpointNotificationCallback(pThis->pNotifyClient); 2644 pThis->pNotifyClient->Release(); 2645 pThis->pNotifyClient = NULL; 2646 } 2577 2647 } 2578 2648 … … 2592 2662 pThis->pIEnumerator->UnregisterEndpointNotificationCallback(pThis->pNotifyClient); 2593 2663 pThis->pNotifyClient->Release(); 2664 pThis->pNotifyClient = NULL; 2594 2665 } 2595 2666
Note:
See TracChangeset
for help on using the changeset viewer.