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 "media/audio/audio_output_controller.h" | 5 #include "media/audio/audio_output_controller.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/threading/platform_thread.h" | 11 #include "base/threading/platform_thread.h" |
12 #include "base/time/time.h" | 12 #include "base/time/time.h" |
13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
14 #include "media/audio/audio_silence_detector.h" | 14 #include "media/audio/audio_power_monitor.h" |
15 #include "media/audio/audio_util.h" | 15 #include "media/audio/audio_util.h" |
16 #include "media/audio/shared_memory_util.h" | 16 #include "media/audio/shared_memory_util.h" |
17 #include "media/base/scoped_histogram_timer.h" | 17 #include "media/base/scoped_histogram_timer.h" |
18 | 18 |
19 using base::Time; | 19 using base::Time; |
20 using base::TimeDelta; | 20 using base::TimeDelta; |
21 | 21 |
22 namespace media { | 22 namespace media { |
23 | 23 |
24 // Amount of contiguous time where all audio is silent before considering the | 24 // Time constant for AudioPowerMonitor. See AudioPowerMonitor ctor comments for |
25 // stream to have transitioned and EventHandler::OnAudible() should be called. | 25 // semantics. This value was arbitrarily chosen, but seems to work well. |
26 static const int kQuestionableSilencePeriodMillis = 50; | 26 static const int kPowerMeasurementTimeConstantMillis = 10; |
27 | 27 |
28 // Sample value range below which audio is considered indistinguishably silent. | 28 // Desired frequency of calls to EventHandler::OnPowerMeasured() for reporting |
29 // | 29 // power levels in the audio signal. |
30 // TODO(miu): This value should be specified in dbFS units rather than full | 30 static const int kPowerMeasurementsPerSecond = 30; |
31 // scale. See TODO in audio_silence_detector.h. | |
32 static const float kIndistinguishableSilenceThreshold = | |
33 1.0f / 4096.0f; // Note: This is approximately -72 dbFS. | |
34 | 31 |
35 // Polling-related constants. | 32 // Polling-related constants. |
36 const int AudioOutputController::kPollNumAttempts = 3; | 33 const int AudioOutputController::kPollNumAttempts = 3; |
37 const int AudioOutputController::kPollPauseInMilliseconds = 3; | 34 const int AudioOutputController::kPollPauseInMilliseconds = 3; |
38 | 35 |
39 AudioOutputController::AudioOutputController(AudioManager* audio_manager, | 36 AudioOutputController::AudioOutputController(AudioManager* audio_manager, |
40 EventHandler* handler, | 37 EventHandler* handler, |
41 const AudioParameters& params, | 38 const AudioParameters& params, |
42 const std::string& input_device_id, | 39 const std::string& input_device_id, |
43 SyncReader* sync_reader) | 40 SyncReader* sync_reader) |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime"); | 148 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime"); |
152 | 149 |
153 // We can start from created or paused state. | 150 // We can start from created or paused state. |
154 if (state_ != kCreated && state_ != kPaused) | 151 if (state_ != kCreated && state_ != kPaused) |
155 return; | 152 return; |
156 | 153 |
157 // Ask for first packet. | 154 // Ask for first packet. |
158 sync_reader_->UpdatePendingBytes(0); | 155 sync_reader_->UpdatePendingBytes(0); |
159 | 156 |
160 state_ = kPlaying; | 157 state_ = kPlaying; |
161 silence_detector_.reset(new AudioSilenceDetector( | 158 |
| 159 // Start monitoring power levels and send an initial notification that we're |
| 160 // starting in silence. |
| 161 handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false); |
| 162 power_monitor_callback_.Reset( |
| 163 base::Bind(&EventHandler::OnPowerMeasured, base::Unretained(handler_))); |
| 164 power_monitor_.reset(new AudioPowerMonitor( |
162 params_.sample_rate(), | 165 params_.sample_rate(), |
163 TimeDelta::FromMilliseconds(kQuestionableSilencePeriodMillis), | 166 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis), |
164 kIndistinguishableSilenceThreshold)); | 167 TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond, |
| 168 base::MessageLoop::current(), |
| 169 power_monitor_callback_.callback())); |
165 | 170 |
166 // We start the AudioOutputStream lazily. | 171 // We start the AudioOutputStream lazily. |
167 AllowEntryToOnMoreIOData(); | 172 AllowEntryToOnMoreIOData(); |
168 stream_->Start(this); | 173 stream_->Start(this); |
169 | 174 |
170 // Tell the event handler that we are now playing, and also start the silence | |
171 // detection notifications. | |
172 handler_->OnPlaying(); | 175 handler_->OnPlaying(); |
173 silence_detector_->Start( | |
174 base::Bind(&EventHandler::OnAudible, base::Unretained(handler_))); | |
175 } | 176 } |
176 | 177 |
177 void AudioOutputController::StopStream() { | 178 void AudioOutputController::StopStream() { |
178 DCHECK(message_loop_->BelongsToCurrentThread()); | 179 DCHECK(message_loop_->BelongsToCurrentThread()); |
179 | 180 |
180 if (state_ == kPlaying) { | 181 if (state_ == kPlaying) { |
181 stream_->Stop(); | 182 stream_->Stop(); |
182 DisallowEntryToOnMoreIOData(); | 183 DisallowEntryToOnMoreIOData(); |
183 silence_detector_->Stop(true); | 184 |
184 silence_detector_.reset(); | 185 // Stop monitoring power levels. By canceling power_monitor_callback_, any |
| 186 // tasks posted to |message_loop_| by AudioPowerMonitor during the |
| 187 // stream_->Stop() call above will not run. |
| 188 power_monitor_.reset(); |
| 189 power_monitor_callback_.Cancel(); |
| 190 |
185 state_ = kPaused; | 191 state_ = kPaused; |
186 } | 192 } |
187 } | 193 } |
188 | 194 |
189 void AudioOutputController::DoPause() { | 195 void AudioOutputController::DoPause() { |
190 DCHECK(message_loop_->BelongsToCurrentThread()); | 196 DCHECK(message_loop_->BelongsToCurrentThread()); |
191 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime"); | 197 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PauseTime"); |
192 | 198 |
193 StopStream(); | 199 StopStream(); |
194 | 200 |
195 if (state_ != kPaused) | 201 if (state_ != kPaused) |
196 return; | 202 return; |
197 | 203 |
198 // Send a special pause mark to the low-latency audio thread. | 204 // Send a special pause mark to the low-latency audio thread. |
199 sync_reader_->UpdatePendingBytes(kPauseMark); | 205 sync_reader_->UpdatePendingBytes(kPauseMark); |
200 | 206 |
| 207 // Paused means silence follows. |
| 208 handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false); |
| 209 |
201 handler_->OnPaused(); | 210 handler_->OnPaused(); |
202 } | 211 } |
203 | 212 |
204 void AudioOutputController::DoClose() { | 213 void AudioOutputController::DoClose() { |
205 DCHECK(message_loop_->BelongsToCurrentThread()); | 214 DCHECK(message_loop_->BelongsToCurrentThread()); |
206 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime"); | 215 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.CloseTime"); |
207 | 216 |
208 if (state_ != kClosed) { | 217 if (state_ != kClosed) { |
209 DoStopCloseAndClearStream(); | 218 DoStopCloseAndClearStream(); |
210 sync_reader_->Close(); | 219 sync_reader_->Close(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 const bool kShouldBlock = true; | 272 const bool kShouldBlock = true; |
264 #else | 273 #else |
265 const bool kShouldBlock = diverting_to_stream_ != NULL; | 274 const bool kShouldBlock = diverting_to_stream_ != NULL; |
266 #endif | 275 #endif |
267 | 276 |
268 const int frames = sync_reader_->Read(kShouldBlock, source, dest); | 277 const int frames = sync_reader_->Read(kShouldBlock, source, dest); |
269 DCHECK_LE(0, frames); | 278 DCHECK_LE(0, frames); |
270 sync_reader_->UpdatePendingBytes( | 279 sync_reader_->UpdatePendingBytes( |
271 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); | 280 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); |
272 | 281 |
273 silence_detector_->Scan(dest, frames); | 282 power_monitor_->Scan(*dest, frames); |
274 | 283 |
275 AllowEntryToOnMoreIOData(); | 284 AllowEntryToOnMoreIOData(); |
276 return frames; | 285 return frames; |
277 } | 286 } |
278 | 287 |
279 void AudioOutputController::OnError(AudioOutputStream* stream) { | 288 void AudioOutputController::OnError(AudioOutputStream* stream) { |
280 // Handle error on the audio controller thread. | 289 // Handle error on the audio controller thread. |
281 message_loop_->PostTask(FROM_HERE, base::Bind( | 290 message_loop_->PostTask(FROM_HERE, base::Bind( |
282 &AudioOutputController::DoReportError, this)); | 291 &AudioOutputController::DoReportError, this)); |
283 } | 292 } |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_)); | 386 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_)); |
378 base::AtomicRefCountInc(&num_allowed_io_); | 387 base::AtomicRefCountInc(&num_allowed_io_); |
379 } | 388 } |
380 | 389 |
381 void AudioOutputController::DisallowEntryToOnMoreIOData() { | 390 void AudioOutputController::DisallowEntryToOnMoreIOData() { |
382 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_); | 391 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_); |
383 DCHECK(is_zero); | 392 DCHECK(is_zero); |
384 } | 393 } |
385 | 394 |
386 } // namespace media | 395 } // namespace media |
OLD | NEW |