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

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"
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698