Replace MediaController with media::FlingingController

FlingingRenderer needs to be updated when status changes happen on a
device that it is currently remoting to. Instead of coupling the
MediaController interface to the MediaStatusObserver interface, it is
simpler to add a new interface that groups the MC and MSO.

The best name for this interface is probably MediaRouteController, but
there is a naming collision with media_router::MediaRouteController.
mr::MRC is a class with baked in desktop and Mojo concepts, and
precise lifetime management, that is not immediatly extractable into
an interface. It is simpler to add a new interface now, and have
mr::MRC implement this interface later.

This CL adds the FlingingController as a high level, simple interface.
It will eventually be renamed to MediaRouteController, as part of
the work to unify the desktop and mobile remoting experience
(see crbug.com/820277).

Bug: 790766
Change-Id: I8248f2fd4b2022c371f37a8fd73af267b3735e7e
Reviewed-on: https://chromium-review.googlesource.com/1136008
Reviewed-by: Mounir Lamouri <mlamouri@chromium.org>
Reviewed-by: Dmitry Gozman <dgozman@chromium.org>
Reviewed-by: Takumi Fujimoto <takumif@chromium.org>
Commit-Queue: Thomas Guilbert <tguilbert@chromium.org>
Cr-Commit-Position: refs/heads/master@{#576942}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java
index bf4ee1c..5256a99 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java
@@ -390,14 +390,14 @@
      */
     @Nullable
     @CalledByNative
-    public MediaControllerBridge getMediaControllerBridge(String routeId) {
+    public FlingingControllerBridge getFlingingControllerBridge(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);
+        return new FlingingControllerBridge(controller);
     }
 
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaControllerBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/FlingingControllerBridge.java
similarity index 79%
rename from chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaControllerBridge.java
rename to chrome/android/java/src/org/chromium/chrome/browser/media/router/FlingingControllerBridge.java
index 3abcd92..e814562 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaControllerBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/FlingingControllerBridge.java
@@ -8,15 +8,15 @@
 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.
+ * A wrapper around a MediaController that allows the native code to use it, and to subscribe to
+ * status changes. See chrome/browser/media/android/remote/flinging_controller_bridge.h for the
+ * corresponding native code.
  */
 @JNINamespace("media_router")
-public class MediaControllerBridge {
+public class FlingingControllerBridge {
     private final MediaController mMediaController;
 
-    public MediaControllerBridge(MediaController mediaController) {
+    public FlingingControllerBridge(MediaController mediaController) {
         mMediaController = mediaController;
     }
 
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 96fe313..63dec56 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -723,8 +723,8 @@
   "java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterDialogController.java",
   "java/src/org/chromium/chrome/browser/media/router/DiscoveryCallback.java",
   "java/src/org/chromium/chrome/browser/media/router/DiscoveryDelegate.java",
+  "java/src/org/chromium/chrome/browser/media/router/FlingingControllerBridge.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",
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index dbbba00..3ed3fcd 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2338,8 +2338,8 @@
       "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/flinging_controller_bridge.cc",
+      "media/android/remote/flinging_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",
@@ -4475,7 +4475,7 @@
       "../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/media/router/FlingingControllerBridge.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",
diff --git a/chrome/browser/media/android/remote/flinging_controller_bridge.cc b/chrome/browser/media/android/remote/flinging_controller_bridge.cc
new file mode 100644
index 0000000..b5d1f27
--- /dev/null
+++ b/chrome/browser/media/android/remote/flinging_controller_bridge.cc
@@ -0,0 +1,73 @@
+// 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/flinging_controller_bridge.h"
+
+#include "jni/FlingingControllerBridge_jni.h"
+
+namespace media_router {
+
+FlingingControllerBridge::FlingingControllerBridge(
+    base::android::ScopedJavaGlobalRef<jobject> controller)
+    : j_flinging_controller_bridge_(controller) {}
+
+FlingingControllerBridge::~FlingingControllerBridge() = default;
+
+void FlingingControllerBridge::Play() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  Java_FlingingControllerBridge_play(env, j_flinging_controller_bridge_);
+}
+
+void FlingingControllerBridge::Pause() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  Java_FlingingControllerBridge_pause(env, j_flinging_controller_bridge_);
+}
+
+void FlingingControllerBridge::SetMute(bool mute) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  Java_FlingingControllerBridge_setMute(env, j_flinging_controller_bridge_,
+                                        mute);
+}
+
+void FlingingControllerBridge::SetVolume(float volume) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  Java_FlingingControllerBridge_setVolume(env, j_flinging_controller_bridge_,
+                                          volume);
+}
+
+void FlingingControllerBridge::Seek(base::TimeDelta time) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  Java_FlingingControllerBridge_seek(env, j_flinging_controller_bridge_,
+                                     time.InMilliseconds());
+}
+
+media::MediaController* FlingingControllerBridge::GetMediaController() {
+  return this;
+}
+
+void FlingingControllerBridge::AddMediaStatusObserver(
+    media::MediaStatusObserver* observer) {
+  NOTREACHED();
+}
+void FlingingControllerBridge::RemoveMediaStatusObserver(
+    media::MediaStatusObserver* observer) {
+  NOTREACHED();
+}
+
+base::TimeDelta FlingingControllerBridge::GetApproximateCurrentTime() {
+  // TODO(https://crbug.com/830871): Implement this method.
+  return base::TimeDelta();
+}
+
+}  // namespace media_router
diff --git a/chrome/browser/media/android/remote/flinging_controller_bridge.h b/chrome/browser/media/android/remote/flinging_controller_bridge.h
new file mode 100644
index 0000000..866e3e5
--- /dev/null
+++ b/chrome/browser/media/android/remote/flinging_controller_bridge.h
@@ -0,0 +1,45 @@
+// 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_FLINGING_CONTROLLER_BRIDGE_H_
+#define CHROME_BROWSER_MEDIA_ANDROID_REMOTE_FLINGING_CONTROLLER_BRIDGE_H_
+
+#include "base/android/scoped_java_ref.h"
+#include "base/time/time.h"
+#include "media/base/flinging_controller.h"
+#include "media/base/media_controller.h"
+
+namespace media_router {
+
+// Allows native code to call into a Java FlingingController.
+class FlingingControllerBridge : public media::FlingingController,
+                                 public media::MediaController {
+ public:
+  explicit FlingingControllerBridge(
+      base::android::ScopedJavaGlobalRef<jobject> controller);
+  ~FlingingControllerBridge() override;
+
+  // FlingingController implementation.
+  media::MediaController* GetMediaController() override;
+  void AddMediaStatusObserver(media::MediaStatusObserver* observer) override;
+  void RemoveMediaStatusObserver(media::MediaStatusObserver* observer) override;
+  base::TimeDelta GetApproximateCurrentTime() 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_flinging_controller_bridge_;
+
+  DISALLOW_COPY_AND_ASSIGN(FlingingControllerBridge);
+};
+
+}  // namespace media_router
+
+#endif  // CHROME_BROWSER_MEDIA_ANDROID_REMOTE_FLINGING_CONTROLLER_BRIDGE_H_
diff --git a/chrome/browser/media/android/remote/media_controller_bridge.cc b/chrome/browser/media/android/remote/media_controller_bridge.cc
deleted file mode 100644
index 7f42cb7..0000000
--- a/chrome/browser/media/android/remote/media_controller_bridge.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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
diff --git a/chrome/browser/media/android/remote/media_controller_bridge.h b/chrome/browser/media/android/remote/media_controller_bridge.h
deleted file mode 100644
index a854346..0000000
--- a/chrome/browser/media/android/remote/media_controller_bridge.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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 "media/base/media_controller.h"
-
-namespace media_router {
-
-// Allows native code to call into a Java MediaController.
-class MediaControllerBridge : public media::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_
diff --git a/chrome/browser/media/android/router/media_router_android.cc b/chrome/browser/media/android/router/media_router_android.cc
index 3546db9..41656d2 100644
--- a/chrome/browser/media/android/router/media_router_android.cc
+++ b/chrome/browser/media/android/router/media_router_android.cc
@@ -316,9 +316,9 @@
     observer.OnRoutesUpdated(active_routes_, std::vector<MediaRoute::Id>());
 }
 
-std::unique_ptr<media::MediaController> MediaRouterAndroid::GetMediaController(
-    const MediaRoute::Id& route_id) {
-  return bridge_->GetMediaController(route_id);
+std::unique_ptr<media::FlingingController>
+MediaRouterAndroid::GetFlingingController(const MediaRoute::Id& route_id) {
+  return bridge_->GetFlingingController(route_id);
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/android/router/media_router_android.h b/chrome/browser/media/android/router/media_router_android.h
index 74e8960..f500f48 100644
--- a/chrome/browser/media/android/router/media_router_android.h
+++ b/chrome/browser/media/android/router/media_router_android.h
@@ -65,7 +65,7 @@
                    const std::string& search_input,
                    const std::string& domain,
                    MediaSinkSearchResponseCallback sink_callback) override;
-  std::unique_ptr<media::MediaController> GetMediaController(
+  std::unique_ptr<media::FlingingController> GetFlingingController(
       const MediaRoute::Id& route_id) override;
 
   // The methods called by the Java bridge.
diff --git a/chrome/browser/media/android/router/media_router_android_bridge.cc b/chrome/browser/media/android/router/media_router_android_bridge.cc
index 9a07306..f20ab550 100644
--- a/chrome/browser/media/android/router/media_router_android_bridge.cc
+++ b/chrome/browser/media/android/router/media_router_android_bridge.cc
@@ -6,7 +6,7 @@
 
 #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/remote/flinging_controller_bridge.h"
 #include "chrome/browser/media/android/router/media_router_android.h"
 #include "jni/ChromeMediaRouter_jni.h"
 #include "media/base/media_controller.h"
@@ -120,21 +120,22 @@
                                                  jsource_id);
 }
 
-std::unique_ptr<media::MediaController>
-MediaRouterAndroidBridge::GetMediaController(const MediaRoute::Id& route_id) {
+std::unique_ptr<media::FlingingController>
+MediaRouterAndroidBridge::GetFlingingController(
+    const MediaRoute::Id& route_id) {
   JNIEnv* env = base::android::AttachCurrentThread();
   ScopedJavaLocalRef<jstring> jroute_id =
       base::android::ConvertUTF8ToJavaString(env, route_id);
 
-  ScopedJavaGlobalRef<jobject> media_controller;
+  ScopedJavaGlobalRef<jobject> flinging_controller;
 
-  media_controller.Reset(Java_ChromeMediaRouter_getMediaControllerBridge(
+  flinging_controller.Reset(Java_ChromeMediaRouter_getFlingingControllerBridge(
       env, java_media_router_, jroute_id));
 
-  if (media_controller.is_null())
+  if (flinging_controller.is_null())
     return nullptr;
 
-  return std::make_unique<MediaControllerBridge>(media_controller);
+  return std::make_unique<FlingingControllerBridge>(flinging_controller);
 }
 
 void MediaRouterAndroidBridge::OnSinksReceived(
diff --git a/chrome/browser/media/android/router/media_router_android_bridge.h b/chrome/browser/media/android/router/media_router_android_bridge.h
index d5e81f9f..d4c7891 100644
--- a/chrome/browser/media/android/router/media_router_android_bridge.h
+++ b/chrome/browser/media/android/router/media_router_android_bridge.h
@@ -10,7 +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 "media/base/media_controller.h"
+#include "media/base/flinging_controller.h"
 #include "url/origin.h"
 
 namespace media_router {
@@ -44,7 +44,7 @@
   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<media::MediaController> GetMediaController(
+  virtual std::unique_ptr<media::FlingingController> GetFlingingController(
       const MediaRoute::Id& route_id);
 
   // Methods called by the Java counterpart.
diff --git a/chrome/browser/media/router/media_router.h b/chrome/browser/media/router/media_router.h
index a11f239..cf856a5 100644
--- a/chrome/browser/media/router/media_router.h
+++ b/chrome/browser/media/router/media_router.h
@@ -23,7 +23,7 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/sessions/core/session_id.h"
 #include "content/public/browser/presentation_service_delegate.h"
-#include "media/base/media_controller.h"
+#include "media/base/flinging_controller.h"
 
 namespace content {
 class WebContents;
@@ -190,9 +190,10 @@
   // 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 controller that sends commands to media within a route, and
+  // propagates MediaStatus changes.
   // Returns a nullptr if no controller can be be found from |route_id|.
-  virtual std::unique_ptr<media::MediaController> GetMediaController(
+  virtual std::unique_ptr<media::FlingingController> GetFlingingController(
       const MediaRoute::Id& route_id) = 0;
 
 #if !defined(OS_ANDROID)
diff --git a/chrome/browser/media/router/media_router_base.cc b/chrome/browser/media/router/media_router_base.cc
index e5c4a5a..e08ec6c 100644
--- a/chrome/browser/media/router/media_router_base.cc
+++ b/chrome/browser/media/router/media_router_base.cc
@@ -86,8 +86,8 @@
   return internal_routes_observer_->current_routes;
 }
 
-std::unique_ptr<media::MediaController> MediaRouterBase::GetMediaController(
-    const MediaRoute::Id& route_id) {
+std::unique_ptr<media::FlingingController>
+MediaRouterBase::GetFlingingController(const MediaRoute::Id& route_id) {
   return nullptr;
 }
 
diff --git a/chrome/browser/media/router/media_router_base.h b/chrome/browser/media/router/media_router_base.h
index 330d14e..0f9916f 100644
--- a/chrome/browser/media/router/media_router_base.h
+++ b/chrome/browser/media/router/media_router_base.h
@@ -17,7 +17,6 @@
 #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 "media/base/media_controller.h"
 #include "third_party/blink/public/platform/modules/presentation/presentation.mojom.h"
 
 namespace media_router {
@@ -35,7 +34,7 @@
   void OnIncognitoProfileShutdown() override;
   IssueManager* GetIssueManager() final;
   std::vector<MediaRoute> GetCurrentRoutes() const override;
-  std::unique_ptr<media::MediaController> GetMediaController(
+  std::unique_ptr<media::FlingingController> GetFlingingController(
       const MediaRoute::Id& route_id) override;
 #if !defined(OS_ANDROID)
   scoped_refptr<MediaRouteController> GetRouteController(
diff --git a/chrome/browser/media/router/presentation/presentation_service_delegate_impl.cc b/chrome/browser/media/router/presentation/presentation_service_delegate_impl.cc
index 1bab943..66f7a24 100644
--- a/chrome/browser/media/router/presentation/presentation_service_delegate_impl.cc
+++ b/chrome/browser/media/router/presentation/presentation_service_delegate_impl.cc
@@ -673,8 +673,8 @@
     observer.OnDefaultPresentationRemoved();
 }
 
-std::unique_ptr<media::MediaController>
-PresentationServiceDelegateImpl::GetMediaController(
+std::unique_ptr<media::FlingingController>
+PresentationServiceDelegateImpl::GetFlingingController(
     int render_process_id,
     int render_frame_id,
     const std::string& presentation_id) {
@@ -684,7 +684,7 @@
   if (route_id.empty())
     return nullptr;
 
-  return router_->GetMediaController(route_id);
+  return router_->GetFlingingController(route_id);
 }
 
 MediaRoute::Id PresentationServiceDelegateImpl::GetRouteId(
diff --git a/chrome/browser/media/router/presentation/presentation_service_delegate_impl.h b/chrome/browser/media/router/presentation/presentation_service_delegate_impl.h
index 6f5e207..5db27b4 100644
--- a/chrome/browser/media/router/presentation/presentation_service_delegate_impl.h
+++ b/chrome/browser/media/router/presentation/presentation_service_delegate_impl.h
@@ -25,7 +25,6 @@
 #include "content/public/browser/presentation_service_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
-#include "media/base/media_controller.h"
 
 namespace content {
 class PresentationScreenAvailabilityListener;
@@ -110,7 +109,7 @@
   void Terminate(int render_process_id,
                  int render_frame_id,
                  const std::string& presentation_id) override;
-  std::unique_ptr<media::MediaController> GetMediaController(
+  std::unique_ptr<media::FlingingController> GetFlingingController(
       int render_process_id,
       int render_frame_id,
       const std::string& presentation_id) override;
diff --git a/content/browser/media/flinging_renderer.cc b/content/browser/media/flinging_renderer.cc
index b6119358..fd24901 100644
--- a/content/browser/media/flinging_renderer.cc
+++ b/content/browser/media/flinging_renderer.cc
@@ -15,7 +15,7 @@
 namespace content {
 
 FlingingRenderer::FlingingRenderer(
-    std::unique_ptr<media::MediaController> controller)
+    std::unique_ptr<media::FlingingController> controller)
     : controller_(std::move(controller)) {}
 
 FlingingRenderer::~FlingingRenderer() = default;
@@ -43,15 +43,15 @@
   if (!presentation_delegate)
     return nullptr;
 
-  auto media_controller = presentation_delegate->GetMediaController(
+  auto flinging_controller = presentation_delegate->GetFlingingController(
       render_frame_host->GetProcess()->GetID(),
       render_frame_host->GetRoutingID(), presentation_id);
 
-  if (!media_controller)
+  if (!flinging_controller)
     return nullptr;
 
   return base::WrapUnique<FlingingRenderer>(
-      new FlingingRenderer(std::move(media_controller)));
+      new FlingingRenderer(std::move(flinging_controller)));
 }
 
 // media::Renderer implementation
@@ -76,21 +76,21 @@
 
 void FlingingRenderer::StartPlayingFrom(base::TimeDelta time) {
   DVLOG(2) << __func__;
-  controller_->Seek(time);
-  controller_->Play();
+  controller_->GetMediaController()->Seek(time);
+  controller_->GetMediaController()->Play();
 }
 
 void FlingingRenderer::SetPlaybackRate(double playback_rate) {
   DVLOG(2) << __func__;
   if (playback_rate == 0)
-    controller_->Pause();
+    controller_->GetMediaController()->Pause();
   else
-    controller_->Play();
+    controller_->GetMediaController()->Play();
 }
 
 void FlingingRenderer::SetVolume(float volume) {
   DVLOG(2) << __func__;
-  controller_->SetVolume(volume);
+  controller_->GetMediaController()->SetVolume(volume);
 }
 
 base::TimeDelta FlingingRenderer::GetMediaTime() {
diff --git a/content/browser/media/flinging_renderer.h b/content/browser/media/flinging_renderer.h
index 38c411c..f5a0eee 100644
--- a/content/browser/media/flinging_renderer.h
+++ b/content/browser/media/flinging_renderer.h
@@ -7,7 +7,7 @@
 
 #include "base/callback.h"
 #include "content/common/content_export.h"
-#include "media/base/media_controller.h"
+#include "media/base/flinging_controller.h"
 #include "media/base/media_resource.h"
 #include "media/base/renderer.h"
 #include "media/base/renderer_client.h"
@@ -50,9 +50,10 @@
  private:
   friend class FlingingRendererTest;
 
-  explicit FlingingRenderer(std::unique_ptr<media::MediaController> controller);
+  explicit FlingingRenderer(
+      std::unique_ptr<media::FlingingController> controller);
 
-  std::unique_ptr<media::MediaController> controller_;
+  std::unique_ptr<media::FlingingController> controller_;
 
   DISALLOW_COPY_AND_ASSIGN(FlingingRenderer);
 };
diff --git a/content/browser/media/flinging_renderer_unittest.cc b/content/browser/media/flinging_renderer_unittest.cc
index 680ac22..629e79c 100644
--- a/content/browser/media/flinging_renderer_unittest.cc
+++ b/content/browser/media/flinging_renderer_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/media/flinging_renderer.h"
 
+#include "base/time/time.h"
 #include "base/version.h"
 #include "media/base/media_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -23,14 +24,33 @@
   MOCK_METHOD1(Seek, void(base::TimeDelta));
 };
 
+class MockFlingingController : public media::FlingingController {
+ public:
+  explicit MockFlingingController(media::MediaController* media_controller)
+      : media_controller_(media_controller) {}
+
+  media::MediaController* GetMediaController() { return media_controller_; }
+
+  MOCK_METHOD1(AddMediaStatusObserver, void(media::MediaStatusObserver*));
+  MOCK_METHOD1(RemoveMediaStatusObserver, void(media::MediaStatusObserver*));
+  MOCK_METHOD0(GetApproximateCurrentTime, base::TimeDelta());
+
+ private:
+  media::MediaController* media_controller_;
+};
+
 class FlingingRendererTest : public testing::Test {
  public:
   FlingingRendererTest()
       : media_controller_(new StrictMock<MockMediaController>()),
-        renderer_(std::unique_ptr<media::MediaController>(media_controller_)) {}
+        flinging_controller_(
+            new StrictMock<MockFlingingController>(media_controller_.get())),
+        renderer_(
+            std::unique_ptr<media::FlingingController>(flinging_controller_)) {}
 
  protected:
-  StrictMock<MockMediaController>* media_controller_;
+  std::unique_ptr<MockMediaController> media_controller_;
+  StrictMock<MockFlingingController>* flinging_controller_;
   FlingingRenderer renderer_;
 };
 
diff --git a/content/browser/presentation/presentation_service_impl_unittest.cc b/content/browser/presentation/presentation_service_impl_unittest.cc
index a635d44..ce326a2 100644
--- a/content/browser/presentation/presentation_service_impl_unittest.cc
+++ b/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -131,8 +131,8 @@
                void(int render_process_id,
                     int render_frame_id,
                     const std::string& presentation_id));
-  MOCK_METHOD3(GetMediaController,
-               std::unique_ptr<media::MediaController>(
+  MOCK_METHOD3(GetFlingingController,
+               std::unique_ptr<media::FlingingController>(
                    int render_process_id,
                    int render_frame_id,
                    const std::string& presentation_id));
diff --git a/content/public/browser/presentation_service_delegate.h b/content/public/browser/presentation_service_delegate.h
index 0320264..73f8cfea 100644
--- a/content/public/browser/presentation_service_delegate.h
+++ b/content/public/browser/presentation_service_delegate.h
@@ -13,7 +13,7 @@
 #include "base/callback.h"
 #include "content/common/content_export.h"
 #include "content/public/common/presentation_connection_message.h"
-#include "media/base/media_controller.h"
+#include "media/base/flinging_controller.h"
 #include "third_party/blink/public/platform/modules/presentation/presentation.mojom.h"
 
 namespace content {
@@ -170,11 +170,11 @@
                          int render_frame_id,
                          const std::string& presentation_id) = 0;
 
-  // Gets a MediaController for a given presentation ID.
+  // Gets a FlingingController 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<media::MediaController> GetMediaController(
+  virtual std::unique_ptr<media::FlingingController> GetFlingingController(
       int render_process_id,
       int render_frame_id,
       const std::string& presentation_id) = 0;
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index ac60e93..7d33caa 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -144,6 +144,7 @@
     "fallback_video_decoder.cc",
     "fallback_video_decoder.h",
     "feedback_signal_accumulator.h",
+    "flinging_controller.h",
     "hdr_metadata.cc",
     "hdr_metadata.h",
     "key_system_names.cc",
diff --git a/media/base/flinging_controller.h b/media/base/flinging_controller.h
new file mode 100644
index 0000000..1bf2634
--- /dev/null
+++ b/media/base/flinging_controller.h
@@ -0,0 +1,37 @@
+// 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 MEDIA_BASE_FLINGING_CONTROLLER_H_
+#define MEDIA_BASE_FLINGING_CONTROLLER_H_
+
+#include "base/time/time.h"
+#include "media/base/media_controller.h"
+#include "media/base/media_status_observer.h"
+
+namespace media {
+
+// Interface that groups all the necessary hooks to control media that is being
+// flung to a cast device, as part of RemotePlayback.
+// TODO(https://crbug.com/820277): Rename this interface to MediaRouteController
+// and change media_router::MediaRouteController to MojoMediaRouteController.
+class FlingingController {
+ public:
+  virtual ~FlingingController() = default;
+
+  // Gets a MediaContoller owned by |this| to issue simple commands.
+  virtual MediaController* GetMediaController() = 0;
+
+  // Subscribe or un-subscribe to changes in the media status.
+  virtual void AddMediaStatusObserver(MediaStatusObserver* observer) = 0;
+  virtual void RemoveMediaStatusObserver(MediaStatusObserver* observer) = 0;
+
+  // Gets the current media playback time. Implementers may sacrifice precision
+  // to avoid a round-trip query to cast devices (see
+  // RemoteMediaPlayer.getApproximateStreamPosition() for example).
+  virtual base::TimeDelta GetApproximateCurrentTime() = 0;
+};
+
+}  // namespace media
+
+#endif  // MEDIA_BASE_FLINGING_CONTROLLER_H_