blob: 48cbdb36326b928c1ad55eceb9d87c83b40c962a [file] [log] [blame]
// Copyright (c) 2014 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.
#include <stddef.h>
#include <memory>
#include "base/containers/circular_deque.h"
#include "base/time/time.h"
#include "media/base/media_export.h"
#include "media/base/multi_channel_resampler.h"
namespace media {
class AudioBus;
class ClockSmoother;
// This class works like a buffer between a push based audio source
// and a pull-based audio sink. The source and sink should operate
// at nominally the same rate, but since they may run on different
// hardware clocks, the rate may differ a little. If left unchecked,
// this difference will first cause lip sync issues between audio
// and video and eventually it will cause buffer overruns/underruns.
// This class solves all that by dynamically resampling the audio
// so that both input and output sources are happy.
// A note about TimeTicks. The playout_time specified in Push and
// Pull calls must come from the same timeline. That timeline can
// be anything you choose as it is never compared to any real-world
// clocks, but they must come from the same clock. Specifically,
// specifying samples / rate as the playout time in Push() or Pull()
// will NOT work.
class MEDIA_EXPORT AudioShifter {
// |max_buffer_size| is how much audio we are allowed to buffer.
// Often, this can be set fairly large as Push() will limit the
// size when it specifies when to play the audio.
// |clock_accuracy| is used to determine if a skip has occurred
// in the audio (as opposed to an inaccuracy in the timestamp.)
// It also limits the smallest amount of buffering allowed.
// |adjustement_time| specifies how long time should be used
// to adjust the audio. This should normally at least a few
// seconds. The larger the value, the smoother and less audible
// the transitions will be. (But it means that perfect audio
// sync will take longer to achieve.)
// |rate| is audio frames per second, eg 48000.
// |channels| is number of channels in input and output audio.
// TODO(hubbe): Allow input rate and output rate to be different
// since we're going to be resampling anyways.
AudioShifter(base::TimeDelta max_buffer_size,
base::TimeDelta clock_accuracy,
base::TimeDelta adjustment_time,
int rate,
int channels);
int sample_rate() const { return rate_; }
int channels() const { return channels_; }
// Push Audio into the shifter. All inputs must have the same number of
// channels, but bus size can vary. The playout time can be noisy and
// does not have to line up perfectly with the number of samples pushed
// so far. However, the playout_time in Push calls and Pull calls must
// not diverge over time.
// Given audio from an a microphone, a reasonable way to calculate
// playout_time would be now + 30ms.
// Ideally playout_time is some time in the future, in which case
// the samples will be buffered until the appropriate time. If
// playout_time is in the past, everything will still work, and we'll
// try to keep the buffering to a minimum.
void Push(std::unique_ptr<AudioBus> input, base::TimeTicks playout_time);
// Fills out |output| with samples. Tries to stretch/shrink the audio
// to compensate for drift between input and output.
// If called from an output device data pull, a reasonable way to
// calculate playout_time would be now + audio pipeline delay.
void Pull(AudioBus* output, base::TimeTicks playout_time);
void Zero(AudioBus* output);
void ResamplerCallback(int frame_delay, AudioBus* destination);
struct AudioQueueEntry {
AudioQueueEntry(base::TimeTicks target_playout_time,
std::unique_ptr<AudioBus> audio);
AudioQueueEntry(AudioQueueEntry&& other);
base::TimeTicks target_playout_time;
std::unique_ptr<AudioBus> audio;
// Set from constructor.
const base::TimeDelta max_buffer_size_;
const base::TimeDelta clock_accuracy_;
const base::TimeDelta adjustment_time_;
const int rate_;
const int channels_;
// The clock smoothers are used to smooth out timestamps
// and adjust for drift and inaccurate clocks.
std::unique_ptr<ClockSmoother> input_clock_smoother_;
std::unique_ptr<ClockSmoother> output_clock_smoother_;
// Are we currently outputting data?
bool running_;
// Number of frames already consumed from |queue_|.
size_t position_;
// Queue of data provided to us.
base::circular_deque<AudioQueueEntry> queue_;
// Timestamp from last Pull() call.
base::TimeTicks previous_playout_time_;
// Number of frames requested in last Pull call.
size_t previous_requested_samples_;
// Timestamp at the end of last audio bus
// consumed by resampler.
base::TimeTicks end_of_last_consumed_audiobus_;
// If Push() timestamps are in the past, we have to decide the playout delay
// ourselves. The delay is then stored here.
base::TimeDelta bias_;
// Resampler.
MultiChannelResampler resampler_;
// Current resampler ratio.
double current_ratio_;
} // namespace media