屏幕关闭时,MediaPlayer 在 Lollipop 上过早切断播放

MediaPlayer cutting off playback too early on Lollipop when Screen is off

我在 Lollipop 设备上遇到了 MediaPlayer 的问题。基本上,当设备屏幕关闭(即用户锁定设备)时,播放会继续,但会提前 1-2 秒结束。不过,当屏幕打开时不会发生这种情况。

我在 MediaPlayer 上有一个 onCompletionListener:

@Override
public void onCompletion(final MediaPlayer mediaPlayer) {
    int progress = mediaPlayer.getCurrentPosition();
    int duration = mediaPlayer.getDuration();
    Log.d("PlaybackController", "progress: " + progress + " duration: " + duration);
    Log.d("PlaybackController", "Delay: " + (duration - progress)); // I'm seeing a difference of 1 - 3 seconds :(.
    mServiceHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            broadcastCompleted();
        }
    }, Math.max(duration - progress, 0));
}

这通常会打印:Delay: [1500 - 3000]。我想知道是否缺少唤醒锁,但我正在制作此处提到的正确锁:http://developer.android.com/guide/topics/media/mediaplayer.html,其中包括一个 PARTIAL_WAKE_LOCK 和一个 WifiLock。还有什么我想念的吗?

好的,看来问题出在 Android 5.0.1 的实验性 MediaPlayer,称为 NuPlayer。 NuPlayer 在所有 Android 5.0.1 设备上默认启用,只能通过开发人员选项禁用。我在这里提交了针对 Android 的错误:https://code.google.com/p/android/issues/detail?id=94069&thanks=94069&ts=1420659450

这是您的用户在 Android 5.0.1 设备上遇到媒体播放问题时可以发送给他们的示例电子邮件:

看起来这可能是 Android 名为 NuPlayer 的新实验性 MediaPlayer 上的错误。要解决此问题,请按照以下步骤操作:

  1. 转到 Android 设置
  2. 转到"About Phone"
  3. 向下滚动到 "Build Number" 并点击内部版本号 7 次。
    • 您会看到一条消息说 "you are now X steps away from being a developer"。
    • 点击 7 次后会显示 "You are now a developer!"
  4. 返回主设置屏幕,您会在 "About Phone"
  5. 上方看到一个名为 "Developer Options" 的新选项
  6. 进入开发者选项并取消选择媒体部分下的 "Use NuPlayer (experimental)"。

更新: 在 MediaPlayer 上设置部分唤醒锁可解决此问题:

playerToPrepare.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK);

部分唤醒锁应该不会有太大的影响,似乎 MediaPlayer 本身会在播放完成时清理它。

-- 原答案 ---

我从这里 Prevent my audio app using NuPlayer on Android Lollipop 5.x? 交叉发布我的答案,直到有 NuPlayer 的修复,你能做的最好的事情就是检测 NuPlayer 何时启用并将用户带到开发人员设置。

此方法检查 Android 的系统属性值,以查看用户是否在开发人员设置下启用了 AwesomePlayer 的使用。由于 Lollipop 默认启用 NuPlayer,如果禁用此值,我们知道将使用 NuPlayer。

SystemProperties.java 放入您的项目中以访问读取系统属性,不要将其包名称从 android.os 更改(它会调用相应的 JNI 方法,因此需要保持不变).

您现在可以检查 phone 是否为 Lollipop/5.0,是否启用 AwesomePlayer,如果未启用则采取相应措施(例如通过打开开发人员设置):

public void openDeveloperSettingsIfAwesomePlayerNotActivated(final Context context) {
    final boolean useAwesome = SystemProperties.getBoolean("persist.sys.media.use-awesome", false);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !useAwesome) {
        final Intent intent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
        context.startActivity(intent);                
    }
}