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

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

Issue 1971443002: Implement Audio Focus Manager for desktop. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months 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 unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/browser/media/session/audio_focus_manager.h"
6
7 #include "base/optional.h"
8 #include "content/browser/media/session/media_session.h"
9 #include "content/public/browser/web_contents.h"
10
11 namespace content {
12
13 namespace {
14
15 const double kDuckingVolumeMultiplier = 0.2;
16 const double kDefaultVolumeMultiplier = 1.0;
17
18 } // anonymous namespace
19
20 AudioFocusManager::AudioFocusEntry::AudioFocusEntry(WebContents* web_contents, A udioFocusManager* audio_focus_manager, AudioFocusType type)
21 : WebContentsObserver(web_contents),
22 audio_focus_manager_(audio_focus_manager) {
Zhiqiang Zhang (Slow) 2016/05/11 15:57:32 You forgot type_(type) here :)
23 }
24
25 AudioFocusManager::AudioFocusType AudioFocusManager::AudioFocusEntry::type() con st {
26 return type_;
27 }
28
29 void AudioFocusManager::AudioFocusEntry::set_type(AudioFocusType type) {
30 type_ = type;
31 }
32
33 void AudioFocusManager::AudioFocusEntry::WebContentsDestroyed() {
34 audio_focus_manager_->OnWebContentsDestroyed(web_contents());
35 // |this| will be destroyed now.
36 }
37
38 // static
39 AudioFocusManager* AudioFocusManager::GetInstance() {
40 return base::Singleton<AudioFocusManager>::get();
41 }
42
43 void AudioFocusManager::RequestAudioFocus(
44 MediaSession* media_session, AudioFocusType type) {
45 WebContents* web_contents = media_session->web_contents();
46 base::Optional<AudioFocusType> previous_type;
47
48 auto it = entries_.find(web_contents);
49 if (it != entries_.end()) {
50 previous_type = it->second->type();
51 it->second->set_type(type);
52 } else {
53 entries_[web_contents] = std::unique_ptr<AudioFocusEntry>(
54 new AudioFocusEntry(web_contents, this, type));
55 }
56
57 if (previous_type && previous_type.value() != type) {
58 switch (previous_type.value()) {
59 case AudioFocusType::GainTransientMayDuck:
60 MaybeStopDucking();
61 break;
62 case AudioFocusType::Gain:
63 RemoveFromFocusStack(web_contents);
64 break;
65 }
66 }
67
68 if (type == AudioFocusType::GainTransientMayDuck) {
69 MaybeStartDucking();
70 return;
71 }
72
73 DCHECK(type == AudioFocusType::Gain);
74
75 if (!focus_stack_.empty()) {
76 // Already on top, it's a no-op.
77 if (*focus_stack_.begin() == web_contents)
78 return;
79
80 MediaSession* other_session = MediaSession::Get(*focus_stack_.begin());
81 if (other_session->IsActive())
82 other_session->Suspend(MediaSession::SuspendType::SYSTEM);
83
84 RemoveFromFocusStack(web_contents);
85 }
86
87 focus_stack_.push_front(web_contents);
88 }
89
90 void AudioFocusManager::AbandonAudioFocus(MediaSession* media_session) {
91 WebContents* web_contents = media_session->web_contents();
92
93 // We do not expect to receive an AbandonAudioFocus call for a session that
94 // didn't ask for audio focus at some point.
95 auto it = entries_.find(web_contents);
96 DCHECK(it != entries_.end());
97
98 AudioFocusType type = it->second->type();
99 entries_.erase(web_contents);
100
101 if (type == AudioFocusType::GainTransientMayDuck) {
102 MaybeStopDucking();
103 return;
104 }
105
106 DCHECK(type == AudioFocusType::Gain);
107
108 if (focus_stack_.empty())
109 return;
110
111 // Something that doesn't have focus is closing.
112 if (*focus_stack_.begin() != web_contents) {
113 RemoveFromFocusStack(web_contents);
114 return;
115 }
116
117 focus_stack_.erase(focus_stack_.begin());
118 if (!focus_stack_.empty())
119 MediaSession::Get(*focus_stack_.begin())->Resume(MediaSession::SuspendType:: SYSTEM);
Zhiqiang Zhang (Slow) 2016/05/11 15:57:32 On Android, we don't resume other sessions when ab
Zhiqiang Zhang (Slow) 2016/05/20 14:14:43 Sorry, no need to clear the stack here. Our curren
120 }
121
122 AudioFocusManager::AudioFocusManager() = default;
123
124 AudioFocusManager::~AudioFocusManager() = default;
125
126 void AudioFocusManager::OnWebContentsDestroyed(WebContents* web_contents) {
127 entries_.erase(web_contents);
128 RemoveFromFocusStack(web_contents);
129 }
130
131 void AudioFocusManager::MaybeStartDucking() const {
132 if (TransientMayDuckEntriesCount() != 1)
133 return;
134
135 // TODO(mlamouri): add StartDuck to MediaSession.
136 for (const auto& it : focus_stack_)
137 MediaSession::Get(it)->SetVolumeMultiplier(kDuckingVolumeMultiplier);
138 }
139
140 void AudioFocusManager::MaybeStopDucking() const {
141 if (TransientMayDuckEntriesCount() != 0)
142 return;
143
144 // TODO(mlamouri): add StopDuck to MediaSession.
145 for (const auto& it : focus_stack_)
146 MediaSession::Get(it)->SetVolumeMultiplier(kDefaultVolumeMultiplier);
147 }
148
149 int AudioFocusManager::TransientMayDuckEntriesCount() const {
150 int count = 0;
151 for (const auto& it : entries_) {
152 if (it.second->type() != AudioFocusType::GainTransientMayDuck)
153 continue;
154 ++count;
155 }
156 return count;
157 }
158
159 void AudioFocusManager::RemoveFromFocusStack(WebContents* web_contents) {
160 focus_stack_.remove_if([web_contents](WebContents* wc) -> bool { return wc == web_contents; });
161 }
162
163 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/media/session/audio_focus_manager.h ('k') | content/browser/media/session/media_session_delegate_default.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698