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

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 #include <utility>
8 9
9 #include "base/bind.h" 10 #include "base/bind.h"
10 #include "base/compiler_specific.h" 11 #include "base/compiler_specific.h"
11 #include "base/message_loop.h" 12 #include "base/message_loop.h"
12 #include "base/time.h" 13 #include "base/time.h"
13 #include "media/audio/audio_io.h" 14 #include "media/audio/audio_io.h"
14 #include "media/audio/audio_output_proxy.h" 15 #include "media/audio/audio_output_proxy.h"
15 #include "media/audio/audio_util.h" 16 #include "media/audio/audio_util.h"
16 17
17 namespace media { 18 namespace media {
(...skipping 19 matching lines...) Expand all
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 buffer_data_.clear(); // 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
57 // May need to re-open the physical stream if no active proxies and 59 // May need to re-open the physical stream if no active proxies and
58 // enough time had pass. 60 // enough time had pass.
59 OpenStream(); 61 OpenStream();
60 if (!physical_stream_.get()) 62 if (!physical_stream_.get())
61 return false; 63 return false;
62 64
63 double volume = 0.0; 65 double volume = 0.0;
64 stream_proxy->GetVolume(&volume); 66 stream_proxy->GetVolume(&volume);
65 bool should_start = proxies_.empty(); 67 bool should_start = proxies_.empty();
66 { 68 {
67 base::AutoLock lock(lock_); 69 base::AutoLock lock(lock_);
68 ProxyData* proxy_data = &proxies_[stream_proxy]; 70 ProxyData* proxy_data = &proxies_[stream_proxy];
69 proxy_data->audio_source_callback = callback; 71 proxy_data->audio_source_callback = callback;
70 proxy_data->volume = volume; 72 proxy_data->volume = volume;
71 proxy_data->pending_bytes = 0; 73 proxy_data->pending_bytes = 0;
74 proxy_data->prebuffering = true;
72 } 75 }
73 // We cannot start physical stream under the lock, 76 // We cannot start physical stream under the lock,
74 // OnMoreData() would try acquiring it... 77 // OnMoreData() would try acquiring it...
75 if (should_start) { 78 if (should_start) {
76 physical_stream_->SetVolume(1.0); 79 physical_stream_->SetVolume(1.0);
77 physical_stream_->Start(this); 80 physical_stream_->Start(this);
78 } 81 }
79 return true; 82 return true;
80 } 83 }
81 84
82 void AudioOutputMixer::StopStream(AudioOutputProxy* stream_proxy) { 85 void AudioOutputMixer::StopStream(AudioOutputProxy* stream_proxy) {
83 DCHECK_EQ(MessageLoop::current(), message_loop_); 86 DCHECK_EQ(MessageLoop::current(), message_loop_);
84 87
85 // Because of possible deadlock we cannot stop physical stream under the lock 88 // Because of possible deadlock we cannot stop physical stream under the lock
86 // (physical_stream_->Stop() can call OnError(), and it acquires the lock to 89 // (physical_stream_->Stop() can call OnError(), and it acquires the lock to
87 // iterate through proxies), so acquire the lock, update proxy list, release 90 // iterate through proxies), so acquire the lock, update proxy list, release
88 // the lock, and only then stop physical stream if necessary. 91 // the lock, and only then stop physical stream if necessary.
89 bool stop_physical_stream = false; 92 bool stop_physical_stream = false;
90 { 93 {
91 base::AutoLock lock(lock_); 94 base::AutoLock lock(lock_);
92 ProxyMap::iterator it = proxies_.find(stream_proxy); 95 ProxyMap::iterator it = proxies_.find(stream_proxy);
93 if (it != proxies_.end()) { 96 if (it != proxies_.end()) {
94 proxies_.erase(it); 97 proxies_.erase(it);
95 stop_physical_stream = proxies_.empty(); 98 stop_physical_stream = proxies_.empty();
96 } 99 }
97 } 100 }
98 if (physical_stream_.get()) { 101 if (physical_stream_.get()) {
99 if (stop_physical_stream) 102 if (stop_physical_stream) {
100 physical_stream_->Stop(); 103 physical_stream_->Stop();
104 buffer_data_.clear(); // Just in case.
105 }
101 close_timer_.Reset(); 106 close_timer_.Reset();
102 } 107 }
103 } 108 }
104 109
105 void AudioOutputMixer::StreamVolumeSet(AudioOutputProxy* stream_proxy, 110 void AudioOutputMixer::StreamVolumeSet(AudioOutputProxy* stream_proxy,
106 double volume) { 111 double volume) {
107 DCHECK_EQ(MessageLoop::current(), message_loop_); 112 DCHECK_EQ(MessageLoop::current(), message_loop_);
108 113
109 ProxyMap::iterator it = proxies_.find(stream_proxy); 114 ProxyMap::iterator it = proxies_.find(stream_proxy);
110 115
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 uint32 AudioOutputMixer::OnMoreData(uint8* dest, 153 uint32 AudioOutputMixer::OnMoreData(uint8* dest,
149 uint32 max_size, 154 uint32 max_size,
150 AudioBuffersState buffers_state) { 155 AudioBuffersState buffers_state) {
151 max_size = std::min(max_size, 156 max_size = std::min(max_size,
152 static_cast<uint32>(params_.GetBytesPerBuffer())); 157 static_cast<uint32>(params_.GetBytesPerBuffer()));
153 // TODO(enal): consider getting rid of lock as it is in time-critical code. 158 // 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 159 // E.g. swap |proxies_| with local variable, and merge 2 lists
155 // at the end. That would speed things up but complicate stopping 160 // at the end. That would speed things up but complicate stopping
156 // the stream. 161 // the stream.
157 base::AutoLock lock(lock_); 162 base::AutoLock lock(lock_);
163
164 // Did we see this buffer before?
vrk (LEFT CHROMIUM) 2012/04/26 00:54:57 For linux, I believe we will always have a unique
165 // If so, get lengths of released data, and delete buffer from the buffer map.
166 int bytes_released = 0;
167 BufferMap::iterator it = buffer_data_.find(dest);
168 if (it != buffer_data_.end()) {
169 bytes_released = it->second.length;
170 buffer_data_.erase(it);
171 }
158 if (proxies_.empty()) 172 if (proxies_.empty())
159 return 0; 173 return 0;
160 uint32 actual_total_size = 0; 174 uint32 actual_total_size = 0;
161 uint32 bytes_per_sample = params_.bits_per_sample() >> 3; 175 uint32 bytes_per_sample = params_.bits_per_sample() >> 3;
162 176
163 // Go through all the streams, getting data for every one of them 177 // Go through all the streams, getting data for every one of them
164 // and mixing it into destination. 178 // and mixing it into destination.
165 // Minor optimization: for the first stream we are writing data directly into 179 // 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 180 // 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. 181 // active stream, and net win in other cases, too.
168 bool first_stream = true; 182 bool first_stream = true;
169 uint8* actual_dest = dest; 183 uint8* actual_dest = dest;
170 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) { 184 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
171 ProxyData* proxy_data = &it->second; 185 ProxyData* proxy_data = &it->second;
172 // TODO(enal): We don't know |pending _bytes| for individual stream, and we 186
173 // should give that value to individual stream's OnMoreData(). I believe it 187 // Handle prebuffering:
174 // can be used there to evaluate exact position of data it should return. 188 // * If we already saw this buffer for this proxy, prebuffering is done,
175 // Current code "sorta works" if everything works perfectly, but would have 189 // proxy now is in the steady state.
176 // problems if some of the buffers are only partially filled -- we don't 190 // * Otherwise add buffer to the set for this proxy.
177 // know how how much data was in the buffer OS returned to us, so we cannot 191 if (proxy_data->prebuffering) {
178 // correctly calculate new value. If we know number of buffers we can solve 192 std::set<void*>::iterator it = proxy_data->buffers.find(dest);
179 // the problem by storing not one value but vector of them. 193 if (it != proxy_data->buffers.end()) {
180 int pending_bytes = std::min(proxy_data->pending_bytes, 194 // Release memory used by set, we don't need it anymore.
181 buffers_state.pending_bytes); 195 std::set<void*> empty;
196 empty.swap(proxy_data->buffers);
197 proxy_data->prebuffering = false;
198 } else {
199 proxy_data->buffers.insert(dest);
200 }
201 }
202 if (!proxy_data->prebuffering) {
203 proxy_data->pending_bytes -= bytes_released;
204 DCHECK_GE(proxy_data->pending_bytes, 0);
205 }
206
182 // Note: there is no way we can deduce hardware_delay_bytes for the 207 // Note: there is no way we can deduce hardware_delay_bytes for the
183 // particular proxy stream. Use zero instead. 208 // particular proxy stream. Use zero instead.
184 uint32 actual_size = proxy_data->audio_source_callback->OnMoreData( 209 uint32 actual_size = proxy_data->audio_source_callback->OnMoreData(
185 actual_dest, 210 actual_dest,
186 max_size, 211 max_size,
187 AudioBuffersState(pending_bytes, 0)); 212 AudioBuffersState(proxy_data->pending_bytes, 0));
188 213 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; 214 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 215
203 // No need to mix muted stream. 216 // No need to mix muted stream.
204 double volume = proxy_data->volume; 217 double volume = proxy_data->volume;
205 if (volume == 0.0) 218 if (volume == 0.0)
206 continue; 219 continue;
207 220
208 // Different handling for first and all subsequent streams. 221 // Different handling for first and all subsequent streams.
209 if (first_stream) { 222 if (first_stream) {
210 if (volume != 1.0) { 223 if (volume != 1.0) {
211 media::AdjustVolume(actual_dest, 224 media::AdjustVolume(actual_dest,
212 actual_size, 225 actual_size,
213 params_.channels(), 226 params_.channels(),
214 bytes_per_sample, 227 bytes_per_sample,
215 volume); 228 volume);
216 } 229 }
217 if (actual_size < max_size) 230 if (actual_size < max_size)
218 memset(dest + actual_size, 0, max_size - actual_size); 231 memset(dest + actual_size, 0, max_size - actual_size);
219 first_stream = false; 232 first_stream = false;
220 actual_dest = mixer_data_.get(); 233 actual_dest = mixer_data_.get();
221 actual_total_size = actual_size; 234 actual_total_size = actual_size;
222 } else { 235 } else {
223 media::MixStreams(dest, 236 media::MixStreams(dest,
224 actual_dest, 237 actual_dest,
225 actual_size, 238 actual_size,
226 bytes_per_sample, 239 bytes_per_sample,
227 volume); 240 volume);
228 actual_total_size = std::max(actual_size, actual_total_size); 241 actual_total_size = std::max(actual_size, actual_total_size);
229 } 242 }
230 } 243 }
244
245 // Now go through all proxies once again and increase pending_bytes
246 // for each proxy. Could not do it earlier because we did not know
247 // actual_total_size.
248 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
249 it->second.pending_bytes += actual_total_size;
250 }
251
252 buffer_data_.insert(
253 std::pair<void*, BufferData>(dest, BufferData(actual_total_size)));
254 DCHECK_LE(buffer_data_.size(), 5u);
231 return actual_total_size; 255 return actual_total_size;
232 } 256 }
233 257
234 void AudioOutputMixer::OnError(AudioOutputStream* stream, int code) { 258 void AudioOutputMixer::OnError(AudioOutputStream* stream, int code) {
235 base::AutoLock lock(lock_); 259 base::AutoLock lock(lock_);
236 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) { 260 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
237 it->second.audio_source_callback->OnError(it->first, code); 261 it->second.audio_source_callback->OnError(it->first, code);
238 } 262 }
239 } 263 }
240 264
241 void AudioOutputMixer::WaitTillDataReady() { 265 void AudioOutputMixer::WaitTillDataReady() {
242 base::AutoLock lock(lock_); 266 base::AutoLock lock(lock_);
243 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) { 267 for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
244 it->second.audio_source_callback->WaitTillDataReady(); 268 it->second.audio_source_callback->WaitTillDataReady();
245 } 269 }
246 } 270 }
247 271
248 } // namespace media 272 } // 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