[RemotePlayback] Keep track of source compatibility and reject prompt() correspondingly

BUG=659675,659677,659679
TEST=manual on avayvod.github.io/remote-playback/test.html
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2

Review-Url: https://codereview.chromium.org/2480003002
Cr-Commit-Position: refs/heads/master@{#431516}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java
index 33dbff5..829330db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java
@@ -9,6 +9,7 @@
 import org.chromium.base.Log;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.blink_public.platform.modules.remoteplayback.WebRemotePlaybackAvailability;
 import org.chromium.chrome.browser.media.remote.RemoteVideoInfo.PlayerState;
 
 /**
@@ -318,9 +319,19 @@
     }
 
     private void onRouteAvailabilityChange() {
+        Log.d(TAG, "onRouteAvailabilityChange: " + mRouteIsAvailable + ", " + mIsPlayable);
         if (mNativeRemoteMediaPlayerBridge == 0) return;
-        boolean usable = mRouteIsAvailable && mIsPlayable;
-        nativeOnRouteAvailabilityChanged(mNativeRemoteMediaPlayerBridge, usable);
+
+        int availability = WebRemotePlaybackAvailability.DeviceNotAvailable;
+        if (!mRouteIsAvailable && !mIsPlayable) {
+            availability = WebRemotePlaybackAvailability.SourceNotSupported;
+        } else if (mRouteIsAvailable && mIsPlayable) {
+            availability = WebRemotePlaybackAvailability.DeviceAvailable;
+        } else if (mRouteIsAvailable) {
+            // mIsPlayable is false here.
+            availability = WebRemotePlaybackAvailability.SourceNotCompatible;
+        }
+        nativeOnRouteAvailabilityChanged(mNativeRemoteMediaPlayerBridge, availability);
     }
 
     @CalledByNative
@@ -354,8 +365,8 @@
     private native void nativeOnPaused(long nativeRemoteMediaPlayerBridge);
     private native void nativeOnRouteUnselected(long nativeRemoteMediaPlayerBridge);
     private native void nativeOnPlaybackFinished(long nativeRemoteMediaPlayerBridge);
-    private native void nativeOnRouteAvailabilityChanged(long nativeRemoteMediaPlayerBridge,
-            boolean available);
+    private native void nativeOnRouteAvailabilityChanged(
+            long nativeRemoteMediaPlayerBridge, int availability);
     private native void nativeOnCancelledRemotePlaybackRequest(long nativeRemoteMediaPlayerBridge);
     private native String nativeGetTitle(long nativeRemoteMediaPlayerBridge);
     private native void nativePauseLocal(long nativeRemoteMediaPlayerBridge);
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index f7846c9..0eebd89 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -99,6 +99,7 @@
   "+third_party/WebKit/public/platform/modules/budget_service/budget_service.mojom.h",
   "+third_party/WebKit/public/platform/modules/notifications/WebNotificationConstants.h",
   "+third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h",
+  "+third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h",
   "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h",
   "+third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h",
   "+third_party/WebKit/public/platform/modules/webshare/webshare.mojom.h",
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.cc b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
index 8a11cf5..2979d24 100644
--- a/chrome/browser/media/android/remote/remote_media_player_bridge.cc
+++ b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
@@ -18,6 +18,7 @@
 #include "media/base/android/media_resource_getter.h"
 #include "media/base/timestamp_constants.h"
 #include "net/base/escape.h"
+#include "third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/android/java_bitmap.h"
 
@@ -252,9 +253,11 @@
 void RemoteMediaPlayerBridge::OnRouteAvailabilityChanged(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
-    jboolean available) {
+    int availability) {
   static_cast<RemoteMediaPlayerManager *>(manager())->
-      OnRouteAvailabilityChanged(player_id(), available);
+      OnRouteAvailabilityChanged(
+          player_id(),
+          static_cast<blink::WebRemotePlaybackAvailability>(availability));
 }
 
 // static
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.h b/chrome/browser/media/android/remote/remote_media_player_bridge.h
index 42425a5..5840e34 100644
--- a/chrome/browser/media/android/remote/remote_media_player_bridge.h
+++ b/chrome/browser/media/android/remote/remote_media_player_bridge.h
@@ -64,7 +64,7 @@
   void OnRouteAvailabilityChanged(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
-      jboolean available);
+      int availability);
   base::android::ScopedJavaLocalRef<jstring> GetTitle(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
diff --git a/chrome/browser/media/android/remote/remote_media_player_manager.cc b/chrome/browser/media/android/remote/remote_media_player_manager.cc
index e5dcc15dc..83d8a438 100644
--- a/chrome/browser/media/android/remote/remote_media_player_manager.cc
+++ b/chrome/browser/media/android/remote/remote_media_player_manager.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/common/chrome_content_client.h"
 #include "content/common/media/media_player_messages_android.h"
+#include "third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/android/java_bitmap.h"
 
@@ -217,10 +218,9 @@
 }
 
 void RemoteMediaPlayerManager::OnRouteAvailabilityChanged(
-    int player_id, bool routes_available) {
-  Send(
-      new MediaPlayerMsg_RemoteRouteAvailabilityChanged(RoutingID(), player_id,
-                                                        routes_available));
+    int player_id, blink::WebRemotePlaybackAvailability availability) {
+  Send(new MediaPlayerMsg_RemoteRouteAvailabilityChanged(
+      RoutingID(), player_id, availability));
 }
 
 void RemoteMediaPlayerManager::OnCancelledRemotePlaybackRequest(int player_id) {
diff --git a/chrome/browser/media/android/remote/remote_media_player_manager.h b/chrome/browser/media/android/remote/remote_media_player_manager.h
index 0e1e6c7..d57e3d7 100644
--- a/chrome/browser/media/android/remote/remote_media_player_manager.h
+++ b/chrome/browser/media/android/remote/remote_media_player_manager.h
@@ -18,6 +18,10 @@
 
 struct MediaPlayerHostMsg_Initialize_Params;
 
+namespace blink {
+enum class WebRemotePlaybackAvailability;
+}
+
 namespace remote_media {
 
 // media::MediaPlayerManager implementation that allows the user to play media
@@ -41,7 +45,8 @@
   void OnRemotePlaybackFinished(int player_id);
 
   // Callback to trigger when the availability of remote routes changes.
-  void OnRouteAvailabilityChanged(int tab_id, bool routes_available);
+  void OnRouteAvailabilityChanged(
+      int player_id, blink::WebRemotePlaybackAvailability availability);
 
   // Callback to trigger when the device picker dialog was dismissed.
   void OnCancelledRemotePlaybackRequest(int player_id);
diff --git a/content/common/DEPS b/content/common/DEPS
index 1708c6d1..c00eeb5f 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -38,6 +38,7 @@
   "+third_party/WebKit/public/platform/modules/permissions/WebPermissionType.h",
   "+third_party/WebKit/public/platform/modules/push_messaging/WebPushError.h",
   "+third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h",
+  "+third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h",
   "+third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationError.h",
   "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h",
   "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h",
diff --git a/content/common/media/media_player_messages_android.h b/content/common/media/media_player_messages_android.h
index 9e02b9b..d7b93e6 100644
--- a/content/common/media/media_player_messages_android.h
+++ b/content/common/media/media_player_messages_android.h
@@ -10,6 +10,7 @@
 #include "ipc/ipc_message_macros.h"
 #include "media/blink/renderer_media_player_interface.h"
 #include "media/gpu/ipc/common/media_param_traits.h"
+#include "third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "url/gurl.h"
 
@@ -20,6 +21,9 @@
 IPC_ENUM_TRAITS_MAX_VALUE(MediaPlayerHostMsg_Initialize_Type,
                           MEDIA_PLAYER_TYPE_LAST)
 
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebRemotePlaybackAvailability,
+                          blink::WebRemotePlaybackAvailability::Last)
+
 // Parameters to describe a media player
 IPC_STRUCT_BEGIN(MediaPlayerHostMsg_Initialize_Params)
   IPC_STRUCT_MEMBER(MediaPlayerHostMsg_Initialize_Type, type)
@@ -131,7 +135,7 @@
 // The availability of remote devices has changed
 IPC_MESSAGE_ROUTED2(MediaPlayerMsg_RemoteRouteAvailabilityChanged,
                     int /* player_id */,
-                    bool /* routes_available */)
+                    blink::WebRemotePlaybackAvailability /* availability */)
 
 // Messages for controlling the media playback in browser process ----------
 
diff --git a/content/renderer/media/android/renderer_media_player_manager.cc b/content/renderer/media/android/renderer_media_player_manager.cc
index 27ebfd7..699fb428 100644
--- a/content/renderer/media/android/renderer_media_player_manager.cc
+++ b/content/renderer/media/android/renderer_media_player_manager.cc
@@ -10,10 +10,13 @@
 #include "content/renderer/media/android/webmediaplayer_android.h"
 #include "content/renderer/render_view_impl.h"
 #include "media/base/media_switches.h"
+#include "third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace content {
 
+using ::blink::WebRemotePlaybackAvailability;
+
 RendererMediaPlayerManager::RendererMediaPlayerManager(
     RenderFrame* render_frame)
     : RenderFrameObserver(render_frame),
@@ -244,10 +247,10 @@
 
 void RendererMediaPlayerManager::OnRemoteRouteAvailabilityChanged(
     int player_id,
-    bool routes_available) {
+    blink::WebRemotePlaybackAvailability availability) {
   media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id);
   if (player)
-    player->OnRemoteRouteAvailabilityChanged(routes_available);
+    player->OnRemoteRouteAvailabilityChanged(availability);
 }
 
 void RendererMediaPlayerManager::EnterFullscreen(int player_id) {
diff --git a/content/renderer/media/android/renderer_media_player_manager.h b/content/renderer/media/android/renderer_media_player_manager.h
index f7007001cd..a2ea4fb 100644
--- a/content/renderer/media/android/renderer_media_player_manager.h
+++ b/content/renderer/media/android/renderer_media_player_manager.h
@@ -15,6 +15,10 @@
 #include "media/blink/renderer_media_player_interface.h"
 #include "url/gurl.h"
 
+namespace blink {
+enum class WebRemotePlaybackAvailability;
+}
+
 namespace content {
 class WebMediaPlayerAndroid;
 
@@ -114,7 +118,8 @@
   void OnDidEnterFullscreen(int player_id);
   void OnPlayerPlay(int player_id);
   void OnPlayerPause(int player_id);
-  void OnRemoteRouteAvailabilityChanged(int player_id, bool routes_available);
+  void OnRemoteRouteAvailabilityChanged(
+      int player_id, blink::WebRemotePlaybackAvailability availability);
 
   // Info for all available WebMediaPlayerAndroid on a page; kept so that
   // we can enumerate them to send updates about tab focus and visibility.
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index 0a160a3..518a138d 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -918,8 +918,8 @@
 }
 
 void WebMediaPlayerAndroid::OnRemoteRouteAvailabilityChanged(
-    bool routes_available) {
-  client_->remoteRouteAvailabilityChanged(routes_available);
+    blink::WebRemotePlaybackAvailability availability) {
+  client_->remoteRouteAvailabilityChanged(availability);
 }
 
 void WebMediaPlayerAndroid::UpdateNetworkState(
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index e604b7d..8f73bbe 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -42,6 +42,7 @@
 class WebMediaPlayerClient;
 class WebMediaPlayerEncryptedMediaClient;
 class WebURL;
+enum class WebRemotePlaybackAvailability;
 }
 
 namespace cc_blink {
@@ -202,7 +203,8 @@
   void OnDidExitFullscreen() override;
   void OnMediaPlayerPlay() override;
   void OnMediaPlayerPause() override;
-  void OnRemoteRouteAvailabilityChanged(bool routes_available) override;
+  void OnRemoteRouteAvailabilityChanged(
+      blink::WebRemotePlaybackAvailability availability) override;
 
   // Called when the player is released.
   void OnPlayerReleased() override;
diff --git a/content/renderer/media/webmediaplayer_ms_unittest.cc b/content/renderer/media/webmediaplayer_ms_unittest.cc
index f89a797..64f3c9f0 100644
--- a/content/renderer/media/webmediaplayer_ms_unittest.cc
+++ b/content/renderer/media/webmediaplayer_ms_unittest.cc
@@ -422,7 +422,8 @@
   void removeTextTrack(blink::WebInbandTextTrack*) override {}
   void mediaSourceOpened(blink::WebMediaSource*) override {}
   void requestSeek(double) override {}
-  void remoteRouteAvailabilityChanged(bool) override {}
+  void remoteRouteAvailabilityChanged(
+      blink::WebRemotePlaybackAvailability) override {}
   void connectedToRemoteDevice() override {}
   void disconnectedFromRemoteDevice() override {}
   void cancelledRemotePlaybackRequest() override {}
diff --git a/media/blink/renderer_media_player_interface.h b/media/blink/renderer_media_player_interface.h
index d3af5fad..0f1bc34 100644
--- a/media/blink/renderer_media_player_interface.h
+++ b/media/blink/renderer_media_player_interface.h
@@ -17,6 +17,10 @@
 #include "ui/gfx/geometry/rect_f.h"
 #include "url/gurl.h"
 
+namespace blink {
+enum class WebRemotePlaybackAvailability;
+}
+
 // Dictates which type of media playback is being initialized.
 enum MediaPlayerHostMsg_Initialize_Type {
   MEDIA_PLAYER_TYPE_URL,
@@ -54,7 +58,8 @@
   virtual void OnDidExitFullscreen() = 0;
   virtual void OnMediaPlayerPlay() = 0;
   virtual void OnMediaPlayerPause() = 0;
-  virtual void OnRemoteRouteAvailabilityChanged(bool routes_available) = 0;
+  virtual void OnRemoteRouteAvailabilityChanged(
+      blink::WebRemotePlaybackAvailability availability) = 0;
 
   // Getters of playback state.
   virtual bool paused() const = 0;
diff --git a/media/blink/webmediaplayer_cast_android.cc b/media/blink/webmediaplayer_cast_android.cc
index 22dcbb7..c9e66937 100644
--- a/media/blink/webmediaplayer_cast_android.cc
+++ b/media/blink/webmediaplayer_cast_android.cc
@@ -332,9 +332,9 @@
 }
 
 void WebMediaPlayerCast::OnRemoteRouteAvailabilityChanged(
-    bool routes_available) {
+    blink::WebRemotePlaybackAvailability availability) {
   DVLOG(1) << __FUNCTION__;
-  client_->remoteRouteAvailabilityChanged(routes_available);
+  client_->remoteRouteAvailabilityChanged(availability);
 }
 
 void WebMediaPlayerCast::SuspendAndReleaseResources() {}
diff --git a/media/blink/webmediaplayer_cast_android.h b/media/blink/webmediaplayer_cast_android.h
index 69766bc..9fdcb6e0 100644
--- a/media/blink/webmediaplayer_cast_android.h
+++ b/media/blink/webmediaplayer_cast_android.h
@@ -80,7 +80,8 @@
   void OnDidExitFullscreen() override;
   void OnMediaPlayerPlay() override;
   void OnMediaPlayerPause() override;
-  void OnRemoteRouteAvailabilityChanged(bool routes_available) override;
+  void OnRemoteRouteAvailabilityChanged(
+      blink::WebRemotePlaybackAvailability availability) override;
 
   // Getters of playback state.
   // bool paused() const override;
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index cf50ffd..55cf6b0 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -82,7 +82,8 @@
   void removeTextTrack(blink::WebInbandTextTrack*) override {}
   void mediaSourceOpened(blink::WebMediaSource*) override {}
   void requestSeek(double) override {}
-  void remoteRouteAvailabilityChanged(bool) override {}
+  void remoteRouteAvailabilityChanged(
+      blink::WebRemotePlaybackAvailability) override {}
   void connectedToRemoteDevice() override {}
   void disconnectedFromRemoteDevice() override {}
   void cancelledRemotePlaybackRequest() override {}
diff --git a/third_party/WebKit/LayoutTests/media/remoteplayback/prompt-twice-throws.html b/third_party/WebKit/LayoutTests/media/remoteplayback/prompt-twice-throws.html
index 9a14115..bacf9a0 100644
--- a/third_party/WebKit/LayoutTests/media/remoteplayback/prompt-twice-throws.html
+++ b/third_party/WebKit/LayoutTests/media/remoteplayback/prompt-twice-throws.html
@@ -23,6 +23,8 @@
                 v.src = findMediaFile('video', 'content/test');
                 document.body.appendChild(v);
 
+                internals.mediaPlayerRemoteRouteAvailabilityChanged(v, true);
+
                 var btn = document.getElementById('button');
                 btn.onclick = function() {
                     v.remote.prompt();
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index 1d90b0d..c812add 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -89,6 +89,7 @@
 #include "public/platform/WebInbandTextTrack.h"
 #include "public/platform/WebMediaPlayerSource.h"
 #include "public/platform/WebMediaStream.h"
+#include "public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h"
 #include "public/platform/modules/remoteplayback/WebRemotePlaybackClient.h"
 #include "public/platform/modules/remoteplayback/WebRemotePlaybackState.h"
 #include "wtf/CurrentTime.h"
@@ -444,7 +445,6 @@
       m_shouldPerformAutomaticTrackSelection(true),
       m_tracksAreReady(true),
       m_processingPreferenceChange(false),
-      m_remoteRoutesAvailable(false),
       m_playingRemotely(false),
       m_inOverlayFullscreenVideo(false),
       m_audioTracks(this, AudioTrackList::create(*this)),
@@ -3168,12 +3168,17 @@
   setCurrentTime(time);
 }
 
-void HTMLMediaElement::remoteRouteAvailabilityChanged(bool routesAvailable) {
-  m_remoteRoutesAvailable = routesAvailable;
+void HTMLMediaElement::remoteRouteAvailabilityChanged(
+    WebRemotePlaybackAvailability availability) {
+  if (remotePlaybackClient())
+    remotePlaybackClient()->availabilityChanged(availability);
   if (mediaControls())
     mediaControls()->refreshCastButtonVisibility();
-  if (remotePlaybackClient())
-    remotePlaybackClient()->availabilityChanged(routesAvailable);
+}
+
+bool HTMLMediaElement::hasRemoteRoutes() const {
+  return remotePlaybackClient() &&
+         remotePlaybackClient()->remotePlaybackAvailable();
 }
 
 void HTMLMediaElement::connectedToRemoteDevice() {
@@ -3403,10 +3408,8 @@
   m_loadState = WaitingForSource;
 
   // We can't cast if we don't have a media player.
-  m_remoteRoutesAvailable = false;
   m_playingRemotely = false;
-  if (mediaControls())
-    mediaControls()->refreshCastButtonVisibilityWithoutUpdate();
+  remoteRouteAvailabilityChanged(WebRemotePlaybackAvailability::Unknown);
 
   if (layoutObject())
     layoutObject()->setShouldDoFullPaintInvalidation();
@@ -3764,8 +3767,8 @@
   }
 
   // We haven't yet found out if any remote routes are available.
-  m_remoteRoutesAvailable = false;
   m_playingRemotely = false;
+  remoteRouteAvailabilityChanged(WebRemotePlaybackAvailability::Unknown);
 
   if (m_audioSourceNode)
     getAudioSourceProvider().setClient(m_audioSourceNode);
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.h b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
index 7e93de2..68c5c31 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
@@ -117,7 +117,7 @@
   };
   void scheduleTextTrackResourceLoad();
 
-  bool hasRemoteRoutes() const { return m_remoteRoutesAvailable; }
+  bool hasRemoteRoutes() const;
   bool isPlayingRemotely() const { return m_playingRemotely; }
 
   // error state
@@ -308,6 +308,9 @@
   WebRemotePlaybackClient* remotePlaybackClient() {
     return m_remotePlaybackClient;
   }
+  const WebRemotePlaybackClient* remotePlaybackClient() const {
+    return m_remotePlaybackClient;
+  }
 
  protected:
   HTMLMediaElement(const QualifiedName&, Document&);
@@ -386,7 +389,7 @@
   void removeTextTrack(WebInbandTextTrack*) final;
   void mediaSourceOpened(WebMediaSource*) final;
   void requestSeek(double) final;
-  void remoteRouteAvailabilityChanged(bool) final;
+  void remoteRouteAvailabilityChanged(WebRemotePlaybackAvailability) final;
   void connectedToRemoteDevice() final;
   void disconnectedFromRemoteDevice() final;
   void cancelledRemotePlaybackRequest() final;
@@ -641,7 +644,6 @@
 
   bool m_tracksAreReady : 1;
   bool m_processingPreferenceChange : 1;
-  bool m_remoteRoutesAvailable : 1;
   bool m_playingRemotely : 1;
   // Whether this element is in overlay fullscreen mode.
   bool m_inOverlayFullscreenVideo : 1;
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp
index 303eb67f..cea984fc 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp
@@ -17,6 +17,7 @@
 #include "platform/testing/UnitTestHelpers.h"
 #include "public/platform/WebMediaPlayer.h"
 #include "public/platform/WebSize.h"
+#include "public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h"
 #include "public/platform/modules/remoteplayback/WebRemotePlaybackClient.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include <memory>
@@ -62,6 +63,23 @@
   void paint(WebCanvas*, const WebRect&, SkPaint&) override{};
 };
 
+class MockWebRemotePlaybackClient : public WebRemotePlaybackClient {
+ public:
+  void stateChanged(WebRemotePlaybackState) override {}
+  void availabilityChanged(
+      WebRemotePlaybackAvailability availability) override {
+    m_availability = availability;
+  }
+  void promptCancelled() override {}
+  bool remotePlaybackAvailable() const override {
+    return m_availability == WebRemotePlaybackAvailability::DeviceAvailable;
+  }
+
+ private:
+  WebRemotePlaybackAvailability m_availability =
+      WebRemotePlaybackAvailability::Unknown;
+};
+
 class StubFrameLoaderClient : public EmptyFrameLoaderClient {
  public:
   static StubFrameLoaderClient* create() { return new StubFrameLoaderClient; }
@@ -72,6 +90,17 @@
       WebMediaPlayerClient*) override {
     return wrapUnique(new MockVideoWebMediaPlayer);
   }
+
+  WebRemotePlaybackClient* createWebRemotePlaybackClient(
+      HTMLMediaElement&) override {
+    if (!m_remotePlaybackClient) {
+      m_remotePlaybackClient = wrapUnique(new MockWebRemotePlaybackClient);
+    }
+    return m_remotePlaybackClient.get();
+  }
+
+ private:
+  std::unique_ptr<MockWebRemotePlaybackClient> m_remotePlaybackClient;
 };
 
 Element* getElementByShadowPseudoId(Node& rootNode,
@@ -125,7 +154,8 @@
   }
 
   void simulateRouteAvailabe() {
-    m_mediaControls->mediaElement().remoteRouteAvailabilityChanged(true);
+    m_mediaControls->mediaElement().remoteRouteAvailabilityChanged(
+        WebRemotePlaybackAvailability::DeviceAvailable);
   }
 
   void ensureLayout() {
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index 581c8bba..94c6379 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -144,6 +144,7 @@
 #include "public/platform/WebConnectionType.h"
 #include "public/platform/WebGraphicsContext3DProvider.h"
 #include "public/platform/WebLayer.h"
+#include "public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h"
 #include "wtf/InstanceCounter.h"
 #include "wtf/PtrUtil.h"
 #include "wtf/dtoa.h"
@@ -2194,7 +2195,9 @@
     HTMLMediaElement* mediaElement,
     bool available) {
   ASSERT(mediaElement);
-  mediaElement->remoteRouteAvailabilityChanged(available);
+  mediaElement->remoteRouteAvailabilityChanged(
+      available ? WebRemotePlaybackAvailability::DeviceAvailable
+                : WebRemotePlaybackAvailability::SourceNotSupported);
 }
 
 void Internals::mediaPlayerPlayingRemotelyChanged(
diff --git a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp
index 55de180..26e3ada76 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp
+++ b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp
@@ -49,7 +49,7 @@
       m_state(element.isPlayingRemotely()
                   ? WebRemotePlaybackState::Connected
                   : WebRemotePlaybackState::Disconnected),
-      m_availability(element.hasRemoteRoutes()),
+      m_availability(WebRemotePlaybackAvailability::Unknown),
       m_mediaElement(&element) {}
 
 const AtomicString& RemotePlayback::interfaceName() const {
@@ -141,8 +141,6 @@
 }
 
 ScriptPromise RemotePlayback::prompt(ScriptState* scriptState) {
-  // TODO(avayvod): implement steps 5, 8, 9 of the algorithm.
-  // https://crbug.com/647441
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
 
@@ -165,6 +163,22 @@
     return promise;
   }
 
+  // TODO(avayvod): don't do this check on low-end devices - merge with
+  // https://codereview.chromium.org/2475293003
+  if (m_availability == WebRemotePlaybackAvailability::DeviceNotAvailable) {
+    resolver->reject(DOMException::create(NotFoundError,
+                                          "No remote playback devices found."));
+    return promise;
+  }
+
+  if (m_availability == WebRemotePlaybackAvailability::SourceNotSupported ||
+      m_availability == WebRemotePlaybackAvailability::SourceNotCompatible) {
+    resolver->reject(DOMException::create(
+        NotSupportedError,
+        "The currentSrc is not compatible with remote playback"));
+    return promise;
+  }
+
   if (m_state == WebRemotePlaybackState::Disconnected) {
     m_promptPromiseResolver = resolver;
     m_mediaElement->requestRemotePlayback();
@@ -191,7 +205,7 @@
   if (iter == m_availabilityCallbacks.end())
     return;
 
-  iter->value->call(this, m_availability);
+  iter->value->call(this, remotePlaybackAvailable());
 }
 
 void RemotePlayback::stateChanged(WebRemotePlaybackState state) {
@@ -231,13 +245,19 @@
   }
 }
 
-void RemotePlayback::availabilityChanged(bool available) {
-  if (m_availability == available)
+void RemotePlayback::availabilityChanged(
+    WebRemotePlaybackAvailability availability) {
+  if (m_availability == availability)
     return;
 
-  m_availability = available;
+  bool oldAvailability = remotePlaybackAvailable();
+  m_availability = availability;
+  bool newAvailability = remotePlaybackAvailable();
+  if (newAvailability == oldAvailability)
+    return;
+
   for (auto& callback : m_availabilityCallbacks.values())
-    callback->call(this, m_availability);
+    callback->call(this, newAvailability);
 }
 
 void RemotePlayback::promptCancelled() {
@@ -249,6 +269,10 @@
   m_promptPromiseResolver = nullptr;
 }
 
+bool RemotePlayback::remotePlaybackAvailable() const {
+  return m_availability == WebRemotePlaybackAvailability::DeviceAvailable;
+}
+
 void RemotePlayback::remotePlaybackDisabled() {
   if (m_promptPromiseResolver) {
     m_promptPromiseResolver->reject(DOMException::create(
diff --git a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.h b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.h
index f8b4371..0023126 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.h
+++ b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.h
@@ -11,6 +11,7 @@
 #include "core/events/EventTarget.h"
 #include "modules/ModulesExport.h"
 #include "platform/heap/Handle.h"
+#include "public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h"
 #include "public/platform/modules/remoteplayback/WebRemotePlaybackClient.h"
 #include "public/platform/modules/remoteplayback/WebRemotePlaybackState.h"
 #include "wtf/Compiler.h"
@@ -84,8 +85,9 @@
 
   // WebRemotePlaybackClient implementation.
   void stateChanged(WebRemotePlaybackState) override;
-  void availabilityChanged(bool available) override;
+  void availabilityChanged(WebRemotePlaybackAvailability) override;
   void promptCancelled() override;
+  bool remotePlaybackAvailable() const override;
 
   // Prevent v8 from garbage collecting the availability callbacks.
   // TODO(avayvod): remove when crbug.com/468240 is fixed and the references
@@ -94,7 +96,7 @@
                                    const v8::Persistent<v8::Object>& wrapper);
 
   WebRemotePlaybackState m_state;
-  bool m_availability;
+  WebRemotePlaybackAvailability m_availability;
   HeapHashMap<int, TraceWrapperMember<RemotePlaybackAvailabilityCallback>>
       m_availabilityCallbacks;
   Member<HTMLMediaElement> m_mediaElement;
diff --git a/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp b/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp
index 9f5d4f6..19a40a93 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp
+++ b/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp
@@ -55,10 +55,6 @@
   void setState(RemotePlayback* remotePlayback, WebRemotePlaybackState state) {
     remotePlayback->stateChanged(state);
   }
-
-  void setAvailability(RemotePlayback* remotePlayback, bool available) {
-    remotePlayback->availabilityChanged(available);
-  }
 };
 
 TEST_F(RemotePlaybackTest, PromptCancelledRejectsWithNotAllowedError) {
@@ -258,7 +254,6 @@
 
   HTMLMediaElementRemotePlayback::setBooleanAttribute(
       HTMLNames::disableremoteplaybackAttr, *element, true);
-  setAvailability(remotePlayback, true);
 
   // Runs pending promises.
   v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 8276020..502fef7e 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -80,6 +80,7 @@
       "./platform/WebDisplayMode.h",
       "./platform/WebInputEvent.h",
       "./platform/WebTextInputType.h",
+      "./platform/modules/remoteplayback/WebRemotePlaybackAvailability.h",
     ]
   }
 
@@ -367,6 +368,7 @@
     "platform/modules/push_messaging/WebPushProvider.h",
     "platform/modules/push_messaging/WebPushSubscription.h",
     "platform/modules/push_messaging/WebPushSubscriptionOptions.h",
+    "platform/modules/remoteplayback/WebRemotePlaybackAvailability.h",
     "platform/modules/remoteplayback/WebRemotePlaybackClient.h",
     "platform/modules/remoteplayback/WebRemotePlaybackState.h",
     "platform/modules/screen_orientation/WebLockOrientationCallback.h",
diff --git a/third_party/WebKit/public/platform/WebMediaPlayerClient.h b/third_party/WebKit/public/platform/WebMediaPlayerClient.h
index 50e0588..f9e4dbd 100644
--- a/third_party/WebKit/public/platform/WebMediaPlayerClient.h
+++ b/third_party/WebKit/public/platform/WebMediaPlayerClient.h
@@ -40,6 +40,8 @@
 class WebLayer;
 class WebMediaSource;
 
+enum class WebRemotePlaybackAvailability;
+
 class BLINK_PLATFORM_EXPORT WebMediaPlayerClient {
  public:
   enum VideoTrackKind {
@@ -86,7 +88,8 @@
   virtual void removeTextTrack(WebInbandTextTrack*) = 0;
   virtual void mediaSourceOpened(WebMediaSource*) = 0;
   virtual void requestSeek(double) = 0;
-  virtual void remoteRouteAvailabilityChanged(bool) = 0;
+  virtual void remoteRouteAvailabilityChanged(
+      WebRemotePlaybackAvailability) = 0;
   virtual void connectedToRemoteDevice() = 0;
   virtual void disconnectedFromRemoteDevice() = 0;
   virtual void cancelledRemotePlaybackRequest() = 0;
diff --git a/third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h b/third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h
new file mode 100644
index 0000000..1bc8f5f
--- /dev/null
+++ b/third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h
@@ -0,0 +1,38 @@
+// Copyright 2016 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 WebRemotePlaybackAvailability_h
+#define WebRemotePlaybackAvailability_h
+
+namespace blink {
+
+// GENERATED_JAVA_ENUM_PACKAGE: (
+//     org.chromium.blink_public.platform.modules.remoteplayback)
+// Various states for the remote playback availability.
+enum class WebRemotePlaybackAvailability {
+  // The availability is unknown.
+  Unknown,
+
+  // The media source is not supported by the browser - device availability
+  // monitoring is unnecessary.
+  SourceNotSupported,
+
+  // The media source is compatible with some supported device types but
+  // no devices were found.
+  DeviceNotAvailable,
+
+  // There're available devices but the current media source is not compatible
+  // with any of those.
+  SourceNotCompatible,
+
+  // There're available remote playback devices and the media source is
+  // compatible with at least one of them.
+  DeviceAvailable,
+
+  Last = DeviceAvailable
+};
+
+}  // namespace blink
+
+#endif  // WebRemotePlaybackState_h
diff --git a/third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackClient.h b/third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackClient.h
index 6131d9eb2..7e66857 100644
--- a/third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackClient.h
+++ b/third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackClient.h
@@ -7,6 +7,7 @@
 
 namespace blink {
 
+enum class WebRemotePlaybackAvailability;
 enum class WebRemotePlaybackState;
 
 // The interface between the HTMLMediaElement and its
@@ -19,10 +20,13 @@
   virtual void stateChanged(WebRemotePlaybackState) = 0;
 
   // Notifies the client of the remote playback device availability change.
-  virtual void availabilityChanged(bool availability) = 0;
+  virtual void availabilityChanged(WebRemotePlaybackAvailability) = 0;
 
   // Notifies the client that the user cancelled the prompt shown via the API.
   virtual void promptCancelled() = 0;
+
+  // Returns if the remote playback available for this media element.
+  virtual bool remotePlaybackAvailable() const = 0;
 };
 
 }  // namespace blink