为演员设备启动演员会话

时间:2017-10-08 14:20:34

标签: android google-cast google-cast-sdk

我有这个用例:

  1. 检测投射设备并保存其ID,名称和信息;
  2. 以自动方式连接到预定义设备并开始演员会话 有一些内容。
  3. 我研究过Google Cast API v3,看起来真的很难。虽然使用v2,但由于发送方应用程序控制了90%的进程,即与设备和加载内容的连接,因此v3会话完全由框架管理,并且会话仅在用户干预时启动。我的用例唯一值得的方法是SessionManager.startSession(Intent intent) doc here,但是完全没有记录如何使用intent,额外参数,操作等等。有没有人对这种方法和意图有一些了解?

3 个答案:

答案 0 :(得分:1)

TLDR;跳到步骤3-选项1 SessionManager.startSession)或步骤3-选项2 MediaRouter.selectRoute

步骤1-设置

像平常一样设置CastOptionsProvider。

这是我们将要使用的主要对象:

MediaRouter mediaRouter = MediaRouter.getInstance(activity);
CastContex context = CastContext.getSharedInstance(activity);
SessionManager sessionManager = context.getSessionManager();

第2步-检索用于保存/使用的路由(设备)

获取路由/设备ID

步骤2-选项1-当前缓存的路由

只需获取当前缓存的路由:

for (RouteInfo route : mediaRouter.getRoutes()) {
    // Save route.getId(); however you want (it's a string)
}

缺点:返回的路线可能已过时。 MediaRouter的路由缓存仅在触发扫描(由您手动或由演员库)触发时更新。

步骤2-选项2-主动扫描

主动扫描以获取最准确的路线列表:

MediaRouter.Callback callback = new MediaRouter.Callback() {
    private void updateMyRouteList() {
        for (RouteInfo route : mediaRouter.getRoutes()) {
            // Save route.getId() however you want (it's a string)
        }
    }
    @Override
    public void onRouteAdded(MediaRouter router, RouteInfo route) {
        updateMyRouteList();
    }

    @Override
    public void onRouteRemoved(MediaRouter router, RouteInfo route) {
        updateMyRouteList();
    }
    @Override
    public void onRouteChanged(MediaRouter router, RouteInfo route) {
        updateMyRouteList();
    }
};
mediaRouter.addCallback(new MediaRouteSelector.Builder()
                .addControlCategory(CastMediaControlIntent.categoryForCast(appId))
                .build(),
        callback,
        MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);

注意!,重要的是停止主动扫描,否则电池会很快耗尽!使用

停止扫描
mediaRouter.removeCallback(callback);

步骤2-选项3-被动扫描

选项2 相同,但是省略了flags的{​​{1}}自变量。
这个应该(我认为)是被动地监听路线变化。 (尽管您可能没有比选项1 更好的结果)。例如:

mediaRouter.addCallback

第3步-加入路线(设备)

如何以编程方式加入路线(设备)。 有两个主要选项。

这两个选项都将创建一个新会话,或者在您要加入的设备上加入现有的会话(如果appId相同)。

首先,准备

mediaRouter.addCallback(new MediaRouteSelector.Builder()
                .addControlCategory(CastMediaControlIntent.categoryForCast(appId))
                .build(),
        callback);

现在,考虑到我们从第2步

获得的// Optional - if your app changes receiverApplicationId on the fly you should change that here context.setReceiverApplicationId(appId); // Most people would just set this as a constant in their CastOptionsProvider // Listen for a successful join sessionManager.addSessionManagerListener(new SessionManagerListener<Session>() { @Override public void onSessionStarted(CastSession castSession, String sessionId) { // We successfully joined a route(device)! } }); ,如何实际加入路线

步骤3-选项1-SessionManager.startSession

注意:我发现此方法在我的Android 4.4设备上不起作用。我收到routeId,错误15(超时)。
不过,它确实可以在我的Android 7.0设备上工作。

SessionManagerListener.onSessionStartFailed

步骤3-选项2-MediaRouter.selectRoute

要使用此选项,您必须具有完整的// Create the intent Intent castIntent = new Intent(); // Mandatory, if null, nothing will happen castIntent.putExtra("CAST_INTENT_TO_CAST_ROUTE_ID_KEY", routeId); // (Optional) Uses this name in the toast castIntent.putExtra("CAST_INTENT_TO_CAST_DEVICE_NAME_KEY", route.getName()); // Optional - false = displays "Connecting to <devicename>..." castIntent.putExtra("CAST_INTENT_TO_CAST_NO_TOAST_KEY", true); sessionManager.startSession(castIntent); 对象,而不仅仅是id字符串。
如果已经有了对象,那就太好了!
如果没有,则可以使用步骤2-选项2-主动扫描中的方法,通过查找匹配的ID来获取Route对象。

Route

步骤4-流内容

一旦您完成了第3步准备工作中的会话,辛苦的工作就完成了。
您可以使用RemoteMediaClient来控制投射内容。

mediaRouter.selectRoute(routeObject);

完整代码

我将包括这一点,因为我花了很多时间来解决会话问题,希望它可以使其他人受益。 (包括Android 4.4 /慢速设备上的间歇性计时和崩溃问题[不确定是问题的根源])。

其中可能有一些多余的东西(特别是如果您使用恒定的appId,则RemoteMediaClient remoteMediaClient = castSession.getRemoteMediaClient(); remoteMediaClient.load(...); 将是无关紧要的),因此请使用所需的东西。

最相关的方法是initialize,它接受​​routeId字符串,并将主动扫描匹配项长达15秒。重试我的工作时还会处理一些错误。

您可以看到真实的full code here

selectRoute

使用chromecast很有趣...

答案 1 :(得分:0)

我发现了另一种不使用意图而是通过路由连接到投射设备的方法。

因此,第一步是使用类CastOptionsProvider和类型转换上下文初始化类型转换。获取设备的第二步和最后一步通过传递您在第二步中检索到的所选设备的路由来连接到投射设备:

MediaRouter.getInstance(activity).selectRoute(route);

答案 2 :(得分:-2)

我最近有同样的要求。

您可以使用MediaRouter检测演员设备。

MediaRouter mMediaRouter = MediaRouter.getInstance(this);
MediaRouteSelector mMediaRouteSelector = new MediaRouteSelector.Builder()
            .addControlCategory(CastMediaControlIntent.categoryForCast(getString(R.string.cast_app_id)))
            .build();
mMediaRouter.addCallback(mMediaRouterCallback, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);

// Then get your media routes using 
List<RouteInfo> routes = mMediaRouter.getRoutes()

// Get cast devices for your media routes.
// Save these for future use as per your use case
List<CastDevice> castDevices = routes.stream()
    .map(route -> CastDevice.getFromBundle(route.getExtras()))
    .collect(Collectors.toCollection())

要自动连接到演员设备并流式播放某些内容,请使用此代码段。请注意,根据您的接收器应用程序,您可能无法使用RemoteMediaPlayer。此代码段对我有用,因为我的接收器应用程序使用MediaManager

// Connect to the cast device you want to stream the content to
private void connectToCastDevice(CastDevice castDevice) {
    Cast.CastOptions apiOptions = Cast.CastOptions.builder(castDevice, mCastListener).build();
    mApiClient = new GoogleApiClient.Builder(this)
            .addApi(Cast.API, apiOptions)
            .addConnectionCallbacks(mConnectionCallback)
            .addOnConnectionFailedListener(mConnectionFailedListener)
            .build();
    mApiClient.connect();
}

// After you are connected to the cast device. Load your media to it
// In my case using RemoteMediaPlayer
private void loadMediaItem(final MediaInfo mediaInfo) {
    LaunchOptions launchOptions = new LaunchOptions();
    launchOptions.setRelaunchIfRunning(false);

    PendingResult<Cast.ApplicationConnectionResult> result = Cast.CastApi.launchApplication(mApiClient, getString(R.string.cast_app_id), launchOptions);

    result.then(new ResultTransform<Cast.ApplicationConnectionResult, RemoteMediaPlayer.MediaChannelResult>() {

        @Nullable @Override
        public PendingResult<RemoteMediaPlayer.MediaChannelResult> onSuccess(@NonNull Cast.ApplicationConnectionResult applicationConnectionResult) {
            Log.d(TAG, "Application launch result: " + applicationConnectionResult);
            return mRemoteMediaPlayer.load(mApiClient, mediaInfo);
        }

    }).andFinally(new ResultCallbacks<RemoteMediaPlayer.MediaChannelResult>() {

        @Override
        public void onSuccess(@NonNull RemoteMediaPlayer.MediaChannelResult mediaChannelResult) {
            Log.d(TAG, "Media channel result: " + mediaChannelResult);
        }

        @Override
        public void onFailure(@NonNull Status status) {
            Log.d(TAG, "Media channel status: " + status);
        }

    });
}