蓝牙开发那些事(9)——结合代码看a2dp协议
上一章讲了一下avdtp的连接过程,这一章我们看一下btstack的实例。
因为a2dp是一个音频传输的框架协议,具体的使用已经牵涉到应用层了,比如说我们的设备是个音箱设备还是个音源设备,我们目前是个音箱设备,所以可以看一下a2dp_sink_deom.c。
其中首先调用a2dp_and_avrcp_setup函数进行了一系列的初始化,从这个函数名就知道,初始化的内容包括了a2dp协议和avrcp协议,a2dp之前我们已经讲了其基础协议avdtp,avrcp的话呢是基于avctp协议的, AVCTP协议描述了蓝牙设备间Audio/Video的控制信号交换的格式和机制,它是一个总体的协议,具体的控制信息由其指定的协议(如AVRCP)实现,AVCTP本身只指定控制command和response的总体的格式,比如说我们在音箱端怎么暂停、播放、停止、上一首、下一首操作,就得依赖avrcp,再比如说音量同步功能,也是依赖avrcp。
1 l2cap_init();2 // Initialize AVDTP Sink3 a2dp_sink_init();4 a2dp_sink_register_packet_handler(&a2dp_sink_packet_handler);5 a2dp_sink_register_media_handler(&handle_l2cap_media_data_packet);67 avdtp_stream_endpoint_t * local_stream_endpoint = a2dp_sink_create_stream_endpoint(AVDTP_AUDIO,8 AVDTP_CODEC_SBC, media_sbc_codec_capabilities, sizeof(media_sbc_codec_capabilities),9 media_sbc_codec_configuration, sizeof(media_sbc_codec_configuration));10 if (!local_stream_endpoint){11 printf("A2DP Sink: not enough memory to create local stream endpoint\n");12 return 1;13 }14 a2dp_local_seid = avdtp_local_seid(local_stream_endpoint);1516 // Initialize AVRCP service.17 avrcp_init();18 avrcp_register_packet_handler(&avrcp_packet_handler);……
基本上都是一些初始化的操作,第一行初始化l2cap, 第二行初始化a2dp sink, 其中给l2cap的数据注册了回调函数
l2cap_register_service(&avdtp_packet_handler, BLUETOOTH_PSM_AVDTP, 0xffff, gap_get_security_level());
我们之前说过,l2cap建立逻辑信道,区分上层协议的依据就是PSM,所以这里的PSM一定要填BLUETOOTH_PSM_AVDTP。
之后凡是avdtp相关的l2cap数据都会进入这个avdtp_packet_handler去处理。
1 void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){2 bd_addr_t event_addr;3 uint16_t psm;4 uint16_t local_cid;5 uint8_t status;6 uint16_t l2cap_mtu;78 bool accept_streaming_connection;9 bool outoing_signaling_active;10 bool decline_connection;1112 avdtp_stream_endpoint_t * stream_endpoint = NULL;13 avdtp_connection_t * connection = NULL;1415 switch (packet_type) {16 case L2CAP_DATA_PACKET:17 connection = avdtp_get_connection_for_l2cap_signaling_cid(channel);18 if (connection){19 handle_l2cap_data_packet_for_signaling_connection(connection, packet, size);20 break;21 }22 23 stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel);24 if (!stream_endpoint){25 if (!connection) break;26 handle_l2cap_data_packet_for_signaling_connection(connection, packet, size);27 break;28 }29 30 if (stream_endpoint->connection){31 if (channel == stream_endpoint->connection->l2cap_signaling_cid){32 handle_l2cap_data_packet_for_signaling_connection(stream_endpoint->connection, packet, size);33 break;34 }35 }3637 if (channel == stream_endpoint->l2cap_media_cid){38 btstack_assert(avdtp_sink_handle_media_data);39 (*avdtp_sink_handle_media_data)(avdtp_local_seid(stream_endpoint), packet, size);40 break;41 }4243 if (channel == stream_endpoint->l2cap_reporting_cid){44 log_info("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED");45 } else if (channel == stream_endpoint->l2cap_recovery_cid){46 log_info("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED");47 } else {48 log_error("avdtp packet handler L2CAP_DATA_PACKET: local cid 0x%02x not found", channel);49 }50 break;51 52 case HCI_EVENT_PACKET:53 switch (hci_event_packet_get_type(packet)) {5455 case L2CAP_EVENT_INCOMING_CONNECTION:56 l2cap_event_incoming_connection_get_address(packet, event_addr);57 local_cid = l2cap_event_incoming_connection_get_local_cid(packet);58 59 outoing_signaling_active = false;60 accept_streaming_connection = false;61 62 connection = avdtp_get_connection_for_bd_addr(event_addr);……
有了上一章的讲述,这里面对各种数据包的分类就好理解了,handle_l2cap_data_packet_for_signaling_connection是处理signal channel的数据,第39行的(*avdtp_sink_handle_media_data)(avdtp_local_seid(stream_endpoint), packet, size)是处理stream channel的数据,第52行的HCI_EVENT_PACKET其实并不是真正的hci event,而是btstack虚拟出来的一类软件内部的hci event,看第55行就知道,这类hci event根据事件type去执行不同操作,l2cap的signal channel去建立逻辑信道的连接的时候,也是有一套状态机的,其中有不同状态,这个L2CAP_EVENT_INCOMING_CONNECTION就是准备建立连接的状态。
我们再回到a2dp_and_avrcp_setup,
第4行a2dp_sink_register_packet_handler(&a2dp_sink_packet_handler);这里面除了有avdtp协议内部对于a2dp各子状态的处理之外,还注册了a2dp_sink_packet_handler这个应用层的回调函数,主要处理在a2dp连接各子状态的时候,对codec层需要做的一些处理,比如说sbc编码器的初始化,音频的具体处理,这些都依赖于上层的实现。
第5行a2dp_sink_register_media_handler(&handle_l2cap_media_data_packet);
这个handle_l2cap_media_data_packet是应用层对于stream包的处理函数,之前avdtp_packet_handler函数,在收到l2cap层的avdtp包的时候,会分析是signal channel的包还是stream channel的包,假如是stream channel的包的话,看一下39行,就是在执行这里所注册的回调函数了。一般来说,这里面应该做的工作是执行解码器解码的工作,解码完了打算干吗?送给播放器播放?具体的还是取决于应用层。
第7行
avdtp_stream_endpoint_t * local_stream_endpoint = a2dp_sink_create_stream_endpoint(AVDTP_AUDIO,AVDTP_CODEC_SBC, media_sbc_codec_capabilities, sizeof(media_sbc_codec_capabilities),media_sbc_codec_configuration, sizeof(media_sbc_codec_configuration));
创建一个sep,也可以看出a2dp中sep的确是一个虚拟的概念了,软件中想创建就可以创建的。
再深入看一下代码,看看给这个sep分配seid的时候:
static uint16_t avdtp_get_next_local_seid(void){if (stream_endpoints_id_counter == 0xffff) {stream_endpoints_id_counter = 1;} else {stream_endpoints_id_counter++;}return stream_endpoints_id_counter;}
可以看到seid无非是做了一个加1 的动态分配的动作。
第14行
a2dp_local_seid = avdtp_local_seid(local_stream_endpoint);
给a2dp_local_seid这个重要变量赋值,因为avdtp的连接是基于seid的,所以以后连接过程都是需要频繁用到的,用一个全局变量保存并不为过。
再接下来avrcp的一系列的初始化。
整个a2dp_and_avrcp_setup函数执行完成后,上层的服务就设置好了,a2dp_sink_demo.c支持从上位机输入指令执行相应程序,比如说,输入‘b’,就会调用a2dp_sink_establish_stream执行a2dp的连接操作,接下来,输入b试试看,让状态机跑起来吧。
蓝牙开发那些事(9)——结合代码看a2dp协议相关推荐
- 【Android】蓝牙开发——BLE(低功耗蓝牙)(附完整Demo)
目录 目录 前言 一.相关概念介绍 二.实战开发 三.项目演示 四.Demo案例源码地址 五.更新记录 1.2020/12/29 :修改 setupService()中错误 2.2021/05/14 ...
- 泰凌微ble mesh蓝牙模组天猫精灵学习之旅④如何在Android开发低功耗蓝牙ble控制 TB-02 模块,代码工程全部开源!(附带Demo)
本<泰凌微ble mesh蓝牙模组天猫精灵学习之旅>系列博客学习由半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1.小白也痴迷,如 ...
- java request 处理过程_小猿圈Java开发之从代码看spring mvc请求处理过程
原标题:小猿圈Java开发之从代码看spring mvc请求处理过程 Java作为编程界的常青树,有自己生存的独到之处,小猿圈java讲师今天就分享一个关于从代码看spring mvc请求处理过程,通 ...
- 蓝牙配对模式 java_【Android】蓝牙开发—— 经典蓝牙配对介绍(Java代码实现演示)附Demo源码...
目录 前言 一.连接&配对方法介绍 二.演示:第一次连接蓝牙设备 & 直接与蓝牙设备建立配对 三.总结 四.补充 五.Demo案例源码地址: 前言 前面两篇文章[Android]蓝 ...
- 【Android】蓝牙开发—— 经典蓝牙配对介绍(Java代码实现演示)附Demo源码
目录 前言 一.连接&配对方法介绍 二.演示:第一次连接蓝牙设备 & 直接与蓝牙设备建立配对 三.总结 四.补充 五.Demo案例源码地址: 前言 前面两篇文章[Android]蓝 ...
- CSR蓝牙开发资源大全(软件代码资料)
CSR蓝牙开发资源大全 BlueSuite 2.4.8 开发生产测试配置工具 http://pan.baidu.com/share/link?shareid=299289621&uk=339 ...
- android蓝牙开发代码,Android蓝牙开发(示例代码)
Android蓝牙开发 近期做蓝牙小车,须要Android端来控制小车的运动.以此文记录开发过程. 使用HC-06无线蓝牙串口透传模块.对于其它的蓝牙设备本文相同适用. 蓝牙开发的流程: 获取本地蓝牙 ...
- android Ble4.0蓝牙开发之搜索慢、startLeScan()过时,6.0以上不需要定位权限也能快速搜索到蓝牙设备
项目中需要用到android Ble蓝牙4.0开发技术,于是开启了蓝牙填坑之旅,说实话,蓝牙开发坑真多,跳出一个又进入下一个,每次遇到 问题,就觉得不可能解决了,还好在自己的摸索中,都一一的化解了,以 ...
- 安卓基于BLE的蓝牙开发入门
BLE蓝牙开发简单入门 BLE背景介绍 引言 BLE简介 Gatt协议以及必备知识 蓝牙开发涉及的API介绍 BLE实战准备 真机调试 权限准备 写两个简单的页面 扫描设备主界面 扫描设备信息界面 实 ...
最新文章
- jsp页面定义的map
- android textview 白色,android – AutoCompleteTextview默认情况下,颜色设置为白色
- 面对SDN/NFV部署挑战 网络厂商能做什么?
- 浅谈社区电子商务的发展及其技术应用
- 云小课|云小课带你快速掌握云数据迁移CDM
- CSS基本选择器之类选择器多类名(CSS、HTML)
- gift to me by myself on 2012's new year
- 硬盘格式化数据恢复的软件推荐
- 编译原理复习总结及思维导图
- 15个经典面试问题及回答思路,挥泪整理面经
- java汤姆猫安装_汤姆猫跑酷安装
- php查找判断二维数组中是否含有某个值
- 用水流的概念来玩硬件(三)----LDO与DCDC电源电路
- 视频如何做成gif动图?
- 论文阅读——Automatic Testing and Improvement of Machine Translation
- 西澳大利亚大学计算机专业,西澳大利亚大学世界排名多少位(西澳大利亚大学热门专业介绍)...
- 修改远程桌面3389端口批处理
- OSI 七层模型详解
- 全球与中国地下用钢纤维市场深度研究分析报告
- 网络云存储技术Windows server 2012 (项目十三 NFS共享的配置与管理)