1515// along with SynchronousAudioRouter. If not, see <http://www.gnu.org/licenses/>.
1616
1717#include " stdafx.h"
18+ #include " mmwrapper.h"
1819#include " sarclient.h"
1920#include " utility.h"
2021
@@ -35,6 +36,13 @@ void SarClient::tick(long bufferIndex)
3536 ATLASSERT (bufferIndex == 0 || bufferIndex == 1 );
3637 bool hasUpdatedNotificationHandles = false ;
3738
39+ if (_updateSampleRateOnTick.exchange (false )) {
40+ DWORD dummy;
41+
42+ DeviceIoControl (_device, SAR_SEND_FORMAT_CHANGE_EVENT,
43+ nullptr , 0 , nullptr , 0 , &dummy, nullptr );
44+ }
45+
3846 // for each endpoint
3947 // read isActive, generation and buffer offset/size/position
4048 // if offset/size invalid, skip endpoint (fill asio buffers with 0)
@@ -304,6 +312,7 @@ bool SarClient::openMmNotificationClient()
304312 }
305313
306314 _mmNotificationClient->AddRef ();
315+ _mmNotificationClient->setClient (shared_from_this ());
307316
308317 if (FAILED (_mmEnumerator->RegisterEndpointNotificationCallback (
309318 _mmNotificationClient))) {
@@ -522,31 +531,68 @@ HRESULT STDMETHODCALLTYPE SarClient::NotificationClient::OnDeviceStateChanged(
522531 _In_ LPCWSTR pwstrDeviceId,
523532 _In_ DWORD dwNewState)
524533{
525- std::ostringstream os;
534+ // When a SAR endpoint is re-activated after its initial creation, its
535+ // supported sample rate may be different. To force the audio engine to
536+ // notice the possible format change, we listen for device state change
537+ // events and tell the kernel mode driver to broadcast a
538+ // KSEVENT_PINCAPS_FORMATCHANGE event, which causes the audio engine to
539+ // re-query the pin capabilities. This isn't needed for newly added
540+ // endpoints or non-SAR endpoints, so we filter out those events.
541+ if (dwNewState != DEVICE_STATE_ACTIVE) {
542+ return S_OK;
543+ }
544+
545+ do {
546+ if (auto client = _client.lock ()) {
547+ CComPtr<IMMDeviceEnumerator> mmEnumerator;
548+ CComPtr<IMMDevice> device;
549+ CComPtr<IPropertyStore> ps;
550+ PROPVARIANT pvalue = {};
551+
552+ // This seems a bit shady, but MSDN's device events example
553+ // initializes COM the same way. It's not clear what the ownership
554+ // of the thread that delivers the IMMNotificationClient events is.
555+ CoInitialize (NULL );
556+
557+ if (FAILED (CoCreateInstance (
558+ __uuidof (MMDeviceEnumerator), nullptr , CLSCTX_ALL,
559+ __uuidof (IMMDeviceEnumerator), (LPVOID *)&mmEnumerator))) {
560+
561+ break ;
562+ }
563+
564+ if (FAILED (mmEnumerator->GetDevice (pwstrDeviceId, &device))) {
565+ break ;
566+ }
526567
527- os << " OnDeviceStateChanged(" << TCHARToUTF8 (pwstrDeviceId)
528- << " , " << dwNewState << " )" ;
529- OutputDebugStringA (os.str ().c_str ());
568+ if (FAILED (device->OpenPropertyStore (STGM_READ, &ps))) {
569+ break ;
570+ }
571+
572+ if (FAILED (ps->GetValue (
573+ PKEY_SynchronousAudioRouter_EndpointId, &pvalue))) {
574+
575+ break ;
576+ }
577+
578+ client->updateSampleRateOnTick ();
579+ PropVariantClear (&pvalue);
580+ }
581+ } while (false );
582+
583+ CoUninitialize ();
530584 return S_OK;
531585}
532586
533587HRESULT STDMETHODCALLTYPE SarClient::NotificationClient::OnDeviceAdded (
534588 _In_ LPCWSTR pwstrDeviceId)
535589{
536- std::ostringstream os;
537-
538- os << " OnDeviceAdded(" << TCHARToUTF8 (pwstrDeviceId) << " )" ;
539- OutputDebugStringA (os.str ().c_str ());
540590 return S_OK;
541591}
542592
543593HRESULT STDMETHODCALLTYPE SarClient::NotificationClient::OnDeviceRemoved (
544594 _In_ LPCWSTR pwstrDeviceId)
545595{
546- std::ostringstream os;
547-
548- os << " OnDeviceRemoved(" << TCHARToUTF8 (pwstrDeviceId) << " )" ;
549- OutputDebugStringA (os.str ().c_str ());
550596 return S_OK;
551597}
552598
@@ -555,25 +601,13 @@ HRESULT STDMETHODCALLTYPE SarClient::NotificationClient::OnDefaultDeviceChanged(
555601 _In_ ERole role,
556602 _In_ LPCWSTR pwstrDefaultDeviceId)
557603{
558- std::ostringstream os;
559-
560- os << " OnDefaultDeviceChanged(" << flow << " , " << role << " , "
561- << TCHARToUTF8 (pwstrDefaultDeviceId) << " )" ;
562- OutputDebugStringA (os.str ().c_str ());
563604 return S_OK;
564605}
565606
566607HRESULT STDMETHODCALLTYPE SarClient::NotificationClient::OnPropertyValueChanged (
567608 _In_ LPCWSTR pwstrDeviceId,
568609 _In_ const PROPERTYKEY key)
569610{
570- std::ostringstream os;
571- CComBSTR bstr (key.fmtid );
572- std::wstring wstr (bstr);
573-
574- os << " OnPropertyValueChanged(" << TCHARToUTF8 (pwstrDeviceId)
575- << " , " << TCHARToUTF8 (wstr.c_str ()) << " )" ;
576- OutputDebugStringA (os.str ().c_str ());
577611 return S_OK;
578612}
579613
0 commit comments