chromium/chromecast/media/cma/backend/mixer/mixer_loopback_connection.cc

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

#include "chromecast/media/cma/backend/mixer/mixer_loopback_connection.h"

#include <utility>

#include "base/check.h"
#include "chromecast/media/audio/mixer_service/loopback_interrupt_reason.h"
#include "chromecast/media/audio/mixer_service/mixer_service_transport.pb.h"
#include "chromecast/media/audio/net/common.pb.h"
#include "chromecast/media/audio/net/conversions.h"
#include "chromecast/net/io_buffer_pool.h"

namespace chromecast {
namespace media {

namespace {

enum MessageTypes : int {
  kStreamConfig = 1,
  kInterrupt,
};

}  // namespace

MixerLoopbackConnection::MixerLoopbackConnection(
    std::unique_ptr<mixer_service::MixerSocket> socket)
    : socket_(std::move(socket)) {
  DCHECK(socket_);
  socket_->SetDelegate(this);
}

MixerLoopbackConnection::~MixerLoopbackConnection() = default;

void MixerLoopbackConnection::SetErrorCallback(base::OnceClosure callback) {
  if (pending_error_) {
    pending_error_ = false;
    std::move(callback).Run();
    return;
  }
  error_callback_ = std::move(callback);
}

void MixerLoopbackConnection::SetStreamConfig(SampleFormat sample_format,
                                              int sample_rate,
                                              int num_channels,
                                              int data_size) {
  mixer_service::Generic message;
  mixer_service::StreamConfig* config = message.mutable_stream_config();
  config->set_sample_format(audio_service::ConvertSampleFormat(sample_format));
  config->set_sample_rate(sample_rate);
  config->set_num_channels(num_channels);
  config->set_data_size(data_size);
  socket_->SendProto(kStreamConfig, message);

  sent_stream_config_ = true;
}

void MixerLoopbackConnection::SendAudio(
    scoped_refptr<net::IOBuffer> audio_buffer,
    int data_size_bytes,
    int64_t timestamp) {
  DCHECK(sent_stream_config_);
  if (!socket_->SendAudioBuffer(std::move(audio_buffer), data_size_bytes,
                                timestamp)) {
    SendInterrupt(LoopbackInterruptReason::kSocketOverflow);
  }
}

void MixerLoopbackConnection::SendInterrupt(LoopbackInterruptReason reason) {
  mixer_service::Generic message;
  mixer_service::StreamInterruption* interrupt =
      message.mutable_stream_interruption();
  interrupt->set_reason(
      static_cast<mixer_service::StreamInterruption::InterruptionReason>(
          reason));
  socket_->SendProto(kInterrupt, message);
}

bool MixerLoopbackConnection::HandleMetadata(
    const mixer_service::Generic& message) {
  return true;
}

bool MixerLoopbackConnection::HandleAudioData(char* data,
                                              size_t size,
                                              int64_t timestamp) {
  return true;
}

void MixerLoopbackConnection::OnConnectionError() {
  if (error_callback_) {
    std::move(error_callback_).Run();
    return;
  }
  pending_error_ = true;
}

}  // namespace media
}  // namespace chromecast