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

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

Issue 10154007: Change the way audio mixer gets "pending bytes" (amount of data currently buffered (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 8 years, 7 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/audio_output_mixer.h" 5 #include "media/audio/audio_output_mixer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/message_loop.h" 11 #include "base/message_loop.h"
12 #include "base/time.h" 12 #include "base/time.h"
13 #include "media/audio/audio_io.h" 13 #include "media/audio/audio_io.h"
14 #include "media/audio/audio_output_proxy.h" 14 #include "media/audio/audio_output_proxy.h"
15 #include "media/audio/audio_util.h" 15 #include "media/audio/audio_util.h"
16 16
17 namespace media { 17 namespace media {
18 18
19 AudioOutputMixer::AudioOutputMixer(AudioManager* audio_manager, 19 AudioOutputMixer::AudioOutputMixer(AudioManager* audio_manager,
20 const AudioParameters& params, 20 const AudioParameters& params,
21 const base::TimeDelta& close_delay) 21 const base::TimeDelta& close_delay)
22 : AudioOutputDispatcher(audio_manager, params), 22 : AudioOutputDispatcher(audio_manager, params),
23 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)), 23 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
24 close_timer_(FROM_HERE, 24 close_timer_(FROM_HERE,
25 close_delay, 25 close_delay,
26 weak_this_.GetWeakPtr(), 26 weak_this_.GetWeakPtr(),
27 &AudioOutputMixer::ClosePhysicalStream) { 27 &AudioOutputMixer::ClosePhysicalStream),
28 pending_bytes_(0) {
28 // TODO(enal): align data. 29 // TODO(enal): align data.
29 mixer_data_.reset(new uint8[params_.GetBytesPerBuffer()]); 30 mixer_data_.reset(new uint8[params_.GetBytesPerBuffer()]);
30 } 31 }
31 32
32 AudioOutputMixer::~AudioOutputMixer() { 33 AudioOutputMixer::~AudioOutputMixer() {
33 } 34 }
34 35
35 bool AudioOutputMixer::OpenStream() { 36 bool AudioOutputMixer::OpenStream() {
36 DCHECK_EQ(MessageLoop::current(), message_loop_); 37 DCHECK_EQ(MessageLoop::current(), message_loop_);
37 38
38 if (physical_stream_.get()) 39 if (physical_stream_.get())
39 return true; 40 return true;
40 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_); 41 AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_);
41 if (!stream) 42 if (!stream)
42 return false; 43 return false;
43 if (!stream->Open()) { 44 if (!stream->Open()) {
44 stream->Close(); 45 stream->Close();
45 return false; 46 return false;
46 } 47 }
48 pending_bytes_ = 0; // Just in case.
47 physical_stream_.reset(stream); 49 physical_stream_.reset(stream);
48 close_timer_.Reset(); 50 close_timer_.Reset();
49 return true; 51 return true;
50 } 52 }
51 53
52 bool AudioOutputMixer::StartStream( 54 bool AudioOutputMixer::StartStream(
53 AudioOutputStream::AudioSourceCallback* callback, 55 AudioOutputStream::AudioSourceCallback* callback,
54 AudioOutputProxy* stream_proxy) { 56 AudioOutputProxy* stream_proxy) {
55 DCHECK_EQ(MessageLoop::current(), message_loop_); 57 DCHECK_EQ(MessageLoop::current(), message_loop_);
56 58
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 bool stop_physical_stream = false; 91 bool stop_physical_stream = false;
90 { 92 {
91 base::AutoLock lock(lock_); 93 base::AutoLock lock(lock_);
92 ProxyMap::iterator it = proxies_.find(stream_proxy); 94 ProxyMap::iterator it = proxies_.find(stream_proxy);
93 if (it != proxies_.end()) { 95 if (it != proxies_.end()) {
94 proxies_.erase(it); 96 proxies_.erase(it);
95 stop_physical_stream = proxies_.empty(); 97 stop_physical_stream = proxies_.empty();
96 } 98 }
97 } 99 }
98 if (physical_stream_.get()) { 100 if (physical_stream_.get()) {
99 if (stop_physical_stream) 101 if (stop_physical_stream) {
100 physical_stream_->Stop(); 102 physical_stream_->Stop();
103 pending_bytes_ = 0; // Just in case.
104 }
101 close_timer_.Reset(); 105 close_timer_.Reset();
102 } 106 }
103 } 107 }
104 108
105 void AudioOutputMixer::StreamVolumeSet(AudioOutputProxy* stream_proxy, 109 void AudioOutputMixer::StreamVolumeSet(AudioOutputProxy* stream_proxy,
106 double volume) { 110 double volume) {
107 DCHECK_EQ(MessageLoop::current(), message_loop_); 111 DCHECK_EQ(MessageLoop::current(), message_loop_);
108 112
109 ProxyMap::iterator it = proxies_.find(stream_proxy); 113 ProxyMap::iterator it = proxies_.find(stream_proxy);
110 114
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 uint32 AudioOutputMixer::OnMoreData(uint8* dest, 152 uint32 AudioOutputMixer::OnMoreData(uint8* dest,
149 uint32 max_size, 153 uint32 max_size,
150 AudioBuffersState buffers_state) { 154 AudioBuffersState buffers_state) {
151 max_size = std::min(max_size, 155 max_size = std::min(max_size,
152 static_cast<uint32>(params_.GetBytesPerBuffer())); 156 static_cast<uint32>(params_.GetBytesPerBuffer()));
153 // TODO(enal): consider getting rid of lock as it is in time-critical code. 157 // TODO(enal): consider getting rid of lock as it is in time-critical code.
154 // E.g. swap |proxies_| with local variable, and merge 2 lists 158 // E.g. swap |proxies_| with local variable, and merge 2 lists
155 // at the end. That would speed things up but complicate stopping 159 // at the end. That would speed things up but complicate stopping
156 // the stream. 160 // the stream.
157 base::AutoLock lock(lock_); 161 base::AutoLock lock(lock_);
158 if (proxies_.empty()) 162
163 DCHECK_GE(pending_bytes_, buffers_state.pending_bytes);
164 if (proxies_.empty()) {
165 pending_bytes_ = buffers_state.pending_bytes;
159 return 0; 166 return 0;
167 }
160 uint32 actual_total_size = 0; 168 uint32 actual_total_size = 0;
161 uint32 bytes_per_sample = params_.bits_per_sample() >> 3; 169 uint32 bytes_per_sample = params_.bits_per_sample() >> 3;
162 170
163 // Go through all the streams, getting data for every one of them 171 // Go through all the streams, getting data for every one of them
164 // and mixing it into destination. 172 // and mixing it into destination.
165 // Minor optimization: for the first stream we are writing data directly into 173 // Minor optimization: for the first stream we are writing data directly into
166 // destination. This way we don't have to mix the data when there is only one 174 // destination. This way we don't have to mix the data when there is only one
167 // active stream, and net win in other cases, too. 175 // active stream, and net win in other cases, too.
168 bool first_stream = true; 176 bool first_stream = true;
169 uint8* actual_dest = dest; 177 uint8* actual_dest = dest;
170 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) { 178 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
171 ProxyData* proxy_data = &it->second; 179 ProxyData* proxy_data = &it->second;
172 // TODO(enal): We don't know |pending _bytes| for individual stream, and we 180
173 // should give that value to individual stream's OnMoreData(). I believe it 181 // If proxy's pending bytes are the same as pending bytes for combined
174 // can be used there to evaluate exact position of data it should return. 182 // stream, both are either pre-buffering or in the steady state. In either
175 // Current code "sorta works" if everything works perfectly, but would have 183 // case new pending bytes for proxy is the same as new pending bytes for
176 // problems if some of the buffers are only partially filled -- we don't 184 // combined stream.
177 // know how how much data was in the buffer OS returned to us, so we cannot 185 // Note: use >= instead of ==, that way is safer.
178 // correctly calculate new value. If we know number of buffers we can solve 186 if (proxy_data->pending_bytes >= pending_bytes_)
179 // the problem by storing not one value but vector of them. 187 proxy_data->pending_bytes = buffers_state.pending_bytes;
180 int pending_bytes = std::min(proxy_data->pending_bytes, 188
181 buffers_state.pending_bytes);
182 // Note: there is no way we can deduce hardware_delay_bytes for the 189 // Note: there is no way we can deduce hardware_delay_bytes for the
183 // particular proxy stream. Use zero instead. 190 // particular proxy stream. Use zero instead.
184 uint32 actual_size = proxy_data->audio_source_callback->OnMoreData( 191 uint32 actual_size = proxy_data->audio_source_callback->OnMoreData(
185 actual_dest, 192 actual_dest,
186 max_size, 193 max_size,
187 AudioBuffersState(pending_bytes, 0)); 194 AudioBuffersState(proxy_data->pending_bytes, 0));
188 195 if (actual_size == 0)
189 // Should update pending_bytes for each proxy.
190 // If stream ended, pending_bytes goes down by max_size.
191 if (actual_size == 0) {
192 pending_bytes -= max_size;
193 proxy_data->pending_bytes = std::max(pending_bytes, 0);
194 continue; 196 continue;
195 }
196
197 // Otherwise, it goes up by amount of data. It cannot exceed max amount of
198 // data we can buffer, but we don't know that value. So we increment
199 // pending_bytes unconditionally but adjust it before actual use (which
200 // would be on a next OnMoreData() call).
201 proxy_data->pending_bytes = pending_bytes + actual_size;
202 197
203 // No need to mix muted stream. 198 // No need to mix muted stream.
204 double volume = proxy_data->volume; 199 double volume = proxy_data->volume;
205 if (volume == 0.0) 200 if (volume == 0.0)
206 continue; 201 continue;
207 202
208 // Different handling for first and all subsequent streams. 203 // Different handling for first and all subsequent streams.
209 if (first_stream) { 204 if (first_stream) {
210 if (volume != 1.0) { 205 if (volume != 1.0) {
211 media::AdjustVolume(actual_dest, 206 media::AdjustVolume(actual_dest,
212 actual_size, 207 actual_size,
213 params_.channels(), 208 params_.channels(),
214 bytes_per_sample, 209 bytes_per_sample,
215 volume); 210 volume);
216 } 211 }
217 if (actual_size < max_size) 212 if (actual_size < max_size)
218 memset(dest + actual_size, 0, max_size - actual_size); 213 memset(dest + actual_size, 0, max_size - actual_size);
219 first_stream = false; 214 first_stream = false;
220 actual_dest = mixer_data_.get(); 215 actual_dest = mixer_data_.get();
221 actual_total_size = actual_size; 216 actual_total_size = actual_size;
222 } else { 217 } else {
223 media::MixStreams(dest, 218 media::MixStreams(dest,
224 actual_dest, 219 actual_dest,
225 actual_size, 220 actual_size,
226 bytes_per_sample, 221 bytes_per_sample,
227 volume); 222 volume);
228 actual_total_size = std::max(actual_size, actual_total_size); 223 actual_total_size = std::max(actual_size, actual_total_size);
229 } 224 }
230 } 225 }
226
227 // Now go through all proxies once again and increase pending_bytes
228 // for each proxy. Could not do it earlier because we did not know
229 // actual_total_size.
230 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
231 it->second.pending_bytes += actual_total_size;
232 }
233 pending_bytes_ = buffers_state.pending_bytes + actual_total_size;
234
231 return actual_total_size; 235 return actual_total_size;
232 } 236 }
233 237
234 void AudioOutputMixer::OnError(AudioOutputStream* stream, int code) { 238 void AudioOutputMixer::OnError(AudioOutputStream* stream, int code) {
235 base::AutoLock lock(lock_); 239 base::AutoLock lock(lock_);
236 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) { 240 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
237 it->second.audio_source_callback->OnError(it->first, code); 241 it->second.audio_source_callback->OnError(it->first, code);
238 } 242 }
239 } 243 }
240 244
241 void AudioOutputMixer::WaitTillDataReady() { 245 void AudioOutputMixer::WaitTillDataReady() {
242 base::AutoLock lock(lock_); 246 base::AutoLock lock(lock_);
243 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) { 247 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
244 it->second.audio_source_callback->WaitTillDataReady(); 248 it->second.audio_source_callback->WaitTillDataReady();
245 } 249 }
246 } 250 }
247 251
248 } // namespace media 252 } // 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