chromium/chromecast/media/common/audio_decoder_wrapper.cc

// Copyright 2017 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/common/audio_decoder_wrapper.h"

#include <algorithm>
#include <utility>

#include "base/logging.h"
#include "chromecast/media/api/decoder_buffer_base.h"
#include "chromecast/media/common/media_pipeline_backend_manager.h"
#include "chromecast/public/media/cast_decoder_buffer.h"

namespace chromecast {
namespace media {

namespace {

// This revoked AudioDecoder would behave as one with buffer filled up and
// doesn't advance |statistics| and doesn't change RenderingDelay.
class RevokedAudioDecoderWrapper : public DestructableAudioDecoder {
 public:
  RevokedAudioDecoderWrapper(RenderingDelay rendering_delay,
                             Statistics statistics,
                             AudioTrackTimestamp audio_track_timestamp,
                             int start_threshold_in_frames,
                             bool requires_decryption)
      : rendering_delay_(rendering_delay),
        statistics_(statistics),
        audio_track_timestamp_(audio_track_timestamp),
        start_threshold_in_frames_(start_threshold_in_frames),
        requires_decryption_(requires_decryption) {}

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

  ~RevokedAudioDecoderWrapper() override = default;

 private:
  // DestructableAudioDecoder implementation:
  void OnInitialized() override {}
  void SetDelegate(Delegate* delegate) override {}
  BufferStatus PushBuffer(scoped_refptr<DecoderBufferBase> buffer) override {
    return MediaPipelineBackend::kBufferPending;
  }
  bool SetConfig(const AudioConfig& config) override { return true; }
  bool SetVolume(float multiplier) override { return true; }
  RenderingDelay GetRenderingDelay() override { return rendering_delay_; }
  void GetStatistics(Statistics* statistics) override {
    *statistics = statistics_;
  }
  AudioTrackTimestamp GetAudioTrackTimestamp() override {
    return audio_track_timestamp_;
  }
  int GetStartThresholdInFrames() override {
    return start_threshold_in_frames_;
  }
  bool RequiresDecryption() override { return requires_decryption_; }

  const RenderingDelay rendering_delay_;
  const Statistics statistics_;
  const AudioTrackTimestamp audio_track_timestamp_;
  const int start_threshold_in_frames_;
  const bool requires_decryption_;
};

}  // namespace

ActiveAudioDecoderWrapper::ActiveAudioDecoderWrapper(
    MediaPipelineBackend::AudioDecoder* backend_decoder,
    AudioContentType type,
    MediaPipelineBackendManager::BufferDelegate* buffer_delegate)
    : decoder_(backend_decoder),
      content_type_(type),
      buffer_delegate_(buffer_delegate),
      initialized_(false),
      delegate_active_(false),
      stream_volume_multiplier_(1.0f) {
  if (buffer_delegate_) {
    buffer_delegate_->OnStreamStarted();
  }
}

ActiveAudioDecoderWrapper::~ActiveAudioDecoderWrapper() {
  if (buffer_delegate_) {
    buffer_delegate_->OnStreamStopped();
  }
}

void ActiveAudioDecoderWrapper::OnInitialized() {
  initialized_ = true;
  if (!delegate_active_) {
    decoder_.SetVolume(stream_volume_multiplier_);
  }
}

void ActiveAudioDecoderWrapper::SetDelegate(Delegate* delegate) {
  decoder_.SetDelegate(delegate);
}

CmaBackend::BufferStatus ActiveAudioDecoderWrapper::PushBuffer(
    scoped_refptr<DecoderBufferBase> buffer) {
  if (buffer_delegate_ && buffer_delegate_->IsActive()) {
    // Mute the decoder, we are sending audio to delegate.
    if (!delegate_active_) {
      delegate_active_ = true;
      decoder_.SetVolume(0.0);
    }
    buffer_delegate_->OnPushBuffer(buffer.get());
  } else {
    // Restore original volume.
    if (delegate_active_) {
      delegate_active_ = false;
      if (!decoder_.SetVolume(stream_volume_multiplier_)) {
        LOG(ERROR) << "SetVolume failed";
      }
    }
  }

  // Retain the buffer. Backend expects pipeline to hold the buffer until
  // Decoder::Delegate::OnBufferComplete is called.
  // TODO: Release the buffer at a proper time.
  pushed_buffer_ = std::move(buffer);
  return decoder_.PushBuffer(pushed_buffer_.get());
}

bool ActiveAudioDecoderWrapper::SetConfig(const AudioConfig& config) {
  if (buffer_delegate_) {
    buffer_delegate_->OnSetConfig(config);
  }
  return decoder_.SetConfig(config);
}

bool ActiveAudioDecoderWrapper::SetVolume(float multiplier) {
  stream_volume_multiplier_ = std::max(0.0f, multiplier);
  if (buffer_delegate_) {
    buffer_delegate_->OnSetVolume(stream_volume_multiplier_);
  }

  if (delegate_active_ || !initialized_) {
    return true;
  }
  return decoder_.SetVolume(stream_volume_multiplier_);
}

ActiveAudioDecoderWrapper::RenderingDelay
ActiveAudioDecoderWrapper::GetRenderingDelay() {
  return decoder_.GetRenderingDelay();
}

void ActiveAudioDecoderWrapper::GetStatistics(Statistics* statistics) {
  decoder_.GetStatistics(statistics);
}

ActiveAudioDecoderWrapper::AudioTrackTimestamp
ActiveAudioDecoderWrapper::GetAudioTrackTimestamp() {
  return decoder_.GetAudioTrackTimestamp();
}

int ActiveAudioDecoderWrapper::GetStartThresholdInFrames() {
  return decoder_.GetStartThresholdInFrames();
}

bool ActiveAudioDecoderWrapper::RequiresDecryption() {
  return (MediaPipelineBackend::AudioDecoder::RequiresDecryption &&
          MediaPipelineBackend::AudioDecoder::RequiresDecryption()) ||
         decoder_.IsUsingSoftwareDecoder();
}

AudioDecoderWrapper::AudioDecoderWrapper(
    MediaPipelineBackend::AudioDecoder* backend_decoder,
    AudioContentType type,
    MediaPipelineBackendManager::BufferDelegate* buffer_delegate)
    : decoder_revoked_(false) {
  audio_decoder_ = std::make_unique<ActiveAudioDecoderWrapper>(
      backend_decoder, type, buffer_delegate);
}

AudioDecoderWrapper::AudioDecoderWrapper(AudioContentType type)
    : decoder_revoked_(true) {
  audio_decoder_ = std::make_unique<RevokedAudioDecoderWrapper>(
      RenderingDelay(), Statistics(), AudioTrackTimestamp(),
      0 /* start_threshold_in_frames */, false);
}

AudioDecoderWrapper::~AudioDecoderWrapper() = default;

void AudioDecoderWrapper::OnInitialized() {
  audio_decoder_->OnInitialized();
}

void AudioDecoderWrapper::Revoke() {
  if (!decoder_revoked_) {
    decoder_revoked_ = true;
    // Get some current values from audio_decoder_(ActiveAudioDecoderWrapper),
    // then replace the audio_decoder_ with a revoked one.
    Statistics statistics;
    audio_decoder_->GetStatistics(&statistics);
    audio_decoder_ = std::make_unique<RevokedAudioDecoderWrapper>(
        audio_decoder_->GetRenderingDelay(), statistics,
        audio_decoder_->GetAudioTrackTimestamp(),
        audio_decoder_->GetStartThresholdInFrames(),
        audio_decoder_->RequiresDecryption());
  }
}

void AudioDecoderWrapper::SetDelegate(Delegate* delegate) {
  audio_decoder_->SetDelegate(delegate);
}

AudioDecoderWrapper::BufferStatus AudioDecoderWrapper::PushBuffer(
    scoped_refptr<DecoderBufferBase> buffer) {
  return audio_decoder_->PushBuffer(buffer);
}

bool AudioDecoderWrapper::SetConfig(const AudioConfig& config) {
  return audio_decoder_->SetConfig(config);
}

bool AudioDecoderWrapper::SetVolume(float multiplier) {
  return audio_decoder_->SetVolume(multiplier);
}

AudioDecoderWrapper::RenderingDelay AudioDecoderWrapper::GetRenderingDelay() {
  return audio_decoder_->GetRenderingDelay();
}

void AudioDecoderWrapper::GetStatistics(Statistics* statistics) {
  audio_decoder_->GetStatistics(statistics);
}

AudioDecoderWrapper::AudioTrackTimestamp
AudioDecoderWrapper::GetAudioTrackTimestamp() {
  return audio_decoder_->GetAudioTrackTimestamp();
}

int AudioDecoderWrapper::GetStartThresholdInFrames() {
  return audio_decoder_->GetStartThresholdInFrames();
}

bool AudioDecoderWrapper::RequiresDecryption() {
  return audio_decoder_->RequiresDecryption();
}

}  // namespace media
}  // namespace chromecast