Chromium Code Reviews| 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_resampler.h" | 5 #include "media/audio/audio_output_resampler.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.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/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "base/time.h" | 13 #include "base/time.h" |
| 14 #include "media/audio/audio_io.h" | 14 #include "media/audio/audio_io.h" |
| 15 #include "media/audio/audio_output_dispatcher_impl.h" | 15 #include "media/audio/audio_output_dispatcher_impl.h" |
| 16 #include "media/audio/audio_output_proxy.h" | 16 #include "media/audio/audio_output_proxy.h" |
| 17 #include "media/audio/audio_util.h" | 17 #include "media/audio/audio_util.h" |
| 18 #include "media/audio/sample_rates.h" | 18 #include "media/audio/sample_rates.h" |
| 19 #include "media/base/audio_pull_fifo.h" | 19 #include "media/base/audio_transform.h" |
| 20 #include "media/base/channel_mixer.h" | |
| 21 #include "media/base/limits.h" | 20 #include "media/base/limits.h" |
| 22 #include "media/base/media_switches.h" | 21 #include "media/base/media_switches.h" |
| 23 #include "media/base/multi_channel_resampler.h" | |
| 24 | 22 |
| 25 namespace media { | 23 namespace media { |
| 26 | 24 |
| 27 class OnMoreDataResampler : public AudioOutputStream::AudioSourceCallback { | 25 class OnMoreDataConverter |
| 26 : public AudioOutputStream::AudioSourceCallback, | |
| 27 public AudioConverter::InputCallback { | |
| 28 public: | 28 public: |
| 29 OnMoreDataResampler(double io_ratio, | 29 OnMoreDataConverter(const AudioParameters& input_params, |
| 30 const AudioParameters& input_params, | |
| 31 const AudioParameters& output_params); | 30 const AudioParameters& output_params); |
| 32 virtual ~OnMoreDataResampler(); | 31 virtual ~OnMoreDataConverter(); |
| 33 | 32 |
| 34 // AudioSourceCallback interface. | 33 // AudioSourceCallback interface. |
| 35 virtual int OnMoreData(AudioBus* dest, | 34 virtual int OnMoreData(AudioBus* dest, |
| 36 AudioBuffersState buffers_state) OVERRIDE; | 35 AudioBuffersState buffers_state) OVERRIDE; |
| 37 virtual int OnMoreIOData(AudioBus* source, | 36 virtual int OnMoreIOData(AudioBus* source, |
| 38 AudioBus* dest, | 37 AudioBus* dest, |
| 39 AudioBuffersState buffers_state) OVERRIDE; | 38 AudioBuffersState buffers_state) OVERRIDE; |
| 40 virtual void OnError(AudioOutputStream* stream, int code) OVERRIDE; | 39 virtual void OnError(AudioOutputStream* stream, int code) OVERRIDE; |
| 41 virtual void WaitTillDataReady() OVERRIDE; | 40 virtual void WaitTillDataReady() OVERRIDE; |
| 42 | 41 |
| 43 // Sets |source_callback_|. If this is not a new object, then Stop() must be | 42 // Sets |source_callback_|. If this is not a new object, then Stop() must be |
| 44 // called before Start(). | 43 // called before Start(). |
| 45 void Start(AudioOutputStream::AudioSourceCallback* callback); | 44 void Start(AudioOutputStream::AudioSourceCallback* callback); |
| 46 | 45 |
| 47 // Clears |source_callback_| and flushes the resampler. | 46 // Clears |source_callback_| and flushes the resampler. |
| 48 void Stop(); | 47 void Stop(); |
| 49 | 48 |
| 50 private: | 49 private: |
| 51 // Called by MultiChannelResampler when more data is necessary. | 50 // AudioConverter::InputCallback implementation. |
| 52 void ProvideInput(AudioBus* audio_bus); | 51 virtual double ProvideInput(AudioBus* audio_bus, |
| 53 | 52 base::TimeDelta buffer_delay) OVERRIDE; |
| 54 // Called by AudioPullFifo when more data is necessary. Requires | |
| 55 // |source_lock_| to have been acquired. | |
| 56 void SourceCallback_Locked(AudioBus* audio_bus); | |
| 57 | |
| 58 // Passes through |source| to the |source_callback_| OnMoreIOData() call. | |
| 59 void SourceIOCallback_Locked(AudioBus* source, AudioBus* dest); | |
| 60 | 53 |
| 61 // Ratio of input bytes to output bytes used to correct playback delay with | 54 // Ratio of input bytes to output bytes used to correct playback delay with |
| 62 // regard to buffering and resampling. | 55 // regard to buffering and resampling. |
| 63 double io_ratio_; | 56 double io_ratio_; |
| 64 | 57 |
| 65 // Source callback and associated lock. | 58 // Source callback and associated lock. |
| 66 base::Lock source_lock_; | 59 base::Lock source_lock_; |
| 67 AudioOutputStream::AudioSourceCallback* source_callback_; | 60 AudioOutputStream::AudioSourceCallback* source_callback_; |
| 68 | 61 |
| 62 // |source| passed to OnMoreIOData() which should be passed downstream. | |
| 63 AudioBus* source_bus_; | |
| 64 | |
| 69 // Last AudioBuffersState object received via OnMoreData(), used to correct | 65 // Last AudioBuffersState object received via OnMoreData(), used to correct |
| 70 // playback delay by ProvideInput() and passed on to |source_callback_|. | 66 // playback delay by ProvideInput() and passed on to |source_callback_|. |
| 71 AudioBuffersState current_buffers_state_; | 67 AudioBuffersState current_buffers_state_; |
| 72 | 68 |
| 73 // Total number of bytes (in terms of output parameters) stored in resampler | 69 const int input_bytes_per_second_; |
| 74 // or FIFO buffers which have not been sent to the audio device. | |
| 75 int outstanding_audio_bytes_; | |
| 76 | 70 |
| 77 // Used to buffer data between the client and the output device in cases where | 71 // Handles resampling, buffering, and channel mixing between input and output |
| 78 // the client buffer size is not the same as the output device buffer size. | 72 // parameters. |
| 79 // Bound to SourceCallback_Locked() so must only be used when |source_lock_| | 73 AudioConverter audio_converter_; |
| 80 // has already been acquired. | |
| 81 scoped_ptr<AudioPullFifo> audio_fifo_; | |
| 82 | 74 |
| 83 // Handles resampling. | 75 DISALLOW_COPY_AND_ASSIGN(OnMoreDataConverter); |
| 84 scoped_ptr<MultiChannelResampler> resampler_; | |
| 85 | |
| 86 // Handles channel transforms. |unmixed_audio_| is a temporary destination | |
| 87 // for audio data before it goes into the channel mixer. | |
| 88 scoped_ptr<ChannelMixer> channel_mixer_; | |
| 89 scoped_ptr<AudioBus> unmixed_audio_; | |
| 90 | |
| 91 int output_bytes_per_frame_; | |
| 92 int input_bytes_per_frame_; | |
| 93 | |
| 94 // Since resampling is expensive, figure out if we should downmix channels | |
| 95 // before resampling. | |
| 96 bool downmix_early_; | |
| 97 | |
| 98 DISALLOW_COPY_AND_ASSIGN(OnMoreDataResampler); | |
| 99 }; | 76 }; |
| 100 | 77 |
| 101 // Record UMA statistics for hardware output configuration. | 78 // Record UMA statistics for hardware output configuration. |
| 102 static void RecordStats(const AudioParameters& output_params) { | 79 static void RecordStats(const AudioParameters& output_params) { |
| 103 UMA_HISTOGRAM_ENUMERATION( | 80 UMA_HISTOGRAM_ENUMERATION( |
| 104 "Media.HardwareAudioBitsPerChannel", output_params.bits_per_sample(), | 81 "Media.HardwareAudioBitsPerChannel", output_params.bits_per_sample(), |
| 105 limits::kMaxBitsPerSample); | 82 limits::kMaxBitsPerSample); |
| 106 UMA_HISTOGRAM_ENUMERATION( | 83 UMA_HISTOGRAM_ENUMERATION( |
| 107 "Media.HardwareAudioChannelLayout", output_params.channel_layout(), | 84 "Media.HardwareAudioChannelLayout", output_params.channel_layout(), |
| 108 CHANNEL_LAYOUT_MAX); | 85 CHANNEL_LAYOUT_MAX); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 163 AudioParameters::AUDIO_PCM_LINEAR, input_params.channel_layout(), | 140 AudioParameters::AUDIO_PCM_LINEAR, input_params.channel_layout(), |
| 164 input_params.sample_rate(), input_params.bits_per_sample(), | 141 input_params.sample_rate(), input_params.bits_per_sample(), |
| 165 frames_per_buffer); | 142 frames_per_buffer); |
| 166 } | 143 } |
| 167 | 144 |
| 168 AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager, | 145 AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager, |
| 169 const AudioParameters& input_params, | 146 const AudioParameters& input_params, |
| 170 const AudioParameters& output_params, | 147 const AudioParameters& output_params, |
| 171 const base::TimeDelta& close_delay) | 148 const base::TimeDelta& close_delay) |
| 172 : AudioOutputDispatcher(audio_manager, input_params), | 149 : AudioOutputDispatcher(audio_manager, input_params), |
| 173 io_ratio_(1), | |
| 174 close_delay_(close_delay), | 150 close_delay_(close_delay), |
| 175 output_params_(output_params), | 151 output_params_(output_params), |
| 176 streams_opened_(false) { | 152 streams_opened_(false) { |
| 177 DCHECK(input_params.IsValid()); | 153 DCHECK(input_params.IsValid()); |
| 178 DCHECK(output_params.IsValid()); | 154 DCHECK(output_params.IsValid()); |
| 179 DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY); | 155 DCHECK_EQ(output_params_.format(), AudioParameters::AUDIO_PCM_LOW_LATENCY); |
| 180 | 156 |
| 181 // Record UMA statistics for the hardware configuration. | 157 // Record UMA statistics for the hardware configuration. |
| 182 RecordStats(output_params); | 158 RecordStats(output_params); |
| 183 | 159 |
| 184 Initialize(); | 160 Initialize(); |
| 185 } | 161 } |
| 186 | 162 |
| 187 AudioOutputResampler::~AudioOutputResampler() { | 163 AudioOutputResampler::~AudioOutputResampler() { |
| 188 DCHECK(callbacks_.empty()); | 164 DCHECK(callbacks_.empty()); |
| 189 } | 165 } |
| 190 | 166 |
| 191 void AudioOutputResampler::Initialize() { | 167 void AudioOutputResampler::Initialize() { |
| 192 DCHECK(!streams_opened_); | 168 DCHECK(!streams_opened_); |
| 193 DCHECK(callbacks_.empty()); | 169 DCHECK(callbacks_.empty()); |
| 194 | |
| 195 io_ratio_ = 1; | |
| 196 | |
| 197 // Only resample or rebuffer if the input parameters don't match the output | |
| 198 // parameters to avoid any unnecessary work. | |
| 199 if (params_.channels() != output_params_.channels() || | |
| 200 params_.sample_rate() != output_params_.sample_rate() || | |
| 201 params_.bits_per_sample() != output_params_.bits_per_sample() || | |
| 202 params_.frames_per_buffer() != output_params_.frames_per_buffer()) { | |
| 203 if (params_.sample_rate() != output_params_.sample_rate()) { | |
| 204 double io_sample_rate_ratio = params_.sample_rate() / | |
| 205 static_cast<double>(output_params_.sample_rate()); | |
| 206 // Include the I/O resampling ratio in our global I/O ratio. | |
| 207 io_ratio_ *= io_sample_rate_ratio; | |
| 208 } | |
| 209 | |
| 210 // Include bits per channel differences. | |
| 211 io_ratio_ *= static_cast<double>(params_.bits_per_sample()) / | |
| 212 output_params_.bits_per_sample(); | |
| 213 | |
| 214 // Include channel count differences. | |
| 215 io_ratio_ *= static_cast<double>(params_.channels()) / | |
| 216 output_params_.channels(); | |
| 217 | |
| 218 DVLOG(1) << "I/O ratio is " << io_ratio_; | |
| 219 } else { | |
| 220 DVLOG(1) << "Input and output params are the same; in pass-through mode."; | |
| 221 } | |
| 222 | |
| 223 // TODO(dalecurtis): All this code should be merged into AudioOutputMixer once | |
| 224 // we've stabilized the issues there. | |
| 225 dispatcher_ = new AudioOutputDispatcherImpl( | 170 dispatcher_ = new AudioOutputDispatcherImpl( |
| 226 audio_manager_, output_params_, close_delay_); | 171 audio_manager_, output_params_, close_delay_); |
| 227 } | 172 } |
| 228 | 173 |
| 229 bool AudioOutputResampler::OpenStream() { | 174 bool AudioOutputResampler::OpenStream() { |
| 230 DCHECK_EQ(MessageLoop::current(), message_loop_); | 175 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 231 | 176 |
| 232 if (dispatcher_->OpenStream()) { | 177 if (dispatcher_->OpenStream()) { |
| 233 // Only record the UMA statistic if we didn't fallback during construction | 178 // Only record the UMA statistic if we didn't fallback during construction |
| 234 // and only for the first stream we open. | 179 // and only for the first stream we open. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 267 | 212 |
| 268 // Retry, if this fails, there's nothing left to do but report the error back. | 213 // Retry, if this fails, there's nothing left to do but report the error back. |
| 269 return dispatcher_->OpenStream(); | 214 return dispatcher_->OpenStream(); |
| 270 } | 215 } |
| 271 | 216 |
| 272 bool AudioOutputResampler::StartStream( | 217 bool AudioOutputResampler::StartStream( |
| 273 AudioOutputStream::AudioSourceCallback* callback, | 218 AudioOutputStream::AudioSourceCallback* callback, |
| 274 AudioOutputProxy* stream_proxy) { | 219 AudioOutputProxy* stream_proxy) { |
| 275 DCHECK_EQ(MessageLoop::current(), message_loop_); | 220 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 276 | 221 |
| 277 OnMoreDataResampler* resampler_callback = NULL; | 222 OnMoreDataConverter* resampler_callback = NULL; |
| 278 CallbackMap::iterator it = callbacks_.find(stream_proxy); | 223 CallbackMap::iterator it = callbacks_.find(stream_proxy); |
| 279 if (it == callbacks_.end()) { | 224 if (it == callbacks_.end()) { |
| 280 resampler_callback = new OnMoreDataResampler( | 225 resampler_callback = new OnMoreDataConverter(params_, output_params_); |
| 281 io_ratio_, params_, output_params_); | |
| 282 callbacks_[stream_proxy] = resampler_callback; | 226 callbacks_[stream_proxy] = resampler_callback; |
| 283 } else { | 227 } else { |
| 284 resampler_callback = it->second; | 228 resampler_callback = it->second; |
| 285 } | 229 } |
| 286 resampler_callback->Start(callback); | 230 resampler_callback->Start(callback); |
| 287 return dispatcher_->StartStream(resampler_callback, stream_proxy); | 231 return dispatcher_->StartStream(resampler_callback, stream_proxy); |
| 288 } | 232 } |
| 289 | 233 |
| 290 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy, | 234 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy, |
| 291 double volume) { | 235 double volume) { |
| 292 DCHECK_EQ(MessageLoop::current(), message_loop_); | 236 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 293 dispatcher_->StreamVolumeSet(stream_proxy, volume); | 237 dispatcher_->StreamVolumeSet(stream_proxy, volume); |
| 294 } | 238 } |
| 295 | 239 |
| 296 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) { | 240 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) { |
| 297 DCHECK_EQ(MessageLoop::current(), message_loop_); | 241 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 298 dispatcher_->StopStream(stream_proxy); | 242 dispatcher_->StopStream(stream_proxy); |
| 299 | 243 |
| 300 // Now that StopStream() has completed the underlying physical stream should | 244 // Now that StopStream() has completed the underlying physical stream should |
| 301 // be stopped and no longer calling OnMoreData(), making it safe to Stop() the | 245 // be stopped and no longer calling OnMoreData(), making it safe to Stop() the |
| 302 // OnMoreDataResampler. | 246 // OnMoreDataConverter. |
| 303 CallbackMap::iterator it = callbacks_.find(stream_proxy); | 247 CallbackMap::iterator it = callbacks_.find(stream_proxy); |
| 304 if (it != callbacks_.end()) | 248 if (it != callbacks_.end()) |
| 305 it->second->Stop(); | 249 it->second->Stop(); |
| 306 } | 250 } |
| 307 | 251 |
| 308 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) { | 252 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) { |
| 309 DCHECK_EQ(MessageLoop::current(), message_loop_); | 253 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 310 dispatcher_->CloseStream(stream_proxy); | 254 dispatcher_->CloseStream(stream_proxy); |
| 311 | 255 |
| 312 // We assume that StopStream() is always called prior to CloseStream(), so | 256 // We assume that StopStream() is always called prior to CloseStream(), so |
| 313 // that it is safe to delete the OnMoreDataResampler here. | 257 // that it is safe to delete the OnMoreDataConverter here. |
| 314 CallbackMap::iterator it = callbacks_.find(stream_proxy); | 258 CallbackMap::iterator it = callbacks_.find(stream_proxy); |
| 315 if (it != callbacks_.end()) { | 259 if (it != callbacks_.end()) { |
| 316 delete it->second; | 260 delete it->second; |
| 317 callbacks_.erase(it); | 261 callbacks_.erase(it); |
| 318 } | 262 } |
| 319 } | 263 } |
| 320 | 264 |
| 321 void AudioOutputResampler::Shutdown() { | 265 void AudioOutputResampler::Shutdown() { |
| 322 DCHECK_EQ(MessageLoop::current(), message_loop_); | 266 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 323 | 267 |
| 324 // No AudioOutputProxy objects should hold a reference to us when we get | 268 // No AudioOutputProxy objects should hold a reference to us when we get |
| 325 // to this stage. | 269 // to this stage. |
| 326 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference"; | 270 DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference"; |
| 327 | 271 |
| 328 dispatcher_->Shutdown(); | 272 dispatcher_->Shutdown(); |
| 329 DCHECK(callbacks_.empty()); | 273 DCHECK(callbacks_.empty()); |
| 330 } | 274 } |
| 331 | 275 |
| 332 OnMoreDataResampler::OnMoreDataResampler( | 276 OnMoreDataConverter::OnMoreDataConverter(const AudioParameters& input_params, |
| 333 double io_ratio, const AudioParameters& input_params, | 277 const AudioParameters& output_params) |
| 334 const AudioParameters& output_params) | 278 : source_callback_(NULL), |
| 335 : io_ratio_(io_ratio), | 279 source_bus_(NULL), |
| 336 source_callback_(NULL), | 280 input_bytes_per_second_(input_params.GetBytesPerSecond()), |
| 337 outstanding_audio_bytes_(0), | 281 audio_converter_(input_params, output_params, false) { |
|
scherkus (not reviewing)
2012/11/17 01:04:37
who calls disable_fifo w/ true?
DaleCurtis
2012/11/17 01:07:14
AudioRendererMixer.
| |
| 338 output_bytes_per_frame_(output_params.GetBytesPerFrame()), | 282 io_ratio_ = |
| 339 input_bytes_per_frame_(input_params.GetBytesPerFrame()), | 283 static_cast<double>(input_params.GetBytesPerSecond()) / |
| 340 downmix_early_(false) { | 284 output_params.GetBytesPerSecond(); |
| 341 // Handle different input and output channel layouts. | |
| 342 if (input_params.channel_layout() != output_params.channel_layout()) { | |
| 343 DVLOG(1) << "Remixing channel layout from " << input_params.channel_layout() | |
| 344 << " to " << output_params.channel_layout() << "; from " | |
| 345 << input_params.channels() << " channels to " | |
| 346 << output_params.channels() << " channels."; | |
| 347 channel_mixer_.reset(new ChannelMixer( | |
| 348 input_params.channel_layout(), output_params.channel_layout())); | |
| 349 | |
| 350 // Pare off data as early as we can for efficiency. | |
| 351 downmix_early_ = input_params.channels() > output_params.channels(); | |
| 352 if (downmix_early_) { | |
| 353 DVLOG(1) << "Remixing channel layout prior to resampling."; | |
| 354 // If we're downmixing early we need a temporary AudioBus which matches | |
| 355 // the the input channel count and input frame size since we're passing | |
| 356 // |unmixed_audio_| directly to the |source_callback_|. | |
| 357 unmixed_audio_ = AudioBus::Create(input_params); | |
| 358 } else { | |
| 359 // Instead, if we're not downmixing early we need a temporary AudioBus | |
| 360 // which matches the input channel count but uses the output frame size | |
| 361 // since we'll mix into the AudioBus from the output stream. | |
| 362 unmixed_audio_ = AudioBus::Create( | |
| 363 input_params.channels(), output_params.frames_per_buffer()); | |
| 364 } | |
| 365 } | |
| 366 | |
| 367 // Only resample if necessary since it's expensive. | |
| 368 if (input_params.sample_rate() != output_params.sample_rate()) { | |
| 369 DVLOG(1) << "Resampling from " << input_params.sample_rate() << " to " | |
| 370 << output_params.sample_rate(); | |
| 371 double io_sample_rate_ratio = input_params.sample_rate() / | |
| 372 static_cast<double>(output_params.sample_rate()); | |
| 373 resampler_.reset(new MultiChannelResampler( | |
| 374 downmix_early_ ? output_params.channels() : | |
| 375 input_params.channels(), | |
| 376 io_sample_rate_ratio, base::Bind( | |
| 377 &OnMoreDataResampler::ProvideInput, base::Unretained(this)))); | |
| 378 } | |
| 379 | |
| 380 // Since the resampler / output device may want a different buffer size than | |
| 381 // the caller asked for, we need to use a FIFO to ensure that both sides | |
| 382 // read in chunk sizes they're configured for. | |
| 383 if (input_params.sample_rate() != output_params.sample_rate() || | |
| 384 input_params.frames_per_buffer() != output_params.frames_per_buffer()) { | |
| 385 DVLOG(1) << "Rebuffering from " << input_params.frames_per_buffer() | |
| 386 << " to " << output_params.frames_per_buffer(); | |
| 387 audio_fifo_.reset(new AudioPullFifo( | |
| 388 downmix_early_ ? output_params.channels() : | |
| 389 input_params.channels(), | |
| 390 input_params.frames_per_buffer(), base::Bind( | |
| 391 &OnMoreDataResampler::SourceCallback_Locked, | |
| 392 base::Unretained(this)))); | |
| 393 } | |
| 394 } | 285 } |
| 395 | 286 |
| 396 OnMoreDataResampler::~OnMoreDataResampler() {} | 287 OnMoreDataConverter::~OnMoreDataConverter() {} |
| 397 | 288 |
| 398 void OnMoreDataResampler::Start( | 289 void OnMoreDataConverter::Start( |
| 399 AudioOutputStream::AudioSourceCallback* callback) { | 290 AudioOutputStream::AudioSourceCallback* callback) { |
| 400 base::AutoLock auto_lock(source_lock_); | 291 base::AutoLock auto_lock(source_lock_); |
| 401 DCHECK(!source_callback_); | 292 DCHECK(!source_callback_); |
| 402 source_callback_ = callback; | 293 source_callback_ = callback; |
| 294 | |
| 295 // While AudioConverter can handle multiple inputs, we're using it only with | |
| 296 // a single input currently. Eventually this may be the basis for a browser | |
| 297 // side mixer. | |
| 298 audio_converter_.AddInput(this); | |
| 403 } | 299 } |
| 404 | 300 |
| 405 void OnMoreDataResampler::Stop() { | 301 void OnMoreDataConverter::Stop() { |
| 406 base::AutoLock auto_lock(source_lock_); | 302 base::AutoLock auto_lock(source_lock_); |
| 407 source_callback_ = NULL; | 303 source_callback_ = NULL; |
| 408 outstanding_audio_bytes_ = 0; | 304 audio_converter_.RemoveInput(this); |
| 409 if (audio_fifo_) | |
| 410 audio_fifo_->Clear(); | |
| 411 if (resampler_) | |
| 412 resampler_->Flush(); | |
| 413 } | 305 } |
| 414 | 306 |
| 415 int OnMoreDataResampler::OnMoreData(AudioBus* dest, | 307 int OnMoreDataConverter::OnMoreData(AudioBus* dest, |
| 416 AudioBuffersState buffers_state) { | 308 AudioBuffersState buffers_state) { |
| 417 return OnMoreIOData(NULL, dest, buffers_state); | 309 return OnMoreIOData(NULL, dest, buffers_state); |
| 418 } | 310 } |
| 419 | 311 |
| 420 int OnMoreDataResampler::OnMoreIOData(AudioBus* source, | 312 int OnMoreDataConverter::OnMoreIOData(AudioBus* source, |
| 421 AudioBus* dest, | 313 AudioBus* dest, |
| 422 AudioBuffersState buffers_state) { | 314 AudioBuffersState buffers_state) { |
| 423 base::AutoLock auto_lock(source_lock_); | 315 base::AutoLock auto_lock(source_lock_); |
| 424 // While we waited for |source_lock_| the callback might have been cleared. | 316 // While we waited for |source_lock_| the callback might have been cleared. |
| 425 if (!source_callback_) { | 317 if (!source_callback_) { |
| 426 dest->Zero(); | 318 dest->Zero(); |
| 427 return dest->frames(); | 319 return dest->frames(); |
| 428 } | 320 } |
| 429 | 321 |
| 322 source_bus_ = source; | |
| 430 current_buffers_state_ = buffers_state; | 323 current_buffers_state_ = buffers_state; |
| 324 audio_converter_.Convert(dest); | |
| 431 | 325 |
| 432 bool needs_mixing = channel_mixer_ && !downmix_early_; | 326 // Always return the full number of frames requested, ProvideInput_Locked() |
| 433 AudioBus* temp_dest = needs_mixing ? unmixed_audio_.get() : dest; | 327 // will pad with silence if it wasn't able to acquire enough data. |
| 434 | |
| 435 if (!resampler_ && !audio_fifo_) { | |
| 436 // We have no internal buffers, so clear any outstanding audio data. | |
| 437 outstanding_audio_bytes_ = 0; | |
| 438 SourceIOCallback_Locked(source, temp_dest); | |
| 439 } else { | |
| 440 if (resampler_) | |
| 441 resampler_->Resample(temp_dest, temp_dest->frames()); | |
| 442 else | |
| 443 ProvideInput(temp_dest); | |
| 444 | |
| 445 // Calculate how much data is left in the internal FIFO and resampler. | |
| 446 outstanding_audio_bytes_ -= temp_dest->frames() * output_bytes_per_frame_; | |
| 447 } | |
| 448 | |
| 449 if (needs_mixing) { | |
| 450 DCHECK_EQ(temp_dest->frames(), dest->frames()); | |
| 451 channel_mixer_->Transform(temp_dest, dest); | |
| 452 } | |
| 453 | |
| 454 // Due to rounding errors while multiplying against |io_ratio_|, | |
| 455 // |outstanding_audio_bytes_| might (rarely) slip below zero. | |
| 456 if (outstanding_audio_bytes_ < 0) { | |
| 457 DLOG(ERROR) << "Outstanding audio bytes went negative! Value: " | |
| 458 << outstanding_audio_bytes_; | |
| 459 outstanding_audio_bytes_ = 0; | |
| 460 } | |
| 461 | |
| 462 // Always return the full number of frames requested, ProvideInput() will pad | |
| 463 // with silence if it wasn't able to acquire enough data. | |
| 464 return dest->frames(); | 328 return dest->frames(); |
| 465 } | 329 } |
| 466 | 330 |
| 467 void OnMoreDataResampler::SourceCallback_Locked(AudioBus* dest) { | 331 double OnMoreDataConverter::ProvideInput(AudioBus* dest, |
| 468 SourceIOCallback_Locked(NULL, dest); | 332 base::TimeDelta buffer_delay) { |
| 333 source_lock_.AssertAcquired(); | |
| 334 | |
| 335 // Adjust playback delay to include |buffer_delay|. | |
| 336 AudioBuffersState new_buffers_state; | |
|
Chris Rogers
2012/11/20 20:01:24
TODO to stop dealing in calculations in units of b
DaleCurtis
2012/11/21 00:33:30
Done.
| |
| 337 new_buffers_state.pending_bytes = | |
| 338 io_ratio_ * (current_buffers_state_.total_bytes() + | |
| 339 buffer_delay.InSecondsF() * input_bytes_per_second_); | |
| 340 | |
| 341 // Retrieve data from the original callback. | |
| 342 int frames = source_callback_->OnMoreIOData( | |
| 343 source_bus_, dest, new_buffers_state); | |
| 344 | |
| 345 // |source_bus_| should only be provided once. | |
|
Chris Rogers
2012/11/20 20:01:24
Setting to NULL doesn't really solve the problem (
DaleCurtis
2012/11/21 00:33:30
Done.
| |
| 346 source_bus_ = NULL; | |
| 347 | |
| 348 // Zero any unfilled frames if anything was filled, otherwise we'll just | |
| 349 // return a volume of zero and let AudioConverter drop the output. | |
| 350 if (frames > 0 && frames < dest->frames()) | |
| 351 dest->ZeroFramesPartial(frames, dest->frames() - frames); | |
| 352 | |
| 353 // TODO(dalecurtis): Return the correct volume here. | |
| 354 return frames > 0 ? 1 : 0; | |
| 469 } | 355 } |
| 470 | 356 |
| 471 void OnMoreDataResampler::SourceIOCallback_Locked(AudioBus* source, | 357 void OnMoreDataConverter::OnError(AudioOutputStream* stream, int code) { |
| 472 AudioBus* dest) { | |
| 473 source_lock_.AssertAcquired(); | |
| 474 | |
| 475 // Adjust playback delay to include the state of the internal buffers used by | |
| 476 // the resampler and/or the FIFO. Since the sample rate and bits per channel | |
| 477 // may be different, we need to scale this value appropriately. | |
| 478 AudioBuffersState new_buffers_state; | |
| 479 new_buffers_state.pending_bytes = io_ratio_ * | |
| 480 (current_buffers_state_.total_bytes() + outstanding_audio_bytes_); | |
| 481 | |
| 482 bool needs_downmix = channel_mixer_ && downmix_early_; | |
| 483 AudioBus* temp_dest = needs_downmix ? unmixed_audio_.get() : dest; | |
| 484 | |
| 485 // Retrieve data from the original callback. Zero any unfilled frames. | |
| 486 int frames = source_callback_->OnMoreIOData( | |
| 487 source, temp_dest, new_buffers_state); | |
| 488 if (frames < temp_dest->frames()) | |
| 489 temp_dest->ZeroFramesPartial(frames, temp_dest->frames() - frames); | |
| 490 | |
| 491 // Scale the number of frames we got back in terms of input bytes to output | |
| 492 // bytes accordingly. | |
| 493 outstanding_audio_bytes_ += | |
| 494 (temp_dest->frames() * input_bytes_per_frame_) / io_ratio_; | |
| 495 | |
| 496 if (needs_downmix) { | |
| 497 DCHECK_EQ(temp_dest->frames(), dest->frames()); | |
| 498 channel_mixer_->Transform(temp_dest, dest); | |
| 499 } | |
| 500 } | |
| 501 | |
| 502 void OnMoreDataResampler::ProvideInput(AudioBus* audio_bus) { | |
| 503 audio_fifo_->Consume(audio_bus, audio_bus->frames()); | |
| 504 } | |
| 505 | |
| 506 void OnMoreDataResampler::OnError(AudioOutputStream* stream, int code) { | |
| 507 base::AutoLock auto_lock(source_lock_); | 358 base::AutoLock auto_lock(source_lock_); |
| 508 if (source_callback_) | 359 if (source_callback_) |
| 509 source_callback_->OnError(stream, code); | 360 source_callback_->OnError(stream, code); |
| 510 } | 361 } |
| 511 | 362 |
| 512 void OnMoreDataResampler::WaitTillDataReady() { | 363 void OnMoreDataConverter::WaitTillDataReady() { |
| 513 base::AutoLock auto_lock(source_lock_); | 364 base::AutoLock auto_lock(source_lock_); |
| 514 if (source_callback_ && !outstanding_audio_bytes_) | 365 if (source_callback_) |
| 515 source_callback_->WaitTillDataReady(); | 366 source_callback_->WaitTillDataReady(); |
| 516 } | 367 } |
| 517 | 368 |
| 518 } // namespace media | 369 } // namespace media |
| OLD | NEW |