Commit 00c53fe4 authored by zijiehe's avatar zijiehe Committed by Commit bot

[Chromoting] Move DefaultAudioDeviceChangeDetector out of AudioCapturerWin

This is a trivial change to move IMMNotificationClient implementation out of
AudioCapturerWin. Now the new DefaultAudioDeviceChangeDetector can unregister
itself from IMMDeviceEnumerator in destructor.

BUG=669070

Review-Url: https://codereview.chromium.org/2809293006
Cr-Commit-Position: refs/heads/master@{#466824}
parent dcb37de1
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "remoting/host/win/default_audio_device_change_detector.h"
namespace { namespace {
const int kChannels = 2; const int kChannels = 2;
...@@ -41,72 +42,16 @@ const int kMaxExpectedTimerLag = 30; ...@@ -41,72 +42,16 @@ const int kMaxExpectedTimerLag = 30;
namespace remoting { 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() AudioCapturerWin::AudioCapturerWin()
: sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID),
silence_detector_(kSilenceThreshold), silence_detector_(kSilenceThreshold),
mm_notification_client_(new MMNotificationClient()),
last_capture_error_(S_OK) { last_capture_error_(S_OK) {
thread_checker_.DetachFromThread(); thread_checker_.DetachFromThread();
} }
AudioCapturerWin::~AudioCapturerWin() { AudioCapturerWin::~AudioCapturerWin() {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
if (audio_client_) { Deinitialize();
audio_client_->Stop();
}
} }
bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) {
...@@ -138,8 +83,11 @@ bool AudioCapturerWin::ResetAndInitialize() { ...@@ -138,8 +83,11 @@ bool AudioCapturerWin::ResetAndInitialize() {
void AudioCapturerWin::Deinitialize() { void AudioCapturerWin::Deinitialize() {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
wave_format_ex_.Reset(nullptr); wave_format_ex_.Reset(nullptr);
mm_device_enumerator_.Reset(); default_device_detector_.reset();
audio_capture_client_.Reset(); audio_capture_client_.Reset();
if (audio_client_) {
audio_client_->Stop();
}
audio_client_.Reset(); audio_client_.Reset();
mm_device_.Reset(); mm_device_.Reset();
audio_volume_.Reset(); audio_volume_.Reset();
...@@ -154,23 +102,19 @@ bool AudioCapturerWin::Initialize() { ...@@ -154,23 +102,19 @@ bool AudioCapturerWin::Initialize() {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
HRESULT hr = S_OK; HRESULT hr = S_OK;
hr = mm_device_enumerator_.CreateInstance(__uuidof(MMDeviceEnumerator)); base::win::ScopedComPtr<IMMDeviceEnumerator> mm_device_enumerator;
hr = mm_device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator));
if (FAILED(hr)) { if (FAILED(hr)) {
LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr; LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr;
return false; return false;
} }
hr = mm_device_enumerator_->RegisterEndpointNotificationCallback( default_device_detector_.reset(
mm_notification_client_.get()); new DefaultAudioDeviceChangeDetector(mm_device_enumerator));
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. // Get the audio endpoint.
hr = mm_device_enumerator_->GetDefaultAudioEndpoint(eRender, eConsole, hr = mm_device_enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
mm_device_.Receive()); mm_device_.Receive());
if (FAILED(hr)) { if (FAILED(hr)) {
LOG(ERROR) << "Failed to get IMMDevice. Error " << hr; LOG(ERROR) << "Failed to get IMMDevice. Error " << hr;
return false; return false;
...@@ -375,8 +319,7 @@ void AudioCapturerWin::DoCapture() { ...@@ -375,8 +319,7 @@ void AudioCapturerWin::DoCapture() {
DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_)); DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_));
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
if (!is_initialized() || if (!is_initialized() || default_device_detector_->GetAndReset()) {
mm_notification_client_->GetAndResetDefaultAudioDeviceChanged()) {
if (!ResetAndInitialize()) { if (!ResetAndInitialize()) {
// Initialization failed, we should wait for next DoCapture call. // Initialization failed, we should wait for next DoCapture call.
return; return;
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
namespace remoting { namespace remoting {
class DefaultAudioDeviceChangeDetector;
class AudioCapturerWin : public AudioCapturer { class AudioCapturerWin : public AudioCapturer {
public: public:
AudioCapturerWin(); AudioCapturerWin();
...@@ -31,11 +33,6 @@ class AudioCapturerWin : public AudioCapturer { ...@@ -31,11 +33,6 @@ class AudioCapturerWin : public AudioCapturer {
bool Start(const PacketCapturedCallback& callback) override; bool Start(const PacketCapturedCallback& callback) override;
private: private:
// An IMMNotificationClient implementation to detect the event of default
// audio device recently changed. If it indicates a changed happend recently,
// we need to recreate all audio components.
class MMNotificationClient;
// Executes Deinitialize() and Initialize(). If Initialize() function call // Executes Deinitialize() and Initialize(). If Initialize() function call
// returns false, Deinitialize() will be called again to ensure we will // returns false, Deinitialize() will be called again to ensure we will
// initialize COM components again. // initialize COM components again.
...@@ -79,13 +76,12 @@ class AudioCapturerWin : public AudioCapturer { ...@@ -79,13 +76,12 @@ class AudioCapturerWin : public AudioCapturer {
AudioSilenceDetector silence_detector_; AudioSilenceDetector silence_detector_;
base::win::ScopedCoMem<WAVEFORMATEX> wave_format_ex_; base::win::ScopedCoMem<WAVEFORMATEX> wave_format_ex_;
base::win::ScopedComPtr<IMMDeviceEnumerator> mm_device_enumerator_;
base::win::ScopedComPtr<IAudioCaptureClient> audio_capture_client_; base::win::ScopedComPtr<IAudioCaptureClient> audio_capture_client_;
base::win::ScopedComPtr<IAudioClient> audio_client_; base::win::ScopedComPtr<IAudioClient> audio_client_;
base::win::ScopedComPtr<IMMDevice> mm_device_; base::win::ScopedComPtr<IMMDevice> mm_device_;
base::win::ScopedComPtr<IAudioEndpointVolume> audio_volume_; base::win::ScopedComPtr<IAudioEndpointVolume> audio_volume_;
const std::unique_ptr<MMNotificationClient> mm_notification_client_; std::unique_ptr<DefaultAudioDeviceChangeDetector> default_device_detector_;
HRESULT last_capture_error_; HRESULT last_capture_error_;
......
...@@ -81,6 +81,8 @@ source_set("win") { ...@@ -81,6 +81,8 @@ source_set("win") {
"com_imported_mstscax.tlh", "com_imported_mstscax.tlh",
"com_security.cc", "com_security.cc",
"com_security.h", "com_security.h",
"default_audio_device_change_detector.cc",
"default_audio_device_change_detector.h",
"elevation_helpers.cc", "elevation_helpers.cc",
"elevation_helpers.h", "elevation_helpers.h",
"launch_process_with_token.cc", "launch_process_with_token.cc",
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/win/default_audio_device_change_detector.h"
#include <unknwn.h>
#include "base/logging.h"
namespace remoting {
DefaultAudioDeviceChangeDetector::DefaultAudioDeviceChangeDetector(
const base::win::ScopedComPtr<IMMDeviceEnumerator>& enumerator)
: enumerator_(enumerator) {
DCHECK(enumerator_);
HRESULT hr = enumerator_->RegisterEndpointNotificationCallback(this);
if (FAILED(hr)) {
// We cannot predict which kind of error the API may return, but this is not
// a fatal error.
LOG(WARNING) << "Failed to register IMMNotificationClient, we may not be "
"able to detect the new default audio device. Error "
<< hr;
}
}
DefaultAudioDeviceChangeDetector::~DefaultAudioDeviceChangeDetector() {
enumerator_->UnregisterEndpointNotificationCallback(this);
}
bool DefaultAudioDeviceChangeDetector::GetAndReset() {
bool result = false;
{
base::AutoLock lock(lock_);
result = changed_;
changed_ = false;
}
return result;
}
HRESULT DefaultAudioDeviceChangeDetector::OnDefaultDeviceChanged(
EDataFlow flow,
ERole role,
LPCWSTR pwstrDefaultDevice) {
{
base::AutoLock lock(lock_);
changed_ = true;
}
return S_OK;
}
HRESULT DefaultAudioDeviceChangeDetector::QueryInterface(REFIID iid,
void** object) {
if (iid == IID_IUnknown || iid == __uuidof(IMMNotificationClient)) {
*object = static_cast<IMMNotificationClient*>(this);
return S_OK;
}
*object = nullptr;
return E_NOINTERFACE;
}
HRESULT DefaultAudioDeviceChangeDetector::OnDeviceAdded(LPCWSTR pwstrDeviceId) {
return S_OK;
}
HRESULT DefaultAudioDeviceChangeDetector::OnDeviceRemoved(
LPCWSTR pwstrDeviceId) {
return S_OK;
}
HRESULT DefaultAudioDeviceChangeDetector::OnDeviceStateChanged(
LPCWSTR pwstrDeviceId,
DWORD dwNewState) {
return S_OK;
}
HRESULT DefaultAudioDeviceChangeDetector::OnPropertyValueChanged(
LPCWSTR pwstrDeviceId,
const PROPERTYKEY key) {
return S_OK;
}
ULONG DefaultAudioDeviceChangeDetector::AddRef() { return 1; }
ULONG DefaultAudioDeviceChangeDetector::Release() { return 1; }
} // namespace remoting
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_HOST_WIN_DEFAULT_AUDIO_DEVICE_CHANGE_DETECTOR_H_
#define REMOTING_HOST_WIN_DEFAULT_AUDIO_DEVICE_CHANGE_DETECTOR_H_
#include <mmdeviceapi.h>
#include "base/synchronization/lock.h"
#include "base/win/scoped_comptr.h"
namespace remoting {
// An IMMNotificationClient implementation to detect the change of the default
// audio output device on the system. It registers itself into the input
// IMMDeviceEnumerator in constructor and unregisters in destructor.
// This class does not use the default ref-counting memory management method
// provided by IUnknown: calling DefaultAudioDeviceChangeDetector::Release()
// won't delete the object.
class DefaultAudioDeviceChangeDetector final : public IMMNotificationClient {
public:
explicit DefaultAudioDeviceChangeDetector(
const base::win::ScopedComPtr<IMMDeviceEnumerator>& enumerator);
~DefaultAudioDeviceChangeDetector();
bool GetAndReset();
private:
// IMMNotificationClient implementation.
HRESULT __stdcall OnDefaultDeviceChanged(EDataFlow flow,
ERole role,
LPCWSTR pwstrDefaultDevice) override;
HRESULT __stdcall QueryInterface(REFIID iid, void** object) override;
// No-ops overrides.
HRESULT __stdcall OnDeviceAdded(LPCWSTR pwstrDeviceId) override;
HRESULT __stdcall OnDeviceRemoved(LPCWSTR pwstrDeviceId) override;
HRESULT __stdcall OnDeviceStateChanged(LPCWSTR pwstrDeviceId,
DWORD dwNewState) override;
HRESULT __stdcall OnPropertyValueChanged(LPCWSTR pwstrDeviceId,
const PROPERTYKEY key) override;
ULONG __stdcall AddRef() override;
ULONG __stdcall Release() override;
const base::win::ScopedComPtr<IMMDeviceEnumerator> enumerator_;
bool changed_ = false;
base::Lock lock_;
};
} // namespace remoting
#endif // REMOTING_HOST_WIN_DEFAULT_AUDIO_DEVICE_CHANGE_DETECTOR_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment