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 <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <limits> | 10 #include <limits> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
14 #include "base/numerics/safe_conversions.h" | 14 #include "base/numerics/safe_conversions.h" |
15 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
16 #include "base/task_runner_util.h" | 16 #include "base/task_runner_util.h" |
17 #include "base/threading/platform_thread.h" | 17 #include "base/threading/platform_thread.h" |
18 #include "base/time/time.h" | 18 #include "base/time/time.h" |
19 #include "base/trace_event/trace_event.h" | 19 #include "base/trace_event/trace_event.h" |
20 #include "media/base/audio_timestamp_helper.h" | 20 #include "media/base/audio_timestamp_helper.h" |
21 | 21 |
22 using base::TimeDelta; | 22 using base::TimeDelta; |
23 | 23 |
24 namespace media { | 24 namespace media { |
| 25 namespace { |
| 26 // Time in seconds between two successive measurements of audio power levels. |
| 27 constexpr int kPowerMonitorLogIntervalSeconds = 15; |
| 28 } // namespace |
25 | 29 |
26 AudioOutputController::AudioOutputController( | 30 AudioOutputController::AudioOutputController( |
27 AudioManager* audio_manager, | 31 AudioManager* audio_manager, |
28 EventHandler* handler, | 32 EventHandler* handler, |
29 const AudioParameters& params, | 33 const AudioParameters& params, |
30 const std::string& output_device_id, | 34 const std::string& output_device_id, |
31 SyncReader* sync_reader) | 35 SyncReader* sync_reader) |
32 : audio_manager_(audio_manager), | 36 : audio_manager_(audio_manager), |
33 params_(params), | 37 params_(params), |
34 handler_(handler), | 38 handler_(handler), |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 | 162 |
159 // We can start from created or paused state. | 163 // We can start from created or paused state. |
160 if (state_ != kCreated && state_ != kPaused) | 164 if (state_ != kCreated && state_ != kPaused) |
161 return; | 165 return; |
162 | 166 |
163 // Ask for first packet. | 167 // Ask for first packet. |
164 sync_reader_->RequestMoreData(base::TimeDelta(), base::TimeTicks(), 0); | 168 sync_reader_->RequestMoreData(base::TimeDelta(), base::TimeTicks(), 0); |
165 | 169 |
166 state_ = kPlaying; | 170 state_ = kPlaying; |
167 | 171 |
| 172 if (will_monitor_audio_levels()) { |
| 173 last_audio_level_log_time_ = base::TimeTicks::Now(); |
| 174 } |
| 175 |
168 stream_->Start(this); | 176 stream_->Start(this); |
169 | 177 |
170 // For UMA tracking purposes, start the wedge detection timer. This allows us | 178 // For UMA tracking purposes, start the wedge detection timer. This allows us |
171 // to record statistics about the number of wedged playbacks in the field. | 179 // to record statistics about the number of wedged playbacks in the field. |
172 // | 180 // |
173 // WedgeCheck() will look to see if |on_more_io_data_called_| is true after | 181 // WedgeCheck() will look to see if |on_more_io_data_called_| is true after |
174 // the timeout expires. Care must be taken to ensure the wedge check delay is | 182 // the timeout expires. Care must be taken to ensure the wedge check delay is |
175 // large enough that the value isn't queried while OnMoreDataIO() is setting | 183 // large enough that the value isn't queried while OnMoreDataIO() is setting |
176 // it. | 184 // it. |
177 // | 185 // |
178 // Timer self-manages its lifetime and WedgeCheck() will only record the UMA | 186 // Timer self-manages its lifetime and WedgeCheck() will only record the UMA |
179 // statistic if state is still kPlaying. Additional Start() calls will | 187 // statistic if state is still kPlaying. Additional Start() calls will |
180 // invalidate the previous timer. | 188 // invalidate the previous timer. |
181 wedge_timer_.reset(new base::OneShotTimer()); | 189 wedge_timer_.reset(new base::OneShotTimer()); |
182 wedge_timer_->Start( | 190 wedge_timer_->Start( |
183 FROM_HERE, TimeDelta::FromSeconds(5), this, | 191 FROM_HERE, TimeDelta::FromSeconds(5), this, |
184 &AudioOutputController::WedgeCheck); | 192 &AudioOutputController::WedgeCheck); |
185 | 193 |
186 handler_->OnControllerPlaying(); | 194 handler_->OnControllerPlaying(); |
187 } | 195 } |
188 | 196 |
189 void AudioOutputController::StopStream() { | 197 void AudioOutputController::StopStream() { |
190 DCHECK(message_loop_->BelongsToCurrentThread()); | 198 DCHECK(message_loop_->BelongsToCurrentThread()); |
191 | 199 |
192 if (state_ == kPlaying) { | 200 if (state_ == kPlaying) { |
193 wedge_timer_.reset(); | 201 wedge_timer_.reset(); |
194 stream_->Stop(); | 202 stream_->Stop(); |
195 | 203 |
| 204 if (will_monitor_audio_levels()) { |
| 205 LogAudioPowerLevel("StopStream"); |
| 206 } |
| 207 |
196 // A stopped stream is silent, and power_montior_.Scan() is no longer being | 208 // A stopped stream is silent, and power_montior_.Scan() is no longer being |
197 // called; so we must reset the power monitor. | 209 // called; so we must reset the power monitor. |
198 power_monitor_.Reset(); | 210 power_monitor_.Reset(); |
199 | 211 |
200 state_ = kPaused; | 212 state_ = kPaused; |
201 } | 213 } |
202 } | 214 } |
203 | 215 |
204 void AudioOutputController::DoPause() { | 216 void AudioOutputController::DoPause() { |
205 DCHECK(message_loop_->BelongsToCurrentThread()); | 217 DCHECK(message_loop_->BelongsToCurrentThread()); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
281 const base::TimeTicks reference_time = delay_timestamp + delay; | 293 const base::TimeTicks reference_time = delay_timestamp + delay; |
282 std::unique_ptr<AudioBus> copy(AudioBus::Create(params_)); | 294 std::unique_ptr<AudioBus> copy(AudioBus::Create(params_)); |
283 dest->CopyTo(copy.get()); | 295 dest->CopyTo(copy.get()); |
284 message_loop_->PostTask( | 296 message_loop_->PostTask( |
285 FROM_HERE, | 297 FROM_HERE, |
286 base::BindOnce( | 298 base::BindOnce( |
287 &AudioOutputController::BroadcastDataToDuplicationTargets, this, | 299 &AudioOutputController::BroadcastDataToDuplicationTargets, this, |
288 std::move(copy), reference_time)); | 300 std::move(copy), reference_time)); |
289 } | 301 } |
290 | 302 |
291 if (will_monitor_audio_levels()) | 303 if (will_monitor_audio_levels()) { |
292 power_monitor_.Scan(*dest, frames); | 304 power_monitor_.Scan(*dest, frames); |
293 | 305 |
| 306 const auto now = base::TimeTicks::Now(); |
| 307 if ((now - last_audio_level_log_time_).InSeconds() > |
| 308 kPowerMonitorLogIntervalSeconds) { |
| 309 LogAudioPowerLevel("OnMoreData"); |
| 310 last_audio_level_log_time_ = now; |
| 311 } |
| 312 } |
| 313 |
294 return frames; | 314 return frames; |
295 } | 315 } |
296 | 316 |
297 void AudioOutputController::BroadcastDataToDuplicationTargets( | 317 void AudioOutputController::BroadcastDataToDuplicationTargets( |
298 std::unique_ptr<AudioBus> audio_bus, | 318 std::unique_ptr<AudioBus> audio_bus, |
299 base::TimeTicks reference_time) { | 319 base::TimeTicks reference_time) { |
300 DCHECK(message_loop_->BelongsToCurrentThread()); | 320 DCHECK(message_loop_->BelongsToCurrentThread()); |
301 if (state_ != kPlaying || duplication_targets_.empty()) | 321 if (state_ != kPlaying || duplication_targets_.empty()) |
302 return; | 322 return; |
303 | 323 |
304 // Note: Do not need to acquire lock since this is running on the same thread | 324 // Note: Do not need to acquire lock since this is running on the same thread |
305 // as where the set is modified. | 325 // as where the set is modified. |
306 for (auto target = std::next(duplication_targets_.begin(), 1); | 326 for (auto target = std::next(duplication_targets_.begin(), 1); |
307 target != duplication_targets_.end(); ++target) { | 327 target != duplication_targets_.end(); ++target) { |
308 std::unique_ptr<AudioBus> copy(AudioBus::Create(params_)); | 328 std::unique_ptr<AudioBus> copy(AudioBus::Create(params_)); |
309 audio_bus->CopyTo(copy.get()); | 329 audio_bus->CopyTo(copy.get()); |
310 (*target)->OnData(std::move(copy), reference_time); | 330 (*target)->OnData(std::move(copy), reference_time); |
311 } | 331 } |
312 | 332 |
313 (*duplication_targets_.begin())->OnData(std::move(audio_bus), reference_time); | 333 (*duplication_targets_.begin())->OnData(std::move(audio_bus), reference_time); |
314 } | 334 } |
315 | 335 |
| 336 void AudioOutputController::LogAudioPowerLevel(const std::string& call_name) { |
| 337 std::pair<float, bool> power_and_clip = |
| 338 power_monitor_.ReadCurrentPowerAndClip(); |
| 339 handler_->OnLog(base::StringPrintf("AOC::%s: average audio level=%.2f dBFS", |
| 340 call_name.c_str(), power_and_clip.first)); |
| 341 } |
| 342 |
316 void AudioOutputController::OnError() { | 343 void AudioOutputController::OnError() { |
317 { | 344 { |
318 base::AutoLock auto_lock(error_lock_); | 345 base::AutoLock auto_lock(error_lock_); |
319 if (ignore_errors_during_stop_close_) | 346 if (ignore_errors_during_stop_close_) |
320 return; | 347 return; |
321 } | 348 } |
322 | 349 |
323 // Handle error on the audio controller thread. | 350 // Handle error on the audio controller thread. |
324 message_loop_->PostTask( | 351 message_loop_->PostTask( |
325 FROM_HERE, base::BindOnce(&AudioOutputController::DoReportError, this)); | 352 FROM_HERE, base::BindOnce(&AudioOutputController::DoReportError, this)); |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 DCHECK(message_loop_->BelongsToCurrentThread()); | 517 DCHECK(message_loop_->BelongsToCurrentThread()); |
491 | 518 |
492 // If we should be playing and we haven't, that's a wedge. | 519 // If we should be playing and we haven't, that's a wedge. |
493 if (state_ == kPlaying) { | 520 if (state_ == kPlaying) { |
494 UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputControllerPlaybackStartupSuccess", | 521 UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputControllerPlaybackStartupSuccess", |
495 base::AtomicRefCountIsOne(&on_more_io_data_called_)); | 522 base::AtomicRefCountIsOne(&on_more_io_data_called_)); |
496 } | 523 } |
497 } | 524 } |
498 | 525 |
499 } // namespace media | 526 } // namespace media |
OLD | NEW |