| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <algorithm> |
| #include <cmath> |
| #include <cstddef> |
| #include <cstdint> |
| #include <memory> |
| #include <optional> |
| |
| #include "base/check_op.h" |
| #include "base/functional/bind.h" |
| #include "chromecast/media/api/audio_clock_simulator.h" |
| #include "chromecast/media/api/audio_provider.h" |
| #include "media/base/audio_bus.h" |
| #include "media/base/multi_channel_resampler.h" |
| |
| namespace chromecast { |
| namespace media { |
| |
| namespace { |
| constexpr size_t kMaxChannels = 32; |
| constexpr size_t kDefaultResampleBufferFrames = 2048; |
| |
| class AudioClockSimulatorImpl : public AudioClockSimulator { |
| public: |
| explicit AudioClockSimulatorImpl(AudioProvider* provider) |
| : provider_(provider), |
| sample_rate_(provider_->sample_rate()), |
| num_channels_(provider_->num_channels()) { |
| DCHECK(provider_); |
| DCHECK_GT(sample_rate_, 0); |
| DCHECK_GT(num_channels_, 0u); |
| DCHECK_LE(num_channels_, kMaxChannels); |
| |
| resample_buffer_ = |
| ::media::AudioBus::Create(num_channels_, kDefaultResampleBufferFrames); |
| resampler_ = std::make_unique<::media::MultiChannelResampler>( |
| num_channels_, 1.0, ::media::SincResampler::kSmallRequestSize, |
| base::BindRepeating(&AudioClockSimulatorImpl::ResamplerReadCallback, |
| base::Unretained(this))); |
| resampler_->PrimeWithSilence(); |
| } |
| |
| ~AudioClockSimulatorImpl() override = default; |
| |
| AudioClockSimulatorImpl(const AudioClockSimulatorImpl&) = delete; |
| AudioClockSimulatorImpl& operator=(const AudioClockSimulatorImpl&) = delete; |
| |
| // AudioClockSimulator implementation: |
| double SetRate(double rate) override { |
| if (in_fill_) { |
| pending_rate_ = rate; |
| return rate; |
| } |
| if (rate != clock_rate_) { |
| clock_rate_ = rate; |
| resampler_->SetRatio(clock_rate_); |
| } |
| return rate; |
| } |
| |
| double DelayFrames() const override { |
| return resampler_->BufferedFrames() + resampler_->KernelSize() / 2; |
| } |
| |
| void SetSampleRate(int sample_rate) override { sample_rate_ = sample_rate; } |
| |
| void SetPlaybackRate(double playback_rate) override { |
| playback_rate_ = playback_rate; |
| } |
| |
| int FillFrames(int num_frames, |
| int64_t playout_timestamp, |
| float* const* channel_data) override { |
| if (num_frames > resample_buffer_->frames()) { |
| resample_buffer_ = |
| ::media::AudioBus::Create(num_channels_, num_frames * 2); |
| } |
| request_timestamp_ = playout_timestamp; |
| // resampler_->BufferedFrames() gives incorrect values in the read callback, |
| // so track the number of buffered frames ourselves. |
| resampler_buffered_frames_ = DelayFrames(); |
| in_fill_ = true; |
| resampler_->Resample(num_frames, resample_buffer_.get()); |
| in_fill_ = false; |
| if (pending_rate_.has_value()) { |
| SetRate(pending_rate_.value()); |
| pending_rate_.reset(); |
| } |
| for (size_t c = 0; c < num_channels_; ++c) { |
| std::copy_n(resample_buffer_->channel(c), num_frames, channel_data[c]); |
| } |
| return num_frames; |
| } |
| |
| size_t num_channels() const override { return num_channels_; } |
| |
| int sample_rate() const override { return sample_rate_; } |
| |
| private: |
| void ResamplerReadCallback(int frame_delay, ::media::AudioBus* output) { |
| float* channels[kMaxChannels]; |
| for (size_t c = 0; c < num_channels_; ++c) { |
| channels[c] = output->channel(c); |
| } |
| |
| int64_t timestamp = |
| request_timestamp_ + FramesToMicroseconds(resampler_buffered_frames_); |
| const int needed_frames = output->frames(); |
| int filled = provider_->FillFrames(output->frames(), timestamp, channels); |
| if (filled < needed_frames) { |
| output->ZeroFramesPartial(filled, needed_frames - filled); |
| } |
| resampler_buffered_frames_ += output->frames(); |
| } |
| |
| int64_t FramesToMicroseconds(double frames) { |
| return std::round(frames * 1000000 / (sample_rate_ * playback_rate_)); |
| } |
| |
| AudioProvider* const provider_; |
| int sample_rate_; |
| const size_t num_channels_; |
| double playback_rate_ = 1.0; |
| |
| double clock_rate_ = 1.0; |
| |
| std::unique_ptr<::media::AudioBus> resample_buffer_; |
| std::unique_ptr<::media::MultiChannelResampler> resampler_; |
| |
| int64_t request_timestamp_ = 0; |
| double resampler_buffered_frames_ = 0.0; |
| bool in_fill_ = false; |
| std::optional<double> pending_rate_; |
| }; |
| |
| } // namespace |
| |
| // static |
| std::unique_ptr<AudioClockSimulator> AudioClockSimulator::Create( |
| AudioProvider* provider) { |
| return std::make_unique<AudioClockSimulatorImpl>(provider); |
| } |
| |
| } // namespace media |
| } // namespace chromecast |