耳机双链接A、B手机,A有业务的情况下,B手机播放音乐需要外放 -- 基于中科蓝汛897X

最近客户提出一个新需求,耳机双链接A、B手机,A手机有业务的情况下,B手机播放音乐,音乐需要外放,基于实现方式,至少有三种方法,且可以相互组合实现,分别为:

方法一、基于手机特性来实现:

耳机出现业务变化的时候,耳机主动给所有的连接设备发送一个状态变化的消息,并且带上业务类型(音乐 / 通话)和手机信息,手机端在收到之后,判断是否为自身设备占用耳机出声通道,如果不是自身设备占用出声通道,那下次播放音乐,直接设置为外放,此方式依赖手机APP端实现将出声通道设置为外放。

方法二、基于蓝牙协议栈来实现:

耳机端判断自己当前的蓝牙状态,如果自己当前处于业务状态,那下一次收到第二台手机的AVDTP的起播信号之后,直接回复reject,并断开AVDTP的连接,后续恢复到空闲状态的时候,耳机需要向disconnect 的AVDTP设备,主动发起discover消息,建立连接,此方法效果依赖手机蓝牙的协议栈处理,不能保证一定能够外放,有些手机的AVDTP断开之后,并不会切换到外放。

方法三、基于断开A2DP的方式来实现

方法三有别于方法二,AVDTP属于A2DP的细分协议,单独断开AVDTP,手机端可能不会外放,但是断开全部A2DP的连接,手机在起播的时候,无法选择蓝牙A2DP作为出声通道,只能外放。具体的逻辑处理为:耳机有业务的时候,判断哪一台设备为活跃设备,然后将非活跃设备的A2DP断开,后续蓝牙处于空闲的时候,回连所有设备的A2DP。

理论说起来比较简单,但是实际处理的时候,会有一些问题:例如当前A手机在播放音乐,B手机来电并接通,出现业务抢占,活跃设备变成了B手机,此时,A手机作为非活跃设备,需要将出声通道改为外放,如果后续B手机挂断电话之后,在播放音乐,那需要保持B手机作为活跃设备,如果B手机没有播放音乐,需要设置A手机播放音乐在耳机端;蓝牙协议栈是不允许同时处理连接协议和断链协议等。

下面是基于方法三的具体实现步骤:

第一步: 写接口,用于获取活跃设备、指定地址的A2DP是否连接,以及连接/断开指定地址的A2DP

c 复制代码
void btstack_get_active_addr(uint8_t *bd_addr); // 此接口用于获取当前活跃设备的地址
bool a2dp_is_connected_by_addr(uint8_t *addr); // 此接口用于判断指定地址的A2DP是否处于连接状态
void a2dp_disconnect_by_addr(uint8_t *addr); // 此接口用于断开指定地址的A2DP
void a2dp_reconnect_by_addr(uint8_t *addr); // 此接口用于连接指定地址的A2DP

相关接口的具体实现如下:

第二步: 有了相关接口之后,就是UI层的实现了,代码如下:

c 复制代码
void a2dp_check_disconnect_or_reconnect(void)
{
	if ((bt_get_connected_num() <= 1) || bt_tws_is_slave()) {
		return;
	}
	if (f_bt.disp_status > BT_STA_CONNECTED) {
		uint8_t active_device[6];
		btstack_get_active_addr(active_device);
		// print_r(link_info_cb.info[0].addr, 6);
		// print_r(link_info_cb.info[1].addr, 6);
		// print_r(active_device, 6);
		// printf("check disconnect A2DP %d - %d\n", a2dp_is_connected_by_addr(link_info_cb.info[0].addr), a2dp_is_connected_by_addr(link_info_cb.info[1].addr));
		if ((memcmp(link_info_cb.info[0].addr, active_device, 6) == 0)
				&& a2dp_is_connected_by_addr(link_info_cb.info[1].addr)) { // 如果当前活跃设备是0号设备,并且1号设备的A2DP还处于连接,那就断开1号设备的A2DP
			a2dp_disconnect_by_addr(link_info_cb.info[1].addr);
		} else if ((memcmp(link_info_cb.info[1].addr, active_device, 6) == 0)
				&& (a2dp_is_connected_by_addr(link_info_cb.info[0].addr))) { // 如果当前活跃设备是1号设备,并且0号设备的A2DP还处于连接,那就断开0号设备的A2DP
			a2dp_disconnect_by_addr(link_info_cb.info[0].addr);
		} else if ((memcmp(link_info_cb.info[0].addr, active_device, 6) == 0)
				&& (!a2dp_is_connected_by_addr(link_info_cb.info[0].addr))) { // 如果当前活跃设备是0号设备,并且0号设备的A2DP没有连接,那就重连0号设备的A2DP
			a2dp_reconnect_by_addr(link_info_cb.info[0].addr);
		} else if ((memcmp(link_info_cb.info[1].addr, active_device, 6) == 0)
				&& (!a2dp_is_connected_by_addr(link_info_cb.info[1].addr))) { // 如果当前活跃设备是1号设备,并且1号设备的A2DP没有连接,那就重连1号设备的A2DP
			a2dp_reconnect_by_addr(link_info_cb.info[1].addr);
		}
	} else if (f_bt.disp_status == BT_STA_CONNECTED) {
		// printf("check reconnect A2DP %d - %d\n", a2dp_is_connected_by_addr(link_info_cb.info[0].addr), a2dp_is_connected_by_addr(link_info_cb.info[1].addr));
		if (!a2dp_is_connected_by_addr(link_info_cb.info[0].addr)) { // 如果0号设备的A2DP没有连接,那就连接0号设备的A2DP
			a2dp_reconnect_by_addr(link_info_cb.info[0].addr);
		} else if (!a2dp_is_connected_by_addr(link_info_cb.info[1].addr)) { // 如果1号设备的A2DP没有连接,那就连接1号设备的A2DP
			a2dp_reconnect_by_addr(link_info_cb.info[1].addr);
		}
	}
}

上述函数,需要放在保存手机连接地址的目录下,link_info_cb为保存连接设备的信息。

第三步,将第二步的函数进行循环检查,每2S检查一次:

c 复制代码
// 这里检查的速度不能太快,太快在极端的情况下,会导致一直连接/断链设备的A2DP,可能会导致蓝牙连接不稳定等问题
    static u32 bt_time_check = 0;
    if (tick_check_expire(bt_time_check, 2000)) { // 每2S检查一次
        bt_time_check = tick_get();
        a2dp_check_disconnect_or_reconnect();
    }

整体逻辑运行讲解:

在0号设备有业务的时候,2S循环检查发现当前处于双链接,并且处于活跃状态,先断开1号设备的A2DP,后续1号设备播放音乐为外放;此时,1号设备打电话,出现业务抢占,那么,2S循环检查发现1号设备为活跃设备,0号设备的A2DP还处于连接,会先断开0号设备的A2DP,第二次循环时间到,发现1号设备的A2DP没有连接,会主动回连1号设备的A2DP;后续挂断电话,如果1号设备音乐播放,那耳机会出声1号设备的音乐;如果1号设备没有播放音乐,那蓝牙就会处于空闲状态,耳机会主动回连0号设备的A2DP,那耳机会出声0号设备。

注:A2DP相关的接口在蓝牙库中实现,相关图示仅用于交流学习,如有侵权,联系删除。

相关推荐
点灯小铭2 小时前
基于单片机的火焰与温度联动检测及声光灭火控制系统
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
不做无法实现的梦~2 小时前
STM32 上部署 MAVLink 协议教程
stm32·单片机·嵌入式硬件
进击的小头2 小时前
第5篇:嵌入式处理器内核全解析:TI DSP各个系列核心差异与选型指南
单片机·嵌入式硬件
HIZYUAN2 小时前
AG32 MCU可以替代STM32+CPLD吗 (二)
stm32·单片机·嵌入式硬件·fpga开发·agm ag32·国产mcu+fpga·低成本soc
古译汉书11 小时前
【IoT死磕系列】Day 9:架构一台“自动驾驶物流车”,看8种协议如何协同作战
网络·arm开发·单片机·物联网·tcp/ip·架构·自动驾驶
FreakStudio13 小时前
小作坊 GitHub 协作闭环:fork-sync-dev-pr-merge 实战指南
python·单片机·嵌入式·面向对象·电子diy
cmpxr_18 小时前
【单片机】位域非原子写的风险
单片机·嵌入式硬件
恒森宇电子有限公司19 小时前
南麟LN1151 超低静态功耗 CMOS 低压差线性稳压器 多种封装形式
单片机·嵌入式硬件
九鼎创展科技21 小时前
国产高性能 MCU 开发板新标杆:PICO2 主板深度解析
单片机·嵌入式硬件