Skip to content

Commit db8af79

Browse files
committed
feat: add audio device changes detect for windows. (#41)
* feat: add audio device changes detect for windows. * Update audio_device_core_win.cc
1 parent 34180ad commit db8af79

File tree

7 files changed

+117
-0
lines changed

7 files changed

+117
-0
lines changed

modules/audio_device/audio_device_generic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ class AudioDeviceGeneric {
135135
virtual int GetRecordAudioParameters(AudioParameters* params) const;
136136
#endif // WEBRTC_IOS
137137

138+
virtual int32_t SetAudioDeviceSink(AudioDeviceSink* sink) = 0;
139+
138140
virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) = 0;
139141

140142
virtual ~AudioDeviceGeneric() {}

modules/audio_device/dummy/audio_device_dummy.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,9 @@ int32_t AudioDeviceDummy::PlayoutDelay(uint16_t& delayMS) const {
222222
return -1;
223223
}
224224

225+
int32_t AudioDeviceDummy::SetAudioDeviceSink(AudioDeviceSink* sink) {
226+
return -1;
227+
}
228+
225229
void AudioDeviceDummy::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {}
226230
} // namespace webrtc

modules/audio_device/dummy/audio_device_dummy.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,10 @@ class AudioDeviceDummy : public AudioDeviceGeneric {
109109
// Delay information and control
110110
int32_t PlayoutDelay(uint16_t& delayMS) const override;
111111

112+
int32_t SetAudioDeviceSink(AudioDeviceSink* sink) override;
113+
112114
void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;
115+
113116
};
114117

115118
} // namespace webrtc

modules/audio_device/dummy/file_audio_device.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,10 @@ int32_t FileAudioDevice::PlayoutDelay(uint16_t& delayMS) const {
427427
return 0;
428428
}
429429

430+
int32_t FileAudioDevice::SetAudioDeviceSink(AudioDeviceSink* sink) {
431+
return -1;
432+
}
433+
430434
void FileAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
431435
MutexLock lock(&mutex_);
432436

modules/audio_device/dummy/file_audio_device.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ class FileAudioDevice : public AudioDeviceGeneric {
123123
// Delay information and control
124124
int32_t PlayoutDelay(uint16_t& delayMS) const override;
125125

126+
int32_t SetAudioDeviceSink(AudioDeviceSink* sink) override;
127+
126128
void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;
127129

128130
private:

modules/audio_device/win/audio_device_core_win.cc

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,8 @@ AudioDeviceWindowsCore::AudioDeviceWindowsCore()
462462
_playChannelsPrioList[0] = 2; // stereo is prio 1
463463
_playChannelsPrioList[1] = 1; // mono is prio 2
464464

465+
_deviceStateListener = new DeviceStateListener();
466+
465467
HRESULT hr;
466468

467469
// We know that this API will work since it has already been verified in
@@ -475,6 +477,8 @@ AudioDeviceWindowsCore::AudioDeviceWindowsCore()
475477
reinterpret_cast<void**>(&_ptrEnumerator));
476478
RTC_DCHECK(_ptrEnumerator);
477479

480+
_ptrEnumerator->RegisterEndpointNotificationCallback(_deviceStateListener);
481+
478482
// DMO initialization for built-in WASAPI AEC.
479483
{
480484
IMediaObject* ptrDMO = NULL;
@@ -500,6 +504,8 @@ AudioDeviceWindowsCore::~AudioDeviceWindowsCore() {
500504

501505
Terminate();
502506

507+
_ptrEnumerator->UnregisterEndpointNotificationCallback(_deviceStateListener);
508+
503509
// The IMMDeviceEnumerator is created during construction. Must release
504510
// it here and not in Terminate() since we don't recreate it in Init().
505511
SAFE_RELEASE(_ptrEnumerator);
@@ -536,6 +542,11 @@ AudioDeviceWindowsCore::~AudioDeviceWindowsCore() {
536542
_hShutdownCaptureEvent = NULL;
537543
}
538544

545+
if(NULL != _deviceStateListener) {
546+
delete _deviceStateListener;
547+
_deviceStateListener = NULL;
548+
}
549+
539550
if (_avrtLibrary) {
540551
BOOL freeOK = FreeLibrary(_avrtLibrary);
541552
if (!freeOK) {
@@ -3894,6 +3905,65 @@ int32_t AudioDeviceWindowsCore::_GetDeviceID(IMMDevice* pDevice,
38943905
return 0;
38953906
}
38963907

3908+
int32_t AudioDeviceWindowsCore::SetAudioDeviceSink(AudioDeviceSink* sink) {
3909+
_deviceStateListener->SetAudioDeviceSink(sink);
3910+
return 0;
3911+
}
3912+
3913+
void AudioDeviceWindowsCore::DeviceStateListener::SetAudioDeviceSink(AudioDeviceSink *sink) {
3914+
callback_ = sink;
3915+
}
3916+
3917+
HRESULT AudioDeviceWindowsCore::DeviceStateListener::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) {
3918+
RTC_DLOG(LS_INFO) << "AudioDeviceWindowsCore::OnDeviceStateChanged => " << pwstrDeviceId << ", NewState => " << dwNewState;
3919+
if(callback_) callback_->OnDevicesUpdated();
3920+
return S_OK;
3921+
}
3922+
3923+
HRESULT AudioDeviceWindowsCore::DeviceStateListener::OnDeviceAdded(LPCWSTR pwstrDeviceId) {
3924+
RTC_DLOG(LS_INFO) << "AudioDeviceWindowsCore::OnDeviceAdded => " << pwstrDeviceId;
3925+
return S_OK;
3926+
}
3927+
3928+
HRESULT AudioDeviceWindowsCore::DeviceStateListener::OnDeviceRemoved(LPCWSTR pwstrDeviceId) {
3929+
RTC_DLOG(LS_INFO) << "AudioDeviceWindowsCore::OnDeviceRemoved => " << pwstrDeviceId;
3930+
return S_OK;
3931+
}
3932+
3933+
HRESULT AudioDeviceWindowsCore::DeviceStateListener::OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) {
3934+
RTC_DLOG(LS_INFO) << "AudioDeviceWindowsCore::OnDefaultDeviceChanged => " << pwstrDefaultDeviceId;
3935+
return S_OK;
3936+
}
3937+
3938+
HRESULT AudioDeviceWindowsCore::DeviceStateListener::OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) {
3939+
//RTC_DLOG(LS_INFO) << "AudioDeviceWindowsCore::OnPropertyValueChanged => " << pwstrDeviceId;
3940+
return S_OK;
3941+
}
3942+
3943+
ULONG AudioDeviceWindowsCore::DeviceStateListener::AddRef() {
3944+
ULONG new_ref = InterlockedIncrement(&ref_count_);
3945+
// RTC_DLOG(LS_INFO) << "__AddRef => " << new_ref;
3946+
return new_ref;
3947+
}
3948+
3949+
ULONG AudioDeviceWindowsCore::DeviceStateListener::Release() {
3950+
ULONG new_ref = InterlockedDecrement(&ref_count_);
3951+
// RTC_DLOG(LS_INFO) << "__Release => " << new_ref;
3952+
return new_ref;
3953+
}
3954+
3955+
HRESULT AudioDeviceWindowsCore::DeviceStateListener::QueryInterface(REFIID iid, void** object) {
3956+
if (object == nullptr) {
3957+
return E_POINTER;
3958+
}
3959+
if (iid == IID_IUnknown || iid == __uuidof(IMMNotificationClient)) {
3960+
*object = static_cast<IMMNotificationClient*>(this);
3961+
return S_OK;
3962+
}
3963+
*object = nullptr;
3964+
return E_NOINTERFACE;
3965+
}
3966+
38973967
// ----------------------------------------------------------------------------
38983968
// _GetDefaultDevice
38993969
// ----------------------------------------------------------------------------

modules/audio_device/win/audio_device_core_win.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <endpointvolume.h>
2626
#include <mediaobj.h> // IMediaObject
2727
#include <mmdeviceapi.h> // MMDevice
28+
#include <comdef.h>
29+
#include <objbase.h>
2830

2931
#include "api/scoped_refptr.h"
3032
#include "rtc_base/synchronization/mutex.h"
@@ -51,6 +53,33 @@ class AudioDeviceWindowsCore : public AudioDeviceGeneric {
5153
AudioDeviceWindowsCore();
5254
~AudioDeviceWindowsCore();
5355

56+
class DeviceStateListener : public IMMNotificationClient {
57+
public:
58+
virtual ~DeviceStateListener() = default;
59+
HRESULT __stdcall OnDeviceStateChanged(LPCWSTR pwstrDeviceId,
60+
DWORD dwNewState) override;
61+
HRESULT __stdcall OnDeviceAdded(LPCWSTR pwstrDeviceId) override;
62+
63+
HRESULT __stdcall OnDeviceRemoved(LPCWSTR pwstrDeviceId) override;
64+
65+
HRESULT
66+
__stdcall OnDefaultDeviceChanged(EDataFlow flow,
67+
ERole role,
68+
LPCWSTR pwstrDefaultDeviceId) override;
69+
70+
HRESULT __stdcall OnPropertyValueChanged(LPCWSTR pwstrDeviceId,
71+
const PROPERTYKEY key) override;
72+
// IUnknown (required by IMMNotificationClient).
73+
ULONG __stdcall AddRef() override;
74+
ULONG __stdcall Release() override;
75+
HRESULT __stdcall QueryInterface(REFIID iid, void** object) override;
76+
void SetAudioDeviceSink(AudioDeviceSink *sink);
77+
78+
private:
79+
LONG ref_count_ = 1;
80+
AudioDeviceSink *callback_ = nullptr;
81+
};
82+
5483
static bool CoreAudioIsSupported();
5584

5685
// Retrieve the currently utilized audio layer
@@ -151,6 +180,8 @@ class AudioDeviceWindowsCore : public AudioDeviceGeneric {
151180

152181
virtual int32_t EnableBuiltInAEC(bool enable);
153182

183+
virtual int32_t SetAudioDeviceSink(AudioDeviceSink* sink);
184+
154185
public:
155186
virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer);
156187

@@ -238,6 +269,7 @@ class AudioDeviceWindowsCore : public AudioDeviceGeneric {
238269
IAudioEndpointVolume* _ptrCaptureVolume;
239270
ISimpleAudioVolume* _ptrRenderSimpleVolume;
240271

272+
DeviceStateListener *_deviceStateListener = nullptr;
241273
// DirectX Media Object (DMO) for the built-in AEC.
242274
rtc::scoped_refptr<IMediaObject> _dmo;
243275
rtc::scoped_refptr<IMediaBuffer> _mediaBuffer;

0 commit comments

Comments
 (0)