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

Side by Side Diff: remoting/host/audio_capturer_win.cc

Issue 2809293006: [Chromoting] Move DefaultAudioDeviceChangeDetector out of AudioCapturerWin (Closed)
Patch Set: Remove override of destructor Created 3 years, 7 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
« no previous file with comments | « remoting/host/audio_capturer_win.h ('k') | remoting/host/win/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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>
11 #include <stdlib.h> 11 #include <stdlib.h>
12 #include <windows.h> 12 #include <windows.h>
13 13
14 #include <algorithm> 14 #include <algorithm>
15 #include <utility> 15 #include <utility>
16 16
17 #include "base/logging.h" 17 #include "base/logging.h"
18 #include "base/memory/ptr_util.h" 18 #include "base/memory/ptr_util.h"
19 #include "base/synchronization/lock.h" 19 #include "base/synchronization/lock.h"
20 #include "remoting/host/win/default_audio_device_change_detector.h"
20 21
21 namespace { 22 namespace {
22 const int kChannels = 2; 23 const int kChannels = 2;
23 const int kBytesPerSample = 2; 24 const int kBytesPerSample = 2;
24 const int kBitsPerSample = kBytesPerSample * 8; 25 const int kBitsPerSample = kBytesPerSample * 8;
25 // Conversion factor from 100ns to 1ms. 26 // Conversion factor from 100ns to 1ms.
26 const int k100nsPerMillisecond = 10000; 27 const int k100nsPerMillisecond = 10000;
27 28
28 // Tolerance for catching packets of silence. If all samples have absolute 29 // Tolerance for catching packets of silence. If all samples have absolute
29 // value less than this threshold, the packet will be counted as a packet of 30 // value less than this threshold, the packet will be counted as a packet of
30 // silence. A value of 2 was chosen, because Windows can give samples of 1 and 31 // silence. A value of 2 was chosen, because Windows can give samples of 1 and
31 // -1, even when no audio is playing. 32 // -1, even when no audio is playing.
32 const int kSilenceThreshold = 2; 33 const int kSilenceThreshold = 2;
33 34
34 // Lower bound for timer intervals, in milliseconds. 35 // Lower bound for timer intervals, in milliseconds.
35 const int kMinTimerInterval = 30; 36 const int kMinTimerInterval = 30;
36 37
37 // Upper bound for the timer precision error, in milliseconds. 38 // Upper bound for the timer precision error, in milliseconds.
38 // Timers are supposed to be accurate to 20ms, so we use 30ms to be safe. 39 // Timers are supposed to be accurate to 20ms, so we use 30ms to be safe.
39 const int kMaxExpectedTimerLag = 30; 40 const int kMaxExpectedTimerLag = 30;
40 } // namespace 41 } // namespace
41 42
42 namespace remoting { 43 namespace remoting {
43 44
44 class AudioCapturerWin::MMNotificationClient : public IMMNotificationClient {
45 public:
46 HRESULT __stdcall OnDefaultDeviceChanged(
47 EDataFlow flow,
48 ERole role,
49 LPCWSTR pwstrDefaultDevice) override {
50 base::AutoLock lock(lock_);
51 default_audio_device_changed_ = true;
52 return S_OK;
53 }
54
55 HRESULT __stdcall QueryInterface(REFIID iid, void** object) override {
56 if (iid == IID_IUnknown || iid == __uuidof(IMMNotificationClient)) {
57 *object = static_cast<IMMNotificationClient*>(this);
58 return S_OK;
59 }
60 *object = nullptr;
61 return E_NOINTERFACE;
62 }
63
64 // No Ops overrides.
65 HRESULT __stdcall OnDeviceAdded(LPCWSTR pwstrDeviceId) override {
66 return S_OK;
67 }
68 HRESULT __stdcall OnDeviceRemoved(LPCWSTR pwstrDeviceId) override {
69 return S_OK;
70 }
71 HRESULT __stdcall OnDeviceStateChanged(LPCWSTR pwstrDeviceId,
72 DWORD dwNewState) override {
73 return S_OK;
74 }
75 HRESULT __stdcall OnPropertyValueChanged(LPCWSTR pwstrDeviceId,
76 const PROPERTYKEY key) override {
77 return S_OK;
78 }
79 ULONG __stdcall AddRef() override { return 1; }
80 ULONG __stdcall Release() override { return 1; }
81
82 bool GetAndResetDefaultAudioDeviceChanged() {
83 base::AutoLock lock(lock_);
84 if (default_audio_device_changed_) {
85 default_audio_device_changed_ = false;
86 return true;
87 }
88 return false;
89 }
90
91 private:
92 // |lock_| musted be locked when accessing |default_audio_device_changed_|.
93 bool default_audio_device_changed_ = false;
94 base::Lock lock_;
95 };
96
97 AudioCapturerWin::AudioCapturerWin() 45 AudioCapturerWin::AudioCapturerWin()
98 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), 46 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID),
99 silence_detector_(kSilenceThreshold), 47 silence_detector_(kSilenceThreshold),
100 mm_notification_client_(new MMNotificationClient()),
101 last_capture_error_(S_OK) { 48 last_capture_error_(S_OK) {
102 thread_checker_.DetachFromThread(); 49 thread_checker_.DetachFromThread();
103 } 50 }
104 51
105 AudioCapturerWin::~AudioCapturerWin() { 52 AudioCapturerWin::~AudioCapturerWin() {
106 DCHECK(thread_checker_.CalledOnValidThread()); 53 DCHECK(thread_checker_.CalledOnValidThread());
107 if (audio_client_) { 54 Deinitialize();
108 audio_client_->Stop();
109 }
110 } 55 }
111 56
112 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { 57 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) {
113 callback_ = callback; 58 callback_ = callback;
114 59
115 if (!Initialize()) { 60 if (!Initialize()) {
116 return false; 61 return false;
117 } 62 }
118 63
119 // Initialize the capture timer and start capturing. Note, this timer won't 64 // Initialize the capture timer and start capturing. Note, this timer won't
(...skipping 11 matching lines...) Expand all
131 if (!Initialize()) { 76 if (!Initialize()) {
132 Deinitialize(); 77 Deinitialize();
133 return false; 78 return false;
134 } 79 }
135 return true; 80 return true;
136 } 81 }
137 82
138 void AudioCapturerWin::Deinitialize() { 83 void AudioCapturerWin::Deinitialize() {
139 DCHECK(thread_checker_.CalledOnValidThread()); 84 DCHECK(thread_checker_.CalledOnValidThread());
140 wave_format_ex_.Reset(nullptr); 85 wave_format_ex_.Reset(nullptr);
141 mm_device_enumerator_.Reset(); 86 default_device_detector_.reset();
142 audio_capture_client_.Reset(); 87 audio_capture_client_.Reset();
88 if (audio_client_) {
89 audio_client_->Stop();
90 }
143 audio_client_.Reset(); 91 audio_client_.Reset();
144 mm_device_.Reset(); 92 mm_device_.Reset();
145 audio_volume_.Reset(); 93 audio_volume_.Reset();
146 } 94 }
147 95
148 bool AudioCapturerWin::Initialize() { 96 bool AudioCapturerWin::Initialize() {
149 DCHECK(!audio_capture_client_.get()); 97 DCHECK(!audio_capture_client_.get());
150 DCHECK(!audio_client_.get()); 98 DCHECK(!audio_client_.get());
151 DCHECK(!mm_device_.get()); 99 DCHECK(!mm_device_.get());
152 DCHECK(!audio_volume_.get()); 100 DCHECK(!audio_volume_.get());
153 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); 101 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr);
154 DCHECK(thread_checker_.CalledOnValidThread()); 102 DCHECK(thread_checker_.CalledOnValidThread());
155 103
156 HRESULT hr = S_OK; 104 HRESULT hr = S_OK;
157 hr = mm_device_enumerator_.CreateInstance(__uuidof(MMDeviceEnumerator)); 105 base::win::ScopedComPtr<IMMDeviceEnumerator> mm_device_enumerator;
106 hr = mm_device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator));
158 if (FAILED(hr)) { 107 if (FAILED(hr)) {
159 LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr; 108 LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr;
160 return false; 109 return false;
161 } 110 }
162 111
163 hr = mm_device_enumerator_->RegisterEndpointNotificationCallback( 112 default_device_detector_.reset(
164 mm_notification_client_.get()); 113 new DefaultAudioDeviceChangeDetector(mm_device_enumerator));
165 if (FAILED(hr)) {
166 // We cannot predict which kind of error the API may return, but this is
167 // not a fatal error.
168 LOG(ERROR) << "Failed to register IMMNotificationClient. Error " << hr;
169 }
170 114
171 // Get the audio endpoint. 115 // Get the audio endpoint.
172 hr = mm_device_enumerator_->GetDefaultAudioEndpoint(eRender, eConsole, 116 hr = mm_device_enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
173 mm_device_.Receive()); 117 mm_device_.Receive());
174 if (FAILED(hr)) { 118 if (FAILED(hr)) {
175 LOG(ERROR) << "Failed to get IMMDevice. Error " << hr; 119 LOG(ERROR) << "Failed to get IMMDevice. Error " << hr;
176 return false; 120 return false;
177 } 121 }
178 122
179 // Get an audio client. 123 // Get an audio client.
180 hr = mm_device_->Activate(__uuidof(IAudioClient), 124 hr = mm_device_->Activate(__uuidof(IAudioClient),
181 CLSCTX_ALL, 125 CLSCTX_ALL,
182 nullptr, 126 nullptr,
183 audio_client_.ReceiveVoid()); 127 audio_client_.ReceiveVoid());
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); 312 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2);
369 packet->set_channels(AudioPacket::CHANNELS_STEREO); 313 packet->set_channels(AudioPacket::CHANNELS_STEREO);
370 314
371 callback_.Run(std::move(packet)); 315 callback_.Run(std::move(packet));
372 } 316 }
373 317
374 void AudioCapturerWin::DoCapture() { 318 void AudioCapturerWin::DoCapture() {
375 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_)); 319 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_));
376 DCHECK(thread_checker_.CalledOnValidThread()); 320 DCHECK(thread_checker_.CalledOnValidThread());
377 321
378 if (!is_initialized() || 322 if (!is_initialized() || default_device_detector_->GetAndReset()) {
379 mm_notification_client_->GetAndResetDefaultAudioDeviceChanged()) {
380 if (!ResetAndInitialize()) { 323 if (!ResetAndInitialize()) {
381 // Initialization failed, we should wait for next DoCapture call. 324 // Initialization failed, we should wait for next DoCapture call.
382 return; 325 return;
383 } 326 }
384 } 327 }
385 328
386 // Fetch all packets from the audio capture endpoint buffer. 329 // Fetch all packets from the audio capture endpoint buffer.
387 HRESULT hr = S_OK; 330 HRESULT hr = S_OK;
388 while (true) { 331 while (true) {
389 UINT32 next_packet_size; 332 UINT32 next_packet_size;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 368
426 bool AudioCapturer::IsSupported() { 369 bool AudioCapturer::IsSupported() {
427 return true; 370 return true;
428 } 371 }
429 372
430 std::unique_ptr<AudioCapturer> AudioCapturer::Create() { 373 std::unique_ptr<AudioCapturer> AudioCapturer::Create() {
431 return base::WrapUnique(new AudioCapturerWin()); 374 return base::WrapUnique(new AudioCapturerWin());
432 } 375 }
433 376
434 } // namespace remoting 377 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/audio_capturer_win.h ('k') | remoting/host/win/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698