| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/media/session/media_session_controllers_manager.h" |
| |
| #include "base/stl_util.h" |
| #include "content/browser/media/session/media_session_controller.h" |
| #include "media/base/media_switches.h" |
| #include "services/media_session/public/cpp/features.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| bool IsMediaSessionEnabled() { |
| return base::FeatureList::IsEnabled( |
| media_session::features::kMediaSessionService) || |
| base::FeatureList::IsEnabled(media::kInternalMediaSession); |
| } |
| |
| } // namespace |
| |
| MediaSessionControllersManager::MediaSessionControllersManager( |
| MediaWebContentsObserver* media_web_contents_observer) |
| : media_web_contents_observer_(media_web_contents_observer) {} |
| |
| MediaSessionControllersManager::~MediaSessionControllersManager() = default; |
| |
| void MediaSessionControllersManager::RenderFrameDeleted( |
| RenderFrameHost* render_frame_host) { |
| if (!IsMediaSessionEnabled()) |
| return; |
| |
| for (auto it = controllers_map_.begin(); it != controllers_map_.end();) { |
| if (it->first.render_frame_host == render_frame_host) |
| it = controllers_map_.erase(it); |
| else |
| ++it; |
| } |
| } |
| |
| bool MediaSessionControllersManager::RequestPlay( |
| const MediaPlayerId& id, |
| bool has_audio, |
| media::MediaContentType media_content_type, |
| bool has_video) { |
| if (!IsMediaSessionEnabled()) |
| return true; |
| |
| // If we have previously received the position for this player then we should |
| // initialize the controller with it. |
| media_session::MediaPosition* position = nullptr; |
| auto position_it = position_map_.find(id); |
| if (position_it != position_map_.end()) |
| position = &position_it->second; |
| |
| bool is_pip_available = false; |
| auto pip_it = pip_availability_map_.find(id); |
| if (pip_it != pip_availability_map_.end()) |
| is_pip_available = pip_it->second; |
| |
| // Since we don't remove session instances on pause, there may be an existing |
| // instance for this playback attempt. |
| // |
| // In this case, try to reinitialize it with the new settings. If they are |
| // the same, this is a no-op. If the reinitialize fails, destroy the |
| // controller. A later playback attempt will create a new controller. |
| auto it = controllers_map_.find(id); |
| if (it != controllers_map_.end()) { |
| if (it->second->Initialize(has_audio, media_content_type, position, |
| is_pip_available, has_video)) { |
| return true; |
| } |
| |
| controllers_map_.erase(it); |
| return false; |
| } |
| std::unique_ptr<MediaSessionController> controller( |
| new MediaSessionController(id, media_web_contents_observer_)); |
| |
| if (!controller->Initialize(has_audio, media_content_type, position, |
| is_pip_available, has_video)) { |
| return false; |
| } |
| |
| controllers_map_[id] = std::move(controller); |
| return true; |
| } |
| |
| void MediaSessionControllersManager::OnPause(const MediaPlayerId& id) { |
| if (!IsMediaSessionEnabled()) |
| return; |
| |
| auto it = controllers_map_.find(id); |
| if (it == controllers_map_.end()) |
| return; |
| |
| it->second->OnPlaybackPaused(); |
| } |
| |
| void MediaSessionControllersManager::OnEnd(const MediaPlayerId& id) { |
| if (!IsMediaSessionEnabled()) |
| return; |
| controllers_map_.erase(id); |
| } |
| |
| void MediaSessionControllersManager::OnMediaPositionStateChanged( |
| const MediaPlayerId& id, |
| const media_session::MediaPosition& position) { |
| if (!IsMediaSessionEnabled()) |
| return; |
| |
| base::InsertOrAssign(position_map_, id, position); |
| |
| auto it = controllers_map_.find(id); |
| if (it == controllers_map_.end()) |
| return; |
| |
| it->second->OnMediaPositionStateChanged(position); |
| } |
| |
| void MediaSessionControllersManager::PictureInPictureStateChanged( |
| bool is_picture_in_picture) { |
| if (!IsMediaSessionEnabled()) |
| return; |
| |
| for (auto& entry : controllers_map_) |
| entry.second->PictureInPictureStateChanged(is_picture_in_picture); |
| } |
| |
| void MediaSessionControllersManager::WebContentsMutedStateChanged(bool muted) { |
| if (!IsMediaSessionEnabled()) |
| return; |
| |
| for (auto& entry : controllers_map_) |
| entry.second->WebContentsMutedStateChanged(muted); |
| } |
| |
| void MediaSessionControllersManager::OnPictureInPictureAvailabilityChanged( |
| const MediaPlayerId& id, |
| bool available) { |
| if (!IsMediaSessionEnabled()) |
| return; |
| |
| base::InsertOrAssign(pip_availability_map_, id, available); |
| |
| auto it = controllers_map_.find(id); |
| if (it == controllers_map_.end()) |
| return; |
| |
| it->second->OnPictureInPictureAvailabilityChanged(available); |
| } |
| |
| } // namespace content |