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..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 / |
|
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.
|
| + 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); |
|
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
|
| + 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); |
|
DaleCurtis
2016/06/01 20:58:07
This looks like it broadcasts twice?
qiangchen
2016/06/01 21:43:15
Explained above.
|
| +} |
| + |
| 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(); |