1 // Copyright (c) 2011 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/compiler_specific.h"
8 #include "base/message_loop.h"
10 #include "media/audio/audio_io.h"
12 AudioOutputDispatcher::AudioOutputDispatcher(
13 AudioManager
* audio_manager
, const AudioParameters
& params
,
15 : audio_manager_(audio_manager
),
16 message_loop_(audio_manager
->GetMessageLoop()),
18 pause_delay_milliseconds_(2 * params
.samples_per_packet
*
19 base::Time::kMillisecondsPerSecond
/ params
.sample_rate
),
21 ALLOW_THIS_IN_INITIALIZER_LIST(close_timer_(
22 base::TimeDelta::FromMilliseconds(close_delay_ms
),
23 this, &AudioOutputDispatcher::ClosePendingStreams
)) {
26 AudioOutputDispatcher::~AudioOutputDispatcher() {
29 bool AudioOutputDispatcher::StreamOpened() {
30 DCHECK_EQ(MessageLoop::current(), message_loop_
);
33 // Ensure that there is at least one open stream.
34 if (idle_streams_
.empty() && !CreateAndOpenStream()) {
43 AudioOutputStream
* AudioOutputDispatcher::StreamStarted() {
44 DCHECK_EQ(MessageLoop::current(), message_loop_
);
46 if (idle_streams_
.empty() && !CreateAndOpenStream()) {
50 AudioOutputStream
* stream
= idle_streams_
.back();
51 idle_streams_
.pop_back();
53 DCHECK_GT(paused_proxies_
, 0u);
58 // Schedule task to allocate streams for other proxies if we need to.
59 message_loop_
->PostTask(FROM_HERE
, NewRunnableMethod(
60 this, &AudioOutputDispatcher::OpenTask
));
65 void AudioOutputDispatcher::StreamStopped(AudioOutputStream
* stream
) {
66 DCHECK_EQ(MessageLoop::current(), message_loop_
);
70 pausing_streams_
.push_front(stream
);
73 // Don't recycle stream until two buffers worth of time has elapsed.
74 message_loop_
->PostDelayedTask(
76 NewRunnableMethod(this, &AudioOutputDispatcher::StopStreamTask
),
77 pause_delay_milliseconds_
);
80 void AudioOutputDispatcher::StopStreamTask() {
81 if (pausing_streams_
.empty())
83 AudioOutputStream
* stream
= pausing_streams_
.back();
84 pausing_streams_
.pop_back();
85 idle_streams_
.push_back(stream
);
88 void AudioOutputDispatcher::StreamClosed() {
89 DCHECK_EQ(MessageLoop::current(), message_loop_
);
91 while (!pausing_streams_
.empty()) {
92 idle_streams_
.push_back(pausing_streams_
.back());
93 pausing_streams_
.pop_back();
96 DCHECK_GT(paused_proxies_
, 0u);
99 while (idle_streams_
.size() > paused_proxies_
) {
100 idle_streams_
.back()->Close();
101 idle_streams_
.pop_back();
105 MessageLoop
* AudioOutputDispatcher::message_loop() {
106 return message_loop_
;
109 bool AudioOutputDispatcher::CreateAndOpenStream() {
110 AudioOutputStream
* stream
=
111 audio_manager_
->MakeAudioOutputStream(params_
);
115 if (!stream
->Open()) {
119 idle_streams_
.push_back(stream
);
123 void AudioOutputDispatcher::OpenTask() {
124 // Make sure that we have at least one stream allocated if there
125 // are paused streams.
126 if (paused_proxies_
> 0 && idle_streams_
.empty() &&
127 pausing_streams_
.empty()) {
128 CreateAndOpenStream();
131 close_timer_
.Reset();
134 // This method is called by |close_timer_|.
135 void AudioOutputDispatcher::ClosePendingStreams() {
136 while (!idle_streams_
.empty()) {
137 idle_streams_
.back()->Close();
138 idle_streams_
.pop_back();