音视频控制传输协议(AVCTP)

📅 2026/7/3 6:13:15 👁️ 阅读次数 📝 编程学习
音视频控制传输协议(AVCTP)

音视频控制传输协议(AVCTP)

本笔记为作者在学习蓝牙Host协议栈的一些心得体会,如有不对的地方,请包涵与谅解!

​ ————by wsoz

音视频控制传输协议(AVCTP)

AVCTP 是蓝牙音视频控制里的“传输/封装层协议”,负责规定控制commandresponse的总体格式与交换机制;具体“控制内容”不是它自己定义的,而是由它承载的上层协议实现,例如 AVRCP。

协议特点

  • AVCTP采用面向连接的点对点的L2CAP通道
  • AVCTP支持连接两端同时具备controller和target功能(双向控制
  • 两个设备之间可以存在多个AVCTP连接,每个AVCTP连接都对应一条独立的L2CAP通道;在同一条ACL链路上,同一个PSM只允许存在一个AVCTP连接
  • 每个AVCTP packet都必须封装在单个L2CAP packet中传输
  • Transaction label的作用域仅限于各自的L2CAP channel,不同L2CAP channel上即使transaction label相同,也分别属于不同的message,不能跨channel关联

总结:AVCTP 是一个建立在面向连接的 L2CAP 通道之上的、支持双端对称控制的音视频控制传输协议,并且以单通道为边界来承载和区分各自独立的控制消息

架构如下:


AVCTP的PSM

L2CAP中,PSM(Protocol/Service Multiplexer)可以理解为上层服务的“入口号”,建立L2CAP channel时需要先知道对方监听的是哪个PSM

对于AVCTP来说,常见会涉及两个PSM

PSM名称用途
0x0017AVCTP控制通道,用于传输普通的音视频控制命令/响应
0x001BAVCTP_Browsing浏览通道,用于传输媒体浏览相关命令

这两个PSM的分工可以这样理解:

  • 0x0017是基础的控制入口,常见的播放、暂停、上一曲、下一曲这类遥控控制,通常都走这条通道
  • 0x001B是扩展的浏览入口,主要给AVRCP Browsing使用,比如浏览媒体播放器、文件夹、歌曲列表等
  • Browsing channel不是所有场景都必须建立,只有双方都支持浏览功能时才需要
  • 一般要先建立0x0017对应的控制通道,再根据功能需要决定是否建立0x001B对应的浏览通道

也就是说,AVCTP之所以会看到两个PSM,不是因为一个连接内部必须同时混用两个入口,而是因为它把普通控制媒体浏览拆成了两类独立业务通道。

注意

  • 这里说的0x00170x001BL2CAP 的 PSM 值
  • 其中0x0017同时也出现在协议标识里表示AVCTP
  • 0x001B在这里表示的是AVCTP_Browsing这个PSM,不要直接和别的编号空间里的UUID含义混为一谈

AVCTP封包格式

AVCTP message在传输时会被封装成一个或多个AVCTP packet。每个AVCTP packet又必须完整放进一个L2CAP packet中,因此AVCTP自己不带长度字段,而是依赖L2CAP的长度来界定一个包的边界。

从封包角度看,AVCTP主要有两种情况:

  1. 未分包消息:整个message可以直接放进一个L2CAP packet
  2. 分包消息:整个message太大,必须拆成多个AVCTP packet

未分包的AVCTP格式

当一条AVCTP message的长度没有超过当前L2CAP MTU时,就可以直接按单包格式发送:

Octet 0 : | Transaction Label(4bit) | Packet Type(2bit=00) | C/R(1bit) | IPID(1bit) | Octet 1 : | PID[15:8] | Octet 2 : | PID[7:0] | Octet 3~ : AVCTP Message Information

也就是说,未分包格式的固定头部是 3 字节

  • 第1字节:Transaction Label + Packet Type + C/R + IPID
  • 第2~3字节:PID
  • 后面才是真正的上层控制数据
分包的AVCTP格式

当一条AVCTP message太长,无法一次装进单个L2CAP packet时,AVCTP会把它拆成多个AVCTP packet。这时Packet Type不再是00,而会分为三种:

  • 01Start Packet
  • 10Continue Packet
  • 11End Packet
Start Packet
Octet 0 : | Transaction Label(4bit) | Packet Type(2bit=01) | C/R(1bit) | IPID(1bit) | Octet 1 : | Number of AVCTP Packets | Octet 2 : | PID[15:8] | Octet 3 : | PID[7:0] | Octet 4~ : AVCTP Message Information 的第一段

Start Packet比单包格式多了一个Number of AVCTP Packets字段,用来告诉接收端:这条完整消息总共会分成几个AVCTP packet

Continue Packet
Octet 0 : | Transaction Label(4bit) | Packet Type(2bit=10) | C/R(1bit) | RFA(1bit) | Octet 1~ : AVCTP Message Information 的中间部分
End Packet
Octet 0 : | Transaction Label(4bit) | Packet Type(2bit=11) | C/R(1bit) | RFA(1bit) | Octet 1~ : AVCTP Message Information 的最后一段

可以看到:

  • Start Packet头部固定是4 字节
  • Continue PacketEnd Packet头部固定都只有1 字节
  • 分包场景下,PIDIPID只出现在Start Packet

字段的含义
字段含义
Transaction Label事务标签,占4bit,用来标识一条命令/响应事务;同一条被分包的消息中,各个分片都要带相同的标签
Packet Type包类型,占2bit,00=单包,01=起始包,10=中间包,11=结束包
C/RCommand/Response标志,占1bit,0表示命令,1表示响应
IPIDInvalid Profile Identifier标志,占1bit,仅在单包或起始包中有意义;在响应里置1表示收到的PID无效
RFAReserved For Future Additions,保留位,在Continue/End Packet中替代IPID,当前应置0
PIDProfile Identifier,2字节,表示当前这条消息属于哪个上层Profile
Number of AVCTP Packets仅出现在Start Packet中,表示这条完整消息一共包含多少个AVCTP packet
Message Information真正的上层命令/响应内容,具体格式由PID所指向的上层Profile定义,例如AVRCP

这里尤其要注意:AVCTP只定义了外层封装头,至于Message Information里面怎么编码,不是AVCTP自己规定的,而是交给对应的上层协议去定义。


如何对数据段进行分析

按下面顺序拆:

  1. 先看Packet Type,判断这是单包还是分包中的某一片
  2. 再看C/R,判断它是命令还是响应
  3. 再看Transaction Label,判断它属于哪一笔事务
  4. 再看PID,判断这条AVCTP承载的是哪个上层Profile
  5. 最后再去解析Message Information里的真正业务内容

注意:这里先说的是AVCTP通用封包格式,在AVRCP Browsing场景时,虽然底层仍然使用AVCTP相关通道,但浏览命令本身还有自己的PDU格式约束,并且浏览通道不使用AVCTP分包。


我的理解:AVCTP 这一层的主要作用,就是在 L2CAP 之上给上层控制协议提供一个统一的传输封装和交换机制,就是提供一个数据承载的框架