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

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

Issue 2847673002: [Chromecast] Complete PostProcessingPipeline changes (Closed)
Patch Set: Fix deps Created 3 years, 7 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> 10 #include <unordered_set>
11 #include <utility> 11 #include <utility>
12 12
13 #include "base/bind_helpers.h" 13 #include "base/bind_helpers.h"
14 #include "base/command_line.h" 14 #include "base/command_line.h"
15 #include "base/lazy_instance.h" 15 #include "base/lazy_instance.h"
16 #include "base/memory/ptr_util.h" 16 #include "base/memory/ptr_util.h"
17 #include "base/memory/weak_ptr.h" 17 #include "base/memory/weak_ptr.h"
18 #include "base/numerics/saturated_arithmetic.h" 18 #include "base/numerics/saturated_arithmetic.h"
19 #include "base/single_thread_task_runner.h" 19 #include "base/single_thread_task_runner.h"
20 #include "base/threading/platform_thread.h" 20 #include "base/threading/platform_thread.h"
21 #include "base/threading/thread_task_runner_handle.h" 21 #include "base/threading/thread_task_runner_handle.h"
22 #include "base/time/time.h"
22 #include "chromecast/base/chromecast_switches.h" 23 #include "chromecast/base/chromecast_switches.h"
23 #include "chromecast/media/base/audio_device_ids.h" 24 #include "chromecast/media/base/audio_device_ids.h"
24 #include "chromecast/media/cma/backend/alsa/alsa_wrapper.h" 25 #include "chromecast/media/cma/backend/alsa/alsa_wrapper.h"
25 #include "chromecast/media/cma/backend/alsa/filter_group.h" 26 #include "chromecast/media/cma/backend/alsa/filter_group.h"
26 #include "chromecast/media/cma/backend/alsa/post_processing_pipeline_parser.h" 27 #include "chromecast/media/cma/backend/alsa/post_processing_pipeline_parser.h"
27 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h" 28 #include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h"
28 #include "media/audio/audio_device_description.h" 29 #include "media/audio/audio_device_description.h"
29 #include "media/base/audio_bus.h" 30 #include "media/base/audio_bus.h"
30 #include "media/base/media_switches.h" 31 #include "media/base/media_switches.h"
31 32
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 const int kUseDefaultFade = -1; 123 const int kUseDefaultFade = -1;
123 const int kMediaDuckFadeMs = 150; 124 const int kMediaDuckFadeMs = 150;
124 const int kMediaUnduckFadeMs = 700; 125 const int kMediaUnduckFadeMs = 700;
125 126
126 int64_t TimespecToMicroseconds(struct timespec time) { 127 int64_t TimespecToMicroseconds(struct timespec time) {
127 return static_cast<int64_t>(time.tv_sec) * 128 return static_cast<int64_t>(time.tv_sec) *
128 base::Time::kMicrosecondsPerSecond + 129 base::Time::kMicrosecondsPerSecond +
129 time.tv_nsec / 1000; 130 time.tv_nsec / 1000;
130 } 131 }
131 132
132 void VectorAccumulate(const int32_t* source, size_t size, int32_t* dest) { 133 bool IsOutputDeviceId(const std::string& device) {
133 for (size_t i = 0; i < size; ++i) { 134 return device == ::media::AudioDeviceDescription::kDefaultDeviceId ||
134 dest[i] = base::SaturatedAddition(source[i], dest[i]); 135 device == ::media::AudioDeviceDescription::kCommunicationsDeviceId ||
135 } 136 device == kLocalAudioDeviceId || device == kAlarmAudioDeviceId ||
137 device == kTtsAudioDeviceId;
136 } 138 }
137 139
138 class StreamMixerAlsaInstance : public StreamMixerAlsa { 140 class StreamMixerAlsaInstance : public StreamMixerAlsa {
139 public: 141 public:
140 StreamMixerAlsaInstance() {} 142 StreamMixerAlsaInstance() {}
141 ~StreamMixerAlsaInstance() override {} 143 ~StreamMixerAlsaInstance() override {}
142 144
143 private: 145 private:
144 DISALLOW_COPY_AND_ASSIGN(StreamMixerAlsaInstance); 146 DISALLOW_COPY_AND_ASSIGN(StreamMixerAlsaInstance);
145 }; 147 };
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 212
211 fixed_output_samples_per_second_ = fixed_samples_per_second; 213 fixed_output_samples_per_second_ = fixed_samples_per_second;
212 214
213 low_sample_rate_cutoff_ = 215 low_sample_rate_cutoff_ =
214 chromecast::GetSwitchValueBoolean(switches::kAlsaEnableUpsampling, false) 216 chromecast::GetSwitchValueBoolean(switches::kAlsaEnableUpsampling, false)
215 ? kLowSampleRateCutoff 217 ? kLowSampleRateCutoff
216 : 0; 218 : 0;
217 219
218 // Read post-processing configuration file 220 // Read post-processing configuration file
219 PostProcessingPipelineParser pipeline_parser; 221 PostProcessingPipelineParser pipeline_parser;
220 pipeline_parser.Initialize();
221 222
222 // Media filter group: 223 CreatePostProcessors(&pipeline_parser);
223 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
224 std::unordered_set<std::string>(
225 {::media::AudioDeviceDescription::kDefaultDeviceId,
226 kLocalAudioDeviceId, "", kAlarmAudioDeviceId}),
227 AudioContentType::kMedia, kNumOutputChannels,
228 pipeline_parser.GetPipelineByDeviceId(
229 ::media::AudioDeviceDescription::kDefaultDeviceId)));
230
231 // Voice filter group:
232 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
233 std::unordered_set<std::string>(
234 {kTtsAudioDeviceId,
235 ::media::AudioDeviceDescription::kCommunicationsDeviceId}),
236 AudioContentType::kCommunication, kNumOutputChannels,
237 pipeline_parser.GetPipelineByDeviceId(kTtsAudioDeviceId)));
238 224
239 // TODO(bshaya): Add support for final mix AudioPostProcessor. 225 // TODO(bshaya): Add support for final mix AudioPostProcessor.
240 DefineAlsaParameters(); 226 DefineAlsaParameters();
241 } 227 }
242 228
229 void StreamMixerAlsa::CreatePostProcessors(
230 PostProcessingPipelineParser* pipeline_parser) {
231 std::unordered_set<std::string> used_streams;
232 for (auto& stream_pipeline : pipeline_parser->GetStreamPipelines()) {
233 const auto& device_ids = stream_pipeline.stream_types;
234 for (const std::string& stream_type : device_ids) {
235 CHECK(IsOutputDeviceId(stream_type))
236 << stream_type << " is not a stream type. Stream types are listed "
237 << "in chromecast/media/base/audio_device_ids.cc and "
238 << "media/audio/audio_device_description.cc";
239 CHECK(used_streams.insert(stream_type).second)
240 << "Multiple instances of stream type '" << stream_type << "' in "
241 << pipeline_parser->GetFilePath() << ".";
242 }
243 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
244 kNumOutputChannels, *device_ids.begin() /* name */,
245 stream_pipeline.pipeline, device_ids,
246 std::vector<FilterGroup*>() /* mixed_inputs */));
247 if (device_ids.find(::media::AudioDeviceDescription::kDefaultDeviceId) !=
248 device_ids.end()) {
249 default_filter_ = filter_groups_.back().get();
250 }
251 }
252
253 // Always provide a default filter; OEM may only specify mix filter.
254 if (!default_filter_) {
255 std::string kDefaultDeviceId =
256 ::media::AudioDeviceDescription::kDefaultDeviceId;
257 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
258 kNumOutputChannels, kDefaultDeviceId /* name */, nullptr,
259 std::unordered_set<std::string>({kDefaultDeviceId}),
260 std::vector<FilterGroup*>() /* mixed_inputs */));
261 default_filter_ = filter_groups_.back().get();
262 }
263
264 std::vector<FilterGroup*> filter_group_ptrs(filter_groups_.size());
265 std::transform(
266 filter_groups_.begin(), filter_groups_.end(), filter_group_ptrs.begin(),
267 [](const std::unique_ptr<FilterGroup>& group) { return group.get(); });
268
269 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
270 kNumOutputChannels, "mix", pipeline_parser->GetMixPipeline(),
271 std::unordered_set<std::string>() /* device_ids */, filter_group_ptrs));
272 mix_filter_ = filter_groups_.back().get();
273
274 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
275 kNumOutputChannels, "linearize", pipeline_parser->GetLinearizePipeline(),
276 std::unordered_set<std::string>() /* device_ids */,
277 std::vector<FilterGroup*>({mix_filter_})));
278 linearize_filter_ = filter_groups_.back().get();
279 }
280
243 void StreamMixerAlsa::ResetTaskRunnerForTest() { 281 void StreamMixerAlsa::ResetTaskRunnerForTest() {
244 mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get(); 282 mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get();
245 } 283 }
246 284
285 void StreamMixerAlsa::ResetPostProcessorsForTest(
286 const std::string& pipeline_json) {
287 LOG(INFO) << __FUNCTION__ << " disregard previous PostProcessor messages.";
288 filter_groups_.clear();
289 default_filter_ = nullptr;
290 PostProcessingPipelineParser parser(pipeline_json);
291 CreatePostProcessors(&parser);
292 }
293
247 void StreamMixerAlsa::DefineAlsaParameters() { 294 void StreamMixerAlsa::DefineAlsaParameters() {
248 // Get the ALSA output configuration from the command line. 295 // Get the ALSA output configuration from the command line.
249 alsa_buffer_size_ = GetSwitchValueNonNegativeInt( 296 alsa_buffer_size_ = GetSwitchValueNonNegativeInt(
250 switches::kAlsaOutputBufferSize, kDefaultOutputBufferSizeFrames); 297 switches::kAlsaOutputBufferSize, kDefaultOutputBufferSizeFrames);
251 298
252 alsa_period_size_ = GetSwitchValueNonNegativeInt( 299 alsa_period_size_ = GetSwitchValueNonNegativeInt(
253 switches::kAlsaOutputPeriodSize, alsa_buffer_size_ / 16); 300 switches::kAlsaOutputPeriodSize, alsa_buffer_size_ / 16);
254 if (alsa_period_size_ >= alsa_buffer_size_) { 301 if (alsa_period_size_ >= alsa_buffer_size_) {
255 LOG(DFATAL) << "ALSA period size must be smaller than the buffer size"; 302 LOG(DFATAL) << "ALSA period size must be smaller than the buffer size";
256 alsa_period_size_ = alsa_buffer_size_ / 2; 303 alsa_period_size_ = alsa_buffer_size_ / 2;
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
501 } 548 }
502 549
503 // Initialize filters 550 // Initialize filters
504 for (auto&& filter_group : filter_groups_) { 551 for (auto&& filter_group : filter_groups_) {
505 filter_group->Initialize(output_samples_per_second_); 552 filter_group->Initialize(output_samples_per_second_);
506 } 553 }
507 554
508 RETURN_REPORT_ERROR(PcmPrepare, pcm_); 555 RETURN_REPORT_ERROR(PcmPrepare, pcm_);
509 RETURN_REPORT_ERROR(PcmStatusMalloc, &pcm_status_); 556 RETURN_REPORT_ERROR(PcmStatusMalloc, &pcm_status_);
510 557
511 rendering_delay_.timestamp_microseconds = kNoTimestamp; 558 alsa_rendering_delay_.timestamp_microseconds = kNoTimestamp;
512 rendering_delay_.delay_microseconds = 0; 559 alsa_rendering_delay_.delay_microseconds = 0;
513 560
514 state_ = kStateNormalPlayback; 561 state_ = kStateNormalPlayback;
515 } 562 }
516 563
517 void StreamMixerAlsa::Stop() { 564 void StreamMixerAlsa::Stop() {
518 for (auto* observer : loopback_observers_) { 565 for (auto* observer : loopback_observers_) {
519 observer->OnLoopbackInterrupted(); 566 observer->OnLoopbackInterrupted();
520 } 567 }
521 568
522 if (alsa_) { 569 if (alsa_) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 623
577 void StreamMixerAlsa::SetAlsaWrapperForTest( 624 void StreamMixerAlsa::SetAlsaWrapperForTest(
578 std::unique_ptr<AlsaWrapper> alsa_wrapper) { 625 std::unique_ptr<AlsaWrapper> alsa_wrapper) {
579 if (alsa_) { 626 if (alsa_) {
580 Close(); 627 Close();
581 } 628 }
582 629
583 alsa_ = std::move(alsa_wrapper); 630 alsa_ = std::move(alsa_wrapper);
584 } 631 }
585 632
586 void StreamMixerAlsa::DisablePostProcessingForTest() {
587 for (auto& filter : filter_groups_) {
588 filter->DisablePostProcessingForTest();
589 }
590 }
591
592 void StreamMixerAlsa::WriteFramesForTest() { 633 void StreamMixerAlsa::WriteFramesForTest() {
593 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::WriteFramesForTest); 634 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::WriteFramesForTest);
594 WriteFrames(); 635 WriteFrames();
595 } 636 }
596 637
597 void StreamMixerAlsa::ClearInputsForTest() { 638 void StreamMixerAlsa::ClearInputsForTest() {
598 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::ClearInputsForTest); 639 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::ClearInputsForTest);
599 inputs_.clear(); 640 inputs_.clear();
600 } 641 }
601 642
(...skipping 24 matching lines...) Expand all
626 input->SetMuted(volume_info_[type].muted); 667 input->SetMuted(volume_info_[type].muted);
627 668
628 check_close_timer_->Stop(); 669 check_close_timer_->Stop();
629 switch (state_) { 670 switch (state_) {
630 case kStateUninitialized: 671 case kStateUninitialized:
631 requested_output_samples_per_second_ = input->input_samples_per_second(); 672 requested_output_samples_per_second_ = input->input_samples_per_second();
632 Start(); 673 Start();
633 // Fallthrough intended 674 // Fallthrough intended
634 case kStateNormalPlayback: { 675 case kStateNormalPlayback: {
635 bool found_filter_group = false; 676 bool found_filter_group = false;
636 input->Initialize(rendering_delay_); 677 input->Initialize(alsa_rendering_delay_);
637 for (auto&& filter_group : filter_groups_) { 678 for (auto&& filter_group : filter_groups_) {
638 if (filter_group->CanProcessInput(input.get())) { 679 if (filter_group->CanProcessInput(input.get())) {
639 found_filter_group = true; 680 found_filter_group = true;
640 input->set_filter_group(filter_group.get()); 681 input->set_filter_group(filter_group.get());
682 LOG(INFO) << "Added input of type " << input->device_id() << " to "
683 << filter_group->name();
641 break; 684 break;
642 } 685 }
643 } 686 }
644 DCHECK(found_filter_group) << "Could not find a filter group for " 687
645 << input->device_id(); 688 // Fallback to default_filter_ if provided
689 if (!found_filter_group && default_filter_) {
690 found_filter_group = true;
691 input->set_filter_group(default_filter_);
692 LOG(INFO) << "Added input of type " << input->device_id() << " to "
693 << default_filter_->name();
694 }
695
696 CHECK(found_filter_group)
697 << "Could not find a filter group for " << input->device_id() << "\n"
698 << "(consider adding a 'default' processor)";
646 inputs_.push_back(std::move(input)); 699 inputs_.push_back(std::move(input));
647 } break; 700 } break;
648 case kStateError: 701 case kStateError:
649 input->SignalError(StreamMixerAlsaInput::MixerError::kInternalError); 702 input->SignalError(StreamMixerAlsaInput::MixerError::kInternalError);
650 ignored_inputs_.push_back(std::move(input)); 703 ignored_inputs_.push_back(std::move(input));
651 break; 704 break;
652 default: 705 default:
653 NOTREACHED(); 706 NOTREACHED();
654 } 707 }
655 } 708 }
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 } else { 855 } else {
803 input->OnSkipped(); 856 input->OnSkipped();
804 } 857 }
805 } 858 }
806 859
807 if (is_silence) { 860 if (is_silence) {
808 // No inputs have any data to provide. Push silence to prevent underrun. 861 // No inputs have any data to provide. Push silence to prevent underrun.
809 chunk_size = kPreventUnderrunChunkSize; 862 chunk_size = kPreventUnderrunChunkSize;
810 } 863 }
811 864
812 // Mix and filter each group. 865 // Recursively mix and filter each group.
813 std::vector<uint8_t>* interleaved = nullptr; 866 linearize_filter_->MixAndFilter(chunk_size);
814 for (auto&& filter_group : filter_groups_) {
815 if (filter_group->MixAndFilter(chunk_size)) {
816 if (!interleaved) {
817 interleaved = filter_group->GetInterleaved();
818 } else {
819 DCHECK_EQ(4, BytesPerOutputFormatSample());
820 VectorAccumulate(
821 reinterpret_cast<int32_t*>(filter_group->GetInterleaved()->data()),
822 chunk_size * kNumOutputChannels,
823 reinterpret_cast<int32_t*>(interleaved->data()));
824 }
825 }
826 }
827 867
828 if (!interleaved) { 868 WriteMixedPcm(chunk_size);
829 // No group has any data, write empty buffer.
830 filter_groups_[0]->ClearInterleaved(chunk_size);
831 interleaved = filter_groups_[0]->GetInterleaved();
832 }
833
834 WriteMixedPcm(interleaved, chunk_size);
835 return true; 869 return true;
836 } 870 }
837 871
838 size_t StreamMixerAlsa::InterleavedSize(int frames) { 872 size_t StreamMixerAlsa::InterleavedSize(int frames) {
839 return BytesPerOutputFormatSample() * 873 return BytesPerOutputFormatSample() *
840 static_cast<size_t>(frames * kNumOutputChannels); 874 static_cast<size_t>(frames * kNumOutputChannels);
841 } 875 }
842 876
843 ssize_t StreamMixerAlsa::BytesPerOutputFormatSample() { 877 ssize_t StreamMixerAlsa::BytesPerOutputFormatSample() {
844 return alsa_->PcmFormatSize(pcm_format_, 1); 878 return alsa_->PcmFormatSize(pcm_format_, 1);
845 } 879 }
846 880
847 void StreamMixerAlsa::WriteMixedPcm(std::vector<uint8_t>* interleaved, 881 void StreamMixerAlsa::WriteMixedPcm(int frames) {
848 int frames) {
849 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); 882 DCHECK(mixer_task_runner_->BelongsToCurrentThread());
850 CHECK_PCM_INITIALIZED(); 883 CHECK_PCM_INITIALIZED();
851 DCHECK(interleaved); 884
852 DCHECK_GE(interleaved->size(), InterleavedSize(frames)); 885 // Resize interleaved if necessary.
886 size_t interleaved_size = static_cast<size_t>(frames) * kNumOutputChannels *
887 BytesPerOutputFormatSample();
888 if (interleaved_.size() < interleaved_size) {
889 interleaved_.resize(interleaved_size);
890 }
891
892 // Get data for loopback.
893 mix_filter_->data()->ToInterleaved(frames, BytesPerOutputFormatSample(),
894 interleaved_.data());
853 895
854 int64_t expected_playback_time; 896 int64_t expected_playback_time;
855 if (rendering_delay_.timestamp_microseconds == kNoTimestamp) { 897 if (alsa_rendering_delay_.timestamp_microseconds == kNoTimestamp) {
856 expected_playback_time = kNoTimestamp; 898 expected_playback_time = kNoTimestamp;
857 } else { 899 } else {
858 expected_playback_time = rendering_delay_.timestamp_microseconds + 900 expected_playback_time = alsa_rendering_delay_.timestamp_microseconds +
859 rendering_delay_.delay_microseconds; 901 alsa_rendering_delay_.delay_microseconds +
902 linearize_filter_->GetRenderingDelayMicroseconds();
860 } 903 }
861 904
862 for (CastMediaShlib::LoopbackAudioObserver* observer : loopback_observers_) { 905 for (CastMediaShlib::LoopbackAudioObserver* observer : loopback_observers_) {
863 observer->OnLoopbackAudio(expected_playback_time, kSampleFormatS32, 906 observer->OnLoopbackAudio(expected_playback_time, kSampleFormatS32,
864 output_samples_per_second_, kNumOutputChannels, 907 output_samples_per_second_, kNumOutputChannels,
865 interleaved->data(), InterleavedSize(frames)); 908 interleaved_.data(), InterleavedSize(frames));
866 } 909 }
867 910
911 // Get data for playout.
912 linearize_filter_->data()->ToInterleaved(frames, BytesPerOutputFormatSample(),
913 interleaved_.data());
914
868 // If the PCM has been drained it will be in SND_PCM_STATE_SETUP and need 915 // If the PCM has been drained it will be in SND_PCM_STATE_SETUP and need
869 // to be prepared in order for playback to work. 916 // to be prepared in order for playback to work.
870 if (alsa_->PcmState(pcm_) == SND_PCM_STATE_SETUP) { 917 if (alsa_->PcmState(pcm_) == SND_PCM_STATE_SETUP) {
871 RETURN_REPORT_ERROR(PcmPrepare, pcm_); 918 RETURN_REPORT_ERROR(PcmPrepare, pcm_);
872 } 919 }
873 920
874 int frames_left = frames; 921 int frames_left = frames;
875 uint8_t* data = interleaved->data(); 922 uint8_t* data = interleaved_.data();
876 while (frames_left) { 923 while (frames_left) {
877 int frames_or_error; 924 int frames_or_error;
878 while ((frames_or_error = alsa_->PcmWritei(pcm_, data, frames_left)) < 0) { 925 while ((frames_or_error = alsa_->PcmWritei(pcm_, data, frames_left)) < 0) {
879 for (auto* observer : loopback_observers_) { 926 for (auto* observer : loopback_observers_) {
880 observer->OnLoopbackInterrupted(); 927 observer->OnLoopbackInterrupted();
881 } 928 }
882 RETURN_REPORT_ERROR(PcmRecover, pcm_, frames_or_error, 929 RETURN_REPORT_ERROR(PcmRecover, pcm_, frames_or_error,
883 kPcmRecoverIsSilent); 930 kPcmRecoverIsSilent);
884 } 931 }
885 frames_left -= frames_or_error; 932 frames_left -= frames_or_error;
886 DCHECK_GE(frames_left, 0); 933 DCHECK_GE(frames_left, 0);
887 data += frames_or_error * kNumOutputChannels * BytesPerOutputFormatSample(); 934 data += frames_or_error * kNumOutputChannels * BytesPerOutputFormatSample();
888 } 935 }
889 UpdateRenderingDelay(frames); 936 UpdateRenderingDelay(frames);
890 for (auto&& input : inputs_) 937 MediaPipelineBackendAlsa::RenderingDelay common_rendering_delay =
891 input->AfterWriteFrames(rendering_delay_); 938 alsa_rendering_delay_;
939 common_rendering_delay.delay_microseconds +=
940 linearize_filter_->GetRenderingDelayMicroseconds() +
941 mix_filter_->GetRenderingDelayMicroseconds();
942 for (auto&& input : inputs_) {
943 MediaPipelineBackendAlsa::RenderingDelay stream_rendering_delay =
944 common_rendering_delay;
945 stream_rendering_delay.delay_microseconds +=
946 input->filter_group()->GetRenderingDelayMicroseconds();
947 input->AfterWriteFrames(stream_rendering_delay);
948 }
892 } 949 }
893 950
894 void StreamMixerAlsa::UpdateRenderingDelay(int newly_pushed_frames) { 951 void StreamMixerAlsa::UpdateRenderingDelay(int newly_pushed_frames) {
895 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); 952 DCHECK(mixer_task_runner_->BelongsToCurrentThread());
896 CHECK_PCM_INITIALIZED(); 953 CHECK_PCM_INITIALIZED();
897 954
898 // TODO(bshaya): Add rendering delay from post-processors. 955 // TODO(bshaya): Add rendering delay from post-processors.
899 if (alsa_->PcmStatus(pcm_, pcm_status_) != 0 || 956 if (alsa_->PcmStatus(pcm_, pcm_status_) != 0 ||
900 alsa_->PcmStatusGetState(pcm_status_) != SND_PCM_STATE_RUNNING) { 957 alsa_->PcmStatusGetState(pcm_status_) != SND_PCM_STATE_RUNNING) {
901 rendering_delay_.timestamp_microseconds = kNoTimestamp; 958 alsa_rendering_delay_.timestamp_microseconds = kNoTimestamp;
902 rendering_delay_.delay_microseconds = 0; 959 alsa_rendering_delay_.delay_microseconds = 0;
903 return; 960 return;
904 } 961 }
905 962
906 snd_htimestamp_t status_timestamp = {}; 963 snd_htimestamp_t status_timestamp = {};
907 alsa_->PcmStatusGetHtstamp(pcm_status_, &status_timestamp); 964 alsa_->PcmStatusGetHtstamp(pcm_status_, &status_timestamp);
908 rendering_delay_.timestamp_microseconds = 965 alsa_rendering_delay_.timestamp_microseconds =
909 TimespecToMicroseconds(status_timestamp); 966 TimespecToMicroseconds(status_timestamp);
910 snd_pcm_sframes_t delay_frames = alsa_->PcmStatusGetDelay(pcm_status_); 967 snd_pcm_sframes_t delay_frames = alsa_->PcmStatusGetDelay(pcm_status_);
911 rendering_delay_.delay_microseconds = static_cast<int64_t>(delay_frames) * 968 alsa_rendering_delay_.delay_microseconds =
912 base::Time::kMicrosecondsPerSecond / 969 static_cast<int64_t>(delay_frames) * base::Time::kMicrosecondsPerSecond /
913 output_samples_per_second_; 970 output_samples_per_second_;
914 } 971 }
915 972
916 void StreamMixerAlsa::AddLoopbackAudioObserver( 973 void StreamMixerAlsa::AddLoopbackAudioObserver(
917 CastMediaShlib::LoopbackAudioObserver* observer) { 974 CastMediaShlib::LoopbackAudioObserver* observer) {
918 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::AddLoopbackAudioObserver, observer); 975 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::AddLoopbackAudioObserver, observer);
919 DCHECK(observer); 976 DCHECK(observer);
920 DCHECK(std::find(loopback_observers_.begin(), loopback_observers_.end(), 977 DCHECK(std::find(loopback_observers_.begin(), loopback_observers_.end(),
921 observer) == loopback_observers_.end()); 978 observer) == loopback_observers_.end());
922 loopback_observers_.push_back(observer); 979 loopback_observers_.push_back(observer);
923 } 980 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
976 for (auto&& input : inputs_) { 1033 for (auto&& input : inputs_) {
977 // Volume limits don't apply to effects streams. 1034 // Volume limits don't apply to effects streams.
978 if (input->primary() && input->content_type() == type) { 1035 if (input->primary() && input->content_type() == type) {
979 input->SetContentTypeVolume(effective_volume, fade_ms); 1036 input->SetContentTypeVolume(effective_volume, fade_ms);
980 } 1037 }
981 } 1038 }
982 } 1039 }
983 1040
984 } // namespace media 1041 } // namespace media
985 } // namespace chromecast 1042 } // 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_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698