Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(296)

Side by Side Diff: chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.cc

Issue 2324533002: [Chromecast] Fix fade-out frames in ALSA mixer (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/stream_mixer_alsa_input_impl.h" 5 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 StreamMixerAlsaInput::Delegate* delegate, 62 StreamMixerAlsaInput::Delegate* delegate,
63 int input_samples_per_second, 63 int input_samples_per_second,
64 bool primary, 64 bool primary,
65 StreamMixerAlsa* mixer) 65 StreamMixerAlsa* mixer)
66 : delegate_(delegate), 66 : delegate_(delegate),
67 input_samples_per_second_(input_samples_per_second), 67 input_samples_per_second_(input_samples_per_second),
68 primary_(primary), 68 primary_(primary),
69 mixer_(mixer), 69 mixer_(mixer),
70 mixer_task_runner_(mixer_->task_runner()), 70 mixer_task_runner_(mixer_->task_runner()),
71 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), 71 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()),
72 resample_ratio_(1.0),
72 state_(kStateUninitialized), 73 state_(kStateUninitialized),
73 volume_multiplier_(1.0f), 74 volume_multiplier_(1.0f),
74 queued_frames_(0), 75 queued_frames_(0),
75 queued_frames_including_resampler_(0), 76 queued_frames_including_resampler_(0),
76 current_buffer_offset_(0), 77 current_buffer_offset_(0),
77 max_queued_frames_(kMaxInputQueueUs * input_samples_per_second / 78 max_queued_frames_(kMaxInputQueueUs * input_samples_per_second /
78 base::Time::kMicrosecondsPerSecond), 79 base::Time::kMicrosecondsPerSecond),
79 fade_frames_remaining_(0), 80 fade_frames_remaining_(0),
80 fade_out_frames_total_(0), 81 fade_out_frames_total_(0),
81 zeroed_frames_(0), 82 zeroed_frames_(0),
82 weak_factory_(this) { 83 weak_factory_(this) {
84 LOG(INFO) << "Create " << this;
83 DCHECK(delegate_); 85 DCHECK(delegate_);
84 DCHECK(mixer_); 86 DCHECK(mixer_);
85 weak_this_ = weak_factory_.GetWeakPtr(); 87 weak_this_ = weak_factory_.GetWeakPtr();
86 } 88 }
87 89
88 StreamMixerAlsaInputImpl::~StreamMixerAlsaInputImpl() { 90 StreamMixerAlsaInputImpl::~StreamMixerAlsaInputImpl() {
91 LOG(INFO) << "Destroy " << this;
89 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); 92 DCHECK(mixer_task_runner_->BelongsToCurrentThread());
90 } 93 }
91 94
92 int StreamMixerAlsaInputImpl::input_samples_per_second() const { 95 int StreamMixerAlsaInputImpl::input_samples_per_second() const {
93 return input_samples_per_second_; 96 return input_samples_per_second_;
94 } 97 }
95 98
96 float StreamMixerAlsaInputImpl::volume_multiplier() const { 99 float StreamMixerAlsaInputImpl::volume_multiplier() const {
97 return volume_multiplier_; 100 return volume_multiplier_;
98 } 101 }
99 102
100 bool StreamMixerAlsaInputImpl::primary() const { 103 bool StreamMixerAlsaInputImpl::primary() const {
101 return primary_; 104 return primary_;
102 } 105 }
103 106
104 bool StreamMixerAlsaInputImpl::IsDeleting() const { 107 bool StreamMixerAlsaInputImpl::IsDeleting() const {
105 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); 108 DCHECK(mixer_task_runner_->BelongsToCurrentThread());
106 return (state_ == kStateFinalFade || state_ == kStateDeleted); 109 return (state_ == kStateFinalFade || state_ == kStateDeleted);
107 } 110 }
108 111
109 void StreamMixerAlsaInputImpl::Initialize( 112 void StreamMixerAlsaInputImpl::Initialize(
110 const MediaPipelineBackendAlsa::RenderingDelay& mixer_rendering_delay) { 113 const MediaPipelineBackendAlsa::RenderingDelay& mixer_rendering_delay) {
111 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); 114 DCHECK(mixer_task_runner_->BelongsToCurrentThread());
112 DCHECK(!IsDeleting()); 115 DCHECK(!IsDeleting());
113 if (mixer_->output_samples_per_second() != input_samples_per_second_) { 116 if (mixer_->output_samples_per_second() != input_samples_per_second_) {
114 double resample_ratio = static_cast<double>(input_samples_per_second_) / 117 resample_ratio_ = static_cast<double>(input_samples_per_second_) /
115 mixer_->output_samples_per_second(); 118 mixer_->output_samples_per_second();
116 resampler_.reset(new ::media::MultiChannelResampler( 119 resampler_.reset(new ::media::MultiChannelResampler(
117 kNumOutputChannels, resample_ratio, kDefaultReadSize, 120 kNumOutputChannels, resample_ratio_, kDefaultReadSize,
118 base::Bind(&StreamMixerAlsaInputImpl::ReadCB, base::Unretained(this)))); 121 base::Bind(&StreamMixerAlsaInputImpl::ReadCB, base::Unretained(this))));
119 resampler_->PrimeWithSilence(); 122 resampler_->PrimeWithSilence();
120 } 123 }
121 mixer_rendering_delay_ = mixer_rendering_delay; 124 mixer_rendering_delay_ = mixer_rendering_delay;
122 fade_out_frames_total_ = NormalFadeFrames(); 125 fade_out_frames_total_ = NormalFadeFrames();
123 fade_frames_remaining_ = NormalFadeFrames(); 126 fade_frames_remaining_ = NormalFadeFrames();
124 } 127 }
125 128
126 void StreamMixerAlsaInputImpl::PreventDelegateCalls() { 129 void StreamMixerAlsaInputImpl::PreventDelegateCalls() {
127 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 130 DCHECK(caller_task_runner_->BelongsToCurrentThread());
(...skipping 11 matching lines...) Expand all
139 delete_cb_ = delete_cb; 142 delete_cb_ = delete_cb;
140 if (state_ != kStateNormalPlayback && state_ != kStateFadingOut && 143 if (state_ != kStateNormalPlayback && state_ != kStateFadingOut &&
141 state_ != kStateGotEos) { 144 state_ != kStateGotEos) {
142 DeleteThis(); 145 DeleteThis();
143 return; 146 return;
144 } 147 }
145 148
146 { 149 {
147 base::AutoLock lock(queue_lock_); 150 base::AutoLock lock(queue_lock_);
148 if (state_ == kStateGotEos) { 151 if (state_ == kStateGotEos) {
149 fade_out_frames_total_ = queued_frames_including_resampler_; 152 fade_out_frames_total_ =
150 fade_frames_remaining_ = queued_frames_including_resampler_; 153 queued_frames_including_resampler_ / resample_ratio_;
154 fade_frames_remaining_ =
155 queued_frames_including_resampler_ / resample_ratio_;
151 } else if (state_ == kStateNormalPlayback) { 156 } else if (state_ == kStateNormalPlayback) {
152 fade_out_frames_total_ = 157 fade_out_frames_total_ =
153 std::min(static_cast<int>(queued_frames_including_resampler_), 158 std::min(static_cast<int>(queued_frames_including_resampler_ /
159 resample_ratio_),
154 NormalFadeFrames()); 160 NormalFadeFrames());
155 fade_frames_remaining_ = fade_out_frames_total_; 161 fade_frames_remaining_ = fade_out_frames_total_;
156 } 162 }
157 } 163 }
158 164
159 state_ = kStateFinalFade; 165 state_ = kStateFinalFade;
160 if (fade_frames_remaining_ == 0) { 166 if (fade_frames_remaining_ == 0) {
161 DeleteThis(); 167 DeleteThis();
162 } else { 168 } else {
163 // Tell the mixer that some more data might be available (since when fading 169 // Tell the mixer that some more data might be available (since when fading
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 const MediaPipelineBackendAlsa::RenderingDelay& delay) { 220 const MediaPipelineBackendAlsa::RenderingDelay& delay) {
215 RUN_ON_CALLER_THREAD(PostPcmCallback, delay); 221 RUN_ON_CALLER_THREAD(PostPcmCallback, delay);
216 delegate_->OnWritePcmCompletion(MediaPipelineBackendAlsa::kBufferSuccess, 222 delegate_->OnWritePcmCompletion(MediaPipelineBackendAlsa::kBufferSuccess,
217 delay); 223 delay);
218 } 224 }
219 225
220 void StreamMixerAlsaInputImpl::DidQueueData(bool end_of_stream) { 226 void StreamMixerAlsaInputImpl::DidQueueData(bool end_of_stream) {
221 RUN_ON_MIXER_THREAD(DidQueueData, end_of_stream); 227 RUN_ON_MIXER_THREAD(DidQueueData, end_of_stream);
222 DCHECK(!IsDeleting()); 228 DCHECK(!IsDeleting());
223 if (end_of_stream) { 229 if (end_of_stream) {
230 LOG(INFO) << "End of stream for " << this;
224 state_ = kStateGotEos; 231 state_ = kStateGotEos;
225 } else if (state_ == kStateUninitialized) { 232 } else if (state_ == kStateUninitialized) {
226 state_ = kStateNormalPlayback; 233 state_ = kStateNormalPlayback;
227 } 234 }
228 mixer_->OnFramesQueued(); 235 mixer_->OnFramesQueued();
229 } 236 }
230 237
231 void StreamMixerAlsaInputImpl::AfterWriteFrames( 238 void StreamMixerAlsaInputImpl::AfterWriteFrames(
232 const MediaPipelineBackendAlsa::RenderingDelay& mixer_rendering_delay) { 239 const MediaPipelineBackendAlsa::RenderingDelay& mixer_rendering_delay) {
233 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); 240 DCHECK(mixer_task_runner_->BelongsToCurrentThread());
234 double resampler_queued_frames = 241 double resampler_queued_frames =
235 (resampler_ ? resampler_->BufferedFrames() : 0); 242 (resampler_ ? resampler_->BufferedFrames() : 0);
236 243
237 bool queued_more_data = false; 244 bool queued_more_data = false;
238 MediaPipelineBackendAlsa::RenderingDelay total_delay; 245 MediaPipelineBackendAlsa::RenderingDelay total_delay;
239 { 246 {
240 base::AutoLock lock(queue_lock_); 247 base::AutoLock lock(queue_lock_);
241 mixer_rendering_delay_ = mixer_rendering_delay; 248 mixer_rendering_delay_ = mixer_rendering_delay;
242 queued_frames_ = 0; 249 queued_frames_ = 0;
243 for (const auto& data : queue_) 250 for (const auto& data : queue_) {
244 queued_frames_ += 251 queued_frames_ +=
245 data->data_size() / (kNumOutputChannels * sizeof(float)); 252 data->data_size() / (kNumOutputChannels * sizeof(float));
253 }
246 queued_frames_ -= current_buffer_offset_; 254 queued_frames_ -= current_buffer_offset_;
247 DCHECK_GE(queued_frames_, 0); 255 DCHECK_GE(queued_frames_, 0);
248 queued_frames_including_resampler_ = 256 queued_frames_including_resampler_ =
249 queued_frames_ + resampler_queued_frames; 257 queued_frames_ + resampler_queued_frames;
250 258
251 if (pending_data_ && queued_frames_ < max_queued_frames_) { 259 if (pending_data_ && queued_frames_ < max_queued_frames_) {
252 scoped_refptr<DecoderBufferBase> data = pending_data_; 260 scoped_refptr<DecoderBufferBase> data = pending_data_;
253 pending_data_ = nullptr; 261 pending_data_ = nullptr;
254 total_delay = QueueData(data); 262 total_delay = QueueData(data);
255 queued_more_data = true; 263 queued_more_data = true;
256 if (data->end_of_stream()) 264 if (data->end_of_stream()) {
265 LOG(INFO) << "End of stream for " << this;
257 state_ = kStateGotEos; 266 state_ = kStateGotEos;
267 }
258 } 268 }
259 } 269 }
260 270
261 if (queued_more_data) 271 if (queued_more_data)
262 PostPcmCallback(total_delay); 272 PostPcmCallback(total_delay);
263 } 273 }
264 274
265 int StreamMixerAlsaInputImpl::MaxReadSize() { 275 int StreamMixerAlsaInputImpl::MaxReadSize() {
266 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); 276 DCHECK(mixer_task_runner_->BelongsToCurrentThread());
267 if (state_ == kStatePaused || state_ == kStateDeleted) 277 if (state_ == kStatePaused || state_ == kStateDeleted)
268 return kPausedReadSamples; 278 return kPausedReadSamples;
269 if (state_ == kStateFinalFade) 279 if (state_ == kStateFinalFade)
270 return fade_frames_remaining_; 280 return fade_frames_remaining_;
271 281
272 int queued_frames; 282 int queued_frames;
273 { 283 {
274 base::AutoLock lock(queue_lock_); 284 base::AutoLock lock(queue_lock_);
275 if (state_ == kStateGotEos) 285 if (state_ == kStateGotEos)
276 return std::max(static_cast<int>(queued_frames_including_resampler_), 286 return std::max(static_cast<int>(queued_frames_including_resampler_ /
287 resample_ratio_),
277 kDefaultReadSize); 288 kDefaultReadSize);
278 queued_frames = queued_frames_; 289 queued_frames = queued_frames_;
279 } 290 }
280 291
281 int available_frames = 0; 292 int available_frames = 0;
282 if (resampler_) { 293 if (resampler_) {
283 int num_chunks = queued_frames / kDefaultReadSize; 294 int num_chunks = queued_frames / kDefaultReadSize;
284 available_frames = resampler_->ChunkSize() * num_chunks; 295 available_frames = resampler_->ChunkSize() * num_chunks;
285 } else { 296 } else {
286 available_frames = queued_frames; 297 available_frames = queued_frames;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 if (buffer) { 372 if (buffer) {
362 const float* buffer_samples = 373 const float* buffer_samples =
363 reinterpret_cast<const float*>(buffer->data()); 374 reinterpret_cast<const float*>(buffer->data());
364 for (int i = 0; i < kNumOutputChannels; ++i) { 375 for (int i = 0; i < kNumOutputChannels; ++i) {
365 const float* buffer_channel = buffer_samples + (buffer_frames * i); 376 const float* buffer_channel = buffer_samples + (buffer_frames * i);
366 memcpy(output->channel(i) + frames_filled, 377 memcpy(output->channel(i) + frames_filled,
367 buffer_channel + buffer_offset, frames_to_copy * sizeof(float)); 378 buffer_channel + buffer_offset, frames_to_copy * sizeof(float));
368 } 379 }
369 frames_left -= frames_to_copy; 380 frames_left -= frames_to_copy;
370 frames_filled += frames_to_copy; 381 frames_filled += frames_to_copy;
371 LOG_IF(WARNING, zeroed_frames_ > 0) << "Filled a total of " 382 LOG_IF(WARNING, state_ != kStateFinalFade && zeroed_frames_ > 0)
372 << zeroed_frames_ << " frames with 0"; 383 << "Filled a total of " << zeroed_frames_ << " frames with 0";
373 zeroed_frames_ = 0; 384 zeroed_frames_ = 0;
374 } else { 385 } else {
375 // No data left in queue; fill remaining frames with zeros. 386 // No data left in queue; fill remaining frames with zeros.
376 LOG_IF(WARNING, zeroed_frames_ == 0) << "Starting to fill frames with 0"; 387 LOG_IF(WARNING, state_ != kStateFinalFade && zeroed_frames_ == 0)
388 << "Starting to fill frames with 0";
377 zeroed_frames_ += frames_left; 389 zeroed_frames_ += frames_left;
378 output->ZeroFramesPartial(frames_filled, frames_left); 390 output->ZeroFramesPartial(frames_filled, frames_left);
379 frames_filled += frames_left; 391 frames_filled += frames_left;
380 frames_left = 0; 392 frames_left = 0;
381 break; 393 break;
382 } 394 }
383 } 395 }
384 396
385 DCHECK_EQ(0, frames_left); 397 DCHECK_EQ(0, frames_left);
386 DCHECK_EQ(frames, frames_filled); 398 DCHECK_EQ(frames, frames_filled);
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 490
479 if (state_ == kStateFadingOut) { 491 if (state_ == kStateFadingOut) {
480 // Tell the mixer that some more data might be available (since when fading 492 // Tell the mixer that some more data might be available (since when fading
481 // out, we can drain the queue completely). 493 // out, we can drain the queue completely).
482 mixer_->OnFramesQueued(); 494 mixer_->OnFramesQueued();
483 } 495 }
484 } 496 }
485 497
486 void StreamMixerAlsaInputImpl::SetVolumeMultiplier(float multiplier) { 498 void StreamMixerAlsaInputImpl::SetVolumeMultiplier(float multiplier) {
487 RUN_ON_MIXER_THREAD(SetVolumeMultiplier, multiplier); 499 RUN_ON_MIXER_THREAD(SetVolumeMultiplier, multiplier);
500 LOG(INFO) << this << ": stream volume = " << multiplier;
488 DCHECK(!IsDeleting()); 501 DCHECK(!IsDeleting());
489 if (multiplier > 1.0f) 502 if (multiplier > 1.0f)
490 multiplier = 1.0f; 503 multiplier = 1.0f;
491 if (multiplier < 0.0f) 504 if (multiplier < 0.0f)
492 multiplier = 0.0f; 505 multiplier = 0.0f;
493 volume_multiplier_ = multiplier; 506 volume_multiplier_ = multiplier;
494 } 507 }
495 508
496 } // namespace media 509 } // namespace media
497 } // namespace chromecast 510 } // namespace chromecast
OLDNEW
« no previous file with comments | « chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698