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 <algorithm> | 7 #include <algorithm> |
8 #include "content/browser/media/session/audio_focus_delegate.h" | 8 #include "content/browser/media/session/audio_focus_delegate.h" |
9 #include "content/browser/media/session/media_session_controller.h" | |
9 #include "content/browser/media/session/media_session_player_observer.h" | 10 #include "content/browser/media/session/media_session_player_observer.h" |
10 #include "content/browser/media/session/media_session_service_impl.h" | 11 #include "content/browser/media/session/media_session_service_impl.h" |
11 #include "content/browser/web_contents/web_contents_impl.h" | 12 #include "content/browser/web_contents/web_contents_impl.h" |
12 #include "content/public/browser/media_session.h" | 13 #include "content/public/browser/media_session.h" |
13 #include "content/public/browser/media_session_observer.h" | 14 #include "content/public/browser/media_session_observer.h" |
14 #include "content/public/browser/web_contents.h" | 15 #include "content/public/browser/web_contents.h" |
15 #include "media/base/media_content_type.h" | 16 #include "media/base/media_content_type.h" |
16 | 17 |
17 #if defined(OS_ANDROID) | 18 #if defined(OS_ANDROID) |
18 #include "content/browser/media/session/media_session_android.h" | 19 #include "content/browser/media/session/media_session_android.h" |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
82 // TODO(zqzhang): refactor MediaSessionImpl, maybe move the interface used to | 83 // TODO(zqzhang): refactor MediaSessionImpl, maybe move the interface used to |
83 // talk with AudioFocusManager out to a seperate class. The AudioFocusManager | 84 // talk with AudioFocusManager out to a seperate class. The AudioFocusManager |
84 // unit tests then could mock the interface and abandon audio focus when | 85 // unit tests then could mock the interface and abandon audio focus when |
85 // WebContents is destroyed. See https://crbug.com/651069 | 86 // WebContents is destroyed. See https://crbug.com/651069 |
86 normal_players_.clear(); | 87 normal_players_.clear(); |
87 pepper_players_.clear(); | 88 pepper_players_.clear(); |
88 one_shot_players_.clear(); | 89 one_shot_players_.clear(); |
89 AbandonSystemAudioFocusIfNeeded(); | 90 AbandonSystemAudioFocusIfNeeded(); |
90 } | 91 } |
91 | 92 |
92 void MediaSessionImpl::SetMediaSessionService( | |
93 MediaSessionServiceImpl* service) { | |
94 service_ = service; | |
95 } | |
96 | |
97 void MediaSessionImpl::AddObserver(MediaSessionObserver* observer) { | 93 void MediaSessionImpl::AddObserver(MediaSessionObserver* observer) { |
98 observers_.AddObserver(observer); | 94 observers_.AddObserver(observer); |
99 } | 95 } |
100 | 96 |
101 void MediaSessionImpl::RemoveObserver(MediaSessionObserver* observer) { | 97 void MediaSessionImpl::RemoveObserver(MediaSessionObserver* observer) { |
102 observers_.RemoveObserver(observer); | 98 observers_.RemoveObserver(observer); |
103 } | 99 } |
104 | 100 |
105 void MediaSessionImpl::SetMetadata( | 101 void MediaSessionImpl::NotifyMediaSessionMetadataChange( |
106 const base::Optional<MediaMetadata>& metadata) { | 102 const base::Optional<MediaMetadata>& metadata) { |
107 metadata_ = metadata; | |
108 for (auto& observer : observers_) | 103 for (auto& observer : observers_) |
109 observer.MediaSessionMetadataChanged(metadata); | 104 observer.MediaSessionMetadataChanged(metadata); |
110 } | 105 } |
111 | 106 |
107 void MediaSessionImpl::NotifyMediaSessionActionsChange( | |
108 const std::set<blink::mojom::MediaSessionAction>& actions) { | |
109 for (auto& observer : observers_) | |
110 observer.MediaSessionActionsChanged(actions); | |
111 } | |
112 | |
112 bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer, | 113 bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer, |
113 int player_id, | 114 int player_id, |
114 media::MediaContentType media_content_type) { | 115 media::MediaContentType media_content_type) { |
115 if (media_content_type == media::MediaContentType::OneShot) | 116 if (media_content_type == media::MediaContentType::OneShot) |
116 return AddOneShotPlayer(observer, player_id); | 117 return AddOneShotPlayer(observer, player_id); |
117 if (media_content_type == media::MediaContentType::Pepper) | 118 if (media_content_type == media::MediaContentType::Pepper) |
118 return AddPepperPlayer(observer, player_id); | 119 return AddPepperPlayer(observer, player_id); |
119 | 120 |
120 observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier()); | 121 observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier()); |
121 | 122 |
(...skipping 21 matching lines...) Expand all Loading... | |
143 | 144 |
144 if (audio_focus_state_ != State::ACTIVE) | 145 if (audio_focus_state_ != State::ACTIVE) |
145 return false; | 146 return false; |
146 | 147 |
147 // The session should be reset if a player is starting while all players are | 148 // The session should be reset if a player is starting while all players are |
148 // suspended. | 149 // suspended. |
149 if (old_audio_focus_state != State::ACTIVE) | 150 if (old_audio_focus_state != State::ACTIVE) |
150 normal_players_.clear(); | 151 normal_players_.clear(); |
151 | 152 |
152 normal_players_.insert(PlayerIdentifier(observer, player_id)); | 153 normal_players_.insert(PlayerIdentifier(observer, player_id)); |
154 | |
155 UpdateRoutedService(); | |
153 NotifyAboutStateChange(); | 156 NotifyAboutStateChange(); |
154 | |
155 return true; | 157 return true; |
156 } | 158 } |
157 | 159 |
158 void MediaSessionImpl::RemovePlayer(MediaSessionPlayerObserver* observer, | 160 void MediaSessionImpl::RemovePlayer(MediaSessionPlayerObserver* observer, |
159 int player_id) { | 161 int player_id) { |
160 bool was_controllable = IsControllable(); | 162 bool was_controllable = IsControllable(); |
161 | 163 |
162 PlayerIdentifier identifier(observer, player_id); | 164 PlayerIdentifier identifier(observer, player_id); |
163 | 165 |
164 auto it = normal_players_.find(identifier); | 166 auto it = normal_players_.find(identifier); |
165 if (it != normal_players_.end()) | 167 if (it != normal_players_.end()) |
166 normal_players_.erase(it); | 168 normal_players_.erase(it); |
167 | 169 |
168 it = pepper_players_.find(identifier); | 170 it = pepper_players_.find(identifier); |
169 if (it != pepper_players_.end()) | 171 if (it != pepper_players_.end()) |
170 pepper_players_.erase(it); | 172 pepper_players_.erase(it); |
171 | 173 |
172 it = one_shot_players_.find(identifier); | 174 it = one_shot_players_.find(identifier); |
173 if (it != one_shot_players_.end()) | 175 if (it != one_shot_players_.end()) |
174 one_shot_players_.erase(it); | 176 one_shot_players_.erase(it); |
175 | 177 |
176 AbandonSystemAudioFocusIfNeeded(); | 178 AbandonSystemAudioFocusIfNeeded(); |
179 UpdateRoutedService(); | |
177 | 180 |
178 // The session may become controllable after removing a one-shot player. | 181 // The session may become controllable after removing a one-shot player. |
179 // However AbandonSystemAudioFocusIfNeeded will short-return and won't notify | 182 // However AbandonSystemAudioFocusIfNeeded will short-return and won't notify |
180 // about the state change. | 183 // about the state change. |
181 if (!was_controllable && IsControllable()) | 184 if (!was_controllable && IsControllable()) |
182 NotifyAboutStateChange(); | 185 NotifyAboutStateChange(); |
183 } | 186 } |
184 | 187 |
185 void MediaSessionImpl::RemovePlayers(MediaSessionPlayerObserver* observer) { | 188 void MediaSessionImpl::RemovePlayers(MediaSessionPlayerObserver* observer) { |
186 bool was_controllable = IsControllable(); | 189 bool was_controllable = IsControllable(); |
(...skipping 13 matching lines...) Expand all Loading... | |
200 } | 203 } |
201 | 204 |
202 for (auto it = one_shot_players_.begin(); it != one_shot_players_.end();) { | 205 for (auto it = one_shot_players_.begin(); it != one_shot_players_.end();) { |
203 if (it->observer == observer) | 206 if (it->observer == observer) |
204 one_shot_players_.erase(it++); | 207 one_shot_players_.erase(it++); |
205 else | 208 else |
206 ++it; | 209 ++it; |
207 } | 210 } |
208 | 211 |
209 AbandonSystemAudioFocusIfNeeded(); | 212 AbandonSystemAudioFocusIfNeeded(); |
213 UpdateRoutedService(); | |
210 | 214 |
211 // The session may become controllable after removing a one-shot player. | 215 // The session may become controllable after removing a one-shot player. |
212 // However AbandonSystemAudioFocusIfNeeded will short-return and won't notify | 216 // However AbandonSystemAudioFocusIfNeeded will short-return and won't notify |
213 // about the state change. | 217 // about the state change. |
214 if (!was_controllable && IsControllable()) | 218 if (!was_controllable && IsControllable()) |
215 NotifyAboutStateChange(); | 219 NotifyAboutStateChange(); |
216 } | 220 } |
217 | 221 |
218 void MediaSessionImpl::RecordSessionDuck() { | 222 void MediaSessionImpl::RecordSessionDuck() { |
219 uma_helper_.RecordSessionSuspended( | 223 uma_helper_.RecordSessionSuspended( |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
292 | 296 |
293 if (audio_focus_state_ != State::SUSPENDED) | 297 if (audio_focus_state_ != State::SUSPENDED) |
294 OnSuspendInternal(suspend_type, State::SUSPENDED); | 298 OnSuspendInternal(suspend_type, State::SUSPENDED); |
295 | 299 |
296 DCHECK(audio_focus_state_ == State::SUSPENDED); | 300 DCHECK(audio_focus_state_ == State::SUSPENDED); |
297 normal_players_.clear(); | 301 normal_players_.clear(); |
298 | 302 |
299 AbandonSystemAudioFocusIfNeeded(); | 303 AbandonSystemAudioFocusIfNeeded(); |
300 } | 304 } |
301 | 305 |
302 void MediaSessionImpl::DidReceiveAction( | |
303 blink::mojom::MediaSessionAction action) { | |
304 if (service_) | |
305 service_->GetClient()->DidReceiveAction(action); | |
306 } | |
307 | |
308 void MediaSessionImpl::OnMediaSessionEnabledAction( | |
309 blink::mojom::MediaSessionAction action) { | |
310 for (auto& observer : observers_) | |
311 observer.MediaSessionEnabledAction(action); | |
312 } | |
313 | |
314 void MediaSessionImpl::OnMediaSessionDisabledAction( | |
315 blink::mojom::MediaSessionAction action) { | |
316 for (auto& observer : observers_) | |
317 observer.MediaSessionDisabledAction(action); | |
318 } | |
319 | |
320 void MediaSessionImpl::StartDucking() { | 306 void MediaSessionImpl::StartDucking() { |
321 if (is_ducking_) | 307 if (is_ducking_) |
322 return; | 308 return; |
323 is_ducking_ = true; | 309 is_ducking_ = true; |
324 UpdateVolumeMultiplier(); | 310 UpdateVolumeMultiplier(); |
325 } | 311 } |
326 | 312 |
327 void MediaSessionImpl::StopDucking() { | 313 void MediaSessionImpl::StopDucking() { |
328 if (!is_ducking_) | 314 if (!is_ducking_) |
329 return; | 315 return; |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
463 | 449 |
464 NotifyAboutStateChange(); | 450 NotifyAboutStateChange(); |
465 } | 451 } |
466 | 452 |
467 MediaSessionImpl::MediaSessionImpl(WebContents* web_contents) | 453 MediaSessionImpl::MediaSessionImpl(WebContents* web_contents) |
468 : WebContentsObserver(web_contents), | 454 : WebContentsObserver(web_contents), |
469 audio_focus_state_(State::INACTIVE), | 455 audio_focus_state_(State::INACTIVE), |
470 audio_focus_type_( | 456 audio_focus_type_( |
471 AudioFocusManager::AudioFocusType::GainTransientMayDuck), | 457 AudioFocusManager::AudioFocusType::GainTransientMayDuck), |
472 is_ducking_(false), | 458 is_ducking_(false), |
473 service_(nullptr) { | 459 routed_service_(nullptr) { |
474 #if defined(OS_ANDROID) | 460 #if defined(OS_ANDROID) |
475 session_android_.reset(new MediaSessionAndroid(this)); | 461 session_android_.reset(new MediaSessionAndroid(this)); |
476 #endif // defined(OS_ANDROID) | 462 #endif // defined(OS_ANDROID) |
477 } | 463 } |
478 | 464 |
479 void MediaSessionImpl::Initialize() { | 465 void MediaSessionImpl::Initialize() { |
480 delegate_ = AudioFocusDelegate::Create(this); | 466 delegate_ = AudioFocusDelegate::Create(this); |
481 } | 467 } |
482 | 468 |
483 bool MediaSessionImpl::RequestSystemAudioFocus( | 469 bool MediaSessionImpl::RequestSystemAudioFocus( |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
545 int player_id) { | 531 int player_id) { |
546 if (!RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain)) | 532 if (!RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain)) |
547 return false; | 533 return false; |
548 | 534 |
549 one_shot_players_.insert(PlayerIdentifier(observer, player_id)); | 535 one_shot_players_.insert(PlayerIdentifier(observer, player_id)); |
550 NotifyAboutStateChange(); | 536 NotifyAboutStateChange(); |
551 | 537 |
552 return true; | 538 return true; |
553 } | 539 } |
554 | 540 |
541 // MediaSessionService-related methods | |
542 | |
543 void MediaSessionImpl::OnServiceCreated( | |
544 MediaSessionServiceImpl* service) { | |
545 services_[service->GetRenderFrameHost()] = service; | |
546 } | |
547 | |
548 void MediaSessionImpl::OnServiceDestroyed( | |
549 MediaSessionServiceImpl* service) { | |
550 services_.erase(service->GetRenderFrameHost()); | |
551 } | |
552 | |
553 void MediaSessionImpl::OnMediaSessionMetadataChanged( | |
554 MediaSessionServiceImpl* service) { | |
555 if (service != routed_service_) | |
556 return; | |
557 | |
558 NotifyMediaSessionMetadataChange(routed_service_->metadata()); | |
559 } | |
560 | |
561 void MediaSessionImpl::OnMediaSessionActionsChanged( | |
562 MediaSessionServiceImpl* service) { | |
563 if (service != routed_service_) | |
564 return; | |
565 | |
566 NotifyMediaSessionActionsChange(routed_service_->actions()); | |
567 } | |
568 | |
569 void MediaSessionImpl::DidReceiveAction( | |
570 blink::mojom::MediaSessionAction action) { | |
571 if (!routed_service_) | |
572 return; | |
573 | |
574 routed_service_->GetClient()->DidReceiveAction(action); | |
575 } | |
576 | |
577 bool MediaSessionImpl::IsServiceActiveForRenderFrameHost( | |
578 RenderFrameHost* rfh) { | |
579 if (!services_.count(rfh)) | |
580 return false; | |
581 | |
582 return services_[rfh]->metadata().has_value() || | |
583 !services_[rfh]->actions().empty(); | |
584 } | |
585 | |
586 void MediaSessionImpl::UpdateRoutedService() { | |
587 RenderFrameHost* rfh = GetMostMeaningfulAudioProducingFrame(); | |
588 MediaSessionServiceImpl* new_service = nullptr; | |
589 if (services_.count(rfh)) | |
590 new_service = services_[rfh]; | |
591 | |
592 if (new_service == routed_service_) | |
593 return; | |
594 | |
595 routed_service_ = new_service; | |
596 if (routed_service_) { | |
597 NotifyMediaSessionMetadataChange(routed_service_->metadata()); | |
598 NotifyMediaSessionActionsChange(routed_service_->actions()); | |
599 } else { | |
600 NotifyMediaSessionMetadataChange(base::nullopt); | |
601 NotifyMediaSessionActionsChange( | |
602 std::set<blink::mojom::MediaSessionAction>()); | |
603 } | |
604 } | |
605 | |
606 RenderFrameHost* MediaSessionImpl::GetMostMeaningfulAudioProducingFrame() { | |
607 // TODO(zqzhang): improve the selection of most-meaningful player. See | |
608 // https://crbug.com/xxxxxx | |
609 | |
610 // Prefer top-level session. | |
611 RenderFrameHost* main_frame = web_contents()->GetMainFrame(); | |
Zhiqiang Zhang (Slow)
2016/11/25 14:50:41
This was the current plan when I talked with Mouni
| |
612 if (IsServiceActiveForRenderFrameHost(main_frame)) { | |
613 return main_frame; | |
614 } | |
615 | |
616 // If not, select an audio-producing frame arbitrarily. | |
617 MediaSessionPlayerObserver* player_observer = nullptr; | |
618 if (!normal_players_.empty()) | |
619 player_observer = normal_players_.begin()->observer; | |
620 else if (!one_shot_players_.empty()) | |
621 player_observer = one_shot_players_.begin()->observer; | |
622 else if (!pepper_players_.empty()) | |
623 player_observer = pepper_players_.begin()->observer; | |
624 | |
625 MediaSessionController* controller = static_cast<MediaSessionController*>( | |
626 player_observer); | |
627 | |
628 if (!controller) | |
629 return nullptr; | |
630 | |
631 return controller->id().first; | |
632 } | |
633 | |
555 } // namespace content | 634 } // namespace content |
OLD | NEW |