| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "media/audio/audio_output_resampler.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" |
| 9 #include "base/compiler_specific.h" |
| 10 #include "base/message_loop.h" |
| 11 #include "base/time.h" |
| 12 #include "media/audio/audio_io.h" |
| 13 #include "media/audio/audio_output_dispatcher_impl.h" |
| 14 #include "media/audio/audio_output_proxy.h" |
| 15 #include "media/audio/audio_util.h" |
| 16 #include "media/base/audio_pull_fifo.h" |
| 17 #include "media/base/multi_channel_resampler.h" |
| 18 |
| 19 namespace media { |
| 20 |
| 21 AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager, |
| 22 const AudioParameters& input_params, |
| 23 const AudioParameters& output_params, |
| 24 const base::TimeDelta& close_delay) |
| 25 : AudioOutputDispatcher(audio_manager, input_params), |
| 26 source_callback_(NULL), |
| 27 io_ratio_(1), |
| 28 input_bytes_per_frame_(input_params.GetBytesPerFrame()), |
| 29 output_bytes_per_frame_(output_params.GetBytesPerFrame()), |
| 30 outstanding_audio_bytes_(0) { |
| 31 // TODO(dalecurtis): Add channel remixing. http://crbug.com/138762 |
| 32 DCHECK_EQ(input_params.channels(), output_params.channels()); |
| 33 // Only resample or rebuffer if the input parameters don't match the output |
| 34 // parameters to avoid any unnecessary work. |
| 35 if (input_params.channels() != output_params.channels() || |
| 36 input_params.sample_rate() != output_params.sample_rate() || |
| 37 input_params.bits_per_sample() != output_params.bits_per_sample() || |
| 38 input_params.frames_per_buffer() != output_params.frames_per_buffer()) { |
| 39 // Only resample if necessary since it's expensive. |
| 40 if (input_params.sample_rate() != output_params.sample_rate()) { |
| 41 double io_sample_rate_ratio = input_params.sample_rate() / |
| 42 static_cast<double>(output_params.sample_rate()); |
| 43 // Include the I/O resampling ratio in our global I/O ratio. |
| 44 io_ratio_ *= io_sample_rate_ratio; |
| 45 resampler_.reset(new MultiChannelResampler( |
| 46 output_params.channels(), io_sample_rate_ratio, base::Bind( |
| 47 &AudioOutputResampler::ProvideInput, base::Unretained(this)))); |
| 48 } |
| 49 |
| 50 // Include bits per channel differences. |
| 51 io_ratio_ *= static_cast<double>(input_params.bits_per_sample()) / |
| 52 output_params.bits_per_sample(); |
| 53 |
| 54 // Include channel count differences. |
| 55 io_ratio_ *= static_cast<double>(input_params.channels()) / |
| 56 output_params.channels(); |
| 57 |
| 58 // Since the resampler / output device may want a different buffer size than |
| 59 // the caller asked for, we need to use a FIFO to ensure that both sides |
| 60 // read in chunk sizes they're configured for. |
| 61 if (input_params.sample_rate() != output_params.sample_rate() || |
| 62 input_params.frames_per_buffer() != output_params.frames_per_buffer()) { |
| 63 audio_fifo_.reset(new AudioPullFifo( |
| 64 input_params.channels(), input_params.frames_per_buffer(), base::Bind( |
| 65 &AudioOutputResampler::SourceCallback, base::Unretained(this)))); |
| 66 } |
| 67 } |
| 68 |
| 69 // TODO(dalecurtis): All this code should be merged into AudioOutputMixer once |
| 70 // we've stabilized the issues there. |
| 71 dispatcher_ = new AudioOutputDispatcherImpl( |
| 72 audio_manager, output_params, close_delay); |
| 73 } |
| 74 |
| 75 AudioOutputResampler::~AudioOutputResampler() {} |
| 76 |
| 77 bool AudioOutputResampler::OpenStream() { |
| 78 // TODO(dalecurtis): Automatically revert to high latency path if OpenStream() |
| 79 // fails; use default high latency output values + rebuffering / resampling. |
| 80 return dispatcher_->OpenStream(); |
| 81 } |
| 82 |
| 83 bool AudioOutputResampler::StartStream( |
| 84 AudioOutputStream::AudioSourceCallback* callback, |
| 85 AudioOutputProxy* stream_proxy) { |
| 86 { |
| 87 base::AutoLock auto_lock(source_lock_); |
| 88 source_callback_ = callback; |
| 89 } |
| 90 return dispatcher_->StartStream(this, stream_proxy); |
| 91 } |
| 92 |
| 93 void AudioOutputResampler::StreamVolumeSet(AudioOutputProxy* stream_proxy, |
| 94 double volume) { |
| 95 dispatcher_->StreamVolumeSet(stream_proxy, volume); |
| 96 } |
| 97 |
| 98 void AudioOutputResampler::Reset() { |
| 99 base::AutoLock auto_lock(source_lock_); |
| 100 source_callback_ = NULL; |
| 101 outstanding_audio_bytes_ = 0; |
| 102 if (audio_fifo_.get()) |
| 103 audio_fifo_->Clear(); |
| 104 if (resampler_.get()) |
| 105 resampler_->Flush(); |
| 106 } |
| 107 |
| 108 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) { |
| 109 Reset(); |
| 110 dispatcher_->StopStream(stream_proxy); |
| 111 } |
| 112 |
| 113 void AudioOutputResampler::CloseStream(AudioOutputProxy* stream_proxy) { |
| 114 Reset(); |
| 115 dispatcher_->CloseStream(stream_proxy); |
| 116 } |
| 117 |
| 118 void AudioOutputResampler::Shutdown() { |
| 119 Reset(); |
| 120 dispatcher_->Shutdown(); |
| 121 } |
| 122 |
| 123 int AudioOutputResampler::OnMoreData(AudioBus* audio_bus, |
| 124 AudioBuffersState buffers_state) { |
| 125 current_buffers_state_ = buffers_state; |
| 126 |
| 127 if (!resampler_.get() && !audio_fifo_.get()) { |
| 128 // We have no internal buffers, so clear any outstanding audio data. |
| 129 outstanding_audio_bytes_ = 0; |
| 130 SourceCallback(audio_bus); |
| 131 return audio_bus->frames(); |
| 132 } |
| 133 |
| 134 if (resampler_.get()) |
| 135 resampler_->Resample(audio_bus, audio_bus->frames()); |
| 136 else |
| 137 ProvideInput(audio_bus); |
| 138 |
| 139 // Calculate how much data is left in the internal FIFO and resampler buffers. |
| 140 outstanding_audio_bytes_ -= audio_bus->frames() * output_bytes_per_frame_; |
| 141 // Due to rounding errors while multiplying against |io_ratio_|, |
| 142 // |outstanding_audio_bytes_| might (rarely) slip below zero. |
| 143 if (outstanding_audio_bytes_ < 0) { |
| 144 DLOG(ERROR) << "Outstanding audio bytes went negative! Value: " |
| 145 << outstanding_audio_bytes_; |
| 146 outstanding_audio_bytes_ = 0; |
| 147 } |
| 148 |
| 149 // Always return the full number of frames requested, ProvideInput() will pad |
| 150 // with silence if it wasn't able to acquire enough data. |
| 151 return audio_bus->frames(); |
| 152 } |
| 153 |
| 154 void AudioOutputResampler::SourceCallback(AudioBus* audio_bus) { |
| 155 base::AutoLock auto_lock(source_lock_); |
| 156 // While we waited for |source_lock_| it might have been cleared. |
| 157 if (!source_callback_) { |
| 158 audio_bus->Zero(); |
| 159 return; |
| 160 } |
| 161 |
| 162 // Adjust playback delay to include the state of the internal buffers used by |
| 163 // the resampler and/or the FIFO. Since the sample rate and bits per channel |
| 164 // may be different, we need to scale this value appropriately. |
| 165 AudioBuffersState new_buffers_state; |
| 166 new_buffers_state.pending_bytes = io_ratio_ * |
| 167 (current_buffers_state_.total_bytes() + outstanding_audio_bytes_); |
| 168 |
| 169 // Retrieve data from the original callback. Zero any unfilled frames. |
| 170 int frames = source_callback_->OnMoreData(audio_bus, new_buffers_state); |
| 171 if (frames < audio_bus->frames()) |
| 172 audio_bus->ZeroFramesPartial(frames, audio_bus->frames() - frames); |
| 173 |
| 174 // Scale the number of frames we got back in terms of input bytes to output |
| 175 // bytes accordingly. |
| 176 outstanding_audio_bytes_ += |
| 177 (audio_bus->frames() * input_bytes_per_frame_) / io_ratio_; |
| 178 } |
| 179 |
| 180 void AudioOutputResampler::ProvideInput(AudioBus* audio_bus) { |
| 181 audio_fifo_->Consume(audio_bus, audio_bus->frames()); |
| 182 } |
| 183 |
| 184 void AudioOutputResampler::OnError(AudioOutputStream* stream, int code) { |
| 185 base::AutoLock auto_lock(source_lock_); |
| 186 if (source_callback_) |
| 187 source_callback_->OnError(stream, code); |
| 188 } |
| 189 |
| 190 void AudioOutputResampler::WaitTillDataReady() { |
| 191 base::AutoLock auto_lock(source_lock_); |
| 192 if (source_callback_ && !outstanding_audio_bytes_) |
| 193 source_callback_->WaitTillDataReady(); |
| 194 } |
| 195 |
| 196 } // namespace media |
| OLD | NEW |