diff --git a/modules/audio_device/audio_device_generic.cc b/modules/audio_device/audio_device_generic.cc index 0105c6ae24..7b8cfd1734 100644 --- a/modules/audio_device/audio_device_generic.cc +++ b/modules/audio_device/audio_device_generic.cc @@ -63,10 +63,4 @@ int AudioDeviceGeneric::GetRecordAudioParameters( } #endif // WEBRTC_IOS -int32_t AudioDeviceGeneric::SetAudioDeviceSink(AudioDeviceSink* sink) { - RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << sink << ")"; - audio_device_module_sink_ = sink; - return 0; -} - } // namespace webrtc diff --git a/modules/audio_device/audio_device_generic.h b/modules/audio_device/audio_device_generic.h index 635f20f5e0..cf88464f99 100644 --- a/modules/audio_device/audio_device_generic.h +++ b/modules/audio_device/audio_device_generic.h @@ -135,14 +135,11 @@ class AudioDeviceGeneric { virtual int GetRecordAudioParameters(AudioParameters* params) const; #endif // WEBRTC_IOS - int32_t SetAudioDeviceSink(AudioDeviceSink* sink); + virtual int32_t SetAudioDeviceSink(AudioDeviceSink* sink) = 0; virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) = 0; virtual ~AudioDeviceGeneric() {} - - protected: - AudioDeviceSink* audio_device_module_sink_ = nullptr; }; } // namespace webrtc diff --git a/modules/audio_device/dummy/audio_device_dummy.cc b/modules/audio_device/dummy/audio_device_dummy.cc index b8fd837038..59011fa85c 100644 --- a/modules/audio_device/dummy/audio_device_dummy.cc +++ b/modules/audio_device/dummy/audio_device_dummy.cc @@ -222,5 +222,9 @@ int32_t AudioDeviceDummy::PlayoutDelay(uint16_t& delayMS) const { return -1; } +int32_t AudioDeviceDummy::SetAudioDeviceSink(AudioDeviceSink* sink) { + return -1; +} + void AudioDeviceDummy::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {} } // namespace webrtc diff --git a/modules/audio_device/dummy/audio_device_dummy.h b/modules/audio_device/dummy/audio_device_dummy.h index 2a2541098e..7294d73ecc 100644 --- a/modules/audio_device/dummy/audio_device_dummy.h +++ b/modules/audio_device/dummy/audio_device_dummy.h @@ -109,7 +109,10 @@ class AudioDeviceDummy : public AudioDeviceGeneric { // Delay information and control int32_t PlayoutDelay(uint16_t& delayMS) const override; + int32_t SetAudioDeviceSink(AudioDeviceSink* sink) override; + void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override; + }; } // namespace webrtc diff --git a/modules/audio_device/dummy/file_audio_device.cc b/modules/audio_device/dummy/file_audio_device.cc index 0e3caa9d4f..25db6980ed 100644 --- a/modules/audio_device/dummy/file_audio_device.cc +++ b/modules/audio_device/dummy/file_audio_device.cc @@ -426,6 +426,10 @@ int32_t FileAudioDevice::PlayoutDelay(uint16_t& delayMS) const { return 0; } +int32_t FileAudioDevice::SetAudioDeviceSink(AudioDeviceSink* sink) { + return -1; +} + void FileAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) { MutexLock lock(&mutex_); diff --git a/modules/audio_device/dummy/file_audio_device.h b/modules/audio_device/dummy/file_audio_device.h index 4d6858f992..6c1836481b 100644 --- a/modules/audio_device/dummy/file_audio_device.h +++ b/modules/audio_device/dummy/file_audio_device.h @@ -121,6 +121,8 @@ class FileAudioDevice : public AudioDeviceGeneric { // Delay information and control int32_t PlayoutDelay(uint16_t& delayMS) const override; + int32_t SetAudioDeviceSink(AudioDeviceSink* sink) override; + void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override; private: diff --git a/modules/audio_device/win/audio_device_core_win.cc b/modules/audio_device/win/audio_device_core_win.cc index a5f1f1438d..5d5f649591 100644 --- a/modules/audio_device/win/audio_device_core_win.cc +++ b/modules/audio_device/win/audio_device_core_win.cc @@ -462,6 +462,8 @@ AudioDeviceWindowsCore::AudioDeviceWindowsCore() _playChannelsPrioList[0] = 2; // stereo is prio 1 _playChannelsPrioList[1] = 1; // mono is prio 2 + _deviceStateListener = new DeviceStateListener(); + HRESULT hr; // We know that this API will work since it has already been verified in @@ -475,6 +477,8 @@ AudioDeviceWindowsCore::AudioDeviceWindowsCore() reinterpret_cast(&_ptrEnumerator)); RTC_DCHECK(_ptrEnumerator); + _ptrEnumerator->RegisterEndpointNotificationCallback(_deviceStateListener); + // DMO initialization for built-in WASAPI AEC. { IMediaObject* ptrDMO = NULL; @@ -500,6 +504,8 @@ AudioDeviceWindowsCore::~AudioDeviceWindowsCore() { Terminate(); + _ptrEnumerator->UnregisterEndpointNotificationCallback(_deviceStateListener); + // The IMMDeviceEnumerator is created during construction. Must release // it here and not in Terminate() since we don't recreate it in Init(). SAFE_RELEASE(_ptrEnumerator); @@ -536,6 +542,11 @@ AudioDeviceWindowsCore::~AudioDeviceWindowsCore() { _hShutdownCaptureEvent = NULL; } + if(NULL != _deviceStateListener) { + delete _deviceStateListener; + _deviceStateListener = NULL; + } + if (_avrtLibrary) { BOOL freeOK = FreeLibrary(_avrtLibrary); if (!freeOK) { @@ -3894,6 +3905,65 @@ int32_t AudioDeviceWindowsCore::_GetDeviceID(IMMDevice* pDevice, return 0; } +int32_t AudioDeviceWindowsCore::SetAudioDeviceSink(AudioDeviceSink* sink) { + _deviceStateListener->SetAudioDeviceSink(sink); + return 0; +} + +void AudioDeviceWindowsCore::DeviceStateListener::SetAudioDeviceSink(AudioDeviceSink *sink) { + callback_ = sink; +} + +HRESULT AudioDeviceWindowsCore::DeviceStateListener::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) { + RTC_DLOG(LS_INFO) << "AudioDeviceWindowsCore::OnDeviceStateChanged => " << pwstrDeviceId << ", NewState => " << dwNewState; + if(callback_) callback_->OnDevicesUpdated(); + return S_OK; +} + +HRESULT AudioDeviceWindowsCore::DeviceStateListener::OnDeviceAdded(LPCWSTR pwstrDeviceId) { + RTC_DLOG(LS_INFO) << "AudioDeviceWindowsCore::OnDeviceAdded => " << pwstrDeviceId; + return S_OK; +} + +HRESULT AudioDeviceWindowsCore::DeviceStateListener::OnDeviceRemoved(LPCWSTR pwstrDeviceId) { + RTC_DLOG(LS_INFO) << "AudioDeviceWindowsCore::OnDeviceRemoved => " << pwstrDeviceId; + return S_OK; +} + +HRESULT AudioDeviceWindowsCore::DeviceStateListener::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) { + RTC_DLOG(LS_INFO) << "AudioDeviceWindowsCore::OnDefaultDeviceChanged => " << pwstrDefaultDeviceId; + return S_OK; +} + +HRESULT AudioDeviceWindowsCore::DeviceStateListener::OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) { + //RTC_DLOG(LS_INFO) << "AudioDeviceWindowsCore::OnPropertyValueChanged => " << pwstrDeviceId; + return S_OK; +} + +ULONG AudioDeviceWindowsCore::DeviceStateListener::AddRef() { + ULONG new_ref = InterlockedIncrement(&ref_count_); + // RTC_DLOG(LS_INFO) << "__AddRef => " << new_ref; + return new_ref; +} + +ULONG AudioDeviceWindowsCore::DeviceStateListener::Release() { + ULONG new_ref = InterlockedDecrement(&ref_count_); + // RTC_DLOG(LS_INFO) << "__Release => " << new_ref; + return new_ref; +} + +HRESULT AudioDeviceWindowsCore::DeviceStateListener::QueryInterface(REFIID iid, void** object) { + if (object == nullptr) { + return E_POINTER; + } + if (iid == IID_IUnknown || iid == __uuidof(IMMNotificationClient)) { + *object = static_cast(this); + return S_OK; + } + *object = nullptr; + return E_NOINTERFACE; +} + // ---------------------------------------------------------------------------- // _GetDefaultDevice // ---------------------------------------------------------------------------- diff --git a/modules/audio_device/win/audio_device_core_win.h b/modules/audio_device/win/audio_device_core_win.h index 7e7ef21157..5435f9a640 100644 --- a/modules/audio_device/win/audio_device_core_win.h +++ b/modules/audio_device/win/audio_device_core_win.h @@ -25,6 +25,8 @@ #include #include // IMediaObject #include // MMDevice +#include +#include #include "api/scoped_refptr.h" #include "rtc_base/synchronization/mutex.h" @@ -51,6 +53,33 @@ class AudioDeviceWindowsCore : public AudioDeviceGeneric { AudioDeviceWindowsCore(); ~AudioDeviceWindowsCore(); + class DeviceStateListener : public IMMNotificationClient { + public: + virtual ~DeviceStateListener() = default; + HRESULT __stdcall OnDeviceStateChanged(LPCWSTR pwstrDeviceId, + DWORD dwNewState) override; + HRESULT __stdcall OnDeviceAdded(LPCWSTR pwstrDeviceId) override; + + HRESULT __stdcall OnDeviceRemoved(LPCWSTR pwstrDeviceId) override; + + HRESULT + __stdcall OnDefaultDeviceChanged(EDataFlow flow, + ERole role, + LPCWSTR pwstrDefaultDeviceId) override; + + HRESULT __stdcall OnPropertyValueChanged(LPCWSTR pwstrDeviceId, + const PROPERTYKEY key) override; + // IUnknown (required by IMMNotificationClient). + ULONG __stdcall AddRef() override; + ULONG __stdcall Release() override; + HRESULT __stdcall QueryInterface(REFIID iid, void** object) override; + void SetAudioDeviceSink(AudioDeviceSink *sink); + + private: + LONG ref_count_ = 1; + AudioDeviceSink *callback_ = nullptr; + }; + static bool CoreAudioIsSupported(); // Retrieve the currently utilized audio layer @@ -151,6 +180,8 @@ class AudioDeviceWindowsCore : public AudioDeviceGeneric { virtual int32_t EnableBuiltInAEC(bool enable); + virtual int32_t SetAudioDeviceSink(AudioDeviceSink* sink); + public: virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer); @@ -238,6 +269,7 @@ class AudioDeviceWindowsCore : public AudioDeviceGeneric { IAudioEndpointVolume* _ptrCaptureVolume; ISimpleAudioVolume* _ptrRenderSimpleVolume; + DeviceStateListener *_deviceStateListener = nullptr; // DirectX Media Object (DMO) for the built-in AEC. rtc::scoped_refptr _dmo; rtc::scoped_refptr _mediaBuffer;