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

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

Issue 2274873003: Letting Flash join MediaSession (stack implementaion) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@media_session_type
Patch Set: addressed Anton's comments Created 4 years, 2 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/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"
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 session->Initialize(); 53 session->Initialize();
54 } 54 }
55 return session; 55 return session;
56 } 56 }
57 57
58 MediaSession::~MediaSession() { 58 MediaSession::~MediaSession() {
59 DCHECK(players_.empty()); 59 DCHECK(players_.empty());
60 DCHECK(audio_focus_state_ == State::INACTIVE); 60 DCHECK(audio_focus_state_ == State::INACTIVE);
61 } 61 }
62 62
63 void MediaSession::WebContentsDestroyed() {
64 // This should only work for tests. In production, all the players should have
65 // already been removed before WebContents is destroyed.
66
67 // TODO(zqzhang): refactor MediaSession, maybe move the interface used to talk
68 // with AudioFocusManager out to a seperate class. The AudioFocusManager unit
69 // tests then could mock the interface and abandon audio focus when
70 // WebContents is destroyed. See https://crbug.com/651069
71 players_.clear();
72 pepper_players_.clear();
73 AbandonSystemAudioFocusIfNeeded();
74 }
75
63 void MediaSession::SetMetadata(const base::Optional<MediaMetadata>& metadata) { 76 void MediaSession::SetMetadata(const base::Optional<MediaMetadata>& metadata) {
64 metadata_ = metadata; 77 metadata_ = metadata;
65 // TODO(zqzhang): On Android, the metadata is sent though JNI everytime the 78 // TODO(zqzhang): On Android, the metadata is sent though JNI everytime the
66 // media session play/pause state changes. Need to find a way to seprate the 79 // media session play/pause state changes. Need to find a way to seprate the
67 // state change and Metadata update. See https://crbug.com/621855. 80 // state change and Metadata update. See https://crbug.com/621855.
68 static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged(); 81 static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged();
69 } 82 }
70 83
71 bool MediaSession::AddPlayer(MediaSessionObserver* observer, 84 bool MediaSession::AddPlayer(MediaSessionObserver* observer,
72 int player_id, 85 int player_id,
73 media::MediaContentType media_content_type) { 86 media::MediaContentType media_content_type) {
87 if (media_content_type == media::MediaContentType::Pepper)
88 return AddPepperPlayer(observer, player_id);
89
74 observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier()); 90 observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier());
75 91
76 // Determine the audio focus type required for playing the new player. 92 // Determine the audio focus type required for playing the new player.
77 // TODO(zqzhang): handle duckable and uncontrollable. 93 // TODO(zqzhang): handle duckable and uncontrollable.
78 // See https://crbug.com/639277. 94 // See https://crbug.com/639277.
79 AudioFocusManager::AudioFocusType required_audio_focus_type; 95 AudioFocusManager::AudioFocusType required_audio_focus_type;
80 if (media_content_type == media::MediaContentType::Persistent) { 96 if (media_content_type == media::MediaContentType::Persistent) {
81 required_audio_focus_type = AudioFocusManager::AudioFocusType::Gain; 97 required_audio_focus_type = AudioFocusManager::AudioFocusType::Gain;
82 } else { 98 } else {
83 required_audio_focus_type = 99 required_audio_focus_type =
84 AudioFocusManager::AudioFocusType::GainTransientMayDuck; 100 AudioFocusManager::AudioFocusType::GainTransientMayDuck;
85 } 101 }
86 102
87 // If the audio focus is already granted and is of type Content, there is 103 // If the audio focus is already granted and is of type Content, there is
88 // nothing to do. If it is granted of type Transient the requested type is 104 // nothing to do. If it is granted of type Transient the requested type is
89 // also transient, there is also nothing to do. Otherwise, the session needs 105 // also transient, there is also nothing to do. Otherwise, the session needs
90 // to request audio focus again. 106 // to request audio focus again.
91 if (audio_focus_state_ == State::ACTIVE && 107 if (audio_focus_state_ == State::ACTIVE &&
92 (audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain || 108 (audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain ||
93 audio_focus_type_ == required_audio_focus_type)) { 109 audio_focus_type_ == required_audio_focus_type)) {
94 players_.insert(PlayerIdentifier(observer, player_id)); 110 players_.insert(PlayerIdentifier(observer, player_id));
95 return true; 111 return true;
96 } 112 }
97 113
98 State old_audio_focus_state = audio_focus_state_; 114 State old_audio_focus_state = audio_focus_state_;
99 State audio_focus_state = RequestSystemAudioFocus(required_audio_focus_type) 115 RequestSystemAudioFocus(required_audio_focus_type);
100 ? State::ACTIVE
101 : State::INACTIVE;
102 SetAudioFocusState(audio_focus_state);
103 audio_focus_type_ = required_audio_focus_type;
104 116
105 if (audio_focus_state_ != State::ACTIVE) 117 if (audio_focus_state_ != State::ACTIVE)
106 return false; 118 return false;
107 119
108 // The session should be reset if a player is starting while all players are 120 // The session should be reset if a player is starting while all players are
109 // suspended. 121 // suspended.
110 if (old_audio_focus_state != State::ACTIVE) 122 if (old_audio_focus_state != State::ACTIVE)
111 players_.clear(); 123 players_.clear();
112 124
113 players_.insert(PlayerIdentifier(observer, player_id)); 125 players_.insert(PlayerIdentifier(observer, player_id));
114 UpdateWebContents(); 126 UpdateWebContents();
115 127
116 return true; 128 return true;
117 } 129 }
118 130
119 void MediaSession::RemovePlayer(MediaSessionObserver* observer, 131 void MediaSession::RemovePlayer(MediaSessionObserver* observer,
120 int player_id) { 132 int player_id) {
121 auto it = players_.find(PlayerIdentifier(observer, player_id)); 133 auto it = players_.find(PlayerIdentifier(observer, player_id));
122 if (it != players_.end()) 134 if (it != players_.end())
123 players_.erase(it); 135 players_.erase(it);
124 136
137 it = pepper_players_.find(PlayerIdentifier(observer, player_id));
138 if (it != pepper_players_.end())
139 pepper_players_.erase(it);
140
125 AbandonSystemAudioFocusIfNeeded(); 141 AbandonSystemAudioFocusIfNeeded();
126 } 142 }
127 143
128 void MediaSession::RemovePlayers(MediaSessionObserver* observer) { 144 void MediaSession::RemovePlayers(MediaSessionObserver* observer) {
129 for (auto it = players_.begin(); it != players_.end();) { 145 for (auto it = players_.begin(); it != players_.end(); ) {
130 if (it->observer == observer) 146 if (it->observer == observer)
131 players_.erase(it++); 147 players_.erase(it++);
132 else 148 else
133 ++it; 149 ++it;
134 } 150 }
135 151
152 for (auto it = pepper_players_.begin(); it != pepper_players_.end(); ) {
153 if (it->observer == observer)
154 pepper_players_.erase(it++);
155 else
156 ++it;
157 }
158
136 AbandonSystemAudioFocusIfNeeded(); 159 AbandonSystemAudioFocusIfNeeded();
137 } 160 }
138 161
139 void MediaSession::RecordSessionDuck() { 162 void MediaSession::RecordSessionDuck() {
140 uma_helper_.RecordSessionSuspended( 163 uma_helper_.RecordSessionSuspended(
141 MediaSessionSuspendedSource::SystemTransientDuck); 164 MediaSessionSuspendedSource::SystemTransientDuck);
142 } 165 }
143 166
144 void MediaSession::OnPlayerPaused(MediaSessionObserver* observer, 167 void MediaSession::OnPlayerPaused(MediaSessionObserver* observer,
145 int player_id) { 168 int player_id) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 } 206 }
184 207
185 void MediaSession::Suspend(SuspendType suspend_type) { 208 void MediaSession::Suspend(SuspendType suspend_type) {
186 DCHECK(!IsSuspended()); 209 DCHECK(!IsSuspended());
187 210
188 OnSuspendInternal(suspend_type, State::SUSPENDED); 211 OnSuspendInternal(suspend_type, State::SUSPENDED);
189 } 212 }
190 213
191 void MediaSession::Stop(SuspendType suspend_type) { 214 void MediaSession::Stop(SuspendType suspend_type) {
192 DCHECK(audio_focus_state_ != State::INACTIVE); 215 DCHECK(audio_focus_state_ != State::INACTIVE);
193
194 DCHECK(suspend_type != SuspendType::CONTENT); 216 DCHECK(suspend_type != SuspendType::CONTENT);
217 DCHECK(!HasPepper());
195 218
196 // TODO(mlamouri): merge the logic between UI and SYSTEM. 219 // TODO(mlamouri): merge the logic between UI and SYSTEM.
197 if (suspend_type == SuspendType::SYSTEM) { 220 if (suspend_type == SuspendType::SYSTEM) {
198 OnSuspendInternal(suspend_type, State::INACTIVE); 221 OnSuspendInternal(suspend_type, State::INACTIVE);
199 return; 222 return;
200 } 223 }
201 224
202 if (audio_focus_state_ != State::SUSPENDED) 225 if (audio_focus_state_ != State::SUSPENDED)
203 OnSuspendInternal(suspend_type, State::SUSPENDED); 226 OnSuspendInternal(suspend_type, State::SUSPENDED);
204 227
205 DCHECK(audio_focus_state_ == State::SUSPENDED); 228 DCHECK(audio_focus_state_ == State::SUSPENDED);
206 players_.clear(); 229 players_.clear();
230
207 AbandonSystemAudioFocusIfNeeded(); 231 AbandonSystemAudioFocusIfNeeded();
208 } 232 }
209 233
210 void MediaSession::StartDucking() { 234 void MediaSession::StartDucking() {
211 if (is_ducking_) 235 if (is_ducking_)
212 return; 236 return;
213 is_ducking_ = true; 237 is_ducking_ = true;
214 UpdateVolumeMultiplier(); 238 UpdateVolumeMultiplier();
215 } 239 }
216 240
217 void MediaSession::StopDucking() { 241 void MediaSession::StopDucking() {
218 if (!is_ducking_) 242 if (!is_ducking_)
219 return; 243 return;
220 is_ducking_ = false; 244 is_ducking_ = false;
221 UpdateVolumeMultiplier(); 245 UpdateVolumeMultiplier();
222 } 246 }
223 247
224 void MediaSession::UpdateVolumeMultiplier() { 248 void MediaSession::UpdateVolumeMultiplier() {
225 for (const auto& it : players_) 249 for (const auto& it : players_) {
226 it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier()); 250 it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier());
251 }
mlamouri (slow - plz ping) 2016/09/30 09:35:22 style: no { }
Zhiqiang Zhang (Slow) 2016/09/30 10:04:42 Done.
252 for (const auto& it : pepper_players_) {
253 it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier());
254 }
mlamouri (slow - plz ping) 2016/09/30 09:35:22 ditto
Zhiqiang Zhang (Slow) 2016/09/30 10:04:42 Done.
227 } 255 }
228 256
229 double MediaSession::GetVolumeMultiplier() const { 257 double MediaSession::GetVolumeMultiplier() const {
230 return is_ducking_ ? kDuckingVolumeMultiplier : kDefaultVolumeMultiplier; 258 return is_ducking_ ? kDuckingVolumeMultiplier : kDefaultVolumeMultiplier;
231 } 259 }
232 260
233 bool MediaSession::IsActive() const { 261 bool MediaSession::IsActive() const {
234 return audio_focus_state_ == State::ACTIVE; 262 return audio_focus_state_ == State::ACTIVE;
235 } 263 }
236 264
237 bool MediaSession::IsReallySuspended() const { 265 bool MediaSession::IsReallySuspended() const {
238 return audio_focus_state_ == State::SUSPENDED; 266 return audio_focus_state_ == State::SUSPENDED;
239 } 267 }
240 268
241 bool MediaSession::IsSuspended() const { 269 bool MediaSession::IsSuspended() const {
242 // TODO(mlamouri): should be == State::SUSPENDED. 270 // TODO(mlamouri): should be == State::SUSPENDED.
243 return audio_focus_state_ != State::ACTIVE; 271 return audio_focus_state_ != State::ACTIVE;
244 } 272 }
245 273
246 bool MediaSession::IsControllable() const { 274 bool MediaSession::IsControllable() const {
247 // Only media session having focus Gain can be controllable unless it is 275 // Only media session having focus Gain can be controllable unless it is
248 // inactive. 276 // inactive.
249 return audio_focus_state_ != State::INACTIVE && 277 return audio_focus_state_ != State::INACTIVE &&
250 audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain; 278 audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain;
251 } 279 }
252 280
281 bool MediaSession::HasPepper() const {
282 return !pepper_players_.empty();
283 }
284
253 std::unique_ptr<base::CallbackList<void(MediaSession::State)>::Subscription> 285 std::unique_ptr<base::CallbackList<void(MediaSession::State)>::Subscription>
254 MediaSession::RegisterMediaSessionStateChangedCallbackForTest( 286 MediaSession::RegisterMediaSessionStateChangedCallbackForTest(
255 const StateChangedCallback& cb) { 287 const StateChangedCallback& cb) {
256 return media_session_state_listeners_.Add(cb); 288 return media_session_state_listeners_.Add(cb);
257 } 289 }
258 290
259 void MediaSession::SetDelegateForTests( 291 void MediaSession::SetDelegateForTests(
260 std::unique_ptr<MediaSessionDelegate> delegate) { 292 std::unique_ptr<MediaSessionDelegate> delegate) {
261 delegate_ = std::move(delegate); 293 delegate_ = std::move(delegate);
262 } 294 }
263 295
264 bool MediaSession::IsActiveForTest() const { 296 bool MediaSession::IsActiveForTest() const {
265 return audio_focus_state_ == State::ACTIVE; 297 return audio_focus_state_ == State::ACTIVE;
266 } 298 }
267 299
268 AudioFocusManager::AudioFocusType MediaSession::audio_focus_type_for_test()
269 const {
270 return audio_focus_type_;
271 }
272
273 MediaSessionUmaHelper* MediaSession::uma_helper_for_test() { 300 MediaSessionUmaHelper* MediaSession::uma_helper_for_test() {
274 return &uma_helper_; 301 return &uma_helper_;
275 } 302 }
276 303
277 void MediaSession::RemoveAllPlayersForTest() { 304 void MediaSession::RemoveAllPlayersForTest() {
278 players_.clear(); 305 players_.clear();
279 AbandonSystemAudioFocusIfNeeded(); 306 AbandonSystemAudioFocusIfNeeded();
280 } 307 }
281 308
282 void MediaSession::OnSuspendInternal(SuspendType suspend_type, 309 void MediaSession::OnSuspendInternal(SuspendType suspend_type,
283 State new_state) { 310 State new_state) {
311 DCHECK(!HasPepper());
312
284 DCHECK(new_state == State::SUSPENDED || new_state == State::INACTIVE); 313 DCHECK(new_state == State::SUSPENDED || new_state == State::INACTIVE);
285 // UI suspend cannot use State::INACTIVE. 314 // UI suspend cannot use State::INACTIVE.
286 DCHECK(suspend_type == SuspendType::SYSTEM || new_state == State::SUSPENDED); 315 DCHECK(suspend_type == SuspendType::SYSTEM || new_state == State::SUSPENDED);
287 316
288 if (audio_focus_state_ != State::ACTIVE) 317 if (audio_focus_state_ != State::ACTIVE)
289 return; 318 return;
290 319
291 switch (suspend_type) { 320 switch (suspend_type) {
292 case SuspendType::UI: 321 case SuspendType::UI:
293 uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::UI); 322 uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::UI);
(...skipping 22 matching lines...) Expand all
316 suspend_type_ = suspend_type; 345 suspend_type_ = suspend_type;
317 346
318 if (suspend_type != SuspendType::CONTENT) { 347 if (suspend_type != SuspendType::CONTENT) {
319 // SuspendType::CONTENT happens when the suspend action came from 348 // SuspendType::CONTENT happens when the suspend action came from
320 // the page in which case the player is already paused. 349 // the page in which case the player is already paused.
321 // Otherwise, the players need to be paused. 350 // Otherwise, the players need to be paused.
322 for (const auto& it : players_) 351 for (const auto& it : players_)
323 it.observer->OnSuspend(it.player_id); 352 it.observer->OnSuspend(it.player_id);
324 } 353 }
325 354
355 for (const auto& it : pepper_players_)
356 it.observer->OnSetVolumeMultiplier(it.player_id, kDuckingVolumeMultiplier);
357
326 UpdateWebContents(); 358 UpdateWebContents();
327 } 359 }
328 360
329 void MediaSession::OnResumeInternal(SuspendType suspend_type) { 361 void MediaSession::OnResumeInternal(SuspendType suspend_type) {
330 if (suspend_type == SuspendType::SYSTEM && suspend_type_ != suspend_type) 362 if (suspend_type == SuspendType::SYSTEM && suspend_type_ != suspend_type)
331 return; 363 return;
332 364
333 SetAudioFocusState(State::ACTIVE); 365 SetAudioFocusState(State::ACTIVE);
334 366
335 for (const auto& it : players_) 367 for (const auto& it : players_)
336 it.observer->OnResume(it.player_id); 368 it.observer->OnResume(it.player_id);
337 369
370 for (const auto& it : pepper_players_)
mlamouri (slow - plz ping) 2016/09/30 09:35:22 style: add { }
Zhiqiang Zhang (Slow) 2016/09/30 10:04:42 Done.
371 it.observer->OnSetVolumeMultiplier(
372 it.player_id, GetVolumeMultiplier());
373
338 UpdateWebContents(); 374 UpdateWebContents();
339 } 375 }
340 376
341 MediaSession::MediaSession(WebContents* web_contents) 377 MediaSession::MediaSession(WebContents* web_contents)
342 : WebContentsObserver(web_contents), 378 : WebContentsObserver(web_contents),
343 audio_focus_state_(State::INACTIVE), 379 audio_focus_state_(State::INACTIVE),
344 audio_focus_type_( 380 audio_focus_type_(
345 AudioFocusManager::AudioFocusType::GainTransientMayDuck), 381 AudioFocusManager::AudioFocusType::GainTransientMayDuck),
346 is_ducking_(false) {} 382 is_ducking_(false) {}
347 383
348 void MediaSession::Initialize() { 384 void MediaSession::Initialize() {
349 delegate_ = MediaSessionDelegate::Create(this); 385 delegate_ = MediaSessionDelegate::Create(this);
350 } 386 }
351 387
352 bool MediaSession::RequestSystemAudioFocus( 388 bool MediaSession::RequestSystemAudioFocus(
353 AudioFocusManager::AudioFocusType audio_focus_type) { 389 AudioFocusManager::AudioFocusType audio_focus_type) {
354 bool result = delegate_->RequestAudioFocus(audio_focus_type); 390 bool result = delegate_->RequestAudioFocus(audio_focus_type);
355 uma_helper_.RecordRequestAudioFocusResult(result); 391 uma_helper_.RecordRequestAudioFocusResult(result);
392
393 // MediaSession must change its state & audio focus type AFTER requesting
394 // audio focus.
395 SetAudioFocusState(result ? State::ACTIVE : State::INACTIVE);
396 audio_focus_type_ = audio_focus_type;
356 return result; 397 return result;
357 } 398 }
358 399
359 void MediaSession::AbandonSystemAudioFocusIfNeeded() { 400 void MediaSession::AbandonSystemAudioFocusIfNeeded() {
360 if (audio_focus_state_ == State::INACTIVE || !players_.empty()) 401 if (audio_focus_state_ == State::INACTIVE || !players_.empty() ||
402 !pepper_players_.empty()) {
361 return; 403 return;
362 404 }
363 delegate_->AbandonAudioFocus(); 405 delegate_->AbandonAudioFocus();
364 406
365 SetAudioFocusState(State::INACTIVE); 407 SetAudioFocusState(State::INACTIVE);
366 UpdateWebContents(); 408 UpdateWebContents();
367 } 409 }
368 410
369 void MediaSession::UpdateWebContents() { 411 void MediaSession::UpdateWebContents() {
370 media_session_state_listeners_.Notify(audio_focus_state_); 412 media_session_state_listeners_.Notify(audio_focus_state_);
371 static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged(); 413 static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged();
372 } 414 }
373 415
374 void MediaSession::SetAudioFocusState(State audio_focus_state) { 416 void MediaSession::SetAudioFocusState(State audio_focus_state) {
375 if (audio_focus_state == audio_focus_state_) 417 if (audio_focus_state == audio_focus_state_)
376 return; 418 return;
377 419
378 audio_focus_state_ = audio_focus_state; 420 audio_focus_state_ = audio_focus_state;
379 switch (audio_focus_state_) { 421 switch (audio_focus_state_) {
380 case State::ACTIVE: 422 case State::ACTIVE:
381 uma_helper_.OnSessionActive(); 423 uma_helper_.OnSessionActive();
382 break; 424 break;
383 case State::SUSPENDED: 425 case State::SUSPENDED:
384 uma_helper_.OnSessionSuspended(); 426 uma_helper_.OnSessionSuspended();
385 break; 427 break;
386 case State::INACTIVE: 428 case State::INACTIVE:
387 uma_helper_.OnSessionInactive(); 429 uma_helper_.OnSessionInactive();
388 break; 430 break;
389 } 431 }
390 } 432 }
391 433
434 bool MediaSession::AddPepperPlayer(MediaSessionObserver* observer,
435 int player_id) {
436 DCHECK(RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain));
437
438 pepper_players_.insert(PlayerIdentifier(observer, player_id));
439
440 observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier());
441
442 return true;
443 }
444
392 } // namespace content 445 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698