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..04b4353922273179a4fdeffed98634670ab7ab9e 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,15 @@ namespace { |
const double kDefaultVolumeMultiplier = 1.0; |
const double kDuckingVolumeMultiplier = 0.2; |
+size_t ComputeFrameDepth(RenderFrameHost* rfh) { |
+ size_t depth = 0; |
+ while (rfh) { |
+ ++depth; |
+ rfh = rfh->GetParent(); |
+ } |
+ return depth; |
+} |
+ |
} // anonymous namespace |
using MediaSessionSuspendedSource = |
@@ -89,11 +99,6 @@ void MediaSessionImpl::WebContentsDestroyed() { |
AbandonSystemAudioFocusIfNeeded(); |
} |
-void MediaSessionImpl::SetMediaSessionService( |
- MediaSessionServiceImpl* service) { |
- service_ = service; |
-} |
- |
void MediaSessionImpl::AddObserver(MediaSessionObserver* observer) { |
observers_.AddObserver(observer); |
} |
@@ -102,13 +107,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 +160,9 @@ bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer, |
normal_players_.clear(); |
normal_players_.insert(PlayerIdentifier(observer, player_id)); |
- NotifyAboutStateChange(); |
+ UpdateRoutedService(); |
+ NotifyAboutStateChange(); |
return true; |
} |
@@ -174,6 +185,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 +219,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 +312,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 +465,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 +547,111 @@ 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 |
whywhat
2016/11/30 22:16:41
is there a test possible for this?
Zhiqiang Zhang (Slow)
2016/12/01 16:34:41
Added unit tests.
|
+ // player and has a corresponding MediaSessionService and return the |
+ // corresponding MediaSessionService. If multiple frames satisfy the criteria, |
+ // prefer the top-most frame. |
+ MediaSessionServiceImpl* best_service = nullptr; |
+ size_t min_depth = std::numeric_limits<size_t>::max(); |
+ |
+ for (const auto& player : normal_players_) { |
whywhat
2016/11/30 22:16:41
I wonder if there's a potential bottleneck - ideal
Zhiqiang Zhang (Slow)
2016/12/01 16:34:41
Done. Now we collect all the frames first and then
|
+ ComputeServiceForRoutingInternal( |
+ player.observer, &best_service, &min_depth); |
+ } |
+ |
+ for (const auto& player : one_shot_players_) { |
+ ComputeServiceForRoutingInternal( |
+ player.observer, &best_service, &min_depth); |
+ } |
+ |
+ for (const auto& player : pepper_players_) { |
+ ComputeServiceForRoutingInternal( |
+ player.observer, &best_service, &min_depth); |
+ } |
+ |
+ return best_service; |
+} |
+ |
+void MediaSessionImpl::ComputeServiceForRoutingInternal( |
+ MediaSessionPlayerObserver* player_observer, |
+ MediaSessionServiceImpl** best_service, |
+ size_t* min_depth) { |
+ MediaSessionController* controller = |
+ static_cast<MediaSessionController*>(player_observer); |
whywhat
2016/11/30 22:16:41
nit: could we avoid this assumption that MSC is th
Zhiqiang Zhang (Slow)
2016/12/01 16:34:41
Added a `GetRenderFrameHost()` method to MediaSess
|
+ if (!controller) |
+ return; |
+ |
+ RenderFrameHost* rfh = controller->GetFrameOrientedId().first; |
+ if (!services_.count(rfh)) |
+ return; |
+ |
+ size_t depth = ComputeFrameDepth(rfh); |
+ if (depth < *min_depth) { |
+ *best_service = services_[rfh]; |
+ *min_depth = depth; |
+ } |
+} |
+ |
} // namespace content |