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"
8 #include "base/compiler_specific.h"
9 #include "base/message_loop.h"
10 #include "base/time.h"
11 #include "media/audio/audio_io.h"
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()),
21 pause_delay_(base::TimeDelta::FromMilliseconds(
22 2 * params
.frames_per_buffer() *
23 base::Time::kMillisecondsPerSecond
/ params
.sample_rate())),
25 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
26 close_timer_(FROM_HERE
,
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_
);
43 // Ensure that there is at least one open stream.
44 if (idle_streams_
.empty() && !CreateAndOpenStream()) {
53 AudioOutputStream
* AudioOutputDispatcher::StreamStarted() {
54 DCHECK_EQ(MessageLoop::current(), message_loop_
);
56 if (idle_streams_
.empty() && !CreateAndOpenStream()) {
60 AudioOutputStream
* stream
= idle_streams_
.back();
61 idle_streams_
.pop_back();
63 DCHECK_GT(paused_proxies_
, 0u);
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()));
75 void AudioOutputDispatcher::StreamStopped(AudioOutputStream
* stream
) {
76 DCHECK_EQ(MessageLoop::current(), message_loop_
);
80 pausing_streams_
.push_front(stream
);
82 // Don't recycle stream until two buffers worth of time has elapsed.
83 message_loop_
->PostDelayedTask(
85 base::Bind(&AudioOutputDispatcher::StopStreamTask
,
86 weak_this_
.GetWeakPtr()),
90 void AudioOutputDispatcher::StopStreamTask() {
91 DCHECK_EQ(MessageLoop::current(), message_loop_
);
93 if (pausing_streams_
.empty())
96 AudioOutputStream
* stream
= pausing_streams_
.back();
97 pausing_streams_
.pop_back();
98 idle_streams_
.push_back(stream
);
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);
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
127 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
129 AudioOutputStreamList::iterator it
= idle_streams_
.begin();
130 for (; it
!= idle_streams_
.end(); ++it
)
132 idle_streams_
.clear();
134 it
= pausing_streams_
.begin();
135 for (; it
!= pausing_streams_
.end(); ++it
)
137 pausing_streams_
.clear();
140 bool AudioOutputDispatcher::CreateAndOpenStream() {
141 AudioOutputStream
* stream
= audio_manager_
->MakeAudioOutputStream(params_
);
145 if (!stream
->Open()) {
149 idle_streams_
.push_back(stream
);
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();