Commit 42b46656 authored by Thomas Guilbert's avatar Thomas Guilbert Committed by Commit Bot

Add GetMediaController to PresentationService

This CL adds the ability to get a MediaControllerBridge from a
presentation ID. The presentation ID is first converted to a route ID,
before being sent to the MediaRouterAndroid.

The MediaControllerBridge allows native code to forward commands to a
Java MediaController. Currently, only RemotePlayback will use this
path, and the Java MediaController interface is only implemented by
the RemoteMediaPlayerWrapper.

Bug: 790766
Change-Id: Ie089aff905fffd2521053620f79fe739ab6eb3a1
Reviewed-on: https://chromium-review.googlesource.com/930472Reviewed-by: default avatarNick Carter <nick@chromium.org>
Reviewed-by: default avatarDerek Cheng <imcheng@chromium.org>
Reviewed-by: default avatarMounir Lamouri <mlamouri@chromium.org>
Reviewed-by: default avatarTakumi Fujimoto <takumif@chromium.org>
Commit-Queue: Thomas Guilbert <tguilbert@chromium.org>
Cr-Commit-Position: refs/heads/master@{#542646}
parent c8a7cccf
......@@ -360,6 +360,23 @@ public class ChromeMediaRouter implements MediaRouteManager {
provider.sendStringMessage(routeId, message, callbackId);
}
/**
* Gets a media controller to be used by native.
* @param routeId The route ID tied to the CastSession for which we want a media controller.
* @return A MediaControllerBridge if it can be obtained from |routeId|, null otherwise.
*/
@Nullable
@CalledByNative
public MediaControllerBridge getMediaControllerBridge(String routeId) {
MediaRouteProvider provider = mRouteIdsToProviders.get(routeId);
if (provider == null) return null;
MediaController controller = provider.getMediaController(routeId);
if (controller == null) return null;
return new MediaControllerBridge(controller);
}
@VisibleForTesting
protected ChromeMediaRouter(long nativeMediaRouterAndroidBridge) {
mNativeMediaRouterAndroidBridge = nativeMediaRouterAndroidBridge;
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.media.router;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
/**
* A wrapper around a MediaController that allows the native code to use it.
* See chrome/browser/media/android/remote/media_controller_bridge.h for the corresponding native
* code.
*/
@JNINamespace("media_router")
public class MediaControllerBridge {
private final MediaController mMediaController;
public MediaControllerBridge(MediaController mediaController) {
mMediaController = mediaController;
}
@CalledByNative
public void play() {
mMediaController.play();
}
@CalledByNative
public void pause() {
mMediaController.pause();
}
@CalledByNative
public void setMute(boolean mute) {
mMediaController.setMute(mute);
}
@CalledByNative
public void setVolume(float volume) {
mMediaController.setVolume(volume);
}
@CalledByNative
public void seek(long positionInMs) {
mMediaController.seek(positionInMs);
}
}
......@@ -594,6 +594,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterDialogController.java",
"java/src/org/chromium/chrome/browser/media/router/DiscoveryDelegate.java",
"java/src/org/chromium/chrome/browser/media/router/MediaController.java",
"java/src/org/chromium/chrome/browser/media/router/MediaControllerBridge.java",
"java/src/org/chromium/chrome/browser/media/router/MediaRoute.java",
"java/src/org/chromium/chrome/browser/media/router/MediaRouteChooserDialogManager.java",
"java/src/org/chromium/chrome/browser/media/router/MediaRouteControllerDialogManager.java",
......
......@@ -2231,6 +2231,8 @@ jumbo_split_static_library("browser") {
"media/android/cdm/media_drm_license_manager.h",
"media/android/cdm/media_drm_storage_factory.cc",
"media/android/cdm/media_drm_storage_factory.h",
"media/android/remote/media_controller_bridge.cc",
"media/android/remote/media_controller_bridge.h",
"media/android/remote/record_cast_action.cc",
"media/android/remote/remote_media_player_bridge.cc",
"media/android/remote/remote_media_player_bridge.h",
......@@ -4294,6 +4296,7 @@ if (is_android) {
"../android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java",
"../android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java",
"../android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterDialogController.java",
"../android/java/src/org/chromium/chrome/browser/media/router/MediaControllerBridge.java",
"../android/java/src/org/chromium/chrome/browser/metrics/LaunchMetrics.java",
"../android/java/src/org/chromium/chrome/browser/metrics/PageLoadMetrics.java",
"../android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media/android/remote/media_controller_bridge.h"
#include "jni/MediaControllerBridge_jni.h"
namespace media_router {
MediaControllerBridge::MediaControllerBridge(
base::android::ScopedJavaGlobalRef<jobject> controller)
: j_media_controller_bridge_(controller) {}
MediaControllerBridge::~MediaControllerBridge() = default;
void MediaControllerBridge::Play() {
JNIEnv* env = base::android::AttachCurrentThread();
DCHECK(env);
Java_MediaControllerBridge_play(env, j_media_controller_bridge_);
}
void MediaControllerBridge::Pause() {
JNIEnv* env = base::android::AttachCurrentThread();
DCHECK(env);
Java_MediaControllerBridge_pause(env, j_media_controller_bridge_);
}
void MediaControllerBridge::SetMute(bool mute) {
JNIEnv* env = base::android::AttachCurrentThread();
DCHECK(env);
Java_MediaControllerBridge_setMute(env, j_media_controller_bridge_, mute);
}
void MediaControllerBridge::SetVolume(float volume) {
JNIEnv* env = base::android::AttachCurrentThread();
DCHECK(env);
Java_MediaControllerBridge_setVolume(env, j_media_controller_bridge_, volume);
}
void MediaControllerBridge::Seek(base::TimeDelta time) {
JNIEnv* env = base::android::AttachCurrentThread();
DCHECK(env);
Java_MediaControllerBridge_seek(env, j_media_controller_bridge_,
time.InMilliseconds());
}
} // namespace media_router
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_MEDIA_ANDROID_REMOTE_MEDIA_CONTROLLER_BRIDGE_H_
#define CHROME_BROWSER_MEDIA_ANDROID_REMOTE_MEDIA_CONTROLLER_BRIDGE_H_
#include "base/android/scoped_java_ref.h"
#include "base/time/time.h"
#include "content/public/browser/media_controller.h"
namespace media_router {
// Allows native code to call into a Java MediaController.
class MediaControllerBridge : public content::MediaController {
public:
explicit MediaControllerBridge(
base::android::ScopedJavaGlobalRef<jobject> controller);
~MediaControllerBridge() override;
// MediaController implementation.
void Play() override;
void Pause() override;
void SetMute(bool mute) override;
void SetVolume(float volume) override;
void Seek(base::TimeDelta time) override;
private:
// Java MediaControllerBridge instance.
base::android::ScopedJavaGlobalRef<jobject> j_media_controller_bridge_;
DISALLOW_COPY_AND_ASSIGN(MediaControllerBridge);
};
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ANDROID_REMOTE_MEDIA_CONTROLLER_BRIDGE_H_
......@@ -311,4 +311,9 @@ void MediaRouterAndroid::RemoveRoute(const MediaRoute::Id& route_id) {
observer.OnRoutesUpdated(active_routes_, std::vector<MediaRoute::Id>());
}
std::unique_ptr<content::MediaController>
MediaRouterAndroid::GetMediaController(const MediaRoute::Id& route_id) {
return bridge_->GetMediaController(route_id);
}
} // namespace media_router
......@@ -65,6 +65,8 @@ class MediaRouterAndroid : public MediaRouterBase {
const std::string& search_input,
const std::string& domain,
MediaSinkSearchResponseCallback sink_callback) override;
std::unique_ptr<content::MediaController> GetMediaController(
const MediaRoute::Id& route_id) override;
// The methods called by the Java bridge.
// Notifies the media router that information about sinks is received for
......
......@@ -6,12 +6,15 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "chrome/browser/media/android/remote/media_controller_bridge.h"
#include "chrome/browser/media/android/router/media_router_android.h"
#include "content/public/browser/media_controller.h"
#include "jni/ChromeMediaRouter_jni.h"
using base::android::ConvertUTF8ToJavaString;
using base::android::ConvertJavaStringToUTF8;
using base::android::JavaRef;
using base::android::ScopedJavaGlobalRef;
using base::android::ScopedJavaLocalRef;
using base::android::AttachCurrentThread;
......@@ -117,6 +120,23 @@ void MediaRouterAndroidBridge::StopObservingMediaSinks(
jsource_id);
}
std::unique_ptr<content::MediaController>
MediaRouterAndroidBridge::GetMediaController(const MediaRoute::Id& route_id) {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jstring> jroute_id =
base::android::ConvertUTF8ToJavaString(env, route_id);
ScopedJavaGlobalRef<jobject> media_controller;
media_controller.Reset(Java_ChromeMediaRouter_getMediaControllerBridge(
env, java_media_router_, jroute_id));
if (media_controller.is_null())
return nullptr;
return std::make_unique<MediaControllerBridge>(media_controller);
}
void MediaRouterAndroidBridge::OnSinksReceived(
JNIEnv* env,
const JavaRef<jobject>& obj,
......
......@@ -10,6 +10,7 @@
#include "chrome/common/media_router/media_route.h"
#include "chrome/common/media_router/media_sink.h"
#include "chrome/common/media_router/media_source.h"
#include "content/public/browser/media_controller.h"
#include "url/origin.h"
namespace media_router {
......@@ -43,6 +44,8 @@ class MediaRouterAndroidBridge {
virtual void DetachRoute(const MediaRoute::Id& route_id);
virtual bool StartObservingMediaSinks(const MediaSource::Id& source_id);
virtual void StopObservingMediaSinks(const MediaSource::Id& source_id);
virtual std::unique_ptr<content::MediaController> GetMediaController(
const MediaRoute::Id& route_id);
// Methods called by the Java counterpart.
void OnSinksReceived(JNIEnv* env,
......
......@@ -22,6 +22,7 @@
#include "chrome/common/media_router/media_sink.h"
#include "chrome/common/media_router/media_source.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/media_controller.h"
#include "content/public/browser/presentation_service_delegate.h"
namespace content {
......@@ -189,6 +190,11 @@ class MediaRouter : public KeyedService {
// there is a change to the media routes, subclass MediaRoutesObserver.
virtual std::vector<MediaRoute> GetCurrentRoutes() const = 0;
// Returns a controller that directly sends commands to media within a route.
// Returns a nullptr if no controller can be be found from |route_id|.
virtual std::unique_ptr<content::MediaController> GetMediaController(
const MediaRoute::Id& route_id) = 0;
#if !defined(OS_ANDROID)
// Returns a controller for sending media commands to a route. Returns a
// nullptr if no MediaRoute exists for the given |route_id|.
......
......@@ -84,6 +84,11 @@ std::vector<MediaRoute> MediaRouterBase::GetCurrentRoutes() const {
return internal_routes_observer_->current_routes;
}
std::unique_ptr<content::MediaController> MediaRouterBase::GetMediaController(
const MediaRoute::Id& route_id) {
return nullptr;
}
#if !defined(OS_ANDROID)
scoped_refptr<MediaRouteController> MediaRouterBase::GetRouteController(
const MediaRoute::Id& route_id) {
......
......@@ -17,6 +17,7 @@
#include "chrome/browser/media/router/media_router.h"
#include "chrome/browser/media/router/media_routes_observer.h"
#include "chrome/common/media_router/media_route.h"
#include "content/public/browser/media_controller.h"
namespace media_router {
......@@ -33,6 +34,8 @@ class MediaRouterBase : public MediaRouter {
void OnIncognitoProfileShutdown() override;
IssueManager* GetIssueManager() final;
std::vector<MediaRoute> GetCurrentRoutes() const override;
std::unique_ptr<content::MediaController> GetMediaController(
const MediaRoute::Id& route_id) override;
#if !defined(OS_ANDROID)
scoped_refptr<MediaRouteController> GetRouteController(
const MediaRoute::Id& route_id) override;
......
......@@ -673,6 +673,20 @@ void PresentationServiceDelegateImpl::ClearDefaultPresentationRequest() {
observer.OnDefaultPresentationRemoved();
}
std::unique_ptr<content::MediaController>
PresentationServiceDelegateImpl::GetMediaController(
int render_process_id,
int render_frame_id,
const std::string& presentation_id) {
const RenderFrameHostId rfh_id(render_process_id, render_frame_id);
MediaRoute::Id route_id = GetRouteId(rfh_id, presentation_id);
if (route_id.empty())
return nullptr;
return router_->GetMediaController(route_id);
}
MediaRoute::Id PresentationServiceDelegateImpl::GetRouteId(
const RenderFrameHostId& render_frame_host_id,
const std::string& presentation_id) const {
......
......@@ -21,6 +21,7 @@
#include "chrome/browser/media/router/presentation/presentation_service_delegate_observers.h"
#include "chrome/browser/media/router/presentation/render_frame_host_id.h"
#include "chrome/common/media_router/media_source.h"
#include "content/public/browser/media_controller.h"
#include "content/public/browser/presentation_request.h"
#include "content/public/browser/presentation_service_delegate.h"
#include "content/public/browser/web_contents_observer.h"
......@@ -110,6 +111,10 @@ class PresentationServiceDelegateImpl
void Terminate(int render_process_id,
int render_frame_id,
const std::string& presentation_id) override;
std::unique_ptr<content::MediaController> GetMediaController(
int render_process_id,
int render_frame_id,
const std::string& presentation_id) override;
void ListenForConnectionStateChange(
int render_process_id,
int render_frame_id,
......
......@@ -134,6 +134,11 @@ class MockPresentationServiceDelegate
void(int render_process_id,
int render_frame_id,
const std::string& presentation_id));
MOCK_METHOD3(GetMediaController,
std::unique_ptr<content::MediaController>(
int render_process_id,
int render_frame_id,
const std::string& presentation_id));
// PresentationConnectionMessage is move-only.
// TODO(crbug.com/729950): Use MOCK_METHOD directly once GMock gets the
......
......@@ -147,6 +147,7 @@ jumbo_source_set("browser_sources") {
"manifest_icon_downloader.h",
"manifest_icon_selector.h",
"media_capture_devices.h",
"media_controller.h",
"media_device_id.cc",
"media_device_id.h",
"media_request_state.h",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_PUBLIC_BROWSER_MEDIA_CONTROLLER_H_
#define CONTENT_PUBLIC_BROWSER_MEDIA_CONTROLLER_H_
#include "base/time/time.h"
namespace content {
// High level interface that allows a controller to issue simple media commands.
// Modeled after the media_router.mojom.MediaController interface.
// State changes will be signaled via the MediaStatusObserver interface.
// TODO(tguilbert): Add MediaStatusObserver interface.
class MediaController {
public:
virtual ~MediaController() = default;
// Starts playing the media if it is paused. Is a no-op if not supported by
// the media or the media is already playing.
virtual void Play() = 0;
// Pauses the media if it is playing. Is a no-op if not supported by the media
// or the media is already paused.
virtual void Pause() = 0;
// Mutes the media if |mute| is true, and unmutes it if false. Is a no-op if
// not supported by the media.
virtual void SetMute(bool mute) = 0;
// Changes the current volume of the media, with 1 being the highest and 0
// being the lowest/no sound. Does not change the (un)muted state of the
// media. Is a no-op if not supported by the media.
virtual void SetVolume(float volume) = 0;
// Sets the current playback position. |time| must be less than or equal to
// the duration of the media. Is a no-op if the media doesn't support seeking.
virtual void Seek(base::TimeDelta time) = 0;
};
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_MEDIA_CONTROLLER_H_
......@@ -12,6 +12,7 @@
#include "base/callback.h"
#include "content/common/content_export.h"
#include "content/public/browser/media_controller.h"
#include "content/public/common/presentation_connection_message.h"
#include "content/public/common/presentation_info.h"
#include "third_party/WebKit/public/platform/modules/presentation/presentation.mojom.h"
......@@ -168,6 +169,15 @@ class CONTENT_EXPORT ControllerPresentationServiceDelegate
int render_frame_id,
const std::string& presentation_id) = 0;
// Gets a MediaController for a given presentation ID.
// |render_process_id|, |render_frame_id|: ID of originating frame.
// |presentation_id|: The ID of the presentation for which we want a
// Controller.
virtual std::unique_ptr<MediaController> GetMediaController(
int render_process_id,
int render_frame_id,
const std::string& presentation_id) = 0;
// Continuously listen for state changes for a PresentationConnection in a
// frame.
// |render_process_id|, |render_frame_id|: ID of frame.
......
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