【问题标题】:How to keep a ChromeCast session alive when the device is asleep?如何在设备处于睡眠状态时保持 ChromeCast 会话处于活动状态?
【发布时间】:2017-10-21 17:21:06
【问题描述】:

我有一个可以将本地媒体内容流式传输到 Chromecast 接收器的应用。这主要是可行的,除了当设备处于睡眠状态并且没有使用外部电源时,会话将在大约 5 分钟后终止/断开连接(从屏幕变黑时开始测量)。

我已经在这里看过这个问题了:

How do I keep a ChromeCast route alive when my app is in the background on battery power?

...并实施了两个建议的答案。

具体来说,在我的应用清单中,我有:

<uses-permission android:name="android.permission.WAKE_LOCK" />

然后在我用来将媒体内容流式传输到 Chromecast 接收器的嵌入式 HTTP 服务器中,我正在做:

PowerManager powerManager = (PowerManager)Environment.getApplicationContext().getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "cast-server-cpu");
wakeLock.acquire();

WifiManager wifiManager = (WifiManager)Environment.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "cast-server-net");
wifiLock.acquire();

该代码在服务器线程启动时执行(在选择 Chromecast 路由时发生),并且在服务器停止之前不会释放锁。这发生在我的MediaRouter.Callback 实现中,它(结合上述问题中接受的答案)如下所示:

this.mediaRouterCallback = new MediaRouter.Callback() {
    private MediaRouter.RouteInfo autoconnectRoute = null;

    @Override
    public void onRouteSelected(MediaRouter mediaRouter, MediaRouter.RouteInfo routeInfo) {
        if (autoconnectRoute == null) {
            if (isPlaying()) {
                stop();
                playButton.setImageResource(R.drawable.icon_play);
            }

            castDevice = CastDevice.getFromBundle(routeInfo.getExtras());
            if (castServer != null) {
                castServer.stop();
            }

            //start the Chromecast file server
            castServer = new CastHttpFileServer();
            new Thread(castServer).start();
        }

        initCastClientListener();
        initRemoteMediaPlayer();
        launchReceiver();
    }

    @Override
    public void onRouteUnselected(MediaRouter mediaRouter, MediaRouter.RouteInfo routeInfo) {
        if (! doesRouterContainRoute(mediaRouter, routeInfo)) {
            //XXX:  do not disconnect in this case (the unselect was not initiated by a user action); see https://stackoverflow.com/questions/18967879/how-do-i-keep-a-chromecast-route-alive-when-my-app-is-in-the-background-on-batte
            autoconnectRoute = routeInfo;
            return;
        }

        //user disconnected, teardown and stop playback
        if (isPlaying()) {
            stop();
            playButton.setImageResource(R.drawable.icon_play);
        }
        if (castServer != null) {
            castServer.stop();
            castServer = null;
        }

        teardown();
        castDevice = null;
    }

    @Override
    public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) {
        super.onRouteAdded(router, route);
        if (autoconnectRoute != null && route.getId().equals(autoconnectRoute.getId())) {
            this.onRouteSelected(router, route);
        }
    }

    private boolean doesRouterContainRoute(MediaRouter router, MediaRouter.RouteInfo route) {
        if (router == null || route == null) {
            return false;
        }

        for (MediaRouter.RouteInfo info : router.getRoutes()) {
            if (info.getId().equals(route.getId())) {
                return true;
            }
        }

        return false;
    }
};

为了在设备处于睡眠状态且未连接到外部电源时保持 Chromecast 会话处于活动状态,还需要做些什么?

另外,考虑到这个问题只有在设备没有连接到 USB 时才会重现,在这种情况下,什么是调试的有效方法?

编辑

以下是会话终止时报告的堆栈跟踪(来自嵌入式 HTTP 服务器):

java.net.SocketException: Software caused connection abort
 at java.net.SocketOutputStream.socketWrite0(Native Method)
 at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:112)
 at java.net.SocketOutputStream.write(SocketOutputStream.java:157)
 at com.myapp.CastHttpFileServer.writeResponse(CastHttpFileServer.java:124)
 at com.myapp.CastHttpFileServer.run(CastHttpFileServer.java:180)

我还注意到,我可以在我的 RemoteMediaPlayer.OnStatusUpdatedListener 实现中捕获此事件,例如:

if (lastStatus == MediaStatus.PLAYER_STATE_PLAYING && mediaStatus.getPlayerState() == MediaStatus.PLAYER_STATE_BUFFERING) {
    //buffer underrun/receiver went away because the wifi died; how do we fix this?
}

【问题讨论】:

  • 检查SO post 中提供的答案,您可以在其中检查未选择时是否存在路由。
  • "在这种情况下,什么是调试的有效方法?" -- 通过 WiFi 尝试adb,也许,使用adb connect。如果这是 Android 6.0+ 设备,这可能是打盹模式或等效模式,在这种情况下,您的应用需要添加到电池优化白名单中。

标签: java android audio chromecast


【解决方案1】:

CommonsWare 有权在他的评论中使用它。我在运行 Android 7.1.2 的设备上进行了测试,Doze mode was causing the network to drop 在闲置了大约 5 分钟后,无论我的应用持有什么唤醒锁

解决方法是在清单中添加以下权限:

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

然后更新我的 onRouteSelected() 回调实现,以请求在选择 ChromeCast 路由时禁用打盹模式:

if (Build.VERSION.SDK_INT >= 23) {
    String packageName = context.getPackageName();
    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    if (! pm.isIgnoringBatteryOptimizations(packageName)) {
        //reguest that Doze mode be disabled
        Intent intent = new Intent();
        intent.setAction(
            Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
        intent.setData(Uri.parse("package:" + packageName));

        context.startActivity(intent);
    }

}

只要用户在出现提示时选择“是”,应用的唤醒锁就会受到尊重,即使设备未充电,ChromeCast 会话也会保持活动状态。

【讨论】:

  • 您在 Google 为 Play 商店批准您的应用时遇到问题吗?我处于类似的情况,我通过 HTTP 将视频从设备流式传输到接收器。打盹模式正在终止网络访问并且演员会话挂起。
  • @masterwok - 是的,我确实做到了。该应用程序因试图绕过打盹模式而被自动拒绝,尽管我多次尝试上诉,但谷歌迄今为止都拒绝了每一个。最终我所做的是构建了两个版本的应用程序;一种适用于因打盹模式而瘫痪的应用商店,另一种是绕过人们可以通过直接下载(即在 Google Play 之外)安装的打盹模式。如果你愿意,可以read all about it
  • 感谢您回复我。我计划在显示说明对话框后使用 ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS 意图将用户直接带到设置。这样做不需要 REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 权限,应该可以防止应用被拒绝。
  • 感谢您的提示。如果您还没有尝试过,我可以确认使用 ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS 不会导致 Play 商店批准出现问题。工作得很好;用户切换设置所必须经历的过程有点复杂(根据我的统计,点击 6 次并进行了一些滚动),但我想他们只需要做一次。
  • 很好,谢谢。顺便说一句,我在看 FuTorrent,他们似乎在应用程序中有一个电池优化设置,名为“保持 CPU 唤醒”。此外,他们的配套应用程序 DivX 似乎根本不请求电池优化设置(这很奇怪,因为它必须充当 HTTP 服务器)。也许这里还有其他解决方案?
猜你喜欢
  • 2018-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 2019-02-25
  • 2017-06-08
相关资源
最近更新 更多