// Copyright 2014 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.remote; import android.graphics.Bitmap; import android.support.v7.media.MediaRouteSelector; import android.support.v7.media.MediaRouter; import android.support.v7.media.MediaRouter.RouteInfo; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.media.remote.RemoteVideoInfo.PlayerState; /** * Each MediaRouteController controls the routes to devices which support remote playback of * particular categories of Media elements (e.g. all YouTube media elements, all media elements * with simple http source URLs). The MediaRouteController is responsible for configuring * and controlling remote playback of the media elements it supports. */ public interface MediaRouteController { /** * Listener for events that are relevant to the state of the media and the media controls */ public interface MediaStateListener { /** * Called when the first route becomes available, or the last route * is removed. * @param available whether routes are available. */ void onRouteAvailabilityChanged(boolean available); /** * Called when the {@link MediaRouteChooserDialog} is closed with no device selected. */ void onRouteDialogCancelled(); /** * Called when an error is detected by the media route controller */ void onError(); /** * Called when a seek completes on the current route */ void onSeekCompleted(); /** * Called when the current route is unselected */ void onRouteUnselected(); /** * Called when the playback state changes (e.g. from Playing to Paused) * @param newState the new playback state */ void onPlaybackStateChanged(PlayerState newState); String getTitle(); Bitmap getPosterBitmap(); void pauseLocal(); long getLocalPosition(); /** * Tells the rest of Chrome that we are starting to cast, so that user inputs control cast * in place of local playback */ void onCastStarting(String routeName); /** * Tells the rest of Chrome that we are no longer casting the video. */ void onCastStopping(); /** * @return the source URL */ String getSourceUrl(); /** * @return the Cookies */ String getCookies(); /** * @return the frame URL */ String getFrameUrl(); /** * @return the start position */ long getStartPositionMillis(); /** * @return true if the user has pressed the pause button (or requested pause some other way) */ boolean isPauseRequested(); /** * @return true if the user has requested a seek */ boolean isSeekRequested(); /** * @return the requested seek location. Only meaningful if isSeekRequested is true. */ long getSeekLocation(); } /** * Listener for events that are relevant to the Browser UI. */ public interface UiListener { /** * Called when a new route is selected * @param name the name of the new route * @param mediaRouteController the controller that selected the route */ void onRouteSelected(String name, MediaRouteController mediaRouteController); /** * Called when the current route is unselected * @param mediaRouteController the controller that had the route. */ void onRouteUnselected(MediaRouteController mediaRouteController); /** * Called when the current route is ready to be used * @param mediaRouteController the controller that has the route. */ void onPrepared(MediaRouteController mediaRouteController); /** * Called when an error is detected by the controller * @param errorType One of the error types from CastMediaControlIntent * @param message The message for the error */ void onError(int errorType, String message); /** * Called when the Playback state has changed (e.g. from playing to paused) * @param newState the new state */ void onPlaybackStateChanged(PlayerState newState); /** * Called when the duration of the currently playing video changes. * @param durationMillis the new duration in ms. */ void onDurationUpdated(long durationMillis); /** * Called when the media route controller receives new information about the * current position in the video. * @param positionMillis the current position in the video in ms. */ void onPositionChanged(long positionMillis); /** * Called if the title of the video changes * @param title the new title */ void onTitleChanged(String title); } /** * Interface for returning the result of checking whether the media element is playable * remotely. */ static interface MediaValidationCallback { /** * Function to deliver the result * @param isPlayable true if the media element is playable, false if not * @param revisedSourceUrl The source url to send to the remote device * @param revisedFrameUrl The frame url to send to the remote device */ void onResult(boolean isPlayable, String revisedSourceUrl, String revisedFrameUrl); } /** * Scan routes, and set up the MediaRouter object. This is called at every time we need to reset * the state. Because of that, this function is idempotent. If that changes in the future, where * this function gets called needs to be re-evaluated. * * @return false if device doesn't support cast, true otherwise. */ boolean initialize(); /** * Can this mediaRouteController handle a media element? * @param sourceUrl the source * @param frameUrl * @return true if it can, false if it can't. */ boolean canPlayMedia(String sourceUrl, String frameUrl); /** * @return A new MediaRouteSelector filtering the remote playback devices from all the routes. */ MediaRouteSelector buildMediaRouteSelector(); /** * @return Whether there're remote playback devices available. */ boolean isRemotePlaybackAvailable(); /** * @return Whether the currently selected device supports remote playback */ boolean currentRouteSupportsRemotePlayback(); /** * Setup this object to discover new routes and register the necessary players. */ void prepareMediaRoute(); /** * Add a Listener that will listen to events from this object * * @param listener the Listener that will receive the events */ void addUiListener(UiListener listener); /** * Removes a Listener from this object * * @param listener the Listener to remove */ void removeUiListener(UiListener listener); /** * @return The currently selected route's friendly name, or null if there is none selected */ String getRouteName(); /** * @return true if this is currently using the default route, false if not. */ boolean routeIsDefaultRoute(); /** * Sets the remote volume of the current route. * * @param delta The delta value in arbitrary "Android Volume Units". */ void setRemoteVolume(int delta); /** * Resume paused playback of the current video. */ void resume(); /** * Pauses the currently playing video if any. */ void pause(); /** * Returns the current remote playback position. Estimates the current position by using the * last known position and the current time. * * TODO(avayvod): Send periodic status update requests to update the position once in several * seconds or so. * * @return The current position of the remote playback in milliseconds. */ long getPosition(); /** * @return The stream duration in milliseconds. */ long getDuration(); /** * @return Whether the video is currently being played. */ boolean isPlaying(); /** * @return Whether the video is being cast (any of playing/paused/loading/stopped). */ boolean isBeingCast(); /** * Initiates a seek request for the remote playback device to the specified position. * * @param msec The position to seek to, in milliseconds. */ void seekTo(long msec); /** * Stop the current remote playback completely and release all resources. */ void release(); /** * @param player - the current player using this media route controller. */ void setMediaStateListener(MediaStateListener listener); /** * @return the current VideoStateListener */ MediaStateListener getMediaStateListener(); @VisibleForTesting PlayerState getDisplayedPlayerState(); /** * Remove an existing media state listener * @param listener */ void removeMediaStateListener(MediaStateListener listener); /** * Add a media state listener * @param listener */ void addMediaStateListener(MediaStateListener listener); /** * Get the poster for the video, if any * @return the poster bitmap, or Null. */ Bitmap getPoster(); /** * Called when a new route has been selected * @param player The player {@link MediaStateListener} that initiated the connection * @param router The MediaRouter. * @param route The selected route. */ void onRouteSelected(MediaStateListener player, MediaRouter router, RouteInfo route); /** * Potentially asynchronous check of whether the media element is playable on remote players. * @param sourceUrl the URL of the media element * @param frameUrl the URL of the frame * @param cookies the cookies for the media element * @param userAgent the user agent * @param callback the callback through which the result will be returned. The callback will be * called either from within the call, or later on the UI thread. */ void checkIfPlayableRemotely(String sourceUrl, String frameUrl, String cookies, String userAgent, MediaValidationCallback callback); /** * @return The Uri of the currently playing video */ @VisibleForTesting String getUriPlaying(); }