chromium/chromecast/media/audio/audio_clock_simulator_impl.cc

// 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