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

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

Issue 2840773004: [Chromoting] Add AudioVolumeApplier to reduce the complexity and the dependency of kChannels (Closed)
Patch Set: 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
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 26 matching lines...) Expand all
37 37
38 // Upper bound for the timer precision error, in milliseconds. 38 // Upper bound for the timer precision error, in milliseconds.
39 // 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.
40 const int kMaxExpectedTimerLag = 30; 40 const int kMaxExpectedTimerLag = 30;
41 } // namespace 41 } // namespace
42 42
43 namespace remoting { 43 namespace remoting {
44 44
45 AudioCapturerWin::AudioCapturerWin() 45 AudioCapturerWin::AudioCapturerWin()
46 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID), 46 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID),
47 silence_detector_(kSilenceThreshold), 47 volume_applier_(kSilenceThreshold),
48 last_capture_error_(S_OK) { 48 last_capture_error_(S_OK) {
49 thread_checker_.DetachFromThread(); 49 thread_checker_.DetachFromThread();
50 } 50 }
51 51
52 AudioCapturerWin::~AudioCapturerWin() { 52 AudioCapturerWin::~AudioCapturerWin() {
53 DCHECK(thread_checker_.CalledOnValidThread()); 53 DCHECK(thread_checker_.CalledOnValidThread());
54 Deinitialize(); 54 Deinitialize();
55 } 55 }
56 56
57 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { 57 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) {
(...skipping 25 matching lines...) Expand all
83 void AudioCapturerWin::Deinitialize() { 83 void AudioCapturerWin::Deinitialize() {
84 DCHECK(thread_checker_.CalledOnValidThread()); 84 DCHECK(thread_checker_.CalledOnValidThread());
85 wave_format_ex_.Reset(nullptr); 85 wave_format_ex_.Reset(nullptr);
86 default_device_detector_.reset(); 86 default_device_detector_.reset();
87 audio_capture_client_.Reset(); 87 audio_capture_client_.Reset();
88 if (audio_client_) { 88 if (audio_client_) {
89 audio_client_->Stop(); 89 audio_client_->Stop();
90 } 90 }
91 audio_client_.Reset(); 91 audio_client_.Reset();
92 mm_device_.Reset(); 92 mm_device_.Reset();
93 audio_volume_.Reset();
94 } 93 }
95 94
96 bool AudioCapturerWin::Initialize() { 95 bool AudioCapturerWin::Initialize() {
97 DCHECK(!audio_capture_client_.Get()); 96 DCHECK(!audio_capture_client_.Get());
98 DCHECK(!audio_client_.Get()); 97 DCHECK(!audio_client_.Get());
99 DCHECK(!mm_device_.Get()); 98 DCHECK(!mm_device_.Get());
100 DCHECK(!audio_volume_.Get());
101 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr); 99 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == nullptr);
102 DCHECK(thread_checker_.CalledOnValidThread()); 100 DCHECK(thread_checker_.CalledOnValidThread());
103 101
104 HRESULT hr = S_OK; 102 HRESULT hr = S_OK;
105 base::win::ScopedComPtr<IMMDeviceEnumerator> mm_device_enumerator; 103 base::win::ScopedComPtr<IMMDeviceEnumerator> mm_device_enumerator;
106 hr = mm_device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator)); 104 hr = mm_device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator));
107 if (FAILED(hr)) { 105 if (FAILED(hr)) {
108 LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr; 106 LOG(ERROR) << "Failed to create IMMDeviceEnumerator. Error " << hr;
109 return false; 107 return false;
110 } 108 }
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 return false; 224 return false;
227 } 225 }
228 226
229 // Start the IAudioClient. 227 // Start the IAudioClient.
230 hr = audio_client_->Start(); 228 hr = audio_client_->Start();
231 if (FAILED(hr)) { 229 if (FAILED(hr)) {
232 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr; 230 LOG(ERROR) << "Failed to start IAudioClient. Error " << hr;
233 return false; 231 return false;
234 } 232 }
235 233
236 // Initialize IAudioEndpointVolume. 234 volume_applier_.ActivateBy(mm_device_.Get());
237 // TODO(zijiehe): Do we need to control per process volume? 235 volume_applier_.Initialize(sampling_rate_, kChannels);
238 hr = mm_device_->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr,
239 audio_volume_.ReceiveVoid());
240 if (FAILED(hr)) {
241 LOG(ERROR) << "Failed to get an IAudioEndpointVolume. Error " << hr;
242 return false;
243 }
244
245 silence_detector_.Reset(sampling_rate_, kChannels);
246 236
247 return true; 237 return true;
248 } 238 }
249 239
250 bool AudioCapturerWin::is_initialized() const { 240 bool AudioCapturerWin::is_initialized() const {
251 // All Com components should be initialized / deinitialized together. 241 // All Com components should be initialized / deinitialized together.
252 return !!audio_volume_; 242 return !!audio_client_;
253 }
254
255 float AudioCapturerWin::GetAudioLevel() {
256 BOOL mute;
257 HRESULT hr = audio_volume_->GetMute(&mute);
258 if (FAILED(hr)) {
259 LOG(ERROR) << "Failed to get mute status from IAudioEndpointVolume, error "
260 << hr;
261 return 1;
262 }
263 if (mute) {
264 return 0;
265 }
266
267 float level;
268 hr = audio_volume_->GetMasterVolumeLevelScalar(&level);
269 if (FAILED(hr) || level > 1) {
270 LOG(ERROR) << "Failed to get master volume from IAudioEndpointVolume, "
271 "error "
272 << hr;
273 return 1;
274 }
275 if (level < 0) {
276 return 0;
277 }
278 return level;
279 }
280
281 void AudioCapturerWin::ProcessSamples(uint8_t* data, size_t frames) {
282 if (frames == 0) {
283 return;
284 }
285
286 int16_t* samples = reinterpret_cast<int16_t*>(data);
287 static_assert(sizeof(samples[0]) == kBytesPerSample,
288 "expect 16 bits per sample");
289 size_t sample_count = frames * kChannels;
290 if (silence_detector_.IsSilence(samples, sample_count)) {
291 return;
292 }
293
294 // Windows API does not provide volume adjusted audio sample as Linux does.
295 // So we need to manually apply volume to the samples.
296 float level = GetAudioLevel();
297 if (level == 0) {
298 return;
299 }
300
301 if (level < 1) {
302 int32_t level_int = static_cast<int32_t>(level * 65536);
303 for (size_t i = 0; i < sample_count; i++) {
304 samples[i] = (static_cast<int32_t>(samples[i]) * level_int) >> 16;
305 }
306 }
307
308 std::unique_ptr<AudioPacket> packet(new AudioPacket());
309 packet->add_data(data, frames * wave_format_ex_->nBlockAlign);
310 packet->set_encoding(AudioPacket::ENCODING_RAW);
311 packet->set_sampling_rate(sampling_rate_);
312 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2);
313 packet->set_channels(AudioPacket::CHANNELS_STEREO);
314
315 callback_.Run(std::move(packet));
316 } 243 }
317 244
318 void AudioCapturerWin::DoCapture() { 245 void AudioCapturerWin::DoCapture() {
319 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_)); 246 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_));
320 DCHECK(thread_checker_.CalledOnValidThread()); 247 DCHECK(thread_checker_.CalledOnValidThread());
321 248
322 if (!is_initialized() || default_device_detector_->GetAndReset()) { 249 if (!is_initialized() || default_device_detector_->GetAndReset()) {
323 if (!ResetAndInitialize()) { 250 if (!ResetAndInitialize()) {
324 // Initialization failed, we should wait for next DoCapture call. 251 // Initialization failed, we should wait for next DoCapture call.
325 return; 252 return;
(...skipping 13 matching lines...) Expand all
339 } 266 }
340 267
341 BYTE* data; 268 BYTE* data;
342 UINT32 frames; 269 UINT32 frames;
343 DWORD flags; 270 DWORD flags;
344 hr = audio_capture_client_->GetBuffer(&data, &frames, &flags, nullptr, 271 hr = audio_capture_client_->GetBuffer(&data, &frames, &flags, nullptr,
345 nullptr); 272 nullptr);
346 if (FAILED(hr)) 273 if (FAILED(hr))
347 break; 274 break;
348 275
349 ProcessSamples(data, frames); 276 if (volume_applier_.Apply(reinterpret_cast<int16_t*>(data), frames)) {
277 std::unique_ptr<AudioPacket> packet(new AudioPacket());
278 packet->add_data(data, frames * wave_format_ex_->nBlockAlign);
279 packet->set_encoding(AudioPacket::ENCODING_RAW);
280 packet->set_sampling_rate(sampling_rate_);
281 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2);
282 packet->set_channels(AudioPacket::CHANNELS_STEREO);
283
284 callback_.Run(std::move(packet));
285 }
350 286
351 hr = audio_capture_client_->ReleaseBuffer(frames); 287 hr = audio_capture_client_->ReleaseBuffer(frames);
352 if (FAILED(hr)) 288 if (FAILED(hr))
353 break; 289 break;
354 } 290 }
355 291
356 // There is nothing to capture if the audio endpoint device has been unplugged 292 // There is nothing to capture if the audio endpoint device has been unplugged
357 // or disabled. 293 // or disabled.
358 if (hr == AUDCLNT_E_DEVICE_INVALIDATED) 294 if (hr == AUDCLNT_E_DEVICE_INVALIDATED)
359 return; 295 return;
360 296
361 // Avoid reporting the same error multiple times. 297 // Avoid reporting the same error multiple times.
362 if (FAILED(hr) && hr != last_capture_error_) { 298 if (FAILED(hr) && hr != last_capture_error_) {
363 last_capture_error_ = hr; 299 last_capture_error_ = hr;
364 LOG(ERROR) << "Failed to capture an audio packet: 0x" 300 LOG(ERROR) << "Failed to capture an audio packet: 0x"
365 << std::hex << hr << std::dec << "."; 301 << std::hex << hr << std::dec << ".";
366 } 302 }
367 } 303 }
368 304
369 bool AudioCapturer::IsSupported() { 305 bool AudioCapturer::IsSupported() {
370 return true; 306 return true;
371 } 307 }
372 308
373 std::unique_ptr<AudioCapturer> AudioCapturer::Create() { 309 std::unique_ptr<AudioCapturer> AudioCapturer::Create() {
374 return base::WrapUnique(new AudioCapturerWin()); 310 return base::WrapUnique(new AudioCapturerWin());
375 } 311 }
376 312
377 } // namespace remoting 313 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698