当前位置: 首页 > ops >正文

蓝牙HFP协议概述

HFP(Hands-Free Profile),蓝牙电话协议,可以让蓝牙设备通过协议定义好的 AT command 控制电话,如接听、挂断、拒接、语音拨号等。每个功能都有特定的 AT command 和 response.

HFP 底层是 RFCOMM 协议,并且具有双角色(AG 和 HF),Audio Gateway (AG)就是手机,Hands-Free unit (HF)就是蓝牙耳机

HF连接建立
需要现有用于HF的RFCOMM通道,而且还要进行一些AT命令交互,这些命令交互成功之后,才叫HFP SLC(Service Level Connection)建立

  1. 充当 HF 角色首先要发送 AT+BRSF=<HF supported features>,
    AG 会回复+BRSF=<AG supported features>
    BRSF (Bluetooth Retrieve Supported Features),此命令就是用于 HF 和 AG
    互相告知对方支持的特性,彼此记录下来对方支持的 feature,这样要使用某一
    个功能,双方都知道彼此是否支持,HF&AG 的 support feature 都是一个 32bit的数, 1-11位代表具体功能是否支持,12-32保留

  2. 如果 HF 和 AG 都支持 BRSF 中的 Codec negotiation,那么 HF 发送:
    AT+BAC=<HF available codecs>
    整个 BAC 的概念是可用的编码(Bluetooth Available Codecs),这个命令是 HF 告知 AG,自己支持的 codec,CVSD 就是 NBS(窄带通话,8KHz)的编解码方式,mSBC 就是 WBS(宽带电话,16KHz)的编解码方式,CVSD必须支持,msbc可选支持

  3. 发送 AT+CIND=?问询支持的 indicators
    (包括 service/call/callsetup/callheld/signal/roam/battchg)的 index
    AT+CIND=?是问询 AG 有多少 indicators,并且自己解析每个 indicators 的 index
    发送 AT+CIND?问询各个 indicators 的 status∂
    发送 AT+CMER enable 各个 indicators,发送这个后,如果某一个 indicator
    有变化,那么 AG 就可以发送+CIEV 来告知
    AT+CMER 是 Standard event reporting activation/deactivation AT command.
    说白了就是使能/失能 indicator,一共有两种格式
    AT+CMER=3,0,0,1 activates “indicator events reporting”.
    AT+CMER=3,0,0,0 deactivates “indicator events reporting”.
    使能之后,AG 可以发送+CIEV 命令来汇报各个 indicator 的变化
    我们前面也提到到+CIEV,终于说到了,我们来看下+CIEV AT command
    +CIEV:Standard “indicator events reporting” unsolicited result code.
    格式为:+CIEV: ,,举例来说(此部分要根据 AT+CIND=?问询到的
    index 来解析,每个 AG 可能 index 不同,所以代码中有解析 index 的动作,我
    这个 index 是根据 2.1.3 小节的 index 来讲解)
    如果后续 AG 发送过来 +CIEV:1,x 那么就是 service 有变化,值为 x,
    如果 AG 发送过来+CIEV:5,x 那么就是 signal 有变化,值为 x
    以上三个发送完毕后,如果 HF&AG 都支持三方通话,那么发送 AT+CHLD=?
    此部分是 HF 问询 AG 三方通话的支持的特性都有哪些

  4. 如果 HF & AG 都支持 HF Indicators 的 feature,那么 HF 发送 AT+BIND=来告知 AG 支持那些 indicator,HFP 的 indicator
    一共有两个,Enhanced Safety (0,1), Battery Level (0-100)
    发送 AT+BIND=?问询 AG 支持哪些 indicator
    发送 AT+BIND?问询 AG 哪些 indicator 是 enable 的
    发送 AT+BIEV 来使能某一个 indicator

断开HFP的链接就是断开rfcomm上hfp的通道

AT+CMER 是全局 Active/deactive ,AT+BIA,那这个命令的作用
就是 active/deactive 某一个 indicator,整个 AT+BIA 的命令如下:
举例:假设有 7 个 indicator,index 是根据 AT+CIND=?得到,使能全局是
AT+BIA=1,1,1,1,1,1,1
失能全部 AT+BIA=0,0,0,0,0,0,0
如果要失能第 3 个,可以写成这样 AT+BIA=1,1,0,1,1,1,1
也可以写成这样 AT+BIA=1,1,0,后续参数自动忽略,采用默认

Audio Connection handling
Audio connection handing 分为 3 个部分介绍:
Audio Connection set up:Audio 的建立,也就是 SCO 的建立
Audio Connection release:Audio 的释放,也就是 SCO 的释放
Codec Connection set up:Codec 的建立,也就是协商 NBS/WBS 的过程

AG端发起连接时
HF 端的 btsnoop 流程是:
1) 收到 controller 发送的 connect request(type 是 sco)的 event
2) HF host 发送 accept sco connect request 的 command 给 controller
3) 收到 controller 发送 sco connection complete 的 event 给 host

HF端发起连接时
先发送AT+BCC命令,收到OK回复,然后AG端就会发起连接

Codec connection 的建立也很简单,在 SLC 建立得而时候如果发送过 AT+BAC,
那么 AG 会发送+BCS 选择 codec id,HF 回复 AT+BCS 回复相同的 codec id,然后
AG 回复 OK.个人理解,这个所谓的codec connection,其实用的还是SLC链路,就是在上面发特定的AT命令的过程而已;不过话又说回来,SLC其实也是发一堆AT命令的过程

Accept an incoming voice call
支持 in band ring 的 AG 在 incoming call 的时候,会先建立 audio connection(SCO),然后在 RING AT command 之后传过来声音,也就是手机铃声,直到被接听或者挂断,或者其他原因中断incoming call 为止,而 no in band ring 是在 call active 的时候才会建立 SCO,所以此时候 HF 要在 incoming call 的时候自己做一个铃声。

在这里插入图片描述
通过上图可以看出,在+CIEV callsetup=incoming 的后面就建立了(E)SCO 的连线,然后后面会有 AG 给 HF 的 RING command 以及可选的 CLIP 命令,直到 HF 发送 ATA 的 AT command 接听,call 状态进去 active

在这里插入图片描述
下面我们就来看下以上 in band ring 和 no in band ring 的差别:
支持 In band ring 的 AG 首先会建立 SCO,然后每次发送 RING command 给 HF 后,
都会发送 ring tone(铃声)给 HF,而 no in band ring AG 只会间隔发送 RING
command 给 HF,等到接听后才会建立 SCO.
还记得我们播打电话的“嘟“的声音吗?对于 Remote
(这是并不是指 AG,是指给 AG 打电话的人)嘟的响一声,那么 HF 就会响应的
收到一个 RING 的指令

如果是在AG端接听或者挂断的话,AG端只会通过+CIEV更新callsetup和call

HF 通过 ATA来接听电话,AT+CHUP 来拒绝来电,ATD来呼出电话,比如ATD10086
ATD>nnn…;就是拨打特定键盘存储的号码,比如我们设置的 1 为 10086,那么我们发送 ATD>1;就会自动拨打 10086

AT+BLDN拨打最后一次号码的功能,也就是末号重播功能

三方通话

http://www.xdnf.cn/news/6918.html

相关文章:

  • 开源项目实战学习之YOLO11:12.1 ultralytics-models-sam-blocks.py源码
  • 【Spring】Spring的请求处理
  • Spring-boot初次使用
  • 2.单链表两数相加(java)
  • 记录算法笔记(2025.5.17)验证二叉搜索树
  • 题单:表达式求值1
  • LVGL- Calendar 日历控件
  • [YOLO模型](4)YOLO V3的介绍
  • 基于STM32_HAL库的SPI通信并驱动W25Q64存储模块
  • RK3588 MNN CPU/Vulkan/OpenCL ResNet50推理测试
  • FreeRTOS的学习记录(任务创建,任务挂起)
  • 【数据结构】_二叉树
  • MyBatis 核心组件源码分析
  • JS逆向-某易云音乐下载器
  • 安卓 Audio Stream 类型
  • 【找工作系列①】【大四毕业】【复习】巩固JavaScript,了解ES6。
  • 复旦微FMQL调试笔记:PS网口
  • 大模型学习:Deepseek+dify零成本部署本地运行实用教程(超级详细!建议收藏)
  • 【LUT技术专题】针对降噪优化的通道感知轻量级LUT算法:DnLUT
  • C/C++实践(十)C语言冒泡排序深度解析:发展历史、技术方法与应用场景
  • cadence安装license manager无法开启,显示并行配置不正确
  • 20250517让NanoPi NEO core开发板在Ubuntu core16.04.2下支持TF卡的热插拔
  • Linux中的域名解析服务器
  • Linux下Nginx源码安装步骤详解
  • 告别 pip:使用 uv 加速你的 Python 包管理
  • Android Studio报错Cannot parse result path string:
  • 2023年全国青少年信息素养大赛-图形化编程复赛真题—打气球
  • 网络编程中的直接内存与零拷贝
  • JDBC 的编写步骤及原理详解
  • 素数筛(欧拉筛算法)