| Index: content/browser/media/session/audio_focus_manager.cc
|
| diff --git a/content/browser/media/session/audio_focus_manager.cc b/content/browser/media/session/audio_focus_manager.cc
|
| index 4ff3491de482542efe4781d46d153e896df8eef4..cad3c5e292356e3b977cf00304d58d56dadd6520 100644
|
| --- a/content/browser/media/session/audio_focus_manager.cc
|
| +++ b/content/browser/media/session/audio_focus_manager.cc
|
| @@ -4,28 +4,12 @@
|
|
|
| #include "content/browser/media/session/audio_focus_manager.h"
|
|
|
| +#include "base/memory/ptr_util.h"
|
| #include "content/browser/media/session/media_session.h"
|
| #include "content/public/browser/web_contents.h"
|
|
|
| namespace content {
|
|
|
| -AudioFocusManager::AudioFocusEntry::AudioFocusEntry(
|
| - WebContents* web_contents,
|
| - AudioFocusManager* audio_focus_manager,
|
| - AudioFocusType type)
|
| - : WebContentsObserver(web_contents),
|
| - audio_focus_manager_(audio_focus_manager) {}
|
| -
|
| -AudioFocusManager::AudioFocusType
|
| -AudioFocusManager::AudioFocusEntry::type() const {
|
| - return type_;
|
| -}
|
| -
|
| -void AudioFocusManager::AudioFocusEntry::WebContentsDestroyed() {
|
| - audio_focus_manager_->OnWebContentsDestroyed(web_contents());
|
| - // |this| will be destroyed now.
|
| -}
|
| -
|
| // static
|
| AudioFocusManager* AudioFocusManager::GetInstance() {
|
| return base::Singleton<AudioFocusManager>::get();
|
| @@ -33,83 +17,77 @@ AudioFocusManager* AudioFocusManager::GetInstance() {
|
|
|
| void AudioFocusManager::RequestAudioFocus(MediaSession* media_session,
|
| AudioFocusType type) {
|
| - WebContents* web_contents = media_session->web_contents();
|
| -
|
| - if (type == AudioFocusType::GainTransientMayDuck) {
|
| - MaybeRemoveFocusEntry(web_contents);
|
| - transient_entries_[web_contents].reset(
|
| - new AudioFocusEntry(web_contents, this, type));
|
| - MaybeStartDucking();
|
| + if (!audio_focus_stack_.empty() &&
|
| + audio_focus_stack_.back() == media_session &&
|
| + audio_focus_stack_.back()->audio_focus_type() == type &&
|
| + audio_focus_stack_.back()->IsActive()) {
|
| + // Early returning if |media_session| is already on top (has focus) and is
|
| + // active.
|
| return;
|
| }
|
|
|
| - DCHECK(type == AudioFocusType::Gain);
|
| - RequestAudioFocusGain(web_contents);
|
| -}
|
| -
|
| -void AudioFocusManager::AbandonAudioFocus(MediaSession* media_session) {
|
| - AbandonAudioFocusInternal(media_session->web_contents());
|
| -}
|
| -
|
| -AudioFocusManager::AudioFocusManager() = default;
|
| -
|
| -AudioFocusManager::~AudioFocusManager() = default;
|
| -
|
| -void AudioFocusManager::RequestAudioFocusGain(WebContents* web_contents) {
|
| - MaybeRemoveTransientEntry(web_contents);
|
| -
|
| - if (focus_entry_) {
|
| - if (focus_entry_->web_contents() == web_contents)
|
| - return;
|
| + MaybeRemoveFocusEntry(media_session);
|
|
|
| - MediaSession* other_session =
|
| - MediaSession::Get(focus_entry_->web_contents());
|
| - if (other_session->IsActive())
|
| - other_session->Suspend(MediaSession::SuspendType::SYSTEM);
|
| + // TODO(zqzhang): It seems like MediaSession is exposed to AudioFocusManager
|
| + // too much. Maybe it's better to do some abstraction and refactoring to clean
|
| + // up the relation between AudioFocusManager and MediaSession.
|
| + // See https://crbug.com/651069
|
| + if (type == AudioFocusType::GainTransientMayDuck) {
|
| + for (const auto old_session : audio_focus_stack_) {
|
| + old_session->StartDucking();
|
| + }
|
| + } else {
|
| + for (const auto old_session : audio_focus_stack_) {
|
| + if (old_session->IsActive()) {
|
| + if (old_session->HasPepper())
|
| + old_session->StartDucking();
|
| + else
|
| + old_session->Suspend(MediaSession::SuspendType::SYSTEM);
|
| + }
|
| + }
|
| }
|
|
|
| - focus_entry_.reset(
|
| - new AudioFocusEntry(web_contents, this, AudioFocusType::Gain));
|
| - MaybeStartDucking();
|
| -}
|
| -
|
| -void AudioFocusManager::OnWebContentsDestroyed(WebContents* web_contents) {
|
| - AbandonAudioFocusInternal(web_contents);
|
| -}
|
| -
|
| -void AudioFocusManager::AbandonAudioFocusInternal(WebContents* web_contents) {
|
| - MaybeRemoveTransientEntry(web_contents);
|
| - MaybeRemoveFocusEntry(web_contents);
|
| + audio_focus_stack_.push_back(media_session);
|
| + audio_focus_stack_.back()->StopDucking();
|
| }
|
|
|
| -void AudioFocusManager::MaybeStartDucking() const {
|
| - if (TransientMayDuckEntriesCount() != 1 || !focus_entry_)
|
| +void AudioFocusManager::AbandonAudioFocus(MediaSession* media_session) {
|
| + if (audio_focus_stack_.empty())
|
| return;
|
|
|
| - MediaSession::Get(focus_entry_->web_contents())->StartDucking();
|
| -}
|
| + if (audio_focus_stack_.back() != media_session) {
|
| + MaybeRemoveFocusEntry(media_session);
|
| + return;
|
| + }
|
|
|
| -void AudioFocusManager::MaybeStopDucking() const {
|
| - if (TransientMayDuckEntriesCount() != 0 || !focus_entry_)
|
| + audio_focus_stack_.pop_back();
|
| + if (audio_focus_stack_.empty())
|
| return;
|
|
|
| - MediaSession::Get(focus_entry_->web_contents())->StopDucking();
|
| + // Allow the top-most MediaSession having Pepper to unduck pepper even if it's
|
| + // not active.
|
| + for (auto iter = audio_focus_stack_.rbegin();
|
| + iter != audio_focus_stack_.rend(); ++iter) {
|
| + if (!(*iter)->HasPepper())
|
| + continue;
|
| +
|
| + MediaSession* pepper_session = *iter;
|
| + pepper_session->StopDucking();
|
| + MaybeRemoveFocusEntry(pepper_session);
|
| + audio_focus_stack_.push_back(pepper_session);
|
| + return;
|
| + }
|
| + // Only try to unduck the new MediaSession on top. The session might be still
|
| + // inactive but it will not be resumed (so it doesn't surprise the user).
|
| + audio_focus_stack_.back()->StopDucking();
|
| }
|
|
|
| -int AudioFocusManager::TransientMayDuckEntriesCount() const {
|
| - return transient_entries_.size();
|
| -}
|
| +AudioFocusManager::AudioFocusManager() = default;
|
|
|
| -void AudioFocusManager::MaybeRemoveTransientEntry(WebContents* web_contents) {
|
| - transient_entries_.erase(web_contents);
|
| - MaybeStopDucking();
|
| -}
|
| +AudioFocusManager::~AudioFocusManager() = default;
|
|
|
| -void AudioFocusManager::MaybeRemoveFocusEntry(WebContents* web_contents) {
|
| - if (focus_entry_ && focus_entry_->web_contents() == web_contents) {
|
| - MediaSession::Get(focus_entry_->web_contents())->StopDucking();
|
| - focus_entry_.reset();
|
| - }
|
| +void AudioFocusManager::MaybeRemoveFocusEntry(MediaSession* media_session) {
|
| + audio_focus_stack_.remove(media_session);
|
| }
|
|
|
| } // namespace content
|
|
|