| Index: media/audio/audio_output_controller.cc
|
| diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc
|
| index f8523f037f378e51fb4c18c716cccc064f6cbfba..9b8f52387d8e7a4f638d73c7d1127ae2a2f394e2 100644
|
| --- a/media/audio/audio_output_controller.cc
|
| +++ b/media/audio/audio_output_controller.cc
|
| @@ -50,6 +50,7 @@ AudioOutputController::AudioOutputController(
|
| AudioOutputController::~AudioOutputController() {
|
| CHECK_EQ(kClosed, state_);
|
| CHECK_EQ(nullptr, stream_);
|
| + CHECK(duplication_targets_.empty());
|
| }
|
|
|
| // static
|
| @@ -309,12 +310,50 @@ int AudioOutputController::OnMoreData(AudioBus* dest,
|
| sync_reader_->UpdatePendingBytes(
|
| total_bytes_delay + frames * params_.GetBytesPerFrame(), frames_skipped);
|
|
|
| + bool need_to_duplicate = false;
|
| + {
|
| + base::AutoLock lock(duplication_targets_lock_);
|
| + need_to_duplicate = !duplication_targets_.empty();
|
| + }
|
| + if (need_to_duplicate) {
|
| + const base::TimeTicks reference_time =
|
| + base::TimeTicks::Now() +
|
| + base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond *
|
| + total_bytes_delay /
|
| + params_.GetBytesPerSecond());
|
| + std::unique_ptr<AudioBus> copy(AudioBus::Create(params_));
|
| + dest->CopyTo(copy.get());
|
| + message_loop_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&AudioOutputController::BroadcastDataToDuplicationTargets,
|
| + this, base::Passed(©), reference_time));
|
| + }
|
| +
|
| if (will_monitor_audio_levels())
|
| power_monitor_.Scan(*dest, frames);
|
|
|
| return frames;
|
| }
|
|
|
| +void AudioOutputController::BroadcastDataToDuplicationTargets(
|
| + std::unique_ptr<AudioBus> audio_bus,
|
| + base::TimeTicks reference_time) {
|
| + DCHECK(message_loop_->BelongsToCurrentThread());
|
| + if (state_ != kPlaying || duplication_targets_.empty())
|
| + return;
|
| +
|
| + // Note: Do not need to acquire lock since this is running on the same thread
|
| + // as where the set is modified.
|
| + for (auto target = std::next(duplication_targets_.begin(), 1);
|
| + target != duplication_targets_.end(); ++target) {
|
| + std::unique_ptr<AudioBus> copy(AudioBus::Create(params_));
|
| + audio_bus->CopyTo(copy.get());
|
| + (*target)->OnData(std::move(copy), reference_time);
|
| + }
|
| +
|
| + (*duplication_targets_.begin())->OnData(std::move(audio_bus), reference_time);
|
| +}
|
| +
|
| void AudioOutputController::OnError(AudioOutputStream* stream) {
|
| {
|
| base::AutoLock auto_lock(error_lock_);
|
| @@ -344,6 +383,7 @@ void AudioOutputController::DoStopCloseAndClearStream() {
|
|
|
| StopStream();
|
| stream_->Close();
|
| +
|
| if (stream_ == diverting_to_stream_)
|
| diverting_to_stream_ = NULL;
|
| stream_ = NULL;
|
| @@ -400,6 +440,18 @@ void AudioOutputController::StopDiverting() {
|
| FROM_HERE, base::Bind(&AudioOutputController::DoStopDiverting, this));
|
| }
|
|
|
| +void AudioOutputController::StartDuplicating(AudioPushSink* sink) {
|
| + message_loop_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&AudioOutputController::DoStartDuplicating, this, sink));
|
| +}
|
| +
|
| +void AudioOutputController::StopDuplicating(AudioPushSink* sink) {
|
| + message_loop_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&AudioOutputController::DoStopDuplicating, this, sink));
|
| +}
|
| +
|
| void AudioOutputController::DoStartDiverting(AudioOutputStream* to_stream) {
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
|
|
| @@ -427,6 +479,23 @@ void AudioOutputController::DoStopDiverting() {
|
| DCHECK(!diverting_to_stream_);
|
| }
|
|
|
| +void AudioOutputController::DoStartDuplicating(AudioPushSink* to_stream) {
|
| + DCHECK(message_loop_->BelongsToCurrentThread());
|
| + if (state_ == kClosed)
|
| + return;
|
| +
|
| + base::AutoLock lock(duplication_targets_lock_);
|
| + duplication_targets_.insert(to_stream);
|
| +}
|
| +
|
| +void AudioOutputController::DoStopDuplicating(AudioPushSink* to_stream) {
|
| + DCHECK(message_loop_->BelongsToCurrentThread());
|
| + to_stream->Close();
|
| +
|
| + base::AutoLock lock(duplication_targets_lock_);
|
| + duplication_targets_.erase(to_stream);
|
| +}
|
| +
|
| std::pair<float, bool> AudioOutputController::ReadCurrentPowerAndClip() {
|
| DCHECK(will_monitor_audio_levels());
|
| return power_monitor_.ReadCurrentPowerAndClip();
|
|
|