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

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: 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
« remoting/host/audio_capturer_win.h ('K') | « 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..248b336aad3ce0188631103b8b646681826fd32c 100644
--- a/remoting/host/audio_capturer_win.cc
+++ b/remoting/host/audio_capturer_win.cc
@@ -40,46 +40,106 @@ const int kMaxExpectedTimerLag = 30;
namespace remoting {
+class AudioCapturerWin::MMNotificationClient : public IMMNotificationClient {
Sergey Ulanov 2016/07/18 23:09:24 Do we need this as a separate class? Maybe just im
Hzj_jie 2016/07/19 02:36:39 Then AudioCapturerWin will export a set of unrelat
+ public:
+ MMNotificationClient(AudioCapturerWin* owner);
+
+ 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 {
+ return S_OK; }
Sergey Ulanov 2016/07/18 23:09:24 here and below: formatting
Hzj_jie 2016/07/19 02:36:39 Done.
+ 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; }
+
+ private:
+ AudioCapturerWin* owner_;
+};
+
+AudioCapturerWin::MMNotificationClient::MMNotificationClient(
+ AudioCapturerWin* owner) : owner_(owner) {
+ DCHECK(owner_);
+}
+
+HRESULT AudioCapturerWin::MMNotificationClient::OnDefaultDeviceChanged(
Sergey Ulanov 2016/07/18 23:09:24 Which thread is this called on?
Hzj_jie 2016/07/19 02:36:40 Totally no idea, no document about it on MSDN.
Sergey Ulanov 2016/07/20 17:28:34 According to comments in audio/win/audio_device_li
Hzj_jie 2016/07/20 20:43:14 Assignment of a bool value is atomic, so the worst
Sergey Ulanov 2016/07/21 18:54:01 No types are atomic in C++ by default. You cannot
Hzj_jie 2016/07/21 23:38:50 Done. Emmm, I believe the way I am using here is
+ EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDevice) {
Sergey Ulanov 2016/07/18 23:09:24 One argument per line please git cl format
Hzj_jie 2016/07/19 02:36:40 Done.
+ owner_->default_audio_device_changed_ = true;
+ return S_OK;
+}
+
+HRESULT AudioCapturerWin::MMNotificationClient::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;
+}
+
AudioCapturerWin::AudioCapturerWin()
: sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID),
silence_detector_(kSilenceThreshold),
+ default_audio_device_changed_(false),
+ notificator_(new MMNotificationClient(this)),
Sergey Ulanov 2016/07/18 23:09:24 I don't think that |notificator_| is the right nam
Hzj_jie 2016/07/19 02:36:40 Done.
last_capture_error_(S_OK) {
thread_checker_.DetachFromThread();
}
AudioCapturerWin::~AudioCapturerWin() {
DCHECK(thread_checker_.CalledOnValidThread());
+
+ HRESULT hr = mm_device_enumerator_->UnregisterEndpointNotificationCallback(
+ notificator_.get());
+ if (FAILED(hr)) {
+ LOG(ERROR) << "Failed to unregister notificator. Error " << hr;
+ }
+
if (audio_client_) {
audio_client_->Stop();
}
}
-bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) {
- DCHECK(!audio_capture_client_.get());
- DCHECK(!audio_client_.get());
- DCHECK(!mm_device_.get());
- DCHECK(!audio_volume_.get());
- DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr);
- DCHECK(thread_checker_.CalledOnValidThread());
-
- callback_ = callback;
-
- // Initialize the capture timer.
- capture_timer_.reset(new base::RepeatingTimer());
+bool AudioCapturerWin::Initialize() {
Sergey Ulanov 2016/07/18 23:09:24 Call this ResetAndInitialize() as it doesn't just
Hzj_jie 2016/07/19 02:36:40 Done.
+ default_audio_device_changed_ = false;
+ wave_format_ex_.Reset(nullptr);
+ mm_device_enumerator_.Release();
+ audio_capture_client_.Release();
+ audio_client_.Release();
+ mm_device_.Release();
+ audio_volume_.Release();
HRESULT hr = S_OK;
-
- base::win::ScopedComPtr<IMMDeviceEnumerator> mm_device_enumerator;
- hr = mm_device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator));
+ 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(
Sergey Ulanov 2016/07/18 23:09:24 Do we also need to unregister the callback when ca
Hzj_jie 2016/07/19 02:36:40 Done.
+ notificator_.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 notificator. 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;
@@ -200,7 +260,9 @@ bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) {
// Initialize IAudioEndpointVolume.
// TODO(zijiehe): Do we need to control per process volume?
- hr = mm_device_->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr,
+ hr = mm_device_->Activate(__uuidof(IAudioEndpointVolume),
+ CLSCTX_ALL,
+ nullptr,
audio_volume_.ReceiveVoid());
if (FAILED(hr)) {
LOG(ERROR) << "Failed to get an IAudioEndpointVolume. Error " << hr;
@@ -209,6 +271,26 @@ bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) {
silence_detector_.Reset(sampling_rate_, kChannels);
+ return true;
+}
+
+bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) {
Sergey Ulanov 2016/07/18 23:09:24 Move this before initialize, so the order of metho
Hzj_jie 2016/07/19 02:36:39 Done.
+ DCHECK(!audio_capture_client_.get());
+ DCHECK(!audio_client_.get());
+ DCHECK(!mm_device_.get());
+ DCHECK(!audio_volume_.get());
+ DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr);
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ callback_ = callback;
+
+ // Initialize the capture timer.
+ capture_timer_.reset(new base::RepeatingTimer());
Sergey Ulanov 2016/07/18 23:09:24 nit: move this below, next to the capture_timer_->
Hzj_jie 2016/07/19 02:36:40 Done.
+
+ if (!Initialize()) {
+ return false;
+ }
+
// Start capturing.
capture_timer_->Start(FROM_HERE,
audio_device_period_,
@@ -284,6 +366,11 @@ void AudioCapturerWin::DoCapture() {
DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_));
DCHECK(thread_checker_.CalledOnValidThread());
+ if (default_audio_device_changed_ && !Initialize()) {
+ // 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) {
« remoting/host/audio_capturer_win.h ('K') | « remoting/host/audio_capturer_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698