【AVRCP】规范精讲[35]:车机搜歌直接播放?AVRCP搜索与播放全流程拆解

在车载蓝牙、TWS耳机这类产品里,用户经常会遇到这样的场景:在车机上输入歌名搜索手机里的音乐,选好歌曲后直接点播放,就能跳过手机App的界面,直接在车机上控制播放。这个看起来简单的"搜歌+播放"功能,背后是AVRCP里一套完整的搜索与播放信令流程。本文就把这套流程从原理、交互到避坑要点一次性讲透,解决搜歌无结果、播放不响应、状态不更新等常见问题。


目录

一、什么是AVRCP搜索与播放?

二、核心交互流程

三、关键协议逻辑与原文解析

四、核心知识点与避坑指南

五、测验


一、什么是AVRCP搜索与播放?

直白说,就是控制端CT(比如车机)主动向目标端TG(比如手机)发送搜索请求,根据关键词查找媒体库中的歌曲,拿到搜索结果后,直接发送播放命令,让目标端的播放器播放指定歌曲。

和之前我们讲的切换播放器再播放不同,这个场景的核心是跨文件浏览的精准定位播放。用户不需要手动切换到目标App,也不需要在文件目录里一层层找歌,直接通过搜索就能定位并播放。

可以打个比方:就像你用智能电视的语音搜索,说"播放周杰伦的晴天",电视直接帮你找到对应视频并开始播放,整个过程不需要你手动翻找目录。

二、核心交互流程

我们结合时序图,一步步拆解CT和TG的每一步交互,搞懂每个动作背后的协议逻辑。

1. 初始状态: AVRCP 会话建立,浏览通道就绪

CT和TG已经建立AVRCP连接,控制通道和浏览通道都正常工作。这是搜索功能的基础,因为搜索和播放命令都需要通过AVRCP的浏览通道传输。

2. 第一步:CT浏览到目标路径,准备搜索

CT先浏览到目标播放器的媒体库路径,这一步是为了确保搜索的范围正确,比如指定在当前音乐App的歌曲库中搜索,而不是在其他目录里。

3. 第二步:CT发送搜索命令,请求查找歌曲

CT发送Search命令,携带用户输入的关键词(比如歌曲名、歌手名),请求TG在媒体库中查找匹配的歌曲。

伪代码示例:

bash 复制代码
// 伪代码:发送搜索请求
avrcp_pkt_t search_pkt;
char keyword[] = "晴天";
avrcp_build_search(&search_pkt, keyword, strlen(keyword));
avrcp_send_pkt(session, &search_pkt);

TG收到请求后,会在媒体库中进行匹配,生成一个搜索结果列表。

4. 第三步: TG 回复搜索结果,CT获取列表

TG回复SearchRsp,返回一个搜索结果列表的句柄,告诉CT匹配的歌曲都在这个列表里。

CT收到响应后,发送GetFolderItems命令,请求获取搜索结果列表里的具体歌曲信息,包括每首歌的UID、歌曲名、歌手、时长等。

TG回复GetFolderListingRsp,把完整的搜索结果列表返回给CT,车机上就可以显示搜索结果供用户选择。

5. 第四步:用户选择歌曲,CT发送播放命令

用户在车机上选择目标歌曲,CT发送PlayItem命令,携带歌曲的UID和搜索结果列表句柄,请求TG直接播放这首歌。

TG收到命令后,会定位到指定歌曲,启动播放器播放,并回复PlayItemRsp,告知CT播放成功。

6. 关键收尾: TG 完成未处理的通知事件

时序图里特别标注了TG需要完成所有未处理的Track Changed、Play Status等通知事件。这一步非常关键,它的作用是让CT能及时收到播放状态的变化,更新车机上的播放进度、歌曲信息和控制按钮状态。

三、关键协议逻辑与原文解析

整个流程里,有几个容易被忽略的关键点,直接影响用户体验和兼容性:

TG shall complete outstanding Track Changed, Play Status, and other relevant outstanding notifications.

这句话是协议给TG开发的硬性要求:当收到PlayItem命令后,TG必须主动完成之前未处理的所有播放相关通知事件,比如轨道变更、播放状态变化等。

很多开发同学在这里踩坑,只处理了播放命令本身,却没有同步处理通知事件,导致CT收不到播放状态变化的通知,车机上的进度条不更新、歌曲信息不刷新,用户以为播放失败了。

CT decides to play an item in the list.

这句话强调了CT的核心角色:用户的播放选择由CT决定,TG只需要响应播放命令,不需要额外的用户交互。这也是为什么车机可以直接控制播放,不需要手机端操作的原因。

四、核心知识点与避坑指南

1. 关键命令与事件梳理

|-----------------------------------------|---------------|---------|
| 命令/事件 | 作用 | 发送方 |
| Search(String) | 发送搜索请求,携带关键词 | CT |
| SearchRsp() | 返回搜索结果列表句柄 | TG |
| GetFolderItems(SearchResultList) | 获取搜索结果列表的具体内容 | CT |
| PlayItem(UID, SearchResultList) | 直接播放指定歌曲 | CT |
| Track Changed/Play Status Notifications | 同步播放状态变化 | TG |

2. 开发中最容易踩的3个坑

  • 坑1:CT没有先调用Search,直接GetFolderItems

很多CT实现会跳过Search命令,直接用固定的UID去调用PlayItem,结果发现歌曲ID在不同手机上不通用,播放失败。正确的做法是先通过Search获取结果列表,再用列表里的UID播放。

  • 坑2:TG收到PlayItem命令后,不完成未处理的通知事件

这是最常见的问题,会导致CT的播放状态一直停留在上一首歌,车机UI不刷新,用户体验极差。TG必须在播放新歌曲后,主动触发Track Changed和Play Status通知。

  • 坑3:搜索关键词编码不兼容

AVRCP的Search命令要求关键词使用UTF-8编码,如果编码错误,TG会返回无结果。很多开发同学直接用GBK或其他编码发送,导致搜歌失败。

3. 为什么这套流程的时序要求这么严格?

因为搜索和播放是跨文件浏览的操作,涉及到两次列表获取(搜索结果列表、歌曲详情列表)和一次直接播放。如果时序混乱,比如先调用PlayItem再获取列表,就会导致播放失败,或者CT无法确认用户选择的歌曲。

五、测验

:AVRCP搜索与播放流程中,CT必须先调用哪个命令才能获取搜索结果?(车载蓝牙开发面试真题)

答:

必须先调用Search命令,携带关键词发送给TG,获取搜索结果列表句柄后,再调用GetFolderItems获取具体的歌曲信息。

:TG收到PlayItem命令后,为什么要主动完成Track Changed等未处理通知?(蓝牙协议栈开发面试题)

答:

为了让CT能及时收到新歌曲的轨道变更和播放状态变化,更新控制端的UI显示和播放控制状态,避免出现状态不同步的问题。

**问:**AVRCP的Search命令对关键词的编码有什么要求?(嵌入式蓝牙开发面试题)

答:

必须使用UTF-8编码发送关键词,否则不同手机的媒体库可能无法匹配,导致搜歌无结果。