Chromium Code Reviews

Side by Side Diff: content/browser/media/session/audio_focus_manager.cc

Issue 2274873003: Letting Flash join MediaSession (stack implementaion) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@media_session_type
Patch Set: added doc Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/media/session/audio_focus_manager.h" 5 #include "content/browser/media/session/audio_focus_manager.h"
6 6
7 #include "base/memory/ptr_util.h"
7 #include "content/browser/media/session/media_session.h" 8 #include "content/browser/media/session/media_session.h"
8 #include "content/public/browser/web_contents.h" 9 #include "content/public/browser/web_contents.h"
9 10
10 namespace content { 11 namespace content {
11 12
12 AudioFocusManager::AudioFocusEntry::AudioFocusEntry( 13 AudioFocusManager::AudioFocusEntry::AudioFocusEntry(
13 WebContents* web_contents, 14 WebContents* web_contents,
14 AudioFocusManager* audio_focus_manager, 15 AudioFocusManager* audio_focus_manager,
15 AudioFocusType type) 16 AudioFocusType type)
16 : WebContentsObserver(web_contents), 17 : WebContentsObserver(web_contents),
17 audio_focus_manager_(audio_focus_manager) {} 18 audio_focus_manager_(audio_focus_manager),
19 type_(type) {}
18 20
19 AudioFocusManager::AudioFocusType 21 AudioFocusManager::AudioFocusType
20 AudioFocusManager::AudioFocusEntry::type() const { 22 AudioFocusManager::AudioFocusEntry::type() const {
21 return type_; 23 return type_;
22 } 24 }
23 25
26 MediaSession* AudioFocusManager::AudioFocusEntry::GetMediaSession() const {
27 return MediaSession::Get(web_contents());
28 }
29
24 void AudioFocusManager::AudioFocusEntry::WebContentsDestroyed() { 30 void AudioFocusManager::AudioFocusEntry::WebContentsDestroyed() {
25 audio_focus_manager_->OnWebContentsDestroyed(web_contents()); 31 audio_focus_manager_->OnWebContentsDestroyed(web_contents());
26 // |this| will be destroyed now. 32 // |this| will be destroyed now.
27 } 33 }
28 34
29 // static 35 // static
30 AudioFocusManager* AudioFocusManager::GetInstance() { 36 AudioFocusManager* AudioFocusManager::GetInstance() {
31 return base::Singleton<AudioFocusManager>::get(); 37 return base::Singleton<AudioFocusManager>::get();
32 } 38 }
33 39
34 void AudioFocusManager::RequestAudioFocus(MediaSession* media_session, 40 void AudioFocusManager::RequestAudioFocus(MediaSession* media_session,
35 AudioFocusType type) { 41 AudioFocusType type) {
36 WebContents* web_contents = media_session->web_contents(); 42 WebContents* web_contents = media_session->web_contents();
37 43
38 if (type == AudioFocusType::GainTransientMayDuck) { 44 if (!audio_focus_stack_.empty() &&
39 MaybeRemoveFocusEntry(web_contents); 45 audio_focus_stack_.back()->web_contents() == web_contents &&
40 transient_entries_[web_contents].reset( 46 audio_focus_stack_.back()->type() == type &&
41 new AudioFocusEntry(web_contents, this, type)); 47 audio_focus_stack_.back()->GetMediaSession()->IsActive()) {
42 MaybeStartDucking(); 48 // Early returning if |media_session| is already on top (has focus) and is
49 // active.
43 return; 50 return;
44 } 51 }
45 52
46 DCHECK(type == AudioFocusType::Gain); 53 MaybeRemoveFocusEntry(web_contents);
47 RequestAudioFocusGain(web_contents); 54
55 if (type == AudioFocusType::GainTransientMayDuck) {
56 for (const auto& focus_entry : audio_focus_stack_) {
57 focus_entry->GetMediaSession()->StartDucking();
whywhat 2016/09/27 17:54:16 I think it's still cleaner if we just do something
Zhiqiang Zhang (Slow) 2016/09/28 16:12:17 Added TODO.
58 }
59 } else {
60 for (const auto& focus_entry : audio_focus_stack_) {
61 MediaSession* session = focus_entry->GetMediaSession();
62 if (session->IsActive()) {
63 if (session->HasPepper())
64 session->StartDucking();
65 else
66 session->Suspend(MediaSession::SuspendType::SYSTEM);
67 }
68 }
69 }
70
71 audio_focus_stack_.push_back(base::MakeUnique<AudioFocusEntry>(
72 web_contents, this, type));
73 audio_focus_stack_.back()->GetMediaSession()->StopDucking();
48 } 74 }
49 75
50 void AudioFocusManager::AbandonAudioFocus(MediaSession* media_session) { 76 void AudioFocusManager::AbandonAudioFocus(MediaSession* media_session) {
51 AbandonAudioFocusInternal(media_session->web_contents()); 77 WebContents* web_contents = media_session->web_contents();
78
79 if (audio_focus_stack_.empty())
80 return;
81
82 if (audio_focus_stack_.back()->web_contents() != web_contents) {
83 MaybeRemoveFocusEntry(web_contents);
84 return;
85 }
86
87 audio_focus_stack_.pop_back();
88 if (audio_focus_stack_.empty())
89 return;
90
91 // Allow the top-most MediaSession having Pepper to unduck pepper even if it's
92 // not active.
93 for (auto iter = audio_focus_stack_.rbegin();
94 iter != audio_focus_stack_.rend(); ++iter) {
95 if ((*iter)->GetMediaSession()->HasPepper()) {
96 (*iter)->GetMediaSession()->StopDucking();
97 break;
98 }
99 }
100 // Only try to unduck the new MediaSession on top. The session might be still
101 // inactive but it will not be resumed (so it doesn't surprise the user).
102 audio_focus_stack_.back()->GetMediaSession()->StopDucking();
whywhat 2016/09/27 17:54:16 Wouldn't you call StopDucking twice if the top MS
Zhiqiang Zhang (Slow) 2016/09/28 16:12:17 s/break/return/ in line 97.
52 } 103 }
53 104
54 AudioFocusManager::AudioFocusManager() = default; 105 AudioFocusManager::AudioFocusManager() = default;
55 106
56 AudioFocusManager::~AudioFocusManager() = default; 107 AudioFocusManager::~AudioFocusManager() = default;
57 108
58 void AudioFocusManager::RequestAudioFocusGain(WebContents* web_contents) {
59 MaybeRemoveTransientEntry(web_contents);
60
61 if (focus_entry_) {
62 if (focus_entry_->web_contents() == web_contents)
63 return;
64
65 MediaSession* other_session =
66 MediaSession::Get(focus_entry_->web_contents());
67 if (other_session->IsActive())
68 other_session->Suspend(MediaSession::SuspendType::SYSTEM);
69 }
70
71 focus_entry_.reset(
72 new AudioFocusEntry(web_contents, this, AudioFocusType::Gain));
73 MaybeStartDucking();
74 }
75
76 void AudioFocusManager::OnWebContentsDestroyed(WebContents* web_contents) { 109 void AudioFocusManager::OnWebContentsDestroyed(WebContents* web_contents) {
77 AbandonAudioFocusInternal(web_contents); 110 AbandonAudioFocus(MediaSession::Get(web_contents));
78 }
79
80 void AudioFocusManager::AbandonAudioFocusInternal(WebContents* web_contents) {
81 MaybeRemoveTransientEntry(web_contents);
82 MaybeRemoveFocusEntry(web_contents);
83 }
84
85 void AudioFocusManager::MaybeStartDucking() const {
86 if (TransientMayDuckEntriesCount() != 1 || !focus_entry_)
87 return;
88
89 MediaSession::Get(focus_entry_->web_contents())->StartDucking();
90 }
91
92 void AudioFocusManager::MaybeStopDucking() const {
93 if (TransientMayDuckEntriesCount() != 0 || !focus_entry_)
94 return;
95
96 MediaSession::Get(focus_entry_->web_contents())->StopDucking();
97 }
98
99 int AudioFocusManager::TransientMayDuckEntriesCount() const {
100 return transient_entries_.size();
101 }
102
103 void AudioFocusManager::MaybeRemoveTransientEntry(WebContents* web_contents) {
104 transient_entries_.erase(web_contents);
105 MaybeStopDucking();
106 } 111 }
107 112
108 void AudioFocusManager::MaybeRemoveFocusEntry(WebContents* web_contents) { 113 void AudioFocusManager::MaybeRemoveFocusEntry(WebContents* web_contents) {
109 if (focus_entry_ && focus_entry_->web_contents() == web_contents) { 114 for (auto iter = audio_focus_stack_.begin(); iter != audio_focus_stack_.end();
110 MediaSession::Get(focus_entry_->web_contents())->StopDucking(); 115 ++iter) {
111 focus_entry_.reset(); 116 if (web_contents == (*iter)->web_contents()) {
117 audio_focus_stack_.erase(iter);
118 return;
119 }
112 } 120 }
113 } 121 }
114 122
115 } // namespace content 123 } // namespace content
OLDNEW

Powered by Google App Engine