chromium/chromecast/media/audio/mixer_service/output_stream_connection.h

// Copyright 2019 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_AUDIO_MIXER_SERVICE_OUTPUT_STREAM_CONNECTION_H_
#define CHROMECAST_MEDIA_AUDIO_MIXER_SERVICE_OUTPUT_STREAM_CONNECTION_H_

#include <cstdint>
#include <memory>

#include "base/memory/scoped_refptr.h"
#include "chromecast/media/audio/mixer_service/mixer_connection.h"
#include "chromecast/media/audio/mixer_service/mixer_socket.h"
#include "net/base/io_buffer.h"

namespace chromecast {
class CastEventBuilder;
class IOBufferPool;

namespace media {
namespace mixer_service {
class Generic;
class OutputStreamParams;

// Mixer service connection for an audio output stream. Not thread-safe; all
// usage of a given instance must be on the same sequence.
class OutputStreamConnection : public MixerConnection,
                               public MixerSocket::Delegate {
 public:
  class Delegate {
   public:
    // Keep in sync with mixer_service.proto:MixerUnderrun.Type
    enum class MixerUnderrunType {
      // An underrun was detected on mixer input.
      kStream = 0,
      // An underrun was detected on mixer output.
      kMixer = 1,
    };

    // Called to fill more audio data. The implementation should write up to
    // |frames| frames of audio data into |buffer|, and then call
    // SendNextBuffer() with the actual number of frames that were filled (or
    // 0 to indicate end-of-stream). The |playout_timestamp| indicates the
    // audio clock timestamp in microseconds when the first frame of the filled
    // data is expected to play out.
    virtual void FillNextBuffer(void* buffer,
                                int frames,
                                int64_t delay_timestamp,
                                int64_t delay) = 0;

    // Called when audio is ready to begin playing out, ie the start threshold
    // has been reached. |mixer_delay| is the delay before the first buffered
    // audio will start playing out, in microseconds.
    virtual void OnAudioReadyForPlayback(int64_t mixer_delay) {}

    // Called when the end of the stream has been played out. At this point it
    // is safe to delete the delegate without dropping any audio.
    virtual void OnEosPlayed() = 0;

    // Called when a mixer error has occurred; audio from this stream will no
    // longer be played out.
    virtual void OnMixerError() {}

    // Called when an underrun happens on mixer input/output.
    virtual void OnMixerUnderrun(MixerUnderrunType type) {}

    // Called when OutputStreamConnection records a cast event. It allows
    // the Delegate to provide some extra data to the event.
    virtual void ProcessCastEvent(CastEventBuilder* event) {}

   protected:
    virtual ~Delegate() = default;
  };

  OutputStreamConnection(Delegate* delegate, const OutputStreamParams& params);

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

  ~OutputStreamConnection() override;

  // Connects to the mixer. After this is called, delegate methods may start
  // to be called. If the mixer connection is lost, this will automatically
  // reconnect.
  void Connect();

  // Sends filled audio data (written into the buffer provided to
  // FillNextBuffer()) to the mixer. |filled_frames| indicates the number of
  // frames of audio that were actually written into the buffer, or 0 to
  // indicate end-of-stream. |pts| is the PTS of the first frame of filled
  // audio; this is only meaningful when params.use_start_timestamp is |true|.
  void SendNextBuffer(int filled_frames, int64_t pts = 0);

  // Sends a preallocated audio buffer. The buffer does not need to be prepared
  // first using MixerSocket::PrepareAudioBuffer(), since that is done inside
  // this method.
  void SendAudioBuffer(scoped_refptr<net::IOBuffer> audio_buffer,
                       int filled_frames,
                       int64_t pts);

  // Sets the volume multiplier for this audio stream.
  void SetVolumeMultiplier(float multiplier);

  // Indicates that playback should (re)start playing PTS |pts| at time
  // |start_timestamp| in microseconds relative to the audio clock.
  void SetStartTimestamp(int64_t start_timestamp, int64_t pts);

  // Informs the mixer how fast the PTS increases per frame. For example if the
  // playback rate is 2.0, then each frame increases the PTS by
  // 2.0 / sample_rate seconds.
  void SetPlaybackRate(float playback_rate);

  // Changes the audio output clock rate. If the provided |rate| is outside of
  // the supported range, the rate will be clamped to the supported range.
  void SetAudioClockRate(double rate);

  // Pauses playback.
  void Pause();

  // Resumes playback.
  void Resume();

  // Adjusts timestamps.
  void SendTimestampAdjustment(int64_t timestamp_adjustment);

 private:
  // MixerConnection implementation:
  void OnConnected(std::unique_ptr<MixerSocket> socket) override;
  void OnConnectionError() override;

  // MixerSocket::Delegate implementation:
  bool HandleMetadata(const Generic& message) override;

  Delegate* const delegate_;
  std::unique_ptr<OutputStreamParams> params_;

  const int frame_size_;
  const int fill_size_frames_;

  const scoped_refptr<IOBufferPool> buffer_pool_;
  scoped_refptr<net::IOBuffer> audio_buffer_;

  std::unique_ptr<MixerSocket> socket_;
  float volume_multiplier_ = 1.0f;

  int64_t start_timestamp_ = INT64_MIN;
  int64_t start_pts_ = INT64_MIN;

  float playback_rate_ = 1.0f;
  double audio_clock_rate_ = 1.0;

  bool paused_ = false;
  bool sent_eos_ = false;

  bool dropping_audio_ = false;
};

}  // namespace mixer_service
}  // namespace media
}  // namespace chromecast

#endif  // CHROMECAST_MEDIA_AUDIO_MIXER_SERVICE_OUTPUT_STREAM_CONNECTION_H_