3

I'm working on an Android app that supports sending music to a ChromeCast. We'd like users to be able to cast entire music playlists while the app runs in the background.

When my Nexus 7 is not connected to USB power and I turn the screen inactivity timeout to 15 seconds in the settings, the app will disconnect from the ChromeCast about 90 seconds after the device powers off its screen.

I've identified that I'm getting a MediaRouter.Callback call to onRouteUnselected, and since that's the callback I get when a user disconnects from a route, I'm handling it by tearing down the ApplicationSession.

When I plug back in and check the logcat, I see this message around the same time:

I/MediaRouter(19970): Choosing a new selected route because the current one is no longer selectable: MediaRouter.RouteInfo{ uniqueId=... }

Can I do anything to avoid the route being unselected when the app is in the background, or is there something else I can do to get the behavior I want?

4

3 回答 3

3

我最终通过拒绝断开消息流并在路由在这些条件下断开时断开会话来解决这个问题,并在路由再次可用时默默地重新选择路由。路线被取消选择,但它不会影响我的投射会话。

为此,我检查未选择时是否存在该路线。

public void onRouteUnselected(final MediaRouter router, final RouteInfo route) {
    if (!onUiThread()) {
        new Handler(Looper.getMainLooper()).post((new Runnable() {
            @Override
            public void run() {
                onRouteUnselected(router, route);
            }
        }));

        return;
    }

    boolean isThisRouteAvailable = doesRouterContainRoute(router, route);

    mRouteToReconnectTo = null;

    if (isThisRouteAvailable) {
        // Perform code to close the message streams and tear down the session.
    } else {
        // The route was unselected because it's no longer available from the router,
        // so try to just keep playing until the message streams get disconnected.
        mRouteToReconnectTo = route;
        // Short-circuited a disconnect.
    }
}

稍后,当路由回来时,我们可以立即重新选择它。

@Override
public void onRouteAdded(MediaRouter router, RouteInfo route) {
    super.onRouteAdded(router, route);
    // if mRouteToReconnectTo is not null, check to see if this route
    // matches it, and reconnect if it does with router.selectRoute(route)
}

@Override
public void onRouteSelected(final MediaRouter router, final RouteInfo route) {
    if (!onUiThread()) {
        new Handler(Looper.getMainLooper()).post((new Runnable() {
            @Override
            public void run() {
                onRouteSelected(router, route);
            }
        }));

        return;
    }

    if (areRoutesEqual(mRouteToReconnectTo, route)) {
        // Short-circuited a reconnect.
        mRouteToReconnectTo = null;
        return;
    }

    mRouteToReconnectTo = null;

    // Standard post-selection stuff goes here
}

没有比较两个 RouteInfo 的好方法,所以我最终编写了一个辅助函数来比较它们的描述字符串。

于 2013-10-16T19:30:13.320 回答
3

Rooster 的回答是完全可行的,并且实际上提供了很好的洞察力,了解如何重新连接到一条路线,一旦它重新上线......

但是....只是为了进一步了解正在发生的事情....

你越来越...

I/MediaRouter(19970): Choosing a new selected route because the current one is no longer selectable: MediaRouter.RouteInfo{ uniqueId=... }

因为当设备进入睡眠状态且未插入电源时,WIFI 硬件将进入低功耗配置文件模式(并可能完全关闭)。这会导致数据包丢失并随后导致 MedaRouter 触发 onRouteUnselected 回调。

为了防止 Wifi 关闭,您可以通过以下方式在 Wifi 上设置 WakeLock:

WifiLock wifiLock;
WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF , "MyWifiLock");
wifiLock.acquire();

使用标志 WifiManager.WIFI_MODE_FULL_HIGH_PERF 将在设备进入睡眠状态时保持 WIFI 硬件处于活动状态。注意,此标志仅适用于 API 12 及更高版本。

我在创建 WifiLock 时尝试使用 WifiManager.WIFI_MODE_FULL 标志,但这似乎没有奏效。

显然,任何使用任何类型的 WifiLock 或 WakeLock 的人都应该非常小心地确保在不再需要时释放锁。此外,请注意,当设备屏幕关闭时,这会导致电池耗尽。

于 2013-10-19T20:50:17.357 回答
0

如果您使用示例代码(在本例中为 Android),您可能正在这样做......

mSession.setStopApplicationWhenEnding(true);
mSession.endSession();

...当路线未选择时。如果你改为这样做......

mSession.setStopApplicationWhenEnding(false);
mSession.endSession();

...然后您可以清理会话,但 Chromecast 将使应用程序保持活动状态。当路由再次可用时(或者可能当用户再次选择设备时),您可以建立一个新会话。我还没有探索如何确定新会话是在与应用程序的“全新”实例通信还是与从另一个会话运行的应用程序通信,但是当我这样做时我会更新这个答案。

于 2014-01-26T21:27:17.610 回答