播放QQ音乐,连接蓝牙播放蓝牙音乐,点击暂停后QQ音乐会自动
问题发生的背景:
①手机连接蓝牙后,RTI即时消息模式开启,但是源是非蓝牙声源(Radio):
②按下手机音乐界面的播放键,蓝牙中间件申请获取蓝牙音乐短焦点;
③ 在①+②前提下,按下手机音乐界面的暂停键,蓝牙中间件申请释放蓝牙音乐短焦点, 但焦点管理类依据规则,把焦点给到上一个声源(Radio),上一个声源播放媒体了。
④ 在①+②前提下,按下车机蓝牙音乐界面的暂停键,蓝牙中间件申请释放蓝牙音乐短焦点,但焦点管理类依据规则,把焦点给到上一个声源(Radio),上一个声源播放媒体了
⑤ 在①前提下,按下车机蓝牙音乐界面的播放键,P层会记忆是蓝牙音乐播放,蓝牙中间件申请获取蓝牙音乐短焦点;按下车机蓝牙音乐界面的暂停键,P层不告知蓝牙中间件申请释放蓝牙音乐短焦点。
结论:
⑤是对的,③ ④ 结果与 ⑤ 不同,
正确的结果是,无论是按下手机还是车机的音乐暂停键,焦点都不能给到上一个声源(Radio)
解析问题发生原因:
手机有即时消息(按键音,锁屏音,导航语音,微信语音、抖音等)和音乐(水果、哔哩哔哩、QQ音乐、ACFUN等)。车机在非蓝牙音乐源的情况下且RTI即时消息模式开启前提下,
如果手机播放蓝牙音乐,则蓝牙中间件需要申请获取长焦点,在暂停(手机端或者车机端 按下暂停按钮),蓝牙中间件不需要申请释放长焦点。
如果手机播放即时消息,则蓝牙中间件需要申请获取短焦点,在自动播放完即时消息后,蓝牙中间件需要申请释放短焦点;
但是由于即时消息和音乐都是从蓝牙通道发到车机的,目前共用了一个源,且一个源不能同时存在长焦点和短焦点,所以一刀切的认为从手机发来的都是即时消息,申请获取短焦点,这样推流结束后(包括按下暂停导致推流结束),都认为是即时消息结束,所以蓝牙中间件申请释放短焦点,上一个声源(Radio),获取焦点后播放媒体了。
解决方案:
第一种:
在不增加 “即时消息” 声源(与RVC、蓝牙电话 同属于短焦点源)前提下,只使用 蓝牙音乐源 + 短焦点,和AVRCP协议来判断,手机播放的是蓝牙音乐还是即时消息。
void retAvrcp13PlayStatus(String address, long songLen, long songPos, byte statusId)
此方法是安富协议栈回调给蓝牙中间件的aidl方法,安富协议栈是把手机蓝牙信道的数据透传给蓝牙中间件。
Address 是手机蓝牙Mac地址,songLen是单曲的长度,songPos是单曲的进度,statusId是播放 和暂停
虽然A2dp协议也有 STEAM 拨流状态和CONNECT 连接状态,代表播放和暂停,但是与 statusId雷同,这里仅用AVRCP 协议判断。
连接蓝牙后,上述方法会不定期的被调用,两次调用间隔时间均<1s,status为2,songLen和songPos都为0,此时认为蓝牙音乐app没有打开。
Vector<Long> buffer = new Vector<>(5); 此buffer是FIFO通道,用于存储 songPos
Status 2->1意味着开始播放,此时保留 buffer 最后一个数据,清空之前的数据,再把 status为1 的 songPos存入buffer里,buffer就有两个数据了,(此时还不能比较,如果手机 哔哩哔哩 App打开播放视频,在300ms内会上传两帧错误数据 songPos 0 songLen 0 status 1),这时候开启300ms计时器,等到 buffer 里面数据满 5个,一般认为可以比较了;如果没有够5个,则再计时,到时判断buffer数据是否满5个,如果满了,则拿出最后两个比较,如果不一致,是上升的,则认为蓝牙音乐是启动了,如果是一致的,则认为播放的是即时消息。如果没有在蓝牙音乐源,则申请蓝牙音乐短焦点。
Status 1->2意味着播放结束,根据上一次判定的播放(蓝牙音乐或即时消息),
如果是播放蓝牙音乐则不申请释放短焦点
如果是播放蓝牙音乐则不申请释放短焦点
如果是即时消息,根据 2->1 的源是Radio,则申请蓝牙短焦点,1->2 再释放蓝牙短焦点。
如果是即时消息,释放蓝牙焦点
需要注意的是,如果在Radio源,播放即时消息过程中,手机播放音乐,这个过程会认为是即时消息的生命周期延续,再暂停,会走到释放蓝牙短焦点,回归到Radio源;这种解决方案是,在判定是播放即时消息后,也要100ms定时去检测 buffer里的数据是否有自增,一直到 Status 1->2,如果有增加,则判定蓝牙音乐播放了,这时候认为不再播放即时消息,而是播放蓝牙音乐。