Commit 28ca7e11 authored by Zhiqiang Zhang's avatar Zhiqiang Zhang Committed by Commit Bot

[CAF MR] Implementing CafMessageHandler

This CL migrates the CastMessageHandler for CAF. There's not
much code change between CastMessageHandler and CafMessageHandler.

Bug: 711860
Change-Id: Id58454c51cd6ada50b507d750a979ffe4e248241
Reviewed-on: https://chromium-review.googlesource.com/1169920
Commit-Queue: Zhiqiang Zhang <zqzhang@chromium.org>
Reviewed-by: default avatarMounir Lamouri <mlamouri@chromium.org>
Reviewed-by: default avatarThomas Guilbert <tguilbert@chromium.org>
Cr-Commit-Position: refs/heads/master@{#583043}
parent 5991ad41
......@@ -13,9 +13,9 @@ import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import org.chromium.base.Log;
import org.chromium.chrome.browser.media.router.CastSessionUtil;
import org.chromium.chrome.browser.media.router.FlingingController;
import org.chromium.chrome.browser.media.router.MediaController;
import org.chromium.chrome.browser.media.router.cast.CastSessionUtil;
import org.chromium.chrome.browser.media.ui.MediaNotificationInfo;
import org.chromium.chrome.browser.media.ui.MediaNotificationManager;
......
......@@ -2,7 +2,7 @@
// 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;
package org.chromium.chrome.browser.media.router;
/**
* Returns a request id in a range that is considered fairly unique. These request ids are used to
......
......@@ -2,7 +2,7 @@
// 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;
package org.chromium.chrome.browser.media.router;
import com.google.android.gms.cast.CastDevice;
import com.google.android.gms.cast.RemoteMediaPlayer;
......@@ -16,6 +16,9 @@ import org.chromium.content_public.common.MediaMetadata;
public class CastSessionUtil {
public static final String MEDIA_NAMESPACE = "urn:x-cast:com.google.cast.media";
// The value is borrowed from the Android Cast SDK code to match their behavior.
public static final double MIN_VOLUME_LEVEL_DELTA = 1e-7;
/**
* Builds a MediaMetadata from the given CastDevice and MediaPlayer, and sets it on the builder
*/
......
......@@ -36,7 +36,7 @@ public abstract class CafBaseMediaRouteProvider
private static final String TAG = "CafMR";
protected static final List<MediaSink> NO_SINKS = Collections.emptyList();
protected final MediaRouter mAndroidMediaRouter;
private final @NonNull MediaRouter mAndroidMediaRouter;
protected final MediaRouteManager mManager;
protected final Map<String, DiscoveryCallback> mDiscoveryCallbacks =
new HashMap<String, DiscoveryCallback>();
......@@ -87,13 +87,6 @@ public abstract class CafBaseMediaRouteProvider
public final void startObservingMediaSinks(String sourceId) {
Log.d(TAG, "startObservingMediaSinks: " + sourceId);
if (mAndroidMediaRouter == null) {
// If the MediaRouter API is not available, report no devices so the page doesn't even
// try to cast.
onSinksReceived(sourceId, NO_SINKS);
return;
}
MediaSource source = getSourceFromId(sourceId);
if (source == null) {
// If the source is invalid or not supported by this provider, report no devices
......@@ -134,8 +127,6 @@ public abstract class CafBaseMediaRouteProvider
public final void stopObservingMediaSinks(String sourceId) {
Log.d(TAG, "startObservingMediaSinks: " + sourceId);
if (mAndroidMediaRouter == null) return;
MediaSource source = getSourceFromId(sourceId);
if (source == null) return;
......@@ -159,10 +150,6 @@ public abstract class CafBaseMediaRouteProvider
if (mPendingCreateRouteRequestInfo != null) {
// TODO(zqzhang): do something.
}
if (mAndroidMediaRouter == null) {
mManager.onRouteRequestError("Not supported", nativeRequestId);
return;
}
MediaSink sink = MediaSink.fromSinkId(sinkId, mAndroidMediaRouter);
if (sink == null) {
......@@ -222,6 +209,10 @@ public abstract class CafBaseMediaRouteProvider
mPendingCreateRouteRequestInfo = null;
}
public @NonNull MediaRouter getAndroidMediaRouter() {
return mAndroidMediaRouter;
}
// TODO(zqzhang): this is a temporary workaround for give CafMRP to manage ClientRecords on
// session start. This needs to be removed once ClientRecord management gets refactored.
abstract void onSessionStarted(CreateRouteRequestInfo request);
......
......@@ -20,6 +20,7 @@ import org.chromium.chrome.browser.media.router.MediaSink;
import org.chromium.chrome.browser.media.router.MediaSource;
import org.chromium.chrome.browser.media.router.cast.CastMediaSource;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
......@@ -37,6 +38,7 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider {
private ClientRecord mLastRemovedRouteRecord;
private final Map<String, ClientRecord> mClientRecords = new HashMap<String, ClientRecord>();
private CafMessageHandler mMessageHandler;
public static CafMediaRouteProvider create(MediaRouteManager manager) {
return new CafMediaRouteProvider(ChromeMediaRouter.getAndroidMediaRouter(), manager);
......@@ -54,10 +56,10 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider {
public void requestSessionLaunch(CreateRouteRequestInfo request) {
CastUtils.getCastContext().setReceiverApplicationId(request.source.getApplicationId());
for (MediaRouter.RouteInfo routeInfo : mAndroidMediaRouter.getRoutes()) {
for (MediaRouter.RouteInfo routeInfo : getAndroidMediaRouter().getRoutes()) {
if (routeInfo.getId().equals(request.sink.getId())) {
// Unselect and then select so that CAF will get notified of the selection.
mAndroidMediaRouter.unselect(0);
getAndroidMediaRouter().unselect(0);
routeInfo.select();
break;
}
......@@ -100,11 +102,11 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider {
if (!isRouteInRecord) return;
ClientRecord client = getClientRecordByRouteId(routeId);
if (client != null && mAndroidMediaRouter != null) {
if (client != null) {
MediaSink sink = MediaSink.fromSinkId(
sessionController().getSink().getId(), mAndroidMediaRouter);
sessionController().getSink().getId(), getAndroidMediaRouter());
if (sink != null) {
sessionController().notifyReceiverAction(routeId, sink, client.clientId, "stop");
mMessageHandler.sendReceiverActionToClient(routeId, sink, client.clientId, "stop");
}
}
}
......@@ -133,6 +135,20 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider {
return CastMediaSource.from(sourceId);
}
public void sendMessageToClient(String clientId, String message) {
ClientRecord clientRecord = mClientRecords.get(clientId);
if (clientRecord == null) return;
if (!clientRecord.isConnected) {
Log.d(TAG, "Queueing message to client %s: %s", clientId, message);
clientRecord.pendingMessages.add(message);
return;
}
Log.d(TAG, "Sending message to client %s: %s", clientId, message);
mManager.onMessage(clientRecord.routeId, message);
}
///////////////////////////////////////////////
// SessionManagerListener implementation
///////////////////////////////////////////////
......@@ -156,10 +172,13 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider {
if (clientId != null) {
ClientRecord clientRecord = mClientRecords.get(clientId);
if (clientRecord != null) {
sessionController().notifyReceiverAction(
mMessageHandler.sendReceiverActionToClient(
clientRecord.routeId, sink, clientId, "cast");
}
}
mMessageHandler.onSessionStarted(sessionController());
sessionController().getSession().getRemoteMediaClient().requestStatus();
}
@Override
......@@ -191,9 +210,7 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider {
}
detachFromSession();
if (mAndroidMediaRouter != null) {
mAndroidMediaRouter.selectRoute(mAndroidMediaRouter.getDefaultRoute());
}
getAndroidMediaRouter().selectRoute(getAndroidMediaRouter().getDefaultRoute());
}
@Override
......@@ -291,4 +308,12 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider {
return false;
return originA.equals(originB);
}
Collection<String> getClients() {
return mClientRecords.keySet();
}
Map<String, ClientRecord> getClientRecordss() {
return mClientRecords;
}
}
// 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.caf;
/**
* The handler for cast messages. It receives events between the Cast SDK and the page, process and
* dispatch the messages accordingly. The handler talks to the Cast SDK via CastSession, and
* talks to the pages via the media router.
*/
public class CastMessageHandler {
// Sequence number used when no sequence number is required or was initially passed.
static final int INVALID_SEQUENCE_NUMBER = -1;
}
......@@ -4,11 +4,18 @@
package org.chromium.chrome.browser.media.router.caf;
import android.support.v7.media.MediaRouter;
import com.google.android.gms.cast.CastDevice;
import com.google.android.gms.cast.framework.CastSession;
import org.chromium.chrome.browser.media.router.CastSessionUtil;
import org.chromium.chrome.browser.media.router.MediaSink;
import org.chromium.chrome.browser.media.router.MediaSource;
import java.util.ArrayList;
import java.util.List;
/**
* A wrapper for {@link CastSession}, extending its functionality for Chrome MediaRouter.
*
......@@ -43,19 +50,46 @@ public class CastSessionController {
}
public void endSession() {
CastSession currentCastSession =
CastUtils.getCastContext().getSessionManager().getCurrentCastSession();
if (currentCastSession == mCastSession) {
CastUtils.getCastContext().getSessionManager().endCurrentSession(true);
MediaRouter mediaRouter = mProvider.getAndroidMediaRouter();
mediaRouter.selectRoute(mediaRouter.getDefaultRoute());
}
public List<String> getNamespaces() {
// Not implemented.
return new ArrayList<>();
}
public List<String> getCapabilities() {
List<String> capabilities = new ArrayList<>();
if (mCastSession == null || !mCastSession.isConnected()) return capabilities;
CastDevice device = mCastSession.getCastDevice();
if (device.hasCapability(CastDevice.CAPABILITY_AUDIO_IN)) {
capabilities.add("audio_in");
}
if (device.hasCapability(CastDevice.CAPABILITY_AUDIO_OUT)) {
capabilities.add("audio_out");
}
if (device.hasCapability(CastDevice.CAPABILITY_VIDEO_IN)) {
capabilities.add("video_in");
}
if (device.hasCapability(CastDevice.CAPABILITY_VIDEO_OUT)) {
capabilities.add("video_out");
}
return capabilities;
}
public void onSessionStarted() {
// Not implemented.
}
public void notifyReceiverAction(
String routeId, MediaSink sink, String clientId, String action) {
// Not implemented.
public boolean isConnected() {
return mCastSession != null && mCastSession.isConnected();
}
public void updateRemoteMediaClient(String message) {
if (!isConnected()) return;
mCastSession.getRemoteMediaClient().onMessageReceived(
mCastSession.getCastDevice(), CastSessionUtil.MEDIA_NAMESPACE, message);
}
}
......@@ -394,7 +394,7 @@ public class CastMediaRouteProvider extends BaseMediaRouteProvider {
tabId));
}
// TODO(zqzhang): Move this method to CastMessageHandler.
// Migrated to CastMessageHandler.sendReceiverActionToClient. See https://crbug.com/711860.
private void sendReceiverAction(
String routeId, MediaSink sink, String clientId, String action) {
try {
......
......@@ -14,6 +14,8 @@ import org.json.JSONObject;
import org.chromium.base.Log;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.media.router.CastRequestIdGenerator;
import org.chromium.chrome.browser.media.router.CastSessionUtil;
import org.chromium.chrome.browser.media.router.ClientRecord;
import java.util.ArrayDeque;
......@@ -28,6 +30,7 @@ import java.util.Queue;
* dispatch the messages accordingly. The handler talks to the Cast SDK via CastSession, and
* talks to the pages via the media router.
*/
// Migrated to CafMessageHandler. See https://crbug.com/711860.
public class CastMessageHandler {
private static final String TAG = "MediaRouter";
......@@ -199,8 +202,7 @@ public class CastMessageHandler {
}
if ("SET_VOLUME".equals(messageType)) {
CastSession.HandleVolumeMessageResult result =
mSession.handleVolumeMessage(
CastSession.HandleVolumeMessageResult result = mSession.handleVolumeMessage(
jsonCastMessage.getJSONObject("volume"), clientId, sequenceNumber);
if (!result.mSucceeded) return false;
......
......@@ -20,6 +20,7 @@ import org.json.JSONObject;
import org.chromium.base.Log;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.media.router.CastSessionUtil;
import org.chromium.chrome.browser.media.router.FlingingController;
import org.chromium.chrome.browser.media.router.MediaSource;
import org.chromium.chrome.browser.media.ui.MediaNotificationInfo;
......@@ -42,9 +43,6 @@ import javax.annotation.Nullable;
public class CastSessionImpl implements MediaNotificationListener, CastSession {
private static final String TAG = "MediaRouter";
// The value is borrowed from the Android Cast SDK code to match their behavior.
private static final double MIN_VOLUME_LEVEL_DELTA = 1e-7;
private static class CastMessagingChannel implements Cast.MessageReceivedCallback {
private final CastSession mSession;
......@@ -405,7 +403,8 @@ public class CastSessionImpl implements MediaNotificationListener, CastSession {
double newLevel = volume.getDouble("level");
double currentLevel = Cast.CastApi.getVolume(mApiClient);
if (!Double.isNaN(currentLevel)
&& Math.abs(currentLevel - newLevel) > MIN_VOLUME_LEVEL_DELTA) {
&& Math.abs(currentLevel - newLevel)
> CastSessionUtil.MIN_VOLUME_LEVEL_DELTA) {
Cast.CastApi.setVolume(mApiClient, newLevel);
waitForVolumeChange = true;
}
......
......@@ -17,12 +17,12 @@ import org.json.JSONObject;
import org.chromium.base.Log;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.media.remote.RemoteMediaPlayerWrapper;
import org.chromium.chrome.browser.media.router.CastSessionUtil;
import org.chromium.chrome.browser.media.router.FlingingController;
import org.chromium.chrome.browser.media.router.MediaSource;
import org.chromium.chrome.browser.media.router.cast.CastMessageHandler;
import org.chromium.chrome.browser.media.router.cast.CastSession;
import org.chromium.chrome.browser.media.router.cast.CastSessionInfo;
import org.chromium.chrome.browser.media.router.cast.CastSessionUtil;
import org.chromium.chrome.browser.media.router.cast.ChromeCastSessionManager;
import org.chromium.chrome.browser.media.ui.MediaNotificationInfo;
import org.chromium.chrome.browser.media.ui.MediaNotificationListener;
......
......@@ -742,6 +742,8 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/media/remote/RemoteVideoInfo.java",
"java/src/org/chromium/chrome/browser/media/remote/PositionExtrapolator.java",
"java/src/org/chromium/chrome/browser/media/router/BaseMediaRouteDialogManager.java",
"java/src/org/chromium/chrome/browser/media/router/CastRequestIdGenerator.java",
"java/src/org/chromium/chrome/browser/media/router/CastSessionUtil.java",
"java/src/org/chromium/chrome/browser/media/router/ClientRecord.java",
"java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java",
"java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterDialogController.java",
......@@ -766,16 +768,14 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/media/router/caf/CastUtils.java",
"java/src/org/chromium/chrome/browser/media/router/caf/CafBaseMediaRouteProvider.java",
"java/src/org/chromium/chrome/browser/media/router/caf/CafMediaRouteProvider.java",
"java/src/org/chromium/chrome/browser/media/router/caf/CastMessageHandler.java",
"java/src/org/chromium/chrome/browser/media/router/caf/CafMessageHandler.java",
"java/src/org/chromium/chrome/browser/media/router/cast/BaseMediaRouteProvider.java",
"java/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProvider.java",
"java/src/org/chromium/chrome/browser/media/router/cast/CastMediaSource.java",
"java/src/org/chromium/chrome/browser/media/router/cast/CastMessageHandler.java",
"java/src/org/chromium/chrome/browser/media/router/cast/CastRequestIdGenerator.java",
"java/src/org/chromium/chrome/browser/media/router/cast/CastSession.java",
"java/src/org/chromium/chrome/browser/media/router/cast/CastSessionImpl.java",
"java/src/org/chromium/chrome/browser/media/router/cast/CastSessionInfo.java",
"java/src/org/chromium/chrome/browser/media/router/cast/CastSessionUtil.java",
"java/src/org/chromium/chrome/browser/media/router/cast/ChromeCastSessionManager.java",
"java/src/org/chromium/chrome/browser/media/router/cast/CreateRouteRequest.java",
"java/src/org/chromium/chrome/browser/media/router/cast/remoting/RemotingCastSession.java",
......
......@@ -35,6 +35,7 @@ import org.robolectric.shadows.ShadowLog;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.media.router.CastSessionUtil;
import org.chromium.chrome.browser.media.router.ClientRecord;
import org.chromium.chrome.browser.media.router.cast.CastMessageHandler.RequestRecord;
import org.chromium.chrome.browser.media.router.cast.JSONTestUtils.JSONObjectLike;
......
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