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

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: Improved Created 6 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 | Annotate | Revision Log
« no previous file with comments | « media/audio/audio_input_controller.h ('k') | no next file » | 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 "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/threading/thread_restrictions.h" 8 #include "base/threading/thread_restrictions.h"
9 #include "base/time/time.h"
9 #include "media/base/limits.h" 10 #include "media/base/limits.h"
10 #include "media/base/scoped_histogram_timer.h" 11 #include "media/base/scoped_histogram_timer.h"
11 #include "media/base/user_input_monitor.h" 12 #include "media/base/user_input_monitor.h"
12 13
14 using base::TimeDelta;
15
13 namespace { 16 namespace {
14 const int kMaxInputChannels = 3; 17 const int kMaxInputChannels = 3;
15 18
16 // TODO(henrika): remove usage of timers and add support for proper 19 // TODO(henrika): remove usage of timers and add support for proper
17 // notification of when the input device is removed. This was originally added 20 // 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 21 // to resolve http://crbug.com/79936 for Windows platforms. This then caused
19 // breakage (very hard to repro bugs!) on other platforms: See 22 // breakage (very hard to repro bugs!) on other platforms: See
20 // http://crbug.com/226327 and http://crbug.com/230972. 23 // http://crbug.com/226327 and http://crbug.com/230972.
21 // See also that the timer has been disabled on Mac now due to 24 // See also that the timer has been disabled on Mac now due to
22 // crbug.com/357501. 25 // crbug.com/357501.
23 const int kTimerResetIntervalSeconds = 1; 26 const int kTimerResetIntervalSeconds = 1;
24 // We have received reports that the timer can be too trigger happy on some 27 // 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 28 // Mac devices and the initial timer interval has therefore been increased
26 // from 1 second to 5 seconds. 29 // from 1 second to 5 seconds.
27 const int kTimerInitialIntervalSeconds = 5; 30 const int kTimerInitialIntervalSeconds = 5;
31
32 // Time constant for AudioPowerMonitor.
33 // The utilized smoothing factor (alpha) in the exponential filter is given
34 // by 1-exp(-1/(fs*ts)), where fs is the sample rate in Hz and ts is the time
35 // constant given by |kPowerMeasurementTimeConstantMilliseconds|.
36 // Example: fs=44100, ts=10e-3 => alpha~0.022420
37 // fs=44100, ts=20e-3 => alpha~0.165903
38 // A large smoothing factor corresponds to a faster filter response to input
39 // changes since y(n)=alpha*x(n)+(1-alpha)*y(n-1), where x(n) is the input
40 // and y(n) is the output.
41 const int kPowerMeasurementTimeConstantMilliseconds = 10;
42
43 // Time between two successive measurements of audio power levels.
44 const int kPowerMonitorLogIntervalMilliseconds = 1000;
28 } 45 }
29 46
30 namespace media { 47 namespace media {
31 48
32 // static 49 // static
33 AudioInputController::Factory* AudioInputController::factory_ = NULL; 50 AudioInputController::Factory* AudioInputController::factory_ = NULL;
34 51
52 #if defined(AUDIO_POWER_MONITORING)
53 // Calculate and log the audible level in the range [0.0,1.0], where 0.0
54 // means the audio signal is silent and 1.0 means it is at maximum volume.
55 // TODO(henrika): we should call MediaStreamManager::SendMessageToNativeLog()
56 // here as well.
57 static void AddPowerLevelToLog(float level_dbfs) {
no longer working on chromium 2014/05/23 08:29:56 shouldn't you hook it up to the native log?
henrika (OOO until Aug 14) 2014/05/23 08:42:45 Yes, just wanted OK about general stuff first. Wil
henrika (OOO until Aug 14) 2014/05/26 11:02:26 I removed this part and log in dBFS instead. Easie
58 float level = 0;
59 static const float kSilenceThresholdDBFS = -72.24719896f;
60 if (level_dbfs < kSilenceThresholdDBFS)
61 level = 0.0f;
62 else if (level_dbfs > 0.0f)
63 level = 1.0f;
64 else
65 level = 1.0f - level_dbfs / kSilenceThresholdDBFS;
66 DVLOG(1) << "audio_level: " << level;
67 }
68 #endif
69
35 AudioInputController::AudioInputController(EventHandler* handler, 70 AudioInputController::AudioInputController(EventHandler* handler,
36 SyncWriter* sync_writer, 71 SyncWriter* sync_writer,
37 UserInputMonitor* user_input_monitor) 72 UserInputMonitor* user_input_monitor)
38 : creator_task_runner_(base::MessageLoopProxy::current()), 73 : creator_task_runner_(base::MessageLoopProxy::current()),
39 handler_(handler), 74 handler_(handler),
40 stream_(NULL), 75 stream_(NULL),
41 data_is_active_(false), 76 data_is_active_(false),
42 state_(CLOSED), 77 state_(CLOSED),
43 sync_writer_(sync_writer), 78 sync_writer_(sync_writer),
44 max_volume_(0.0), 79 max_volume_(0.0),
45 user_input_monitor_(user_input_monitor), 80 user_input_monitor_(user_input_monitor),
46 prev_key_down_count_(0) { 81 prev_key_down_count_(0) {
47 DCHECK(creator_task_runner_.get()); 82 DCHECK(creator_task_runner_.get());
48 } 83 }
49 84
50 AudioInputController::~AudioInputController() { 85 AudioInputController::~AudioInputController() {
51 DCHECK_EQ(state_, CLOSED); 86 DCHECK_EQ(state_, CLOSED);
52 } 87 }
53 88
54 // static 89 // static
55 scoped_refptr<AudioInputController> AudioInputController::Create( 90 scoped_refptr<AudioInputController> AudioInputController::Create(
56 AudioManager* audio_manager, 91 AudioManager* audio_manager,
57 EventHandler* event_handler, 92 EventHandler* event_handler,
58 const AudioParameters& params, 93 const AudioParameters& params,
59 const std::string& device_id, 94 const std::string& device_id,
60 UserInputMonitor* user_input_monitor) { 95 UserInputMonitor* user_input_monitor) {
61 DCHECK(audio_manager); 96 DCHECK(audio_manager);
97 DVLOG(1) << "AudioInputController::Create";
62 98
63 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) 99 if (!params.IsValid() || (params.channels() > kMaxInputChannels))
64 return NULL; 100 return NULL;
65 101
66 if (factory_) { 102 if (factory_) {
67 return factory_->Create( 103 return factory_->Create(
68 audio_manager, event_handler, params, user_input_monitor); 104 audio_manager, event_handler, params, user_input_monitor);
69 } 105 }
70 scoped_refptr<AudioInputController> controller( 106 scoped_refptr<AudioInputController> controller(
71 new AudioInputController(event_handler, NULL, user_input_monitor)); 107 new AudioInputController(event_handler, NULL, user_input_monitor));
(...skipping 14 matching lines...) Expand all
86 // static 122 // static
87 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( 123 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
88 AudioManager* audio_manager, 124 AudioManager* audio_manager,
89 EventHandler* event_handler, 125 EventHandler* event_handler,
90 const AudioParameters& params, 126 const AudioParameters& params,
91 const std::string& device_id, 127 const std::string& device_id,
92 SyncWriter* sync_writer, 128 SyncWriter* sync_writer,
93 UserInputMonitor* user_input_monitor) { 129 UserInputMonitor* user_input_monitor) {
94 DCHECK(audio_manager); 130 DCHECK(audio_manager);
95 DCHECK(sync_writer); 131 DCHECK(sync_writer);
132 DVLOG(1) << "AudioInputController::CreateLowLatency";
96 133
97 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) 134 if (!params.IsValid() || (params.channels() > kMaxInputChannels))
98 return NULL; 135 return NULL;
99 136
100 // Create the AudioInputController object and ensure that it runs on 137 // Create the AudioInputController object and ensure that it runs on
101 // the audio-manager thread. 138 // the audio-manager thread.
102 scoped_refptr<AudioInputController> controller( 139 scoped_refptr<AudioInputController> controller(
103 new AudioInputController(event_handler, sync_writer, user_input_monitor)); 140 new AudioInputController(event_handler, sync_writer, user_input_monitor));
104 controller->task_runner_ = audio_manager->GetTaskRunner(); 141 controller->task_runner_ = audio_manager->GetTaskRunner();
105 142
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 void AudioInputController::SetAutomaticGainControl(bool enabled) { 203 void AudioInputController::SetAutomaticGainControl(bool enabled) {
167 task_runner_->PostTask(FROM_HERE, base::Bind( 204 task_runner_->PostTask(FROM_HERE, base::Bind(
168 &AudioInputController::DoSetAutomaticGainControl, this, enabled)); 205 &AudioInputController::DoSetAutomaticGainControl, this, enabled));
169 } 206 }
170 207
171 void AudioInputController::DoCreate(AudioManager* audio_manager, 208 void AudioInputController::DoCreate(AudioManager* audio_manager,
172 const AudioParameters& params, 209 const AudioParameters& params,
173 const std::string& device_id) { 210 const std::string& device_id) {
174 DCHECK(task_runner_->BelongsToCurrentThread()); 211 DCHECK(task_runner_->BelongsToCurrentThread());
175 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); 212 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
213 DVLOG(1) << "AudioInputController::DoCreate";
214
215 #if defined(AUDIO_POWER_MONITORING)
216 // Create the audio (power) level meter given the provided audio parameters.
217 // An AudioBus is also needed to wrap the raw data buffer from the native
218 // layer to match AudioPowerMonitor::Scan().
219 // TODO(henrika): Remove use of extra AudioBus. See http://crbug.com/375155.
220 audio_level_.reset(new media::AudioPowerMonitor(params.sample_rate(),
221 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMilliseconds)));
222 audio_bus_ = AudioBus::Create(params);
223 audio_params_ = params;
224 #endif
225
176 // TODO(miu): See TODO at top of file. Until that's resolved, assume all 226 // 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 227 // 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 228 // errors. In reality, probably only Windows needs to be treated as
179 // unreliable here. 229 // unreliable here.
180 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id), 230 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id),
181 true); 231 true);
182 } 232 }
183 233
184 void AudioInputController::DoCreateForStream( 234 void AudioInputController::DoCreateForStream(
185 AudioInputStream* stream_to_control, bool enable_nodata_timer) { 235 AudioInputStream* stream_to_control, bool enable_nodata_timer) {
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 void AudioInputController::DoClose() { 309 void AudioInputController::DoClose() {
260 DCHECK(task_runner_->BelongsToCurrentThread()); 310 DCHECK(task_runner_->BelongsToCurrentThread());
261 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); 311 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime");
262 312
263 if (state_ == CLOSED) 313 if (state_ == CLOSED)
264 return; 314 return;
265 315
266 // Delete the timer on the same thread that created it. 316 // Delete the timer on the same thread that created it.
267 no_data_timer_.reset(); 317 no_data_timer_.reset();
268 318
319 #if defined(AUDIO_POWER_MONITORING)
320 if (audio_level_)
321 audio_level_->Reset();
no longer working on chromium 2014/05/23 08:29:56 I realized I was confused with Reset() and reset()
henrika (OOO until Aug 14) 2014/05/23 08:42:45 Good point. I can do that.
henrika (OOO until Aug 14) 2014/05/26 11:02:26 Done.
322 #endif
323
269 DoStopCloseAndClearStream(); 324 DoStopCloseAndClearStream();
270 SetDataIsActive(false); 325 SetDataIsActive(false);
271 326
272 if (SharedMemoryAndSyncSocketMode()) 327 if (SharedMemoryAndSyncSocketMode())
273 sync_writer_->Close(); 328 sync_writer_->Close();
274 329
275 if (user_input_monitor_) 330 if (user_input_monitor_)
276 user_input_monitor_->DisableKeyPressMonitoring(); 331 user_input_monitor_->DisableKeyPressMonitoring();
277 332
278 state_ = CLOSED; 333 state_ = CLOSED;
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 key_pressed = current_count != prev_key_down_count_; 425 key_pressed = current_count != prev_key_down_count_;
371 prev_key_down_count_ = current_count; 426 prev_key_down_count_ = current_count;
372 DVLOG_IF(6, key_pressed) << "Detected keypress."; 427 DVLOG_IF(6, key_pressed) << "Detected keypress.";
373 } 428 }
374 429
375 // Use SharedMemory and SyncSocket if the client has created a SyncWriter. 430 // Use SharedMemory and SyncSocket if the client has created a SyncWriter.
376 // Used by all low-latency clients except WebSpeech. 431 // Used by all low-latency clients except WebSpeech.
377 if (SharedMemoryAndSyncSocketMode()) { 432 if (SharedMemoryAndSyncSocketMode()) {
378 sync_writer_->Write(data, size, volume, key_pressed); 433 sync_writer_->Write(data, size, volume, key_pressed);
379 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); 434 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
435
436 #if defined(AUDIO_POWER_MONITORING)
437 {
438 // Only do power-level measurements if an AudioPowerMonitor object has
439 // been created. Done in DoCreate() but not DoCreateForStream(), hence
440 // logging will mainly be done for WebRTC and WebSpeech clients.
441 base::AutoLock auto_lock(lock_);
442 if (!audio_level_)
no longer working on chromium 2014/05/23 08:29:56 why this needs to be under the lock?
henrika (OOO until Aug 14) 2014/05/23 08:42:45 The callback is called on a native audio thread an
no longer working on chromium 2014/05/26 14:20:16 not sure I follow here. In DoCreate(), the creatio
443 return;
444 }
445
446 // Perform periodic audio (power) level measurements.
447 if ((base::TimeTicks::Now() - last_audio_level_log_time_).InMilliseconds() >
448 kPowerMonitorLogIntervalMilliseconds) {
no longer working on chromium 2014/05/23 08:29:56 indentation
henrika (OOO until Aug 14) 2014/05/23 08:42:45 Done.
henrika (OOO until Aug 14) 2014/05/26 11:02:26 Actually; this is what I get when using git cl for
449 // Wrap data into and AudioBus to match AudioPowerMonitor::Scan.
450 audio_bus_->FromInterleaved(
no longer working on chromium 2014/05/23 08:29:56 please add a todo here to remind switching to Audi
henrika (OOO until Aug 14) 2014/05/23 08:42:45 Will do.
451 data, audio_bus_->frames(), audio_params_.bits_per_sample() / 8);
452 audio_level_->Scan(*audio_bus_, audio_bus_->frames());
453
454 // Get current average power level and add it to the log.
455 std::pair<float, bool> result = audio_level_->ReadCurrentPowerAndClip();
456 AddPowerLevelToLog(result.first);
457
458 // Reset the average power level (since we don't log continuously).
459 audio_level_->Reset();
no longer working on chromium 2014/05/23 08:29:56 I am not familiar with AudioPowerMonitor, do you k
henrika (OOO until Aug 14) 2014/05/23 08:42:45 Yes it works. The smoothing factor controls how fa
460 last_audio_level_log_time_ = base::TimeTicks::Now();
461 }
462 #endif
463
380 return; 464 return;
381 } 465 }
382 466
383 // TODO(henrika): Investigate if we can avoid the extra copy here. 467 // TODO(henrika): Investigate if we can avoid the extra copy here.
384 // (see http://crbug.com/249316 for details). AFAIK, this scope is only 468 // (see http://crbug.com/249316 for details). AFAIK, this scope is only
385 // active for WebSpeech clients. 469 // active for WebSpeech clients.
386 scoped_ptr<uint8[]> audio_data(new uint8[size]); 470 scoped_ptr<uint8[]> audio_data(new uint8[size]);
387 memcpy(audio_data.get(), data, size); 471 memcpy(audio_data.get(), data, size);
388 472
389 // Ownership of the audio buffer will be with the callback until it is run, 473 // Ownership of the audio buffer will be with the callback until it is run,
(...skipping 30 matching lines...) Expand all
420 504
421 void AudioInputController::SetDataIsActive(bool enabled) { 505 void AudioInputController::SetDataIsActive(bool enabled) {
422 base::subtle::Release_Store(&data_is_active_, enabled); 506 base::subtle::Release_Store(&data_is_active_, enabled);
423 } 507 }
424 508
425 bool AudioInputController::GetDataIsActive() { 509 bool AudioInputController::GetDataIsActive() {
426 return (base::subtle::Acquire_Load(&data_is_active_) != false); 510 return (base::subtle::Acquire_Load(&data_is_active_) != false);
427 } 511 }
428 512
429 } // namespace media 513 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_input_controller.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698