Chromium Code Reviews| 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..c6139f2ba7bb96af241a04f6547feb1c290fa4b4 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,24 @@ 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) { |
| + size_t depth = 0; |
|
whywhat
2016/12/02 16:09:17
nit: IIUC, you could DCHECK(rfh && map->find(rfh)
Zhiqiang Zhang (Slow)
2016/12/05 11:37:32
Added DCHECK(rfh) here.
I prefer not to DCHECK(ma
|
| + RenderFrameHost* current_frame = rfh; |
| + while (current_frame) { |
| + if (map_rfh_to_depth->count(current_frame)) { |
|
whywhat
2016/12/02 16:09:18
you could use an iterator to avoid double lookup i
Zhiqiang Zhang (Slow)
2016/12/05 11:37:32
Done.
|
| + depth += (*map_rfh_to_depth)[current_frame]; |
| + break; |
| + } |
| + ++depth; |
| + current_frame = current_frame->GetParent(); |
| + } |
| + (*map_rfh_to_depth)[rfh] = depth; |
| + return depth; |
| +} |
| + |
| } // anonymous namespace |
| using MediaSessionSuspendedSource = |
| @@ -89,11 +108,6 @@ void MediaSessionImpl::WebContentsDestroyed() { |
| AbandonSystemAudioFocusIfNeeded(); |
| } |
| -void MediaSessionImpl::SetMediaSessionService( |
| - MediaSessionServiceImpl* service) { |
| - service_ = service; |
| -} |
| - |
| void MediaSessionImpl::AddObserver(MediaSessionObserver* observer) { |
| observers_.AddObserver(observer); |
| } |
| @@ -102,13 +116,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 +169,9 @@ bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer, |
| normal_players_.clear(); |
| normal_players_.insert(PlayerIdentifier(observer, player_id)); |
| - NotifyAboutStateChange(); |
| + UpdateRoutedService(); |
| + NotifyAboutStateChange(); |
| return true; |
| } |
| @@ -174,6 +194,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 +228,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 +321,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 +474,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 +556,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 |