Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Unified Diff: content/browser/media/session/media_session_impl.cc

Issue 2475473002: Implement one-shot audio focus inside MediaSession (Closed)
Patch Set: fixed a case where removing the last one-shot player Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..1b5e706c47a32b0167e2306d9c7b7dc3cd5b1a41 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,47 @@ 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);
+ bool was_controllable = IsControllable();
+
+ 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);
+
AbandonSystemAudioFocusIfNeeded();
+
+ // The session may become controllable after removing a one-shot player.
+ // However AbandonSystemAudioFocusIfNeeded will short-return and won't notify
+ // about the state change.
+ if (!was_controllable && IsControllable())
+ NotifyAboutStateChange();
}
void MediaSessionImpl::RemovePlayers(MediaSessionPlayerObserver* observer) {
- for (auto it = players_.begin(); it != players_.end();) {
+ bool was_controllable = IsControllable();
+
+ for (auto it = normal_players_.begin(); it != normal_players_.end();) {
if (it->observer == observer)
- players_.erase(it++);
+ normal_players_.erase(it++);
else
++it;
}
@@ -182,7 +199,20 @@ 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;
+ }
+
AbandonSystemAudioFocusIfNeeded();
+
+ // The session may become controllable after removing a one-shot player.
+ // However AbandonSystemAudioFocusIfNeeded will short-return and won't notify
+ // about the state change.
+ if (!was_controllable && IsControllable())
+ NotifyAboutStateChange();
}
void MediaSessionImpl::RecordSessionDuck() {
@@ -197,15 +227,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))) {
+ 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 +294,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 +332,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 +357,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 +388,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 +402,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 +439,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 +455,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 +493,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 +537,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;
}
« no previous file with comments | « content/browser/media/session/media_session_impl.h ('k') | content/browser/media/session/media_session_impl_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698