Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: media/audio/audio_output_dispatcher_impl.cc

Issue 9691001: Audio software mixer. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "media/audio/audio_output_dispatcher_impl.h"
6
7 #include <algorithm>
8
9 #include "base/bind.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"
16
17 AudioOutputDispatcherImpl::AudioOutputDispatcherImpl(
18 AudioManager* audio_manager,
19 const AudioParameters& params,
20 const base::TimeDelta& close_delay)
21 : AudioOutputDispatcher(audio_manager, params),
22 pause_delay_(base::TimeDelta::FromMilliseconds(
23 2 * params.frames_per_buffer() *
24 base::Time::kMillisecondsPerSecond / params.sample_rate())),
25 paused_proxies_(0),
26 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
27 close_timer_(FROM_HERE,
28 close_delay,
29 weak_this_.GetWeakPtr(),
30 &AudioOutputDispatcherImpl::ClosePendingStreams) {
31 }
32
33 AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() {
34 DCHECK(proxy_to_physical_map_.empty());
35 }
36
37 bool AudioOutputDispatcherImpl::OpenStream() {
38 DCHECK_EQ(MessageLoop::current(), message_loop_);
39
40 paused_proxies_++;
41
42 // Ensure that there is at least one open stream.
43 if (idle_streams_.empty() && !CreateAndOpenStream())
44 return false;
45
46 close_timer_.Reset();
47 return true;
48 }
49
50 bool AudioOutputDispatcherImpl::StartStream(
51 AudioOutputStream::AudioSourceCallback* callback,
52 AudioOutputProxy* stream_proxy) {
53 DCHECK_EQ(MessageLoop::current(), message_loop_);
54
55 if (idle_streams_.empty() && !CreateAndOpenStream())
56 return false;
57
58 AudioOutputStream* physical_stream = idle_streams_.back();
59 DCHECK_NE(static_cast<AudioOutputStream*>(NULL), physical_stream);
vrk (LEFT CHROMIUM) 2012/04/06 23:37:05 DCHECK(physical_stream)?
enal1 2012/04/16 22:01:35 Done.
60 idle_streams_.pop_back();
61
62 DCHECK_GT(paused_proxies_, 0u);
63 --paused_proxies_;
64
65 close_timer_.Reset();
66
67 // Schedule task to allocate streams for other proxies if we need to.
68 message_loop_->PostTask(FROM_HERE, base::Bind(
69 &AudioOutputDispatcherImpl::OpenTask, weak_this_.GetWeakPtr()));
70
71 double volume = 0;
72 stream_proxy->GetVolume(&volume);
73 physical_stream->SetVolume(volume);
74 physical_stream->Start(callback);
75 proxy_to_physical_map_[stream_proxy] = physical_stream;
76 return true;
77 }
78
79 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
80 DCHECK_EQ(MessageLoop::current(), message_loop_);
81
82 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
83 DCHECK(it != proxy_to_physical_map_.end());
84 AudioOutputStream* physical_stream = it->second;
85 proxy_to_physical_map_.erase(it);
86
87 DCHECK_NE(static_cast<AudioOutputStream*>(NULL), physical_stream);
vrk (LEFT CHROMIUM) 2012/04/06 23:37:05 Remove DCHECK: doing a null DCHECK before usage is
enal1 2012/04/16 22:01:35 Done.
88 physical_stream->Stop();
89
90 ++paused_proxies_;
91
92 pausing_streams_.push_front(physical_stream);
93
94 // Don't recycle stream until two buffers worth of time has elapsed.
95 message_loop_->PostDelayedTask(
96 FROM_HERE,
97 base::Bind(&AudioOutputDispatcherImpl::StopStreamTask,
98 weak_this_.GetWeakPtr()),
99 pause_delay_);
100 }
101
102 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy,
103 double volume) {
104 DCHECK_EQ(MessageLoop::current(), message_loop_);
105 AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
106 if (it != proxy_to_physical_map_.end()) {
107 AudioOutputStream* physical_stream = it->second;
108 physical_stream->SetVolume(volume);
109 }
110 }
111
112 void AudioOutputDispatcherImpl::StopStreamTask() {
113 DCHECK_EQ(MessageLoop::current(), message_loop_);
114
115 if (pausing_streams_.empty())
116 return;
117
118 AudioOutputStream* stream = pausing_streams_.back();
119 pausing_streams_.pop_back();
120 idle_streams_.push_back(stream);
121 close_timer_.Reset();
122 }
123
124 void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) {
125 DCHECK_EQ(MessageLoop::current(), message_loop_);
126
127 while (!pausing_streams_.empty()) {
128 idle_streams_.push_back(pausing_streams_.back());
129 pausing_streams_.pop_back();
130 }
131
132 DCHECK_GT(paused_proxies_, 0u);
133 paused_proxies_--;
134
135 while (idle_streams_.size() > paused_proxies_) {
136 idle_streams_.back()->Close();
137 idle_streams_.pop_back();
138 }
139 }
140
141 void AudioOutputDispatcherImpl::Shutdown() {
142 DCHECK_EQ(MessageLoop::current(), message_loop_);
143
144 // Cancel any pending tasks to close paused streams or create new ones.
145 weak_this_.InvalidateWeakPtrs();
146
147 // No AudioOutputProxy objects should hold a reference to us when we get
148 // to this stage.
149 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
150
151 AudioOutputStreamList::iterator it = idle_streams_.begin();
152 for (; it != idle_streams_.end(); ++it)
153 (*it)->Close();
154 idle_streams_.clear();
155
156 it = pausing_streams_.begin();
157 for (; it != pausing_streams_.end(); ++it)
158 (*it)->Close();
159 pausing_streams_.clear();
vrk (LEFT CHROMIUM) 2012/04/06 23:37:05 Do you need to clear the proxy_to_physical_map_ so
enal1 2012/04/16 22:01:35 StopStream() removes physical stream from the map.
160 }
161
162 bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
163 DCHECK_EQ(MessageLoop::current(), message_loop_);
164 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_);
165 if (!stream)
166 return false;
167
168 if (!stream->Open()) {
169 stream->Close();
170 return false;
171 }
172 idle_streams_.push_back(stream);
173 return true;
174 }
175
176 void AudioOutputDispatcherImpl::OpenTask() {
177 DCHECK_EQ(MessageLoop::current(), message_loop_);
178 // Make sure that we have at least one stream allocated if there
179 // are paused streams.
180 if (paused_proxies_ > 0 && idle_streams_.empty() &&
181 pausing_streams_.empty()) {
182 CreateAndOpenStream();
183 }
184
185 close_timer_.Reset();
186 }
187
188 // This method is called by |close_timer_|.
189 void AudioOutputDispatcherImpl::ClosePendingStreams() {
190 DCHECK_EQ(MessageLoop::current(), message_loop_);
191 while (!idle_streams_.empty()) {
192 idle_streams_.back()->Close();
193 idle_streams_.pop_back();
194 }
195 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698