blob: 51e87bcbd9d41ec51384d9e53b122c68cbcad519 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_INPUT_CONNECTION_H_
#define CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_INPUT_CONNECTION_H_
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
#include "base/timer/timer.h"
#include "chromecast/media/audio/mixer_service/mixer_socket.h"
#include "chromecast/media/cma/backend/audio_fader.h"
#include "chromecast/media/cma/backend/mixer/mixer_input.h"
#include "chromecast/public/media/media_pipeline_backend.h"
#include "chromecast/public/volume_control.h"
namespace base {
class SequencedTaskRunner;
} // namespace base
namespace media {
class AudioBus;
} // namespace media
namespace net {
class IOBuffer;
} // namespace net
namespace chromecast {
class IOBufferPool;
namespace media {
class StreamMixer;
namespace mixer_service {
class Generic;
class OutputStreamParams;
} // namespace mixer_service
// A mixer source that receives audio data from a mixer service connection and
// buffers/fades it as requested before feeding it to the mixer. Must be created
// on an IO thread. This class manages its own lifetime and should not be
// externally deleted.
class MixerInputConnection : public mixer_service::MixerSocket::Delegate,
public MixerInput::Source,
public AudioFader::Source {
public:
using RenderingDelay = MediaPipelineBackend::AudioDecoder::RenderingDelay;
MixerInputConnection(StreamMixer* mixer,
std::unique_ptr<mixer_service::MixerSocket> socket,
const mixer_service::OutputStreamParams& params);
// Only public to allow task_runner->DeleteSoon() to work.
~MixerInputConnection() override;
private:
friend class MixerServiceReceiver;
enum class State {
kUninitialized, // Not initialized by the mixer yet.
kNormalPlayback, // Normal playback.
kGotEos, // Got the end-of-stream buffer (normal playback).
kSignaledEos, // Sent EOS signal up to delegate.
kRemoved, // The caller has removed this source; finish playing out.
};
// mixer_service::MixerSocket::Delegate implementation:
bool HandleMetadata(const mixer_service::Generic& message) override;
bool HandleAudioData(char* data, int size, int64_t timestamp) override;
bool HandleAudioBuffer(scoped_refptr<net::IOBuffer> buffer,
char* data,
int size,
int64_t timestamp) override;
void OnConnectionError() override;
void OnInactivityTimeout();
void RestartPlaybackAt(int64_t timestamp, int64_t pts);
void SetMediaPlaybackRate(double rate);
void SetPaused(bool paused);
// MixerInput::Source implementation:
int num_channels() override;
int input_samples_per_second() override;
bool primary() override;
const std::string& device_id() override;
AudioContentType content_type() override;
int desired_read_size() override;
int playout_channel() override;
void InitializeAudioPlayback(int read_size,
RenderingDelay initial_rendering_delay) override;
int FillAudioPlaybackFrames(int num_frames,
RenderingDelay rendering_delay,
::media::AudioBus* buffer) override;
void OnAudioPlaybackError(MixerError error) override;
void FinalizeAudioPlayback() override;
// AudioFader::Source implementation:
int FillFaderFrames(int num_frames,
RenderingDelay rendering_delay,
float* const* channels)
EXCLUSIVE_LOCKS_REQUIRED(lock_) override;
void WritePcm(scoped_refptr<net::IOBuffer> data);
RenderingDelay QueueData(scoped_refptr<net::IOBuffer> data)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void PostPcmCompletion();
void PostEos();
void PostError(MixerError error);
void PostAudioReadyForPlayback();
void DropAudio(int64_t frames) EXCLUSIVE_LOCKS_REQUIRED(lock_);
void CheckAndStartPlaybackIfNecessary(int num_frames,
int64_t playback_absolute_timestamp)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
StreamMixer* const mixer_;
std::unique_ptr<mixer_service::MixerSocket> socket_;
const int fill_size_;
const int num_channels_;
const int input_samples_per_second_;
const mixer_service::SampleFormat sample_format_;
const bool primary_;
const std::string device_id_;
const AudioContentType content_type_;
const int playout_channel_;
const scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
const int max_queued_frames_;
// Minimum number of frames buffered before starting to fill data.
int start_threshold_frames_;
scoped_refptr<IOBufferPool> buffer_pool_;
// Only used on the IO thread.
bool audio_ready_for_playback_fired_ = false;
base::OneShotTimer inactivity_timer_;
base::Lock lock_;
State state_ GUARDED_BY(lock_) = State::kUninitialized;
bool paused_ GUARDED_BY(lock_) = false;
bool mixer_error_ GUARDED_BY(lock_) = false;
scoped_refptr<net::IOBuffer> pending_data_ GUARDED_BY(lock_);
base::circular_deque<scoped_refptr<net::IOBuffer>> queue_ GUARDED_BY(lock_);
int queued_frames_ GUARDED_BY(lock_) = 0;
RenderingDelay mixer_rendering_delay_ GUARDED_BY(lock_);
RenderingDelay last_buffer_delay_ GUARDED_BY(lock_);
int extra_delay_frames_ GUARDED_BY(lock_) = 0;
int current_buffer_offset_ GUARDED_BY(lock_) = 0;
AudioFader fader_ GUARDED_BY(lock_);
bool zero_fader_frames_ GUARDED_BY(lock_) = false;
bool started_ GUARDED_BY(lock_) = false;
double playback_rate_ GUARDED_BY(lock_) = 1.0;
bool use_start_timestamp_ GUARDED_BY(lock_) = false;
// The absolute timestamp relative to clock monotonic (raw) at which the
// playback should start. INT64_MIN indicates playback should start ASAP.
// INT64_MAX indicates playback should start at a specified timestamp,
// but we don't know what that timestamp is.
int64_t playback_start_timestamp_ GUARDED_BY(lock_) = INT64_MIN;
// The PTS the playback should start at. We will drop audio pushed to us
// with PTS values below this value. If the audio doesn't have a starting
// PTS, then this value can be INT64_MIN, to play whatever audio is sent
// to us.
int64_t playback_start_pts_ GUARDED_BY(lock_) = INT64_MIN;
int remaining_silence_frames_ GUARDED_BY(lock_) = 0;
base::RepeatingClosure pcm_completion_task_;
base::RepeatingClosure eos_task_;
base::RepeatingClosure ready_for_playback_task_;
base::WeakPtr<MixerInputConnection> weak_this_;
base::WeakPtrFactory<MixerInputConnection> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MixerInputConnection);
};
} // namespace media
} // namespace chromecast
#endif // CHROMECAST_MEDIA_CMA_BACKEND_MIXER_MIXER_INPUT_CONNECTION_H_