blob: 875a0f64816682ea55d7e615b0d5bda7fa60bf52 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMECAST_MEDIA_AUDIO_AUDIO_CLOCK_SIMULATOR_H_
#define CHROMECAST_MEDIA_AUDIO_AUDIO_CLOCK_SIMULATOR_H_
#include <cstddef>
#include <cstdint>
#include <memory>
#include "chromecast/media/audio/audio_provider.h"
namespace media {
class AudioBus;
} // namespace media
namespace chromecast {
namespace media {
// Simulates a modifiable audio output clock rate by interpolating as needed to
// add or remove single frames.
class AudioClockSimulator : public AudioProvider {
public:
// Number of frames to linearly interpolate over. One interpolation starts,
// it continues until the window is complete; rate changes only take effect
// once the window is complete.
static constexpr int kInterpolateWindow = 1024;
// Maximum/minimum rate that this class supports. If the rate passed to
// SetRate() is outside of these bounds, it is clamped to within the bounds
// and the clamped value is returned. Note that the rate is essentially
// (num_input_frames) / (num_output_frames).
static constexpr double kMaxRate =
(kInterpolateWindow + 1.0) / kInterpolateWindow;
static constexpr double kMinRate =
kInterpolateWindow / (kInterpolateWindow + 1.0);
// Maximum channels that this class supports.
static constexpr size_t kMaxChannels = 32;
explicit AudioClockSimulator(AudioProvider* provider);
~AudioClockSimulator() override;
AudioClockSimulator(const AudioClockSimulator&) = delete;
AudioClockSimulator& operator=(const AudioClockSimulator&) = delete;
// Sets the simulated audio clock rate. The rate is capped internally between
// kMinRate and kMaxRate. Returns the capped effective rate.
double SetRate(double rate);
// Returns the number of frames of additional delay due to audio stored
// internally. Will always return 0 or 1.
int DelayFrames() const;
// Sets a new playback sample rate. Needed to calculate timestamps correctly.
void SetSampleRate(int sample_rate);
// Sets the playback rate (rate at which samples are played out relative to
// the sample rate). Needed to calculate timestamps correctly.
void SetPlaybackRate(double playback_rate);
// AudioProvider implementation:
int FillFrames(int num_frames,
int64_t playout_timestamp,
float* const* channel_data) override;
size_t num_channels() const override;
int sample_rate() const override;
private:
enum class State {
kPassthrough,
kLengthening,
kShortening,
};
struct FillResult {
bool complete;
int filled;
};
FillResult FillDataLengthen(int num_frames,
int64_t playout_timestamp,
float* const* channel_data,
int offset);
FillResult FillDataShorten(int num_frames,
int64_t playout_timestamp,
float* const* channel_data,
int offset);
void InterpolateLonger(int num_frames,
float* const* channel_data,
int offset);
void InterpolateShorter(int num_frames,
float* const* channel_data,
int offset);
int64_t FramesToMicroseconds(int64_t frames);
AudioProvider* const provider_;
int sample_rate_;
const size_t num_channels_;
double playback_rate_ = 1.0;
double clock_rate_ = 1.0;
int64_t input_frames_ = 0;
int64_t output_frames_ = 0;
State state_ = State::kPassthrough;
int interpolate_position_ = 0;
bool first_frame_filled_ = false;
// Scratch buffer used to hold the filled original data before it is
// interpolated for output. The first frame (first sample across all channels)
// at index 0 is used to hold the last frame of the previous partial
// interpolation step.
// At the start of the interpolation window:
// * If we are interpolating to make the audio longer, the first frame is
// not used (the weight is 0), so it can be any value.
// * If we are interpolating to make the audio shorted, the first fill
// request to the provider fills in the first frame (so we request one
// extra frame of audio) - this accounts for the frame that is removed due
// to interpolation.
// The |first_frame_filled_| member var tracks whether or not the first frame
// of the |scratch_buffer_| contains valid audio.
std::unique_ptr<::media::AudioBus> scratch_buffer_;
};
} // namespace media
} // namespace chromecast
#endif // CHROMECAST_MEDIA_AUDIO_AUDIO_CLOCK_SIMULATOR_H_