cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / media / audio / audio_output_dispatcher_impl.cc
blob1df8e7ddd5ba3b02c168a5cf1d5c209451971faf
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"
7 #include <algorithm>
9 #include "base/bind.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"
15 #include "media/audio/audio_util.h"
17 namespace media {
19 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl(
20 AudioManager* audio_manager,
21 const AudioParameters& params,
22 const std::string& input_device_id,
23 const base::TimeDelta& close_delay)
24 : AudioOutputDispatcher(audio_manager, params, input_device_id),
25 pause_delay_(base::TimeDelta::FromMicroseconds(
26 2 * params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
27 static_cast<float>(params.sample_rate()))),
28 paused_proxies_(0),
29 weak_this_(this),
30 close_timer_(FROM_HERE,
31 close_delay,
32 this,
33 &AudioOutputDispatcherImpl::ClosePendingStreams) {
36 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() {
37 DCHECK(proxy_to_physical_map_.empty());
38 DCHECK(idle_streams_.empty());
39 DCHECK(pausing_streams_.empty());
42 bool AudioOutputDispatcherImpl::OpenStream() {
43 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
45 paused_proxies_++;
47 // Ensure that there is at least one open stream.
48 if (idle_streams_.empty() && !CreateAndOpenStream()) {
49 paused_proxies_--;
50 return false;
53 close_timer_.Reset();
54 return true;
57 bool AudioOutputDispatcherImpl::StartStream(
58 AudioOutputStream::AudioSourceCallback* callback,
59 AudioOutputProxy* stream_proxy) {
60 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
62 if (idle_streams_.empty() && !CreateAndOpenStream())
63 return false;
65 AudioOutputStream* physical_stream = idle_streams_.back();
66 DCHECK(physical_stream);
67 idle_streams_.pop_back();
69 DCHECK_GT(paused_proxies_, 0u);
70 --paused_proxies_;
72 close_timer_.Reset();
74 // Schedule task to allocate streams for other proxies if we need to.
75 message_loop_->PostTask(FROM_HERE, base::Bind(
76 &AudioOutputDispatcherImpl::OpenTask, weak_this_.GetWeakPtr()));
78 double volume = 0;
79 stream_proxy->GetVolume(&volume);
80 physical_stream->SetVolume(volume);
81 physical_stream->Start(callback);
82 proxy_to_physical_map_[stream_proxy] = physical_stream;
83 return true;
86 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
87 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
89 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
90 DCHECK(it != proxy_to_physical_map_.end());
91 AudioOutputStream* physical_stream = it->second;
92 proxy_to_physical_map_.erase(it);
94 physical_stream->Stop();
96 ++paused_proxies_;
98 pausing_streams_.push_front(physical_stream);
100 // Don't recycle stream until two buffers worth of time has elapsed.
101 message_loop_->PostDelayedTask(
102 FROM_HERE,
103 base::Bind(&AudioOutputDispatcherImpl::StopStreamTask,
104 weak_this_.GetWeakPtr()),
105 pause_delay_);
108 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy,
109 double volume) {
110 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
111 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
112 if (it != proxy_to_physical_map_.end()) {
113 AudioOutputStream* physical_stream = it->second;
114 physical_stream->SetVolume(volume);
118 void AudioOutputDispatcherImpl::StopStreamTask() {
119 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
121 if (pausing_streams_.empty())
122 return;
124 AudioOutputStream* stream = pausing_streams_.back();
125 pausing_streams_.pop_back();
126 idle_streams_.push_back(stream);
127 close_timer_.Reset();
130 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) {
131 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
133 while (!pausing_streams_.empty()) {
134 idle_streams_.push_back(pausing_streams_.back());
135 pausing_streams_.pop_back();
138 DCHECK_GT(paused_proxies_, 0u);
139 paused_proxies_--;
141 while (idle_streams_.size() > paused_proxies_) {
142 idle_streams_.back()->Close();
143 idle_streams_.pop_back();
147 void AudioOutputDispatcherImpl::Shutdown() {
148 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
150 // Cancel any pending tasks to close paused streams or create new ones.
151 weak_this_.InvalidateWeakPtrs();
153 // No AudioOutputProxy objects should hold a reference to us when we get
154 // to this stage.
155 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
157 AudioOutputStreamList::iterator it = idle_streams_.begin();
158 for (; it != idle_streams_.end(); ++it)
159 (*it)->Close();
160 idle_streams_.clear();
162 it = pausing_streams_.begin();
163 for (; it != pausing_streams_.end(); ++it)
164 (*it)->Close();
165 pausing_streams_.clear();
168 bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
169 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
170 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(
171 params_, input_device_id_);
172 if (!stream)
173 return false;
175 if (!stream->Open()) {
176 stream->Close();
177 return false;
179 idle_streams_.push_back(stream);
180 return true;
183 void AudioOutputDispatcherImpl::OpenTask() {
184 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
185 // Make sure that we have at least one stream allocated if there
186 // are paused streams.
187 if (paused_proxies_ > 0 && idle_streams_.empty() &&
188 pausing_streams_.empty()) {
189 CreateAndOpenStream();
192 close_timer_.Reset();
195 // This method is called by |close_timer_|.
196 void AudioOutputDispatcherImpl::ClosePendingStreams() {
197 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
198 while (!idle_streams_.empty()) {
199 idle_streams_.back()->Close();
200 idle_streams_.pop_back();
204 } // namespace media