安卓源码避坑指南7——蓝牙音乐播放状态一直为暂停态
蓝牙音乐的播放状态是蓝牙音乐等相关应用重点关心的变量,应用根据该状态值(播放、暂停)实时更新界面图标显示。本期就和大家简单分享下蓝牙音乐播放状态上报错误的源码问题。
播放状态都是通过AVRCP协议从手机端获取过来的,还不了解的同学查看前面的AVRCP系列文章,相信能给大家提供帮助。
CT控制端获取播放状态有两种方法:
1、AVRCP Get Play Status
2、AVRCP Register Notification(Event = Playback)
方法1是蓝牙协议栈bluedroid通过命令AVRCP Get Play Status可以获取到当前的播放状态及进度条信息,但是该命令只有音乐播放时才会触发2s的定时器循环获取,而且获取到信息只会将进度条Position上报,其他信息不做处理,因此该命令在现有的安卓系统中无法满足音乐应用的需求。
方法2则是通过命令AVRCP Register Notification注册一个Playback事件的通知,当播放状态改变时,手机端TG会主动通知到CT端,该方法获取到的播放或暂停状态才符合应用的要求。
通过注册通知命令获取播放状态在安卓系统的时序图如下:
音乐播放状态值最终保存在AvrcpPlayer.mPlayStatus变量中,后续蓝牙服务对外广播当前的音乐播放状态也是获取该值广播出去的。
按照通常的分析,该值应该一直保存着最新的手机通知的状态值,然而事实却非如此…
问题环境:高通安卓系统(android-9)
问题现象:蓝牙音乐实际在播放中,可CT控制端上报给应用的播放状态一直为Pause态
详细的播放状态值在PlaybackState类中有定义:Pause = 2、Playing = 3。
不知大家在蓝牙音乐开发使用的过程中是否有遇到这种问题,我首先怀疑是手机本身通知的状态有误,查看HCI文件后打消了这种想法。
AvrcpPlayer.mPlayStatus值是在什么时候被改写了?
带着这个疑点查看源码,可知AvrcpPlayer.mPlayStatus变量只有在AvrcpPlayer.setPlayStatus()方法调用才会被重写,但是这个方法只会在手机通知播放状态变化时才会调用到,但分析完HCI后,手机通知的状态值明显都是正确值 Playing,那怎么无缘无故变成Pause ?
分析到这儿,不知大家是否困惑了,反正我已经…
继续查看logcat,终于发现问题所在:更新音乐播放器AvrcpPlayer相关信息时,高通安卓源码中还新增了更新播放器对象mAddressedPlayer的操作,从而间接改变了AvrcpPlayer.mPlayStatus的值。
播放器的更新也是通过注册一个Players和Player事件的通知来实现的,CT控制端接收到播放器改变的通知后使用命令AVRCP Get Folder Items获取播放器信息,最终在AvrcpControllerStateMachine状态机中通过msg.what = MESSAGE_PROCESS_GET_PLAYER_ITEMS更新播放器信息。
由于手机回复AVRCP Get Folder Items的信息中Play Status = Paused :
从而将AvrcpPlayer.mPlayStatus值从 Playing变为Pause:
解决方案:更新播放器对象mAddressedPlayer前,将旧播放器对象中的 mPlayStatus值更新到新播放器对象中进行保存。