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 |