Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "chromecast/media/cma/backend/alsa/audio_decoder_alsa.h" | 5 #include "chromecast/media/cma/backend/alsa/audio_decoder_alsa.h" |
| 6 | 6 |
| 7 #include <time.h> | 7 #include <time.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <limits> | 10 #include <limits> |
| 11 | 11 |
| 12 #include "base/callback_helpers.h" | 12 #include "base/callback_helpers.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/macros.h" | 14 #include "base/macros.h" |
| 15 #include "base/trace_event/trace_event.h" | 15 #include "base/trace_event/trace_event.h" |
| 16 #include "chromecast/base/task_runner_impl.h" | 16 #include "chromecast/base/task_runner_impl.h" |
| 17 #include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h" | 17 #include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h" |
| 18 #include "chromecast/media/cma/base/decoder_buffer_adapter.h" | |
| 18 #include "chromecast/media/cma/base/decoder_buffer_base.h" | 19 #include "chromecast/media/cma/base/decoder_buffer_base.h" |
| 19 #include "chromecast/public/media/cast_decoder_buffer.h" | 20 #include "chromecast/public/media/cast_decoder_buffer.h" |
| 21 #include "media/base/audio_buffer.h" | |
| 22 #include "media/base/audio_bus.h" | |
| 23 #include "media/base/channel_layout.h" | |
| 24 #include "media/base/decoder_buffer.h" | |
| 25 #include "media/base/sample_format.h" | |
| 26 #include "media/filters/audio_renderer_algorithm.h" | |
| 20 | 27 |
| 21 #define TRACE_FUNCTION_ENTRY0() TRACE_EVENT0("cma", __FUNCTION__) | 28 #define TRACE_FUNCTION_ENTRY0() TRACE_EVENT0("cma", __FUNCTION__) |
| 22 | 29 |
| 23 #define TRACE_FUNCTION_ENTRY1(arg1) \ | 30 #define TRACE_FUNCTION_ENTRY1(arg1) \ |
| 24 TRACE_EVENT1("cma", __FUNCTION__, #arg1, arg1) | 31 TRACE_EVENT1("cma", __FUNCTION__, #arg1, arg1) |
| 25 | 32 |
| 26 #define TRACE_FUNCTION_ENTRY2(arg1, arg2) \ | 33 #define TRACE_FUNCTION_ENTRY2(arg1, arg2) \ |
| 27 TRACE_EVENT2("cma", __FUNCTION__, #arg1, arg1, #arg2, arg2) | 34 TRACE_EVENT2("cma", __FUNCTION__, #arg1, arg1, #arg2, arg2) |
| 28 | 35 |
| 29 namespace chromecast { | 36 namespace chromecast { |
| 30 namespace media { | 37 namespace media { |
| 31 | 38 |
| 32 namespace { | 39 namespace { |
| 33 | 40 |
| 41 const int kBitsPerSample = 32; | |
| 42 const int kDefaultFramesPerBuffer = 1024; | |
| 43 const int kSilenceBufferFrames = 2048; | |
| 44 const int kMaxOutputMs = 20; | |
| 45 | |
| 46 const double kPlaybackRateEpsilon = 0.001; | |
| 47 | |
| 34 const CastAudioDecoder::OutputFormat kDecoderSampleFormat = | 48 const CastAudioDecoder::OutputFormat kDecoderSampleFormat = |
| 35 CastAudioDecoder::kOutputPlanarFloat; | 49 CastAudioDecoder::kOutputPlanarFloat; |
| 36 | 50 |
| 37 const int64_t kInvalidDelayTimestamp = std::numeric_limits<int64_t>::min(); | 51 const int64_t kInvalidTimestamp = std::numeric_limits<int64_t>::min(); |
| 38 | |
| 39 AudioDecoderAlsa::RenderingDelay kInvalidRenderingDelay() { | |
| 40 AudioDecoderAlsa::RenderingDelay delay; | |
| 41 delay.timestamp_microseconds = kInvalidDelayTimestamp; | |
| 42 delay.delay_microseconds = 0; | |
| 43 return delay; | |
| 44 } | |
| 45 | 52 |
| 46 } // namespace | 53 } // namespace |
| 47 | 54 |
| 55 AudioDecoderAlsa::RateShifterInfo::RateShifterInfo(float playback_rate) | |
| 56 : rate(playback_rate), input_frames(0), output_frames(0) {} | |
| 57 | |
| 48 AudioDecoderAlsa::AudioDecoderAlsa(MediaPipelineBackendAlsa* backend) | 58 AudioDecoderAlsa::AudioDecoderAlsa(MediaPipelineBackendAlsa* backend) |
| 49 : backend_(backend), | 59 : backend_(backend), |
| 50 task_runner_(backend->GetTaskRunner()), | 60 task_runner_(backend->GetTaskRunner()), |
| 51 delegate_(nullptr), | 61 delegate_(nullptr), |
| 52 is_eos_(false), | 62 pending_write_pcm_(false), |
| 63 pending_buffer_complete_(false), | |
| 64 got_eos_(false), | |
| 65 pushed_eos_(false), | |
| 53 error_(false), | 66 error_(false), |
| 67 rate_shifter_output_( | |
| 68 ::media::AudioBus::Create(2, kDefaultFramesPerBuffer)), | |
|
slan
2016/12/07 00:22:27
nit: Can we do "2 /* num_channels */" or kNumChann
kmackay
2016/12/07 22:59:57
Done.
| |
| 69 current_pts_(kInvalidTimestamp), | |
| 70 pending_output_frames_(0), | |
| 54 volume_multiplier_(1.0f), | 71 volume_multiplier_(1.0f), |
| 55 weak_factory_(this) { | 72 weak_factory_(this) { |
| 56 TRACE_FUNCTION_ENTRY0(); | 73 TRACE_FUNCTION_ENTRY0(); |
| 57 DCHECK(backend_); | 74 DCHECK(backend_); |
| 58 DCHECK(task_runner_.get()); | 75 DCHECK(task_runner_.get()); |
| 59 DCHECK(task_runner_->BelongsToCurrentThread()); | 76 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 77 rate_shifter_info_.push_back(RateShifterInfo(1.0f)); | |
|
slan
2016/12/07 00:22:27
Why do we need this call? The queue is cleared whe
kmackay
2016/12/07 22:59:57
We don't; removed
| |
| 60 } | 78 } |
| 61 | 79 |
| 62 AudioDecoderAlsa::~AudioDecoderAlsa() { | 80 AudioDecoderAlsa::~AudioDecoderAlsa() { |
| 63 TRACE_FUNCTION_ENTRY0(); | 81 TRACE_FUNCTION_ENTRY0(); |
| 64 DCHECK(task_runner_->BelongsToCurrentThread()); | 82 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 65 } | 83 } |
| 66 | 84 |
| 67 void AudioDecoderAlsa::SetDelegate( | 85 void AudioDecoderAlsa::SetDelegate( |
| 68 MediaPipelineBackend::Decoder::Delegate* delegate) { | 86 MediaPipelineBackend::Decoder::Delegate* delegate) { |
| 69 DCHECK(delegate); | 87 DCHECK(delegate); |
| 70 delegate_ = delegate; | 88 delegate_ = delegate; |
| 71 } | 89 } |
| 72 | 90 |
| 73 void AudioDecoderAlsa::Initialize() { | 91 void AudioDecoderAlsa::Initialize() { |
| 74 TRACE_FUNCTION_ENTRY0(); | 92 TRACE_FUNCTION_ENTRY0(); |
| 75 DCHECK(delegate_); | 93 DCHECK(delegate_); |
| 76 stats_ = Statistics(); | 94 stats_ = Statistics(); |
| 77 is_eos_ = false; | 95 pending_write_pcm_ = false; |
| 78 last_buffer_pts_ = std::numeric_limits<int64_t>::min(); | 96 pending_buffer_complete_ = false; |
| 97 got_eos_ = false; | |
| 98 pushed_eos_ = false; | |
| 99 current_pts_ = kInvalidTimestamp; | |
| 100 pending_output_frames_ = 0; | |
| 79 | 101 |
| 80 last_known_delay_.timestamp_microseconds = kInvalidDelayTimestamp; | 102 last_known_delay_.timestamp_microseconds = kInvalidTimestamp; |
| 81 last_known_delay_.delay_microseconds = 0; | 103 last_known_delay_.delay_microseconds = 0; |
| 82 } | 104 } |
| 83 | 105 |
| 84 bool AudioDecoderAlsa::Start(int64_t start_pts) { | 106 bool AudioDecoderAlsa::Start(int64_t start_pts) { |
| 85 TRACE_FUNCTION_ENTRY0(); | 107 TRACE_FUNCTION_ENTRY0(); |
| 86 current_pts_ = start_pts; | 108 current_pts_ = start_pts; |
| 87 DCHECK(IsValidConfig(config_)); | 109 DCHECK(IsValidConfig(config_)); |
| 88 mixer_input_.reset(new StreamMixerAlsaInput( | 110 mixer_input_.reset(new StreamMixerAlsaInput( |
| 89 this, config_.samples_per_second, backend_->Primary())); | 111 this, config_.samples_per_second, backend_->Primary())); |
| 90 mixer_input_->SetVolumeMultiplier(volume_multiplier_); | 112 mixer_input_->SetVolumeMultiplier(volume_multiplier_); |
| 91 // Create decoder_ if necessary. This can happen if Stop() was called, and | 113 // Create decoder_ if necessary. This can happen if Stop() was called, and |
| 92 // SetConfig() was not called since then. | 114 // SetConfig() was not called since then. |
| 93 if (!decoder_) | 115 if (!decoder_) { |
| 94 CreateDecoder(); | 116 CreateDecoder(); |
| 117 } | |
| 118 if (!rate_shifter_) { | |
| 119 CreateRateShifter(config_.samples_per_second); | |
| 120 } | |
| 95 return true; | 121 return true; |
| 96 } | 122 } |
| 97 | 123 |
| 98 void AudioDecoderAlsa::Stop() { | 124 void AudioDecoderAlsa::Stop() { |
| 99 TRACE_FUNCTION_ENTRY0(); | 125 TRACE_FUNCTION_ENTRY0(); |
| 100 decoder_.reset(); | 126 decoder_.reset(); |
| 101 mixer_input_.reset(); | 127 mixer_input_.reset(); |
| 128 rate_shifter_.reset(); | |
| 129 weak_factory_.InvalidateWeakPtrs(); | |
| 102 | 130 |
| 103 Initialize(); | 131 Initialize(); |
| 104 } | 132 } |
| 105 | 133 |
| 106 bool AudioDecoderAlsa::Pause() { | 134 bool AudioDecoderAlsa::Pause() { |
| 107 TRACE_FUNCTION_ENTRY0(); | 135 TRACE_FUNCTION_ENTRY0(); |
| 108 DCHECK(mixer_input_); | 136 DCHECK(mixer_input_); |
| 109 mixer_input_->SetPaused(true); | 137 mixer_input_->SetPaused(true); |
| 110 return true; | 138 return true; |
| 111 } | 139 } |
| 112 | 140 |
| 113 bool AudioDecoderAlsa::Resume() { | 141 bool AudioDecoderAlsa::Resume() { |
| 114 TRACE_FUNCTION_ENTRY0(); | 142 TRACE_FUNCTION_ENTRY0(); |
| 115 DCHECK(mixer_input_); | 143 DCHECK(mixer_input_); |
| 116 mixer_input_->SetPaused(false); | 144 mixer_input_->SetPaused(false); |
| 117 return true; | 145 return true; |
| 118 } | 146 } |
| 119 | 147 |
| 148 bool AudioDecoderAlsa::SetPlaybackRate(float rate) { | |
| 149 if (std::abs(rate - 1.0) < kPlaybackRateEpsilon) { | |
|
slan
2016/12/07 00:22:27
Why this check? Are we worried about apps setting
kmackay
2016/12/07 22:59:57
AudioRendererAlgorithm treats values close to 1 as
| |
| 150 rate = 1.0f; | |
| 151 } | |
| 152 LOG(INFO) << "SetPlaybackRate to " << rate; | |
| 153 | |
| 154 while (!rate_shifter_info_.empty() && | |
| 155 rate_shifter_info_.back().input_frames == 0) { | |
| 156 rate_shifter_info_.pop_back(); | |
| 157 } | |
| 158 rate_shifter_info_.push_back(RateShifterInfo(rate)); | |
| 159 return true; | |
| 160 } | |
| 161 | |
| 120 AudioDecoderAlsa::BufferStatus AudioDecoderAlsa::PushBuffer( | 162 AudioDecoderAlsa::BufferStatus AudioDecoderAlsa::PushBuffer( |
| 121 CastDecoderBuffer* buffer) { | 163 CastDecoderBuffer* buffer) { |
| 122 TRACE_FUNCTION_ENTRY0(); | 164 TRACE_FUNCTION_ENTRY0(); |
| 123 DCHECK(task_runner_->BelongsToCurrentThread()); | 165 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 124 DCHECK(buffer); | 166 DCHECK(buffer); |
| 125 DCHECK(!is_eos_); | 167 DCHECK(!got_eos_); |
| 126 DCHECK(!error_); | 168 DCHECK(!error_); |
| 169 DCHECK(!pending_buffer_complete_); | |
| 127 | 170 |
| 128 uint64_t input_bytes = buffer->end_of_stream() ? 0 : buffer->data_size(); | 171 uint64_t input_bytes = buffer->end_of_stream() ? 0 : buffer->data_size(); |
| 129 scoped_refptr<DecoderBufferBase> buffer_base( | 172 scoped_refptr<DecoderBufferBase> buffer_base( |
| 130 static_cast<DecoderBufferBase*>(buffer)); | 173 static_cast<DecoderBufferBase*>(buffer)); |
| 131 if (!buffer->end_of_stream()) { | 174 if (!buffer->end_of_stream()) { |
| 132 last_buffer_pts_ = buffer->timestamp(); | 175 current_pts_ = buffer->timestamp(); |
| 133 current_pts_ = std::min(current_pts_, last_buffer_pts_); | |
| 134 } | 176 } |
| 135 | 177 |
| 136 // If the buffer is already decoded, do not attempt to decode. Call | 178 // If the buffer is already decoded, do not attempt to decode. Call |
| 137 // OnBufferDecoded asynchronously on the main thread. | 179 // OnBufferDecoded asynchronously on the main thread. |
| 138 if (BypassDecoder()) { | 180 if (BypassDecoder()) { |
| 139 DCHECK(!decoder_); | 181 DCHECK(!decoder_); |
| 140 task_runner_->PostTask( | 182 task_runner_->PostTask( |
| 141 FROM_HERE, | 183 FROM_HERE, |
| 142 base::Bind(&AudioDecoderAlsa::OnBufferDecoded, | 184 base::Bind(&AudioDecoderAlsa::OnBufferDecoded, |
| 143 weak_factory_.GetWeakPtr(), input_bytes, | 185 weak_factory_.GetWeakPtr(), input_bytes, |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 167 } | 209 } |
| 168 | 210 |
| 169 bool AudioDecoderAlsa::SetConfig(const AudioConfig& config) { | 211 bool AudioDecoderAlsa::SetConfig(const AudioConfig& config) { |
| 170 TRACE_FUNCTION_ENTRY0(); | 212 TRACE_FUNCTION_ENTRY0(); |
| 171 DCHECK(task_runner_->BelongsToCurrentThread()); | 213 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 172 if (!IsValidConfig(config)) { | 214 if (!IsValidConfig(config)) { |
| 173 LOG(ERROR) << "Invalid audio config passed to SetConfig"; | 215 LOG(ERROR) << "Invalid audio config passed to SetConfig"; |
| 174 return false; | 216 return false; |
| 175 } | 217 } |
| 176 | 218 |
| 219 if (!rate_shifter_ || | |
| 220 config.samples_per_second != config_.samples_per_second) { | |
| 221 CreateRateShifter(config.samples_per_second); | |
| 222 } | |
| 223 | |
| 177 if (mixer_input_ && config.samples_per_second != config_.samples_per_second) { | 224 if (mixer_input_ && config.samples_per_second != config_.samples_per_second) { |
| 178 // Destroy the old input first to ensure that the mixer output sample rate | 225 // Destroy the old input first to ensure that the mixer output sample rate |
| 179 // is updated. | 226 // is updated. |
| 180 mixer_input_.reset(); | 227 mixer_input_.reset(); |
| 181 mixer_input_.reset(new StreamMixerAlsaInput( | 228 mixer_input_.reset(new StreamMixerAlsaInput( |
| 182 this, config.samples_per_second, backend_->Primary())); | 229 this, config.samples_per_second, backend_->Primary())); |
| 183 mixer_input_->SetVolumeMultiplier(volume_multiplier_); | 230 mixer_input_->SetVolumeMultiplier(volume_multiplier_); |
| 231 pending_write_pcm_ = false; | |
| 232 pending_output_frames_ = 0; | |
| 184 } | 233 } |
| 185 | 234 |
| 186 config_ = config; | 235 config_ = config; |
| 187 decoder_.reset(); | 236 decoder_.reset(); |
| 188 CreateDecoder(); | 237 CreateDecoder(); |
| 238 | |
| 239 if (pending_buffer_complete_ && !rate_shifter_->IsQueueFull()) { | |
|
slan
2016/12/07 00:22:27
Why do we need to check the rate_shifter queue her
kmackay
2016/12/07 22:59:57
We need to have flow control, so the app doesn't p
slan
2016/12/09 00:05:31
Acknowledged.
| |
| 240 pending_buffer_complete_ = false; | |
| 241 delegate_->OnPushBufferComplete(MediaPipelineBackendAlsa::kBufferSuccess); | |
| 242 } | |
| 189 return true; | 243 return true; |
| 190 } | 244 } |
| 191 | 245 |
| 192 void AudioDecoderAlsa::CreateDecoder() { | 246 void AudioDecoderAlsa::CreateDecoder() { |
| 193 DCHECK(!decoder_); | 247 DCHECK(!decoder_); |
| 194 DCHECK(IsValidConfig(config_)); | 248 DCHECK(IsValidConfig(config_)); |
| 195 | 249 |
| 196 // No need to create a decoder if the samples are already decoded. | 250 // No need to create a decoder if the samples are already decoded. |
| 197 if (BypassDecoder()) { | 251 if (BypassDecoder()) { |
| 198 LOG(INFO) << "Data is not coded. Decoder will not be used."; | 252 LOG(INFO) << "Data is not coded. Decoder will not be used."; |
| 199 return; | 253 return; |
| 200 } | 254 } |
| 201 | 255 |
| 202 // Create a decoder. | 256 // Create a decoder. |
| 203 decoder_ = CastAudioDecoder::Create( | 257 decoder_ = CastAudioDecoder::Create( |
| 204 task_runner_, | 258 task_runner_, |
| 205 config_, | 259 config_, |
| 206 kDecoderSampleFormat, | 260 kDecoderSampleFormat, |
| 207 base::Bind(&AudioDecoderAlsa::OnDecoderInitialized, | 261 base::Bind(&AudioDecoderAlsa::OnDecoderInitialized, |
| 208 weak_factory_.GetWeakPtr())); | 262 weak_factory_.GetWeakPtr())); |
| 209 } | 263 } |
| 210 | 264 |
| 265 void AudioDecoderAlsa::CreateRateShifter(int samples_per_second) { | |
|
slan
2016/12/07 00:22:27
Do we want to DCHECK that rate_shifter_ is flushed
kmackay
2016/12/07 22:59:58
No; it might not be in some cases (eg, sample rate
slan
2016/12/09 00:05:31
In that case, wouldn't we want to play out the aud
kmackay
2016/12/09 00:21:16
Ideally yes, but we're already resetting the mixer
| |
| 266 rate_shifter_info_.clear(); | |
| 267 rate_shifter_info_.push_back(RateShifterInfo(1.0f)); | |
| 268 | |
| 269 rate_shifter_.reset(new ::media::AudioRendererAlgorithm()); | |
| 270 rate_shifter_->Initialize(::media::AudioParameters( | |
| 271 ::media::AudioParameters::AUDIO_PCM_LINEAR, | |
| 272 ::media::CHANNEL_LAYOUT_STEREO, samples_per_second, kBitsPerSample, | |
| 273 kDefaultFramesPerBuffer)); | |
| 274 } | |
| 275 | |
| 211 bool AudioDecoderAlsa::SetVolume(float multiplier) { | 276 bool AudioDecoderAlsa::SetVolume(float multiplier) { |
| 212 TRACE_FUNCTION_ENTRY1(multiplier); | 277 TRACE_FUNCTION_ENTRY1(multiplier); |
| 213 DCHECK(task_runner_->BelongsToCurrentThread()); | 278 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 214 volume_multiplier_ = multiplier; | 279 volume_multiplier_ = multiplier; |
| 215 if (mixer_input_) | 280 if (mixer_input_) |
| 216 mixer_input_->SetVolumeMultiplier(volume_multiplier_); | 281 mixer_input_->SetVolumeMultiplier(volume_multiplier_); |
| 217 return true; | 282 return true; |
| 218 } | 283 } |
| 219 | 284 |
| 220 AudioDecoderAlsa::RenderingDelay AudioDecoderAlsa::GetRenderingDelay() { | 285 AudioDecoderAlsa::RenderingDelay AudioDecoderAlsa::GetRenderingDelay() { |
| 221 TRACE_FUNCTION_ENTRY0(); | 286 TRACE_FUNCTION_ENTRY0(); |
| 222 return last_known_delay_; | 287 AudioDecoderAlsa::RenderingDelay delay = last_known_delay_; |
| 288 if (delay.timestamp_microseconds != kInvalidTimestamp) { | |
| 289 double usec_per_sample = 1000000.0 / config_.samples_per_second; | |
| 290 for (const RateShifterInfo& info : rate_shifter_info_) { | |
|
slan
2016/12/07 00:22:27
This is dense. Could you put a simple comment insi
kmackay
2016/12/07 22:59:58
Added comments. The last_known_delay_ is the last
slan
2016/12/09 00:05:31
OK, I get it now.
| |
| 291 double queued_output_frames = | |
| 292 (info.input_frames / info.rate) - info.output_frames; | |
| 293 delay.delay_microseconds += queued_output_frames * usec_per_sample; | |
| 294 } | |
| 295 | |
| 296 delay.delay_microseconds += pending_output_frames_ * usec_per_sample; | |
| 297 } | |
| 298 | |
| 299 return delay; | |
| 223 } | 300 } |
| 224 | 301 |
| 225 void AudioDecoderAlsa::OnDecoderInitialized(bool success) { | 302 void AudioDecoderAlsa::OnDecoderInitialized(bool success) { |
| 226 TRACE_FUNCTION_ENTRY0(); | 303 TRACE_FUNCTION_ENTRY0(); |
| 227 DCHECK(task_runner_->BelongsToCurrentThread()); | 304 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 228 LOG(INFO) << "Decoder initialization was " | 305 LOG(INFO) << "Decoder initialization was " |
| 229 << (success ? "successful" : "unsuccessful"); | 306 << (success ? "successful" : "unsuccessful"); |
| 230 if (!success) | 307 if (!success) |
| 231 delegate_->OnDecoderError(); | 308 delegate_->OnDecoderError(); |
| 232 } | 309 } |
| 233 | 310 |
| 234 void AudioDecoderAlsa::OnBufferDecoded( | 311 void AudioDecoderAlsa::OnBufferDecoded( |
| 235 uint64_t input_bytes, | 312 uint64_t input_bytes, |
| 236 CastAudioDecoder::Status status, | 313 CastAudioDecoder::Status status, |
| 237 const scoped_refptr<DecoderBufferBase>& decoded) { | 314 const scoped_refptr<DecoderBufferBase>& decoded) { |
| 238 TRACE_FUNCTION_ENTRY0(); | 315 TRACE_FUNCTION_ENTRY0(); |
| 239 DCHECK(task_runner_->BelongsToCurrentThread()); | 316 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 240 DCHECK(!is_eos_); | 317 DCHECK(!got_eos_); |
| 241 | 318 DCHECK(!pending_buffer_complete_); |
| 242 Statistics delta = Statistics(); | 319 DCHECK(rate_shifter_); |
| 243 | 320 |
| 244 if (status == CastAudioDecoder::Status::kDecodeError) { | 321 if (status == CastAudioDecoder::Status::kDecodeError) { |
| 245 LOG(ERROR) << "Decode error"; | 322 LOG(ERROR) << "Decode error"; |
| 246 task_runner_->PostTask(FROM_HERE, | 323 delegate_->OnPushBufferComplete(MediaPipelineBackendAlsa::kBufferFailed); |
| 247 base::Bind(&AudioDecoderAlsa::OnWritePcmCompletion, | 324 return; |
| 248 weak_factory_.GetWeakPtr(), | 325 } |
| 249 MediaPipelineBackendAlsa::kBufferFailed, | 326 if (error_) { |
|
slan
2016/12/07 00:22:27
Can we rename this variable to mixer_error_? This
kmackay
2016/12/07 22:59:58
Done.
| |
| 250 kInvalidRenderingDelay())); | 327 delegate_->OnPushBufferComplete(MediaPipelineBackendAlsa::kBufferFailed); |
| 251 UpdateStatistics(delta); | |
| 252 return; | 328 return; |
| 253 } | 329 } |
| 254 | 330 |
| 331 Statistics delta; | |
| 255 delta.decoded_bytes = input_bytes; | 332 delta.decoded_bytes = input_bytes; |
| 256 UpdateStatistics(delta); | 333 UpdateStatistics(delta); |
| 257 | 334 |
| 258 if (decoded->end_of_stream()) | 335 if (decoded->end_of_stream()) { |
| 259 is_eos_ = true; | 336 got_eos_ = true; |
| 337 } else { | |
| 338 int input_frames = decoded->data_size() / (2 * sizeof(float)); | |
|
slan
2016/12/07 00:22:27
nit: kNumChannels
kmackay
2016/12/07 22:59:57
Done.
| |
| 260 | 339 |
| 340 RateShifterInfo* rate_info = &rate_shifter_info_.front(); | |
| 341 // Bypass rate shifter if the rate is 1.0. | |
| 342 if (rate_info->rate == 1.0 && rate_shifter_->frames_buffered() == 0 && | |
| 343 !pending_write_pcm_) { | |
| 344 DCHECK_EQ(rate_info->output_frames, rate_info->input_frames); | |
| 345 pending_buffer_complete_ = true; | |
| 346 pending_write_pcm_ = true; | |
| 347 pending_output_frames_ = input_frames; | |
| 348 if (got_eos_) { | |
|
halliwell
2016/12/06 17:27:59
I don't think this branch can be hit? DCHECK(!got
slan
2016/12/07 00:22:27
got_eos_ can mutate above (line 336)
meganit, tho
kmackay
2016/12/07 22:59:57
I prefer to set the state variables before calling
slan
2016/12/09 00:05:31
Yes, I suppose that's fair...
| |
| 349 DCHECK(!pushed_eos_); | |
| 350 pushed_eos_ = true; | |
| 351 } | |
| 352 mixer_input_->WritePcm(decoded); | |
| 353 return; | |
| 354 } | |
| 355 | |
| 356 const uint8_t* channels[2] = { | |
|
slan
2016/12/07 00:22:27
Add comment:
// Otherwise, if the rate is not 1.0
kmackay
2016/12/07 22:59:57
Done.
| |
| 357 decoded->data(), decoded->data() + input_frames * sizeof(float)}; | |
| 358 scoped_refptr<::media::AudioBuffer> buffer = ::media::AudioBuffer::CopyFrom( | |
| 359 ::media::kSampleFormatPlanarF32, ::media::CHANNEL_LAYOUT_STEREO, 2, | |
| 360 config_.samples_per_second, input_frames, channels, base::TimeDelta()); | |
| 361 rate_shifter_->EnqueueBuffer(buffer); | |
| 362 rate_shifter_info_.back().input_frames += input_frames; | |
| 363 } | |
| 364 | |
| 365 PushRateShifted(); | |
| 366 if (decoded->end_of_stream() || (!rate_shifter_->IsQueueFull() && | |
|
slan
2016/12/07 00:22:27
Why not check got_eos_?
kmackay
2016/12/07 22:59:57
Added comment.
| |
| 367 rate_shifter_info_.front().rate != 1.0)) { | |
| 368 delegate_->OnPushBufferComplete(MediaPipelineBackendAlsa::kBufferSuccess); | |
| 369 } else { | |
| 370 pending_buffer_complete_ = true; | |
| 371 } | |
| 372 } | |
| 373 | |
| 374 void AudioDecoderAlsa::PushRateShifted() { | |
| 261 DCHECK(mixer_input_); | 375 DCHECK(mixer_input_); |
| 262 mixer_input_->WritePcm(decoded); | 376 |
| 377 if (pending_write_pcm_) { | |
| 378 return; | |
| 379 } | |
| 380 | |
| 381 if (got_eos_) { | |
| 382 // Push some silence into the rate shifter so we can get out any remaining | |
| 383 // rate-shifted data. | |
|
slan
2016/12/07 00:22:27
Perhaps make this an anonymous function that takes
kmackay
2016/12/07 22:59:57
Done.
| |
| 384 scoped_refptr<::media::AudioBuffer> silence_buffer = | |
| 385 ::media::AudioBuffer::CreateBuffer( | |
| 386 ::media::kSampleFormatPlanarF32, ::media::CHANNEL_LAYOUT_STEREO, 2, | |
| 387 config_.samples_per_second, kSilenceBufferFrames); | |
| 388 for (uint8_t* channel : silence_buffer->channel_data()) { | |
| 389 float* real_channel = reinterpret_cast<float*>(channel); | |
| 390 std::fill_n(real_channel, kSilenceBufferFrames, 0.0f); | |
| 391 } | |
| 392 | |
| 393 rate_shifter_->EnqueueBuffer(silence_buffer); | |
| 394 } | |
| 395 | |
| 396 RateShifterInfo* rate_info = &rate_shifter_info_.front(); | |
|
slan
2016/12/07 00:22:27
It seems to be an implicit assumption everywhere t
kmackay
2016/12/07 22:59:57
Done.
| |
| 397 int64_t possible_output_frames = rate_info->input_frames / rate_info->rate; | |
| 398 DCHECK_GE(possible_output_frames, rate_info->output_frames); | |
| 399 | |
| 400 int desired_output_frames = possible_output_frames - rate_info->output_frames; | |
| 401 if (desired_output_frames == 0) { | |
| 402 if (got_eos_) { | |
| 403 DCHECK(!pushed_eos_); | |
| 404 pending_write_pcm_ = true; | |
| 405 pushed_eos_ = true; | |
| 406 | |
| 407 scoped_refptr<DecoderBufferBase> eos_buffer( | |
| 408 new DecoderBufferAdapter(::media::DecoderBuffer::CreateEOSBuffer())); | |
| 409 mixer_input_->WritePcm(eos_buffer); | |
| 410 } | |
| 411 return; | |
| 412 } | |
| 413 // Don't push too many frames at a time. | |
| 414 desired_output_frames = std::min( | |
| 415 desired_output_frames, config_.samples_per_second * kMaxOutputMs / 1000); | |
|
slan
2016/12/07 00:22:27
base::kMillisecondsPerSecond
kmackay
2016/12/07 22:59:57
Added constant.
| |
| 416 | |
| 417 if (desired_output_frames > rate_shifter_output_->frames()) { | |
| 418 rate_shifter_output_ = ::media::AudioBus::Create(2, desired_output_frames); | |
|
slan
2016/12/07 00:22:27
Is seems inefficient for rate_shifter_ouptut_ to b
kmackay
2016/12/07 22:59:57
It already does that? It only reallocates if it ne
slan
2016/12/09 00:05:31
Yuuuupppp, lgtm
| |
| 419 } | |
| 420 | |
| 421 int out_frames = rate_shifter_->FillBuffer( | |
| 422 rate_shifter_output_.get(), 0, desired_output_frames, rate_info->rate); | |
| 423 if (out_frames <= 0) { | |
| 424 return; | |
| 425 } | |
| 426 | |
| 427 rate_info->output_frames += out_frames; | |
| 428 DCHECK_GE(possible_output_frames, rate_info->output_frames); | |
| 429 | |
| 430 int channel_data_size = out_frames * sizeof(float); | |
|
slan
2016/12/07 00:22:27
Do we have a more conventional way of going from A
kmackay
2016/12/07 22:59:57
No, we don't. Usually we convert from ::media::Dec
slan
2016/12/09 00:05:31
Acknowledged.
| |
| 431 scoped_refptr<DecoderBufferBase> output_buffer(new DecoderBufferAdapter( | |
| 432 new ::media::DecoderBuffer(channel_data_size * 2))); | |
| 433 for (int c = 0; c < 2; ++c) { | |
| 434 memcpy(output_buffer->writable_data() + c * channel_data_size, | |
| 435 rate_shifter_output_->channel(c), channel_data_size); | |
| 436 } | |
| 437 pending_write_pcm_ = true; | |
| 438 pending_output_frames_ = out_frames; | |
| 439 mixer_input_->WritePcm(output_buffer); | |
| 440 | |
| 441 if (rate_shifter_info_.size() > 1 && | |
| 442 possible_output_frames == rate_info->output_frames) { | |
| 443 double remaining_input_frames = | |
| 444 rate_info->input_frames - (rate_info->output_frames * rate_info->rate); | |
| 445 rate_shifter_info_.pop_front(); | |
| 446 | |
| 447 rate_info = &rate_shifter_info_.front(); | |
| 448 LOG(INFO) << "New playback rate in effect: " << rate_info->rate; | |
| 449 rate_info->input_frames += remaining_input_frames; | |
| 450 DCHECK_EQ(0, rate_info->output_frames); | |
| 451 | |
| 452 // If new playback rate is 1.0, clear out 'extra' data in the rate shifter. | |
| 453 if (rate_info->rate == 1.0) { | |
| 454 int extra_frames = rate_shifter_->frames_buffered() - | |
| 455 static_cast<int>(rate_info->input_frames); | |
| 456 if (extra_frames > 0) { | |
|
slan
2016/12/07 00:22:27
When this condition hits, what has happened? Shoul
kmackay
2016/12/07 22:59:57
They already were. I added more comments.
| |
| 457 // Clear out extra buffered data. | |
| 458 std::unique_ptr<::media::AudioBus> dropped = | |
| 459 ::media::AudioBus::Create(2, extra_frames); | |
| 460 int cleared_frames = | |
| 461 rate_shifter_->FillBuffer(dropped.get(), 0, extra_frames, 1.0f); | |
| 462 DCHECK_EQ(extra_frames, cleared_frames); | |
| 463 } | |
| 464 rate_info->input_frames = rate_shifter_->frames_buffered(); | |
| 465 } | |
| 466 } | |
| 263 } | 467 } |
| 264 | 468 |
| 265 bool AudioDecoderAlsa::BypassDecoder() const { | 469 bool AudioDecoderAlsa::BypassDecoder() const { |
| 266 DCHECK(task_runner_->BelongsToCurrentThread()); | 470 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 267 // The mixer input requires planar float PCM data. | 471 // The mixer input requires planar float PCM data. |
| 268 return (config_.codec == kCodecPCM && | 472 return (config_.codec == kCodecPCM && |
| 269 config_.sample_format == kSampleFormatPlanarF32); | 473 config_.sample_format == kSampleFormatPlanarF32); |
| 270 } | 474 } |
| 271 | 475 |
| 272 void AudioDecoderAlsa::OnWritePcmCompletion(BufferStatus status, | 476 void AudioDecoderAlsa::OnWritePcmCompletion(BufferStatus status, |
|
slan
2016/12/07 00:22:27
Is it OK to ignore |status| here?
kmackay
2016/12/07 22:59:57
Added DCHECK
| |
| 273 const RenderingDelay& delay) { | 477 const RenderingDelay& delay) { |
| 274 TRACE_FUNCTION_ENTRY0(); | 478 TRACE_FUNCTION_ENTRY0(); |
| 275 DCHECK(task_runner_->BelongsToCurrentThread()); | 479 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 276 if (status == MediaPipelineBackendAlsa::kBufferSuccess && !is_eos_) | 480 pending_write_pcm_ = false; |
| 277 current_pts_ = last_buffer_pts_; | 481 pending_output_frames_ = 0; |
| 278 if (delay.timestamp_microseconds != kInvalidDelayTimestamp) | 482 last_known_delay_ = delay; |
| 279 last_known_delay_ = delay; | 483 |
| 280 delegate_->OnPushBufferComplete(status); | 484 if (pushed_eos_) { |
| 281 if (is_eos_) | 485 if (pending_buffer_complete_) { |
| 486 pending_buffer_complete_ = false; | |
| 487 delegate_->OnPushBufferComplete(MediaPipelineBackendAlsa::kBufferSuccess); | |
| 488 } | |
| 282 delegate_->OnEndOfStream(); | 489 delegate_->OnEndOfStream(); |
| 490 } else { | |
| 491 task_runner_->PostTask(FROM_HERE, base::Bind(&AudioDecoderAlsa::PushMorePcm, | |
| 492 weak_factory_.GetWeakPtr())); | |
| 493 } | |
| 494 } | |
| 495 | |
| 496 void AudioDecoderAlsa::PushMorePcm() { | |
| 497 PushRateShifted(); | |
| 498 | |
| 499 double rate = rate_shifter_info_.front().rate; | |
|
slan
2016/12/07 00:22:27
nit: Move inside if (pending_buffer_complete_), an
kmackay
2016/12/07 22:59:58
Done.
| |
| 500 if (pending_buffer_complete_ && | |
| 501 ((rate == 1.0 && !pending_write_pcm_) || | |
| 502 (rate != 1.0 && !rate_shifter_->IsQueueFull()))) { | |
| 503 pending_buffer_complete_ = false; | |
| 504 delegate_->OnPushBufferComplete(MediaPipelineBackendAlsa::kBufferSuccess); | |
| 505 } | |
| 283 } | 506 } |
| 284 | 507 |
| 285 void AudioDecoderAlsa::OnMixerError(MixerError error) { | 508 void AudioDecoderAlsa::OnMixerError(MixerError error) { |
| 286 TRACE_FUNCTION_ENTRY0(); | 509 TRACE_FUNCTION_ENTRY0(); |
| 287 DCHECK(task_runner_->BelongsToCurrentThread()); | 510 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 288 if (error != MixerError::kInputIgnored) | 511 if (error != MixerError::kInputIgnored) |
| 289 LOG(ERROR) << "Mixer error occurred."; | 512 LOG(ERROR) << "Mixer error occurred."; |
| 290 error_ = true; | 513 error_ = true; |
| 291 delegate_->OnDecoderError(); | 514 delegate_->OnDecoderError(); |
| 292 } | 515 } |
| 293 | 516 |
| 294 } // namespace media | 517 } // namespace media |
| 295 } // namespace chromecast | 518 } // namespace chromecast |
| OLD | NEW |