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

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

Issue 2847673002: [Chromecast] Complete PostProcessingPipeline changes (Closed)
Patch Set: Add more test 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 bool is_test) {
232 std::unordered_set<std::string> used_streams;
233
234 for (auto& stream_pipeline : pipeline_parser->GetStreamPipelines()) {
235 const auto& device_ids = stream_pipeline.stream_types;
236 for (const std::string& stream_type : device_ids) {
237 if (!is_test) {
238 CHECK(IsOutputDeviceId(stream_type))
239 << stream_type << " is not a stream type. Stream types are listed "
240 << "in chromecast/media/base/audio_device_ids.cc and "
241 << "media/audio/audio_device_description.cc";
242 }
243 CHECK(used_streams.insert(stream_type).second)
244 << "Multiple instances of stream type '" << stream_type << "' in "
245 << pipeline_parser->file_path() << ".";
246 }
247 filter_groups_.push_back(
248 base::MakeUnique<FilterGroup>(kNumOutputChannels, *device_ids.begin(),
249 stream_pipeline.pipeline, device_ids));
250 if (device_ids.find(::media::AudioDeviceDescription::kDefaultDeviceId) !=
251 device_ids.end()) {
252 default_filter_ = filter_groups_.back().get();
253 }
254 }
255
256 std::vector<FilterGroup*> filter_group_ptrs(filter_groups_.size());
257 std::transform(
258 filter_groups_.begin(), filter_groups_.end(), filter_group_ptrs.begin(),
259 [](const std::unique_ptr<FilterGroup>& group) { return group.get(); });
260
261 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
262 kNumOutputChannels, "mix", pipeline_parser->GetMixPipeline(),
263 filter_group_ptrs));
264 mix_filter_ = filter_groups_.back().get();
265
266 filter_groups_.push_back(base::MakeUnique<FilterGroup>(
267 kNumOutputChannels, "linearize", pipeline_parser->GetLinearizePipeline(),
268 std::vector<FilterGroup*>({mix_filter_})));
269 linearize_filter_ = filter_groups_.back().get();
270 }
271
243 void StreamMixerAlsa::ResetTaskRunnerForTest() { 272 void StreamMixerAlsa::ResetTaskRunnerForTest() {
244 mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get(); 273 mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get();
245 } 274 }
246 275
276 void StreamMixerAlsa::ResetPostProcessorsForTest(
277 const std::string& pipeline_json) {
278 LOG(INFO) << __FUNCTION__ << " disregard previous PostProcessor messages.";
279 filter_groups_.clear();
280 PostProcessingPipelineParser parser(pipeline_json);
281 CreatePostProcessors(&parser, true /* is_test */);
282 }
283
247 void StreamMixerAlsa::DefineAlsaParameters() { 284 void StreamMixerAlsa::DefineAlsaParameters() {
248 // Get the ALSA output configuration from the command line. 285 // Get the ALSA output configuration from the command line.
249 alsa_buffer_size_ = GetSwitchValueNonNegativeInt( 286 alsa_buffer_size_ = GetSwitchValueNonNegativeInt(
250 switches::kAlsaOutputBufferSize, kDefaultOutputBufferSizeFrames); 287 switches::kAlsaOutputBufferSize, kDefaultOutputBufferSizeFrames);
251 288
252 alsa_period_size_ = GetSwitchValueNonNegativeInt( 289 alsa_period_size_ = GetSwitchValueNonNegativeInt(
253 switches::kAlsaOutputPeriodSize, alsa_buffer_size_ / 16); 290 switches::kAlsaOutputPeriodSize, alsa_buffer_size_ / 16);
254 if (alsa_period_size_ >= alsa_buffer_size_) { 291 if (alsa_period_size_ >= alsa_buffer_size_) {
255 LOG(DFATAL) << "ALSA period size must be smaller than the buffer size"; 292 LOG(DFATAL) << "ALSA period size must be smaller than the buffer size";
256 alsa_period_size_ = alsa_buffer_size_ / 2; 293 alsa_period_size_ = alsa_buffer_size_ / 2;
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
501 } 538 }
502 539
503 // Initialize filters 540 // Initialize filters
504 for (auto&& filter_group : filter_groups_) { 541 for (auto&& filter_group : filter_groups_) {
505 filter_group->Initialize(output_samples_per_second_); 542 filter_group->Initialize(output_samples_per_second_);
506 } 543 }
507 544
508 RETURN_REPORT_ERROR(PcmPrepare, pcm_); 545 RETURN_REPORT_ERROR(PcmPrepare, pcm_);
509 RETURN_REPORT_ERROR(PcmStatusMalloc, &pcm_status_); 546 RETURN_REPORT_ERROR(PcmStatusMalloc, &pcm_status_);
510 547
511 rendering_delay_.timestamp_microseconds = kNoTimestamp; 548 alsa_rendering_delay_.timestamp_microseconds = kNoTimestamp;
512 rendering_delay_.delay_microseconds = 0; 549 alsa_rendering_delay_.delay_microseconds = 0;
513 550
514 state_ = kStateNormalPlayback; 551 state_ = kStateNormalPlayback;
515 } 552 }
516 553
517 void StreamMixerAlsa::Stop() { 554 void StreamMixerAlsa::Stop() {
518 for (auto* observer : loopback_observers_) { 555 for (auto* observer : loopback_observers_) {
519 observer->OnLoopbackInterrupted(); 556 observer->OnLoopbackInterrupted();
520 } 557 }
521 558
522 if (alsa_) { 559 if (alsa_) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 613
577 void StreamMixerAlsa::SetAlsaWrapperForTest( 614 void StreamMixerAlsa::SetAlsaWrapperForTest(
578 std::unique_ptr<AlsaWrapper> alsa_wrapper) { 615 std::unique_ptr<AlsaWrapper> alsa_wrapper) {
579 if (alsa_) { 616 if (alsa_) {
580 Close(); 617 Close();
581 } 618 }
582 619
583 alsa_ = std::move(alsa_wrapper); 620 alsa_ = std::move(alsa_wrapper);
584 } 621 }
585 622
586 void StreamMixerAlsa::DisablePostProcessingForTest() {
587 for (auto& filter : filter_groups_) {
588 filter->DisablePostProcessingForTest();
589 }
590 }
591
592 void StreamMixerAlsa::WriteFramesForTest() { 623 void StreamMixerAlsa::WriteFramesForTest() {
593 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::WriteFramesForTest); 624 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::WriteFramesForTest);
594 WriteFrames(); 625 WriteFrames();
595 } 626 }
596 627
597 void StreamMixerAlsa::ClearInputsForTest() { 628 void StreamMixerAlsa::ClearInputsForTest() {
598 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::ClearInputsForTest); 629 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::ClearInputsForTest);
599 inputs_.clear(); 630 inputs_.clear();
600 } 631 }
601 632
(...skipping 24 matching lines...) Expand all
626 input->SetMuted(volume_info_[type].muted); 657 input->SetMuted(volume_info_[type].muted);
627 658
628 check_close_timer_->Stop(); 659 check_close_timer_->Stop();
629 switch (state_) { 660 switch (state_) {
630 case kStateUninitialized: 661 case kStateUninitialized:
631 requested_output_samples_per_second_ = input->input_samples_per_second(); 662 requested_output_samples_per_second_ = input->input_samples_per_second();
632 Start(); 663 Start();
633 // Fallthrough intended 664 // Fallthrough intended
634 case kStateNormalPlayback: { 665 case kStateNormalPlayback: {
635 bool found_filter_group = false; 666 bool found_filter_group = false;
636 input->Initialize(rendering_delay_); 667 input->Initialize(alsa_rendering_delay_);
637 for (auto&& filter_group : filter_groups_) { 668 for (auto&& filter_group : filter_groups_) {
638 if (filter_group->CanProcessInput(input.get())) { 669 if (filter_group->CanProcessInput(input.get())) {
639 found_filter_group = true; 670 found_filter_group = true;
640 input->set_filter_group(filter_group.get()); 671 input->set_filter_group(filter_group.get());
672 LOG(INFO) << "Added input of type " << input->device_id() << " to "
673 << filter_group->name();
641 break; 674 break;
642 } 675 }
643 } 676 }
644 DCHECK(found_filter_group) << "Could not find a filter group for " 677
645 << input->device_id(); 678 // Fallback to default_filter_ if provided
679 if (!found_filter_group && default_filter_) {
680 found_filter_group = true;
681 input->set_filter_group(default_filter_);
682 LOG(INFO) << "Added input of type " << input->device_id() << " to "
683 << default_filter_->name();
684 }
685
686 CHECK(found_filter_group)
687 << "Could not find a filter group for " << input->device_id() << "\n"
688 << "(consider adding a 'default' processor)";
646 inputs_.push_back(std::move(input)); 689 inputs_.push_back(std::move(input));
647 } break; 690 } break;
648 case kStateError: 691 case kStateError:
649 input->SignalError(StreamMixerAlsaInput::MixerError::kInternalError); 692 input->SignalError(StreamMixerAlsaInput::MixerError::kInternalError);
650 ignored_inputs_.push_back(std::move(input)); 693 ignored_inputs_.push_back(std::move(input));
651 break; 694 break;
652 default: 695 default:
653 NOTREACHED(); 696 NOTREACHED();
654 } 697 }
655 } 698 }
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 } else { 845 } else {
803 input->OnSkipped(); 846 input->OnSkipped();
804 } 847 }
805 } 848 }
806 849
807 if (is_silence) { 850 if (is_silence) {
808 // No inputs have any data to provide. Push silence to prevent underrun. 851 // No inputs have any data to provide. Push silence to prevent underrun.
809 chunk_size = kPreventUnderrunChunkSize; 852 chunk_size = kPreventUnderrunChunkSize;
810 } 853 }
811 854
812 // Mix and filter each group. 855 // Recursively mix and filter each group.
813 std::vector<uint8_t>* interleaved = nullptr; 856 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 857
828 if (!interleaved) { 858 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; 859 return true;
836 } 860 }
837 861
838 size_t StreamMixerAlsa::InterleavedSize(int frames) { 862 size_t StreamMixerAlsa::InterleavedSize(int frames) {
839 return BytesPerOutputFormatSample() * 863 return BytesPerOutputFormatSample() *
840 static_cast<size_t>(frames * kNumOutputChannels); 864 static_cast<size_t>(frames * kNumOutputChannels);
841 } 865 }
842 866
843 ssize_t StreamMixerAlsa::BytesPerOutputFormatSample() { 867 ssize_t StreamMixerAlsa::BytesPerOutputFormatSample() {
844 return alsa_->PcmFormatSize(pcm_format_, 1); 868 return alsa_->PcmFormatSize(pcm_format_, 1);
845 } 869 }
846 870
847 void StreamMixerAlsa::WriteMixedPcm(std::vector<uint8_t>* interleaved, 871 void StreamMixerAlsa::WriteMixedPcm(int frames) {
848 int frames) {
849 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); 872 DCHECK(mixer_task_runner_->BelongsToCurrentThread());
850 CHECK_PCM_INITIALIZED(); 873 CHECK_PCM_INITIALIZED();
851 DCHECK(interleaved); 874
852 DCHECK_GE(interleaved->size(), InterleavedSize(frames)); 875 // Resize interleaved if necessary.
876 size_t interleaved_size = static_cast<size_t>(frames) * kNumOutputChannels *
877 BytesPerOutputFormatSample();
878 if (interleaved_.size() < interleaved_size) {
879 interleaved_.resize(interleaved_size);
880 }
881
882 // Get data for loopback.
883 mix_filter_->data()->ToInterleaved(frames, BytesPerOutputFormatSample(),
884 interleaved_.data());
853 885
854 int64_t expected_playback_time; 886 int64_t expected_playback_time;
855 if (rendering_delay_.timestamp_microseconds == kNoTimestamp) { 887 if (alsa_rendering_delay_.timestamp_microseconds == kNoTimestamp) {
856 expected_playback_time = kNoTimestamp; 888 expected_playback_time = kNoTimestamp;
857 } else { 889 } else {
858 expected_playback_time = rendering_delay_.timestamp_microseconds + 890 expected_playback_time = alsa_rendering_delay_.timestamp_microseconds +
859 rendering_delay_.delay_microseconds; 891 alsa_rendering_delay_.delay_microseconds +
892 linearize_filter_->GetRenderingDelayMicroseconds();
860 } 893 }
861 894
862 for (CastMediaShlib::LoopbackAudioObserver* observer : loopback_observers_) { 895 for (CastMediaShlib::LoopbackAudioObserver* observer : loopback_observers_) {
863 observer->OnLoopbackAudio(expected_playback_time, kSampleFormatS32, 896 observer->OnLoopbackAudio(expected_playback_time, kSampleFormatS32,
864 output_samples_per_second_, kNumOutputChannels, 897 output_samples_per_second_, kNumOutputChannels,
865 interleaved->data(), InterleavedSize(frames)); 898 interleaved_.data(), InterleavedSize(frames));
866 } 899 }
867 900
901 // Get data for playout.
902 linearize_filter_->data()->ToInterleaved(frames, BytesPerOutputFormatSample(),
903 interleaved_.data());
904
868 // If the PCM has been drained it will be in SND_PCM_STATE_SETUP and need 905 // 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. 906 // to be prepared in order for playback to work.
870 if (alsa_->PcmState(pcm_) == SND_PCM_STATE_SETUP) { 907 if (alsa_->PcmState(pcm_) == SND_PCM_STATE_SETUP) {
871 RETURN_REPORT_ERROR(PcmPrepare, pcm_); 908 RETURN_REPORT_ERROR(PcmPrepare, pcm_);
872 } 909 }
873 910
874 int frames_left = frames; 911 int frames_left = frames;
875 uint8_t* data = interleaved->data(); 912 uint8_t* data = interleaved_.data();
876 while (frames_left) { 913 while (frames_left) {
877 int frames_or_error; 914 int frames_or_error;
878 while ((frames_or_error = alsa_->PcmWritei(pcm_, data, frames_left)) < 0) { 915 while ((frames_or_error = alsa_->PcmWritei(pcm_, data, frames_left)) < 0) {
879 for (auto* observer : loopback_observers_) { 916 for (auto* observer : loopback_observers_) {
880 observer->OnLoopbackInterrupted(); 917 observer->OnLoopbackInterrupted();
881 } 918 }
882 RETURN_REPORT_ERROR(PcmRecover, pcm_, frames_or_error, 919 RETURN_REPORT_ERROR(PcmRecover, pcm_, frames_or_error,
883 kPcmRecoverIsSilent); 920 kPcmRecoverIsSilent);
884 } 921 }
885 frames_left -= frames_or_error; 922 frames_left -= frames_or_error;
886 DCHECK_GE(frames_left, 0); 923 DCHECK_GE(frames_left, 0);
887 data += frames_or_error * kNumOutputChannels * BytesPerOutputFormatSample(); 924 data += frames_or_error * kNumOutputChannels * BytesPerOutputFormatSample();
888 } 925 }
889 UpdateRenderingDelay(frames); 926 UpdateRenderingDelay(frames);
890 for (auto&& input : inputs_) 927 MediaPipelineBackendAlsa::RenderingDelay common_rendering_delay =
891 input->AfterWriteFrames(rendering_delay_); 928 alsa_rendering_delay_;
929 common_rendering_delay.delay_microseconds +=
930 linearize_filter_->GetRenderingDelayMicroseconds() +
931 mix_filter_->GetRenderingDelayMicroseconds();
932 for (auto&& input : inputs_) {
933 MediaPipelineBackendAlsa::RenderingDelay stream_rendering_delay =
934 common_rendering_delay;
935 stream_rendering_delay.delay_microseconds +=
936 input->filter_group()->GetRenderingDelayMicroseconds();
937 input->AfterWriteFrames(stream_rendering_delay);
938 }
892 } 939 }
893 940
894 void StreamMixerAlsa::UpdateRenderingDelay(int newly_pushed_frames) { 941 void StreamMixerAlsa::UpdateRenderingDelay(int newly_pushed_frames) {
895 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); 942 DCHECK(mixer_task_runner_->BelongsToCurrentThread());
896 CHECK_PCM_INITIALIZED(); 943 CHECK_PCM_INITIALIZED();
897 944
898 // TODO(bshaya): Add rendering delay from post-processors. 945 // TODO(bshaya): Add rendering delay from post-processors.
899 if (alsa_->PcmStatus(pcm_, pcm_status_) != 0 || 946 if (alsa_->PcmStatus(pcm_, pcm_status_) != 0 ||
900 alsa_->PcmStatusGetState(pcm_status_) != SND_PCM_STATE_RUNNING) { 947 alsa_->PcmStatusGetState(pcm_status_) != SND_PCM_STATE_RUNNING) {
901 rendering_delay_.timestamp_microseconds = kNoTimestamp; 948 alsa_rendering_delay_.timestamp_microseconds = kNoTimestamp;
902 rendering_delay_.delay_microseconds = 0; 949 alsa_rendering_delay_.delay_microseconds = 0;
903 return; 950 return;
904 } 951 }
905 952
906 snd_htimestamp_t status_timestamp = {}; 953 snd_htimestamp_t status_timestamp = {};
907 alsa_->PcmStatusGetHtstamp(pcm_status_, &status_timestamp); 954 alsa_->PcmStatusGetHtstamp(pcm_status_, &status_timestamp);
908 rendering_delay_.timestamp_microseconds = 955 alsa_rendering_delay_.timestamp_microseconds =
909 TimespecToMicroseconds(status_timestamp); 956 TimespecToMicroseconds(status_timestamp);
910 snd_pcm_sframes_t delay_frames = alsa_->PcmStatusGetDelay(pcm_status_); 957 snd_pcm_sframes_t delay_frames = alsa_->PcmStatusGetDelay(pcm_status_);
911 rendering_delay_.delay_microseconds = static_cast<int64_t>(delay_frames) * 958 alsa_rendering_delay_.delay_microseconds =
912 base::Time::kMicrosecondsPerSecond / 959 static_cast<int64_t>(delay_frames) * base::Time::kMicrosecondsPerSecond /
913 output_samples_per_second_; 960 output_samples_per_second_;
914 } 961 }
915 962
916 void StreamMixerAlsa::AddLoopbackAudioObserver( 963 void StreamMixerAlsa::AddLoopbackAudioObserver(
917 CastMediaShlib::LoopbackAudioObserver* observer) { 964 CastMediaShlib::LoopbackAudioObserver* observer) {
918 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::AddLoopbackAudioObserver, observer); 965 RUN_ON_MIXER_THREAD(&StreamMixerAlsa::AddLoopbackAudioObserver, observer);
919 DCHECK(observer); 966 DCHECK(observer);
920 DCHECK(std::find(loopback_observers_.begin(), loopback_observers_.end(), 967 DCHECK(std::find(loopback_observers_.begin(), loopback_observers_.end(),
921 observer) == loopback_observers_.end()); 968 observer) == loopback_observers_.end());
922 loopback_observers_.push_back(observer); 969 loopback_observers_.push_back(observer);
923 } 970 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
976 for (auto&& input : inputs_) { 1023 for (auto&& input : inputs_) {
977 // Volume limits don't apply to effects streams. 1024 // Volume limits don't apply to effects streams.
978 if (input->primary() && input->content_type() == type) { 1025 if (input->primary() && input->content_type() == type) {
979 input->SetContentTypeVolume(effective_volume, fade_ms); 1026 input->SetContentTypeVolume(effective_volume, fade_ms);
980 } 1027 }
981 } 1028 }
982 } 1029 }
983 1030
984 } // namespace media 1031 } // namespace media
985 } // namespace chromecast 1032 } // namespace chromecast
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698