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

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: add tests 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
(...skipping 17 matching lines...) Expand all
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(SuspendType type) {
121 DCHECK(IsSuspended()); 129 DCHECK(IsSuspended());
122 130
123 OnResumeInternal(); 131 OnResumeInternal(type);
124 } 132 }
125 133
126 void MediaSession::Suspend() { 134 void MediaSession::Suspend(SuspendType type) {
127 DCHECK(!IsSuspended()); 135 DCHECK(!IsSuspended());
128 136
129 // Since the playback can be resumed, it's a transient suspension. 137 // Since the playback can be resumed, it's a transient suspension.
130 OnSuspendInternal(true); 138 OnSuspendInternal(type);
131 } 139 }
132 140
133 bool MediaSession::IsSuspended() const { 141 bool MediaSession::IsSuspended() const {
142 // TODO(mlamouri): should be == State::Suspended.
134 return audio_focus_state_ != State::Active; 143 return audio_focus_state_ != State::Active;
135 } 144 }
136 145
137 bool MediaSession::IsControllable() const { 146 bool MediaSession::IsControllable() const {
138 // Only content type media session can be controllable unless it's stopped. 147 // Only content type media session can be controllable unless it is inactive.
139 return audio_focus_state_ != State::Suspended && 148 return audio_focus_state_ != State::Inactive &&
140 audio_focus_type_ == Type::Content; 149 audio_focus_type_ == Type::Content;
141 } 150 }
142 151
143 void MediaSession::ResetJavaRefForTest() { 152 void MediaSession::ResetJavaRefForTest() {
144 j_media_session_.Reset(); 153 j_media_session_.Reset();
145 } 154 }
146 155
147 bool MediaSession::IsActiveForTest() const { 156 bool MediaSession::IsActiveForTest() const {
148 return audio_focus_state_ == State::Active; 157 return audio_focus_state_ == State::Active;
149 } 158 }
150 159
151 MediaSession::Type MediaSession::audio_focus_type_for_test() const { 160 MediaSession::Type MediaSession::audio_focus_type_for_test() const {
152 return audio_focus_type_; 161 return audio_focus_type_;
153 } 162 }
154 163
155 void MediaSession::RemoveAllPlayersForTest() { 164 void MediaSession::RemoveAllPlayersForTest() {
156 players_.clear(); 165 players_.clear();
157 AbandonSystemAudioFocusIfNeeded(); 166 AbandonSystemAudioFocusIfNeeded();
158 } 167 }
159 168
160 void MediaSession::OnSuspendInternal(bool temporary) { 169 void MediaSession::OnSuspendInternal(SuspendType type) {
161 if (temporary) 170 audio_focus_state_ = State::Suspended;
162 audio_focus_state_ = State::TemporarilySuspended; 171 suspend_type_ = type;
163 else
164 audio_focus_state_ = State::Suspended;
165 172
166 for (const auto& it : players_) 173 for (const auto& it : players_)
167 it.observer->OnSuspend(it.player_id); 174 it.observer->OnSuspend(it.player_id);
168 } 175 }
169 176
170 void MediaSession::OnResumeInternal() { 177 void MediaSession::OnResumeInternal(SuspendType type) {
178 if (suspend_type_ != type && type != SuspendType::UI)
179 return;
180
171 audio_focus_state_ = State::Active; 181 audio_focus_state_ = State::Active;
172 182
173 for (const auto& it : players_) 183 for (const auto& it : players_)
174 it.observer->OnResume(it.player_id); 184 it.observer->OnResume(it.player_id);
175 } 185 }
176 186
177 MediaSession::MediaSession(WebContents* web_contents) 187 MediaSession::MediaSession(WebContents* web_contents)
178 : WebContentsObserver(web_contents), 188 : WebContentsObserver(web_contents),
179 audio_focus_state_(State::Suspended), 189 audio_focus_state_(State::Inactive),
180 audio_focus_type_(Type::Transient) {} 190 audio_focus_type_(Type::Transient) {}
181 191
182 void MediaSession::Initialize() { 192 void MediaSession::Initialize() {
183 JNIEnv* env = base::android::AttachCurrentThread(); 193 JNIEnv* env = base::android::AttachCurrentThread();
184 DCHECK(env); 194 DCHECK(env);
185 j_media_session_.Reset(Java_MediaSession_createMediaSession( 195 j_media_session_.Reset(Java_MediaSession_createMediaSession(
186 env, 196 env,
187 base::android::GetApplicationContext(), 197 base::android::GetApplicationContext(),
188 reinterpret_cast<intptr_t>(this))); 198 reinterpret_cast<intptr_t>(this)));
189 } 199 }
190 200
191 bool MediaSession::RequestSystemAudioFocus(Type type) { 201 bool MediaSession::RequestSystemAudioFocus(Type type) {
192 // During tests, j_media_session_ might be null. 202 // During tests, j_media_session_ might be null.
193 if (j_media_session_.is_null()) 203 if (j_media_session_.is_null())
194 return true; 204 return true;
195 205
196 JNIEnv* env = base::android::AttachCurrentThread(); 206 JNIEnv* env = base::android::AttachCurrentThread();
197 DCHECK(env); 207 DCHECK(env);
198 return Java_MediaSession_requestAudioFocus(env, j_media_session_.obj(), 208 return Java_MediaSession_requestAudioFocus(env, j_media_session_.obj(),
199 type == Type::Transient); 209 type == Type::Transient);
200 } 210 }
201 211
202 void MediaSession::AbandonSystemAudioFocusIfNeeded() { 212 void MediaSession::AbandonSystemAudioFocusIfNeeded() {
203 if (audio_focus_state_ == State::Suspended || !players_.empty()) 213 if (audio_focus_state_ == State::Inactive || !players_.empty())
204 return; 214 return;
205 215
206 // During tests, j_media_session_ might be null. 216 // During tests, j_media_session_ might be null.
207 if (!j_media_session_.is_null()) { 217 if (!j_media_session_.is_null()) {
208 JNIEnv* env = base::android::AttachCurrentThread(); 218 JNIEnv* env = base::android::AttachCurrentThread();
209 DCHECK(env); 219 DCHECK(env);
210 Java_MediaSession_abandonAudioFocus(env, j_media_session_.obj()); 220 Java_MediaSession_abandonAudioFocus(env, j_media_session_.obj());
211 } 221 }
212 222
213 audio_focus_state_ = State::Suspended; 223 audio_focus_state_ = State::Inactive;
214 UpdateWebContents(); 224 UpdateWebContents();
215 } 225 }
216 226
217 void MediaSession::UpdateWebContents() { 227 void MediaSession::UpdateWebContents() {
218 static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged(); 228 static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged();
219 } 229 }
220 230
221 } // namespace content 231 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698