#include "media/remoting/renderer_controller.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "media/base/remoting_constants.h"
#include "media/remoting/metrics.h"
#if BUILDFLAG(IS_ANDROID)
#include "media/base/android/media_codec_util.h"
#endif
namespace media {
namespace remoting {
RemotingSinkAudioCapability;
RemotingSinkFeature;
RemotingSinkVideoCapability;
namespace {
constexpr int kPixelsPerSec4k = …;
constexpr int kPixelsPerSec2k = …;
StopTrigger GetStopTrigger(mojom::RemotingStopReason reason) { … }
MediaObserverClient::ReasonToSwitchToLocal GetSwitchReason(
StopTrigger stop_trigger) { … }
}
RendererController::RendererController(
mojo::PendingReceiver<mojom::RemotingSource> source_receiver,
mojo::PendingRemote<mojom::Remoter> remoter)
#if BUILDFLAG(ENABLE_MEDIA_REMOTING_RPC)
: … { … }
RendererController::~RendererController() { … }
void RendererController::OnSinkAvailable(
mojom::RemotingSinkMetadataPtr metadata) { … }
void RendererController::OnSinkGone() { … }
void RendererController::OnStarted() { … }
void RendererController::OnStartFailed(mojom::RemotingStartFailReason reason) { … }
void RendererController::OnStopped(mojom::RemotingStopReason reason) { … }
void RendererController::OnMessageFromSink(
const std::vector<uint8_t>& message) { … }
void RendererController::OnBecameDominantVisibleContent(bool is_dominant) { … }
void RendererController::OnRemotePlaybackDisabled(bool disabled) { … }
void RendererController::OnMediaRemotingRequested() { … }
#if BUILDFLAG(ENABLE_MEDIA_REMOTING_RPC)
openscreen::WeakPtr<openscreen::cast::RpcMessenger>
RendererController::GetRpcMessenger() { … }
#endif
void RendererController::StartDataPipe(uint32_t data_pipe_capacity,
bool audio,
bool video,
DataPipeStartCallback done_callback) { … }
void RendererController::OnMetadataChanged(const PipelineMetadata& metadata) { … }
void RendererController::OnDataSourceInitialized(
const GURL& url_after_redirects) { … }
void RendererController::OnHlsManifestDetected() { … }
void RendererController::UpdateRemotePlaybackAvailabilityMonitoringState() { … }
bool RendererController::IsVideoCodecSupported() const { … }
bool RendererController::IsAudioCodecSupported() const { … }
void RendererController::OnPlaying() { … }
void RendererController::OnPaused() { … }
void RendererController::OnFrozen() { … }
RemotingCompatibility RendererController::GetVideoCompatibility() const { … }
RemotingCompatibility RendererController::GetAudioCompatibility() const { … }
RemotingCompatibility RendererController::GetCompatibility() const { … }
bool RendererController::IsAudioOrVideoSupported() const { … }
void RendererController::UpdateAndMaybeSwitch(StartTrigger start_trigger,
StopTrigger stop_trigger) { … }
void RendererController::OnRendererFatalError(StopTrigger stop_trigger) { … }
void RendererController::SetClient(MediaObserverClient* client) { … }
bool RendererController::HasVideoCapability(
mojom::RemotingSinkVideoCapability capability) const { … }
bool RendererController::HasAudioCapability(
mojom::RemotingSinkAudioCapability capability) const { … }
bool RendererController::HasFeatureCapability(
RemotingSinkFeature capability) const { … }
bool RendererController::SinkSupportsRemoting() const { … }
bool RendererController::ShouldBeRemoting() { … }
void RendererController::MaybeStartCalculatePixelRateTimer() { … }
void RendererController::DoCalculatePixelRate(
int decoded_frame_count_before_delay,
base::TimeTicks delayed_start_time) { … }
PixelRateSupport RendererController::GetPixelRateSupport() const { … }
void RendererController::SendMessageToSink(std::vector<uint8_t> message) { … }
#if BUILDFLAG(IS_ANDROID)
bool RendererController::IsAudioRemotePlaybackSupported() const {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(has_audio());
if (pipeline_metadata_.audio_decoder_config.is_encrypted())
return false;
switch (pipeline_metadata_.audio_decoder_config.codec()) {
case AudioCodec::kAAC:
case AudioCodec::kOpus:
case AudioCodec::kMP3:
case AudioCodec::kPCM:
case AudioCodec::kVorbis:
case AudioCodec::kFLAC:
case AudioCodec::kAMR_NB:
case AudioCodec::kAMR_WB:
case AudioCodec::kPCM_MULAW:
case AudioCodec::kGSM_MS:
case AudioCodec::kPCM_S16BE:
case AudioCodec::kPCM_S24BE:
case AudioCodec::kEAC3:
case AudioCodec::kPCM_ALAW:
case AudioCodec::kALAC:
case AudioCodec::kAC3:
case AudioCodec::kDTS:
case AudioCodec::kDTSXP2:
case AudioCodec::kDTSE:
return true;
default:
return false;
}
}
bool RendererController::IsVideoRemotePlaybackSupported() const {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(has_video());
if (pipeline_metadata_.video_decoder_config.is_encrypted())
return false;
switch (pipeline_metadata_.video_decoder_config.codec()) {
case VideoCodec::kH264:
case VideoCodec::kVP8:
case VideoCodec::kVP9:
case VideoCodec::kHEVC:
return true;
default:
return false;
}
}
bool RendererController::IsRemotePlaybackSupported() const {
return ((has_audio() || has_video()) &&
(!has_video() || IsVideoRemotePlaybackSupported()) &&
(!has_audio() || IsAudioRemotePlaybackSupported()));
}
#endif
}
}