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

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

Issue 2722673004: Revert of [Chromecast] Process streams with different post-processing. (Closed)
Patch Set: Created 3 years, 9 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
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.h" 5 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 #include <limits> 9 #include <limits>
10 #include <unordered_set>
11 #include <utility> 10 #include <utility>
12 11
13 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
14 #include "base/command_line.h" 13 #include "base/command_line.h"
15 #include "base/lazy_instance.h" 14 #include "base/lazy_instance.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/memory/weak_ptr.h" 15 #include "base/memory/weak_ptr.h"
18 #include "base/numerics/saturated_arithmetic.h"
19 #include "base/single_thread_task_runner.h" 16 #include "base/single_thread_task_runner.h"
20 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
21 #include "base/threading/platform_thread.h" 18 #include "base/threading/platform_thread.h"
22 #include "base/threading/thread_task_runner_handle.h" 19 #include "base/threading/thread_task_runner_handle.h"
23 #include "chromecast/base/chromecast_switches.h" 20 #include "chromecast/base/chromecast_switches.h"
24 #include "chromecast/media/base/audio_device_ids.h"
25 #include "chromecast/media/cma/backend/alsa/alsa_wrapper.h" 21 #include "chromecast/media/cma/backend/alsa/alsa_wrapper.h"
26 #include "chromecast/media/cma/backend/alsa/audio_filter_factory.h" 22 #include "chromecast/media/cma/backend/alsa/audio_filter_factory.h"
27 #include "chromecast/media/cma/backend/alsa/filter_group.h"
28 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h" 23 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h"
29 #include "media/audio/audio_device_description.h"
30 #include "media/base/audio_bus.h" 24 #include "media/base/audio_bus.h"
31 #include "media/base/media_switches.h" 25 #include "media/base/media_switches.h"
32 26
33 #define RETURN_REPORT_ERROR(snd_func, ...) \ 27 #define RETURN_REPORT_ERROR(snd_func, ...) \
34 do { \ 28 do { \
35 int err = alsa_->snd_func(__VA_ARGS__); \ 29 int err = alsa_->snd_func(__VA_ARGS__); \
36 if (err < 0) { \ 30 if (err < 0) { \
37 LOG(ERROR) << #snd_func " error: " << alsa_->StrError(err); \ 31 LOG(ERROR) << #snd_func " error: " << alsa_->StrError(err); \
38 SignalError(); \ 32 SignalError(); \
39 return; \ 33 return; \
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 // direction they adjusted the requested parameter in, but since we read the 105 // direction they adjusted the requested parameter in, but since we read the
112 // output param and then log the information, this module doesn't need to get 106 // output param and then log the information, this module doesn't need to get
113 // the direction explicitly. 107 // the direction explicitly.
114 static int* kAlsaDirDontCare = nullptr; 108 static int* kAlsaDirDontCare = nullptr;
115 109
116 // These sample formats will be tried in order. 32 bit samples is ideal, but 110 // These sample formats will be tried in order. 32 bit samples is ideal, but
117 // some devices do not support 32 bit samples. 111 // some devices do not support 32 bit samples.
118 const snd_pcm_format_t kPreferredSampleFormats[] = {SND_PCM_FORMAT_S32, 112 const snd_pcm_format_t kPreferredSampleFormats[] = {SND_PCM_FORMAT_S32,
119 SND_PCM_FORMAT_S16}; 113 SND_PCM_FORMAT_S16};
120 114
115 // How many seconds of silence should be passed to the filters to flush them.
116 const float kSilenceSecondsToFilter = 1.0f;
117
121 const int64_t kNoTimestamp = std::numeric_limits<int64_t>::min(); 118 const int64_t kNoTimestamp = std::numeric_limits<int64_t>::min();
122 119
123 int64_t TimespecToMicroseconds(struct timespec time) { 120 int64_t TimespecToMicroseconds(struct timespec time) {
124 return static_cast<int64_t>(time.tv_sec) * 121 return static_cast<int64_t>(time.tv_sec) *
125 base::Time::kMicrosecondsPerSecond + 122 base::Time::kMicrosecondsPerSecond +
126 time.tv_nsec / 1000; 123 time.tv_nsec / 1000;
127 } 124 }
128 125
129 bool GetSwitchValueAsInt(const std::string& switch_name, 126 bool GetSwitchValueAsInt(const std::string& switch_name,
130 int default_value, 127 int default_value,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 } 160 }
164 161
165 if (*value < 0) { 162 if (*value < 0) {
166 LOG(DFATAL) << "--" << switch_name << " must have a non-negative value"; 163 LOG(DFATAL) << "--" << switch_name << " must have a non-negative value";
167 *value = default_value; 164 *value = default_value;
168 return false; 165 return false;
169 } 166 }
170 return true; 167 return true;
171 } 168 }
172 169
173 void VectorAccumulate(const int32_t* source, size_t size, int32_t* dest) {
174 for (size_t i = 0; i < size; ++i) {
175 dest[i] = base::SaturatedAddition(source[i], dest[i]);
176 }
177 }
178
179 class StreamMixerAlsaInstance : public StreamMixerAlsa { 170 class StreamMixerAlsaInstance : public StreamMixerAlsa {
180 public: 171 public:
181 StreamMixerAlsaInstance() {} 172 StreamMixerAlsaInstance() {}
182 ~StreamMixerAlsaInstance() override {} 173 ~StreamMixerAlsaInstance() override {}
183 174
184 private: 175 private:
185 DISALLOW_COPY_AND_ASSIGN(StreamMixerAlsaInstance); 176 DISALLOW_COPY_AND_ASSIGN(StreamMixerAlsaInstance);
186 }; 177 };
187 178
188 base::LazyInstance<StreamMixerAlsaInstance> g_mixer_instance = 179 base::LazyInstance<StreamMixerAlsaInstance> g_mixer_instance =
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 LOG(INFO) << "Setting fixed sample rate to " << fixed_samples_per_second; 238 LOG(INFO) << "Setting fixed sample rate to " << fixed_samples_per_second;
248 } 239 }
249 240
250 fixed_output_samples_per_second_ = fixed_samples_per_second; 241 fixed_output_samples_per_second_ = fixed_samples_per_second;
251 242
252 low_sample_rate_cutoff_ = 243 low_sample_rate_cutoff_ =
253 chromecast::GetSwitchValueBoolean(switches::kAlsaEnableUpsampling, false) 244 chromecast::GetSwitchValueBoolean(switches::kAlsaEnableUpsampling, false)
254 ? kLowSampleRateCutoff 245 ? kLowSampleRateCutoff
255 : 0; 246 : 0;
256 247
257 // Create filter groups. 248 // Create filters
258 // TODO(bshaya): Switch to filter groups based on AudioContentType 249 pre_loopback_filter_ = AudioFilterFactory::MakeAudioFilter(
259 filter_groups_.push_back(base::MakeUnique<FilterGroup>( 250 AudioFilterFactory::PRE_LOOPBACK_FILTER);
260 std::unordered_set<std::string>( 251 post_loopback_filter_ = AudioFilterFactory::MakeAudioFilter(
261 {::media::AudioDeviceDescription::kCommunicationsDeviceId}), 252 AudioFilterFactory::POST_LOOPBACK_FILTER);
262 AudioFilterFactory::COMMUNICATION_AUDIO_FILTER));
263 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
264 std::unordered_set<std::string>({kAlarmAudioDeviceId}),
265 AudioFilterFactory::ALARM_AUDIO_FILTER));
266 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
267 std::unordered_set<std::string>({kTtsAudioDeviceId}),
268 AudioFilterFactory::TTS_AUDIO_FILTER));
269 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
270 std::unordered_set<std::string>(
271 {::media::AudioDeviceDescription::kDefaultDeviceId,
272 kEarconAudioDeviceId}),
273 AudioFilterFactory::MEDIA_AUDIO_FILTER));
274 253
275 DefineAlsaParameters(); 254 DefineAlsaParameters();
276 } 255 }
277 256
278 void StreamMixerAlsa::ResetTaskRunnerForTest() { 257 void StreamMixerAlsa::ResetTaskRunnerForTest() {
279 mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get(); 258 mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get();
280 } 259 }
281 260
282 void StreamMixerAlsa::DefineAlsaParameters() { 261 void StreamMixerAlsa::DefineAlsaParameters() {
283 // Get the ALSA output configuration from the command line. 262 // Get the ALSA output configuration from the command line.
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after
543 int err = SetAlsaPlaybackParams(); 522 int err = SetAlsaPlaybackParams();
544 if (err < 0) { 523 if (err < 0) {
545 LOG(ERROR) << "Error setting ALSA playback parameters: " 524 LOG(ERROR) << "Error setting ALSA playback parameters: "
546 << alsa_->StrError(err); 525 << alsa_->StrError(err);
547 SignalError(); 526 SignalError();
548 return; 527 return;
549 } 528 }
550 } 529 }
551 530
552 // Initialize filters 531 // Initialize filters
553 for (auto&& filter_group : filter_groups_) { 532 if (pre_loopback_filter_) {
554 filter_group->Initialize(output_samples_per_second_, 533 pre_loopback_filter_->SetSampleRateAndFormat(
555 ::media::SampleFormat::kSampleFormatS32); 534 output_samples_per_second_, ::media::SampleFormat::kSampleFormatS32);
535 }
536
537 if (post_loopback_filter_) {
538 post_loopback_filter_->SetSampleRateAndFormat(
539 output_samples_per_second_, ::media::SampleFormat::kSampleFormatS32);
556 } 540 }
557 541
558 RETURN_REPORT_ERROR(PcmPrepare, pcm_); 542 RETURN_REPORT_ERROR(PcmPrepare, pcm_);
559 RETURN_REPORT_ERROR(PcmStatusMalloc, &pcm_status_); 543 RETURN_REPORT_ERROR(PcmStatusMalloc, &pcm_status_);
560 544
561 rendering_delay_.timestamp_microseconds = kNoTimestamp; 545 rendering_delay_.timestamp_microseconds = kNoTimestamp;
562 rendering_delay_.delay_microseconds = 0; 546 rendering_delay_.delay_microseconds = 0;
563 547
564 state_ = kStateNormalPlayback; 548 state_ = kStateNormalPlayback;
565 } 549 }
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 } 628 }
645 629
646 void StreamMixerAlsa::AddInput(std::unique_ptr<InputQueue> input) { 630 void StreamMixerAlsa::AddInput(std::unique_ptr<InputQueue> input) {
647 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::AddInput, 631 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::AddInput,
648 base::Passed(std::move(input))); 632 base::Passed(std::move(input)));
649 if (!alsa_) { 633 if (!alsa_) {
650 alsa_.reset(new AlsaWrapper()); 634 alsa_.reset(new AlsaWrapper());
651 } 635 }
652 636
653 DCHECK(input); 637 DCHECK(input);
654
655 // If the new input is a primary one, we may need to change the output 638 // If the new input is a primary one, we may need to change the output
656 // sample rate to match its input sample rate. 639 // sample rate to match its input sample rate.
657 // We only change the output rate if it is not set to a fixed value. 640 // We only change the output rate if it is not set to a fixed value.
658 if (input->primary() && 641 if (input->primary() &&
659 fixed_output_samples_per_second_ == kInvalidSampleRate) { 642 fixed_output_samples_per_second_ == kInvalidSampleRate) {
660 CheckChangeOutputRate(input->input_samples_per_second()); 643 CheckChangeOutputRate(input->input_samples_per_second());
661 } 644 }
662 645
663 check_close_timer_->Stop(); 646 check_close_timer_->Stop();
664 switch (state_) { 647 if (state_ == kStateUninitialized) {
665 case kStateUninitialized: 648 requested_output_samples_per_second_ = input->input_samples_per_second();
666 requested_output_samples_per_second_ = input->input_samples_per_second(); 649 Start();
667 Start(); 650 input->Initialize(rendering_delay_);
668 // Fallthrough intended 651 inputs_.push_back(std::move(input));
669 case kStateNormalPlayback: { 652 } else if (state_ == kStateNormalPlayback) {
670 bool found_filter_group = false; 653 input->Initialize(rendering_delay_);
671 input->Initialize(rendering_delay_); 654 inputs_.push_back(std::move(input));
672 for (auto&& filter_group : filter_groups_) { 655 } else {
673 if (filter_group->CanProcessInput(input.get())) { 656 input->SignalError(StreamMixerAlsaInput::MixerError::kInternalError);
674 found_filter_group = true; 657 ignored_inputs_.push_back(std::move(input));
675 input->set_filter_group(filter_group.get());
676 break;
677 }
678 }
679 DCHECK(found_filter_group) << "Could not find a filter group for "
680 << input->device_id();
681 inputs_.push_back(std::move(input));
682 } break;
683 case kStateError:
684 input->SignalError(StreamMixerAlsaInput::MixerError::kInternalError);
685 ignored_inputs_.push_back(std::move(input));
686 break;
687 default:
688 NOTREACHED();
689 } 658 }
690 } 659 }
691 660
692 void StreamMixerAlsa::CheckChangeOutputRate(int input_samples_per_second) { 661 void StreamMixerAlsa::CheckChangeOutputRate(int input_samples_per_second) {
693 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); 662 DCHECK(mixer_task_runner_->BelongsToCurrentThread());
694 if (!pcm_ || 663 if (!pcm_ ||
695 input_samples_per_second == requested_output_samples_per_second_ || 664 input_samples_per_second == requested_output_samples_per_second_ ||
696 input_samples_per_second == output_samples_per_second_ || 665 input_samples_per_second == output_samples_per_second_ ||
697 input_samples_per_second < static_cast<int>(low_sample_rate_cutoff_)) { 666 input_samples_per_second < static_cast<int>(low_sample_rate_cutoff_)) {
698 return; 667 return;
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
786 retry_write_frames_timer_->Stop(); 755 retry_write_frames_timer_->Stop();
787 if (TryWriteFrames()) { 756 if (TryWriteFrames()) {
788 retry_write_frames_timer_->Start( 757 retry_write_frames_timer_->Start(
789 FROM_HERE, base::TimeDelta(), 758 FROM_HERE, base::TimeDelta(),
790 base::Bind(&StreamMixerAlsa::WriteFrames, base::Unretained(this))); 759 base::Bind(&StreamMixerAlsa::WriteFrames, base::Unretained(this)));
791 } 760 }
792 } 761 }
793 762
794 bool StreamMixerAlsa::TryWriteFrames() { 763 bool StreamMixerAlsa::TryWriteFrames() {
795 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); 764 DCHECK(mixer_task_runner_->BelongsToCurrentThread());
796 DCHECK_GE(filter_groups_.size(), 1u);
797
798 if (state_ != kStateNormalPlayback) { 765 if (state_ != kStateNormalPlayback) {
799 return false; 766 return false;
800 } 767 }
801 768
802 const int min_frames_in_buffer = 769 const int min_frames_in_buffer =
803 output_samples_per_second_ * kMinBufferedDataMs / 1000; 770 output_samples_per_second_ * kMinBufferedDataMs / 1000;
804 int chunk_size = output_samples_per_second_ * kMaxWriteSizeMs / 1000; 771 int chunk_size = output_samples_per_second_ * kMaxWriteSizeMs / 1000;
805 bool is_silence = true; 772 std::vector<InputQueue*> active_inputs;
806 for (auto&& filter_group : filter_groups_) {
807 filter_group->ClearActiveInputs();
808 }
809 for (auto&& input : inputs_) { 773 for (auto&& input : inputs_) {
810 int read_size = input->MaxReadSize(); 774 int read_size = input->MaxReadSize();
811 if (read_size > 0) { 775 if (read_size > 0) {
812 DCHECK(input->filter_group()); 776 active_inputs.push_back(input.get());
813 input->filter_group()->AddActiveInput(input.get());
814 chunk_size = std::min(chunk_size, read_size); 777 chunk_size = std::min(chunk_size, read_size);
815 is_silence = false;
816 } else if (input->primary()) { 778 } else if (input->primary()) {
817 if (alsa_->PcmStatus(pcm_, pcm_status_) != 0) { 779 if (alsa_->PcmStatus(pcm_, pcm_status_) != 0) {
818 LOG(ERROR) << "Failed to get status"; 780 LOG(ERROR) << "Failed to get status";
819 return false; 781 return false;
820 } 782 }
821 783
822 int frames_in_buffer = 784 int frames_in_buffer =
823 alsa_buffer_size_ - alsa_->PcmStatusGetAvail(pcm_status_); 785 alsa_buffer_size_ - alsa_->PcmStatusGetAvail(pcm_status_);
824 if (alsa_->PcmStatusGetState(pcm_status_) == SND_PCM_STATE_XRUN || 786 if (alsa_->PcmStatusGetState(pcm_status_) == SND_PCM_STATE_XRUN ||
825 frames_in_buffer < min_frames_in_buffer) { 787 frames_in_buffer < min_frames_in_buffer) {
826 // If there has been (or soon will be) an underrun, continue without the 788 // If there has been (or soon will be) an underrun, continue without the
827 // empty primary input stream. 789 // empty primary input stream.
828 input->OnSkipped(); 790 input->OnSkipped();
829 continue; 791 continue;
830 } 792 }
831 793
832 // A primary input cannot provide any data, so wait until later. 794 // A primary input cannot provide any data, so wait until later.
833 retry_write_frames_timer_->Start( 795 retry_write_frames_timer_->Start(
834 FROM_HERE, base::TimeDelta::FromMilliseconds(kMinBufferedDataMs / 2), 796 FROM_HERE, base::TimeDelta::FromMilliseconds(kMinBufferedDataMs / 2),
835 base::Bind(&StreamMixerAlsa::WriteFrames, base::Unretained(this))); 797 base::Bind(&StreamMixerAlsa::WriteFrames, base::Unretained(this)));
836 return false; 798 return false;
837 } else { 799 } else {
838 input->OnSkipped(); 800 input->OnSkipped();
839 } 801 }
840 } 802 }
841 803
842 if (is_silence) { 804 if (active_inputs.empty()) {
843 // No inputs have any data to provide. Push silence to prevent underrun. 805 // No inputs have any data to provide. Fill with silence to avoid underrun.
844 chunk_size = kPreventUnderrunChunkSize; 806 chunk_size = kPreventUnderrunChunkSize;
807 if (!mixed_ || mixed_->frames() < chunk_size) {
808 mixed_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size);
809 }
810
811 mixed_->Zero();
812 WriteMixedPcm(*mixed_, chunk_size, true /* is_silence */);
813 return true;
845 } 814 }
846 815
847 // Mix and filter each group. 816 // If |mixed_| has not been allocated, or it is too small, allocate a buffer.
848 std::vector<uint8_t>* interleaved = nullptr; 817 if (!mixed_ || mixed_->frames() < chunk_size) {
849 for (auto&& filter_group : filter_groups_) { 818 mixed_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size);
850 if (filter_group->MixAndFilter(chunk_size)) { 819 }
851 if (!interleaved) { 820
852 interleaved = filter_group->GetInterleaved(); 821 // If |temp_| has not been allocated, or is too small, allocate a buffer.
853 } else { 822 if (!temp_ || temp_->frames() < chunk_size) {
854 DCHECK_EQ(4, BytesPerOutputFormatSample()); 823 temp_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size);
855 VectorAccumulate( 824 }
856 reinterpret_cast<int32_t*>(filter_group->GetInterleaved()->data()), 825
857 chunk_size * kNumOutputChannels, 826 mixed_->ZeroFramesPartial(0, chunk_size);
858 reinterpret_cast<int32_t*>(interleaved->data())); 827
859 } 828 // Loop through active inputs, polling them for data, and mixing them.
829 for (InputQueue* input : active_inputs) {
830 input->GetResampledData(temp_.get(), chunk_size);
831 for (int c = 0; c < kNumOutputChannels; ++c) {
832 input->VolumeScaleAccumulate(c, temp_->channel(c), chunk_size,
833 mixed_->channel(c));
860 } 834 }
861 } 835 }
862 836
863 if (!interleaved) { 837 WriteMixedPcm(*mixed_, chunk_size, false /* is_silence */);
864 // No group has any data, write empty buffer.
865 filter_groups_[0]->ClearInterleaved(chunk_size);
866 interleaved = filter_groups_[0]->GetInterleaved();
867 }
868
869 WriteMixedPcm(interleaved, chunk_size);
870 return true; 838 return true;
871 } 839 }
872 840
873 size_t StreamMixerAlsa::InterleavedSize(int frames) {
874 return BytesPerOutputFormatSample() *
875 static_cast<size_t>(frames * kNumOutputChannels);
876 }
877
878 ssize_t StreamMixerAlsa::BytesPerOutputFormatSample() { 841 ssize_t StreamMixerAlsa::BytesPerOutputFormatSample() {
879 return alsa_->PcmFormatSize(pcm_format_, 1); 842 return alsa_->PcmFormatSize(pcm_format_, 1);
880 } 843 }
881 844
882 void StreamMixerAlsa::WriteMixedPcm(std::vector<uint8_t>* interleaved, 845 void StreamMixerAlsa::WriteMixedPcm(const ::media::AudioBus& mixed,
883 int frames) { 846 int frames, bool is_silence) {
884 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); 847 DCHECK(mixer_task_runner_->BelongsToCurrentThread());
885 CHECK_PCM_INITIALIZED(); 848 CHECK_PCM_INITIALIZED();
886 DCHECK(interleaved); 849
887 DCHECK_GE(interleaved->size(), InterleavedSize(frames)); 850 size_t interleaved_size = static_cast<size_t>(frames * kNumOutputChannels) *
851 BytesPerOutputFormatSample();
852 if (interleaved_.size() < interleaved_size) {
853 interleaved_.resize(interleaved_size);
854 }
888 855
889 int64_t expected_playback_time; 856 int64_t expected_playback_time;
890 if (rendering_delay_.timestamp_microseconds == kNoTimestamp) { 857 if (rendering_delay_.timestamp_microseconds == kNoTimestamp) {
891 expected_playback_time = kNoTimestamp; 858 expected_playback_time = kNoTimestamp;
892 } else { 859 } else {
893 expected_playback_time = rendering_delay_.timestamp_microseconds + 860 expected_playback_time = rendering_delay_.timestamp_microseconds +
894 rendering_delay_.delay_microseconds; 861 rendering_delay_.delay_microseconds;
895 } 862 }
896 863
864 mixed.ToInterleaved(frames, BytesPerOutputFormatSample(),
865 interleaved_.data());
866
867 // Ensure that, on onset of silence, at least |kSilenceSecondsToFilter|
868 // second of audio get pushed through the filters to clear any memory.
869 bool filter_frames = true;
870 if (is_silence) {
871 int silence_frames_to_filter =
872 output_samples_per_second_ * kSilenceSecondsToFilter;
873 if (silence_frames_filtered_ < silence_frames_to_filter) {
874 silence_frames_filtered_ += frames;
875 } else {
876 filter_frames = false;
877 }
878 } else {
879 silence_frames_filtered_ = 0;
880 }
881
882 // Filter, send to observers, and post filter
883 if (pre_loopback_filter_ && filter_frames) {
884 pre_loopback_filter_->ProcessInterleaved(interleaved_.data(), frames);
885 }
886
897 for (CastMediaShlib::LoopbackAudioObserver* observer : loopback_observers_) { 887 for (CastMediaShlib::LoopbackAudioObserver* observer : loopback_observers_) {
898 observer->OnLoopbackAudio(expected_playback_time, kSampleFormatS32, 888 observer->OnLoopbackAudio(expected_playback_time, kSampleFormatS32,
899 output_samples_per_second_, kNumOutputChannels, 889 output_samples_per_second_, kNumOutputChannels,
900 interleaved->data(), InterleavedSize(frames)); 890 interleaved_.data(), interleaved_size);
891 }
892
893 if (post_loopback_filter_ && filter_frames) {
894 post_loopback_filter_->ProcessInterleaved(interleaved_.data(), frames);
901 } 895 }
902 896
903 // If the PCM has been drained it will be in SND_PCM_STATE_SETUP and need 897 // If the PCM has been drained it will be in SND_PCM_STATE_SETUP and need
904 // to be prepared in order for playback to work. 898 // to be prepared in order for playback to work.
905 if (alsa_->PcmState(pcm_) == SND_PCM_STATE_SETUP) { 899 if (alsa_->PcmState(pcm_) == SND_PCM_STATE_SETUP) {
906 RETURN_REPORT_ERROR(PcmPrepare, pcm_); 900 RETURN_REPORT_ERROR(PcmPrepare, pcm_);
907 } 901 }
908 902
909 int frames_left = frames; 903 int frames_left = frames;
910 uint8_t* data = interleaved->data(); 904 uint8_t* data = &interleaved_[0];
911 while (frames_left) { 905 while (frames_left) {
912 int frames_or_error; 906 int frames_or_error;
913 while ((frames_or_error = alsa_->PcmWritei(pcm_, data, frames_left)) < 0) { 907 while ((frames_or_error = alsa_->PcmWritei(pcm_, data, frames_left)) < 0) {
914 for (auto* observer : loopback_observers_) { 908 for (auto* observer : loopback_observers_) {
915 observer->OnLoopbackInterrupted(); 909 observer->OnLoopbackInterrupted();
916 } 910 }
917 RETURN_REPORT_ERROR(PcmRecover, pcm_, frames_or_error, 911 RETURN_REPORT_ERROR(PcmRecover, pcm_, frames_or_error,
918 kPcmRecoverIsSilent); 912 kPcmRecoverIsSilent);
919 } 913 }
920 frames_left -= frames_or_error; 914 frames_left -= frames_or_error;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
962 DCHECK(std::find(loopback_observers_.begin(), loopback_observers_.end(), 956 DCHECK(std::find(loopback_observers_.begin(), loopback_observers_.end(),
963 observer) != loopback_observers_.end()); 957 observer) != loopback_observers_.end());
964 loopback_observers_.erase(std::remove(loopback_observers_.begin(), 958 loopback_observers_.erase(std::remove(loopback_observers_.begin(),
965 loopback_observers_.end(), observer), 959 loopback_observers_.end(), observer),
966 loopback_observers_.end()); 960 loopback_observers_.end());
967 observer->OnRemoved(); 961 observer->OnRemoved();
968 } 962 }
969 963
970 } // namespace media 964 } // namespace media
971 } // namespace chromecast 965 } // namespace chromecast
OLDNEW
« no previous file with comments | « chromecast/media/cma/backend/alsa/stream_mixer_alsa.h ('k') | chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698