Chromium Code Reviews| 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..9c80adadce3378a48d6244eb7d72a5cc6774c169 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) |
| + return; |
| + |
|
miu
2016/06/01 00:29:42
You'll also need to return early here if |duplicat
qiangchen
2016/06/01 17:51:11
Done.
|
| + // 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,24 @@ 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_); |
| + |
|
miu
2016/06/01 00:29:42
style nit: remove empty line (to make this look ju
qiangchen
2016/06/01 17:51:12
Done.
|
| + 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(); |