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

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

Issue 2475473002: Implement one-shot audio focus inside MediaSession (Closed)
Patch Set: nit 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..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;
}
« 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