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
3 // found in the LICENSE file.
5 #include "media/audio/audio_output_dispatcher_impl.h"
10 #include "base/compiler_specific.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/time/time.h"
13 #include "media/audio/audio_io.h"
14 #include "media/audio/audio_output_proxy.h"
18 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl(
19 AudioManager* audio_manager,
20 const AudioParameters& params,
21 const std::string& output_device_id,
22 const std::string& input_device_id,
23 const base::TimeDelta& close_delay)
24 : AudioOutputDispatcher(audio_manager, params, output_device_id,
26 pause_delay_(base::TimeDelta::FromMicroseconds(
27 2 * params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
28 static_cast<float>(params.sample_rate()))),
31 close_timer_(FROM_HERE,
34 &AudioOutputDispatcherImpl::ClosePendingStreams) {
37 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() {
38 DCHECK(proxy_to_physical_map_.empty());
39 DCHECK(idle_streams_.empty());
40 DCHECK(pausing_streams_.empty());
43 bool AudioOutputDispatcherImpl::OpenStream() {
44 DCHECK(message_loop_->BelongsToCurrentThread());
48 // Ensure that there is at least one open stream.
49 if (idle_streams_.empty() && !CreateAndOpenStream()) {
58 bool AudioOutputDispatcherImpl::StartStream(
59 AudioOutputStream::AudioSourceCallback* callback,
60 AudioOutputProxy* stream_proxy) {
61 DCHECK(message_loop_->BelongsToCurrentThread());
63 if (idle_streams_.empty() && !CreateAndOpenStream())
66 AudioOutputStream* physical_stream = idle_streams_.back();
67 DCHECK(physical_stream);
68 idle_streams_.pop_back();
70 DCHECK_GT(paused_proxies_, 0u);
76 stream_proxy->GetVolume(&volume);
77 physical_stream->SetVolume(volume);
78 physical_stream->Start(callback);
79 proxy_to_physical_map_[stream_proxy] = physical_stream;
83 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
84 DCHECK(message_loop_->BelongsToCurrentThread());
86 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
87 DCHECK(it != proxy_to_physical_map_.end());
88 AudioOutputStream* physical_stream = it->second;
89 proxy_to_physical_map_.erase(it);
91 physical_stream->Stop();
95 pausing_streams_.push_front(physical_stream);
97 // Don't recycle stream until two buffers worth of time has elapsed.
98 message_loop_->PostDelayedTask(
100 base::Bind(&AudioOutputDispatcherImpl::StopStreamTask,
101 weak_this_.GetWeakPtr()),
105 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy,
107 DCHECK(message_loop_->BelongsToCurrentThread());
108 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
109 if (it != proxy_to_physical_map_.end()) {
110 AudioOutputStream* physical_stream = it->second;
111 physical_stream->SetVolume(volume);
115 void AudioOutputDispatcherImpl::StopStreamTask() {
116 DCHECK(message_loop_->BelongsToCurrentThread());
118 if (pausing_streams_.empty())
121 AudioOutputStream* stream = pausing_streams_.back();
122 pausing_streams_.pop_back();
123 idle_streams_.push_back(stream);
124 close_timer_.Reset();
127 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) {
128 DCHECK(message_loop_->BelongsToCurrentThread());
130 while (!pausing_streams_.empty()) {
131 idle_streams_.push_back(pausing_streams_.back());
132 pausing_streams_.pop_back();
135 DCHECK_GT(paused_proxies_, 0u);
138 while (idle_streams_.size() > paused_proxies_) {
139 idle_streams_.back()->Close();
140 idle_streams_.pop_back();
144 void AudioOutputDispatcherImpl::Shutdown() {
145 DCHECK(message_loop_->BelongsToCurrentThread());
147 // Cancel any pending tasks to close paused streams or create new ones.
148 weak_this_.InvalidateWeakPtrs();
150 // No AudioOutputProxy objects should hold a reference to us when we get
152 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
154 AudioOutputStreamList::iterator it = idle_streams_.begin();
155 for (; it != idle_streams_.end(); ++it)
157 idle_streams_.clear();
159 it = pausing_streams_.begin();
160 for (; it != pausing_streams_.end(); ++it)
162 pausing_streams_.clear();
165 bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
166 DCHECK(message_loop_->BelongsToCurrentThread());
167 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(
168 params_, output_device_id_, input_device_id_);
172 if (!stream->Open()) {
176 idle_streams_.push_back(stream);
180 // This method is called by |close_timer_|.
181 void AudioOutputDispatcherImpl::ClosePendingStreams() {
182 DCHECK(message_loop_->BelongsToCurrentThread());
183 while (!idle_streams_.empty()) {
184 idle_streams_.back()->Close();
185 idle_streams_.pop_back();