Skip to content

Commit

Permalink
feat: add audio device changes detect for windows. (#41)
Browse files Browse the repository at this point in the history
* feat: add audio device changes detect for windows.

* Update audio_device_core_win.cc
  • Loading branch information
cloudwebrtc committed Jun 6, 2023
1 parent c62ce62 commit 335be94
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 0 deletions.
2 changes: 2 additions & 0 deletions modules/audio_device/audio_device_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ class AudioDeviceGeneric {
virtual int GetRecordAudioParameters(AudioParameters* params) const;
#endif // WEBRTC_IOS

virtual int32_t SetAudioDeviceSink(AudioDeviceSink* sink) = 0;

virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) = 0;

virtual ~AudioDeviceGeneric() {}
Expand Down
4 changes: 4 additions & 0 deletions modules/audio_device/dummy/audio_device_dummy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions modules/audio_device/dummy/audio_device_dummy.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions modules/audio_device/dummy/file_audio_device.cc
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,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_);

Expand Down
2 changes: 2 additions & 0 deletions modules/audio_device/dummy/file_audio_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,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:
Expand Down
70 changes: 70 additions & 0 deletions modules/audio_device/win/audio_device_core_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,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
Expand All @@ -474,6 +476,8 @@ AudioDeviceWindowsCore::AudioDeviceWindowsCore()
reinterpret_cast<void**>(&_ptrEnumerator));
RTC_DCHECK(_ptrEnumerator);

_ptrEnumerator->RegisterEndpointNotificationCallback(_deviceStateListener);

// DMO initialization for built-in WASAPI AEC.
{
IMediaObject* ptrDMO = NULL;
Expand All @@ -499,6 +503,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);
Expand Down Expand Up @@ -535,6 +541,11 @@ AudioDeviceWindowsCore::~AudioDeviceWindowsCore() {
_hShutdownCaptureEvent = NULL;
}

if(NULL != _deviceStateListener) {
delete _deviceStateListener;
_deviceStateListener = NULL;
}

if (_avrtLibrary) {
BOOL freeOK = FreeLibrary(_avrtLibrary);
if (!freeOK) {
Expand Down Expand Up @@ -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<IMMNotificationClient*>(this);
return S_OK;
}
*object = nullptr;
return E_NOINTERFACE;
}

// ----------------------------------------------------------------------------
// _GetDefaultDevice
// ----------------------------------------------------------------------------
Expand Down
32 changes: 32 additions & 0 deletions modules/audio_device/win/audio_device_core_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <endpointvolume.h>
#include <mediaobj.h> // IMediaObject
#include <mmdeviceapi.h> // MMDevice
#include <comdef.h>
#include <objbase.h>

#include "api/scoped_refptr.h"
#include "modules/audio_device/audio_device_generic.h"
Expand Down Expand Up @@ -50,6 +52,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
Expand Down Expand Up @@ -150,6 +179,8 @@ class AudioDeviceWindowsCore : public AudioDeviceGeneric {

virtual int32_t EnableBuiltInAEC(bool enable);

virtual int32_t SetAudioDeviceSink(AudioDeviceSink* sink);

public:
virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer);

Expand Down Expand Up @@ -237,6 +268,7 @@ class AudioDeviceWindowsCore : public AudioDeviceGeneric {
IAudioEndpointVolume* _ptrCaptureVolume;
ISimpleAudioVolume* _ptrRenderSimpleVolume;

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

0 comments on commit 335be94

Please sign in to comment.