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"
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"
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())),
28 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
29 close_timer_(FROM_HERE
,
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_
);
46 // Ensure that there is at least one open stream.
47 if (idle_streams_
.empty() && !CreateAndOpenStream()) {
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())
64 AudioOutputStream
* physical_stream
= idle_streams_
.back();
65 DCHECK(physical_stream
);
66 idle_streams_
.pop_back();
68 DCHECK_GT(paused_proxies_
, 0u);
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()));
78 stream_proxy
->GetVolume(&volume
);
79 physical_stream
->SetVolume(volume
);
80 physical_stream
->Start(callback
);
81 proxy_to_physical_map_
[stream_proxy
] = physical_stream
;
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();
97 pausing_streams_
.push_front(physical_stream
);
99 // Don't recycle stream until two buffers worth of time has elapsed.
100 message_loop_
->PostDelayedTask(
102 base::Bind(&AudioOutputDispatcherImpl::StopStreamTask
,
103 weak_this_
.GetWeakPtr()),
107 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy
* stream_proxy
,
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())
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);
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
154 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
156 AudioOutputStreamList::iterator it
= idle_streams_
.begin();
157 for (; it
!= idle_streams_
.end(); ++it
)
159 idle_streams_
.clear();
161 it
= pausing_streams_
.begin();
162 for (; it
!= pausing_streams_
.end(); ++it
)
164 pausing_streams_
.clear();
167 bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
168 DCHECK_EQ(MessageLoop::current(), message_loop_
);
169 AudioOutputStream
* stream
= audio_manager_
->MakeAudioOutputStream(params_
);
173 if (!stream
->Open()) {
177 idle_streams_
.push_back(stream
);
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();