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

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

Issue 2526533002: Allow MediaSession in iframes to be routed (Closed)
Patch Set: nits Created 4 years 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_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"
19 #endif // defined(OS_ANDROID) 20 #endif // defined(OS_ANDROID)
20 21
21 namespace content { 22 namespace content {
22 23
23 namespace { 24 namespace {
24 25
25 const double kDefaultVolumeMultiplier = 1.0; 26 const double kDefaultVolumeMultiplier = 1.0;
26 const double kDuckingVolumeMultiplier = 0.2; 27 const double kDuckingVolumeMultiplier = 0.2;
27 28
29 using MapRenderFrameHostToDepth = std::map<RenderFrameHost*, size_t>;
30
31 size_t ComputeFrameDepth(RenderFrameHost* rfh,
32 MapRenderFrameHostToDepth* map_rfh_to_depth) {
33 DCHECK(rfh);
34 size_t depth = 0;
35 RenderFrameHost* current_frame = rfh;
36 while (current_frame) {
37 auto it = map_rfh_to_depth->find(current_frame);
38 if (it != map_rfh_to_depth->end()) {
39 depth += it->second;
40 break;
41 }
42 ++depth;
43 current_frame = current_frame->GetParent();
44 }
45 (*map_rfh_to_depth)[rfh] = depth;
46 return depth;
47 }
48
28 } // anonymous namespace 49 } // anonymous namespace
29 50
30 using MediaSessionSuspendedSource = 51 using MediaSessionSuspendedSource =
31 MediaSessionUmaHelper::MediaSessionSuspendedSource; 52 MediaSessionUmaHelper::MediaSessionSuspendedSource;
32 53
33 DEFINE_WEB_CONTENTS_USER_DATA_KEY(MediaSessionImpl); 54 DEFINE_WEB_CONTENTS_USER_DATA_KEY(MediaSessionImpl);
34 55
35 MediaSessionImpl::PlayerIdentifier::PlayerIdentifier( 56 MediaSessionImpl::PlayerIdentifier::PlayerIdentifier(
36 MediaSessionPlayerObserver* observer, 57 MediaSessionPlayerObserver* observer,
37 int player_id) 58 int player_id)
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 // TODO(zqzhang): refactor MediaSessionImpl, maybe move the interface used to 103 // TODO(zqzhang): refactor MediaSessionImpl, maybe move the interface used to
83 // talk with AudioFocusManager out to a seperate class. The AudioFocusManager 104 // talk with AudioFocusManager out to a seperate class. The AudioFocusManager
84 // unit tests then could mock the interface and abandon audio focus when 105 // unit tests then could mock the interface and abandon audio focus when
85 // WebContents is destroyed. See https://crbug.com/651069 106 // WebContents is destroyed. See https://crbug.com/651069
86 normal_players_.clear(); 107 normal_players_.clear();
87 pepper_players_.clear(); 108 pepper_players_.clear();
88 one_shot_players_.clear(); 109 one_shot_players_.clear();
89 AbandonSystemAudioFocusIfNeeded(); 110 AbandonSystemAudioFocusIfNeeded();
90 } 111 }
91 112
92 void MediaSessionImpl::SetMediaSessionService(
93 MediaSessionServiceImpl* service) {
94 service_ = service;
95 }
96
97 void MediaSessionImpl::AddObserver(MediaSessionObserver* observer) { 113 void MediaSessionImpl::AddObserver(MediaSessionObserver* observer) {
98 observers_.AddObserver(observer); 114 observers_.AddObserver(observer);
99 } 115 }
100 116
101 void MediaSessionImpl::RemoveObserver(MediaSessionObserver* observer) { 117 void MediaSessionImpl::RemoveObserver(MediaSessionObserver* observer) {
102 observers_.RemoveObserver(observer); 118 observers_.RemoveObserver(observer);
103 } 119 }
104 120
105 void MediaSessionImpl::SetMetadata( 121 void MediaSessionImpl::NotifyMediaSessionMetadataChange(
106 const base::Optional<MediaMetadata>& metadata) { 122 const base::Optional<MediaMetadata>& metadata) {
107 metadata_ = metadata;
108 for (auto& observer : observers_) 123 for (auto& observer : observers_)
109 observer.MediaSessionMetadataChanged(metadata); 124 observer.MediaSessionMetadataChanged(metadata);
110 } 125 }
111 126
127 void MediaSessionImpl::NotifyMediaSessionActionsChange(
128 const std::set<blink::mojom::MediaSessionAction>& actions) {
129 for (auto& observer : observers_)
130 observer.MediaSessionActionsChanged(actions);
131 }
132
112 bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer, 133 bool MediaSessionImpl::AddPlayer(MediaSessionPlayerObserver* observer,
113 int player_id, 134 int player_id,
114 media::MediaContentType media_content_type) { 135 media::MediaContentType media_content_type) {
115 if (media_content_type == media::MediaContentType::OneShot) 136 if (media_content_type == media::MediaContentType::OneShot)
116 return AddOneShotPlayer(observer, player_id); 137 return AddOneShotPlayer(observer, player_id);
117 if (media_content_type == media::MediaContentType::Pepper) 138 if (media_content_type == media::MediaContentType::Pepper)
118 return AddPepperPlayer(observer, player_id); 139 return AddPepperPlayer(observer, player_id);
119 140
120 observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier()); 141 observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier());
121 142
(...skipping 21 matching lines...) Expand all
143 164
144 if (audio_focus_state_ != State::ACTIVE) 165 if (audio_focus_state_ != State::ACTIVE)
145 return false; 166 return false;
146 167
147 // The session should be reset if a player is starting while all players are 168 // The session should be reset if a player is starting while all players are
148 // suspended. 169 // suspended.
149 if (old_audio_focus_state != State::ACTIVE) 170 if (old_audio_focus_state != State::ACTIVE)
150 normal_players_.clear(); 171 normal_players_.clear();
151 172
152 normal_players_.insert(PlayerIdentifier(observer, player_id)); 173 normal_players_.insert(PlayerIdentifier(observer, player_id));
174
175 UpdateRoutedService();
153 NotifyAboutStateChange(); 176 NotifyAboutStateChange();
154
155 return true; 177 return true;
156 } 178 }
157 179
158 void MediaSessionImpl::RemovePlayer(MediaSessionPlayerObserver* observer, 180 void MediaSessionImpl::RemovePlayer(MediaSessionPlayerObserver* observer,
159 int player_id) { 181 int player_id) {
160 bool was_controllable = IsControllable(); 182 bool was_controllable = IsControllable();
161 183
162 PlayerIdentifier identifier(observer, player_id); 184 PlayerIdentifier identifier(observer, player_id);
163 185
164 auto it = normal_players_.find(identifier); 186 auto it = normal_players_.find(identifier);
165 if (it != normal_players_.end()) 187 if (it != normal_players_.end())
166 normal_players_.erase(it); 188 normal_players_.erase(it);
167 189
168 it = pepper_players_.find(identifier); 190 it = pepper_players_.find(identifier);
169 if (it != pepper_players_.end()) 191 if (it != pepper_players_.end())
170 pepper_players_.erase(it); 192 pepper_players_.erase(it);
171 193
172 it = one_shot_players_.find(identifier); 194 it = one_shot_players_.find(identifier);
173 if (it != one_shot_players_.end()) 195 if (it != one_shot_players_.end())
174 one_shot_players_.erase(it); 196 one_shot_players_.erase(it);
175 197
176 AbandonSystemAudioFocusIfNeeded(); 198 AbandonSystemAudioFocusIfNeeded();
199 UpdateRoutedService();
177 200
178 // The session may become controllable after removing a one-shot player. 201 // The session may become controllable after removing a one-shot player.
179 // However AbandonSystemAudioFocusIfNeeded will short-return and won't notify 202 // However AbandonSystemAudioFocusIfNeeded will short-return and won't notify
180 // about the state change. 203 // about the state change.
181 if (!was_controllable && IsControllable()) 204 if (!was_controllable && IsControllable())
182 NotifyAboutStateChange(); 205 NotifyAboutStateChange();
183 } 206 }
184 207
185 void MediaSessionImpl::RemovePlayers(MediaSessionPlayerObserver* observer) { 208 void MediaSessionImpl::RemovePlayers(MediaSessionPlayerObserver* observer) {
186 bool was_controllable = IsControllable(); 209 bool was_controllable = IsControllable();
(...skipping 13 matching lines...) Expand all
200 } 223 }
201 224
202 for (auto it = one_shot_players_.begin(); it != one_shot_players_.end();) { 225 for (auto it = one_shot_players_.begin(); it != one_shot_players_.end();) {
203 if (it->observer == observer) 226 if (it->observer == observer)
204 one_shot_players_.erase(it++); 227 one_shot_players_.erase(it++);
205 else 228 else
206 ++it; 229 ++it;
207 } 230 }
208 231
209 AbandonSystemAudioFocusIfNeeded(); 232 AbandonSystemAudioFocusIfNeeded();
233 UpdateRoutedService();
210 234
211 // The session may become controllable after removing a one-shot player. 235 // The session may become controllable after removing a one-shot player.
212 // However AbandonSystemAudioFocusIfNeeded will short-return and won't notify 236 // However AbandonSystemAudioFocusIfNeeded will short-return and won't notify
213 // about the state change. 237 // about the state change.
214 if (!was_controllable && IsControllable()) 238 if (!was_controllable && IsControllable())
215 NotifyAboutStateChange(); 239 NotifyAboutStateChange();
216 } 240 }
217 241
218 void MediaSessionImpl::RecordSessionDuck() { 242 void MediaSessionImpl::RecordSessionDuck() {
219 uma_helper_.RecordSessionSuspended( 243 uma_helper_.RecordSessionSuspended(
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 316
293 if (audio_focus_state_ != State::SUSPENDED) 317 if (audio_focus_state_ != State::SUSPENDED)
294 OnSuspendInternal(suspend_type, State::SUSPENDED); 318 OnSuspendInternal(suspend_type, State::SUSPENDED);
295 319
296 DCHECK(audio_focus_state_ == State::SUSPENDED); 320 DCHECK(audio_focus_state_ == State::SUSPENDED);
297 normal_players_.clear(); 321 normal_players_.clear();
298 322
299 AbandonSystemAudioFocusIfNeeded(); 323 AbandonSystemAudioFocusIfNeeded();
300 } 324 }
301 325
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() { 326 void MediaSessionImpl::StartDucking() {
321 if (is_ducking_) 327 if (is_ducking_)
322 return; 328 return;
323 is_ducking_ = true; 329 is_ducking_ = true;
324 UpdateVolumeMultiplier(); 330 UpdateVolumeMultiplier();
325 } 331 }
326 332
327 void MediaSessionImpl::StopDucking() { 333 void MediaSessionImpl::StopDucking() {
328 if (!is_ducking_) 334 if (!is_ducking_)
329 return; 335 return;
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
463 469
464 NotifyAboutStateChange(); 470 NotifyAboutStateChange();
465 } 471 }
466 472
467 MediaSessionImpl::MediaSessionImpl(WebContents* web_contents) 473 MediaSessionImpl::MediaSessionImpl(WebContents* web_contents)
468 : WebContentsObserver(web_contents), 474 : WebContentsObserver(web_contents),
469 audio_focus_state_(State::INACTIVE), 475 audio_focus_state_(State::INACTIVE),
470 audio_focus_type_( 476 audio_focus_type_(
471 AudioFocusManager::AudioFocusType::GainTransientMayDuck), 477 AudioFocusManager::AudioFocusType::GainTransientMayDuck),
472 is_ducking_(false), 478 is_ducking_(false),
473 service_(nullptr) { 479 routed_service_(nullptr) {
474 #if defined(OS_ANDROID) 480 #if defined(OS_ANDROID)
475 session_android_.reset(new MediaSessionAndroid(this)); 481 session_android_.reset(new MediaSessionAndroid(this));
476 #endif // defined(OS_ANDROID) 482 #endif // defined(OS_ANDROID)
477 } 483 }
478 484
479 void MediaSessionImpl::Initialize() { 485 void MediaSessionImpl::Initialize() {
480 delegate_ = AudioFocusDelegate::Create(this); 486 delegate_ = AudioFocusDelegate::Create(this);
481 } 487 }
482 488
483 bool MediaSessionImpl::RequestSystemAudioFocus( 489 bool MediaSessionImpl::RequestSystemAudioFocus(
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
545 int player_id) { 551 int player_id) {
546 if (!RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain)) 552 if (!RequestSystemAudioFocus(AudioFocusManager::AudioFocusType::Gain))
547 return false; 553 return false;
548 554
549 one_shot_players_.insert(PlayerIdentifier(observer, player_id)); 555 one_shot_players_.insert(PlayerIdentifier(observer, player_id));
550 NotifyAboutStateChange(); 556 NotifyAboutStateChange();
551 557
552 return true; 558 return true;
553 } 559 }
554 560
561 // MediaSessionService-related methods
562
563 void MediaSessionImpl::OnServiceCreated(MediaSessionServiceImpl* service) {
564 services_[service->GetRenderFrameHost()] = service;
565 }
566
567 void MediaSessionImpl::OnServiceDestroyed(MediaSessionServiceImpl* service) {
568 services_.erase(service->GetRenderFrameHost());
569 }
570
571 void MediaSessionImpl::OnMediaSessionMetadataChanged(
572 MediaSessionServiceImpl* service) {
573 if (service != routed_service_)
574 return;
575
576 NotifyMediaSessionMetadataChange(routed_service_->metadata());
577 }
578
579 void MediaSessionImpl::OnMediaSessionActionsChanged(
580 MediaSessionServiceImpl* service) {
581 if (service != routed_service_)
582 return;
583
584 NotifyMediaSessionActionsChange(routed_service_->actions());
585 }
586
587 void MediaSessionImpl::DidReceiveAction(
588 blink::mojom::MediaSessionAction action) {
589 if (!routed_service_)
590 return;
591
592 routed_service_->GetClient()->DidReceiveAction(action);
593 }
594
595 bool MediaSessionImpl::IsServiceActiveForRenderFrameHost(RenderFrameHost* rfh) {
596 if (!services_.count(rfh))
597 return false;
598
599 return services_[rfh]->metadata().has_value() ||
600 !services_[rfh]->actions().empty();
601 }
602
603 void MediaSessionImpl::UpdateRoutedService() {
604 MediaSessionServiceImpl* new_service = ComputeServiceForRouting();
605 if (new_service == routed_service_)
606 return;
607
608 routed_service_ = new_service;
609 if (routed_service_) {
610 NotifyMediaSessionMetadataChange(routed_service_->metadata());
611 NotifyMediaSessionActionsChange(routed_service_->actions());
612 } else {
613 NotifyMediaSessionMetadataChange(base::nullopt);
614 NotifyMediaSessionActionsChange(
615 std::set<blink::mojom::MediaSessionAction>());
616 }
617 }
618
619 MediaSessionServiceImpl* MediaSessionImpl::ComputeServiceForRouting() {
620 // The service selection strategy is: select a frame that has a playing/paused
621 // player and has a corresponding MediaSessionService and return the
622 // corresponding MediaSessionService. If multiple frames satisfy the criteria,
623 // prefer the top-most frame.
624 std::set<RenderFrameHost*> frames;
625 for (const auto& player : normal_players_) {
626 RenderFrameHost* frame = player.observer->GetRenderFrameHost();
627 if (frame)
628 frames.insert(frame);
629 }
630
631 for (const auto& player : one_shot_players_) {
632 RenderFrameHost* frame = player.observer->GetRenderFrameHost();
633 if (frame)
634 frames.insert(frame);
635 }
636
637 for (const auto& player : pepper_players_) {
638 RenderFrameHost* frame = player.observer->GetRenderFrameHost();
639 if (frame)
640 frames.insert(frame);
641 }
642
643 RenderFrameHost* best_frame = nullptr;
644 size_t min_depth = std::numeric_limits<size_t>::max();
645 std::map<RenderFrameHost*, size_t> map_rfh_to_depth;
646
647 for (RenderFrameHost* frame : frames) {
648 size_t depth = ComputeFrameDepth(frame, &map_rfh_to_depth);
649 if (depth >= min_depth)
650 continue;
651 if (!IsServiceActiveForRenderFrameHost(frame))
652 continue;
653 best_frame = frame;
654 min_depth = depth;
655 }
656
657 return best_frame ? services_[best_frame] : nullptr;
658 }
659
555 } // namespace content 660 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698