Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(419)

Unified Diff: remoting/host/audio_capturer_win.cc

Issue 2163473002: [Chromoting] Audio playback won't work after switching default playback device (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Resolve review comments Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « remoting/host/audio_capturer_win.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: remoting/host/audio_capturer_win.cc
diff --git a/remoting/host/audio_capturer_win.cc b/remoting/host/audio_capturer_win.cc
index f6ea113160b6662e1e3f31ff5625f3755d6e7497..442aa02e0f48cf539c77508cd7fbaf676d1a64ed 100644
--- a/remoting/host/audio_capturer_win.cc
+++ b/remoting/host/audio_capturer_win.cc
@@ -16,6 +16,7 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
+#include "base/synchronization/lock.h"
namespace {
const int kChannels = 2;
@@ -40,11 +41,65 @@ const int kMaxExpectedTimerLag = 30;
namespace remoting {
+class AudioCapturerWin::MMNotificationClient : public IMMNotificationClient {
+ public:
+ HRESULT __stdcall OnDefaultDeviceChanged(
+ EDataFlow flow,
+ ERole role,
+ LPCWSTR pwstrDefaultDevice) override {
+ base::AutoLock lock(lock_);
+ default_audio_device_changed_ = true;
+ return S_OK;
+ }
+
+ HRESULT __stdcall QueryInterface(REFIID iid, void** object) override {
+ if (iid == IID_IUnknown || iid == __uuidof(IMMNotificationClient)) {
+ *object = static_cast<IMMNotificationClient*>(this);
+ return S_OK;
+ }
+ *object = nullptr;
+ return E_NOINTERFACE;
+ }
+
+ // No Ops overrides.
+ HRESULT __stdcall OnDeviceAdded(LPCWSTR pwstrDeviceId) override {
+ return S_OK;
+ }
+ HRESULT __stdcall OnDeviceRemoved(LPCWSTR pwstrDeviceId) override {
+ return S_OK;
+ }
+ HRESULT __stdcall OnDeviceStateChanged(LPCWSTR pwstrDeviceId,
+ DWORD dwNewState) override {
+ return S_OK;
+ }
+ HRESULT __stdcall OnPropertyValueChanged(LPCWSTR pwstrDeviceId,
+ const PROPERTYKEY key) override {
+ return S_OK;
+ }
+ ULONG __stdcall AddRef() override { return 1; }
+ ULONG __stdcall Release() override { return 1; }
+
+ bool GetAndResetDefaultAudioDeviceChanged() {
+ base::AutoLock lock(lock_);
+ if (default_audio_device_changed_) {
+ default_audio_device_changed_ = false;
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ // |lock_| musted be locked when accessing |default_audio_device_changed_|.
+ bool default_audio_device_changed_ = false;
+ base::Lock lock_;
+};
+
AudioCapturerWin::AudioCapturerWin()
: sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID),
silence_detector_(kSilenceThreshold),
+ mm_notification_client_(new MMNotificationClient()),
last_capture_error_(S_OK) {
- thread_checker_.DetachFromThread();
+ thread_checker_.DetachFromThread();
}
AudioCapturerWin::~AudioCapturerWin() {
@@ -64,22 +119,46 @@ bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) {
callback_ = callback;
- // Initialize the capture timer.
+ if (!ResetAndInitialize()) {
+ return false;
+ }
+
+ // Initialize the capture timer and start capturing. Note, this timer won't
+ // be reset or restarted in ResetAndInitialize() function. Which means we
+ // expect the audio_device_period_ is a system wide configuration, it would
+ // not be changed with the default audio device.
capture_timer_.reset(new base::RepeatingTimer());
+ capture_timer_->Start(FROM_HERE, audio_device_period_, this,
+ &AudioCapturerWin::DoCapture);
+ return true;
+}
- HRESULT hr = S_OK;
+bool AudioCapturerWin::ResetAndInitialize() {
+ wave_format_ex_.Reset(nullptr);
+ mm_device_enumerator_.Release();
+ audio_capture_client_.Release();
+ audio_client_.Release();
+ mm_device_.Release();
+ audio_volume_.Release();
- base::win::ScopedComPtr<IMMDeviceEnumerator> mm_device_enumerator;
- hr = mm_device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator));
+ HRESULT hr = S_OK;
+ hr = mm_device_enumerator_.CreateInstance(__uuidof(MMDeviceEnumerator));
if (FAILED(hr)) {
LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr;
return false;
}
+ hr = mm_device_enumerator_->RegisterEndpointNotificationCallback(
+ mm_notification_client_.get());
+ if (FAILED(hr)) {
+ // We cannot predict which kind of error the API may return, but this is
+ // not a fatal error.
+ LOG(ERROR) << "Failed to register IMMNotificationClient. Error " << hr;
+ }
+
// Get the audio endpoint.
- hr = mm_device_enumerator->GetDefaultAudioEndpoint(eRender,
- eConsole,
- mm_device_.Receive());
+ hr = mm_device_enumerator_->GetDefaultAudioEndpoint(eRender, eConsole,
+ mm_device_.Receive());
if (FAILED(hr)) {
LOG(ERROR) << "Failed to get IMMDevice. Error " << hr;
return false;
@@ -209,14 +288,17 @@ bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) {
silence_detector_.Reset(sampling_rate_, kChannels);
- // Start capturing.
- capture_timer_->Start(FROM_HERE,
- audio_device_period_,
- this,
- &AudioCapturerWin::DoCapture);
return true;
}
+bool AudioCapturerWin::Initialized() const {
Sergey Ulanov 2016/07/22 23:38:05 nit: call it is_initialized()?
Hzj_jie 2016/07/23 00:24:18 Done.
+ return wave_format_ex_.get() &&
+ audio_capture_client_ &&
+ audio_client_ &&
+ mm_device_ &&
+ audio_volume_;
Sergey Ulanov 2016/07/22 23:38:05 The way ResetAndInitialize() is implemented I'm no
Hzj_jie 2016/07/23 00:24:18 Indeed, no, the last statement mm_device->Activate
+}
+
float AudioCapturerWin::GetAudioLevel() {
BOOL mute;
HRESULT hr = audio_volume_->GetMute(&mute);
@@ -284,6 +366,14 @@ void AudioCapturerWin::DoCapture() {
DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_));
DCHECK(thread_checker_.CalledOnValidThread());
+ if (!Initialized() ||
+ mm_notification_client_->GetAndResetDefaultAudioDeviceChanged()) {
+ if (!ResetAndInitialize()) {
+ // Initialization failed, we should wait for next DoCapture call.
+ return;
+ }
+ }
+
// Fetch all packets from the audio capture endpoint buffer.
HRESULT hr = S_OK;
while (true) {
« no previous file with comments | « remoting/host/audio_capturer_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698