Report errors from ChromiumEnv::GetChildren in Posix.
[chromium-blink-merge.git] / media / audio / audio_output_dispatcher_impl.cc
blob84d5ac02c94dea74dcde3ede14e93326d6434e35
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"
16 namespace media {
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,
25 input_device_id),
26 pause_delay_(base::TimeDelta::FromMicroseconds(
27 2 * params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
28 static_cast<float>(params.sample_rate()))),
29 paused_proxies_(0),
30 weak_this_(this),
31 close_timer_(FROM_HERE,
32 close_delay,
33 this,
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());
46 paused_proxies_++;
48 // Ensure that there is at least one open stream.
49 if (idle_streams_.empty() && !CreateAndOpenStream()) {
50 paused_proxies_--;
51 return false;
54 close_timer_.Reset();
55 return true;
58 bool AudioOutputDispatcherImpl::StartStream(
59 AudioOutputStream::AudioSourceCallback* callback,
60 AudioOutputProxy* stream_proxy) {
61 DCHECK(message_loop_->BelongsToCurrentThread());
63 if (idle_streams_.empty() && !CreateAndOpenStream())
64 return false;
66 AudioOutputStream* physical_stream = idle_streams_.back();
67 DCHECK(physical_stream);
68 idle_streams_.pop_back();
70 DCHECK_GT(paused_proxies_, 0u);
71 --paused_proxies_;
73 close_timer_.Reset();
75 // Schedule task to allocate streams for other proxies if we need to.
76 message_loop_->PostTask(FROM_HERE, base::Bind(
77 &AudioOutputDispatcherImpl::OpenTask, weak_this_.GetWeakPtr()));
79 double volume = 0;
80 stream_proxy->GetVolume(&volume);
81 physical_stream->SetVolume(volume);
82 physical_stream->Start(callback);
83 proxy_to_physical_map_[stream_proxy] = physical_stream;
84 return true;
87 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
88 DCHECK(message_loop_->BelongsToCurrentThread());
90 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
91 DCHECK(it != proxy_to_physical_map_.end());
92 AudioOutputStream* physical_stream = it->second;
93 proxy_to_physical_map_.erase(it);
95 physical_stream->Stop();
97 ++paused_proxies_;
99 pausing_streams_.push_front(physical_stream);
101 // Don't recycle stream until two buffers worth of time has elapsed.
102 message_loop_->PostDelayedTask(
103 FROM_HERE,
104 base::Bind(&AudioOutputDispatcherImpl::StopStreamTask,
105 weak_this_.GetWeakPtr()),
106 pause_delay_);
109 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy,
110 double volume) {
111 DCHECK(message_loop_->BelongsToCurrentThread());
112 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
113 if (it != proxy_to_physical_map_.end()) {
114 AudioOutputStream* physical_stream = it->second;
115 physical_stream->SetVolume(volume);
119 void AudioOutputDispatcherImpl::StopStreamTask() {
120 DCHECK(message_loop_->BelongsToCurrentThread());
122 if (pausing_streams_.empty())
123 return;
125 AudioOutputStream* stream = pausing_streams_.back();
126 pausing_streams_.pop_back();
127 idle_streams_.push_back(stream);
128 close_timer_.Reset();
131 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) {
132 DCHECK(message_loop_->BelongsToCurrentThread());
134 while (!pausing_streams_.empty()) {
135 idle_streams_.push_back(pausing_streams_.back());
136 pausing_streams_.pop_back();
139 DCHECK_GT(paused_proxies_, 0u);
140 paused_proxies_--;
142 while (idle_streams_.size() > paused_proxies_) {
143 idle_streams_.back()->Close();
144 idle_streams_.pop_back();
148 void AudioOutputDispatcherImpl::Shutdown() {
149 DCHECK(message_loop_->BelongsToCurrentThread());
151 // Cancel any pending tasks to close paused streams or create new ones.
152 weak_this_.InvalidateWeakPtrs();
154 // No AudioOutputProxy objects should hold a reference to us when we get
155 // to this stage.
156 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
158 AudioOutputStreamList::iterator it = idle_streams_.begin();
159 for (; it != idle_streams_.end(); ++it)
160 (*it)->Close();
161 idle_streams_.clear();
163 it = pausing_streams_.begin();
164 for (; it != pausing_streams_.end(); ++it)
165 (*it)->Close();
166 pausing_streams_.clear();
169 bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
170 DCHECK(message_loop_->BelongsToCurrentThread());
171 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(
172 params_, output_device_id_, input_device_id_);
173 if (!stream)
174 return false;
176 if (!stream->Open()) {
177 stream->Close();
178 return false;
180 idle_streams_.push_back(stream);
181 return true;
184 void AudioOutputDispatcherImpl::OpenTask() {
185 DCHECK(message_loop_->BelongsToCurrentThread());
186 // Make sure that we have at least one stream allocated if there
187 // are paused streams.
188 if (paused_proxies_ > 0 && idle_streams_.empty() &&
189 pausing_streams_.empty()) {
190 CreateAndOpenStream();
193 close_timer_.Reset();
196 // This method is called by |close_timer_|.
197 void AudioOutputDispatcherImpl::ClosePendingStreams() {
198 DCHECK(message_loop_->BelongsToCurrentThread());
199 while (!idle_streams_.empty()) {
200 idle_streams_.back()->Close();
201 idle_streams_.pop_back();
205 } // namespace media