#ifndef FUCHSIA_WEB_WEBENGINE_RENDERER_WEB_ENGINE_AUDIO_RENDERER_H_
#define FUCHSIA_WEB_WEBENGINE_RENDERER_WEB_ENGINE_AUDIO_RENDERER_H_
#include <fuchsia/media/cpp/fidl.h>
#include <list>
#include <memory>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "fuchsia_web/webengine/web_engine_export.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/common/sysmem_buffer_stream.h"
#include "media/fuchsia/common/sysmem_client.h"
#include "media/fuchsia/common/vmo_buffer.h"
namespace media {
class MediaLog;
}
class WEB_ENGINE_EXPORT WebEngineAudioRenderer final
: public media::AudioRenderer,
public media::TimeSource,
public media::SysmemBufferStream::Sink {
public:
WebEngineAudioRenderer(media::MediaLog* media_log,
fidl::InterfaceHandle<fuchsia::media::AudioConsumer>
audio_consumer_handle);
~WebEngineAudioRenderer() override;
void Initialize(media::DemuxerStream* stream,
media::CdmContext* cdm_context,
media::RendererClient* client,
media::PipelineStatusCallback init_cb) override;
TimeSource* GetTimeSource() override;
void Flush(base::OnceClosure callback) override;
void StartPlaying() override;
void SetVolume(float volume) override;
void SetLatencyHint(std::optional<base::TimeDelta> latency_hint) override;
void SetPreservesPitch(bool preserves_pitch) override;
void SetWasPlayedWithUserActivationAndHighMediaEngagement(
bool was_played_with_user_activation_and_high_media_engagement) override;
void StartTicking() override;
void StopTicking() override;
void SetPlaybackRate(double playback_rate) override;
void SetMediaTime(base::TimeDelta time) override;
base::TimeDelta CurrentMediaTime() override;
bool GetWallClockTimes(
const std::vector<base::TimeDelta>& media_timestamps,
std::vector<base::TimeTicks>* wall_clock_times) override;
private:
enum class PlaybackState {
kStopped,
kStartPending,
kStarting,
kPlaying,
kPaused,
};
void StartAudioConsumer();
PlaybackState GetPlaybackState() NO_THREAD_SAFETY_ANALYSIS;
void SetPlaybackState(PlaybackState state)
EXCLUSIVE_LOCKS_REQUIRED(timeline_lock_);
void OnError(media::PipelineStatus Status);
void UpdateVolume();
void InitializeStream();
void OnBuffersAcquired(
std::vector<media::VmoBuffer> buffers,
const fuchsia::sysmem2::SingleBufferSettings& buffer_settings);
void InitializeStreamSink();
void UpdatePlaybackRate();
void RequestAudioConsumerStatus();
void OnAudioConsumerStatusChanged(fuchsia::media::AudioConsumerStatus status);
void ScheduleBufferTimers();
void ScheduleReadDemuxerStream(bool is_time_moving,
base::TimeTicks end_of_buffer_time);
void ReadDemuxerStream();
void OnDemuxerStreamReadDone(
media::DemuxerStream::Status status,
media::DemuxerStream::DecoderBufferVector buffers);
void ScheduleOutOfBufferTimer(bool is_time_moving,
base::TimeTicks end_of_buffer_time);
void SendInputPacket(media::StreamProcessorHelper::IoPacket packet);
void OnStreamSendDone(
std::unique_ptr<media::StreamProcessorHelper::IoPacket> packet);
void SetBufferState(media::BufferingState buffer_state);
void FlushInternal();
void OnEndOfStream();
bool IsTimeMoving() EXCLUSIVE_LOCKS_REQUIRED(timeline_lock_);
base::TimeDelta CurrentMediaTimeLocked()
EXCLUSIVE_LOCKS_REQUIRED(timeline_lock_);
void OnSysmemBufferStreamBufferCollectionToken(
fuchsia::sysmem2::BufferCollectionTokenPtr token) override;
void OnSysmemBufferStreamOutputPacket(
media::StreamProcessorHelper::IoPacket packet) override;
void OnSysmemBufferStreamEndOfStream() override;
void OnSysmemBufferStreamError() override;
void OnSysmemBufferStreamNoKey() override;
fidl::InterfaceHandle<fuchsia::media::AudioConsumer> audio_consumer_handle_;
fuchsia::media::AudioConsumerPtr audio_consumer_;
fuchsia::media::StreamSinkPtr stream_sink_;
fuchsia::media::audio::VolumeControlPtr volume_control_;
float volume_ = 1.0;
double playback_rate_ = 1.0;
raw_ptr<media::CdmContext> cdm_context_ = nullptr;
raw_ptr<media::DemuxerStream> demuxer_stream_ = nullptr;
bool is_demuxer_read_pending_ = false;
bool drop_next_demuxer_read_result_ = false;
raw_ptr<media::RendererClient> client_ = nullptr;
media::PipelineStatusCallback init_cb_;
bool renderer_started_ = false;
media::BufferingState buffer_state_ = media::BUFFERING_HAVE_NOTHING;
base::TimeDelta last_packet_timestamp_ = base::TimeDelta::Min();
base::DeadlineTimer read_timer_;
base::DeadlineTimer out_of_buffer_timer_;
media::SysmemAllocatorClient sysmem_allocator_{"WebEngineAudioRenderer"};
std::unique_ptr<media::SysmemCollectionClient> input_buffer_collection_;
std::unique_ptr<media::SysmemBufferStream> sysmem_buffer_stream_;
std::vector<media::VmoBuffer> input_buffers_;
std::list<media::StreamProcessorHelper::IoPacket> delayed_packets_;
bool has_delayed_end_of_stream_ = false;
base::TimeDelta min_lead_time_ = base::Milliseconds(100);
base::TimeDelta max_lead_time_ = base::Milliseconds(500);
bool is_at_end_of_stream_ = false;
base::Lock timeline_lock_;
PlaybackState state_ GUARDED_BY(timeline_lock_) = PlaybackState::kStopped;
base::TimeTicks reference_time_ GUARDED_BY(timeline_lock_);
base::TimeDelta media_pos_ GUARDED_BY(timeline_lock_);
int32_t media_delta_ GUARDED_BY(timeline_lock_) = 0;
int32_t reference_delta_ GUARDED_BY(timeline_lock_) = 1;
THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<WebEngineAudioRenderer> weak_factory_{this};
};
#endif