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 <limits> | 9 #include <limits> |
10 | 10 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
43 ignore_errors_during_stop_close_(false) { | 43 ignore_errors_during_stop_close_(false) { |
44 DCHECK(audio_manager); | 44 DCHECK(audio_manager); |
45 DCHECK(handler_); | 45 DCHECK(handler_); |
46 DCHECK(sync_reader_); | 46 DCHECK(sync_reader_); |
47 DCHECK(message_loop_.get()); | 47 DCHECK(message_loop_.get()); |
48 } | 48 } |
49 | 49 |
50 AudioOutputController::~AudioOutputController() { | 50 AudioOutputController::~AudioOutputController() { |
51 CHECK_EQ(kClosed, state_); | 51 CHECK_EQ(kClosed, state_); |
52 CHECK_EQ(nullptr, stream_); | 52 CHECK_EQ(nullptr, stream_); |
53 CHECK(duplication_targets_.empty()); | |
53 } | 54 } |
54 | 55 |
55 // static | 56 // static |
56 scoped_refptr<AudioOutputController> AudioOutputController::Create( | 57 scoped_refptr<AudioOutputController> AudioOutputController::Create( |
57 AudioManager* audio_manager, | 58 AudioManager* audio_manager, |
58 EventHandler* event_handler, | 59 EventHandler* event_handler, |
59 const AudioParameters& params, | 60 const AudioParameters& params, |
60 const std::string& output_device_id, | 61 const std::string& output_device_id, |
61 SyncReader* sync_reader) { | 62 SyncReader* sync_reader) { |
62 CHECK(audio_manager); | 63 CHECK(audio_manager); |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
302 // thread starts, its safe to compare and then increment. | 303 // thread starts, its safe to compare and then increment. |
303 if (base::AtomicRefCountIsZero(&on_more_io_data_called_)) | 304 if (base::AtomicRefCountIsZero(&on_more_io_data_called_)) |
304 base::AtomicRefCountInc(&on_more_io_data_called_); | 305 base::AtomicRefCountInc(&on_more_io_data_called_); |
305 | 306 |
306 sync_reader_->Read(dest); | 307 sync_reader_->Read(dest); |
307 | 308 |
308 const int frames = dest->frames(); | 309 const int frames = dest->frames(); |
309 sync_reader_->UpdatePendingBytes( | 310 sync_reader_->UpdatePendingBytes( |
310 total_bytes_delay + frames * params_.GetBytesPerFrame(), frames_skipped); | 311 total_bytes_delay + frames * params_.GetBytesPerFrame(), frames_skipped); |
311 | 312 |
313 bool need_to_duplicate = false; | |
314 { | |
315 base::AutoLock lock(duplication_targets_lock_); | |
316 need_to_duplicate = !duplication_targets_.empty(); | |
317 } | |
318 if (need_to_duplicate) { | |
319 const base::TimeTicks reference_time = | |
320 base::TimeTicks::Now() + | |
321 base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond * | |
322 total_bytes_delay / | |
DaleCurtis
2016/06/01 20:58:07
These are integer values and will lose precision.
qiangchen
2016/06/01 21:43:15
Really necessary? I think multiplication is before
DaleCurtis
2016/06/01 21:52:09
It depends on how you use these timestamps, but it
qiangchen
2016/06/01 23:11:13
Acknowledged.
| |
323 params_.GetBytesPerSecond()); | |
324 std::unique_ptr<AudioBus> copy(AudioBus::Create(params_)); | |
325 dest->CopyTo(copy.get()); | |
326 message_loop_->PostTask( | |
327 FROM_HERE, | |
328 base::Bind(&AudioOutputController::BroadcastDataToDuplicationTargets, | |
329 this, base::Passed(©), reference_time)); | |
330 } | |
331 | |
312 if (will_monitor_audio_levels()) | 332 if (will_monitor_audio_levels()) |
313 power_monitor_.Scan(*dest, frames); | 333 power_monitor_.Scan(*dest, frames); |
314 | 334 |
315 return frames; | 335 return frames; |
316 } | 336 } |
317 | 337 |
338 void AudioOutputController::BroadcastDataToDuplicationTargets( | |
339 std::unique_ptr<AudioBus> audio_bus, | |
340 base::TimeTicks reference_time) { | |
341 DCHECK(message_loop_->BelongsToCurrentThread()); | |
342 if (state_ != kPlaying || duplication_targets_.empty()) | |
343 return; | |
344 | |
345 // Note: Do not need to acquire lock since this is running on the same thread | |
346 // as where the set is modified. | |
347 for (auto target = std::next(duplication_targets_.begin(), 1); | |
DaleCurtis
2016/06/01 20:58:07
How come you need std::next here? Does for (auto a
qiangchen
2016/06/01 21:43:15
This loop skips the first target.
The statement af
DaleCurtis
2016/06/01 21:52:58
Up to you, but it seems like this would be clearer
qiangchen
2016/06/01 23:11:13
Not that simple.
Without using this technique, fo
| |
348 target != duplication_targets_.end(); ++target) { | |
349 std::unique_ptr<AudioBus> copy(AudioBus::Create(params_)); | |
350 audio_bus->CopyTo(copy.get()); | |
351 (*target)->OnData(std::move(copy), reference_time); | |
352 } | |
353 | |
354 (*duplication_targets_.begin())->OnData(std::move(audio_bus), reference_time); | |
DaleCurtis
2016/06/01 20:58:07
This looks like it broadcasts twice?
qiangchen
2016/06/01 21:43:15
Explained above.
| |
355 } | |
356 | |
318 void AudioOutputController::OnError(AudioOutputStream* stream) { | 357 void AudioOutputController::OnError(AudioOutputStream* stream) { |
319 { | 358 { |
320 base::AutoLock auto_lock(error_lock_); | 359 base::AutoLock auto_lock(error_lock_); |
321 if (ignore_errors_during_stop_close_) | 360 if (ignore_errors_during_stop_close_) |
322 return; | 361 return; |
323 } | 362 } |
324 | 363 |
325 // Handle error on the audio controller thread. | 364 // Handle error on the audio controller thread. |
326 message_loop_->PostTask(FROM_HERE, base::Bind( | 365 message_loop_->PostTask(FROM_HERE, base::Bind( |
327 &AudioOutputController::DoReportError, this)); | 366 &AudioOutputController::DoReportError, this)); |
328 } | 367 } |
329 | 368 |
330 void AudioOutputController::DoStopCloseAndClearStream() { | 369 void AudioOutputController::DoStopCloseAndClearStream() { |
331 DCHECK(message_loop_->BelongsToCurrentThread()); | 370 DCHECK(message_loop_->BelongsToCurrentThread()); |
332 | 371 |
333 // Allow calling unconditionally and bail if we don't have a stream_ to close. | 372 // Allow calling unconditionally and bail if we don't have a stream_ to close. |
334 if (stream_) { | 373 if (stream_) { |
335 { | 374 { |
336 base::AutoLock auto_lock(error_lock_); | 375 base::AutoLock auto_lock(error_lock_); |
337 ignore_errors_during_stop_close_ = true; | 376 ignore_errors_during_stop_close_ = true; |
338 } | 377 } |
339 | 378 |
340 // De-register from state change callbacks if stream_ was created via | 379 // De-register from state change callbacks if stream_ was created via |
341 // AudioManager. | 380 // AudioManager. |
342 if (stream_ != diverting_to_stream_) | 381 if (stream_ != diverting_to_stream_) |
343 audio_manager_->RemoveOutputDeviceChangeListener(this); | 382 audio_manager_->RemoveOutputDeviceChangeListener(this); |
344 | 383 |
345 StopStream(); | 384 StopStream(); |
346 stream_->Close(); | 385 stream_->Close(); |
386 | |
347 if (stream_ == diverting_to_stream_) | 387 if (stream_ == diverting_to_stream_) |
348 diverting_to_stream_ = NULL; | 388 diverting_to_stream_ = NULL; |
349 stream_ = NULL; | 389 stream_ = NULL; |
350 | 390 |
351 // Since the stream is no longer running, no lock is necessary. | 391 // Since the stream is no longer running, no lock is necessary. |
352 ignore_errors_during_stop_close_ = false; | 392 ignore_errors_during_stop_close_ = false; |
353 } | 393 } |
354 | 394 |
355 state_ = kEmpty; | 395 state_ = kEmpty; |
356 } | 396 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
393 message_loop_->PostTask( | 433 message_loop_->PostTask( |
394 FROM_HERE, | 434 FROM_HERE, |
395 base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream)); | 435 base::Bind(&AudioOutputController::DoStartDiverting, this, to_stream)); |
396 } | 436 } |
397 | 437 |
398 void AudioOutputController::StopDiverting() { | 438 void AudioOutputController::StopDiverting() { |
399 message_loop_->PostTask( | 439 message_loop_->PostTask( |
400 FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this)); | 440 FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this)); |
401 } | 441 } |
402 | 442 |
443 void AudioOutputController::StartDuplicating(AudioPushSink* sink) { | |
444 message_loop_->PostTask( | |
445 FROM_HERE, | |
446 base::Bind(&AudioOutputController::DoStartDuplicating, this, sink)); | |
447 } | |
448 | |
449 void AudioOutputController::StopDuplicating(AudioPushSink* sink) { | |
450 message_loop_->PostTask( | |
451 FROM_HERE, | |
452 base::Bind(&AudioOutputController::DoStopDuplicating, this, sink)); | |
453 } | |
454 | |
403 void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) { | 455 void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) { |
404 DCHECK(message_loop_->BelongsToCurrentThread()); | 456 DCHECK(message_loop_->BelongsToCurrentThread()); |
405 | 457 |
406 if (state_ == kClosed) | 458 if (state_ == kClosed) |
407 return; | 459 return; |
408 | 460 |
409 DCHECK(!diverting_to_stream_); | 461 DCHECK(!diverting_to_stream_); |
410 diverting_to_stream_ = to_stream; | 462 diverting_to_stream_ = to_stream; |
411 // Note: OnDeviceChange() will engage the "re-create" process, which will | 463 // Note: OnDeviceChange() will engage the "re-create" process, which will |
412 // detect and use the alternate AudioOutputStream rather than create a new one | 464 // detect and use the alternate AudioOutputStream rather than create a new one |
413 // via AudioManager. | 465 // via AudioManager. |
414 OnDeviceChange(); | 466 OnDeviceChange(); |
415 } | 467 } |
416 | 468 |
417 void AudioOutputController::DoStopDiverting() { | 469 void AudioOutputController::DoStopDiverting() { |
418 DCHECK(message_loop_->BelongsToCurrentThread()); | 470 DCHECK(message_loop_->BelongsToCurrentThread()); |
419 | 471 |
420 if (state_ == kClosed) | 472 if (state_ == kClosed) |
421 return; | 473 return; |
422 | 474 |
423 // Note: OnDeviceChange() will cause the existing stream (the consumer of the | 475 // Note: OnDeviceChange() will cause the existing stream (the consumer of the |
424 // diverted audio data) to be closed, and diverting_to_stream_ will be set | 476 // diverted audio data) to be closed, and diverting_to_stream_ will be set |
425 // back to NULL. | 477 // back to NULL. |
426 OnDeviceChange(); | 478 OnDeviceChange(); |
427 DCHECK(!diverting_to_stream_); | 479 DCHECK(!diverting_to_stream_); |
428 } | 480 } |
429 | 481 |
482 void AudioOutputController::DoStartDuplicating(AudioPushSink* to_stream) { | |
483 DCHECK(message_loop_->BelongsToCurrentThread()); | |
484 if (state_ == kClosed) | |
485 return; | |
486 | |
487 base::AutoLock lock(duplication_targets_lock_); | |
488 duplication_targets_.insert(to_stream); | |
489 } | |
490 | |
491 void AudioOutputController::DoStopDuplicating(AudioPushSink* to_stream) { | |
492 DCHECK(message_loop_->BelongsToCurrentThread()); | |
493 to_stream->Close(); | |
494 | |
495 base::AutoLock lock(duplication_targets_lock_); | |
496 duplication_targets_.erase(to_stream); | |
497 } | |
498 | |
430 std::pair<float, bool> AudioOutputController::ReadCurrentPowerAndClip() { | 499 std::pair<float, bool> AudioOutputController::ReadCurrentPowerAndClip() { |
431 DCHECK(will_monitor_audio_levels()); | 500 DCHECK(will_monitor_audio_levels()); |
432 return power_monitor_.ReadCurrentPowerAndClip(); | 501 return power_monitor_.ReadCurrentPowerAndClip(); |
433 } | 502 } |
434 | 503 |
435 void AudioOutputController::WedgeCheck() { | 504 void AudioOutputController::WedgeCheck() { |
436 DCHECK(message_loop_->BelongsToCurrentThread()); | 505 DCHECK(message_loop_->BelongsToCurrentThread()); |
437 | 506 |
438 // If we should be playing and we haven't, that's a wedge. | 507 // If we should be playing and we haven't, that's a wedge. |
439 if (state_ == kPlaying) { | 508 if (state_ == kPlaying) { |
440 UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputControllerPlaybackStartupSuccess", | 509 UMA_HISTOGRAM_BOOLEAN("Media.AudioOutputControllerPlaybackStartupSuccess", |
441 base::AtomicRefCountIsOne(&on_more_io_data_called_)); | 510 base::AtomicRefCountIsOne(&on_more_io_data_called_)); |
442 } | 511 } |
443 } | 512 } |
444 | 513 |
445 } // namespace media | 514 } // namespace media |
OLD | NEW |