| 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 |