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_impl.h" | 5 #include "content/browser/media/session/media_session_impl.h" |
6 | 6 |
7 #include "content/browser/media/session/audio_focus_delegate.h" | 7 #include "content/browser/media/session/audio_focus_delegate.h" |
8 #include "content/browser/media/session/media_session_player_observer.h" | 8 #include "content/browser/media/session/media_session_player_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 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
58 if (!session) { | 58 if (!session) { |
59 CreateForWebContents(web_contents); | 59 CreateForWebContents(web_contents); |
60 session = FromWebContents(web_contents); | 60 session = FromWebContents(web_contents); |
61 session->Initialize(); | 61 session->Initialize(); |
62 } | 62 } |
63 return session; | 63 return session; |
64 } | 64 } |
65 | 65 |
66 MediaSessionImpl::~MediaSessionImpl() { | 66 MediaSessionImpl::~MediaSessionImpl() { |
67 DCHECK(players_.empty()); | 67 DCHECK(players_.empty()); |
68 DCHECK(pepper_players_.empty()); | |
69 DCHECK(one_shot_players_.empty()); | |
68 DCHECK(audio_focus_state_ == State::INACTIVE); | 70 DCHECK(audio_focus_state_ == State::INACTIVE); |
69 for (auto& observer : observers_) | 71 for (auto& observer : observers_) |
70 observer.MediaSessionDestroyed(); | 72 observer.MediaSessionDestroyed(); |
71 } | 73 } |
72 | 74 |
73 void MediaSessionImpl::WebContentsDestroyed() { | 75 void MediaSessionImpl::WebContentsDestroyed() { |
74 // This should only work for tests. In production, all the players should have | 76 // This should only work for tests. In production, all the players should have |
75 // already been removed before WebContents is destroyed. | 77 // already been removed before WebContents is destroyed. |
76 | 78 |
77 // TODO(zqzhang): refactor MediaSessionImpl, maybe move the interface used to | 79 // TODO(zqzhang): refactor MediaSessionImpl, maybe move the interface used to |
(...skipping 16 matching lines...) Expand all Loading... | |
94 void MediaSessionImpl::SetMetadata( | 96 void MediaSessionImpl::SetMetadata( |
95 const base::Optional<MediaMetadata>& metadata) { | 97 const base::Optional<MediaMetadata>& metadata) { |
96 metadata_ = metadata; | 98 metadata_ = metadata; |
97 for (auto& observer : observers_) | 99 for (auto& observer : observers_) |
98 observer.MediaSessionMetadataChanged(metadata); | 100 observer.MediaSessionMetadataChanged(metadata); |
99 } | 101 } |
100 | 102 |
101 bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer, | 103 bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer, |
102 int player_id, | 104 int player_id, |
103 media::MediaContentType media_content_type) { | 105 media::MediaContentType media_content_type) { |
104 if (media_content_type == media::MediaContentType::Uncontrollable) | 106 if (media_content_type == media::MediaContentType::OneShot) |
105 return true; | 107 return AddOneShotPlayer(observer, player_id); |
106 if (media_content_type == media::MediaContentType::Pepper) | 108 if (media_content_type == media::MediaContentType::Pepper) |
107 return AddPepperPlayer(observer, player_id); | 109 return AddPepperPlayer(observer, player_id); |
108 | 110 |
109 observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier()); | 111 observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier()); |
110 | 112 |
111 // Determine the audio focus type required for playing the new player. | |
112 // TODO(zqzhang): handle duckable and uncontrollable. | |
113 // See https://crbug.com/639277. | |
114 AudioFocusManager::AudioFocusType required_audio_focus_type; | 113 AudioFocusManager::AudioFocusType required_audio_focus_type; |
115 if (media_content_type == media::MediaContentType::Persistent) { | 114 if (media_content_type == media::MediaContentType::Persistent) { |
116 required_audio_focus_type = AudioFocusManager::AudioFocusType::Gain; | 115 required_audio_focus_type = AudioFocusManager::AudioFocusType::Gain; |
117 } else { | 116 } else { |
118 required_audio_focus_type = | 117 required_audio_focus_type = |
119 AudioFocusManager::AudioFocusType::GainTransientMayDuck; | 118 AudioFocusManager::AudioFocusType::GainTransientMayDuck; |
120 } | 119 } |
121 | 120 |
122 // If the audio focus is already granted and is of type Content, there is | 121 // If the audio focus is already granted and is of type Content, there is |
123 // nothing to do. If it is granted of type Transient the requested type is | 122 // nothing to do. If it is granted of type Transient the requested type is |
(...skipping 11 matching lines...) Expand all Loading... | |
135 | 134 |
136 if (audio_focus_state_ != State::ACTIVE) | 135 if (audio_focus_state_ != State::ACTIVE) |
137 return false; | 136 return false; |
138 | 137 |
139 // The session should be reset if a player is starting while all players are | 138 // The session should be reset if a player is starting while all players are |
140 // suspended. | 139 // suspended. |
141 if (old_audio_focus_state != State::ACTIVE) | 140 if (old_audio_focus_state != State::ACTIVE) |
142 players_.clear(); | 141 players_.clear(); |
143 | 142 |
144 players_.insert(PlayerIdentifier(observer, player_id)); | 143 players_.insert(PlayerIdentifier(observer, player_id)); |
145 UpdateWebContents(); | 144 DispatchStateChange(); |
146 | 145 |
147 return true; | 146 return true; |
148 } | 147 } |
149 | 148 |
150 void MediaSessionImpl::RemovePlayer(MediaSessionPlayerObserver* observer, | 149 void MediaSessionImpl::RemovePlayer(MediaSessionPlayerObserver* observer, |
151 int player_id) { | 150 int player_id) { |
152 auto it = players_.find(PlayerIdentifier(observer, player_id)); | 151 auto it = players_.find(PlayerIdentifier(observer, player_id)); |
153 if (it != players_.end()) | 152 if (it != players_.end()) |
154 players_.erase(it); | 153 players_.erase(it); |
155 | 154 |
156 it = pepper_players_.find(PlayerIdentifier(observer, player_id)); | 155 it = pepper_players_.find(PlayerIdentifier(observer, player_id)); |
157 if (it != pepper_players_.end()) | 156 if (it != pepper_players_.end()) |
158 pepper_players_.erase(it); | 157 pepper_players_.erase(it); |
159 | 158 |
159 it = one_shot_players_.find(PlayerIdentifier(observer, player_id)); | |
160 if (it != one_shot_players_.end()) { | |
161 one_shot_players_.erase(it); | |
162 | |
163 // The session may become controllable after all one-shot players are | |
164 // removed. | |
165 if (one_shot_players_.empty()) | |
166 DispatchStateChange(); | |
167 } | |
168 | |
160 AbandonSystemAudioFocusIfNeeded(); | 169 AbandonSystemAudioFocusIfNeeded(); |
161 } | 170 } |
162 | 171 |
163 void MediaSessionImpl::RemovePlayers(MediaSessionPlayerObserver* observer) { | 172 void MediaSessionImpl::RemovePlayers(MediaSessionPlayerObserver* observer) { |
164 for (auto it = players_.begin(); it != players_.end();) { | 173 for (auto it = players_.begin(); it != players_.end();) { |
165 if (it->observer == observer) | 174 if (it->observer == observer) |
166 players_.erase(it++); | 175 players_.erase(it++); |
167 else | 176 else |
168 ++it; | 177 ++it; |
169 } | 178 } |
170 | 179 |
171 for (auto it = pepper_players_.begin(); it != pepper_players_.end();) { | 180 for (auto it = pepper_players_.begin(); it != pepper_players_.end();) { |
172 if (it->observer == observer) | 181 if (it->observer == observer) |
173 pepper_players_.erase(it++); | 182 pepper_players_.erase(it++); |
174 else | 183 else |
175 ++it; | 184 ++it; |
176 } | 185 } |
177 | 186 |
187 for (auto it = one_shot_players_.begin(); it != one_shot_players_.end();) { | |
188 if (it->observer == observer) | |
189 one_shot_players_.erase(it++); | |
190 else | |
191 ++it; | |
192 | |
193 // The session may become controllable after all one-shot players are | |
194 // removed. | |
195 if (one_shot_players_.empty()) | |
196 DispatchStateChange(); | |
197 } | |
198 | |
178 AbandonSystemAudioFocusIfNeeded(); | 199 AbandonSystemAudioFocusIfNeeded(); |
179 } | 200 } |
180 | 201 |
181 void MediaSessionImpl::RecordSessionDuck() { | 202 void MediaSessionImpl::RecordSessionDuck() { |
182 uma_helper_.RecordSessionSuspended( | 203 uma_helper_.RecordSessionSuspended( |
183 MediaSessionSuspendedSource::SystemTransientDuck); | 204 MediaSessionSuspendedSource::SystemTransientDuck); |
184 } | 205 } |
185 | 206 |
186 void MediaSessionImpl::OnPlayerPaused(MediaSessionPlayerObserver* observer, | 207 void MediaSessionImpl::OnPlayerPaused(MediaSessionPlayerObserver* observer, |
187 int player_id) { | 208 int player_id) { |
188 // If a playback is completed, BrowserMediaPlayerManager will call | 209 // If a playback is completed, BrowserMediaPlayerManager will call |
189 // OnPlayerPaused() after RemovePlayer(). This is a workaround. | 210 // OnPlayerPaused() after RemovePlayer(). This is a workaround. |
190 // Also, this method may be called when a player that is not added | 211 // Also, this method may be called when a player that is not added |
191 // to this session (e.g. a silent video) is paused. MediaSessionImpl | 212 // to this session (e.g. a silent video) is paused. MediaSessionImpl |
192 // should ignore the paused player for this case. | 213 // should ignore the paused player for this case. |
193 if (!players_.count(PlayerIdentifier(observer, player_id)) && | 214 if (!players_.count(PlayerIdentifier(observer, player_id)) && |
194 !pepper_players_.count(PlayerIdentifier(observer, player_id))) { | 215 !pepper_players_.count(PlayerIdentifier(observer, player_id)) && |
216 !one_shot_players_.count(PlayerIdentifier(observer, player_id))) { | |
195 return; | 217 return; |
196 } | 218 } |
197 | 219 |
198 // If the player to be removed is a pepper player, or there is more than one | 220 // If the player to be removed is a pepper player, or there is more than one |
199 // observer, remove the paused one from the session. | 221 // observer, remove the paused one from the session. |
200 if (pepper_players_.count(PlayerIdentifier(observer, player_id)) || | 222 if (pepper_players_.count(PlayerIdentifier(observer, player_id)) || |
201 players_.size() != 1) { | 223 players_.size() != 1) { |
202 RemovePlayer(observer, player_id); | 224 RemovePlayer(observer, player_id); |
203 return; | 225 return; |
204 } | 226 } |
205 | 227 |
228 // If the player is a one-shot player, just remove it since it is not expected | |
229 // to resume a one-shot player via resuming MediaSession. | |
230 if (one_shot_players_.count(PlayerIdentifier(observer, player_id))) { | |
231 RemovePlayer(observer, player_id); | |
232 return; | |
233 } | |
234 | |
206 // Otherwise, suspend the session. | 235 // Otherwise, suspend the session. |
207 DCHECK(!IsSuspended()); | 236 DCHECK(!IsSuspended()); |
208 OnSuspendInternal(SuspendType::CONTENT, State::SUSPENDED); | 237 OnSuspendInternal(SuspendType::CONTENT, State::SUSPENDED); |
209 } | 238 } |
210 | 239 |
211 void MediaSessionImpl::Resume(SuspendType suspend_type) { | 240 void MediaSessionImpl::Resume(SuspendType suspend_type) { |
212 DCHECK(IsReallySuspended()); | 241 DCHECK(IsReallySuspended()); |
213 | 242 |
214 // When the resume requests comes from another source than system, audio focus | 243 // When the resume requests comes from another source than system, audio focus |
215 // must be requested. | 244 // must be requested. |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
287 return audio_focus_state_ == State::SUSPENDED; | 316 return audio_focus_state_ == State::SUSPENDED; |
288 } | 317 } |
289 | 318 |
290 bool MediaSessionImpl::IsSuspended() const { | 319 bool MediaSessionImpl::IsSuspended() const { |
291 // TODO(mlamouri): should be == State::SUSPENDED. | 320 // TODO(mlamouri): should be == State::SUSPENDED. |
292 return audio_focus_state_ != State::ACTIVE; | 321 return audio_focus_state_ != State::ACTIVE; |
293 } | 322 } |
294 | 323 |
295 bool MediaSessionImpl::IsControllable() const { | 324 bool MediaSessionImpl::IsControllable() const { |
296 // Only media session having focus Gain can be controllable unless it is | 325 // Only media session having focus Gain can be controllable unless it is |
297 // inactive. | 326 // inactive. Also, the session will be uncontrollable if it contains one-shot |
327 // players. | |
298 return audio_focus_state_ != State::INACTIVE && | 328 return audio_focus_state_ != State::INACTIVE && |
299 audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain; | 329 audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain && |
330 (one_shot_players_.empty()); | |
300 } | 331 } |
301 | 332 |
302 bool MediaSessionImpl::HasPepper() const { | 333 bool MediaSessionImpl::HasPepper() const { |
303 return !pepper_players_.empty(); | 334 return !pepper_players_.empty(); |
304 } | 335 } |
305 | 336 |
306 std::unique_ptr<base::CallbackList<void(MediaSessionImpl::State)>::Subscription> | 337 std::unique_ptr<base::CallbackList<void(MediaSessionImpl::State)>::Subscription> |
307 MediaSessionImpl::RegisterMediaSessionStateChangedCallbackForTest( | 338 MediaSessionImpl::RegisterMediaSessionStateChangedCallbackForTest( |
308 const StateChangedCallback& cb) { | 339 const StateChangedCallback& cb) { |
309 return media_session_state_listeners_.Add(cb); | 340 return media_session_state_listeners_.Add(cb); |
310 } | 341 } |
311 | 342 |
312 void MediaSessionImpl::SetDelegateForTests( | 343 void MediaSessionImpl::SetDelegateForTests( |
313 std::unique_ptr<AudioFocusDelegate> delegate) { | 344 std::unique_ptr<AudioFocusDelegate> delegate) { |
314 delegate_ = std::move(delegate); | 345 delegate_ = std::move(delegate); |
315 } | 346 } |
316 | 347 |
317 bool MediaSessionImpl::IsActiveForTest() const { | 348 bool MediaSessionImpl::IsActiveForTest() const { |
318 return audio_focus_state_ == State::ACTIVE; | 349 return audio_focus_state_ == State::ACTIVE; |
319 } | 350 } |
320 | 351 |
321 MediaSessionUmaHelper* MediaSessionImpl::uma_helper_for_test() { | 352 MediaSessionUmaHelper* MediaSessionImpl::uma_helper_for_test() { |
322 return &uma_helper_; | 353 return &uma_helper_; |
323 } | 354 } |
324 | 355 |
325 void MediaSessionImpl::RemoveAllPlayersForTest() { | 356 void MediaSessionImpl::RemoveAllPlayersForTest() { |
326 players_.clear(); | 357 players_.clear(); |
358 pepper_players_.clear(); | |
359 one_shot_players_.clear(); | |
whywhat
2016/11/03 14:32:17
nit: I feel there's more code duplication here w.r
Zhiqiang Zhang (Slow)
2016/11/04 14:10:54
Yeah, I feel this too. But as pepper_players_ is l
| |
327 AbandonSystemAudioFocusIfNeeded(); | 360 AbandonSystemAudioFocusIfNeeded(); |
328 } | 361 } |
329 | 362 |
330 void MediaSessionImpl::OnSuspendInternal(SuspendType suspend_type, | 363 void MediaSessionImpl::OnSuspendInternal(SuspendType suspend_type, |
331 State new_state) { | 364 State new_state) { |
332 DCHECK(!HasPepper()); | 365 DCHECK(!HasPepper()); |
333 | 366 |
334 DCHECK(new_state == State::SUSPENDED || new_state == State::INACTIVE); | 367 DCHECK(new_state == State::SUSPENDED || new_state == State::INACTIVE); |
335 // UI suspend cannot use State::INACTIVE. | 368 // UI suspend cannot use State::INACTIVE. |
336 DCHECK(suspend_type == SuspendType::SYSTEM || new_state == State::SUSPENDED); | 369 DCHECK(suspend_type == SuspendType::SYSTEM || new_state == State::SUSPENDED); |
337 | 370 |
371 if (!one_shot_players_.empty()) | |
372 return; | |
373 | |
338 if (audio_focus_state_ != State::ACTIVE) | 374 if (audio_focus_state_ != State::ACTIVE) |
339 return; | 375 return; |
340 | 376 |
341 switch (suspend_type) { | 377 switch (suspend_type) { |
342 case SuspendType::UI: | 378 case SuspendType::UI: |
343 uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::UI); | 379 uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::UI); |
344 break; | 380 break; |
345 case SuspendType::SYSTEM: | 381 case SuspendType::SYSTEM: |
346 switch (new_state) { | 382 switch (new_state) { |
347 case State::SUSPENDED: | 383 case State::SUSPENDED: |
(...skipping 21 matching lines...) Expand all Loading... | |
369 // SuspendType::CONTENT happens when the suspend action came from | 405 // SuspendType::CONTENT happens when the suspend action came from |
370 // the page in which case the player is already paused. | 406 // the page in which case the player is already paused. |
371 // Otherwise, the players need to be paused. | 407 // Otherwise, the players need to be paused. |
372 for (const auto& it : players_) | 408 for (const auto& it : players_) |
373 it.observer->OnSuspend(it.player_id); | 409 it.observer->OnSuspend(it.player_id); |
374 } | 410 } |
375 | 411 |
376 for (const auto& it : pepper_players_) | 412 for (const auto& it : pepper_players_) |
377 it.observer->OnSetVolumeMultiplier(it.player_id, kDuckingVolumeMultiplier); | 413 it.observer->OnSetVolumeMultiplier(it.player_id, kDuckingVolumeMultiplier); |
378 | 414 |
379 UpdateWebContents(); | 415 DispatchStateChange(); |
380 } | 416 } |
381 | 417 |
382 void MediaSessionImpl::OnResumeInternal(SuspendType suspend_type) { | 418 void MediaSessionImpl::OnResumeInternal(SuspendType suspend_type) { |
383 if (suspend_type == SuspendType::SYSTEM && suspend_type_ != suspend_type) | 419 if (suspend_type == SuspendType::SYSTEM && suspend_type_ != suspend_type) |
384 return; | 420 return; |
385 | 421 |
386 SetAudioFocusState(State::ACTIVE); | 422 SetAudioFocusState(State::ACTIVE); |
387 | 423 |
388 for (const auto& it : players_) | 424 for (const auto& it : players_) |
389 it.observer->OnResume(it.player_id); | 425 it.observer->OnResume(it.player_id); |
390 | 426 |
391 for (const auto& it : pepper_players_) | 427 for (const auto& it : pepper_players_) |
392 it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier()); | 428 it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier()); |
393 | 429 |
394 UpdateWebContents(); | 430 DispatchStateChange(); |
395 } | 431 } |
396 | 432 |
397 MediaSessionImpl::MediaSessionImpl(WebContents* web_contents) | 433 MediaSessionImpl::MediaSessionImpl(WebContents* web_contents) |
398 : WebContentsObserver(web_contents), | 434 : WebContentsObserver(web_contents), |
399 audio_focus_state_(State::INACTIVE), | 435 audio_focus_state_(State::INACTIVE), |
400 audio_focus_type_( | 436 audio_focus_type_( |
401 AudioFocusManager::AudioFocusType::GainTransientMayDuck), | 437 AudioFocusManager::AudioFocusType::GainTransientMayDuck), |
402 is_ducking_(false) { | 438 is_ducking_(false) { |
403 #if defined(OS_ANDROID) | 439 #if defined(OS_ANDROID) |
404 session_android_.reset(new MediaSessionAndroid(this)); | 440 session_android_.reset(new MediaSessionAndroid(this)); |
(...skipping 11 matching lines...) Expand all Loading... | |
416 | 452 |
417 // MediaSessionImpl must change its state & audio focus type AFTER requesting | 453 // MediaSessionImpl must change its state & audio focus type AFTER requesting |
418 // audio focus. | 454 // audio focus. |
419 SetAudioFocusState(result ? State::ACTIVE : State::INACTIVE); | 455 SetAudioFocusState(result ? State::ACTIVE : State::INACTIVE); |
420 audio_focus_type_ = audio_focus_type; | 456 audio_focus_type_ = audio_focus_type; |
421 return result; | 457 return result; |
422 } | 458 } |
423 | 459 |
424 void MediaSessionImpl::AbandonSystemAudioFocusIfNeeded() { | 460 void MediaSessionImpl::AbandonSystemAudioFocusIfNeeded() { |
425 if (audio_focus_state_ == State::INACTIVE || !players_.empty() || | 461 if (audio_focus_state_ == State::INACTIVE || !players_.empty() || |
426 !pepper_players_.empty()) { | 462 !pepper_players_.empty() || !one_shot_players_.empty()) { |
427 return; | 463 return; |
428 } | 464 } |
429 delegate_->AbandonAudioFocus(); | 465 delegate_->AbandonAudioFocus(); |
430 | 466 |
431 SetAudioFocusState(State::INACTIVE); | 467 SetAudioFocusState(State::INACTIVE); |
432 UpdateWebContents(); | 468 DispatchStateChange(); |
433 } | 469 } |
434 | 470 |
435 void MediaSessionImpl::UpdateWebContents() { | 471 void MediaSessionImpl::DispatchStateChange() { |
436 media_session_state_listeners_.Notify(audio_focus_state_); | 472 media_session_state_listeners_.Notify(audio_focus_state_); |
437 for (auto& observer : observers_) | 473 for (auto& observer : observers_) |
438 observer.MediaSessionStateChanged(IsControllable(), IsSuspended()); | 474 observer.MediaSessionStateChanged(IsControllable(), IsSuspended()); |
439 } | 475 } |
440 | 476 |
441 void MediaSessionImpl::SetAudioFocusState(State audio_focus_state) { | 477 void MediaSessionImpl::SetAudioFocusState(State audio_focus_state) { |
442 if (audio_focus_state == audio_focus_state_) | 478 if (audio_focus_state == audio_focus_state_) |
443 return; | 479 return; |
444 | 480 |
445 audio_focus_state_ = audio_focus_state; | 481 audio_focus_state_ = audio_focus_state; |
(...skipping 13 matching lines...) Expand all Loading... | |
459 bool MediaSessionImpl::AddPepperPlayer(MediaSessionPlayerObserver* observer, | 495 bool MediaSessionImpl::AddPepperPlayer(MediaSessionPlayerObserver* observer, |
460 int player_id) { | 496 int player_id) { |
461 bool success = | 497 bool success = |
462 RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain); | 498 RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain); |
463 DCHECK(success); | 499 DCHECK(success); |
464 | 500 |
465 pepper_players_.insert(PlayerIdentifier(observer, player_id)); | 501 pepper_players_.insert(PlayerIdentifier(observer, player_id)); |
466 | 502 |
467 observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier()); | 503 observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier()); |
468 | 504 |
505 DispatchStateChange(); | |
469 return true; | 506 return true; |
470 } | 507 } |
471 | 508 |
509 bool MediaSessionImpl::AddOneShotPlayer(MediaSessionPlayerObserver* observer, | |
510 int player_id) { | |
511 // Don't check whether the request is successful or not. One-shot players | |
512 // should play uninterrupted. | |
whywhat
2016/11/03 14:32:16
that means we'd play them even if the user is in t
Zhiqiang Zhang (Slow)
2016/11/04 14:10:54
OK, let's give a chance for the players to respond
| |
513 RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain); | |
514 | |
515 one_shot_players_.insert(PlayerIdentifier(observer, player_id)); | |
516 | |
517 DispatchStateChange(); | |
518 return true; | |
519 } | |
520 | |
472 } // namespace content | 521 } // namespace content |
OLD | NEW |