Commit 216c89d0 authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

[Media Session] Implement seeking in content

Implement the "seekto" and "scrubto" mojo commands
by calling the "seekto" action handler in Blink.

For reference, these are separate in the generic
media session mojo API because not all media
sessions support scrubbing.

BUG=977375

Change-Id: Ib62e069a03539e57de832e8108c877be7f582e93
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1697428Reviewed-by: default avatarMounir Lamouri <mlamouri@chromium.org>
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#683206}
parent efbd8e60
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include "media/base/media_content_type.h" #include "media/base/media_content_type.h"
#include "services/media_session/public/cpp/media_image_manager.h" #include "services/media_session/public/cpp/media_image_manager.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h" #include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "third_party/blink/public/mojom/mediasession/media_session.mojom.h"
#include "ui/gfx/favicon_size.h" #include "ui/gfx/favicon_size.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
...@@ -913,6 +912,20 @@ void MediaSessionImpl::SkipAd() { ...@@ -913,6 +912,20 @@ void MediaSessionImpl::SkipAd() {
DidReceiveAction(media_session::mojom::MediaSessionAction::kSkipAd); DidReceiveAction(media_session::mojom::MediaSessionAction::kSkipAd);
} }
void MediaSessionImpl::SeekTo(base::TimeDelta seek_time) {
DidReceiveAction(
media_session::mojom::MediaSessionAction::kSeekTo,
blink::mojom::MediaSessionActionDetails::NewSeekTo(
blink::mojom::MediaSessionSeekToDetails::New(seek_time, false)));
}
void MediaSessionImpl::ScrubTo(base::TimeDelta seek_time) {
DidReceiveAction(
media_session::mojom::MediaSessionAction::kSeekTo,
blink::mojom::MediaSessionActionDetails::NewSeekTo(
blink::mojom::MediaSessionSeekToDetails::New(seek_time, true)));
}
void MediaSessionImpl::GetMediaImageBitmap( void MediaSessionImpl::GetMediaImageBitmap(
const media_session::MediaImage& image, const media_session::MediaImage& image,
int minimum_size_px, int minimum_size_px,
...@@ -1070,6 +1083,12 @@ void MediaSessionImpl::OnMediaSessionActionsChanged( ...@@ -1070,6 +1083,12 @@ void MediaSessionImpl::OnMediaSessionActionsChanged(
void MediaSessionImpl::DidReceiveAction( void MediaSessionImpl::DidReceiveAction(
media_session::mojom::MediaSessionAction action) { media_session::mojom::MediaSessionAction action) {
DidReceiveAction(action, nullptr /* details */);
}
void MediaSessionImpl::DidReceiveAction(
media_session::mojom::MediaSessionAction action,
blink::mojom::MediaSessionActionDetailsPtr details) {
MediaSessionUmaHelper::RecordMediaSessionUserAction( MediaSessionUmaHelper::RecordMediaSessionUserAction(
MediaSessionActionToUserAction(action), focused_); MediaSessionActionToUserAction(action), focused_);
...@@ -1108,7 +1127,7 @@ void MediaSessionImpl::DidReceiveAction( ...@@ -1108,7 +1127,7 @@ void MediaSessionImpl::DidReceiveAction(
if (!routed_service_) if (!routed_service_)
return; return;
routed_service_->GetClient()->DidReceiveAction(action, nullptr /* details */); routed_service_->GetClient()->DidReceiveAction(action, std::move(details));
} }
bool MediaSessionImpl::IsServiceActiveForRenderFrameHost(RenderFrameHost* rfh) { bool MediaSessionImpl::IsServiceActiveForRenderFrameHost(RenderFrameHost* rfh) {
...@@ -1195,6 +1214,12 @@ void MediaSessionImpl::RebuildAndNotifyActionsChanged() { ...@@ -1195,6 +1214,12 @@ void MediaSessionImpl::RebuildAndNotifyActionsChanged() {
actions.insert(media_session::mojom::MediaSessionAction::kStop); actions.insert(media_session::mojom::MediaSessionAction::kStop);
} }
// If we support kSeekTo then we support kScrubTo as well.
if (base::Contains(actions,
media_session::mojom::MediaSessionAction::kSeekTo)) {
actions.insert(media_session::mojom::MediaSessionAction::kScrubTo);
}
if (actions_ == actions) if (actions_ == actions)
return; return;
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote_set.h" #include "mojo/public/cpp/bindings/remote_set.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h" #include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "third_party/blink/public/mojom/mediasession/media_session.mojom.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
...@@ -238,6 +239,12 @@ class MediaSessionImpl : public MediaSession, ...@@ -238,6 +239,12 @@ class MediaSessionImpl : public MediaSession,
// Skip ad. // Skip ad.
CONTENT_EXPORT void SkipAd() override; CONTENT_EXPORT void SkipAd() override;
// Seek the media session to a specific time.
void SeekTo(base::TimeDelta seek_time) override;
// Scrub ("fast seek") the media session to a specific time.
void ScrubTo(base::TimeDelta seek_time) override;
// Downloads the bitmap version of a MediaImage at least |minimum_size_px| // Downloads the bitmap version of a MediaImage at least |minimum_size_px|
// and closest to |desired_size_px|. If the download failed, was too small or // and closest to |desired_size_px|. If the download failed, was too small or
// the image did not come from the media session then returns a null image. // the image did not come from the media session then returns a null image.
...@@ -254,12 +261,6 @@ class MediaSessionImpl : public MediaSession, ...@@ -254,12 +261,6 @@ class MediaSessionImpl : public MediaSession,
// Returns whether the action should be routed to |routed_service_|. // Returns whether the action should be routed to |routed_service_|.
bool ShouldRouteAction(media_session::mojom::MediaSessionAction action) const; bool ShouldRouteAction(media_session::mojom::MediaSessionAction action) const;
// Seek the media session to a specific time.
void SeekTo(base::TimeDelta seek_time) override {}
// Scrub ("fast seek") the media session to a specific time.
void ScrubTo(base::TimeDelta seek_time) override {}
private: private:
friend class content::WebContentsUserData<MediaSessionImpl>; friend class content::WebContentsUserData<MediaSessionImpl>;
friend class ::MediaSessionImplBrowserTest; friend class ::MediaSessionImplBrowserTest;
...@@ -365,6 +366,11 @@ class MediaSessionImpl : public MediaSession, ...@@ -365,6 +366,11 @@ class MediaSessionImpl : public MediaSession,
// changed. // changed.
void RebuildAndNotifyMetadataChanged(); void RebuildAndNotifyMetadataChanged();
// Called when a MediaSessionAction is received. The action will be forwarded
// to blink::MediaSession corresponding to the current routed service.
void DidReceiveAction(media_session::mojom::MediaSessionAction action,
blink::mojom::MediaSessionActionDetailsPtr details);
// A set of actions supported by |routed_service_| and the current media // A set of actions supported by |routed_service_| and the current media
// session. // session.
std::set<media_session::mojom::MediaSessionAction> actions_; std::set<media_session::mojom::MediaSessionAction> actions_;
......
...@@ -581,6 +581,75 @@ TEST_F(MediaSessionImplServiceRoutingTest, ...@@ -581,6 +581,75 @@ TEST_F(MediaSessionImplServiceRoutingTest,
run_loop.Run(); run_loop.Run();
} }
TEST_F(MediaSessionImplServiceRoutingTest,
TestSeekToBehaviorWhenMainFrameIsRouted) {
base::RunLoop run_loop;
StartPlayerForFrame(main_frame_);
StartPlayerForFrame(sub_frame_);
CreateServiceForFrame(main_frame_);
base::TimeDelta seek_time = base::TimeDelta::FromSeconds(10);
EXPECT_CALL(*GetClientForFrame(main_frame_),
DidReceiveAction(MediaSessionAction::kSeekTo, _))
.WillOnce([&run_loop, &seek_time](auto a, auto details) {
EXPECT_EQ(seek_time, details->get_seek_to()->seek_time);
EXPECT_FALSE(details->get_seek_to()->fast_seek);
run_loop.Quit();
});
services_[main_frame_]->EnableAction(MediaSessionAction::kSeekTo);
MediaSessionImpl::Get(contents())->SeekTo(seek_time);
run_loop.Run();
}
TEST_F(MediaSessionImplServiceRoutingTest,
TestScrubToBehaviorWhenMainFrameIsRouted) {
base::RunLoop run_loop;
StartPlayerForFrame(main_frame_);
StartPlayerForFrame(sub_frame_);
CreateServiceForFrame(main_frame_);
base::TimeDelta seek_time = base::TimeDelta::FromSeconds(10);
EXPECT_CALL(*GetClientForFrame(main_frame_),
DidReceiveAction(MediaSessionAction::kSeekTo, _))
.WillOnce([&run_loop, &seek_time](auto a, auto details) {
EXPECT_EQ(seek_time, details->get_seek_to()->seek_time);
EXPECT_TRUE(details->get_seek_to()->fast_seek);
run_loop.Quit();
});
services_[main_frame_]->EnableAction(MediaSessionAction::kSeekTo);
MediaSessionImpl::Get(contents())->ScrubTo(seek_time);
run_loop.Run();
}
TEST_F(MediaSessionImplServiceRoutingTest, SeekToActionEnablesScrubTo) {
CreateServiceForFrame(main_frame_);
StartPlayerForFrame(main_frame_);
std::set<MediaSessionAction> expected_actions(default_actions().begin(),
default_actions().end());
expected_actions.insert(MediaSessionAction::kSeekTo);
expected_actions.insert(MediaSessionAction::kScrubTo);
services_[main_frame_]->EnableAction(MediaSessionAction::kSeekTo);
media_session::test::MockMediaSessionMojoObserver observer(
*GetMediaSession());
observer.WaitForExpectedActions(expected_actions);
services_[main_frame_]->DisableAction(MediaSessionAction::kSeekTo);
observer.WaitForExpectedActions(default_actions());
}
TEST_F(MediaSessionImplServiceRoutingTest, TEST_F(MediaSessionImplServiceRoutingTest,
NotifyObserverMetadataWhenControllable) { NotifyObserverMetadataWhenControllable) {
media_session::MediaMetadata expected_metadata; media_session::MediaMetadata expected_metadata;
......
...@@ -39072,6 +39072,8 @@ Called by update_use_counter_css.py.--> ...@@ -39072,6 +39072,8 @@ Called by update_use_counter_css.py.-->
<int value="8" label="Seek forward"/> <int value="8" label="Seek forward"/>
<int value="9" label="Skip ad"/> <int value="9" label="Skip ad"/>
<int value="10" label="Stop"/> <int value="10" label="Stop"/>
<int value="11" label="Seek to"/>
<int value="12" label="Scrub to"/>
</enum> </enum>
<enum name="MediaSinkType"> <enum name="MediaSinkType">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment