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

Side by Side Diff: media/audio/audio_input_controller.cc

Issue 287873004: Adds volume level measurements to the AudioInputController for low-latency clients (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removed dependency of content in media Created 6 years, 6 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 | Annotate | Revision Log
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 "media/audio/audio_input_controller.h" 5 #include "media/audio/audio_input_controller.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/strings/stringprintf.h"
8 #include "base/threading/thread_restrictions.h" 9 #include "base/threading/thread_restrictions.h"
10 #include "base/time/time.h"
9 #include "media/base/limits.h" 11 #include "media/base/limits.h"
10 #include "media/base/scoped_histogram_timer.h" 12 #include "media/base/scoped_histogram_timer.h"
11 #include "media/base/user_input_monitor.h" 13 #include "media/base/user_input_monitor.h"
12 14
15 using base::TimeDelta;
16
13 namespace { 17 namespace {
14 const int kMaxInputChannels = 3; 18 const int kMaxInputChannels = 3;
15 19
16 // TODO(henrika): remove usage of timers and add support for proper 20 // TODO(henrika): remove usage of timers and add support for proper
17 // notification of when the input device is removed. This was originally added 21 // notification of when the input device is removed. This was originally added
18 // to resolve http://crbug.com/79936 for Windows platforms. This then caused 22 // to resolve http://crbug.com/79936 for Windows platforms. This then caused
19 // breakage (very hard to repro bugs!) on other platforms: See 23 // breakage (very hard to repro bugs!) on other platforms: See
20 // http://crbug.com/226327 and http://crbug.com/230972. 24 // http://crbug.com/226327 and http://crbug.com/230972.
21 // See also that the timer has been disabled on Mac now due to 25 // See also that the timer has been disabled on Mac now due to
22 // crbug.com/357501. 26 // crbug.com/357501.
23 const int kTimerResetIntervalSeconds = 1; 27 const int kTimerResetIntervalSeconds = 1;
24 // We have received reports that the timer can be too trigger happy on some 28 // We have received reports that the timer can be too trigger happy on some
25 // Mac devices and the initial timer interval has therefore been increased 29 // Mac devices and the initial timer interval has therefore been increased
26 // from 1 second to 5 seconds. 30 // from 1 second to 5 seconds.
27 const int kTimerInitialIntervalSeconds = 5; 31 const int kTimerInitialIntervalSeconds = 5;
32
33 // Time constant for AudioPowerMonitor.
34 // The utilized smoothing factor (alpha) in the exponential filter is given
35 // by 1-exp(-1/(fs*ts)), where fs is the sample rate in Hz and ts is the time
36 // constant given by |kPowerMeasurementTimeConstantMilliseconds|.
37 // Example: fs=44100, ts=10e-3 => alpha~0.022420
38 // fs=44100, ts=20e-3 => alpha~0.165903
39 // A large smoothing factor corresponds to a faster filter response to input
40 // changes since y(n)=alpha*x(n)+(1-alpha)*y(n-1), where x(n) is the input
41 // and y(n) is the output.
42 const int kPowerMeasurementTimeConstantMilliseconds = 10;
43
44 // Time in seconds between two successive measurements of audio power levels.
45 const int kPowerMonitorLogIntervalSeconds = 5;
28 } 46 }
29 47
30 namespace media { 48 namespace media {
31 49
32 // static 50 // static
33 AudioInputController::Factory* AudioInputController::factory_ = NULL; 51 AudioInputController::Factory* AudioInputController::factory_ = NULL;
34 52
35 AudioInputController::AudioInputController(EventHandler* handler, 53 AudioInputController::AudioInputController(EventHandler* handler,
36 SyncWriter* sync_writer, 54 SyncWriter* sync_writer,
37 UserInputMonitor* user_input_monitor) 55 UserInputMonitor* user_input_monitor)
(...skipping 14 matching lines...) Expand all
52 } 70 }
53 71
54 // static 72 // static
55 scoped_refptr<AudioInputController> AudioInputController::Create( 73 scoped_refptr<AudioInputController> AudioInputController::Create(
56 AudioManager* audio_manager, 74 AudioManager* audio_manager,
57 EventHandler* event_handler, 75 EventHandler* event_handler,
58 const AudioParameters& params, 76 const AudioParameters& params,
59 const std::string& device_id, 77 const std::string& device_id,
60 UserInputMonitor* user_input_monitor) { 78 UserInputMonitor* user_input_monitor) {
61 DCHECK(audio_manager); 79 DCHECK(audio_manager);
80 DVLOG(1) << "AudioInputController::Create";
62 81
63 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) 82 if (!params.IsValid() || (params.channels() > kMaxInputChannels))
64 return NULL; 83 return NULL;
65 84
66 if (factory_) { 85 if (factory_) {
67 return factory_->Create( 86 return factory_->Create(
68 audio_manager, event_handler, params, user_input_monitor); 87 audio_manager, event_handler, params, user_input_monitor);
69 } 88 }
70 scoped_refptr<AudioInputController> controller( 89 scoped_refptr<AudioInputController> controller(
71 new AudioInputController(event_handler, NULL, user_input_monitor)); 90 new AudioInputController(event_handler, NULL, user_input_monitor));
(...skipping 14 matching lines...) Expand all
86 // static 105 // static
87 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( 106 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
88 AudioManager* audio_manager, 107 AudioManager* audio_manager,
89 EventHandler* event_handler, 108 EventHandler* event_handler,
90 const AudioParameters& params, 109 const AudioParameters& params,
91 const std::string& device_id, 110 const std::string& device_id,
92 SyncWriter* sync_writer, 111 SyncWriter* sync_writer,
93 UserInputMonitor* user_input_monitor) { 112 UserInputMonitor* user_input_monitor) {
94 DCHECK(audio_manager); 113 DCHECK(audio_manager);
95 DCHECK(sync_writer); 114 DCHECK(sync_writer);
115 DVLOG(1) << "AudioInputController::CreateLowLatency";
96 116
97 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) 117 if (!params.IsValid() || (params.channels() > kMaxInputChannels))
98 return NULL; 118 return NULL;
99 119
100 // Create the AudioInputController object and ensure that it runs on 120 // Create the AudioInputController object and ensure that it runs on
101 // the audio-manager thread. 121 // the audio-manager thread.
102 scoped_refptr<AudioInputController> controller( 122 scoped_refptr<AudioInputController> controller(
103 new AudioInputController(event_handler, sync_writer, user_input_monitor)); 123 new AudioInputController(event_handler, sync_writer, user_input_monitor));
104 controller->task_runner_ = audio_manager->GetTaskRunner(); 124 controller->task_runner_ = audio_manager->GetTaskRunner();
105 125
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 void AudioInputController::SetAutomaticGainControl(bool enabled) { 186 void AudioInputController::SetAutomaticGainControl(bool enabled) {
167 task_runner_->PostTask(FROM_HERE, base::Bind( 187 task_runner_->PostTask(FROM_HERE, base::Bind(
168 &AudioInputController::DoSetAutomaticGainControl, this, enabled)); 188 &AudioInputController::DoSetAutomaticGainControl, this, enabled));
169 } 189 }
170 190
171 void AudioInputController::DoCreate(AudioManager* audio_manager, 191 void AudioInputController::DoCreate(AudioManager* audio_manager,
172 const AudioParameters& params, 192 const AudioParameters& params,
173 const std::string& device_id) { 193 const std::string& device_id) {
174 DCHECK(task_runner_->BelongsToCurrentThread()); 194 DCHECK(task_runner_->BelongsToCurrentThread());
175 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); 195 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
196 DVLOG(1) << "AudioInputController::DoCreate";
197
198 #if defined(AUDIO_POWER_MONITORING)
199 // Create the audio (power) level meter given the provided audio parameters.
200 // An AudioBus is also needed to wrap the raw data buffer from the native
201 // layer to match AudioPowerMonitor::Scan().
202 // TODO(henrika): Remove use of extra AudioBus. See http://crbug.com/375155.
203 audio_level_.reset(new media::AudioPowerMonitor(
204 params.sample_rate(),
205 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMilliseconds)));
206 audio_bus_ = AudioBus::Create(params);
207 audio_params_ = params;
208 #endif
209
176 // TODO(miu): See TODO at top of file. Until that's resolved, assume all 210 // TODO(miu): See TODO at top of file. Until that's resolved, assume all
177 // platform audio input requires the |no_data_timer_| be used to auto-detect 211 // platform audio input requires the |no_data_timer_| be used to auto-detect
178 // errors. In reality, probably only Windows needs to be treated as 212 // errors. In reality, probably only Windows needs to be treated as
179 // unreliable here. 213 // unreliable here.
180 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id), 214 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id),
181 true); 215 true);
182 } 216 }
183 217
184 void AudioInputController::DoCreateForStream( 218 void AudioInputController::DoCreateForStream(
185 AudioInputStream* stream_to_control, bool enable_nodata_timer) { 219 AudioInputStream* stream_to_control, bool enable_nodata_timer) {
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 void AudioInputController::DoClose() { 293 void AudioInputController::DoClose() {
260 DCHECK(task_runner_->BelongsToCurrentThread()); 294 DCHECK(task_runner_->BelongsToCurrentThread());
261 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); 295 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime");
262 296
263 if (state_ == CLOSED) 297 if (state_ == CLOSED)
264 return; 298 return;
265 299
266 // Delete the timer on the same thread that created it. 300 // Delete the timer on the same thread that created it.
267 no_data_timer_.reset(); 301 no_data_timer_.reset();
268 302
303 #if defined(AUDIO_POWER_MONITORING)
304 std::string log_string("AIC::DoClose: closing input stream");
no longer working on chromium 2014/05/26 14:20:16 nit, const
henrika (OOO until Aug 14) 2014/05/26 15:01:17 Removed.
305 if (handler_)
306 handler_->OnLog(this, log_string);
307 if (audio_level_)
308 audio_level_->Reset();
309 #endif
310
269 DoStopCloseAndClearStream(); 311 DoStopCloseAndClearStream();
270 SetDataIsActive(false); 312 SetDataIsActive(false);
271 313
272 if (SharedMemoryAndSyncSocketMode()) 314 if (SharedMemoryAndSyncSocketMode())
273 sync_writer_->Close(); 315 sync_writer_->Close();
274 316
275 if (user_input_monitor_) 317 if (user_input_monitor_)
276 user_input_monitor_->DisableKeyPressMonitoring(); 318 user_input_monitor_->DisableKeyPressMonitoring();
277 319
278 state_ = CLOSED; 320 state_ = CLOSED;
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 key_pressed = current_count != prev_key_down_count_; 412 key_pressed = current_count != prev_key_down_count_;
371 prev_key_down_count_ = current_count; 413 prev_key_down_count_ = current_count;
372 DVLOG_IF(6, key_pressed) << "Detected keypress."; 414 DVLOG_IF(6, key_pressed) << "Detected keypress.";
373 } 415 }
374 416
375 // Use SharedMemory and SyncSocket if the client has created a SyncWriter. 417 // Use SharedMemory and SyncSocket if the client has created a SyncWriter.
376 // Used by all low-latency clients except WebSpeech. 418 // Used by all low-latency clients except WebSpeech.
377 if (SharedMemoryAndSyncSocketMode()) { 419 if (SharedMemoryAndSyncSocketMode()) {
378 sync_writer_->Write(data, size, volume, key_pressed); 420 sync_writer_->Write(data, size, volume, key_pressed);
379 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); 421 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
422
423 #if defined(AUDIO_POWER_MONITORING)
424 {
425 // Only do power-level measurements if an AudioPowerMonitor object has
426 // been created. Done in DoCreate() but not DoCreateForStream(), hence
427 // logging will mainly be done for WebRTC and WebSpeech clients.
428 base::AutoLock auto_lock(lock_);
429 if (!audio_level_)
430 return;
431 }
432
433 // Perform periodic audio (power) level measurements.
434 if ((base::TimeTicks::Now() - last_audio_level_log_time_).InSeconds() >
435 kPowerMonitorLogIntervalSeconds) {
436 // Wrap data into an AudioBus to match AudioPowerMonitor::Scan.
437 // TODO(henrika): remove this section when capture side uses AudioBus.
438 // See http://crbug.com/375155 for details.
439 audio_bus_->FromInterleaved(
440 data, audio_bus_->frames(), audio_params_.bits_per_sample() / 8);
441 audio_level_->Scan(*audio_bus_, audio_bus_->frames());
442
443 task_runner_->PostTask(
444 FROM_HERE, base::Bind(&AudioInputController::DoLogAudioLevel, this));
445
446 last_audio_level_log_time_ = base::TimeTicks::Now();
447 }
448 #endif
449
380 return; 450 return;
381 } 451 }
382 452
383 // TODO(henrika): Investigate if we can avoid the extra copy here. 453 // TODO(henrika): Investigate if we can avoid the extra copy here.
384 // (see http://crbug.com/249316 for details). AFAIK, this scope is only 454 // (see http://crbug.com/249316 for details). AFAIK, this scope is only
385 // active for WebSpeech clients. 455 // active for WebSpeech clients.
386 scoped_ptr<uint8[]> audio_data(new uint8[size]); 456 scoped_ptr<uint8[]> audio_data(new uint8[size]);
387 memcpy(audio_data.get(), data, size); 457 memcpy(audio_data.get(), data, size);
388 458
389 // Ownership of the audio buffer will be with the callback until it is run, 459 // Ownership of the audio buffer will be with the callback until it is run,
390 // when ownership is passed to the callback function. 460 // when ownership is passed to the callback function.
391 task_runner_->PostTask(FROM_HERE, base::Bind( 461 task_runner_->PostTask(FROM_HERE, base::Bind(
392 &AudioInputController::DoOnData, this, base::Passed(&audio_data), size)); 462 &AudioInputController::DoOnData, this, base::Passed(&audio_data), size));
393 } 463 }
394 464
395 void AudioInputController::DoOnData(scoped_ptr<uint8[]> data, uint32 size) { 465 void AudioInputController::DoOnData(scoped_ptr<uint8[]> data, uint32 size) {
396 DCHECK(task_runner_->BelongsToCurrentThread()); 466 DCHECK(task_runner_->BelongsToCurrentThread());
397 if (handler_) 467 if (handler_)
398 handler_->OnData(this, data.get(), size); 468 handler_->OnData(this, data.get(), size);
399 } 469 }
400 470
471 void AudioInputController::DoLogAudioLevel() {
472 DCHECK(task_runner_->BelongsToCurrentThread());
473
474 // Get current average power level and add it to the log.
475 // Possible range is given by [-inf, 0] dBFS.
476 std::pair<float, bool> result = audio_level_->ReadCurrentPowerAndClip();
no longer working on chromium 2014/05/26 14:20:16 this introduces a race here. audio_level_ is chang
henrika (OOO until Aug 14) 2014/05/26 15:01:17 Will fix.
477 std::string log_string = base::StringPrintf(
478 "AIC::OnData: average audio level=%.2f dBFS", result.first);
479 static const float kSilenceThresholdDBFS = -72.24719896f;
480 if (result.first < kSilenceThresholdDBFS)
481 log_string += " <=> no audio input!";
482 if (handler_)
483 handler_->OnLog(this, log_string);
484
485 // Reset the average power level (since we don't log continuously).
486 audio_level_->Reset();
487 }
488
401 void AudioInputController::OnError(AudioInputStream* stream) { 489 void AudioInputController::OnError(AudioInputStream* stream) {
402 // Handle error on the audio-manager thread. 490 // Handle error on the audio-manager thread.
403 task_runner_->PostTask(FROM_HERE, base::Bind( 491 task_runner_->PostTask(FROM_HERE, base::Bind(
404 &AudioInputController::DoReportError, this)); 492 &AudioInputController::DoReportError, this));
405 } 493 }
406 494
407 void AudioInputController::DoStopCloseAndClearStream() { 495 void AudioInputController::DoStopCloseAndClearStream() {
408 DCHECK(task_runner_->BelongsToCurrentThread()); 496 DCHECK(task_runner_->BelongsToCurrentThread());
409 497
410 // Allow calling unconditionally and bail if we don't have a stream to close. 498 // Allow calling unconditionally and bail if we don't have a stream to close.
411 if (stream_ != NULL) { 499 if (stream_ != NULL) {
412 stream_->Stop(); 500 stream_->Stop();
413 stream_->Close(); 501 stream_->Close();
414 stream_ = NULL; 502 stream_ = NULL;
415 } 503 }
416 504
417 // The event handler should not be touched after the stream has been closed. 505 // The event handler should not be touched after the stream has been closed.
418 handler_ = NULL; 506 handler_ = NULL;
419 } 507 }
420 508
421 void AudioInputController::SetDataIsActive(bool enabled) { 509 void AudioInputController::SetDataIsActive(bool enabled) {
422 base::subtle::Release_Store(&data_is_active_, enabled); 510 base::subtle::Release_Store(&data_is_active_, enabled);
423 } 511 }
424 512
425 bool AudioInputController::GetDataIsActive() { 513 bool AudioInputController::GetDataIsActive() {
426 return (base::subtle::Acquire_Load(&data_is_active_) != false); 514 return (base::subtle::Acquire_Load(&data_is_active_) != false);
427 } 515 }
428 516
429 } // namespace media 517 } // namespace media
OLDNEW
« media/audio/audio_input_controller.h ('K') | « media/audio/audio_input_controller.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698