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

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

Issue 12082111: Delete AudioOutputMixer. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix .gyp Created 7 years, 10 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
« no previous file with comments | « media/audio/audio_output_mixer.h ('k') | media/audio/audio_output_proxy_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_mixer.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 namespace media {
18
19 AudioOutputMixer::AudioOutputMixer(AudioManager* audio_manager,
20 const AudioParameters& params,
21 const base::TimeDelta& close_delay)
22 : AudioOutputDispatcher(audio_manager, params),
23 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
24 close_timer_(FROM_HERE,
25 close_delay,
26 weak_this_.GetWeakPtr(),
27 &AudioOutputMixer::ClosePhysicalStream),
28 pending_bytes_(0) {
29 // TODO(enal): align data.
30 mixer_data_.reset(new uint8[params_.GetBytesPerBuffer()]);
31 }
32
33 AudioOutputMixer::~AudioOutputMixer() {
34 }
35
36 bool AudioOutputMixer::OpenStream() {
37 DCHECK_EQ(MessageLoop::current(), message_loop_);
38
39 if (physical_stream_.get())
40 return true;
41 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_);
42 if (!stream)
43 return false;
44 if (!stream->Open()) {
45 stream->Close();
46 return false;
47 }
48 pending_bytes_ = 0; // Just in case.
49 physical_stream_.reset(stream);
50 close_timer_.Reset();
51 return true;
52 }
53
54 bool AudioOutputMixer::StartStream(
55 AudioOutputStream::AudioSourceCallback* callback,
56 AudioOutputProxy* stream_proxy) {
57 DCHECK_EQ(MessageLoop::current(), message_loop_);
58
59 // May need to re-open the physical stream if no active proxies and
60 // enough time had pass.
61 OpenStream();
62 if (!physical_stream_.get())
63 return false;
64
65 double volume = 0.0;
66 stream_proxy->GetVolume(&volume);
67 bool should_start = proxies_.empty();
68 {
69 base::AutoLock lock(lock_);
70 ProxyData* proxy_data = &proxies_[stream_proxy];
71 proxy_data->audio_source_callback = callback;
72 proxy_data->volume = volume;
73 proxy_data->pending_bytes = 0;
74 }
75 // We cannot start physical stream under the lock,
76 // OnMoreData() would try acquiring it...
77 if (should_start) {
78 physical_stream_->SetVolume(1.0);
79 physical_stream_->Start(this);
80 }
81 return true;
82 }
83
84 void AudioOutputMixer::StopStream(AudioOutputProxy* stream_proxy) {
85 DCHECK_EQ(MessageLoop::current(), message_loop_);
86
87 // Because of possible deadlock we cannot stop physical stream under the lock
88 // (physical_stream_->Stop() can call OnError(), and it acquires the lock to
89 // iterate through proxies), so acquire the lock, update proxy list, release
90 // the lock, and only then stop physical stream if necessary.
91 bool stop_physical_stream = false;
92 {
93 base::AutoLock lock(lock_);
94 ProxyMap::iterator it = proxies_.find(stream_proxy);
95 if (it != proxies_.end()) {
96 proxies_.erase(it);
97 stop_physical_stream = proxies_.empty();
98 }
99 }
100 if (physical_stream_.get()) {
101 if (stop_physical_stream) {
102 physical_stream_->Stop();
103 pending_bytes_ = 0; // Just in case.
104 }
105 close_timer_.Reset();
106 }
107 }
108
109 void AudioOutputMixer::StreamVolumeSet(AudioOutputProxy* stream_proxy,
110 double volume) {
111 DCHECK_EQ(MessageLoop::current(), message_loop_);
112
113 ProxyMap::iterator it = proxies_.find(stream_proxy);
114
115 // Do nothing if stream is not currently playing.
116 if (it != proxies_.end()) {
117 base::AutoLock lock(lock_);
118 it->second.volume = volume;
119 }
120 }
121
122 void AudioOutputMixer::CloseStream(AudioOutputProxy* stream_proxy) {
123 DCHECK_EQ(MessageLoop::current(), message_loop_);
124
125 StopStream(stream_proxy);
126 }
127
128 void AudioOutputMixer::Shutdown() {
129 DCHECK_EQ(MessageLoop::current(), message_loop_);
130
131 // Cancel any pending tasks to close physical stream.
132 weak_this_.InvalidateWeakPtrs();
133
134 while (!proxies_.empty()) {
135 CloseStream(proxies_.begin()->first);
136 }
137 ClosePhysicalStream();
138
139 // No AudioOutputProxy objects should hold a reference to us when we get
140 // to this stage.
141 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
142 }
143
144 void AudioOutputMixer::ClosePhysicalStream() {
145 DCHECK_EQ(MessageLoop::current(), message_loop_);
146
147 if (proxies_.empty() && physical_stream_.get() != NULL)
148 physical_stream_.release()->Close();
149 }
150
151 // AudioSourceCallback implementation.
152 uint32 AudioOutputMixer::OnMoreData(uint8* dest,
153 uint32 max_size,
154 AudioBuffersState buffers_state) {
155 max_size = std::min(max_size,
156 static_cast<uint32>(params_.GetBytesPerBuffer()));
157 // TODO(enal): consider getting rid of lock as it is in time-critical code.
158 // E.g. swap |proxies_| with local variable, and merge 2 lists
159 // at the end. That would speed things up but complicate stopping
160 // the stream.
161 base::AutoLock lock(lock_);
162
163 DCHECK_GE(pending_bytes_, buffers_state.pending_bytes);
164 if (proxies_.empty()) {
165 pending_bytes_ = buffers_state.pending_bytes;
166 return 0;
167 }
168 uint32 actual_total_size = 0;
169 uint32 bytes_per_sample = params_.bits_per_sample() >> 3;
170
171 // Go through all the streams, getting data for every one of them
172 // and mixing it into destination.
173 // Minor optimization: for the first stream we are writing data directly into
174 // destination. This way we don't have to mix the data when there is only one
175 // active stream, and net win in other cases, too.
176 bool first_stream = true;
177 uint8* actual_dest = dest;
178 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
179 ProxyData* proxy_data = &it->second;
180
181 // If proxy's pending bytes are the same as pending bytes for combined
182 // stream, both are either pre-buffering or in the steady state. In either
183 // case new pending bytes for proxy is the same as new pending bytes for
184 // combined stream.
185 // Note: use >= instead of ==, that way is safer.
186 if (proxy_data->pending_bytes >= pending_bytes_)
187 proxy_data->pending_bytes = buffers_state.pending_bytes;
188
189 // Note: there is no way we can deduce hardware_delay_bytes for the
190 // particular proxy stream. Use zero instead.
191 uint32 actual_size = proxy_data->audio_source_callback->OnMoreData(
192 actual_dest,
193 max_size,
194 AudioBuffersState(proxy_data->pending_bytes, 0));
195 if (actual_size == 0)
196 continue;
197 double volume = proxy_data->volume;
198
199 // Different handling for first and all subsequent streams.
200 if (first_stream) {
201 if (volume != 1.0) {
202 media::AdjustVolume(actual_dest,
203 actual_size,
204 params_.channels(),
205 bytes_per_sample,
206 volume);
207 }
208 if (actual_size < max_size)
209 memset(dest + actual_size, 0, max_size - actual_size);
210 first_stream = false;
211 actual_dest = mixer_data_.get();
212 actual_total_size = actual_size;
213 } else {
214 media::MixStreams(dest,
215 actual_dest,
216 actual_size,
217 bytes_per_sample,
218 volume);
219 actual_total_size = std::max(actual_size, actual_total_size);
220 }
221 }
222
223 // Now go through all proxies once again and increase pending_bytes
224 // for each proxy. Could not do it earlier because we did not know
225 // actual_total_size.
226 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
227 it->second.pending_bytes += actual_total_size;
228 }
229 pending_bytes_ = buffers_state.pending_bytes + actual_total_size;
230
231 return actual_total_size;
232 }
233
234 void AudioOutputMixer::OnError(AudioOutputStream* stream, int code) {
235 base::AutoLock lock(lock_);
236 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
237 it->second.audio_source_callback->OnError(it->first, code);
238 }
239 }
240
241 void AudioOutputMixer::WaitTillDataReady() {
242 base::AutoLock lock(lock_);
243 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
244 it->second.audio_source_callback->WaitTillDataReady();
245 }
246 }
247
248 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_output_mixer.h ('k') | media/audio/audio_output_proxy_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698