OLD | NEW |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |