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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/host/audio_capturer_win.h" 5 #include "remoting/host/audio_capturer_win.h"
6 6
7 #include <avrt.h> 7 #include <avrt.h>
8 #include <mmreg.h> 8 #include <mmreg.h>
9 #include <mmsystem.h> 9 #include <mmsystem.h>
10 #include <stdint.h> 10 #include <stdint.h>
(...skipping 22 matching lines...) Expand all
33 // Lower bound for timer intervals, in milliseconds. 33 // Lower bound for timer intervals, in milliseconds.
34 const int kMinTimerInterval = 30; 34 const int kMinTimerInterval = 30;
35 35
36 // Upper bound for the timer precision error, in milliseconds. 36 // Upper bound for the timer precision error, in milliseconds.
37 // Timers are supposed to be accurate to 20ms, so we use 30ms to be safe. 37 // Timers are supposed to be accurate to 20ms, so we use 30ms to be safe.
38 const int kMaxExpectedTimerLag = 30; 38 const int kMaxExpectedTimerLag = 30;
39 } // namespace 39 } // namespace
40 40
41 namespace remoting { 41 namespace remoting {
42 42
43 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
44 public:
45 MMNotificationClient(AudioCapturerWin* owner);
46
47 HRESULT __stdcall OnDefaultDeviceChanged(EDataFlow flow,
48 ERole role,
49 LPCWSTR pwstrDefaultDevice) override;
50
51 HRESULT __stdcall QueryInterface(REFIID iid, void** object) override;
52
53 // No Ops overrides.
54 HRESULT __stdcall OnDeviceAdded(LPCWSTR pwstrDeviceId) override {
55 return S_OK; }
Sergey Ulanov 2016/07/18 23:09:24 here and below: formatting
Hzj_jie 2016/07/19 02:36:39 Done.
56 HRESULT __stdcall OnDeviceRemoved(LPCWSTR pwstrDeviceId) override {
57 return S_OK; }
58 HRESULT __stdcall OnDeviceStateChanged(LPCWSTR pwstrDeviceId,
59 DWORD dwNewState) override {
60 return S_OK; }
61 HRESULT __stdcall OnPropertyValueChanged(LPCWSTR pwstrDeviceId,
62 const PROPERTYKEY key) override {
63 return S_OK; }
64 ULONG __stdcall AddRef() override { return 1; }
65 ULONG __stdcall Release() override { return 1; }
66
67 private:
68 AudioCapturerWin* owner_;
69 };
70
71 AudioCapturerWin::MMNotificationClient::MMNotificationClient(
72 AudioCapturerWin* owner) : owner_(owner) {
73 DCHECK(owner_);
74 }
75
76 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
77 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.
78 owner_->default_audio_device_changed_ = true;
79 return S_OK;
80 }
81
82 HRESULT AudioCapturerWin::MMNotificationClient::QueryInterface(
83 REFIID iid, void** object) {
84 if (iid == IID_IUnknown || iid == __uuidof(IMMNotificationClient)) {
85 *object = static_cast<IMMNotificationClient*>(this);
86 return S_OK;
87 }
88 *object = nullptr;
89 return E_NOINTERFACE;
90 }
91
43 AudioCapturerWin::AudioCapturerWin() 92 AudioCapturerWin::AudioCapturerWin()
44 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), 93 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID),
45 silence_detector_(kSilenceThreshold), 94 silence_detector_(kSilenceThreshold),
95 default_audio_device_changed_(false),
96 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.
46 last_capture_error_(S_OK) { 97 last_capture_error_(S_OK) {
47 thread_checker_.DetachFromThread(); 98 thread_checker_.DetachFromThread();
48 } 99 }
49 100
50 AudioCapturerWin::~AudioCapturerWin() { 101 AudioCapturerWin::~AudioCapturerWin() {
51 DCHECK(thread_checker_.CalledOnValidThread()); 102 DCHECK(thread_checker_.CalledOnValidThread());
103
104 HRESULT hr = mm_device_enumerator_->UnregisterEndpointNotificationCallback(
105 notificator_.get());
106 if (FAILED(hr)) {
107 LOG(ERROR) << "Failed to unregister notificator. Error " << hr;
108 }
109
52 if (audio_client_) { 110 if (audio_client_) {
53 audio_client_->Stop(); 111 audio_client_->Stop();
54 } 112 }
55 } 113 }
56 114
57 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { 115 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.
58 DCHECK(!audio_capture_client_.get()); 116 default_audio_device_changed_ = false;
59 DCHECK(!audio_client_.get()); 117 wave_format_ex_.Reset(nullptr);
60 DCHECK(!mm_device_.get()); 118 mm_device_enumerator_.Release();
61 DCHECK(!audio_volume_.get()); 119 audio_capture_client_.Release();
62 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); 120 audio_client_.Release();
63 DCHECK(thread_checker_.CalledOnValidThread()); 121 mm_device_.Release();
64 122 audio_volume_.Release();
65 callback_ = callback;
66
67 // Initialize the capture timer.
68 capture_timer_.reset(new base::RepeatingTimer());
69 123
70 HRESULT hr = S_OK; 124 HRESULT hr = S_OK;
71 125 hr = mm_device_enumerator_.CreateInstance(__uuidof(MMDeviceEnumerator));
72 base::win::ScopedComPtr<IMMDeviceEnumerator> mm_device_enumerator;
73 hr = mm_device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator));
74 if (FAILED(hr)) { 126 if (FAILED(hr)) {
75 LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr; 127 LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr;
76 return false; 128 return false;
77 } 129 }
78 130
131 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.
132 notificator_.get());
133 if (FAILED(hr)) {
134 // We cannot predict which kind of error the API may return, but this is
135 // not a fatal error.
136 LOG(ERROR) << "Failed to register notificator. Error " << hr;
137 }
138
79 // Get the audio endpoint. 139 // Get the audio endpoint.
80 hr = mm_device_enumerator->GetDefaultAudioEndpoint(eRender, 140 hr = mm_device_enumerator_->GetDefaultAudioEndpoint(eRender,
81 eConsole, 141 eConsole,
82 mm_device_.Receive()); 142 mm_device_.Receive());
83 if (FAILED(hr)) { 143 if (FAILED(hr)) {
84 LOG(ERROR) << "Failed to get IMMDevice. Error " << hr; 144 LOG(ERROR) << "Failed to get IMMDevice. Error " << hr;
85 return false; 145 return false;
86 } 146 }
87 147
88 // Get an audio client. 148 // Get an audio client.
89 hr = mm_device_->Activate(__uuidof(IAudioClient), 149 hr = mm_device_->Activate(__uuidof(IAudioClient),
90 CLSCTX_ALL, 150 CLSCTX_ALL,
91 nullptr, 151 nullptr,
92 audio_client_.ReceiveVoid()); 152 audio_client_.ReceiveVoid());
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 253
194 // Start the IAudioClient. 254 // Start the IAudioClient.
195 hr = audio_client_->Start(); 255 hr = audio_client_->Start();
196 if (FAILED(hr)) { 256 if (FAILED(hr)) {
197 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; 257 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr;
198 return false; 258 return false;
199 } 259 }
200 260
201 // Initialize IAudioEndpointVolume. 261 // Initialize IAudioEndpointVolume.
202 // TODO(zijiehe): Do we need to control per process volume? 262 // TODO(zijiehe): Do we need to control per process volume?
203 hr = mm_device_->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr, 263 hr = mm_device_->Activate(__uuidof(IAudioEndpointVolume),
264 CLSCTX_ALL,
265 nullptr,
204 audio_volume_.ReceiveVoid()); 266 audio_volume_.ReceiveVoid());
205 if (FAILED(hr)) { 267 if (FAILED(hr)) {
206 LOG(ERROR) << "Failed to get an IAudioEndpointVolume. Error " << hr; 268 LOG(ERROR) << "Failed to get an IAudioEndpointVolume. Error " << hr;
207 return false; 269 return false;
208 } 270 }
209 271
210 silence_detector_.Reset(sampling_rate_, kChannels); 272 silence_detector_.Reset(sampling_rate_, kChannels);
211 273
274 return true;
275 }
276
277 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.
278 DCHECK(!audio_capture_client_.get());
279 DCHECK(!audio_client_.get());
280 DCHECK(!mm_device_.get());
281 DCHECK(!audio_volume_.get());
282 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr);
283 DCHECK(thread_checker_.CalledOnValidThread());
284
285 callback_ = callback;
286
287 // Initialize the capture timer.
288 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.
289
290 if (!Initialize()) {
291 return false;
292 }
293
212 // Start capturing. 294 // Start capturing.
213 capture_timer_->Start(FROM_HERE, 295 capture_timer_->Start(FROM_HERE,
214 audio_device_period_, 296 audio_device_period_,
215 this, 297 this,
216 &AudioCapturerWin::DoCapture); 298 &AudioCapturerWin::DoCapture);
217 return true; 299 return true;
218 } 300 }
219 301
220 float AudioCapturerWin::GetAudioLevel() { 302 float AudioCapturerWin::GetAudioLevel() {
221 BOOL mute; 303 BOOL mute;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); 359 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2);
278 packet->set_channels(AudioPacket::CHANNELS_STEREO); 360 packet->set_channels(AudioPacket::CHANNELS_STEREO);
279 361
280 callback_.Run(std::move(packet)); 362 callback_.Run(std::move(packet));
281 } 363 }
282 364
283 void AudioCapturerWin::DoCapture() { 365 void AudioCapturerWin::DoCapture() {
284 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_)); 366 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_));
285 DCHECK(thread_checker_.CalledOnValidThread()); 367 DCHECK(thread_checker_.CalledOnValidThread());
286 368
369 if (default_audio_device_changed_ && !Initialize()) {
370 // Initialization failed, we should wait for next DoCapture call.
371 return;
372 }
373
287 // Fetch all packets from the audio capture endpoint buffer. 374 // Fetch all packets from the audio capture endpoint buffer.
288 HRESULT hr = S_OK; 375 HRESULT hr = S_OK;
289 while (true) { 376 while (true) {
290 UINT32 next_packet_size; 377 UINT32 next_packet_size;
291 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size); 378 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size);
292 if (FAILED(hr)) 379 if (FAILED(hr))
293 break; 380 break;
294 381
295 if (next_packet_size <= 0) { 382 if (next_packet_size <= 0) {
296 return; 383 return;
(...skipping 29 matching lines...) Expand all
326 413
327 bool AudioCapturer::IsSupported() { 414 bool AudioCapturer::IsSupported() {
328 return true; 415 return true;
329 } 416 }
330 417
331 std::unique_ptr<AudioCapturer> AudioCapturer::Create() { 418 std::unique_ptr<AudioCapturer> AudioCapturer::Create() {
332 return base::WrapUnique(new AudioCapturerWin()); 419 return base::WrapUnique(new AudioCapturerWin());
333 } 420 }
334 421
335 } // namespace remoting 422 } // namespace remoting
OLDNEW
« 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