#ifndef MEDIA_REMOTING_RENDERER_CONTROLLER_H_
#define MEDIA_REMOTING_RENDERER_CONTROLLER_H_
#include <memory>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "media/base/media_observer.h"
#include "media/media_buildflags.h"
#include "media/mojo/mojom/remoting.mojom.h"
#include "media/mojo/mojom/remoting_common.mojom.h"
#include "media/remoting/metrics.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#if BUILDFLAG(ENABLE_MEDIA_REMOTING_RPC)
#include "third_party/openscreen/src/cast/streaming/public/rpc_messenger.h"
#include "third_party/openscreen/src/util/weak_ptr.h"
#endif
namespace base {
class TickClock;
}
namespace media {
namespace remoting {
class RendererController final : public mojom::RemotingSource,
public MediaObserver {
public:
RendererController(
mojo::PendingReceiver<mojom::RemotingSource> source_receiver,
mojo::PendingRemote<mojom::Remoter> remoter);
RendererController(const RendererController&) = delete;
RendererController& operator=(const RendererController&) = delete;
~RendererController() override;
void OnSinkAvailable(mojom::RemotingSinkMetadataPtr metadata) override;
void OnSinkGone() override;
void OnStarted() override;
void OnStartFailed(mojom::RemotingStartFailReason reason) override;
void OnMessageFromSink(const std::vector<uint8_t>& message) override;
void OnStopped(mojom::RemotingStopReason reason) override;
void OnBecameDominantVisibleContent(bool is_dominant) override;
void OnMetadataChanged(const PipelineMetadata& metadata) override;
void OnRemotePlaybackDisabled(bool disabled) override;
void OnMediaRemotingRequested() override;
void OnPlaying() override;
void OnPaused() override;
void OnFrozen() override;
void OnDataSourceInitialized(const GURL& url_after_redirects) override;
void OnHlsManifestDetected() override;
void SetClient(MediaObserverClient* client) override;
base::WeakPtr<RendererController> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
bool remote_rendering_started() const {
DCHECK(thread_checker_.CalledOnValidThread());
return remote_rendering_started_;
}
using DataPipeStartCallback = base::OnceCallback<void(
mojo::PendingRemote<mojom::RemotingDataStreamSender> audio,
mojo::PendingRemote<mojom::RemotingDataStreamSender> video,
mojo::ScopedDataPipeProducerHandle audio_handle,
mojo::ScopedDataPipeProducerHandle video_handle)>;
void StartDataPipe(uint32_t data_pipe_capacity,
bool audio,
bool video,
DataPipeStartCallback done_callback);
#if BUILDFLAG(ENABLE_MEDIA_REMOTING_RPC)
openscreen::WeakPtr<openscreen::cast::RpcMessenger> GetRpcMessenger();
#endif
void OnRendererFatalError(StopTrigger stop_trigger);
private:
friend class RendererControllerTest;
bool has_audio() const {
return pipeline_metadata_.has_audio &&
pipeline_metadata_.audio_decoder_config.IsValidConfig();
}
bool has_video() const {
return pipeline_metadata_.has_video &&
pipeline_metadata_.video_decoder_config.IsValidConfig();
}
void UpdateFromSessionState(StartTrigger start_trigger,
StopTrigger stop_trigger);
bool IsVideoCodecSupported() const;
bool IsAudioCodecSupported() const;
bool IsAudioOrVideoSupported() const;
RemotingCompatibility GetVideoCompatibility() const;
RemotingCompatibility GetAudioCompatibility() const;
RemotingCompatibility GetCompatibility() const;
void UpdateAndMaybeSwitch(StartTrigger start_trigger,
StopTrigger stop_trigger);
void UpdateRemotePlaybackAvailabilityMonitoringState();
bool HasVideoCapability(mojom::RemotingSinkVideoCapability capability) const;
bool HasAudioCapability(mojom::RemotingSinkAudioCapability capability) const;
bool HasFeatureCapability(mojom::RemotingSinkFeature capability) const;
bool SinkSupportsRemoting() const;
bool ShouldBeRemoting();
void MaybeStartCalculatePixelRateTimer();
void DoCalculatePixelRate(int decoded_frame_count_before_delay,
base::TimeTicks delayed_start_time);
PixelRateSupport GetPixelRateSupport() const;
void SendMessageToSink(std::vector<uint8_t> message);
#if BUILDFLAG(IS_ANDROID)
bool IsAudioRemotePlaybackSupported() const;
bool IsVideoRemotePlaybackSupported() const;
bool IsRemotePlaybackSupported() const;
#endif
#if BUILDFLAG(ENABLE_MEDIA_REMOTING_RPC)
openscreen::cast::RpcMessenger rpc_messenger_;
#endif
const mojo::Receiver<mojom::RemotingSource> receiver_;
const mojo::Remote<mojom::Remoter> remoter_;
mojom::RemotingSinkMetadataPtr sink_metadata_;
bool remote_rendering_started_ = false;
bool is_remote_playback_disabled_ = true;
bool is_dominant_content_ = false;
bool is_paused_ = true;
bool encountered_renderer_fatal_error_ = false;
base::ThreadChecker thread_checker_;
PipelineMetadata pipeline_metadata_;
GURL url_after_redirects_;
bool is_hls_ = false;
bool is_media_remoting_requested_ = false;
SessionMetricsRecorder metrics_recorder_;
raw_ptr<MediaObserverClient> client_ = nullptr;
base::OneShotTimer pixel_rate_timer_;
double pixels_per_second_ = 0;
raw_ptr<const base::TickClock> clock_;
base::WeakPtrFactory<RendererController> weak_factory_{this};
};
}
}
#endif