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

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

Powered by Google App Engine
This is Rietveld 408576698