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

Side by Side Diff: content/browser/media/android/media_session.cc

Issue 1243683003: Android MediaSession: do not resume a UI suspended session on a system resume. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: review comments Created 5 years, 5 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/android/media_session.h" 5 #include "content/browser/media/android/media_session.h"
6 6
7 #include "base/android/jni_android.h" 7 #include "base/android/jni_android.h"
8 #include "content/browser/media/android/media_session_observer.h" 8 #include "content/browser/media/android/media_session_observer.h"
9 #include "content/browser/web_contents/web_contents_impl.h" 9 #include "content/browser/web_contents/web_contents_impl.h"
10 #include "content/public/browser/web_contents.h" 10 #include "content/public/browser/web_contents.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 if (!session) { 45 if (!session) {
46 CreateForWebContents(web_contents); 46 CreateForWebContents(web_contents);
47 session = FromWebContents(web_contents); 47 session = FromWebContents(web_contents);
48 session->Initialize(); 48 session->Initialize();
49 } 49 }
50 return session; 50 return session;
51 } 51 }
52 52
53 MediaSession::~MediaSession() { 53 MediaSession::~MediaSession() {
54 DCHECK(players_.empty()); 54 DCHECK(players_.empty());
55 DCHECK(audio_focus_state_ == State::Suspended); 55 DCHECK(audio_focus_state_ == State::INACTIVE);
56 } 56 }
57 57
58 bool MediaSession::AddPlayer(MediaSessionObserver* observer, 58 bool MediaSession::AddPlayer(MediaSessionObserver* observer,
59 int player_id, 59 int player_id,
60 Type type) { 60 Type type) {
61 // If the audio focus is already granted and is of type Content, there is 61 // If the audio focus is already granted and is of type Content, there is
62 // nothing to do. If it is granted of type Transient the requested type is 62 // nothing to do. If it is granted of type Transient the requested type is
63 // also transient, there is also nothing to do. Otherwise, the session needs 63 // also transient, there is also nothing to do. Otherwise, the session needs
64 // to request audio focus again. 64 // to request audio focus again.
65 if (audio_focus_state_ == State::Active && 65 if (audio_focus_state_ == State::ACTIVE &&
66 (audio_focus_type_ == Type::Content || audio_focus_type_ == type)) { 66 (audio_focus_type_ == Type::Content || audio_focus_type_ == type)) {
67 players_.insert(PlayerIdentifier(observer, player_id)); 67 players_.insert(PlayerIdentifier(observer, player_id));
68 return true; 68 return true;
69 } 69 }
70 70
71 State old_audio_focus_state = audio_focus_state_; 71 State old_audio_focus_state = audio_focus_state_;
72 audio_focus_state_ = RequestSystemAudioFocus(type) ? State::Active 72 audio_focus_state_ = RequestSystemAudioFocus(type) ? State::ACTIVE
73 : State::Suspended; 73 : State::INACTIVE;
74 audio_focus_type_ = type; 74 audio_focus_type_ = type;
75 75
76 if (audio_focus_state_ != State::Active) 76 if (audio_focus_state_ != State::ACTIVE)
77 return false; 77 return false;
78 78
79 // The session should be reset if a player is starting while all players are 79 // The session should be reset if a player is starting while all players are
80 // suspended. 80 // suspended.
81 if (old_audio_focus_state != State::Active) 81 if (old_audio_focus_state != State::ACTIVE)
82 players_.clear(); 82 players_.clear();
83 83
84 players_.insert(PlayerIdentifier(observer, player_id)); 84 players_.insert(PlayerIdentifier(observer, player_id));
85 UpdateWebContents(); 85 UpdateWebContents();
86 86
87 return true; 87 return true;
88 } 88 }
89 89
90 void MediaSession::RemovePlayer(MediaSessionObserver* observer, 90 void MediaSession::RemovePlayer(MediaSessionObserver* observer,
91 int player_id) { 91 int player_id) {
92 auto it = players_.find(PlayerIdentifier(observer, player_id)); 92 auto it = players_.find(PlayerIdentifier(observer, player_id));
93 if (it != players_.end()) 93 if (it != players_.end())
94 players_.erase(it); 94 players_.erase(it);
95 95
96 AbandonSystemAudioFocusIfNeeded(); 96 AbandonSystemAudioFocusIfNeeded();
97 } 97 }
98 98
99 void MediaSession::RemovePlayers(MediaSessionObserver* observer) { 99 void MediaSession::RemovePlayers(MediaSessionObserver* observer) {
100 for (auto it = players_.begin(); it != players_.end();) { 100 for (auto it = players_.begin(); it != players_.end();) {
101 if (it->observer == observer) 101 if (it->observer == observer)
102 players_.erase(it++); 102 players_.erase(it++);
103 else 103 else
104 ++it; 104 ++it;
105 } 105 }
106 106
107 AbandonSystemAudioFocusIfNeeded(); 107 AbandonSystemAudioFocusIfNeeded();
108 } 108 }
109 109
110 void MediaSession::OnSuspend(JNIEnv* env, jobject obj, jboolean temporary) { 110 void MediaSession::OnSuspend(JNIEnv* env, jobject obj, jboolean temporary) {
111 OnSuspendInternal(temporary); 111 if (audio_focus_state_ != State::ACTIVE)
112 return;
113
114 OnSuspendInternal(SuspendType::SYSTEM);
115 if (!temporary)
116 audio_focus_state_ = State::INACTIVE;
112 UpdateWebContents(); 117 UpdateWebContents();
113 } 118 }
114 119
115 void MediaSession::OnResume(JNIEnv* env, jobject obj) { 120 void MediaSession::OnResume(JNIEnv* env, jobject obj) {
116 OnResumeInternal(); 121 if (audio_focus_state_ != State::SUSPENDED)
122 return;
123
124 OnResumeInternal(SuspendType::SYSTEM);
117 UpdateWebContents(); 125 UpdateWebContents();
118 } 126 }
119 127
120 void MediaSession::Resume() { 128 void MediaSession::Resume() {
121 DCHECK(IsSuspended()); 129 DCHECK(IsSuspended());
122 130
123 OnResumeInternal(); 131 OnResumeInternal(SuspendType::UI);
124 } 132 }
125 133
126 void MediaSession::Suspend() { 134 void MediaSession::Suspend() {
127 DCHECK(!IsSuspended()); 135 DCHECK(!IsSuspended());
128 136
129 // Since the playback can be resumed, it's a transient suspension. 137 OnSuspendInternal(SuspendType::UI);
130 OnSuspendInternal(true);
131 } 138 }
132 139
133 bool MediaSession::IsSuspended() const { 140 bool MediaSession::IsSuspended() const {
134 return audio_focus_state_ != State::Active; 141 // TODO(mlamouri): should be == State::SUSPENDED.
142 return audio_focus_state_ != State::ACTIVE;
135 } 143 }
136 144
137 bool MediaSession::IsControllable() const { 145 bool MediaSession::IsControllable() const {
138 // Only content type media session can be controllable unless it's stopped. 146 // Only content type media session can be controllable unless it is inactive.
139 return audio_focus_state_ != State::Suspended && 147 return audio_focus_state_ != State::INACTIVE &&
140 audio_focus_type_ == Type::Content; 148 audio_focus_type_ == Type::Content;
141 } 149 }
142 150
143 void MediaSession::ResetJavaRefForTest() { 151 void MediaSession::ResetJavaRefForTest() {
144 j_media_session_.Reset(); 152 j_media_session_.Reset();
145 } 153 }
146 154
147 bool MediaSession::IsActiveForTest() const { 155 bool MediaSession::IsActiveForTest() const {
148 return audio_focus_state_ == State::Active; 156 return audio_focus_state_ == State::ACTIVE;
149 } 157 }
150 158
151 MediaSession::Type MediaSession::audio_focus_type_for_test() const { 159 MediaSession::Type MediaSession::audio_focus_type_for_test() const {
152 return audio_focus_type_; 160 return audio_focus_type_;
153 } 161 }
154 162
155 void MediaSession::RemoveAllPlayersForTest() { 163 void MediaSession::RemoveAllPlayersForTest() {
156 players_.clear(); 164 players_.clear();
157 AbandonSystemAudioFocusIfNeeded(); 165 AbandonSystemAudioFocusIfNeeded();
158 } 166 }
159 167
160 void MediaSession::OnSuspendInternal(bool temporary) { 168 void MediaSession::OnSuspendInternal(SuspendType type) {
161 if (temporary) 169 audio_focus_state_ = State::SUSPENDED;
162 audio_focus_state_ = State::TemporarilySuspended; 170 suspend_type_ = type;
163 else
164 audio_focus_state_ = State::Suspended;
165 171
166 for (const auto& it : players_) 172 for (const auto& it : players_)
167 it.observer->OnSuspend(it.player_id); 173 it.observer->OnSuspend(it.player_id);
168 } 174 }
169 175
170 void MediaSession::OnResumeInternal() { 176 void MediaSession::OnResumeInternal(SuspendType type) {
171 audio_focus_state_ = State::Active; 177 if (suspend_type_ != type && type != SuspendType::UI)
178 return;
179
180 audio_focus_state_ = State::ACTIVE;
172 181
173 for (const auto& it : players_) 182 for (const auto& it : players_)
174 it.observer->OnResume(it.player_id); 183 it.observer->OnResume(it.player_id);
175 } 184 }
176 185
177 MediaSession::MediaSession(WebContents* web_contents) 186 MediaSession::MediaSession(WebContents* web_contents)
178 : WebContentsObserver(web_contents), 187 : WebContentsObserver(web_contents),
179 audio_focus_state_(State::Suspended), 188 audio_focus_state_(State::INACTIVE),
180 audio_focus_type_(Type::Transient) {} 189 audio_focus_type_(Type::Transient) {}
181 190
182 void MediaSession::Initialize() { 191 void MediaSession::Initialize() {
183 JNIEnv* env = base::android::AttachCurrentThread(); 192 JNIEnv* env = base::android::AttachCurrentThread();
184 DCHECK(env); 193 DCHECK(env);
185 j_media_session_.Reset(Java_MediaSession_createMediaSession( 194 j_media_session_.Reset(Java_MediaSession_createMediaSession(
186 env, 195 env,
187 base::android::GetApplicationContext(), 196 base::android::GetApplicationContext(),
188 reinterpret_cast<intptr_t>(this))); 197 reinterpret_cast<intptr_t>(this)));
189 } 198 }
190 199
191 bool MediaSession::RequestSystemAudioFocus(Type type) { 200 bool MediaSession::RequestSystemAudioFocus(Type type) {
192 // During tests, j_media_session_ might be null. 201 // During tests, j_media_session_ might be null.
193 if (j_media_session_.is_null()) 202 if (j_media_session_.is_null())
194 return true; 203 return true;
195 204
196 JNIEnv* env = base::android::AttachCurrentThread(); 205 JNIEnv* env = base::android::AttachCurrentThread();
197 DCHECK(env); 206 DCHECK(env);
198 return Java_MediaSession_requestAudioFocus(env, j_media_session_.obj(), 207 return Java_MediaSession_requestAudioFocus(env, j_media_session_.obj(),
199 type == Type::Transient); 208 type == Type::Transient);
200 } 209 }
201 210
202 void MediaSession::AbandonSystemAudioFocusIfNeeded() { 211 void MediaSession::AbandonSystemAudioFocusIfNeeded() {
203 if (audio_focus_state_ == State::Suspended || !players_.empty()) 212 if (audio_focus_state_ == State::INACTIVE || !players_.empty())
204 return; 213 return;
205 214
206 // During tests, j_media_session_ might be null. 215 // During tests, j_media_session_ might be null.
207 if (!j_media_session_.is_null()) { 216 if (!j_media_session_.is_null()) {
208 JNIEnv* env = base::android::AttachCurrentThread(); 217 JNIEnv* env = base::android::AttachCurrentThread();
209 DCHECK(env); 218 DCHECK(env);
210 Java_MediaSession_abandonAudioFocus(env, j_media_session_.obj()); 219 Java_MediaSession_abandonAudioFocus(env, j_media_session_.obj());
211 } 220 }
212 221
213 audio_focus_state_ = State::Suspended; 222 audio_focus_state_ = State::INACTIVE;
214 UpdateWebContents(); 223 UpdateWebContents();
215 } 224 }
216 225
217 void MediaSession::UpdateWebContents() { 226 void MediaSession::UpdateWebContents() {
218 static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged(); 227 static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged();
219 } 228 }
220 229
221 } // namespace content 230 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/media/android/media_session.h ('k') | content/browser/media/android/media_session_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698