OLD | NEW |
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/session/media_session.h" | 5 #include "content/browser/media/session/media_session.h" |
6 | 6 |
7 #include "content/browser/media/session/media_session_delegate.h" | 7 #include "content/browser/media/session/media_session_delegate.h" |
8 #include "content/browser/media/session/media_session_observer.h" | 8 #include "content/browser/media/session/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" |
11 #include "content/public/browser/web_contents_delegate.h" | 11 #include "content/public/browser/web_contents_delegate.h" |
| 12 #include "media/base/media_content_type.h" |
12 | 13 |
13 namespace content { | 14 namespace content { |
14 | 15 |
15 namespace { | 16 namespace { |
16 | 17 |
17 const double kDefaultVolumeMultiplier = 1.0; | 18 const double kDefaultVolumeMultiplier = 1.0; |
18 | 19 |
19 } // anonymous namespace | 20 } // anonymous namespace |
20 | 21 |
21 using MediaSessionSuspendedSource = | 22 using MediaSessionSuspendedSource = |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 void MediaSession::SetMetadata(const MediaMetadata& metadata) { | 62 void MediaSession::SetMetadata(const MediaMetadata& metadata) { |
62 metadata_ = metadata; | 63 metadata_ = metadata; |
63 // TODO(zqzhang): On Android, the metadata is sent though JNI everytime the | 64 // TODO(zqzhang): On Android, the metadata is sent though JNI everytime the |
64 // media session play/pause state changes. Need to find a way to seprate the | 65 // media session play/pause state changes. Need to find a way to seprate the |
65 // state change and Metadata update. See https://crbug.com/621855. | 66 // state change and Metadata update. See https://crbug.com/621855. |
66 static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged(); | 67 static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged(); |
67 } | 68 } |
68 | 69 |
69 bool MediaSession::AddPlayer(MediaSessionObserver* observer, | 70 bool MediaSession::AddPlayer(MediaSessionObserver* observer, |
70 int player_id, | 71 int player_id, |
71 Type type) { | 72 media::MediaContentType media_content_type) { |
72 observer->OnSetVolumeMultiplier(player_id, volume_multiplier_); | 73 observer->OnSetVolumeMultiplier(player_id, volume_multiplier_); |
73 | 74 |
| 75 // Determine the audio focus type required for playing the new player. |
| 76 // TODO(zqzhang): handle duckable and uncontrollable. |
| 77 // See https://crbug.com/639277. |
| 78 AudioFocusManager::AudioFocusType required_audio_focus_type; |
| 79 if (media_content_type == media::MediaContentType::Persistent) { |
| 80 required_audio_focus_type = AudioFocusManager::AudioFocusType::Gain; |
| 81 } else { |
| 82 required_audio_focus_type = |
| 83 AudioFocusManager::AudioFocusType::GainTransientMayDuck; |
| 84 } |
| 85 |
74 // If the audio focus is already granted and is of type Content, there is | 86 // If the audio focus is already granted and is of type Content, there is |
75 // nothing to do. If it is granted of type Transient the requested type is | 87 // nothing to do. If it is granted of type Transient the requested type is |
76 // also transient, there is also nothing to do. Otherwise, the session needs | 88 // also transient, there is also nothing to do. Otherwise, the session needs |
77 // to request audio focus again. | 89 // to request audio focus again. |
78 if (audio_focus_state_ == State::ACTIVE && | 90 if (audio_focus_state_ == State::ACTIVE && |
79 (audio_focus_type_ == Type::Content || audio_focus_type_ == type)) { | 91 (audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain || |
| 92 audio_focus_type_ == required_audio_focus_type)) { |
80 players_.insert(PlayerIdentifier(observer, player_id)); | 93 players_.insert(PlayerIdentifier(observer, player_id)); |
81 return true; | 94 return true; |
82 } | 95 } |
83 | 96 |
84 State old_audio_focus_state = audio_focus_state_; | 97 State old_audio_focus_state = audio_focus_state_; |
85 State audio_focus_state = RequestSystemAudioFocus(type) ? State::ACTIVE | 98 State audio_focus_state = RequestSystemAudioFocus(required_audio_focus_type) |
86 : State::INACTIVE; | 99 ? State::ACTIVE |
| 100 : State::INACTIVE; |
87 SetAudioFocusState(audio_focus_state); | 101 SetAudioFocusState(audio_focus_state); |
88 audio_focus_type_ = type; | 102 audio_focus_type_ = required_audio_focus_type; |
89 | 103 |
90 if (audio_focus_state_ != State::ACTIVE) | 104 if (audio_focus_state_ != State::ACTIVE) |
91 return false; | 105 return false; |
92 | 106 |
93 // The session should be reset if a player is starting while all players are | 107 // The session should be reset if a player is starting while all players are |
94 // suspended. | 108 // suspended. |
95 if (old_audio_focus_state != State::ACTIVE) | 109 if (old_audio_focus_state != State::ACTIVE) |
96 players_.clear(); | 110 players_.clear(); |
97 | 111 |
98 players_.insert(PlayerIdentifier(observer, player_id)); | 112 players_.insert(PlayerIdentifier(observer, player_id)); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 if (players_.size() != 1) { | 154 if (players_.size() != 1) { |
141 RemovePlayer(observer, player_id); | 155 RemovePlayer(observer, player_id); |
142 return; | 156 return; |
143 } | 157 } |
144 | 158 |
145 // Otherwise, suspend the session. | 159 // Otherwise, suspend the session. |
146 DCHECK(!IsSuspended()); | 160 DCHECK(!IsSuspended()); |
147 OnSuspendInternal(SuspendType::CONTENT, State::SUSPENDED); | 161 OnSuspendInternal(SuspendType::CONTENT, State::SUSPENDED); |
148 } | 162 } |
149 | 163 |
150 void MediaSession::Resume(SuspendType type) { | 164 void MediaSession::Resume(SuspendType suspend_type) { |
151 DCHECK(IsReallySuspended()); | 165 DCHECK(IsReallySuspended()); |
152 | 166 |
153 // When the resume requests comes from another source than system, audio focus | 167 // When the resume requests comes from another source than system, audio focus |
154 // must be requested. | 168 // must be requested. |
155 if (type != SuspendType::SYSTEM) { | 169 if (suspend_type != SuspendType::SYSTEM) { |
156 // Request audio focus again in case we lost it because another app started | 170 // Request audio focus again in case we lost it because another app started |
157 // playing while the playback was paused. | 171 // playing while the playback was paused. |
158 State audio_focus_state = RequestSystemAudioFocus(audio_focus_type_) | 172 State audio_focus_state = RequestSystemAudioFocus(audio_focus_type_) |
159 ? State::ACTIVE | 173 ? State::ACTIVE |
160 : State::INACTIVE; | 174 : State::INACTIVE; |
161 SetAudioFocusState(audio_focus_state); | 175 SetAudioFocusState(audio_focus_state); |
162 | 176 |
163 if (audio_focus_state_ != State::ACTIVE) | 177 if (audio_focus_state_ != State::ACTIVE) |
164 return; | 178 return; |
165 } | 179 } |
166 | 180 |
167 OnResumeInternal(type); | 181 OnResumeInternal(suspend_type); |
168 } | 182 } |
169 | 183 |
170 void MediaSession::Suspend(SuspendType type) { | 184 void MediaSession::Suspend(SuspendType suspend_type) { |
171 DCHECK(!IsSuspended()); | 185 DCHECK(!IsSuspended()); |
172 | 186 |
173 OnSuspendInternal(type, State::SUSPENDED); | 187 OnSuspendInternal(suspend_type, State::SUSPENDED); |
174 } | 188 } |
175 | 189 |
176 void MediaSession::Stop(SuspendType type) { | 190 void MediaSession::Stop(SuspendType suspend_type) { |
177 DCHECK(audio_focus_state_ != State::INACTIVE); | 191 DCHECK(audio_focus_state_ != State::INACTIVE); |
178 | 192 |
179 DCHECK(type != SuspendType::CONTENT); | 193 DCHECK(suspend_type != SuspendType::CONTENT); |
180 | 194 |
181 // TODO(mlamouri): merge the logic between UI and SYSTEM. | 195 // TODO(mlamouri): merge the logic between UI and SYSTEM. |
182 if (type == SuspendType::SYSTEM) { | 196 if (suspend_type == SuspendType::SYSTEM) { |
183 OnSuspendInternal(type, State::INACTIVE); | 197 OnSuspendInternal(suspend_type, State::INACTIVE); |
184 return; | 198 return; |
185 } | 199 } |
186 | 200 |
187 if (audio_focus_state_ != State::SUSPENDED) | 201 if (audio_focus_state_ != State::SUSPENDED) |
188 OnSuspendInternal(type, State::SUSPENDED); | 202 OnSuspendInternal(suspend_type, State::SUSPENDED); |
189 | 203 |
190 DCHECK(audio_focus_state_ == State::SUSPENDED); | 204 DCHECK(audio_focus_state_ == State::SUSPENDED); |
191 players_.clear(); | 205 players_.clear(); |
192 AbandonSystemAudioFocusIfNeeded(); | 206 AbandonSystemAudioFocusIfNeeded(); |
193 } | 207 } |
194 | 208 |
195 void MediaSession::SetVolumeMultiplier(double volume_multiplier) { | 209 void MediaSession::SetVolumeMultiplier(double volume_multiplier) { |
196 volume_multiplier_ = volume_multiplier; | 210 volume_multiplier_ = volume_multiplier; |
197 for (const auto& it : players_) | 211 for (const auto& it : players_) |
198 it.observer->OnSetVolumeMultiplier(it.player_id, volume_multiplier_); | 212 it.observer->OnSetVolumeMultiplier(it.player_id, volume_multiplier_); |
199 } | 213 } |
200 | 214 |
201 bool MediaSession::IsActive() const { | 215 bool MediaSession::IsActive() const { |
202 return audio_focus_state_ == State::ACTIVE; | 216 return audio_focus_state_ == State::ACTIVE; |
203 } | 217 } |
204 | 218 |
205 bool MediaSession::IsReallySuspended() const { | 219 bool MediaSession::IsReallySuspended() const { |
206 return audio_focus_state_ == State::SUSPENDED; | 220 return audio_focus_state_ == State::SUSPENDED; |
207 } | 221 } |
208 | 222 |
209 bool MediaSession::IsSuspended() const { | 223 bool MediaSession::IsSuspended() const { |
210 // TODO(mlamouri): should be == State::SUSPENDED. | 224 // TODO(mlamouri): should be == State::SUSPENDED. |
211 return audio_focus_state_ != State::ACTIVE; | 225 return audio_focus_state_ != State::ACTIVE; |
212 } | 226 } |
213 | 227 |
214 bool MediaSession::IsControllable() const { | 228 bool MediaSession::IsControllable() const { |
215 // Only content type media session can be controllable unless it is inactive. | 229 // Only media session having focus Gain can be controllable unless it is |
| 230 // inactive. |
216 return audio_focus_state_ != State::INACTIVE && | 231 return audio_focus_state_ != State::INACTIVE && |
217 audio_focus_type_ == Type::Content; | 232 audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain; |
218 } | 233 } |
219 | 234 |
220 std::unique_ptr<base::CallbackList<void(MediaSession::State)>::Subscription> | 235 std::unique_ptr<base::CallbackList<void(MediaSession::State)>::Subscription> |
221 MediaSession::RegisterMediaSessionStateChangedCallbackForTest( | 236 MediaSession::RegisterMediaSessionStateChangedCallbackForTest( |
222 const StateChangedCallback& cb) { | 237 const StateChangedCallback& cb) { |
223 return media_session_state_listeners_.Add(cb); | 238 return media_session_state_listeners_.Add(cb); |
224 } | 239 } |
225 | 240 |
226 void MediaSession::SetDelegateForTests( | 241 void MediaSession::SetDelegateForTests( |
227 std::unique_ptr<MediaSessionDelegate> delegate) { | 242 std::unique_ptr<MediaSessionDelegate> delegate) { |
228 delegate_ = std::move(delegate); | 243 delegate_ = std::move(delegate); |
229 } | 244 } |
230 | 245 |
231 bool MediaSession::IsActiveForTest() const { | 246 bool MediaSession::IsActiveForTest() const { |
232 return audio_focus_state_ == State::ACTIVE; | 247 return audio_focus_state_ == State::ACTIVE; |
233 } | 248 } |
234 | 249 |
235 MediaSession::Type MediaSession::audio_focus_type_for_test() const { | 250 AudioFocusManager::AudioFocusType MediaSession::audio_focus_type_for_test() |
| 251 const { |
236 return audio_focus_type_; | 252 return audio_focus_type_; |
237 } | 253 } |
238 | 254 |
239 MediaSessionUmaHelper* MediaSession::uma_helper_for_test() { | 255 MediaSessionUmaHelper* MediaSession::uma_helper_for_test() { |
240 return &uma_helper_; | 256 return &uma_helper_; |
241 } | 257 } |
242 | 258 |
243 void MediaSession::RemoveAllPlayersForTest() { | 259 void MediaSession::RemoveAllPlayersForTest() { |
244 players_.clear(); | 260 players_.clear(); |
245 AbandonSystemAudioFocusIfNeeded(); | 261 AbandonSystemAudioFocusIfNeeded(); |
246 } | 262 } |
247 | 263 |
248 void MediaSession::OnSuspendInternal(SuspendType type, State new_state) { | 264 void MediaSession::OnSuspendInternal(SuspendType suspend_type, |
| 265 State new_state) { |
249 DCHECK(new_state == State::SUSPENDED || new_state == State::INACTIVE); | 266 DCHECK(new_state == State::SUSPENDED || new_state == State::INACTIVE); |
250 // UI suspend cannot use State::INACTIVE. | 267 // UI suspend cannot use State::INACTIVE. |
251 DCHECK(type == SuspendType::SYSTEM || new_state == State::SUSPENDED); | 268 DCHECK(suspend_type == SuspendType::SYSTEM || new_state == State::SUSPENDED); |
252 | 269 |
253 if (audio_focus_state_ != State::ACTIVE) | 270 if (audio_focus_state_ != State::ACTIVE) |
254 return; | 271 return; |
255 | 272 |
256 switch (type) { | 273 switch (suspend_type) { |
257 case SuspendType::UI: | 274 case SuspendType::UI: |
258 uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::UI); | 275 uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::UI); |
259 break; | 276 break; |
260 case SuspendType::SYSTEM: | 277 case SuspendType::SYSTEM: |
261 switch (new_state) { | 278 switch (new_state) { |
262 case State::SUSPENDED: | 279 case State::SUSPENDED: |
263 uma_helper_.RecordSessionSuspended( | 280 uma_helper_.RecordSessionSuspended( |
264 MediaSessionSuspendedSource::SystemTransient); | 281 MediaSessionSuspendedSource::SystemTransient); |
265 break; | 282 break; |
266 case State::INACTIVE: | 283 case State::INACTIVE: |
267 uma_helper_.RecordSessionSuspended( | 284 uma_helper_.RecordSessionSuspended( |
268 MediaSessionSuspendedSource::SystemPermanent); | 285 MediaSessionSuspendedSource::SystemPermanent); |
269 break; | 286 break; |
270 case State::ACTIVE: | 287 case State::ACTIVE: |
271 NOTREACHED(); | 288 NOTREACHED(); |
272 break; | 289 break; |
273 } | 290 } |
274 break; | 291 break; |
275 case SuspendType::CONTENT: | 292 case SuspendType::CONTENT: |
276 uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::CONTENT); | 293 uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::CONTENT); |
277 break; | 294 break; |
278 } | 295 } |
279 | 296 |
280 SetAudioFocusState(new_state); | 297 SetAudioFocusState(new_state); |
281 suspend_type_ = type; | 298 suspend_type_ = suspend_type; |
282 | 299 |
283 if (type != SuspendType::CONTENT) { | 300 if (suspend_type != SuspendType::CONTENT) { |
284 // SuspendType::CONTENT happens when the suspend action came from | 301 // SuspendType::CONTENT happens when the suspend action came from |
285 // the page in which case the player is already paused. | 302 // the page in which case the player is already paused. |
286 // Otherwise, the players need to be paused. | 303 // Otherwise, the players need to be paused. |
287 for (const auto& it : players_) | 304 for (const auto& it : players_) |
288 it.observer->OnSuspend(it.player_id); | 305 it.observer->OnSuspend(it.player_id); |
289 } | 306 } |
290 | 307 |
291 UpdateWebContents(); | 308 UpdateWebContents(); |
292 } | 309 } |
293 | 310 |
294 void MediaSession::OnResumeInternal(SuspendType type) { | 311 void MediaSession::OnResumeInternal(SuspendType suspend_type) { |
295 if (type == SuspendType::SYSTEM && suspend_type_ != type) | 312 if (suspend_type == SuspendType::SYSTEM && suspend_type_ != suspend_type) |
296 return; | 313 return; |
297 | 314 |
298 SetAudioFocusState(State::ACTIVE); | 315 SetAudioFocusState(State::ACTIVE); |
299 | 316 |
300 for (const auto& it : players_) | 317 for (const auto& it : players_) |
301 it.observer->OnResume(it.player_id); | 318 it.observer->OnResume(it.player_id); |
302 | 319 |
303 UpdateWebContents(); | 320 UpdateWebContents(); |
304 } | 321 } |
305 | 322 |
306 MediaSession::MediaSession(WebContents* web_contents) | 323 MediaSession::MediaSession(WebContents* web_contents) |
307 : WebContentsObserver(web_contents), | 324 : WebContentsObserver(web_contents), |
308 audio_focus_state_(State::INACTIVE), | 325 audio_focus_state_(State::INACTIVE), |
309 audio_focus_type_(Type::Transient), | 326 audio_focus_type_( |
310 volume_multiplier_(kDefaultVolumeMultiplier) { | 327 AudioFocusManager::AudioFocusType::GainTransientMayDuck), |
311 } | 328 volume_multiplier_(kDefaultVolumeMultiplier) {} |
312 | 329 |
313 void MediaSession::Initialize() { | 330 void MediaSession::Initialize() { |
314 delegate_ = MediaSessionDelegate::Create(this); | 331 delegate_ = MediaSessionDelegate::Create(this); |
315 } | 332 } |
316 | 333 |
317 bool MediaSession::RequestSystemAudioFocus(Type type) { | 334 bool MediaSession::RequestSystemAudioFocus( |
318 bool result = delegate_->RequestAudioFocus(type); | 335 AudioFocusManager::AudioFocusType audio_focus_type) { |
| 336 bool result = delegate_->RequestAudioFocus(audio_focus_type); |
319 uma_helper_.RecordRequestAudioFocusResult(result); | 337 uma_helper_.RecordRequestAudioFocusResult(result); |
320 return result; | 338 return result; |
321 } | 339 } |
322 | 340 |
323 void MediaSession::AbandonSystemAudioFocusIfNeeded() { | 341 void MediaSession::AbandonSystemAudioFocusIfNeeded() { |
324 if (audio_focus_state_ == State::INACTIVE || !players_.empty()) | 342 if (audio_focus_state_ == State::INACTIVE || !players_.empty()) |
325 return; | 343 return; |
326 | 344 |
327 delegate_->AbandonAudioFocus(); | 345 delegate_->AbandonAudioFocus(); |
328 | 346 |
(...skipping 18 matching lines...) Expand all Loading... |
347 case State::SUSPENDED: | 365 case State::SUSPENDED: |
348 uma_helper_.OnSessionSuspended(); | 366 uma_helper_.OnSessionSuspended(); |
349 break; | 367 break; |
350 case State::INACTIVE: | 368 case State::INACTIVE: |
351 uma_helper_.OnSessionInactive(); | 369 uma_helper_.OnSessionInactive(); |
352 break; | 370 break; |
353 } | 371 } |
354 } | 372 } |
355 | 373 |
356 } // namespace content | 374 } // namespace content |
OLD | NEW |