| 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/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 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 | 58 |
| 59 const int kMaxSlewTimeUpMs = 15; | 59 const int kMaxSlewTimeUpMs = 15; |
| 60 const int kMaxSlewTimeDownMs = 15; | 60 const int kMaxSlewTimeDownMs = 15; |
| 61 | 61 |
| 62 } // namespace | 62 } // namespace |
| 63 | 63 |
| 64 StreamMixerAlsaInputImpl::StreamMixerAlsaInputImpl( | 64 StreamMixerAlsaInputImpl::StreamMixerAlsaInputImpl( |
| 65 StreamMixerAlsaInput::Delegate* delegate, | 65 StreamMixerAlsaInput::Delegate* delegate, |
| 66 int input_samples_per_second, | 66 int input_samples_per_second, |
| 67 bool primary, | 67 bool primary, |
| 68 const std::string& device_id, |
| 68 StreamMixerAlsa* mixer) | 69 StreamMixerAlsa* mixer) |
| 69 : delegate_(delegate), | 70 : delegate_(delegate), |
| 70 input_samples_per_second_(input_samples_per_second), | 71 input_samples_per_second_(input_samples_per_second), |
| 71 primary_(primary), | 72 primary_(primary), |
| 73 device_id_(device_id), |
| 72 mixer_(mixer), | 74 mixer_(mixer), |
| 75 filter_group_(nullptr), |
| 73 mixer_task_runner_(mixer_->task_runner()), | 76 mixer_task_runner_(mixer_->task_runner()), |
| 74 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 77 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 75 resample_ratio_(1.0), | 78 resample_ratio_(1.0), |
| 76 state_(kStateUninitialized), | 79 state_(kStateUninitialized), |
| 77 slew_volume_(kMaxSlewTimeUpMs, kMaxSlewTimeDownMs), | 80 slew_volume_(kMaxSlewTimeUpMs, kMaxSlewTimeDownMs), |
| 78 queued_frames_(0), | 81 queued_frames_(0), |
| 79 queued_frames_including_resampler_(0), | 82 queued_frames_including_resampler_(0), |
| 80 current_buffer_offset_(0), | 83 current_buffer_offset_(0), |
| 81 max_queued_frames_(kMaxInputQueueUs * input_samples_per_second / | 84 max_queued_frames_(kMaxInputQueueUs * input_samples_per_second / |
| 82 base::Time::kMicrosecondsPerSecond), | 85 base::Time::kMicrosecondsPerSecond), |
| 83 fade_frames_remaining_(0), | 86 fade_frames_remaining_(0), |
| 84 fade_out_frames_total_(0), | 87 fade_out_frames_total_(0), |
| 85 zeroed_frames_(0), | 88 zeroed_frames_(0), |
| 86 is_underflowing_(false), | 89 is_underflowing_(false), |
| 87 weak_factory_(this) { | 90 weak_factory_(this) { |
| 88 LOG(INFO) << "Create " << this; | 91 LOG(INFO) << "Create " << device_id_ << " (" << this << ")"; |
| 89 DCHECK(delegate_); | 92 DCHECK(delegate_); |
| 90 DCHECK(mixer_); | 93 DCHECK(mixer_); |
| 91 weak_this_ = weak_factory_.GetWeakPtr(); | 94 weak_this_ = weak_factory_.GetWeakPtr(); |
| 92 } | 95 } |
| 93 | 96 |
| 94 StreamMixerAlsaInputImpl::~StreamMixerAlsaInputImpl() { | 97 StreamMixerAlsaInputImpl::~StreamMixerAlsaInputImpl() { |
| 95 LOG(INFO) << "Destroy " << this; | 98 LOG(INFO) << "Destroy " << device_id_ << " (" << this << ")"; |
| 96 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 99 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
| 97 } | 100 } |
| 98 | 101 |
| 99 int StreamMixerAlsaInputImpl::input_samples_per_second() const { | 102 int StreamMixerAlsaInputImpl::input_samples_per_second() const { |
| 100 return input_samples_per_second_; | 103 return input_samples_per_second_; |
| 101 } | 104 } |
| 102 | 105 |
| 103 bool StreamMixerAlsaInputImpl::primary() const { | 106 bool StreamMixerAlsaInputImpl::primary() const { |
| 104 return primary_; | 107 return primary_; |
| 105 } | 108 } |
| 106 | 109 |
| 110 std::string StreamMixerAlsaInputImpl::device_id() const { |
| 111 return device_id_; |
| 112 } |
| 113 |
| 107 bool StreamMixerAlsaInputImpl::IsDeleting() const { | 114 bool StreamMixerAlsaInputImpl::IsDeleting() const { |
| 108 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 115 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
| 109 return (state_ == kStateFinalFade || state_ == kStateDeleted); | 116 return (state_ == kStateFinalFade || state_ == kStateDeleted); |
| 110 } | 117 } |
| 111 | 118 |
| 112 void StreamMixerAlsaInputImpl::Initialize( | 119 void StreamMixerAlsaInputImpl::Initialize( |
| 113 const MediaPipelineBackendAlsa::RenderingDelay& mixer_rendering_delay) { | 120 const MediaPipelineBackendAlsa::RenderingDelay& mixer_rendering_delay) { |
| 114 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 121 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
| 115 DCHECK(!IsDeleting()); | 122 DCHECK(!IsDeleting()); |
| 116 if (mixer_->output_samples_per_second() != input_samples_per_second_) { | 123 if (mixer_->output_samples_per_second() != input_samples_per_second_) { |
| 117 resample_ratio_ = static_cast<double>(input_samples_per_second_) / | 124 resample_ratio_ = static_cast<double>(input_samples_per_second_) / |
| 118 mixer_->output_samples_per_second(); | 125 mixer_->output_samples_per_second(); |
| 119 resampler_.reset(new ::media::MultiChannelResampler( | 126 resampler_.reset(new ::media::MultiChannelResampler( |
| 120 kNumOutputChannels, resample_ratio_, kDefaultReadSize, | 127 kNumOutputChannels, resample_ratio_, kDefaultReadSize, |
| 121 base::Bind(&StreamMixerAlsaInputImpl::ReadCB, base::Unretained(this)))); | 128 base::Bind(&StreamMixerAlsaInputImpl::ReadCB, base::Unretained(this)))); |
| 122 resampler_->PrimeWithSilence(); | 129 resampler_->PrimeWithSilence(); |
| 123 } | 130 } |
| 124 slew_volume_.SetSampleRate(mixer_->output_samples_per_second()); | 131 slew_volume_.SetSampleRate(mixer_->output_samples_per_second()); |
| 125 mixer_rendering_delay_ = mixer_rendering_delay; | 132 mixer_rendering_delay_ = mixer_rendering_delay; |
| 126 fade_out_frames_total_ = NormalFadeFrames(); | 133 fade_out_frames_total_ = NormalFadeFrames(); |
| 127 fade_frames_remaining_ = NormalFadeFrames(); | 134 fade_frames_remaining_ = NormalFadeFrames(); |
| 128 } | 135 } |
| 129 | 136 |
| 137 void StreamMixerAlsaInputImpl::set_filter_group(FilterGroup* filter_group) { |
| 138 filter_group_ = filter_group; |
| 139 } |
| 140 |
| 141 FilterGroup* StreamMixerAlsaInputImpl::filter_group() { |
| 142 return filter_group_; |
| 143 } |
| 144 |
| 130 void StreamMixerAlsaInputImpl::PreventDelegateCalls() { | 145 void StreamMixerAlsaInputImpl::PreventDelegateCalls() { |
| 131 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 146 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 132 weak_factory_.InvalidateWeakPtrs(); | 147 weak_factory_.InvalidateWeakPtrs(); |
| 133 | 148 |
| 134 base::AutoLock lock(queue_lock_); | 149 base::AutoLock lock(queue_lock_); |
| 135 pending_data_ = nullptr; | 150 pending_data_ = nullptr; |
| 136 } | 151 } |
| 137 | 152 |
| 138 void StreamMixerAlsaInputImpl::PrepareToDelete( | 153 void StreamMixerAlsaInputImpl::PrepareToDelete( |
| 139 const OnReadyToDeleteCb& delete_cb) { | 154 const OnReadyToDeleteCb& delete_cb) { |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 int StreamMixerAlsaInputImpl::NormalFadeFrames() { | 434 int StreamMixerAlsaInputImpl::NormalFadeFrames() { |
| 420 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 435 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
| 421 int frames = (mixer_->output_samples_per_second() * kFadeMs / | 436 int frames = (mixer_->output_samples_per_second() * kFadeMs / |
| 422 base::Time::kMillisecondsPerSecond) - | 437 base::Time::kMillisecondsPerSecond) - |
| 423 1; | 438 1; |
| 424 return std::max(frames, 0); | 439 return std::max(frames, 0); |
| 425 } | 440 } |
| 426 | 441 |
| 427 void StreamMixerAlsaInputImpl::FadeIn(::media::AudioBus* dest, int frames) { | 442 void StreamMixerAlsaInputImpl::FadeIn(::media::AudioBus* dest, int frames) { |
| 428 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 443 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
| 429 LOG(INFO) << "Fading in, " << fade_frames_remaining_ << " frames remaining"; | |
| 430 float fade_in_frames = mixer_->output_samples_per_second() * kFadeMs / | 444 float fade_in_frames = mixer_->output_samples_per_second() * kFadeMs / |
| 431 base::Time::kMillisecondsPerSecond; | 445 base::Time::kMillisecondsPerSecond; |
| 432 for (int f = 0; f < frames && fade_frames_remaining_; ++f) { | 446 for (int f = 0; f < frames && fade_frames_remaining_; ++f) { |
| 433 float fade_multiplier = 1.0 - fade_frames_remaining_ / fade_in_frames; | 447 float fade_multiplier = 1.0 - fade_frames_remaining_ / fade_in_frames; |
| 434 for (int c = 0; c < kNumOutputChannels; ++c) | 448 for (int c = 0; c < kNumOutputChannels; ++c) |
| 435 dest->channel(c)[f] *= fade_multiplier; | 449 dest->channel(c)[f] *= fade_multiplier; |
| 436 --fade_frames_remaining_; | 450 --fade_frames_remaining_; |
| 437 } | 451 } |
| 438 } | 452 } |
| 439 | 453 |
| 440 void StreamMixerAlsaInputImpl::FadeOut(::media::AudioBus* dest, int frames) { | 454 void StreamMixerAlsaInputImpl::FadeOut(::media::AudioBus* dest, int frames) { |
| 441 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 455 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
| 442 LOG(INFO) << "Fading out, " << fade_frames_remaining_ << " frames remaining"; | |
| 443 int f = 0; | 456 int f = 0; |
| 444 for (; f < frames && fade_frames_remaining_; ++f) { | 457 for (; f < frames && fade_frames_remaining_; ++f) { |
| 445 float fade_multiplier = | 458 float fade_multiplier = |
| 446 fade_frames_remaining_ / static_cast<float>(fade_out_frames_total_); | 459 fade_frames_remaining_ / static_cast<float>(fade_out_frames_total_); |
| 447 for (int c = 0; c < kNumOutputChannels; ++c) | 460 for (int c = 0; c < kNumOutputChannels; ++c) |
| 448 dest->channel(c)[f] *= fade_multiplier; | 461 dest->channel(c)[f] *= fade_multiplier; |
| 449 --fade_frames_remaining_; | 462 --fade_frames_remaining_; |
| 450 } | 463 } |
| 451 // Zero remaining frames | 464 // Zero remaining frames |
| 452 for (; f < frames; ++f) { | 465 for (; f < frames; ++f) { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 | 521 |
| 509 if (state_ == kStateFadingOut) { | 522 if (state_ == kStateFadingOut) { |
| 510 // Tell the mixer that some more data might be available (since when fading | 523 // Tell the mixer that some more data might be available (since when fading |
| 511 // out, we can drain the queue completely). | 524 // out, we can drain the queue completely). |
| 512 mixer_->OnFramesQueued(); | 525 mixer_->OnFramesQueued(); |
| 513 } | 526 } |
| 514 } | 527 } |
| 515 | 528 |
| 516 void StreamMixerAlsaInputImpl::SetVolumeMultiplier(float multiplier) { | 529 void StreamMixerAlsaInputImpl::SetVolumeMultiplier(float multiplier) { |
| 517 RUN_ON_MIXER_THREAD(SetVolumeMultiplier, multiplier); | 530 RUN_ON_MIXER_THREAD(SetVolumeMultiplier, multiplier); |
| 518 LOG(INFO) << this << ": stream volume = " << multiplier; | 531 LOG(INFO) << device_id_ << "(" << this << "): stream volume = " << multiplier; |
| 519 DCHECK(!IsDeleting()); | 532 DCHECK(!IsDeleting()); |
| 520 if (multiplier > 1.0f) | 533 if (multiplier > 1.0f) |
| 521 multiplier = 1.0f; | 534 multiplier = 1.0f; |
| 522 if (multiplier < 0.0f) | 535 if (multiplier < 0.0f) |
| 523 multiplier = 0.0f; | 536 multiplier = 0.0f; |
| 524 slew_volume_.SetVolume(multiplier); | 537 slew_volume_.SetVolume(multiplier); |
| 525 } | 538 } |
| 526 | 539 |
| 527 void StreamMixerAlsaInputImpl::VolumeScaleAccumulate(bool repeat_transition, | 540 void StreamMixerAlsaInputImpl::VolumeScaleAccumulate(bool repeat_transition, |
| 528 const float* src, | 541 const float* src, |
| 529 int frames, | 542 int frames, |
| 530 float* dest) { | 543 float* dest) { |
| 531 slew_volume_.ProcessFMAC(repeat_transition, src, frames, dest); | 544 slew_volume_.ProcessFMAC(repeat_transition, src, frames, dest); |
| 532 } | 545 } |
| 533 | 546 |
| 534 } // namespace media | 547 } // namespace media |
| 535 } // namespace chromecast | 548 } // namespace chromecast |
| OLD | NEW |