Move media/audio files into media namespace
[chromium-blink-merge.git] / media / audio / audio_output_dispatcher.cc
blob998fc1b852afcd46d36007819d9f71882aa5c63c
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.h"
7 #include "base/bind.h"
8 #include "base/compiler_specific.h"
9 #include "base/message_loop.h"
10 #include "base/time.h"
11 #include "media/audio/audio_io.h"
13 namespace media {
15 AudioOutputDispatcher::AudioOutputDispatcher(
16 AudioManager* audio_manager, const AudioParameters& params,
17 base::TimeDelta close_delay)
18 : audio_manager_(audio_manager),
19 message_loop_(MessageLoop::current()),
20 params_(params),
21 pause_delay_(base::TimeDelta::FromMilliseconds(
22 2 * params.frames_per_buffer() *
23 base::Time::kMillisecondsPerSecond / params.sample_rate())),
24 paused_proxies_(0),
25 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
26 close_timer_(FROM_HERE,
27 close_delay,
28 weak_this_.GetWeakPtr(),
29 &AudioOutputDispatcher::ClosePendingStreams) {
30 // We expect to be instantiated on the audio thread. Otherwise the
31 // message_loop_ member will point to the wrong message loop!
32 DCHECK(audio_manager->GetMessageLoop()->BelongsToCurrentThread());
35 AudioOutputDispatcher::~AudioOutputDispatcher() {
36 DCHECK_EQ(MessageLoop::current(), message_loop_);
39 bool AudioOutputDispatcher::StreamOpened() {
40 DCHECK_EQ(MessageLoop::current(), message_loop_);
41 paused_proxies_++;
43 // Ensure that there is at least one open stream.
44 if (idle_streams_.empty() && !CreateAndOpenStream()) {
45 return false;
48 close_timer_.Reset();
50 return true;
53 AudioOutputStream* AudioOutputDispatcher::StreamStarted() {
54 DCHECK_EQ(MessageLoop::current(), message_loop_);
56 if (idle_streams_.empty() && !CreateAndOpenStream()) {
57 return NULL;
60 AudioOutputStream* stream = idle_streams_.back();
61 idle_streams_.pop_back();
63 DCHECK_GT(paused_proxies_, 0u);
64 paused_proxies_--;
66 close_timer_.Reset();
68 // Schedule task to allocate streams for other proxies if we need to.
69 message_loop_->PostTask(FROM_HERE, base::Bind(
70 &AudioOutputDispatcher::OpenTask, weak_this_.GetWeakPtr()));
72 return stream;
75 void AudioOutputDispatcher::StreamStopped(AudioOutputStream* stream) {
76 DCHECK_EQ(MessageLoop::current(), message_loop_);
78 paused_proxies_++;
80 pausing_streams_.push_front(stream);
82 // Don't recycle stream until two buffers worth of time has elapsed.
83 message_loop_->PostDelayedTask(
84 FROM_HERE,
85 base::Bind(&AudioOutputDispatcher::StopStreamTask,
86 weak_this_.GetWeakPtr()),
87 pause_delay_);
90 void AudioOutputDispatcher::StopStreamTask() {
91 DCHECK_EQ(MessageLoop::current(), message_loop_);
93 if (pausing_streams_.empty())
94 return;
96 AudioOutputStream* stream = pausing_streams_.back();
97 pausing_streams_.pop_back();
98 idle_streams_.push_back(stream);
99 close_timer_.Reset();
102 void AudioOutputDispatcher::StreamClosed() {
103 DCHECK_EQ(MessageLoop::current(), message_loop_);
105 while (!pausing_streams_.empty()) {
106 idle_streams_.push_back(pausing_streams_.back());
107 pausing_streams_.pop_back();
110 DCHECK_GT(paused_proxies_, 0u);
111 paused_proxies_--;
113 while (idle_streams_.size() > paused_proxies_) {
114 idle_streams_.back()->Close();
115 idle_streams_.pop_back();
119 void AudioOutputDispatcher::Shutdown() {
120 DCHECK_EQ(MessageLoop::current(), message_loop_);
122 // Cancel any pending tasks to close paused streams or create new ones.
123 weak_this_.InvalidateWeakPtrs();
125 // No AudioOutputProxy objects should hold a reference to us when we get
126 // to this stage.
127 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
129 AudioOutputStreamList::iterator it = idle_streams_.begin();
130 for (; it != idle_streams_.end(); ++it)
131 (*it)->Close();
132 idle_streams_.clear();
134 it = pausing_streams_.begin();
135 for (; it != pausing_streams_.end(); ++it)
136 (*it)->Close();
137 pausing_streams_.clear();
140 bool AudioOutputDispatcher::CreateAndOpenStream() {
141 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_);
142 if (!stream)
143 return false;
145 if (!stream->Open()) {
146 stream->Close();
147 return false;
149 idle_streams_.push_back(stream);
150 return true;
153 void AudioOutputDispatcher::OpenTask() {
154 // Make sure that we have at least one stream allocated if there
155 // are paused streams.
156 if (paused_proxies_ > 0 && idle_streams_.empty() &&
157 pausing_streams_.empty()) {
158 CreateAndOpenStream();
161 close_timer_.Reset();
164 // This method is called by |close_timer_|.
165 void AudioOutputDispatcher::ClosePendingStreams() {
166 DCHECK_EQ(MessageLoop::current(), message_loop_);
168 while (!idle_streams_.empty()) {
169 idle_streams_.back()->Close();
170 idle_streams_.pop_back();
174 } // namespace media