| 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 7b56e49618c3ff198418fb8706fafdde4b180cdb..8f5e8e3d488c7bff0071672ff5615c0c06c96189 100644
|
| --- a/content/browser/media/session/media_session_impl.cc
|
| +++ b/content/browser/media/session/media_session_impl.cc
|
| @@ -4,6 +4,7 @@
|
|
|
| #include "content/browser/media/session/media_session_impl.h"
|
|
|
| +#include <algorithm>
|
| #include "content/browser/media/session/audio_focus_delegate.h"
|
| #include "content/browser/media/session/media_session_player_observer.h"
|
| #include "content/browser/media/session/media_session_service_impl.h"
|
| @@ -66,7 +67,9 @@ MediaSessionImpl* MediaSessionImpl::Get(WebContents* web_contents) {
|
| }
|
|
|
| MediaSessionImpl::~MediaSessionImpl() {
|
| - DCHECK(players_.empty());
|
| + DCHECK(normal_players_.empty());
|
| + DCHECK(pepper_players_.empty());
|
| + DCHECK(one_shot_players_.empty());
|
| DCHECK(audio_focus_state_ == State::INACTIVE);
|
| for (auto& observer : observers_)
|
| observer.MediaSessionDestroyed();
|
| @@ -80,8 +83,9 @@ void MediaSessionImpl::WebContentsDestroyed() {
|
| // talk with AudioFocusManager out to a seperate class. The AudioFocusManager
|
| // unit tests then could mock the interface and abandon audio focus when
|
| // WebContents is destroyed. See https://crbug.com/651069
|
| - players_.clear();
|
| + normal_players_.clear();
|
| pepper_players_.clear();
|
| + one_shot_players_.clear();
|
| AbandonSystemAudioFocusIfNeeded();
|
| }
|
|
|
| @@ -108,16 +112,13 @@ void MediaSessionImpl::SetMetadata(
|
| bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer,
|
| int player_id,
|
| media::MediaContentType media_content_type) {
|
| - if (media_content_type == media::MediaContentType::Uncontrollable)
|
| - return true;
|
| + if (media_content_type == media::MediaContentType::OneShot)
|
| + return AddOneShotPlayer(observer, player_id);
|
| if (media_content_type == media::MediaContentType::Pepper)
|
| return AddPepperPlayer(observer, player_id);
|
|
|
| observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier());
|
|
|
| - // Determine the audio focus type required for playing the new player.
|
| - // TODO(zqzhang): handle duckable and uncontrollable.
|
| - // See https://crbug.com/639277.
|
| AudioFocusManager::AudioFocusType required_audio_focus_type;
|
| if (media_content_type == media::MediaContentType::Persistent) {
|
| required_audio_focus_type = AudioFocusManager::AudioFocusType::Gain;
|
| @@ -133,7 +134,7 @@ bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer,
|
| if (audio_focus_state_ == State::ACTIVE &&
|
| (audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain ||
|
| audio_focus_type_ == required_audio_focus_type)) {
|
| - players_.insert(PlayerIdentifier(observer, player_id));
|
| + normal_players_.insert(PlayerIdentifier(observer, player_id));
|
| return true;
|
| }
|
|
|
| @@ -146,31 +147,43 @@ bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer,
|
| // The session should be reset if a player is starting while all players are
|
| // suspended.
|
| if (old_audio_focus_state != State::ACTIVE)
|
| - players_.clear();
|
| + normal_players_.clear();
|
|
|
| - players_.insert(PlayerIdentifier(observer, player_id));
|
| - UpdateWebContents();
|
| + normal_players_.insert(PlayerIdentifier(observer, player_id));
|
| + NotifyAboutStateChange();
|
|
|
| return true;
|
| }
|
|
|
| void MediaSessionImpl::RemovePlayer(MediaSessionPlayerObserver* observer,
|
| int player_id) {
|
| - auto it = players_.find(PlayerIdentifier(observer, player_id));
|
| - if (it != players_.end())
|
| - players_.erase(it);
|
| + PlayerIdentifier identifier(observer, player_id);
|
| +
|
| + auto it = normal_players_.find(identifier);
|
| + if (it != normal_players_.end())
|
| + normal_players_.erase(it);
|
|
|
| - it = pepper_players_.find(PlayerIdentifier(observer, player_id));
|
| + it = pepper_players_.find(identifier);
|
| if (it != pepper_players_.end())
|
| pepper_players_.erase(it);
|
|
|
| + it = one_shot_players_.find(identifier);
|
| + if (it != one_shot_players_.end()) {
|
| + one_shot_players_.erase(it);
|
| +
|
| + // The session may become controllable after all one-shot players are
|
| + // removed.
|
| + if (one_shot_players_.empty())
|
| + NotifyAboutStateChange();
|
| + }
|
| +
|
| AbandonSystemAudioFocusIfNeeded();
|
| }
|
|
|
| void MediaSessionImpl::RemovePlayers(MediaSessionPlayerObserver* observer) {
|
| - for (auto it = players_.begin(); it != players_.end();) {
|
| + for (auto it = normal_players_.begin(); it != normal_players_.end();) {
|
| if (it->observer == observer)
|
| - players_.erase(it++);
|
| + normal_players_.erase(it++);
|
| else
|
| ++it;
|
| }
|
| @@ -182,6 +195,18 @@ void MediaSessionImpl::RemovePlayers(MediaSessionPlayerObserver* observer) {
|
| ++it;
|
| }
|
|
|
| + for (auto it = one_shot_players_.begin(); it != one_shot_players_.end();) {
|
| + if (it->observer == observer)
|
| + one_shot_players_.erase(it++);
|
| + else
|
| + ++it;
|
| +
|
| + // The session may become controllable after all one-shot players are
|
| + // removed.
|
| + if (one_shot_players_.empty())
|
| + NotifyAboutStateChange();
|
| + }
|
| +
|
| AbandonSystemAudioFocusIfNeeded();
|
| }
|
|
|
| @@ -197,15 +222,24 @@ void MediaSessionImpl::OnPlayerPaused(MediaSessionPlayerObserver* observer,
|
| // Also, this method may be called when a player that is not added
|
| // to this session (e.g. a silent video) is paused. MediaSessionImpl
|
| // should ignore the paused player for this case.
|
| - if (!players_.count(PlayerIdentifier(observer, player_id)) &&
|
| - !pepper_players_.count(PlayerIdentifier(observer, player_id))) {
|
| + PlayerIdentifier identifier(observer, player_id);
|
| + if (!normal_players_.count(identifier) &&
|
| + !pepper_players_.count(identifier) &&
|
| + !one_shot_players_.count(identifier)) {
|
| return;
|
| }
|
|
|
| // If the player to be removed is a pepper player, or there is more than one
|
| // observer, remove the paused one from the session.
|
| - if (pepper_players_.count(PlayerIdentifier(observer, player_id)) ||
|
| - players_.size() != 1) {
|
| + if (pepper_players_.count(identifier) ||
|
| + normal_players_.size() != 1) {
|
| + RemovePlayer(observer, player_id);
|
| + return;
|
| + }
|
| +
|
| + // If the player is a one-shot player, just remove it since it is not expected
|
| + // to resume a one-shot player via resuming MediaSession.
|
| + if (one_shot_players_.count(identifier)) {
|
| RemovePlayer(observer, player_id);
|
| return;
|
| }
|
| @@ -256,7 +290,7 @@ void MediaSessionImpl::Stop(SuspendType suspend_type) {
|
| OnSuspendInternal(suspend_type, State::SUSPENDED);
|
|
|
| DCHECK(audio_focus_state_ == State::SUSPENDED);
|
| - players_.clear();
|
| + normal_players_.clear();
|
|
|
| AbandonSystemAudioFocusIfNeeded();
|
| }
|
| @@ -294,7 +328,7 @@ void MediaSessionImpl::StopDucking() {
|
| }
|
|
|
| void MediaSessionImpl::UpdateVolumeMultiplier() {
|
| - for (const auto& it : players_)
|
| + for (const auto& it : normal_players_)
|
| it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier());
|
| for (const auto& it : pepper_players_)
|
| it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier());
|
| @@ -319,9 +353,11 @@ bool MediaSessionImpl::IsSuspended() const {
|
|
|
| bool MediaSessionImpl::IsControllable() const {
|
| // Only media session having focus Gain can be controllable unless it is
|
| - // inactive.
|
| + // inactive. Also, the session will be uncontrollable if it contains one-shot
|
| + // players.
|
| return audio_focus_state_ != State::INACTIVE &&
|
| - audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain;
|
| + audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain &&
|
| + one_shot_players_.empty();
|
| }
|
|
|
| bool MediaSessionImpl::HasPepper() const {
|
| @@ -348,7 +384,9 @@ MediaSessionUmaHelper* MediaSessionImpl::uma_helper_for_test() {
|
| }
|
|
|
| void MediaSessionImpl::RemoveAllPlayersForTest() {
|
| - players_.clear();
|
| + normal_players_.clear();
|
| + pepper_players_.clear();
|
| + one_shot_players_.clear();
|
| AbandonSystemAudioFocusIfNeeded();
|
| }
|
|
|
| @@ -360,6 +398,9 @@ void MediaSessionImpl::OnSuspendInternal(SuspendType suspend_type,
|
| // UI suspend cannot use State::INACTIVE.
|
| DCHECK(suspend_type == SuspendType::SYSTEM || new_state == State::SUSPENDED);
|
|
|
| + if (!one_shot_players_.empty())
|
| + return;
|
| +
|
| if (audio_focus_state_ != State::ACTIVE)
|
| return;
|
|
|
| @@ -394,14 +435,14 @@ void MediaSessionImpl::OnSuspendInternal(SuspendType suspend_type,
|
| // SuspendType::CONTENT happens when the suspend action came from
|
| // the page in which case the player is already paused.
|
| // Otherwise, the players need to be paused.
|
| - for (const auto& it : players_)
|
| + for (const auto& it : normal_players_)
|
| it.observer->OnSuspend(it.player_id);
|
| }
|
|
|
| for (const auto& it : pepper_players_)
|
| it.observer->OnSetVolumeMultiplier(it.player_id, kDuckingVolumeMultiplier);
|
|
|
| - UpdateWebContents();
|
| + NotifyAboutStateChange();
|
| }
|
|
|
| void MediaSessionImpl::OnResumeInternal(SuspendType suspend_type) {
|
| @@ -410,13 +451,13 @@ void MediaSessionImpl::OnResumeInternal(SuspendType suspend_type) {
|
|
|
| SetAudioFocusState(State::ACTIVE);
|
|
|
| - for (const auto& it : players_)
|
| + for (const auto& it : normal_players_)
|
| it.observer->OnResume(it.player_id);
|
|
|
| for (const auto& it : pepper_players_)
|
| it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier());
|
|
|
| - UpdateWebContents();
|
| + NotifyAboutStateChange();
|
| }
|
|
|
| MediaSessionImpl::MediaSessionImpl(WebContents* web_contents)
|
| @@ -448,17 +489,17 @@ bool MediaSessionImpl::RequestSystemAudioFocus(
|
| }
|
|
|
| void MediaSessionImpl::AbandonSystemAudioFocusIfNeeded() {
|
| - if (audio_focus_state_ == State::INACTIVE || !players_.empty() ||
|
| - !pepper_players_.empty()) {
|
| + if (audio_focus_state_ == State::INACTIVE || !normal_players_.empty() ||
|
| + !pepper_players_.empty() || !one_shot_players_.empty()) {
|
| return;
|
| }
|
| delegate_->AbandonAudioFocus();
|
|
|
| SetAudioFocusState(State::INACTIVE);
|
| - UpdateWebContents();
|
| + NotifyAboutStateChange();
|
| }
|
|
|
| -void MediaSessionImpl::UpdateWebContents() {
|
| +void MediaSessionImpl::NotifyAboutStateChange() {
|
| media_session_state_listeners_.Notify(audio_focus_state_);
|
| for (auto& observer : observers_)
|
| observer.MediaSessionStateChanged(IsControllable(), IsSuspended());
|
| @@ -492,6 +533,18 @@ bool MediaSessionImpl::AddPepperPlayer(MediaSessionPlayerObserver* observer,
|
|
|
| observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier());
|
|
|
| + NotifyAboutStateChange();
|
| + return success;
|
| +}
|
| +
|
| +bool MediaSessionImpl::AddOneShotPlayer(MediaSessionPlayerObserver* observer,
|
| + int player_id) {
|
| + if (!RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain))
|
| + return false;
|
| +
|
| + one_shot_players_.insert(PlayerIdentifier(observer, player_id));
|
| + NotifyAboutStateChange();
|
| +
|
| return true;
|
| }
|
|
|
|
|