Commit ac7ad272 authored by Zhiqiang Zhang's avatar Zhiqiang Zhang Committed by Commit Bot

[CAF MR] Making several CAF MR classes sticky

Previously we made CastMessage & CastSessionImpl (now
CastSessionController) lifecycle bound to per connection, which
makes the session management over-complicated. This CL makes
those classes having the same lifecycle as CafBaseMRP/CafMRP, so
there's no need to create/set/unset instances any more. These
instances will only be active when there's currently an active
session.

Bug: 711860
Change-Id: I1736bb7085cd1ffbffed8ec40f3410ebe997e64e
Reviewed-on: https://chromium-review.googlesource.com/1171582Reviewed-by: default avatarThomas Guilbert <tguilbert@chromium.org>
Commit-Queue: Zhiqiang Zhang <zqzhang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#584309}
parent 78a0d81f
...@@ -44,12 +44,13 @@ public abstract class CafBaseMediaRouteProvider ...@@ -44,12 +44,13 @@ public abstract class CafBaseMediaRouteProvider
protected Handler mHandler = new Handler(); protected Handler mHandler = new Handler();
// There can be only one Cast session at the same time on Android. // There can be only one Cast session at the same time on Android.
private CastSessionController mSessionController; private final CastSessionController mSessionController;
private CreateRouteRequestInfo mPendingCreateRouteRequestInfo; private CreateRouteRequestInfo mPendingCreateRouteRequestInfo;
protected CafBaseMediaRouteProvider(MediaRouter androidMediaRouter, MediaRouteManager manager) { protected CafBaseMediaRouteProvider(MediaRouter androidMediaRouter, MediaRouteManager manager) {
mAndroidMediaRouter = androidMediaRouter; mAndroidMediaRouter = androidMediaRouter;
mManager = manager; mManager = manager;
mSessionController = new CastSessionController(this);
} }
/** /**
...@@ -59,8 +60,6 @@ public abstract class CafBaseMediaRouteProvider ...@@ -59,8 +60,6 @@ public abstract class CafBaseMediaRouteProvider
@Nullable @Nullable
protected abstract MediaSource getSourceFromId(@NonNull String sourceId); protected abstract MediaSource getSourceFromId(@NonNull String sourceId);
protected abstract void requestSessionLaunch(CreateRouteRequestInfo createRouteRequest);
/** /**
* Forward the sinks back to the native counterpart. * Forward the sinks back to the native counterpart.
*/ */
...@@ -166,7 +165,7 @@ public abstract class CafBaseMediaRouteProvider ...@@ -166,7 +165,7 @@ public abstract class CafBaseMediaRouteProvider
mPendingCreateRouteRequestInfo = new CreateRouteRequestInfo( mPendingCreateRouteRequestInfo = new CreateRouteRequestInfo(
source, sink, presentationId, origin, tabId, isIncognito, nativeRequestId); source, sink, presentationId, origin, tabId, isIncognito, nativeRequestId);
requestSessionLaunch(mPendingCreateRouteRequestInfo); mSessionController.requestSessionLaunch(mPendingCreateRouteRequestInfo);
} }
@Override @Override
...@@ -183,6 +182,15 @@ public abstract class CafBaseMediaRouteProvider ...@@ -183,6 +182,15 @@ public abstract class CafBaseMediaRouteProvider
mSessionController.endSession(); mSessionController.endSession();
} }
///////////////////////////////////////////////////////
// SessionManagerListener implementation begin
///////////////////////////////////////////////////////
@Override
public final void onSessionStarting(CastSession session) {
// The session is not connected yet at this point so this is no-op.
}
@Override @Override
public void onSessionStartFailed(CastSession session, int error) { public void onSessionStartFailed(CastSession session, int error) {
for (String routeId : mRoutes.keySet()) { for (String routeId : mRoutes.keySet()) {
...@@ -193,9 +201,7 @@ public abstract class CafBaseMediaRouteProvider ...@@ -193,9 +201,7 @@ public abstract class CafBaseMediaRouteProvider
@Override @Override
public final void onSessionStarted(CastSession session, String sessionId) { public final void onSessionStarted(CastSession session, String sessionId) {
mSessionController = new CastSessionController(session, this, mSessionController.attachToCastSession(session);
mPendingCreateRouteRequestInfo.sink, mPendingCreateRouteRequestInfo.source);
onSessionStarted(mPendingCreateRouteRequestInfo); onSessionStarted(mPendingCreateRouteRequestInfo);
MediaSink sink = mPendingCreateRouteRequestInfo.sink; MediaSink sink = mPendingCreateRouteRequestInfo.sink;
...@@ -209,6 +215,35 @@ public abstract class CafBaseMediaRouteProvider ...@@ -209,6 +215,35 @@ public abstract class CafBaseMediaRouteProvider
mPendingCreateRouteRequestInfo = null; mPendingCreateRouteRequestInfo = null;
} }
@Override
public final void onSessionResumed(CastSession session, boolean wasSuspended) {
mSessionController.attachToCastSession(session);
}
@Override
public final void onSessionResuming(CastSession session, String sessionId) {}
@Override
public final void onSessionResumeFailed(CastSession session, int error) {}
@Override
public void onSessionEnding(CastSession session) {
mSessionController.detachFromCastSession(session);
getAndroidMediaRouter().selectRoute(getAndroidMediaRouter().getDefaultRoute());
}
@Override
public final void onSessionEnded(CastSession session, int error) {}
@Override
public final void onSessionSuspended(CastSession session, int reason) {
mSessionController.detachFromCastSession(session);
}
///////////////////////////////////////////////////////
// SessionManagerListener implementation end
///////////////////////////////////////////////////////
public @NonNull MediaRouter getAndroidMediaRouter() { public @NonNull MediaRouter getAndroidMediaRouter() {
return mAndroidMediaRouter; return mAndroidMediaRouter;
} }
...@@ -218,36 +253,14 @@ public abstract class CafBaseMediaRouteProvider ...@@ -218,36 +253,14 @@ public abstract class CafBaseMediaRouteProvider
abstract void onSessionStarted(CreateRouteRequestInfo request); abstract void onSessionStarted(CreateRouteRequestInfo request);
protected boolean hasSession() { protected boolean hasSession() {
return mSessionController != null; return mSessionController != null && mSessionController.isConnected();
} }
protected CastSessionController sessionController() { protected CastSessionController sessionController() {
return mSessionController; return mSessionController;
} }
// TODO(zqzhang): This should go away once the session controller becomes a sticky instance. public CafMessageHandler getMessageHandler() {
protected void detachFromSession() { return null;
mSessionController = null;
}
protected static class CreateRouteRequestInfo {
public final MediaSource source;
public final MediaSink sink;
public final String presentationId;
public final String origin;
public final int tabId;
public final boolean isIncognito;
public final int nativeRequestId;
public CreateRouteRequestInfo(MediaSource source, MediaSink sink, String presentationId,
String origin, int tabId, boolean isIncognito, int nativeRequestId) {
this.source = source;
this.sink = sink;
this.presentationId = presentationId;
this.origin = origin;
this.tabId = tabId;
this.isIncognito = isIncognito;
this.nativeRequestId = nativeRequestId;
}
} }
} }
...@@ -52,20 +52,6 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider { ...@@ -52,20 +52,6 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider {
return mClientRecords.keySet(); return mClientRecords.keySet();
} }
@Override
public void requestSessionLaunch(CreateRouteRequestInfo request) {
CastUtils.getCastContext().setReceiverApplicationId(request.source.getApplicationId());
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.
getAndroidMediaRouter().unselect(0);
routeInfo.select();
break;
}
}
}
@Override @Override
public void joinRoute( public void joinRoute(
String sourceId, String presentationId, String origin, int tabId, int nativeRequestId) { String sourceId, String presentationId, String origin, int tabId, int nativeRequestId) {
...@@ -149,12 +135,10 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider { ...@@ -149,12 +135,10 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider {
mManager.onMessage(clientRecord.routeId, message); mManager.onMessage(clientRecord.routeId, message);
} }
///////////////////////////////////////////////
// SessionManagerListener implementation
///////////////////////////////////////////////
@Override @Override
public void onSessionStarting(CastSession session) {} public CafMessageHandler getMessageHandler() {
return mMessageHandler;
}
@Override @Override
public void onSessionStarted(CreateRouteRequestInfo request) { public void onSessionStarted(CreateRouteRequestInfo request) {
...@@ -189,13 +173,7 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider { ...@@ -189,13 +173,7 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider {
@Override @Override
public void onSessionEnding(CastSession session) { public void onSessionEnding(CastSession session) {
// Not implemented. super.onSessionEnding(session);
}
@Override
public void onSessionEnded(CastSession session, int error) {
if (!hasSession()) return;
if (mClientRecords.isEmpty()) { if (mClientRecords.isEmpty()) {
for (String routeId : mRoutes.keySet()) mManager.onRouteClosed(routeId); for (String routeId : mRoutes.keySet()) mManager.onRouteClosed(routeId);
mRoutes.clear(); mRoutes.clear();
...@@ -208,22 +186,8 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider { ...@@ -208,22 +186,8 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider {
} }
mClientRecords.clear(); mClientRecords.clear();
} }
detachFromSession();
getAndroidMediaRouter().selectRoute(getAndroidMediaRouter().getDefaultRoute());
} }
@Override
public void onSessionResuming(CastSession session, String sessionId) {}
@Override
public void onSessionResumed(CastSession session, boolean wasSuspended) {}
@Override
public void onSessionResumeFailed(CastSession session, int error) {}
@Override
public void onSessionSuspended(CastSession session, int reason) {}
private void addRoute(MediaRoute route, String origin, int tabId) { private void addRoute(MediaRoute route, String origin, int tabId) {
CastMediaSource source = CastMediaSource.from(route.sourceId); CastMediaSource source = CastMediaSource.from(route.sourceId);
...@@ -253,6 +217,7 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider { ...@@ -253,6 +217,7 @@ public class CafMediaRouteProvider extends CafBaseMediaRouteProvider {
private CafMediaRouteProvider(MediaRouter androidMediaRouter, MediaRouteManager manager) { private CafMediaRouteProvider(MediaRouter androidMediaRouter, MediaRouteManager manager) {
super(androidMediaRouter, manager); super(androidMediaRouter, manager);
mMessageHandler = new CafMessageHandler(this);
} }
private boolean canJoinExistingSession( private boolean canJoinExistingSession(
......
...@@ -6,15 +6,20 @@ package org.chromium.chrome.browser.media.router.caf; ...@@ -6,15 +6,20 @@ package org.chromium.chrome.browser.media.router.caf;
import android.support.v7.media.MediaRouter; import android.support.v7.media.MediaRouter;
import com.google.android.gms.cast.ApplicationMetadata;
import com.google.android.gms.cast.Cast;
import com.google.android.gms.cast.CastDevice; import com.google.android.gms.cast.CastDevice;
import com.google.android.gms.cast.framework.CastSession; import com.google.android.gms.cast.framework.CastSession;
import org.chromium.base.Log;
import org.chromium.chrome.browser.media.router.CastSessionUtil; import org.chromium.chrome.browser.media.router.CastSessionUtil;
import org.chromium.chrome.browser.media.router.MediaSink; import org.chromium.chrome.browser.media.router.MediaSink;
import org.chromium.chrome.browser.media.router.MediaSource; import org.chromium.chrome.browser.media.router.MediaSource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* A wrapper for {@link CastSession}, extending its functionality for Chrome MediaRouter. * A wrapper for {@link CastSession}, extending its functionality for Chrome MediaRouter.
...@@ -22,19 +27,33 @@ import java.util.List; ...@@ -22,19 +27,33 @@ import java.util.List;
* Has the same lifecycle with CastSession. * Has the same lifecycle with CastSession.
*/ */
public class CastSessionController { public class CastSessionController {
private static final String TAG = "CastSessionController"; private static final String TAG = "CafSessionCtrl";
private final CastSession mCastSession; private CastSession mCastSession;
private final CafBaseMediaRouteProvider mProvider; private final CafBaseMediaRouteProvider mProvider;
private final MediaSink mSink; private MediaSink mSink;
private final MediaSource mSource; private MediaSource mSource;
private List<String> mNamespaces;
private final CastListener mCastListener;
public CastSessionController(CastSession castSession, CafBaseMediaRouteProvider provider, public CastSessionController(CafBaseMediaRouteProvider provider) {
MediaSink sink, MediaSource source) {
mCastSession = castSession;
mProvider = provider; mProvider = provider;
mSink = sink; mCastListener = new CastListener();
mSource = source; }
public void requestSessionLaunch(CreateRouteRequestInfo request) {
mSource = request.source;
mSink = request.sink;
CastUtils.getCastContext().setReceiverApplicationId(request.source.getApplicationId());
for (MediaRouter.RouteInfo routeInfo : mProvider.getAndroidMediaRouter().getRoutes()) {
if (routeInfo.getId().equals(request.sink.getId())) {
// Unselect and then select so that CAF will get notified of the selection.
mProvider.getAndroidMediaRouter().unselect(MediaRouter.UNSELECT_REASON_UNKNOWN);
routeInfo.select();
break;
}
}
} }
public MediaSource getSource() { public MediaSource getSource() {
...@@ -78,10 +97,6 @@ public class CastSessionController { ...@@ -78,10 +97,6 @@ public class CastSessionController {
return capabilities; return capabilities;
} }
public void onSessionStarted() {
// Not implemented.
}
public boolean isConnected() { public boolean isConnected() {
return mCastSession != null && mCastSession.isConnected(); return mCastSession != null && mCastSession.isConnected();
} }
...@@ -92,4 +107,91 @@ public class CastSessionController { ...@@ -92,4 +107,91 @@ public class CastSessionController {
mCastSession.getRemoteMediaClient().onMessageReceived( mCastSession.getRemoteMediaClient().onMessageReceived(
mCastSession.getCastDevice(), CastSessionUtil.MEDIA_NAMESPACE, message); mCastSession.getCastDevice(), CastSessionUtil.MEDIA_NAMESPACE, message);
} }
public void attachToCastSession(CastSession session) {
mCastSession = session;
mCastSession.addCastListener(mCastListener);
}
public void detachFromCastSession(CastSession session) {
mCastSession.removeCastListener(mCastListener);
mCastSession = null;
}
private class CastListener extends Cast.Listener {
@Override
public void onApplicationStatusChanged() {
CastSessionController.this.onApplicationStatusChanged();
}
@Override
public void onApplicationMetadataChanged(ApplicationMetadata metadata) {
onApplicationStatusChanged();
}
@Override
public void onVolumeChanged() {
CafMessageHandler messageHandler = mProvider.getMessageHandler();
if (messageHandler == null) return;
messageHandler.onVolumeChanged();
}
}
private void onApplicationStatusChanged() {
updateNamespaces();
CafMessageHandler messageHandler = mProvider.getMessageHandler();
if (messageHandler != null) {
messageHandler.broadcastClientMessage(
"update_sesssion", messageHandler.buildSessionMessage());
}
}
private void updateNamespaces() {
if (!isConnected()) return;
Set<String> namespacesToAdd =
new HashSet<>(mCastSession.getApplicationMetadata().getSupportedNamespaces());
Set<String> namespacesToRemove = new HashSet<String>(mNamespaces);
namespacesToRemove.removeAll(namespacesToAdd);
namespacesToAdd.removeAll(mNamespaces);
for (String namespace : namespacesToRemove) unregisterNamespace(namespace);
for (String namespace : namespacesToAdd) registerNamespace(namespace);
}
private void registerNamespace(String namespace) {
assert !mNamespaces.contains(namespace);
if (!isConnected()) return;
try {
mCastSession.setMessageReceivedCallbacks(namespace, this ::onMessageReceived);
mNamespaces.add(namespace);
} catch (Exception e) {
Log.e(TAG, "Failed to register namespace listener for %s", namespace, e);
}
}
private void unregisterNamespace(String namespace) {
assert mNamespaces.contains(namespace);
if (!isConnected()) return;
try {
mCastSession.removeMessageReceivedCallbacks(namespace);
mNamespaces.remove(namespace);
} catch (Exception e) {
Log.e(TAG, "Failed to remove the namespace listener for %s", namespace, e);
}
}
private void onMessageReceived(CastDevice castDevice, String namespace, String message) {
Log.d(TAG,
"Received message from Cast device: namespace=\"" + namespace + "\" message=\""
+ message + "\"");
CafMessageHandler messageHandler = mProvider.getMessageHandler();
messageHandler.onMessageReceived(namespace, message);
}
} }
// 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;
import org.chromium.chrome.browser.media.router.MediaSink;
import org.chromium.chrome.browser.media.router.MediaSource;
/** The information of create route requests. */
public class CreateRouteRequestInfo {
public final MediaSource source;
public final MediaSink sink;
public final String presentationId;
public final String origin;
public final int tabId;
public final boolean isIncognito;
public final int nativeRequestId;
public CreateRouteRequestInfo(MediaSource source, MediaSink sink, String presentationId,
String origin, int tabId, boolean isIncognito, int nativeRequestId) {
this.source = source;
this.sink = sink;
this.presentationId = presentationId;
this.origin = origin;
this.tabId = tabId;
this.isIncognito = isIncognito;
this.nativeRequestId = nativeRequestId;
}
}
...@@ -778,6 +778,7 @@ chrome_java_sources = [ ...@@ -778,6 +778,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/media/router/caf/CafBaseMediaRouteProvider.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/CafMediaRouteProvider.java",
"java/src/org/chromium/chrome/browser/media/router/caf/CafMessageHandler.java", "java/src/org/chromium/chrome/browser/media/router/caf/CafMessageHandler.java",
"java/src/org/chromium/chrome/browser/media/router/caf/CreateRouteRequestInfo.java",
"java/src/org/chromium/chrome/browser/media/router/cast/BaseMediaRouteProvider.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/CastMediaRouteProvider.java",
"java/src/org/chromium/chrome/browser/media/router/cast/CastMediaSource.java", "java/src/org/chromium/chrome/browser/media/router/cast/CastMediaSource.java",
......
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