#include "content/browser/media/session/media_session_controller.h"
#include "content/browser/media/media_devices_util.h"
#include "content/browser/media/media_web_contents_observer.h"
#include "content/browser/media/session/media_session_impl.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/media_device_id.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "media/base/media_content_type.h"
namespace content {
int MediaSessionController::player_count_ = 0;
MediaSessionController::MediaSessionController(const MediaPlayerId& id,
WebContentsImpl* web_contents)
: id_(id),
web_contents_(web_contents),
media_session_(MediaSessionImpl::Get(web_contents)) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
MediaSessionController::~MediaSessionController() {
media_session_->RemovePlayer(this, player_id_);
}
void MediaSessionController::SetMetadata(
bool has_audio,
bool has_video,
media::MediaContentType media_content_type) {
#if defined(OHOS_MEDIA_POLICY)
media_session_->SetMediaContentType(media_content_type);
#endif
has_audio_ = has_audio;
has_video_ = has_video;
media_content_type_ = media_content_type;
LOG(INFO) << "MediaSessionController mediaContentType is:" << static_cast<uint32_t>(media_content_type_);
AddOrRemovePlayer();
}
bool MediaSessionController::OnPlaybackStarted() {
is_paused_ = false;
is_playback_in_progress_ = true;
#if defined(OHOS_MEDIA_POLICY)
if (media_session_) {
media_session_->SetPlayingState(true);
media_session_->SetPauseByAvsession(false);
}
LOG(INFO) << "MediaSessionController OnPlaybackStarted SetPlayingState true";
#endif
return AddOrRemovePlayer();
}
void MediaSessionController::OnSuspend(int player_id) {
LOG(INFO) << "MediaSessionController::OnSuspend, player_id: " << player_id;
DCHECK_EQ(player_id_, player_id);
web_contents_->media_web_contents_observer()
->GetMediaPlayerRemote(id_)
->RequestPause(true);
}
void MediaSessionController::OnResume(int player_id) {
DCHECK_EQ(player_id_, player_id);
web_contents_->media_web_contents_observer()
->GetMediaPlayerRemote(id_)
->RequestPlay();
}
#if defined(OHOS_MEDIA_POLICY)
void MediaSessionController::OnSetHtmlPlayEnabled(int player_id, bool enabled) {
DCHECK_EQ(player_id_, player_id);
if (!web_contents_)
return;
auto web_contents_observer = web_contents_->media_web_contents_observer();
if (!web_contents_observer)
return;
if(web_contents_observer->IsPlayerIdInMediaPlayerRemotesMap(id_))
web_contents_observer->GetMediaPlayerRemote(id_)->SetHtmlPlayEnabled(enabled);
}
#endif
void MediaSessionController::OnSeekForward(int player_id,
base::TimeDelta seek_time) {
DCHECK_EQ(player_id_, player_id);
web_contents_->media_web_contents_observer()
->GetMediaPlayerRemote(id_)
->RequestSeekForward(seek_time);
}
void MediaSessionController::OnSeekBackward(int player_id,
base::TimeDelta seek_time) {
DCHECK_EQ(player_id_, player_id);
web_contents_->media_web_contents_observer()
->GetMediaPlayerRemote(id_)
->RequestSeekBackward(seek_time);
}
void MediaSessionController::OnSeekTo(int player_id,
base::TimeDelta seek_time) {
DCHECK_EQ(player_id_, player_id);
web_contents_->media_web_contents_observer()
->GetMediaPlayerRemote(id_)
->RequestSeekTo(seek_time);
}
void MediaSessionController::OnSetVolumeMultiplier(int player_id,
double volume_multiplier) {
DCHECK_EQ(player_id_, player_id);
auto* observer = web_contents_->media_web_contents_observer();
if (!observer->IsMediaPlayerRemoteAvailable(id_))
return;
observer->GetMediaPlayerRemote(id_)->SetVolumeMultiplier(volume_multiplier);
}
void MediaSessionController::OnEnterPictureInPicture(int player_id) {
DCHECK_EQ(player_id_, player_id);
web_contents_->media_web_contents_observer()
->GetMediaPlayerRemote(id_)
->RequestEnterPictureInPicture();
}
void MediaSessionController::OnExitPictureInPicture(int player_id) {
DCHECK_EQ(player_id_, player_id);
web_contents_->media_web_contents_observer()
->GetMediaPlayerRemote(id_)
->RequestExitPictureInPicture();
}
void MediaSessionController::OnSetAudioSinkId(
int player_id,
const std::string& raw_device_id) {
DCHECK_EQ(player_id_, player_id);
auto* render_frame_host = RenderFrameHost::FromID(id_.frame_routing_id);
if (!render_frame_host)
return;
auto salt_and_origin = content::GetMediaDeviceSaltAndOrigin(
render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID());
std::string hashed_sink_id = GetHMACForMediaDeviceID(
salt_and_origin.device_id_salt, salt_and_origin.origin, raw_device_id);
static_cast<RenderFrameHostImpl*>(render_frame_host)
->SetAudioOutputDeviceIdForGlobalMediaControls(hashed_sink_id);
web_contents_->media_web_contents_observer()
->GetMediaPlayerRemote(id_)
->SetAudioSinkId(hashed_sink_id);
}
void MediaSessionController::OnSetMute(int player_id, bool mute) {
DCHECK_EQ(player_id_, player_id);
web_contents_->media_web_contents_observer()
->GetMediaPlayerRemote(id_)
->RequestMute(mute);
}
void MediaSessionController::OnRequestMediaRemoting(int player_id) {
DCHECK_EQ(player_id_, player_id);
if (is_paused_) {
web_contents_->media_web_contents_observer()
->GetMediaPlayerRemote(id_)
->RequestPlay();
}
web_contents_->media_web_contents_observer()
->GetMediaPlayerRemote(id_)
->RequestMediaRemoting();
}
RenderFrameHost* MediaSessionController::render_frame_host() const {
return RenderFrameHost::FromID(id_.frame_routing_id);
}
absl::optional<media_session::MediaPosition>
MediaSessionController::GetPosition(int player_id) const {
DCHECK_EQ(player_id_, player_id);
return position_;
}
bool MediaSessionController::IsPictureInPictureAvailable(int player_id) const {
DCHECK_EQ(player_id_, player_id);
return is_picture_in_picture_available_;
}
void MediaSessionController::OnPlaybackPaused(bool reached_end_of_stream) {
is_paused_ = true;
#if defined(OHOS_MEDIA_POLICY)
media_session_->SetPlayingState(false);
LOG(INFO) << "MediaSessionController OnPlaybackStarted SetPlayingState false";
#endif
if (reached_end_of_stream) {
is_playback_in_progress_ = false;
AddOrRemovePlayer();
}
#if defined(OHOS_MEDIA_AVSESSION)
if (media_session_) {
media_session_->SetEndOfMedia(reached_end_of_stream);
}
#endif
if (media_session_->IsActive())
media_session_->OnPlayerPaused(this, player_id_);
}
void MediaSessionController::PictureInPictureStateChanged(
bool is_picture_in_picture) {
AddOrRemovePlayer();
}
void MediaSessionController::WebContentsMutedStateChanged(bool muted) {
AddOrRemovePlayer();
}
#if defined(OHOS_MEDIA_POLICY)
void MediaSessionController::SetHtmlPlayEnabled(bool enabled) {
OnSetHtmlPlayEnabled(player_id_, enabled);
}
#endif
void MediaSessionController::OnMediaPositionStateChanged(
const media_session::MediaPosition& position) {
position_ = position;
media_session_->RebuildAndNotifyMediaPositionChanged();
}
void MediaSessionController::OnMediaMutedStatusChanged(bool mute) {
media_session_->OnMediaMutedStatusChanged(mute);
}
#if defined(OHOS_MEDIA_AVSESSION)
void MediaSessionController::OnEndAVSession(const MediaPlayerId& id,
bool is_hidden) {
if (is_hidden && media_session_) {
media_session_->EndSessionWhenHide();
}
}
#endif
void MediaSessionController::OnPictureInPictureAvailabilityChanged(
bool available) {
is_picture_in_picture_available_ = available;
media_session_->OnPictureInPictureAvailabilityChanged();
}
void MediaSessionController::OnAudioOutputSinkChanged(
const std::string& raw_device_id) {
audio_output_sink_id_ = raw_device_id;
media_session_->OnAudioOutputSinkIdChanged();
}
void MediaSessionController::OnAudioOutputSinkChangingDisabled() {
supports_audio_output_device_switching_ = false;
media_session_->OnAudioOutputSinkChangingDisabled();
}
void MediaSessionController::OnRemotePlaybackMetadataChanged(
media_session::mojom::RemotePlaybackMetadataPtr metadata) {
media_session_->SetRemotePlaybackMetadata(std::move(metadata));
}
bool MediaSessionController::IsMediaSessionNeeded() const {
if (web_contents_->HasPictureInPictureVideo())
return true;
if (!is_playback_in_progress_)
return false;
#if defined(OHOS_MEDIA_AVSESSION)
if (media_content_type_ == media::MediaContentType::Transient) {
LOG(INFO) << __func__<< ", media_content_type_: media::MediaContentType::Transient";
return false;
}
#endif
return has_audio_ && !web_contents_->IsAudioMuted();
}
#if defined(OHOS_MEDIA_POLICY)
void MediaSessionController::SetSessionStateIfNeed(bool isNeedMediaSession)
{
if (!media_session_) {
return;
}
if (media_content_type_ == media::MediaContentType::OneShot) {
LOG(INFO) << "MediaSessionController contentType is oneShot, don't control mediaSession";
return;
}
if (isNeedMediaSession) {
LOG(INFO) << "MediaSessionController media has mediaSession";
media_session_->SetSessionState(MediaSessionImpl::NWebMediaSessionState::NEED);
} else {
LOG(INFO) << "MediaSessionController media is preloading, has no mediaSession";
media_session_->SetSessionState(MediaSessionImpl::NWebMediaSessionState::NONEED);
}
}
#endif
bool MediaSessionController::AddOrRemovePlayer() {
const bool needs_session = IsMediaSessionNeeded();
#if defined(OHOS_MEDIA_POLICY)
SetSessionStateIfNeed(needs_session);
#endif
if (needs_session) {
if (!media_session_->AddPlayer(this, player_id_)) {
OnSuspend(player_id_);
return false;
}
if (is_paused_)
media_session_->OnPlayerPaused(this, player_id_);
return true;
}
media_session_->RemovePlayer(this, player_id_);
return true;
}
bool MediaSessionController::HasAudio(int player_id) const {
DCHECK_EQ(player_id_, player_id);
return has_audio_;
}
bool MediaSessionController::HasVideo(int player_id) const {
DCHECK_EQ(player_id_, player_id);
return has_video_;
}
std::string MediaSessionController::GetAudioOutputSinkId(int player_id) const {
DCHECK_EQ(player_id_, player_id);
return audio_output_sink_id_;
}
bool MediaSessionController::SupportsAudioOutputDeviceSwitching(
int player_id) const {
DCHECK_EQ(player_id_, player_id);
return supports_audio_output_device_switching_;
}
media::MediaContentType MediaSessionController::GetMediaContentType() const {
return media_content_type_;
}
}