| Index: content/browser/media/session/media_session_impl.cc
|
| diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
|
| index 1b5e706c47a32b0167e2306d9c7b7dc3cd5b1a41..5254f43d7c6cbff73199ddf599a88d73dee94f0c 100644
|
| --- a/content/browser/media/session/media_session_impl.cc
|
| +++ b/content/browser/media/session/media_session_impl.cc
|
| @@ -6,6 +6,7 @@
|
|
|
| #include <algorithm>
|
| #include "content/browser/media/session/audio_focus_delegate.h"
|
| +#include "content/browser/media/session/media_session_controller.h"
|
| #include "content/browser/media/session/media_session_player_observer.h"
|
| #include "content/browser/media/session/media_session_service_impl.h"
|
| #include "content/browser/web_contents/web_contents_impl.h"
|
| @@ -25,6 +26,26 @@ namespace {
|
| const double kDefaultVolumeMultiplier = 1.0;
|
| const double kDuckingVolumeMultiplier = 0.2;
|
|
|
| +using MapRenderFrameHostToDepth = std::map<RenderFrameHost*, size_t>;
|
| +
|
| +size_t ComputeFrameDepth(RenderFrameHost* rfh,
|
| + MapRenderFrameHostToDepth* map_rfh_to_depth) {
|
| + DCHECK(rfh);
|
| + size_t depth = 0;
|
| + RenderFrameHost* current_frame = rfh;
|
| + while (current_frame) {
|
| + auto it = map_rfh_to_depth->find(current_frame);
|
| + if (it != map_rfh_to_depth->end()) {
|
| + depth += it->second;
|
| + break;
|
| + }
|
| + ++depth;
|
| + current_frame = current_frame->GetParent();
|
| + }
|
| + (*map_rfh_to_depth)[rfh] = depth;
|
| + return depth;
|
| +}
|
| +
|
| } // anonymous namespace
|
|
|
| using MediaSessionSuspendedSource =
|
| @@ -89,11 +110,6 @@ void MediaSessionImpl::WebContentsDestroyed() {
|
| AbandonSystemAudioFocusIfNeeded();
|
| }
|
|
|
| -void MediaSessionImpl::SetMediaSessionService(
|
| - MediaSessionServiceImpl* service) {
|
| - service_ = service;
|
| -}
|
| -
|
| void MediaSessionImpl::AddObserver(MediaSessionObserver* observer) {
|
| observers_.AddObserver(observer);
|
| }
|
| @@ -102,13 +118,18 @@ void MediaSessionImpl::RemoveObserver(MediaSessionObserver* observer) {
|
| observers_.RemoveObserver(observer);
|
| }
|
|
|
| -void MediaSessionImpl::SetMetadata(
|
| +void MediaSessionImpl::NotifyMediaSessionMetadataChange(
|
| const base::Optional<MediaMetadata>& metadata) {
|
| - metadata_ = metadata;
|
| for (auto& observer : observers_)
|
| observer.MediaSessionMetadataChanged(metadata);
|
| }
|
|
|
| +void MediaSessionImpl::NotifyMediaSessionActionsChange(
|
| + const std::set<blink::mojom::MediaSessionAction>& actions) {
|
| + for (auto& observer : observers_)
|
| + observer.MediaSessionActionsChanged(actions);
|
| +}
|
| +
|
| bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer,
|
| int player_id,
|
| media::MediaContentType media_content_type) {
|
| @@ -150,8 +171,9 @@ bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer,
|
| normal_players_.clear();
|
|
|
| normal_players_.insert(PlayerIdentifier(observer, player_id));
|
| - NotifyAboutStateChange();
|
|
|
| + UpdateRoutedService();
|
| + NotifyAboutStateChange();
|
| return true;
|
| }
|
|
|
| @@ -174,6 +196,7 @@ void MediaSessionImpl::RemovePlayer(MediaSessionPlayerObserver* observer,
|
| one_shot_players_.erase(it);
|
|
|
| AbandonSystemAudioFocusIfNeeded();
|
| + UpdateRoutedService();
|
|
|
| // The session may become controllable after removing a one-shot player.
|
| // However AbandonSystemAudioFocusIfNeeded will short-return and won't notify
|
| @@ -207,6 +230,7 @@ void MediaSessionImpl::RemovePlayers(MediaSessionPlayerObserver* observer) {
|
| }
|
|
|
| AbandonSystemAudioFocusIfNeeded();
|
| + UpdateRoutedService();
|
|
|
| // The session may become controllable after removing a one-shot player.
|
| // However AbandonSystemAudioFocusIfNeeded will short-return and won't notify
|
| @@ -299,24 +323,6 @@ void MediaSessionImpl::Stop(SuspendType suspend_type) {
|
| AbandonSystemAudioFocusIfNeeded();
|
| }
|
|
|
| -void MediaSessionImpl::DidReceiveAction(
|
| - blink::mojom::MediaSessionAction action) {
|
| - if (service_)
|
| - service_->GetClient()->DidReceiveAction(action);
|
| -}
|
| -
|
| -void MediaSessionImpl::OnMediaSessionEnabledAction(
|
| - blink::mojom::MediaSessionAction action) {
|
| - for (auto& observer : observers_)
|
| - observer.MediaSessionEnabledAction(action);
|
| -}
|
| -
|
| -void MediaSessionImpl::OnMediaSessionDisabledAction(
|
| - blink::mojom::MediaSessionAction action) {
|
| - for (auto& observer : observers_)
|
| - observer.MediaSessionDisabledAction(action);
|
| -}
|
| -
|
| void MediaSessionImpl::StartDucking() {
|
| if (is_ducking_)
|
| return;
|
| @@ -470,7 +476,7 @@ MediaSessionImpl::MediaSessionImpl(WebContents* web_contents)
|
| audio_focus_type_(
|
| AudioFocusManager::AudioFocusType::GainTransientMayDuck),
|
| is_ducking_(false),
|
| - service_(nullptr) {
|
| + routed_service_(nullptr) {
|
| #if defined(OS_ANDROID)
|
| session_android_.reset(new MediaSessionAndroid(this));
|
| #endif // defined(OS_ANDROID)
|
| @@ -552,4 +558,103 @@ bool MediaSessionImpl::AddOneShotPlayer(MediaSessionPlayerObserver* observer,
|
| return true;
|
| }
|
|
|
| +// MediaSessionService-related methods
|
| +
|
| +void MediaSessionImpl::OnServiceCreated(MediaSessionServiceImpl* service) {
|
| + services_[service->GetRenderFrameHost()] = service;
|
| +}
|
| +
|
| +void MediaSessionImpl::OnServiceDestroyed(MediaSessionServiceImpl* service) {
|
| + services_.erase(service->GetRenderFrameHost());
|
| +}
|
| +
|
| +void MediaSessionImpl::OnMediaSessionMetadataChanged(
|
| + MediaSessionServiceImpl* service) {
|
| + if (service != routed_service_)
|
| + return;
|
| +
|
| + NotifyMediaSessionMetadataChange(routed_service_->metadata());
|
| +}
|
| +
|
| +void MediaSessionImpl::OnMediaSessionActionsChanged(
|
| + MediaSessionServiceImpl* service) {
|
| + if (service != routed_service_)
|
| + return;
|
| +
|
| + NotifyMediaSessionActionsChange(routed_service_->actions());
|
| +}
|
| +
|
| +void MediaSessionImpl::DidReceiveAction(
|
| + blink::mojom::MediaSessionAction action) {
|
| + if (!routed_service_)
|
| + return;
|
| +
|
| + routed_service_->GetClient()->DidReceiveAction(action);
|
| +}
|
| +
|
| +bool MediaSessionImpl::IsServiceActiveForRenderFrameHost(RenderFrameHost* rfh) {
|
| + if (!services_.count(rfh))
|
| + return false;
|
| +
|
| + return services_[rfh]->metadata().has_value() ||
|
| + !services_[rfh]->actions().empty();
|
| +}
|
| +
|
| +void MediaSessionImpl::UpdateRoutedService() {
|
| + MediaSessionServiceImpl* new_service = ComputeServiceForRouting();
|
| + if (new_service == routed_service_)
|
| + return;
|
| +
|
| + routed_service_ = new_service;
|
| + if (routed_service_) {
|
| + NotifyMediaSessionMetadataChange(routed_service_->metadata());
|
| + NotifyMediaSessionActionsChange(routed_service_->actions());
|
| + } else {
|
| + NotifyMediaSessionMetadataChange(base::nullopt);
|
| + NotifyMediaSessionActionsChange(
|
| + std::set<blink::mojom::MediaSessionAction>());
|
| + }
|
| +}
|
| +
|
| +MediaSessionServiceImpl* MediaSessionImpl::ComputeServiceForRouting() {
|
| + // The service selection strategy is: select a frame that has a playing/paused
|
| + // player and has a corresponding MediaSessionService and return the
|
| + // corresponding MediaSessionService. If multiple frames satisfy the criteria,
|
| + // prefer the top-most frame.
|
| + std::set<RenderFrameHost*> frames;
|
| + for (const auto& player : normal_players_) {
|
| + RenderFrameHost* frame = player.observer->GetRenderFrameHost();
|
| + if (frame)
|
| + frames.insert(frame);
|
| + }
|
| +
|
| + for (const auto& player : one_shot_players_) {
|
| + RenderFrameHost* frame = player.observer->GetRenderFrameHost();
|
| + if (frame)
|
| + frames.insert(frame);
|
| + }
|
| +
|
| + for (const auto& player : pepper_players_) {
|
| + RenderFrameHost* frame = player.observer->GetRenderFrameHost();
|
| + if (frame)
|
| + frames.insert(frame);
|
| + }
|
| +
|
| + RenderFrameHost* best_frame = nullptr;
|
| + size_t min_depth = std::numeric_limits<size_t>::max();
|
| + std::map<RenderFrameHost*, size_t> map_rfh_to_depth;
|
| +
|
| + for (RenderFrameHost* frame : frames) {
|
| + size_t depth = ComputeFrameDepth(frame, &map_rfh_to_depth);
|
| + if (depth >= min_depth)
|
| + continue;
|
| + if (!IsServiceActiveForRenderFrameHost(frame))
|
| + continue;
|
| + best_frame = frame;
|
| + min_depth = depth;
|
| + }
|
| +
|
| + return best_frame ? services_[best_frame] : nullptr;
|
| +}
|
| +
|
| } // namespace content
|
|
|