chromium/chromecast/media/audio/mixer_service/loopback_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_LOOPBACK_CONNECTION_H_
#define CHROMECAST_MEDIA_AUDIO_MIXER_SERVICE_LOOPBACK_CONNECTION_H_

#include <cstdint>
#include <memory>

#include "base/memory/scoped_refptr.h"
#include "chromecast/media/audio/mixer_service/loopback_interrupt_reason.h"
#include "chromecast/media/audio/mixer_service/mixer_connection.h"
#include "chromecast/media/audio/mixer_service/mixer_socket.h"
#include "chromecast/public/media/decoder_config.h"

namespace chromecast {
namespace media {
namespace mixer_service {
class Generic;

// Connection for observing loopback audio data from the mixer. Must be created
// and used on an IO thread.
class LoopbackConnection : public MixerConnection,
                           public MixerSocket::Delegate {
 public:
  // Observer for audio loopback data.
  class Delegate {
   public:
    // Called whenever loopback audio data is available. The |timestamp| is the
    // estimated time in microseconds (relative to the audio clock) that
    // the audio will actually be output. |length| is the length of the audio
    // |data| in bytes. The format of the data is given by |sample_format| and
    // |num_channels|.
    virtual void OnLoopbackAudio(int64_t timestamp,
                                 media::SampleFormat sample_format,
                                 int sample_rate,
                                 int num_channels,
                                 uint8_t* data,
                                 int length) = 0;

    // Called if the loopback data is not continuous (ie, does not accurately
    // represent the actual output) for any reason. For example, if there is an
    // output underflow, or if output is disabled due to no output streams.
    virtual void OnLoopbackInterrupted(LoopbackInterruptReason reason) = 0;

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

  explicit LoopbackConnection(Delegate* delegate);
  // For testing only.
  LoopbackConnection(Delegate* delegate,
                     std::unique_ptr<MixerSocket> connected_socket_for_test);

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

  ~LoopbackConnection() override;

  // Initiates connection to the mixer service. Delegate methods can be called
  // at any point after Connect() is called, until this is destroyed.
  void Connect();

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

  // MixerSocket::Delegate implementation:
  bool HandleMetadata(const Generic& message) override;
  bool HandleAudioData(char* data, size_t size, int64_t timestamp) override;

  Delegate* const delegate_;

  std::unique_ptr<MixerSocket> socket_;

  media::SampleFormat format_ = kUnknownSampleFormat;
  int sample_rate_ = 0;
  int num_channels_ = 0;
};

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

#endif  // CHROMECAST_MEDIA_AUDIO_MIXER_SERVICE_LOOPBACK_CONNECTION_H_