Mailbox support for texture layers.
[chromium-blink-merge.git] / media / audio / audio_output_dispatcher_impl.cc
blobd2542786ba7e9acd7e5f4e7936aa899299a78a0e
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.h"
12 #include "base/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 base::TimeDelta& close_delay)
23 : AudioOutputDispatcher(audio_manager, params),
24 pause_delay_(base::TimeDelta::FromMilliseconds(
25 2 * params.frames_per_buffer() *
26 base::Time::kMillisecondsPerSecond / params.sample_rate())),
27 paused_proxies_(0),
28 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
29 close_timer_(FROM_HERE,
30 close_delay,
31 weak_this_.GetWeakPtr(),
32 &AudioOutputDispatcherImpl::ClosePendingStreams) {
35 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() {
36 DCHECK(proxy_to_physical_map_.empty());
37 DCHECK(idle_streams_.empty());
38 DCHECK(pausing_streams_.empty());
41 bool AudioOutputDispatcherImpl::OpenStream() {
42 DCHECK_EQ(MessageLoop::current(), message_loop_);
44 paused_proxies_++;
46 // Ensure that there is at least one open stream.
47 if (idle_streams_.empty() && !CreateAndOpenStream()) {
48 paused_proxies_--;
49 return false;
52 close_timer_.Reset();
53 return true;
56 bool AudioOutputDispatcherImpl::StartStream(
57 AudioOutputStream::AudioSourceCallback* callback,
58 AudioOutputProxy* stream_proxy) {
59 DCHECK_EQ(MessageLoop::current(), message_loop_);
61 if (idle_streams_.empty() && !CreateAndOpenStream())
62 return false;
64 AudioOutputStream* physical_stream = idle_streams_.back();
65 DCHECK(physical_stream);
66 idle_streams_.pop_back();
68 DCHECK_GT(paused_proxies_, 0u);
69 --paused_proxies_;
71 close_timer_.Reset();
73 // Schedule task to allocate streams for other proxies if we need to.
74 message_loop_->PostTask(FROM_HERE, base::Bind(
75 &AudioOutputDispatcherImpl::OpenTask, weak_this_.GetWeakPtr()));
77 double volume = 0;
78 stream_proxy->GetVolume(&volume);
79 physical_stream->SetVolume(volume);
80 physical_stream->Start(callback);
81 proxy_to_physical_map_[stream_proxy] = physical_stream;
82 return true;
85 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
86 DCHECK_EQ(MessageLoop::current(), message_loop_);
88 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
89 DCHECK(it != proxy_to_physical_map_.end());
90 AudioOutputStream* physical_stream = it->second;
91 proxy_to_physical_map_.erase(it);
93 physical_stream->Stop();
95 ++paused_proxies_;
97 pausing_streams_.push_front(physical_stream);
99 // Don't recycle stream until two buffers worth of time has elapsed.
100 message_loop_->PostDelayedTask(
101 FROM_HERE,
102 base::Bind(&AudioOutputDispatcherImpl::StopStreamTask,
103 weak_this_.GetWeakPtr()),
104 pause_delay_);
107 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy,
108 double volume) {
109 DCHECK_EQ(MessageLoop::current(), message_loop_);
110 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
111 if (it != proxy_to_physical_map_.end()) {
112 AudioOutputStream* physical_stream = it->second;
113 physical_stream->SetVolume(volume);
117 void AudioOutputDispatcherImpl::StopStreamTask() {
118 DCHECK_EQ(MessageLoop::current(), message_loop_);
120 if (pausing_streams_.empty())
121 return;
123 AudioOutputStream* stream = pausing_streams_.back();
124 pausing_streams_.pop_back();
125 idle_streams_.push_back(stream);
126 close_timer_.Reset();
129 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) {
130 DCHECK_EQ(MessageLoop::current(), message_loop_);
132 while (!pausing_streams_.empty()) {
133 idle_streams_.push_back(pausing_streams_.back());
134 pausing_streams_.pop_back();
137 DCHECK_GT(paused_proxies_, 0u);
138 paused_proxies_--;
140 while (idle_streams_.size() > paused_proxies_) {
141 idle_streams_.back()->Close();
142 idle_streams_.pop_back();
146 void AudioOutputDispatcherImpl::Shutdown() {
147 DCHECK_EQ(MessageLoop::current(), message_loop_);
149 // Cancel any pending tasks to close paused streams or create new ones.
150 weak_this_.InvalidateWeakPtrs();
152 // No AudioOutputProxy objects should hold a reference to us when we get
153 // to this stage.
154 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
156 AudioOutputStreamList::iterator it = idle_streams_.begin();
157 for (; it != idle_streams_.end(); ++it)
158 (*it)->Close();
159 idle_streams_.clear();
161 it = pausing_streams_.begin();
162 for (; it != pausing_streams_.end(); ++it)
163 (*it)->Close();
164 pausing_streams_.clear();
167 bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
168 DCHECK_EQ(MessageLoop::current(), message_loop_);
169 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_);
170 if (!stream)
171 return false;
173 if (!stream->Open()) {
174 stream->Close();
175 return false;
177 idle_streams_.push_back(stream);
178 return true;
181 void AudioOutputDispatcherImpl::OpenTask() {
182 DCHECK_EQ(MessageLoop::current(), message_loop_);
183 // Make sure that we have at least one stream allocated if there
184 // are paused streams.
185 if (paused_proxies_ > 0 && idle_streams_.empty() &&
186 pausing_streams_.empty()) {
187 CreateAndOpenStream();
190 close_timer_.Reset();
193 // This method is called by |close_timer_|.
194 void AudioOutputDispatcherImpl::ClosePendingStreams() {
195 DCHECK_EQ(MessageLoop::current(), message_loop_);
196 while (!idle_streams_.empty()) {
197 idle_streams_.back()->Close();
198 idle_streams_.pop_back();
202 } // namespace media