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" |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 for (const auto& it : pepper_players_) |
| 252 it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier()); |
227 } | 253 } |
228 | 254 |
229 double MediaSession::GetVolumeMultiplier() const { | 255 double MediaSession::GetVolumeMultiplier() const { |
230 return is_ducking_ ? kDuckingVolumeMultiplier : kDefaultVolumeMultiplier; | 256 return is_ducking_ ? kDuckingVolumeMultiplier : kDefaultVolumeMultiplier; |
231 } | 257 } |
232 | 258 |
233 bool MediaSession::IsActive() const { | 259 bool MediaSession::IsActive() const { |
234 return audio_focus_state_ == State::ACTIVE; | 260 return audio_focus_state_ == State::ACTIVE; |
235 } | 261 } |
236 | 262 |
237 bool MediaSession::IsReallySuspended() const { | 263 bool MediaSession::IsReallySuspended() const { |
238 return audio_focus_state_ == State::SUSPENDED; | 264 return audio_focus_state_ == State::SUSPENDED; |
239 } | 265 } |
240 | 266 |
241 bool MediaSession::IsSuspended() const { | 267 bool MediaSession::IsSuspended() const { |
242 // TODO(mlamouri): should be == State::SUSPENDED. | 268 // TODO(mlamouri): should be == State::SUSPENDED. |
243 return audio_focus_state_ != State::ACTIVE; | 269 return audio_focus_state_ != State::ACTIVE; |
244 } | 270 } |
245 | 271 |
246 bool MediaSession::IsControllable() const { | 272 bool MediaSession::IsControllable() const { |
247 // Only media session having focus Gain can be controllable unless it is | 273 // Only media session having focus Gain can be controllable unless it is |
248 // inactive. | 274 // inactive. |
249 return audio_focus_state_ != State::INACTIVE && | 275 return audio_focus_state_ != State::INACTIVE && |
250 audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain; | 276 audio_focus_type_ == AudioFocusManager::AudioFocusType::Gain; |
251 } | 277 } |
252 | 278 |
| 279 bool MediaSession::HasPepper() const { |
| 280 return !pepper_players_.empty(); |
| 281 } |
| 282 |
253 std::unique_ptr<base::CallbackList<void(MediaSession::State)>::Subscription> | 283 std::unique_ptr<base::CallbackList<void(MediaSession::State)>::Subscription> |
254 MediaSession::RegisterMediaSessionStateChangedCallbackForTest( | 284 MediaSession::RegisterMediaSessionStateChangedCallbackForTest( |
255 const StateChangedCallback& cb) { | 285 const StateChangedCallback& cb) { |
256 return media_session_state_listeners_.Add(cb); | 286 return media_session_state_listeners_.Add(cb); |
257 } | 287 } |
258 | 288 |
259 void MediaSession::SetDelegateForTests( | 289 void MediaSession::SetDelegateForTests( |
260 std::unique_ptr<MediaSessionDelegate> delegate) { | 290 std::unique_ptr<MediaSessionDelegate> delegate) { |
261 delegate_ = std::move(delegate); | 291 delegate_ = std::move(delegate); |
262 } | 292 } |
263 | 293 |
264 bool MediaSession::IsActiveForTest() const { | 294 bool MediaSession::IsActiveForTest() const { |
265 return audio_focus_state_ == State::ACTIVE; | 295 return audio_focus_state_ == State::ACTIVE; |
266 } | 296 } |
267 | 297 |
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() { | 298 MediaSessionUmaHelper* MediaSession::uma_helper_for_test() { |
274 return &uma_helper_; | 299 return &uma_helper_; |
275 } | 300 } |
276 | 301 |
277 void MediaSession::RemoveAllPlayersForTest() { | 302 void MediaSession::RemoveAllPlayersForTest() { |
278 players_.clear(); | 303 players_.clear(); |
279 AbandonSystemAudioFocusIfNeeded(); | 304 AbandonSystemAudioFocusIfNeeded(); |
280 } | 305 } |
281 | 306 |
282 void MediaSession::OnSuspendInternal(SuspendType suspend_type, | 307 void MediaSession::OnSuspendInternal(SuspendType suspend_type, |
283 State new_state) { | 308 State new_state) { |
| 309 DCHECK(!HasPepper()); |
| 310 |
284 DCHECK(new_state == State::SUSPENDED || new_state == State::INACTIVE); | 311 DCHECK(new_state == State::SUSPENDED || new_state == State::INACTIVE); |
285 // UI suspend cannot use State::INACTIVE. | 312 // UI suspend cannot use State::INACTIVE. |
286 DCHECK(suspend_type == SuspendType::SYSTEM || new_state == State::SUSPENDED); | 313 DCHECK(suspend_type == SuspendType::SYSTEM || new_state == State::SUSPENDED); |
287 | 314 |
288 if (audio_focus_state_ != State::ACTIVE) | 315 if (audio_focus_state_ != State::ACTIVE) |
289 return; | 316 return; |
290 | 317 |
291 switch (suspend_type) { | 318 switch (suspend_type) { |
292 case SuspendType::UI: | 319 case SuspendType::UI: |
293 uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::UI); | 320 uma_helper_.RecordSessionSuspended(MediaSessionSuspendedSource::UI); |
(...skipping 22 matching lines...) Expand all Loading... |
316 suspend_type_ = suspend_type; | 343 suspend_type_ = suspend_type; |
317 | 344 |
318 if (suspend_type != SuspendType::CONTENT) { | 345 if (suspend_type != SuspendType::CONTENT) { |
319 // SuspendType::CONTENT happens when the suspend action came from | 346 // SuspendType::CONTENT happens when the suspend action came from |
320 // the page in which case the player is already paused. | 347 // the page in which case the player is already paused. |
321 // Otherwise, the players need to be paused. | 348 // Otherwise, the players need to be paused. |
322 for (const auto& it : players_) | 349 for (const auto& it : players_) |
323 it.observer->OnSuspend(it.player_id); | 350 it.observer->OnSuspend(it.player_id); |
324 } | 351 } |
325 | 352 |
| 353 for (const auto& it : pepper_players_) |
| 354 it.observer->OnSetVolumeMultiplier(it.player_id, kDuckingVolumeMultiplier); |
| 355 |
326 UpdateWebContents(); | 356 UpdateWebContents(); |
327 } | 357 } |
328 | 358 |
329 void MediaSession::OnResumeInternal(SuspendType suspend_type) { | 359 void MediaSession::OnResumeInternal(SuspendType suspend_type) { |
330 if (suspend_type == SuspendType::SYSTEM && suspend_type_ != suspend_type) | 360 if (suspend_type == SuspendType::SYSTEM && suspend_type_ != suspend_type) |
331 return; | 361 return; |
332 | 362 |
333 SetAudioFocusState(State::ACTIVE); | 363 SetAudioFocusState(State::ACTIVE); |
334 | 364 |
335 for (const auto& it : players_) | 365 for (const auto& it : players_) |
336 it.observer->OnResume(it.player_id); | 366 it.observer->OnResume(it.player_id); |
337 | 367 |
| 368 for (const auto& it : pepper_players_) |
| 369 it.observer->OnSetVolumeMultiplier(it.player_id, GetVolumeMultiplier()); |
| 370 |
338 UpdateWebContents(); | 371 UpdateWebContents(); |
339 } | 372 } |
340 | 373 |
341 MediaSession::MediaSession(WebContents* web_contents) | 374 MediaSession::MediaSession(WebContents* web_contents) |
342 : WebContentsObserver(web_contents), | 375 : WebContentsObserver(web_contents), |
343 audio_focus_state_(State::INACTIVE), | 376 audio_focus_state_(State::INACTIVE), |
344 audio_focus_type_( | 377 audio_focus_type_( |
345 AudioFocusManager::AudioFocusType::GainTransientMayDuck), | 378 AudioFocusManager::AudioFocusType::GainTransientMayDuck), |
346 is_ducking_(false) {} | 379 is_ducking_(false) {} |
347 | 380 |
348 void MediaSession::Initialize() { | 381 void MediaSession::Initialize() { |
349 delegate_ = MediaSessionDelegate::Create(this); | 382 delegate_ = MediaSessionDelegate::Create(this); |
350 } | 383 } |
351 | 384 |
352 bool MediaSession::RequestSystemAudioFocus( | 385 bool MediaSession::RequestSystemAudioFocus( |
353 AudioFocusManager::AudioFocusType audio_focus_type) { | 386 AudioFocusManager::AudioFocusType audio_focus_type) { |
354 bool result = delegate_->RequestAudioFocus(audio_focus_type); | 387 bool result = delegate_->RequestAudioFocus(audio_focus_type); |
355 uma_helper_.RecordRequestAudioFocusResult(result); | 388 uma_helper_.RecordRequestAudioFocusResult(result); |
| 389 |
| 390 // MediaSession must change its state & audio focus type AFTER requesting |
| 391 // audio focus. |
| 392 SetAudioFocusState(result ? State::ACTIVE : State::INACTIVE); |
| 393 audio_focus_type_ = audio_focus_type; |
356 return result; | 394 return result; |
357 } | 395 } |
358 | 396 |
359 void MediaSession::AbandonSystemAudioFocusIfNeeded() { | 397 void MediaSession::AbandonSystemAudioFocusIfNeeded() { |
360 if (audio_focus_state_ == State::INACTIVE || !players_.empty()) | 398 if (audio_focus_state_ == State::INACTIVE || !players_.empty() || |
| 399 !pepper_players_.empty()) { |
361 return; | 400 return; |
362 | 401 } |
363 delegate_->AbandonAudioFocus(); | 402 delegate_->AbandonAudioFocus(); |
364 | 403 |
365 SetAudioFocusState(State::INACTIVE); | 404 SetAudioFocusState(State::INACTIVE); |
366 UpdateWebContents(); | 405 UpdateWebContents(); |
367 } | 406 } |
368 | 407 |
369 void MediaSession::UpdateWebContents() { | 408 void MediaSession::UpdateWebContents() { |
370 media_session_state_listeners_.Notify(audio_focus_state_); | 409 media_session_state_listeners_.Notify(audio_focus_state_); |
371 static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged(); | 410 static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged(); |
372 } | 411 } |
373 | 412 |
374 void MediaSession::SetAudioFocusState(State audio_focus_state) { | 413 void MediaSession::SetAudioFocusState(State audio_focus_state) { |
375 if (audio_focus_state == audio_focus_state_) | 414 if (audio_focus_state == audio_focus_state_) |
376 return; | 415 return; |
377 | 416 |
378 audio_focus_state_ = audio_focus_state; | 417 audio_focus_state_ = audio_focus_state; |
379 switch (audio_focus_state_) { | 418 switch (audio_focus_state_) { |
380 case State::ACTIVE: | 419 case State::ACTIVE: |
381 uma_helper_.OnSessionActive(); | 420 uma_helper_.OnSessionActive(); |
382 break; | 421 break; |
383 case State::SUSPENDED: | 422 case State::SUSPENDED: |
384 uma_helper_.OnSessionSuspended(); | 423 uma_helper_.OnSessionSuspended(); |
385 break; | 424 break; |
386 case State::INACTIVE: | 425 case State::INACTIVE: |
387 uma_helper_.OnSessionInactive(); | 426 uma_helper_.OnSessionInactive(); |
388 break; | 427 break; |
389 } | 428 } |
390 } | 429 } |
391 | 430 |
| 431 bool MediaSession::AddPepperPlayer(MediaSessionObserver* observer, |
| 432 int player_id) { |
| 433 DCHECK(RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain)); |
| 434 |
| 435 pepper_players_.insert(PlayerIdentifier(observer, player_id)); |
| 436 |
| 437 observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier()); |
| 438 |
| 439 return true; |
| 440 } |
| 441 |
392 } // namespace content | 442 } // namespace content |
OLD | NEW |