blob: e8791bdbdd12f84c01115bedd7d73cea961831fd [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 MEDIA_FUCHSIA_AUDIO_FUCHSIA_AUDIO_RENDERER_H_
#define MEDIA_FUCHSIA_AUDIO_FUCHSIA_AUDIO_RENDERER_H_
#include <fuchsia/media/cpp/fidl.h>
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "media/base/audio_renderer.h"
#include "media/base/buffering_state.h"
#include "media/base/demuxer_stream.h"
#include "media/base/time_source.h"
#include "media/fuchsia/mojom/fuchsia_audio_consumer_provider.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace media {
class DecryptingDemuxerStream;
class MediaLog;
// AudioRenderer implementation that output audio to AudioConsumer interface on
// Fuchsia. Unlike the default AudioRendererImpl it doesn't decode audio and
// sends encoded stream directly to AudioConsumer provided by the platform.
class FuchsiaAudioRenderer : public AudioRenderer, public TimeSource {
public:
FuchsiaAudioRenderer(
MediaLog* media_log,
mojo::PendingRemote<media::mojom::FuchsiaAudioConsumerProvider>
audio_consumer_provider);
~FuchsiaAudioRenderer() final;
// AudioRenderer implementation.
void Initialize(DemuxerStream* stream,
CdmContext* cdm_context,
RendererClient* client,
const PipelineStatusCB& init_cb) final;
TimeSource* GetTimeSource() final;
void Flush(base::OnceClosure callback) final;
void StartPlaying() final;
void SetVolume(float volume) final;
// TimeSource implementation.
void StartTicking() final;
void StopTicking() final;
void SetPlaybackRate(double playback_rate) final;
void SetMediaTime(base::TimeDelta time) final;
base::TimeDelta CurrentMediaTime() final;
bool GetWallClockTimes(const std::vector<base::TimeDelta>& media_timestamps,
std::vector<base::TimeTicks>* wall_clock_times) final;
private:
enum class PlaybackState {
kStopped,
// We've called Start(), but haven't received updated state. |start_time_|
// should not be used yet.
kStarting,
kPlaying,
// We've reached end of stream from the demuxer,
kEndOfStream,
};
// Struct used to store state of an input buffer shared with the
// |stream_sink_|.
struct StreamSinkBuffer {
zx::vmo vmo;
bool is_used = false;
};
// Resets AudioConsumer and reports error to the |client_|.
void OnError(PipelineStatus Status);
// Callback for DecryptingDemuxerStream::Initialize().
void OnDecryptorInitialized(PipelineStatus status);
// Helpers to receive AudioConsumerStatus from the |audio_consumer_|.
void RequestAudioConsumerStatus();
void OnAudioConsumerStatusChanged(fuchsia::media::AudioConsumerStatus status);
// Helpers to pump data from |demuxer_stream_| to |stream_sink_|.
void ScheduleReadDemuxerStream();
void ReadDemuxerStream();
void OnDemuxerStreamReadDone(DemuxerStream::Status status,
scoped_refptr<DecoderBuffer> buffer);
// Result handler for StreamSink::SendPacket().
void OnStreamSendDone(size_t buffer_index);
// Updates buffer state and notifies the |client_| if necessary.
void SetBufferState(BufferingState buffer_state);
// Discards all pending packets.
void FlushInternal();
// End-of-stream event handler for |audio_consumer_|.
void OnEndOfStream();
// Calculates media position based on the TimelineFunction returned from
// AudioConsumer.
base::TimeDelta CurrentMediaTimeLocked()
EXCLUSIVE_LOCKS_REQUIRED(state_lock_);
MediaLog* const media_log_;
// Handle for |audio_consumer_|. It's stored here until Initialize() is
// called.
fidl::InterfaceHandle<fuchsia::media::AudioConsumer> audio_consumer_handle_;
fuchsia::media::AudioConsumerPtr audio_consumer_;
fuchsia::media::StreamSinkPtr stream_sink_;
fuchsia::media::audio::VolumeControlPtr volume_control_;
DemuxerStream* demuxer_stream_ = nullptr;
RendererClient* client_ = nullptr;
// Initialize() completion callback.
PipelineStatusCB init_cb_;
std::unique_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream_;
BufferingState buffer_state_ = BUFFERING_HAVE_NOTHING;
base::TimeDelta last_packet_timestamp_ = base::TimeDelta::Min();
base::OneShotTimer read_timer_;
std::vector<StreamSinkBuffer> stream_sink_buffers_;
size_t num_pending_packets_ = 0u;
// Lead time range requested by the |audio_consumer_|. Initialized to 0 until
// the initial AudioConsumerStatus is received.
base::TimeDelta min_lead_time_;
base::TimeDelta max_lead_time_;
// TimeSource interface is not single-threaded. It's used to guard fields
// that area accessed in the TimeSource implementation.
base::Lock state_lock_;
PlaybackState state_ GUARDED_BY(state_lock_) = PlaybackState::kStopped;
// Values from TimelineFunction returned by AudioConsumer.
base::TimeTicks reference_time_ GUARDED_BY(state_lock_);
base::TimeDelta media_pos_ GUARDED_BY(state_lock_);
int32_t media_delta_ GUARDED_BY(state_lock_) = 1;
int32_t reference_delta_ GUARDED_BY(state_lock_) = 1;
THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<FuchsiaAudioRenderer> weak_factory_{this};
};
} // namespace media
#endif // MEDIA_FUCHSIA_AUDIO_FUCHSIA_AUDIO_RENDERER_H_