chromium/chromecast/media/cma/backend/audio_decoder_for_mixer.h

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_DECODER_FOR_MIXER_H_
#define CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_DECODER_FOR_MIXER_H_

#include <cstdint>
#include <memory>

#include "base/functional/bind.h"
#include "chromecast/media/api/cast_audio_decoder.h"
#include "chromecast/media/audio/mixer_service/output_stream_connection.h"
#include "chromecast/public/media/decoder_config.h"
#include "chromecast/public/media/media_pipeline_backend.h"
#include "chromecast/public/media/media_pipeline_device_params.h"
#include "media/base/audio_buffer.h"

namespace base {
class SingleThreadTaskRunner;
}  // namespace base

namespace chromecast {
class IOBufferPool;

namespace media {
class DecoderBufferBase;
class MediaPipelineBackendForMixer;

// AudioDecoder implementation that streams decoded stream to the StreamMixer.
class AudioDecoderForMixer
    : public MediaPipelineBackend::AudioDecoder,
      public mixer_service::OutputStreamConnection::Delegate {
 public:
  using BufferStatus = MediaPipelineBackend::BufferStatus;

  explicit AudioDecoderForMixer(MediaPipelineBackendForMixer* backend);

  AudioDecoderForMixer(const AudioDecoderForMixer&) = delete;
  AudioDecoderForMixer& operator=(const AudioDecoderForMixer&) = delete;

  ~AudioDecoderForMixer() override;

  virtual void Initialize();
  virtual bool Start(int64_t pts, bool av_sync_enabled);
  void StartPlaybackAt(int64_t timestamp);
  virtual void Stop();
  virtual bool Pause();
  virtual bool Resume();
  virtual float SetPlaybackRate(float rate);
  virtual bool GetTimestampedPts(int64_t* timestamp, int64_t* pts) const;
  virtual int64_t GetCurrentPts() const;

  // MediaPipelineBackend::AudioDecoder implementation:
  void SetDelegate(MediaPipelineBackend::Decoder::Delegate* delegate) override;
  BufferStatus PushBuffer(CastDecoderBuffer* buffer) override;
  void GetStatistics(Statistics* statistics) override;
  bool SetConfig(const AudioConfig& config) override;
  bool SetVolume(float multiplier) override;
  RenderingDelay GetRenderingDelay() override;
  AudioTrackTimestamp GetAudioTrackTimestamp() override;
  int GetStartThresholdInFrames() override;

  // This allows for very small changes in the rate of audio playback that are
  // (supposedly) imperceptible.
  double SetAvSyncPlaybackRate(double rate);
  void RestartPlaybackAt(int64_t pts, int64_t timestamp);

  RenderingDelay GetMixerRenderingDelay();

 private:
  friend class MockAudioDecoderForMixer;
  friend class AvSyncTest;

  // mixer_service::OutputStreamConnection::Delegate implementation:
  void FillNextBuffer(void* buffer,
                      int frames,
                      int64_t delay_timestamp,
                      int64_t delay) override;
  void OnAudioReadyForPlayback(int64_t mixer_delay) override;
  void OnEosPlayed() override;
  void OnMixerError() override;

  void CreateBufferPool(const AudioConfig& config, int frame_count);
  void CreateMixerInput(const AudioConfig& config, bool av_sync_enabled);
  void CleanUpPcm();
  void ResetMixerInputForNewConfig(const AudioConfig& config);
  void CreateDecoder();

  void OnBufferDecoded(uint64_t input_bytes,
                       bool has_config,
                       CastAudioDecoder::Status status,
                       const AudioConfig& config,
                       scoped_refptr<DecoderBufferBase> decoded);
  void CheckBufferComplete();
  void WritePcm(scoped_refptr<DecoderBufferBase> buffer);
  bool BypassDecoder() const;
  void UpdateStatistics(Statistics delta);

  MediaPipelineBackendForMixer* const backend_;
  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
  MediaPipelineBackend::Decoder::Delegate* delegate_ = nullptr;

  Statistics stats_;

  int buffer_pool_frames_ = 0;
  bool pending_buffer_complete_ = false;
  bool mixer_error_ = false;
  bool paused_ = false;
  float playback_rate_ = 1.0f;
  bool reported_ready_for_playback_ = false;
  RenderingDelay mixer_delay_;

  AudioConfig input_config_;
  AudioConfig decoded_config_;
  std::unique_ptr<CastAudioDecoder> decoder_;

  double av_sync_clock_rate_ = 1.0;

  std::unique_ptr<mixer_service::OutputStreamConnection> mixer_input_;

  RenderingDelay next_buffer_delay_;
  int64_t pending_output_frames_ = -1;
  float volume_multiplier_ = 1.0f;

  int64_t last_push_pts_ = INT64_MIN;
  int64_t last_push_playout_timestamp_ = INT64_MIN;

  scoped_refptr<::media::AudioBufferMemoryPool> pool_;
  scoped_refptr<IOBufferPool> buffer_pool_;

  int64_t playback_start_pts_ = 0;
  bool av_sync_enabled_ = false;

  base::WeakPtrFactory<AudioDecoderForMixer> weak_factory_;
};

}  // namespace media
}  // namespace chromecast

#endif  // CHROMECAST_MEDIA_CMA_BACKEND_AUDIO_DECODER_FOR_MIXER_H_