| // Copyright 2021 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_CAST_AUDIO_RENDERER_H_ |
| #define CHROMECAST_MEDIA_AUDIO_CAST_AUDIO_RENDERER_H_ |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "base/memory/scoped_refptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/sequence_checker.h" |
| #include "base/threading/sequence_bound.h" |
| #include "base/time/time.h" |
| #include "base/timer/timer.h" |
| #include "chromecast/common/mojom/audio_socket.mojom.h" |
| #include "chromecast/media/audio/audio_output_service/output_stream_connection.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/base/waiting.h" |
| #include "media/mojo/mojom/cast_application_media_info_manager.mojom.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| |
| namespace base { |
| class SequencedTaskRunner; |
| } // namespace base |
| |
| namespace blink { |
| class BrowserInterfaceBrokerProxy; |
| } // namespace blink |
| |
| namespace media { |
| class AudioDecoderConfig; |
| class DecoderBuffer; |
| class DecryptingDemuxerStream; |
| class MediaLog; |
| } // namespace media |
| |
| namespace chromecast { |
| namespace media { |
| |
| // Cast implementation of ::media::AudioRenderer which sends decrypted audio |
| // buffers to the audio output service for decoding and rendering. |
| // Threading model: after constructed, ::media::AudioRenderer methods will be |
| // called on the main thread. ::media::TimeSource methods will be called from |
| // multiple threads (so lock is required for timeline related fields/methods). |
| // audio_output_service::OutputStreamConnection::Delegate methods will be called |
| // from an IO thread. |
| class CastAudioRenderer |
| : public ::media::AudioRenderer, |
| public ::media::TimeSource, |
| public audio_output_service::OutputStreamConnection::Delegate { |
| public: |
| CastAudioRenderer(scoped_refptr<base::SequencedTaskRunner> media_task_runner, |
| ::media::MediaLog* media_log, |
| blink::BrowserInterfaceBrokerProxy* interface_broker); |
| CastAudioRenderer(const CastAudioRenderer&) = delete; |
| CastAudioRenderer& operator=(const CastAudioRenderer&) = delete; |
| ~CastAudioRenderer() override; |
| |
| private: |
| enum class PlaybackState { |
| kStopped, |
| |
| // We've called Start(), but haven't received updated state. |start_time_| |
| // should not be used yet. |
| kStarting, |
| |
| // Playback is active. When the stream reaches EOS it stays in the kPlaying |
| // state. |
| kPlaying, |
| }; |
| |
| // ::media::AudioRenderer implementation: |
| void Initialize(::media::DemuxerStream* stream, |
| ::media::CdmContext* cdm_context, |
| ::media::RendererClient* client, |
| ::media::PipelineStatusCallback init_cb) override; |
| ::media::TimeSource* GetTimeSource() override; |
| void Flush(base::OnceClosure callback) override; |
| void StartPlaying() override; |
| void SetVolume(float volume) override; |
| void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) override; |
| void SetPreservesPitch(bool preserves_pitch) override; |
| void SetWasPlayedWithUserActivation( |
| bool was_played_with_user_activation) override; |
| |
| // ::media::TimeSource implementation: |
| 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; |
| |
| // audio_output_service::OutputStreamConnection::Delegate implementation: |
| void OnBackendInitialized( |
| const audio_output_service::BackendInitializationStatus& status) override; |
| void OnNextBuffer(int64_t media_timestamp_microseconds, |
| int64_t reference_timestamp_microseconds, |
| int64_t delay_microseconds, |
| int64_t delay_timestamp_microseconds) override; |
| |
| void ScheduleFetchNextBuffer(); |
| void FetchNextBuffer(); |
| void OnEndOfStream(); |
| |
| // Returns current PlaybackState. |
| PlaybackState GetPlaybackState() EXCLUSIVE_LOCKS_REQUIRED(timeline_lock_); |
| |
| // Helper function used with DCHECKs to hold |timeline_lock_|. |
| bool CurrentPlaybackStateEquals(PlaybackState playback_state); |
| |
| // Used to update |state_|. |
| void SetPlaybackState(PlaybackState state) |
| EXCLUSIVE_LOCKS_REQUIRED(timeline_lock_); |
| |
| // Returns true if media clock is ticking and the rate is above 0.0. |
| bool IsTimeMoving() EXCLUSIVE_LOCKS_REQUIRED(timeline_lock_); |
| |
| // Updates TimelineFunction parameters after StopTicking() or |
| // SetPlaybackRate(0.0). Normally these parameters are provided by |
| // the audio output service, but this happens asynchronously and we need to |
| // make sure that StopTicking() and SetPlaybackRate(0.0) stop the media clock |
| // synchronously. Must be called before updating the |state_|. |
| void UpdateTimelineOnStop() EXCLUSIVE_LOCKS_REQUIRED(timeline_lock_); |
| |
| void UpdateAudioDecoderConfig(const ::media::AudioDecoderConfig& config); |
| |
| base::TimeDelta CurrentMediaTimeLocked() |
| EXCLUSIVE_LOCKS_REQUIRED(timeline_lock_); |
| |
| // Updates buffer state and notifies the |client_| if necessary. |
| void SetBufferState(::media::BufferingState buffer_state); |
| |
| void OnNewBuffer(::media::DemuxerStream::Status read_status, |
| scoped_refptr<::media::DecoderBuffer> buffer); |
| void OnError(::media::PipelineStatus pipeline_status); |
| void OnDecryptingDemuxerInitialized(::media::PipelineStatus pipeline_status); |
| void OnWaiting(::media::WaitingReason reason); |
| void OnApplicationMediaInfoReceived( |
| ::media::mojom::CastApplicationMediaInfoPtr application_media_info); |
| void FlushInternal(); |
| |
| const scoped_refptr<base::SequencedTaskRunner> media_task_runner_; |
| ::media::MediaLog* const media_log_; |
| |
| scoped_refptr<base::SequencedTaskRunner> main_task_runner_; |
| ::media::DemuxerStream* demuxer_stream_ = nullptr; |
| std::unique_ptr<::media::DecryptingDemuxerStream> decrypting_stream_; |
| ::media::RendererClient* renderer_client_ = nullptr; |
| base::SequenceBound<audio_output_service::OutputStreamConnection> |
| output_connection_; |
| |
| bool is_pending_demuxer_read_ = false; |
| ::media::PipelineStatusCallback init_cb_; |
| base::OnceClosure flush_cb_; |
| |
| float volume_ = 1.0f; |
| |
| ::media::BufferingState buffer_state_ = ::media::BUFFERING_HAVE_NOTHING; |
| |
| base::TimeDelta last_pushed_timestamp_ = base::TimeDelta::Min(); |
| base::OneShotTimer read_timer_; |
| |
| // Indicates that StartPlaying() has been called. Note that playback doesn't |
| // start until StartTicking() is called. |
| bool renderer_started_ = false; |
| |
| // Indicates that StartTicking() has been called. |
| bool ticking_ = false; |
| |
| bool is_at_end_of_stream_ = false; |
| |
| // TimeSource interface is not single-threaded. The lock is used to guard |
| // fields that are accessed in the TimeSource implementation. |
| base::Lock timeline_lock_; |
| |
| float playback_rate_ GUARDED_BY(timeline_lock_) = 0.0f; |
| |
| // Should be changed by calling SetPlaybackState() on the main thread. |
| PlaybackState state_ GUARDED_BY(timeline_lock_) = PlaybackState::kStopped; |
| |
| base::TimeTicks reference_time_ GUARDED_BY(timeline_lock_); |
| base::TimeDelta media_pos_ GUARDED_BY(timeline_lock_); |
| |
| // TODO(b/173250111): update these values based on whether the media session |
| // is multiroom. |
| base::TimeDelta min_lead_time_ = base::Milliseconds(100); |
| base::TimeDelta max_lead_time_ = base::Milliseconds(500); |
| |
| mojo::PendingRemote<::media::mojom::CastApplicationMediaInfoManager> |
| application_media_info_manager_pending_remote_; |
| mojo::Remote<::media::mojom::CastApplicationMediaInfoManager> |
| application_media_info_manager_remote_; |
| mojo::PendingRemote<mojom::AudioSocketBroker> |
| audio_socket_broker_pending_remote_; |
| |
| SEQUENCE_CHECKER(sequence_checker_); |
| |
| base::WeakPtrFactory<CastAudioRenderer> weak_factory_{this}; |
| }; |
| |
| } // namespace media |
| } // namespace chromecast |
| |
| #endif // CHROMECAST_MEDIA_AUDIO_CAST_AUDIO_RENDERER_H_ |