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