OLD | NEW |
---|---|
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 Loading... | |
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 { | |
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; | |
56 } | |
57 HRESULT __stdcall OnDeviceRemoved(LPCWSTR pwstrDeviceId) override { | |
58 return S_OK; | |
59 } | |
60 HRESULT __stdcall OnDeviceStateChanged(LPCWSTR pwstrDeviceId, | |
61 DWORD dwNewState) override { | |
62 return S_OK; | |
63 } | |
64 HRESULT __stdcall OnPropertyValueChanged(LPCWSTR pwstrDeviceId, | |
65 const PROPERTYKEY key) override { | |
66 return S_OK; | |
67 } | |
68 ULONG __stdcall AddRef() override { return 1; } | |
69 ULONG __stdcall Release() override { return 1; } | |
70 | |
71 private: | |
72 AudioCapturerWin* owner_; | |
73 }; | |
74 | |
75 AudioCapturerWin::MMNotificationClient::MMNotificationClient( | |
76 AudioCapturerWin* owner) | |
77 : owner_(owner) { | |
Sergey Ulanov
2016/07/20 17:28:34
nit: Please either inline all methods in MMNotific
Hzj_jie
2016/07/20 20:43:14
Oh, I thought only functions with only return stat
Sergey Ulanov
2016/07/21 18:54:02
That's for when you define class in a header, whic
| |
78 DCHECK(owner_); | |
79 } | |
80 | |
81 HRESULT AudioCapturerWin::MMNotificationClient::OnDefaultDeviceChanged( | |
82 EDataFlow flow, | |
83 ERole role, | |
84 LPCWSTR pwstrDefaultDevice) { | |
85 owner_->default_audio_device_changed_ = true; | |
86 return S_OK; | |
87 } | |
88 | |
89 HRESULT AudioCapturerWin::MMNotificationClient::QueryInterface(REFIID iid, | |
90 void** object) { | |
91 if (iid == IID_IUnknown || iid == __uuidof(IMMNotificationClient)) { | |
92 *object = static_cast<IMMNotificationClient*>(this); | |
93 return S_OK; | |
94 } | |
95 *object = nullptr; | |
96 return E_NOINTERFACE; | |
97 } | |
98 | |
43 AudioCapturerWin::AudioCapturerWin() | 99 AudioCapturerWin::AudioCapturerWin() |
44 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), | 100 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), |
45 silence_detector_(kSilenceThreshold), | 101 silence_detector_(kSilenceThreshold), |
102 mm_notification_client_(new MMNotificationClient(this)), | |
46 last_capture_error_(S_OK) { | 103 last_capture_error_(S_OK) { |
47 thread_checker_.DetachFromThread(); | 104 thread_checker_.DetachFromThread(); |
48 } | 105 } |
49 | 106 |
50 AudioCapturerWin::~AudioCapturerWin() { | 107 AudioCapturerWin::~AudioCapturerWin() { |
51 DCHECK(thread_checker_.CalledOnValidThread()); | 108 DCHECK(thread_checker_.CalledOnValidThread()); |
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::Start(const PacketCapturedCallback& callback) { |
58 DCHECK(!audio_capture_client_.get()); | 116 DCHECK(!audio_capture_client_.get()); |
59 DCHECK(!audio_client_.get()); | 117 DCHECK(!audio_client_.get()); |
60 DCHECK(!mm_device_.get()); | 118 DCHECK(!mm_device_.get()); |
61 DCHECK(!audio_volume_.get()); | 119 DCHECK(!audio_volume_.get()); |
62 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); | 120 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); |
63 DCHECK(thread_checker_.CalledOnValidThread()); | 121 DCHECK(thread_checker_.CalledOnValidThread()); |
64 | 122 |
65 callback_ = callback; | 123 callback_ = callback; |
66 | 124 |
67 // Initialize the capture timer. | 125 if (!ResetAndInitialize()) { |
126 return false; | |
127 } | |
128 | |
129 // Initialize the capture timer and start capturing. | |
68 capture_timer_.reset(new base::RepeatingTimer()); | 130 capture_timer_.reset(new base::RepeatingTimer()); |
131 capture_timer_->Start(FROM_HERE, audio_device_period_, this, | |
132 &AudioCapturerWin::DoCapture); | |
133 return true; | |
134 } | |
135 | |
136 bool AudioCapturerWin::ResetAndInitialize() { | |
137 default_audio_device_changed_ = false; | |
138 wave_format_ex_.Reset(nullptr); | |
139 mm_device_enumerator_.Release(); | |
140 audio_capture_client_.Release(); | |
141 audio_client_.Release(); | |
142 mm_device_.Release(); | |
143 audio_volume_.Release(); | |
69 | 144 |
70 HRESULT hr = S_OK; | 145 HRESULT hr = S_OK; |
71 | 146 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)) { | 147 if (FAILED(hr)) { |
75 LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr; | 148 LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr; |
76 return false; | 149 return false; |
77 } | 150 } |
78 | 151 |
152 hr = mm_device_enumerator_->RegisterEndpointNotificationCallback( | |
153 mm_notification_client_.get()); | |
154 if (FAILED(hr)) { | |
155 // We cannot predict which kind of error the API may return, but this is | |
156 // not a fatal error. | |
157 LOG(ERROR) << "Failed to register IMMNotificationClient. Error " << hr; | |
158 } | |
159 | |
79 // Get the audio endpoint. | 160 // Get the audio endpoint. |
80 hr = mm_device_enumerator->GetDefaultAudioEndpoint(eRender, | 161 hr = mm_device_enumerator_->GetDefaultAudioEndpoint(eRender, eConsole, |
81 eConsole, | 162 mm_device_.Receive()); |
82 mm_device_.Receive()); | |
83 if (FAILED(hr)) { | 163 if (FAILED(hr)) { |
84 LOG(ERROR) << "Failed to get IMMDevice. Error " << hr; | 164 LOG(ERROR) << "Failed to get IMMDevice. Error " << hr; |
85 return false; | 165 return false; |
86 } | 166 } |
87 | 167 |
88 // Get an audio client. | 168 // Get an audio client. |
89 hr = mm_device_->Activate(__uuidof(IAudioClient), | 169 hr = mm_device_->Activate(__uuidof(IAudioClient), |
90 CLSCTX_ALL, | 170 CLSCTX_ALL, |
91 nullptr, | 171 nullptr, |
92 audio_client_.ReceiveVoid()); | 172 audio_client_.ReceiveVoid()); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
202 // TODO(zijiehe): Do we need to control per process volume? | 282 // TODO(zijiehe): Do we need to control per process volume? |
203 hr = mm_device_->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr, | 283 hr = mm_device_->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr, |
204 audio_volume_.ReceiveVoid()); | 284 audio_volume_.ReceiveVoid()); |
205 if (FAILED(hr)) { | 285 if (FAILED(hr)) { |
206 LOG(ERROR) << "Failed to get an IAudioEndpointVolume. Error " << hr; | 286 LOG(ERROR) << "Failed to get an IAudioEndpointVolume. Error " << hr; |
207 return false; | 287 return false; |
208 } | 288 } |
209 | 289 |
210 silence_detector_.Reset(sampling_rate_, kChannels); | 290 silence_detector_.Reset(sampling_rate_, kChannels); |
211 | 291 |
212 // Start capturing. | |
213 capture_timer_->Start(FROM_HERE, | |
214 audio_device_period_, | |
215 this, | |
216 &AudioCapturerWin::DoCapture); | |
217 return true; | 292 return true; |
218 } | 293 } |
219 | 294 |
220 float AudioCapturerWin::GetAudioLevel() { | 295 float AudioCapturerWin::GetAudioLevel() { |
221 BOOL mute; | 296 BOOL mute; |
222 HRESULT hr = audio_volume_->GetMute(&mute); | 297 HRESULT hr = audio_volume_->GetMute(&mute); |
223 if (FAILED(hr)) { | 298 if (FAILED(hr)) { |
224 LOG(ERROR) << "Failed to get mute status from IAudioEndpointVolume, error " | 299 LOG(ERROR) << "Failed to get mute status from IAudioEndpointVolume, error " |
225 << hr; | 300 << hr; |
226 return 1; | 301 return 1; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
277 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); | 352 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2); |
278 packet->set_channels(AudioPacket::CHANNELS_STEREO); | 353 packet->set_channels(AudioPacket::CHANNELS_STEREO); |
279 | 354 |
280 callback_.Run(std::move(packet)); | 355 callback_.Run(std::move(packet)); |
281 } | 356 } |
282 | 357 |
283 void AudioCapturerWin::DoCapture() { | 358 void AudioCapturerWin::DoCapture() { |
284 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_)); | 359 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_)); |
285 DCHECK(thread_checker_.CalledOnValidThread()); | 360 DCHECK(thread_checker_.CalledOnValidThread()); |
286 | 361 |
362 if (default_audio_device_changed_ && !ResetAndInitialize()) { | |
363 // Initialization failed, we should wait for next DoCapture call. | |
364 return; | |
365 } | |
366 | |
287 // Fetch all packets from the audio capture endpoint buffer. | 367 // Fetch all packets from the audio capture endpoint buffer. |
288 HRESULT hr = S_OK; | 368 HRESULT hr = S_OK; |
289 while (true) { | 369 while (true) { |
290 UINT32 next_packet_size; | 370 UINT32 next_packet_size; |
291 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size); | 371 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size); |
292 if (FAILED(hr)) | 372 if (FAILED(hr)) |
293 break; | 373 break; |
294 | 374 |
295 if (next_packet_size <= 0) { | 375 if (next_packet_size <= 0) { |
296 return; | 376 return; |
(...skipping 29 matching lines...) Expand all Loading... | |
326 | 406 |
327 bool AudioCapturer::IsSupported() { | 407 bool AudioCapturer::IsSupported() { |
328 return true; | 408 return true; |
329 } | 409 } |
330 | 410 |
331 std::unique_ptr<AudioCapturer> AudioCapturer::Create() { | 411 std::unique_ptr<AudioCapturer> AudioCapturer::Create() { |
332 return base::WrapUnique(new AudioCapturerWin()); | 412 return base::WrapUnique(new AudioCapturerWin()); |
333 } | 413 } |
334 | 414 |
335 } // namespace remoting | 415 } // namespace remoting |
OLD | NEW |