blob: bcdcd58cd42dc95dca0c34109308065713de1a1c [file] [log] [blame]
// Copyright 2017 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.cast.remoting;
import android.support.v7.media.MediaRouter;
import org.chromium.base.Log;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.media.router.ChromeMediaRouter;
import org.chromium.chrome.browser.media.router.FlingingController;
import org.chromium.chrome.browser.media.router.MediaRoute;
import org.chromium.chrome.browser.media.router.MediaRouteManager;
import org.chromium.chrome.browser.media.router.MediaRouteProvider;
import org.chromium.chrome.browser.media.router.MediaSink;
import org.chromium.chrome.browser.media.router.MediaSource;
import org.chromium.chrome.browser.media.router.cast.BaseMediaRouteProvider;
import org.chromium.chrome.browser.media.router.cast.CastSession;
import org.chromium.chrome.browser.media.router.cast.ChromeCastSessionManager;
import org.chromium.chrome.browser.media.router.cast.CreateRouteRequest;
import javax.annotation.Nullable;
/**
* A {@link MediaRouteProvider} implementation for media remote playback.
*/
// Migrated to CafRemotingMediaRouteProvider. See https://crbug.com/711860.
public class RemotingMediaRouteProvider extends BaseMediaRouteProvider {
private static final String TAG = "MediaRemoting";
private int mPendingNativeRequestId;
private MediaRoute mPendingMediaRoute;
/**
* @return Initialized {@link RemotingMediaRouteProvider} object.
*/
public static RemotingMediaRouteProvider create(MediaRouteManager manager) {
return new RemotingMediaRouteProvider(ChromeMediaRouter.getAndroidMediaRouter(), manager);
}
@Override
protected MediaSource getSourceFromId(String sourceId) {
return RemotingMediaSource.from(sourceId);
}
@Override
protected ChromeCastSessionManager.CastSessionLaunchRequest createSessionLaunchRequest(
MediaSource source, MediaSink sink, String presentationId, String origin, int tabId,
boolean isIncognito, int nativeRequestId) {
return new CreateRouteRequest(source, sink, presentationId, origin, tabId, isIncognito,
nativeRequestId, this, CreateRouteRequest.RequestedCastSessionType.REMOTE, null);
}
@Override
public void joinRoute(
String sourceId, String presentationId, String origin, int tabId, int nativeRequestId) {
mManager.onRouteRequestError(
"Remote playback doesn't support joining routes", nativeRequestId);
}
@Override
public void closeRoute(String routeId) {
MediaRoute route = mRoutes.get(routeId);
if (route == null) return;
if (mSession == null) {
mRoutes.remove(routeId);
mManager.onRouteClosed(routeId);
return;
}
ChromeCastSessionManager.get().stopApplication();
}
@Override
public void detachRoute(String routeId) {
mRoutes.remove(routeId);
}
@Override
public void sendStringMessage(String routeId, String message) {
Log.e(TAG, "Remote playback does not support sending messages");
}
@VisibleForTesting
RemotingMediaRouteProvider(MediaRouter androidMediaRouter, MediaRouteManager manager) {
super(androidMediaRouter, manager);
}
@Override
public void onSessionEnded() {
if (mSession == null) return;
for (String routeId : mRoutes.keySet()) mManager.onRouteClosed(routeId);
mRoutes.clear();
mSession = null;
if (mAndroidMediaRouter != null) {
mAndroidMediaRouter.selectRoute(mAndroidMediaRouter.getDefaultRoute());
}
}
@Override
public void onSessionStarting(ChromeCastSessionManager.CastSessionLaunchRequest launchRequest) {
CreateRouteRequest request = (CreateRouteRequest) launchRequest;
MediaSink sink = request.getSink();
MediaSource source = request.getSource();
// Calling mManager.onRouteCreated() too early causes some issues. If we call it here
// directly, getMediaController() might be called before onSessionStarted(), which causes
// the FlingingRenderer's creation to fail. Instead, save the route and request ID, and only
// signal the route as having been created when onSessionStarted() is called.
mPendingMediaRoute =
new MediaRoute(sink.getId(), source.getSourceId(), request.getPresentationId());
mPendingNativeRequestId = request.getNativeRequestId();
}
private void clearPendingRoute() {
mPendingMediaRoute = null;
mPendingNativeRequestId = 0;
}
@Override
public void onSessionStarted(CastSession session) {
super.onSessionStarted(session);
// Continued from onSessionStarting()
mRoutes.put(mPendingMediaRoute.id, mPendingMediaRoute);
mManager.onRouteCreated(mPendingMediaRoute.id, mPendingMediaRoute.sinkId,
mPendingNativeRequestId, this, true);
clearPendingRoute();
}
@Override
public void onSessionStartFailed() {
super.onSessionStartFailed();
mManager.onRouteRequestError(
"Failure to start RemotingCastSession", mPendingNativeRequestId);
clearPendingRoute();
};
@Override
@Nullable
public FlingingController getFlingingController(String routeId) {
// We cannot return a FlingingController if we don't have a session.
if (mSession == null) return null;
// Don't return controllers for stale routes.
if (!mRoutes.containsKey(routeId)) return null;
// RemotePlayback does not support joining routes, which means we only
// have a single route active at a time. If we have a a valid CastSession
// and the route ID is current, this means that the given |mSession|
// corresponds to the route ID, and it is ok to return the FlingingController.
return mSession.getFlingingController();
}
}