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 7b56e49618c3ff198418fb8706fafdde4b180cdb..2120e3281e8d2030d9f03ec636a2b7c376ea59b1 100644 |
| --- a/content/browser/media/session/media_session_impl.cc |
| +++ b/content/browser/media/session/media_session_impl.cc |
| @@ -66,7 +66,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 +82,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 +111,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 +133,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 +146,41 @@ 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); |
| + auto it = normal_players_.find(PlayerIdentifier(observer, player_id)); |
|
DaleCurtis
2016/11/04 19:15:42
You construct a PlayerIdentifier 3 times, might be
Zhiqiang Zhang (Slow)
2016/11/04 21:44:00
Done.
|
| + if (it != normal_players_.end()) |
| + normal_players_.erase(it); |
| it = pepper_players_.find(PlayerIdentifier(observer, player_id)); |
| if (it != pepper_players_.end()) |
| pepper_players_.erase(it); |
| + it = one_shot_players_.find(PlayerIdentifier(observer, player_id)); |
| + 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();) { |
|
DaleCurtis
2016/11/04 19:15:42
This pattern only makes sense with maps, right? Yo
Zhiqiang Zhang (Slow)
2016/11/04 21:44:00
Hmm, PlayersMap is actually unordered_set<>. Accor
|
| if (it->observer == observer) |
| - players_.erase(it++); |
| + normal_players_.erase(it++); |
| else |
| ++it; |
| } |
| @@ -182,6 +192,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 +219,23 @@ 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))) { |
| + if (!normal_players_.count(PlayerIdentifier(observer, player_id)) && |
|
DaleCurtis
2016/11/04 19:15:42
Again multiple id construction.
Zhiqiang Zhang (Slow)
2016/11/04 21:44:00
Done.
|
| + !pepper_players_.count(PlayerIdentifier(observer, player_id)) && |
| + !one_shot_players_.count(PlayerIdentifier(observer, player_id))) { |
| 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) { |
| + 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(PlayerIdentifier(observer, player_id))) { |
| RemovePlayer(observer, player_id); |
| return; |
| } |
| @@ -256,7 +286,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 +324,7 @@ void MediaSessionImpl::StopDucking() { |
| } |
| void MediaSessionImpl::UpdateVolumeMultiplier() { |
|
DaleCurtis
2016/11/04 19:15:42
One shot players don't get volume changes?
Zhiqiang Zhang (Slow)
2016/11/04 21:44:00
Yes. Consider the following case:
1. WebRTC starts
|
| - 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 +349,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()); |
|
DaleCurtis
2016/11/04 19:15:42
No unnecessary parens.
Zhiqiang Zhang (Slow)
2016/11/04 21:44:00
Done.
|
| } |
| bool MediaSessionImpl::HasPepper() const { |
| @@ -348,7 +380,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 +394,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 +431,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 +447,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 +485,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 +529,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; |
| } |