chromium/chromecast/media/audio/cma_audio_output_stream.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_CMA_AUDIO_OUTPUT_STREAM_H_
#define CHROMECAST_MEDIA_AUDIO_CMA_AUDIO_OUTPUT_STREAM_H_

#include <memory>
#include <string>

#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chromecast/media/api/cma_backend.h"
#include "media/audio/audio_io.h"
#include "media/base/audio_parameters.h"

namespace base {
class WaitableEvent;
}  // namespace base

namespace media {
class AudioBus;
}  // namespace media

namespace chromecast {

class TaskRunnerImpl;

namespace media {

class CmaAudioOutput;
class CmaBackendFactory;

class CmaAudioOutputStream : public CmaBackend::Decoder::Delegate {
 public:
  CmaAudioOutputStream(const ::media::AudioParameters& audio_params,
                       base::TimeDelta buffer_duration,
                       const std::string& device_id,
                       CmaBackendFactory* cma_backend_factory);

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

  ~CmaAudioOutputStream() override;

  void SetRunning(bool running);
  void Initialize(const std::string& application_session_id);
  void Start(::media::AudioOutputStream::AudioSourceCallback* source_callback);
  void Stop(base::WaitableEvent* finished);
  void Flush(base::WaitableEvent* finished);
  void Close(base::OnceClosure closure);
  void SetVolume(double volume);

 private:
  enum class CmaBackendState {
    kUninitialized,
    kStopped,
    kPaused,
    kStarted,
    kPendingClose,
  };

  void PushBuffer();

  // CmaBackend::Decoder::Delegate implementation:
  void OnEndOfStream() override {}
  void OnDecoderError() override;
  void OnKeyStatusChanged(const std::string& key_id,
                          CastKeyStatus key_status,
                          uint32_t system_code) override {}
  void OnVideoResolutionChanged(const Size& size) override {}
  void OnPushBufferComplete(BufferStatus status) override;

  const bool is_audio_prefetch_;

  const ::media::AudioParameters audio_params_;
  const std::string device_id_;
  CmaBackendFactory* const cma_backend_factory_;
  std::unique_ptr<CmaAudioOutput> output_;

  base::Lock running_lock_;
  bool running_ = true;
  CmaBackendState cma_backend_state_ = CmaBackendState::kUninitialized;
  const base::TimeDelta buffer_duration_;
  std::unique_ptr<::media::AudioBus> audio_bus_;
  base::OneShotTimer push_timer_;
  bool push_in_progress_ = false;
  bool encountered_error_ = false;
  base::TimeTicks next_push_time_;
  base::TimeTicks last_push_complete_time_;
  base::TimeDelta last_rendering_delay_;
  base::TimeDelta render_buffer_size_estimate_;
  ::media::AudioOutputStream::AudioSourceCallback* source_callback_ = nullptr;

  THREAD_CHECKER(media_thread_checker_);
};

}  // namespace media
}  // namespace chromecast

#endif  // CHROMECAST_MEDIA_AUDIO_CMA_AUDIO_OUTPUT_STREAM_H_