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.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 <utility> | 10 #include <utility> |
10 | 11 |
11 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
12 #include "base/command_line.h" | 13 #include "base/command_line.h" |
13 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
14 #include "base/memory/weak_ptr.h" | 15 #include "base/memory/weak_ptr.h" |
15 #include "base/single_thread_task_runner.h" | 16 #include "base/single_thread_task_runner.h" |
16 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
17 #include "base/threading/platform_thread.h" | 18 #include "base/threading/platform_thread.h" |
18 #include "base/threading/thread_task_runner_handle.h" | 19 #include "base/threading/thread_task_runner_handle.h" |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 // direction they adjusted the requested parameter in, but since we read the | 103 // direction they adjusted the requested parameter in, but since we read the |
103 // output param and then log the information, this module doesn't need to get | 104 // output param and then log the information, this module doesn't need to get |
104 // the direction explicitly. | 105 // the direction explicitly. |
105 static int* kAlsaDirDontCare = nullptr; | 106 static int* kAlsaDirDontCare = nullptr; |
106 | 107 |
107 // These sample formats will be tried in order. 32 bit samples is ideal, but | 108 // These sample formats will be tried in order. 32 bit samples is ideal, but |
108 // some devices do not support 32 bit samples. | 109 // some devices do not support 32 bit samples. |
109 const snd_pcm_format_t kPreferredSampleFormats[] = {SND_PCM_FORMAT_S32, | 110 const snd_pcm_format_t kPreferredSampleFormats[] = {SND_PCM_FORMAT_S32, |
110 SND_PCM_FORMAT_S16}; | 111 SND_PCM_FORMAT_S16}; |
111 | 112 |
| 113 const int64_t kNoTimestamp = std::numeric_limits<int64_t>::min(); |
| 114 |
112 int64_t TimespecToMicroseconds(struct timespec time) { | 115 int64_t TimespecToMicroseconds(struct timespec time) { |
113 return static_cast<int64_t>(time.tv_sec) * | 116 return static_cast<int64_t>(time.tv_sec) * |
114 base::Time::kMicrosecondsPerSecond + | 117 base::Time::kMicrosecondsPerSecond + |
115 time.tv_nsec / 1000; | 118 time.tv_nsec / 1000; |
116 } | 119 } |
117 | 120 |
118 bool GetSwitchValueAsInt(const std::string& switch_name, | 121 bool GetSwitchValueAsInt(const std::string& switch_name, |
119 int default_value, | 122 int default_value, |
120 int* value) { | 123 int* value) { |
121 DCHECK(value); | 124 DCHECK(value); |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 } | 530 } |
528 | 531 |
529 if (post_loopback_filter_) { | 532 if (post_loopback_filter_) { |
530 post_loopback_filter_->SetSampleRateAndFormat( | 533 post_loopback_filter_->SetSampleRateAndFormat( |
531 output_samples_per_second_, ::media::SampleFormat::kSampleFormatS32); | 534 output_samples_per_second_, ::media::SampleFormat::kSampleFormatS32); |
532 } | 535 } |
533 | 536 |
534 RETURN_REPORT_ERROR(PcmPrepare, pcm_); | 537 RETURN_REPORT_ERROR(PcmPrepare, pcm_); |
535 RETURN_REPORT_ERROR(PcmStatusMalloc, &pcm_status_); | 538 RETURN_REPORT_ERROR(PcmStatusMalloc, &pcm_status_); |
536 | 539 |
537 struct timespec now = {0, 0}; | 540 rendering_delay_.timestamp_microseconds = kNoTimestamp; |
538 clock_gettime(CLOCK_MONOTONIC_RAW, &now); | |
539 rendering_delay_.timestamp_microseconds = TimespecToMicroseconds(now); | |
540 rendering_delay_.delay_microseconds = 0; | 541 rendering_delay_.delay_microseconds = 0; |
541 | 542 |
542 state_ = kStateNormalPlayback; | 543 state_ = kStateNormalPlayback; |
543 } | 544 } |
544 | 545 |
545 void StreamMixerAlsa::Stop() { | 546 void StreamMixerAlsa::Stop() { |
546 for (auto* observer : loopback_observers_) { | 547 for (auto* observer : loopback_observers_) { |
547 observer->OnLoopbackInterrupted(); | 548 observer->OnLoopbackInterrupted(); |
548 } | 549 } |
549 | 550 |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
822 int frames) { | 823 int frames) { |
823 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 824 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
824 CHECK_PCM_INITIALIZED(); | 825 CHECK_PCM_INITIALIZED(); |
825 | 826 |
826 size_t interleaved_size = static_cast<size_t>(frames * kNumOutputChannels) * | 827 size_t interleaved_size = static_cast<size_t>(frames * kNumOutputChannels) * |
827 BytesPerOutputFormatSample(); | 828 BytesPerOutputFormatSample(); |
828 if (interleaved_.size() < interleaved_size) { | 829 if (interleaved_.size() < interleaved_size) { |
829 interleaved_.resize(interleaved_size); | 830 interleaved_.resize(interleaved_size); |
830 } | 831 } |
831 | 832 |
832 int64_t expected_playback_time = rendering_delay_.timestamp_microseconds + | 833 int64_t expected_playback_time; |
833 rendering_delay_.delay_microseconds; | 834 if (rendering_delay_.timestamp_microseconds == kNoTimestamp) { |
| 835 expected_playback_time = kNoTimestamp; |
| 836 } else { |
| 837 expected_playback_time = rendering_delay_.timestamp_microseconds + |
| 838 rendering_delay_.delay_microseconds; |
| 839 } |
| 840 |
834 mixed.ToInterleaved(frames, BytesPerOutputFormatSample(), | 841 mixed.ToInterleaved(frames, BytesPerOutputFormatSample(), |
835 interleaved_.data()); | 842 interleaved_.data()); |
836 // Filter, send to observers, and post filter | 843 // Filter, send to observers, and post filter |
837 if (pre_loopback_filter_) { | 844 if (pre_loopback_filter_) { |
838 pre_loopback_filter_->ProcessInterleaved(interleaved_.data(), frames); | 845 pre_loopback_filter_->ProcessInterleaved(interleaved_.data(), frames); |
839 } | 846 } |
840 | 847 |
841 for (CastMediaShlib::LoopbackAudioObserver* observer : loopback_observers_) { | 848 for (CastMediaShlib::LoopbackAudioObserver* observer : loopback_observers_) { |
842 observer->OnLoopbackAudio(expected_playback_time, kSampleFormatS32, | 849 observer->OnLoopbackAudio(expected_playback_time, kSampleFormatS32, |
843 output_samples_per_second_, kNumOutputChannels, | 850 output_samples_per_second_, kNumOutputChannels, |
(...skipping 27 matching lines...) Expand all Loading... |
871 } | 878 } |
872 UpdateRenderingDelay(frames); | 879 UpdateRenderingDelay(frames); |
873 for (auto&& input : inputs_) | 880 for (auto&& input : inputs_) |
874 input->AfterWriteFrames(rendering_delay_); | 881 input->AfterWriteFrames(rendering_delay_); |
875 } | 882 } |
876 | 883 |
877 void StreamMixerAlsa::UpdateRenderingDelay(int newly_pushed_frames) { | 884 void StreamMixerAlsa::UpdateRenderingDelay(int newly_pushed_frames) { |
878 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); | 885 DCHECK(mixer_task_runner_->BelongsToCurrentThread()); |
879 CHECK_PCM_INITIALIZED(); | 886 CHECK_PCM_INITIALIZED(); |
880 | 887 |
881 if (alsa_->PcmStatus(pcm_, pcm_status_) != 0) { | 888 if (alsa_->PcmStatus(pcm_, pcm_status_) != 0 || |
882 // Estimate updated delay based on the number of frames we just pushed. | 889 alsa_->PcmStatusGetState(pcm_status_) != SND_PCM_STATE_RUNNING) { |
883 rendering_delay_.delay_microseconds += | 890 rendering_delay_.timestamp_microseconds = kNoTimestamp; |
884 static_cast<int64_t>(newly_pushed_frames) * | 891 rendering_delay_.delay_microseconds = 0; |
885 base::Time::kMicrosecondsPerSecond / output_samples_per_second_; | |
886 return; | 892 return; |
887 } | 893 } |
888 | 894 |
889 snd_htimestamp_t status_timestamp; | 895 snd_htimestamp_t status_timestamp; |
890 alsa_->PcmStatusGetHtstamp(pcm_status_, &status_timestamp); | 896 alsa_->PcmStatusGetHtstamp(pcm_status_, &status_timestamp); |
891 rendering_delay_.timestamp_microseconds = | 897 rendering_delay_.timestamp_microseconds = |
892 TimespecToMicroseconds(status_timestamp); | 898 TimespecToMicroseconds(status_timestamp); |
893 snd_pcm_sframes_t delay_frames = alsa_->PcmStatusGetDelay(pcm_status_); | 899 snd_pcm_sframes_t delay_frames = alsa_->PcmStatusGetDelay(pcm_status_); |
894 rendering_delay_.delay_microseconds = static_cast<int64_t>(delay_frames) * | 900 rendering_delay_.delay_microseconds = static_cast<int64_t>(delay_frames) * |
895 base::Time::kMicrosecondsPerSecond / | 901 base::Time::kMicrosecondsPerSecond / |
(...skipping 15 matching lines...) Expand all Loading... |
911 DCHECK(std::find(loopback_observers_.begin(), loopback_observers_.end(), | 917 DCHECK(std::find(loopback_observers_.begin(), loopback_observers_.end(), |
912 observer) != loopback_observers_.end()); | 918 observer) != loopback_observers_.end()); |
913 loopback_observers_.erase(std::remove(loopback_observers_.begin(), | 919 loopback_observers_.erase(std::remove(loopback_observers_.begin(), |
914 loopback_observers_.end(), observer), | 920 loopback_observers_.end(), observer), |
915 loopback_observers_.end()); | 921 loopback_observers_.end()); |
916 observer->OnRemoved(); | 922 observer->OnRemoved(); |
917 } | 923 } |
918 | 924 |
919 } // namespace media | 925 } // namespace media |
920 } // namespace chromecast | 926 } // namespace chromecast |
OLD | NEW |