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

#ifndef MEDIA_BASE_AUDIO_SHIFTER_H_
#define MEDIA_BASE_AUDIO_SHIFTER_H_

#include <stddef.h>

#include <deque>
#include <memory>

#include "base/memory/linked_ptr.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 {
 public:
  // |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 occured
  // 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 achive.)
  // |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);
  ~AudioShifter();

  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 approperiate time. If
  // playout_time is in the past, everything will still work, and we'll
  // try to keep the buffring 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);

private:
  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(const AudioQueueEntry& other);
    ~AudioQueueEntry();
    base::TimeTicks target_playout_time;
    linked_ptr<AudioBus> audio;
  };

  typedef std::deque<AudioQueueEntry> AudioShifterQueue;

  // 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.
  AudioShifterQueue queue_;

  // Timestamp from alst Pull() call.
  base::TimeTicks previous_playout_time_;
  // Number of rames 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 decidede the playout delay
  // ourselves. The delay is then stored here.
  base::TimeDelta bias_;

  // Resampler.
  MultiChannelResampler resampler_;

  // Current resampler ratio.
  double current_ratio_;
};

}  // namespace media

#endif  // MEDIA_BASE_AUDIO_SHIFTER_H_
