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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 // Number of samples to report as readable when paused. When paused, the mixer | 52 // Number of samples to report as readable when paused. When paused, the mixer |
53 // will still pull this many frames each time it tries to write frames, but we | 53 // will still pull this many frames each time it tries to write frames, but we |
54 // fill the frames with silence. | 54 // fill the frames with silence. |
55 const int kPausedReadSamples = 512; | 55 const int kPausedReadSamples = 512; |
56 const int kDefaultReadSize = ::media::SincResampler::kDefaultRequestSize; | 56 const int kDefaultReadSize = ::media::SincResampler::kDefaultRequestSize; |
57 const int64_t kNoTimestamp = std::numeric_limits<int64_t>::min(); | 57 const int64_t kNoTimestamp = std::numeric_limits<int64_t>::min(); |
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 std::string AudioContentTypeToString(media::AudioContentType type) { |
| 63 switch (type) { |
| 64 case media::AudioContentType::kAlarm: |
| 65 return "alarm"; |
| 66 case media::AudioContentType::kCommunication: |
| 67 return "communication"; |
| 68 default: |
| 69 return "media"; |
| 70 } |
| 71 } |
| 72 |
62 } // namespace | 73 } // namespace |
63 | 74 |
64 StreamMixerAlsaInputImpl::StreamMixerAlsaInputImpl( | 75 StreamMixerAlsaInputImpl::StreamMixerAlsaInputImpl( |
65 StreamMixerAlsaInput::Delegate* delegate, | 76 StreamMixerAlsaInput::Delegate* delegate, |
66 int input_samples_per_second, | 77 int input_samples_per_second, |
67 bool primary, | 78 bool primary, |
68 const std::string& device_id, | 79 const std::string& device_id, |
| 80 AudioContentType content_type, |
69 StreamMixerAlsa* mixer) | 81 StreamMixerAlsa* mixer) |
70 : delegate_(delegate), | 82 : delegate_(delegate), |
71 input_samples_per_second_(input_samples_per_second), | 83 input_samples_per_second_(input_samples_per_second), |
72 primary_(primary), | 84 primary_(primary), |
73 device_id_(device_id), | 85 device_id_(device_id), |
| 86 content_type_(content_type), |
74 mixer_(mixer), | 87 mixer_(mixer), |
75 filter_group_(nullptr), | 88 filter_group_(nullptr), |
76 mixer_task_runner_(mixer_->task_runner()), | 89 mixer_task_runner_(mixer_->task_runner()), |
77 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 90 caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
78 resample_ratio_(1.0), | 91 resample_ratio_(1.0), |
79 state_(kStateUninitialized), | 92 state_(kStateUninitialized), |
| 93 stream_volume_multiplier_(1.0f), |
| 94 type_volume_multiplier_(1.0f), |
| 95 mute_volume_multiplier_(1.0f), |
80 slew_volume_(kMaxSlewTimeUpMs, kMaxSlewTimeDownMs), | 96 slew_volume_(kMaxSlewTimeUpMs, kMaxSlewTimeDownMs), |
81 queued_frames_(0), | 97 queued_frames_(0), |
82 queued_frames_including_resampler_(0), | 98 queued_frames_including_resampler_(0), |
83 current_buffer_offset_(0), | 99 current_buffer_offset_(0), |
84 max_queued_frames_(kMaxInputQueueUs * input_samples_per_second / | 100 max_queued_frames_(kMaxInputQueueUs * input_samples_per_second / |
85 base::Time::kMicrosecondsPerSecond), | 101 base::Time::kMicrosecondsPerSecond), |
86 fade_frames_remaining_(0), | 102 fade_frames_remaining_(0), |
87 fade_out_frames_total_(0), | 103 fade_out_frames_total_(0), |
88 zeroed_frames_(0), | 104 zeroed_frames_(0), |
89 is_underflowing_(false), | 105 is_underflowing_(false), |
90 weak_factory_(this) { | 106 weak_factory_(this) { |
91 LOG(INFO) << "Create " << device_id_ << " (" << this << ")"; | 107 LOG(INFO) << "Create " << device_id_ << " (" << this |
| 108 << "), content type = " << AudioContentTypeToString(content_type_); |
92 DCHECK(delegate_); | 109 DCHECK(delegate_); |
93 DCHECK(mixer_); | 110 DCHECK(mixer_); |
94 weak_this_ = weak_factory_.GetWeakPtr(); | 111 weak_this_ = weak_factory_.GetWeakPtr(); |
95 } | 112 } |
96 | 113 |
97 StreamMixerAlsaInputImpl::~StreamMixerAlsaInputImpl() { | 114 StreamMixerAlsaInputImpl::~StreamMixerAlsaInputImpl() { |
98 LOG(INFO) << "Destroy " << device_id_ << " (" << this << ")"; | 115 LOG(INFO) << "Destroy " << device_id_ << " (" << this << ")"; |
99 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 116 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
100 } | 117 } |
101 | 118 |
102 int StreamMixerAlsaInputImpl::input_samples_per_second() const { | 119 int StreamMixerAlsaInputImpl::input_samples_per_second() const { |
103 return input_samples_per_second_; | 120 return input_samples_per_second_; |
104 } | 121 } |
105 | 122 |
106 bool StreamMixerAlsaInputImpl::primary() const { | 123 bool StreamMixerAlsaInputImpl::primary() const { |
107 return primary_; | 124 return primary_; |
108 } | 125 } |
109 | 126 |
110 std::string StreamMixerAlsaInputImpl::device_id() const { | 127 std::string StreamMixerAlsaInputImpl::device_id() const { |
111 return device_id_; | 128 return device_id_; |
112 } | 129 } |
113 | 130 |
| 131 AudioContentType StreamMixerAlsaInputImpl::content_type() const { |
| 132 return content_type_; |
| 133 } |
| 134 |
114 bool StreamMixerAlsaInputImpl::IsDeleting() const { | 135 bool StreamMixerAlsaInputImpl::IsDeleting() const { |
115 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 136 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
116 return (state_ == kStateFinalFade || state_ == kStateDeleted); | 137 return (state_ == kStateFinalFade || state_ == kStateDeleted); |
117 } | 138 } |
118 | 139 |
119 void StreamMixerAlsaInputImpl::Initialize( | 140 void StreamMixerAlsaInputImpl::Initialize( |
120 const MediaPipelineBackendAlsa::RenderingDelay& mixer_rendering_delay) { | 141 const MediaPipelineBackendAlsa::RenderingDelay& mixer_rendering_delay) { |
121 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 142 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
122 DCHECK(!IsDeleting()); | 143 DCHECK(!IsDeleting()); |
123 if (mixer_->output_samples_per_second() != input_samples_per_second_) { | 144 if (mixer_->output_samples_per_second() != input_samples_per_second_) { |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 void StreamMixerAlsaInputImpl::OnSkipped() { | 279 void StreamMixerAlsaInputImpl::OnSkipped() { |
259 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 280 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
260 if (!is_underflowing_) { | 281 if (!is_underflowing_) { |
261 LOG(WARNING) << "Underflow for " << this; | 282 LOG(WARNING) << "Underflow for " << this; |
262 is_underflowing_ = true; | 283 is_underflowing_ = true; |
263 } | 284 } |
264 if (state_ == kStateNormalPlayback) { | 285 if (state_ == kStateNormalPlayback) { |
265 // Fade in once this input starts providing data again. | 286 // Fade in once this input starts providing data again. |
266 fade_frames_remaining_ = NormalFadeFrames(); | 287 fade_frames_remaining_ = NormalFadeFrames(); |
267 } | 288 } |
| 289 slew_volume_.Interrupted(); |
268 } | 290 } |
269 | 291 |
270 void StreamMixerAlsaInputImpl::AfterWriteFrames( | 292 void StreamMixerAlsaInputImpl::AfterWriteFrames( |
271 const MediaPipelineBackendAlsa::RenderingDelay& mixer_rendering_delay) { | 293 const MediaPipelineBackendAlsa::RenderingDelay& mixer_rendering_delay) { |
272 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 294 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
273 double resampler_queued_frames = | 295 double resampler_queued_frames = |
274 (resampler_ ? resampler_->BufferedFrames() : 0); | 296 (resampler_ ? resampler_->BufferedFrames() : 0); |
275 | 297 |
276 bool queued_more_data = false; | 298 bool queued_more_data = false; |
277 MediaPipelineBackendAlsa::RenderingDelay total_delay; | 299 MediaPipelineBackendAlsa::RenderingDelay total_delay; |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
521 | 543 |
522 if (state_ == kStateFadingOut) { | 544 if (state_ == kStateFadingOut) { |
523 // Tell the mixer that some more data might be available (since when fading | 545 // Tell the mixer that some more data might be available (since when fading |
524 // out, we can drain the queue completely). | 546 // out, we can drain the queue completely). |
525 mixer_->OnFramesQueued(); | 547 mixer_->OnFramesQueued(); |
526 } | 548 } |
527 } | 549 } |
528 | 550 |
529 void StreamMixerAlsaInputImpl::SetVolumeMultiplier(float multiplier) { | 551 void StreamMixerAlsaInputImpl::SetVolumeMultiplier(float multiplier) { |
530 RUN_ON_MIXER_THREAD(SetVolumeMultiplier, multiplier); | 552 RUN_ON_MIXER_THREAD(SetVolumeMultiplier, multiplier); |
531 LOG(INFO) << device_id_ << "(" << this << "): stream volume = " << multiplier; | |
532 DCHECK(!IsDeleting()); | 553 DCHECK(!IsDeleting()); |
533 if (multiplier > 1.0f) | 554 stream_volume_multiplier_ = std::max(0.0f, std::min(multiplier, 1.0f)); |
534 multiplier = 1.0f; | 555 float effective_volume = stream_volume_multiplier_ * type_volume_multiplier_ * |
535 if (multiplier < 0.0f) | 556 mute_volume_multiplier_; |
536 multiplier = 0.0f; | 557 LOG(INFO) << device_id_ << "(" << this |
537 slew_volume_.SetVolume(multiplier); | 558 << "): stream volume = " << stream_volume_multiplier_ |
| 559 << ", effective multiplier = " << effective_volume; |
| 560 slew_volume_.SetVolume(effective_volume); |
| 561 } |
| 562 |
| 563 void StreamMixerAlsaInputImpl::SetContentTypeVolume(float volume) { |
| 564 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
| 565 type_volume_multiplier_ = std::max(0.0f, std::min(volume, 1.0f)); |
| 566 float effective_volume = stream_volume_multiplier_ * type_volume_multiplier_ * |
| 567 mute_volume_multiplier_; |
| 568 LOG(INFO) << device_id_ << "(" << this |
| 569 << "): type volume = " << type_volume_multiplier_ |
| 570 << ", effective multiplier = " << effective_volume; |
| 571 slew_volume_.SetVolume(effective_volume); |
| 572 } |
| 573 |
| 574 void StreamMixerAlsaInputImpl::SetMuted(bool muted) { |
| 575 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
| 576 mute_volume_multiplier_ = muted ? 0.0f : 1.0f; |
| 577 float effective_volume = stream_volume_multiplier_ * type_volume_multiplier_ * |
| 578 mute_volume_multiplier_; |
| 579 LOG(INFO) << device_id_ << "(" << this |
| 580 << "): mute volume = " << mute_volume_multiplier_ |
| 581 << ", effective multiplier = " << effective_volume; |
| 582 slew_volume_.SetVolume(effective_volume); |
538 } | 583 } |
539 | 584 |
540 void StreamMixerAlsaInputImpl::VolumeScaleAccumulate(bool repeat_transition, | 585 void StreamMixerAlsaInputImpl::VolumeScaleAccumulate(bool repeat_transition, |
541 const float* src, | 586 const float* src, |
542 int frames, | 587 int frames, |
543 float* dest) { | 588 float* dest) { |
544 slew_volume_.ProcessFMAC(repeat_transition, src, frames, dest); | 589 slew_volume_.ProcessFMAC(repeat_transition, src, frames, dest); |
545 } | 590 } |
546 | 591 |
547 } // namespace media | 592 } // namespace media |
548 } // namespace chromecast | 593 } // namespace chromecast |
OLD | NEW |