Android跟蓝牙耳机建立连接有两种方式

android 车载蓝牙音乐介绍 测试 阅读详情

Android 跟蓝牙耳机建立连接有两种方式。

1. Android 主动跟蓝牙耳机连BluetoothSettings 中和蓝牙耳机配对上之后, BluetoothHeadsetService 会收到BONDING_CREATED_ACTION,这个时候BluetoothHeadsetService 会主动去和蓝牙耳机建立RFCOMM 连接。
if (action.equals(BluetoothIntent.BONDING_CREATED_ACTION)) {
  if (mState == BluetoothHeadset.STATE_DISCONNECTED) {
  // Lets try and initiate an RFCOMM connection
   try {
    mBinder.connectHeadset(address, null);
   } catch (RemoteException e) {}
  }
}

RFCOMM 连接的真正实现是在ConnectionThread 中,它分两步,第一步先通过SDPClient 查询蓝牙设备时候支持Headset 和Handsfree profile。
// 1) SDP query
SDPClient client = SDPClient.getSDPClient(address);
if (DBG) log("Connecting to SDP server (" + address + ")...");
if (!client.connectSDPAsync()) {
  Log.e(TAG, "Failed to start SDP connection to " + address);
  mConnectingStatusHandler.obtainMessage(SDP_ERROR).sendToTarget();
  client.disconnectSDP();
  return;
}
if (isInterrupted()) {
  client.disconnectSDP();
  return;
}
if (!client.waitForSDPAsyncConnect(20000)) { // 20 secs
  if (DBG) log("Failed to make SDP connection to " + address);
  mConnectingStatusHandler.obtainMessage(SDP_ERROR).sendToTarget();
  client.disconnectSDP();
  return;
}
if (DBG) log("SDP server connected (" + address + ")");
int headsetChannel = client.isHeadset();
if (DBG) log("headset channel = " + headsetChannel);
int handsfreeChannel = client.isHandsfree();
if (DBG) log("handsfree channel = " + handsfreeChannel);
client.disconnectSDP();
第2步才是去真正建立RFCOMM 连接。
// 2) RFCOMM connect

mHeadset = new HeadsetBase(mBluetooth, address, channel);
if (isInterrupted()) {
  return;
}
int result = mHeadset.waitForAsyncConnect(20000, // 20 secs
mConnectedStatusHandler);
if (DBG) log("Headset RFCOMM connection attempt took " +(System.currentTimeMillis() - timestamp) + " ms");
if (isInterrupted()) {
  return;
}
if (result < 0) {
  Log.e(TAG, "mHeadset.waitForAsyncConnect() error: " + result);
  mConnectingStatusHandler.obtainMessage(RFCOMM_ERROR).sendToTarget();
  return;
} else if (result == 0) {
  Log.e(TAG, "mHeadset.waitForAsyncConnect() error: " + result +"(timeout)");
  mConnectingStatusHandler.obtainMessage(RFCOMM_ERROR).sendToTarget();
  return;
} else {
  if (DBG) log("mHeadset.waitForAsyncConnect() success");
  mConnectingStatusHandler.obtainMessage(RFCOMM_CONNECTED).sendToTarget();
}
当RFCOMM连接成功建立后,BluetoothHeadsetDevice 会收到RFCOMM_CONNECTED消息,它会调用BluetoothHandsfree 来建立SCO 连接,广播通知Headset状态变化的Intent
(PhoneApp 和BluetoothSettings 会接收这个Intent)。
case RFCOMM_CONNECTED:
// success
if (DBG) log("Rfcomm connected");
if (mConnectThread != null) {
  try {
   mConnectThread.join();
  } catch (InterruptedException e) {
   Log.w(TAG, "Connect attempt cancelled, ignoring
   RFCOMM_CONNECTED", e);
   return;
  }
  mConnectThread = null;
}
setState(BluetoothHeadset.STATE_CONNECTED,BluetoothHeadset.RESULT_SUCCESS);
mBtHandsfree.connectHeadset(mHeadset, mHeadsetType);
break;
BluetoothHandsfree 会先做一些初始化工作,比如根据是Headset 还是Handsfree 初始化不同的ATParser,并且启动一个接收线程从已建立的RFCOMM上接收蓝牙耳机过来的控制命令(也就是AT 命令),接着判断如果是在打电话过程中,才去建立SCO 连接来打通数据通道。
/* package */
void connectHeadset(HeadsetBase headset, int headsetType) {
  mHeadset = headset;
  mHeadsetType = headsetType;
  if (mHeadsetType == TYPE_HEADSET) {
   initializeHeadsetAtParser();
  } else {
   initializeHandsfreeAtParser();
  }
  headset.startEventThread();
  configAudioParameters();
  if (inDebug()) {
   startDebug();
  }
  if (isIncallAudio()) {
   audioOn();
  }
}
建立SCO 连接是通过SCOSocket 实现的
/** Request to establish SCO (audio) connection to bluetooth
* headset/handsfree, if one is connected. Does not block.
* Returns false if the user has requested audio off, or if there
* is some other immediate problem that will prevent BT audio.
*/
/* package */
synchronized boolean audioOn() {
  mOutgoingSco = createScoSocket();
  if (!mOutgoingSco.connect(mHeadset.getAddress())) {
   mOutgoingSco = null;
  }
  return true;
}
当SCO 连接成功建立后,BluetoothHandsfree 会收到SCO_CONNECTED 消息,它就会去调用AudioManager 的setBluetoothScoOn函数,从而通知音频系统有个蓝牙耳机可用了。
到此,Android 完成了和蓝牙耳机的全部连接。
case SCO_CONNECTED:
if (msg.arg1 == ScoSocket.STATE_CONNECTED && isHeadsetConnected()&&mConnectedSco == null) {
  if (DBG) log("Routing audio for outgoing SCO conection");
  mConnectedSco = (ScoSocket)msg.obj;
  mAudioManager.setBluetoothScoOn(true);
} else if (msg.arg1 == ScoSocket.STATE_CONNECTED) {
  if (DBG) log("Rejecting new connected outgoing SCO socket");
  ((ScoSocket)msg.obj).close();
  mOutgoingSco.close();
}
mOutgoingSco = null;
break;
2. 蓝牙耳机主动跟Android 连首先BluetoothAudioGateway 会在一个线程中收到来自蓝牙耳机的RFCOMM 连接,然后发送消息给BluetoothHeadsetService。
mConnectingHeadsetRfcommChannel = -1;
mConnectingHandsfreeRfcommChannel = -1;
if(waitForHandsfreeConnectNative(SELECT_WAIT_TIMEOUT) == false) {
  if (mTimeoutRemainingMs > 0) {
   try {
    Log.i(tag, "select thread timed out, but " +
    mTimeoutRemainingMs + "ms of
    waiting remain.");
    Thread.sleep(mTimeoutRemainingMs);
   } catch (InterruptedException e) {
    Log.i(tag, "select thread was interrupted (2),
    exiting");
    mInterrupted = true;
   }
  }
}

BluetoothHeadsetService 会根据当前的状态来处理消息,分3 种情况,第一是当前状态是非连接状态,会发送RFCOMM_CONNECTED 消息,后续处理请参见前面的分析。
case BluetoothHeadset.STATE_DISCONNECTED:
// headset connecting us, lets join
setState(BluetoothHeadset.STATE_CONNECTING);
mHeadsetAddress = info.mAddress;
mHeadset = new HeadsetBase(mBluetooth, mHeadsetAddress,info.mSocketFd,info.mRfcommChan,mConnectedStatusHandler);
mHeadsetType = type;
mConnectingStatusHandler.obtainMessage(RFCOMM_CONNECTED).sendToTarget();
break;
如果当前是正在连接状态, 则先停掉已经存在的ConnectThread,并直接调用BluetoothHandsfree 去建立SCO 连接。
case BluetoothHeadset.STATE_CONNECTING:
// If we are here, we are in danger of a race condition
// incoming rfcomm connection, but we are also attempting an
// outgoing connection. Lets try and interrupt the outgoing
// connection.
mConnectThread.interrupt();
// Now continue with new connection, including calling callback
mHeadset = new HeadsetBase(mBluetooth,mHeadsetAddress,info.mSocketFd,info.mRfcommChan,mConnectedStatusHandler);
mHeadsetType = type;
setState(BluetoothHeadset.STATE_CONNECTED,BluetoothHeadset.RESULT_SUCCESS);
mBtHandsfree.connectHeadset(mHeadset,mHeadsetType);
// Make sure that old outgoing connect thread is dead.
break;
如果当前是已连接的状态,这种情况是一种错误case,所以直接断掉所有连接。
case BluetoothHeadset.STATE_CONNECTED:
if (DBG) log("Already connected to " + mHeadsetAddress + ",disconnecting" +info.mAddress);
mBluetooth.disconnectRemoteDeviceAcl(info.mAddress);
break;
蓝牙耳机也可能会主动发起SCO 连接, BluetoothHandsfree 会接收到一个SCO_ACCEPTED消息,它会去调用AudioManager 的setBluetoothScoOn 函数,从而通知音频系统有个蓝牙耳机可用了。到此,蓝牙耳机完成了和Android 的全部连接。
case SCO_ACCEPTED:
if (msg.arg1 == ScoSocket.STATE_CONNECTED) {
  if (isHeadsetConnected() && mAudioPossible && mConnectedSco ==null) {
   Log.i(TAG, "Routing audio for incoming SCO connection");
   mConnectedSco = (ScoSocket)msg.obj;
   mAudioManager.setBluetoothScoOn(true);
  } else {
   Log.i(TAG, "Rejecting incoming SCO connection");
   ((ScoSocket)msg.obj).close();
  }
} // else error trying to accept, try again
mIncomingSco = createScoSocket();
mIncomingSco.accept();
break;

Android实现蓝牙耳机连接 代码地址如下:http://www.demodashi.com/demo/13259.html 前言 讲讲android对于蓝牙耳机连接技术的实现 今天涉及的内容有: 1. 流程讲解 2. 新建广播BluetoothReceiver,用于监听处理蓝牙连接过程中各状态 3. 在MainActivity中调用 4. 注意的点 5. 项目结构图和效果图 下面做以讲解 ... 阅读详情

相关推荐

Android 蓝牙 连接配对流程详细分析-史上最全文档

android-蓝牙A2dp-avrcp-hfp-opp-配对流程-ble-rfcomm源码流程图-点击下载 Android 蓝牙配对连接源码分析文档大全-点击下载 1、此篇文档主要对经典蓝牙的扫描配对连接流程进行了分析,并通过实际的耳机配对连接手表的例子进行梳理。主要目的是通过该文档学习,对蓝牙的扫描配对流程有一个清晰的认识。在项目中遇到相关问题,知道从哪方面去入手分析。 2.1Inquiry概念简介 搜索Inquiry顾名思义就是检测和收集周围环境中的蓝牙设备,根据询问的方式可分为......

手机-手表蓝牙开发工程师的博客 8859

android 实现ble蓝牙自动配对连接

蓝牙自动配对,即搜索到其它蓝牙设备之后直接进行配对,不需要弹出配对确认框或者密钥输入框。

ming0gy的博客 7600

英飞凌 AURIX Development Studio工程移植到Hightec的方法

1. 软件简介 AURIX™ Development Studio是英飞凌针对AURIX TC2XX/TC3XX系列单片机推出了一款免费的软件,集成了iLLD库,内置Tasking compiler和Tasking Debugger,但这两个模块只能用于非商业用途,可供学习和试用。iLLD库是英飞凌为TC2XX和TC3XX Tricore系列单片机提供的底层驱动库,有完善的使用手册,和较好的移植性。 Hightec是一款可以用来开发Aurix系列单片机的编译器,有免费版,可商用,集成GCC编译器,可用UDE

weixin_42967006的博客 7136

基于经典蓝牙 RFCOMM 的私有协议 Fuzzing

应用开发者可基于 BLE 提供的ATT/GATT协议,开发自己的私有协议。就像我们可以基于 TCP 创建 HTTP 协议一样。同样道理,对于经典蓝牙,我们在上一篇文章说过低功耗蓝牙应用层协议的测试方法。本次就来聊聊经典蓝牙(BR,Basic Rate)一些私有协议的测试方法。

个人笔记 3196

Windows 下 Codex MCP 服务配置全攻略:从环境搭建到实战避坑

本文详细介绍了在Windows系统下配置Codex MCP服务的完整流程与实战避坑指南。内容涵盖从Node.js环境搭建、Codex CLI安装,到核心配置文件config.toml的编写与解析,并重点解决了Windows平台特有的环境变量设置、MCP服务启动命令适配等关键难点,帮助开发者顺利完成从环境准备到编辑器插件连接的整个配置过程。

weixin_28826545的博客 2069

阿里奇门接口联调全流程详解:从沙箱自测到正式上线的保姆级攻略

本文详细解析阿里奇门接口联调的全流程,从沙箱自测到正式上线的关键步骤与避坑指南。涵盖环境配置、业务场景测试、跨团队协作、灰度发布及生产运维监控,帮助开发者高效完成API对接,确保供应链协同系统的稳定运行。特别适合首次接触奇门对接的技术负责人参考。

weixin_42535461的博客 414

Android 蓝牙开发(二) --手机与蓝牙音箱配对,并播放音频

蓝牙音箱

QG 1979

DBT关键切片重建算法

DBT通过有限角度(通常15°~50°)扫描,获取一系列低剂量投影图,重建出三维断层图像。传统FBP在稀疏角度下会产生严重的“伪影拖尾”和层间干扰。临床诊断中,放射科医生往往只关注几层关键切片(即病灶所在层),其余层仅作参考。

AI的内部世界的博客 89

android蓝牙耳机接入,Android跟蓝牙耳机建立连接有两种方式

2. 蓝牙耳机主动跟Android 连首先BluetoothAudioGateway 会在一个线程中收到来自蓝牙耳机的RFCOMM 连接,然后发送消息给BluetoothHeadsetService。mConnectingHeadsetRfcommChannel = -1;mConnectingHandsfreeRfcommChannel = -1;if(waitForHandsfreeConne...

weixin_42133753的博客 1580

【声纳技术】声呐时间反转镜技术:从被动聚焦到主动空间复用

时间反转镜技术以其独特的物理机制,为水声通信与声呐探测提供了一条绕过传统自适应均衡器的新路径。被动时间反转利用接收端的空间分集实现脉冲压缩,结构简洁、计算高效;主动时间反转则通过发射端预编码,将多径能量引导至目标位置,为多用户下行链路的空间复用奠定了物理基础。从Kuperman等人在海洋中首次验证声学时间反转镜,到TR-MIMO声呐的湖试验证,再到VTRM-CRK多用户通信系统的海试成功,该技术已从理论概念逐步走向工程实用。

u012133341的博客 55

生产环境中redis的SCAN命令如何替代KEYS命令?

本文介绍了使用SCAN命令替代KEYS的完整方案。SCAN通过游标分批迭代,避免KEYS命令遍历整个键空间导致的阻塞风险。文章详细说明了SCAN的基础语法、迭代流程和Java实现示例,强调必须关闭Cursor避免连接泄漏。针对生产环境,提供了COUNT参数调优、客户端去重、集群模式适配等优化建议,并列举了典型错误场景。SCAN通过分批次迭代和游标管理,可安全实现高性能键空间遍历。全文150字。

DN金猿的博客 179

Android蓝牙耳机型号,Android 蓝牙( Bluetooth)耳机连接分析及实现

Android 实现了对Headset 和Handsfree 两种profile 的支持。其实现核心是BluetoothHeadsetService,在PhoneApp 创建的时候会启动它。if (getSystemService(Context.BLUETOOTH_SERVICE) != null) {mBtHandsfree = new BluetoothHandsfree(this, p...

weixin_27427397的博客 1288

利用requests库下载bilibili字幕文件

文章目录1. 前言2. 程序下载大法好2.1 挖掘思路2.2 核心知识点2.3 汇总代码 1. 前言   之前的博客介绍了使用工具下载B站视频,但美中不足的是无法下载字幕。为了提高效率,将下载字幕的工作用程序自动化处理。 2. 程序下载大法好 2.1 挖掘思路   在谷歌浏览器中按下F12,打开谷歌开发者工具。搜索subtitle,则会得到一个json文件,如下图所示:   在网页中空白位置点击查看网页源代码,然后通过搜索(Ctrl+f)查找subtitle,则会发现在subtitle_url中包含了对应

herosunly的博客 4万+

Android 蓝牙( Bluetooth)耳机连接分析及实现

原文: http://blog.163.com/fenglang_2006/blog/static/133662318200910300590726/ Android 实现了对Headset 和Handsfree 两种profile 的支持。其实现核心是BluetoothHeadsetService,在PhoneApp 创建的时候会启动它。  if (getSyst

fanciman的专栏 1913

数据结构课程设计--基于知识图谱的中医食疗数据管理与应用

【代码】数据结构课程设计--基于知识图谱的中医食疗数据管理与应用。

M_inherit的博客 565

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Android与蓝牙耳机建立连接的分析

Android 实现了对Headset 和Handsfree 两种profile 的支持。其实现核心是BluetoothHeadsetService,在PhoneApp 创建的时候会启动它。  if (getSystemService(Context.BLUETOOTH_SERVICE) != null) {   mBtHandsfree = new BluetoothHandsfree(th

myxmu的专栏 1574

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

android连接苹果蓝牙耳机,苹果蓝牙耳机怎么配对 苹果蓝牙耳机怎么配对安卓手机 苹果蓝牙耳机使用说明...

近几年来,手机的发展非常迅速,功能越来越多,不仅可以发信息打电话,还可以联网玩游戏聊天购物等。而且通过手机蓝牙功能,可以在手机直接传输一些文件、音乐、游戏等。那么苹果蓝牙耳机怎么配对?苹果蓝牙耳机怎么配对安卓手机?下面一起来看看苹果蓝牙耳机使用说明吧。一、苹果蓝牙耳机怎么配对1、首先按下苹果耳机的电源键,长按几秒,将蓝牙耳机开机。2、保证蓝牙耳机电量的充足,可以完成连接。3、在苹果手机桌面找到“设...

weixin_35916518的博客 2万+

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

苹果无线耳机android能用吗,苹果的蓝牙耳机安卓能用吗

苹果的蓝牙耳机在安卓设备上是可以使用的,无论是安卓手机、平板还是其他智能设备都可以连接airpods耳机,因为它本身是一种蓝牙产品,然后才是苹果耳机,所以本质上和其他蓝牙耳机一样是通用的。不过在安卓和苹果手机上用苹果的蓝牙耳机会出现连接、功能方面的不同,体验不是原生的好,并且airpods价格偏贵,所以安卓用户选苹果耳机性价比不高。苹果的蓝牙耳机安卓能用吗有延迟吗1、结论;可以用。它可以像其他品牌...

weixin_39632693的博客 1万+

android蓝牙耳机来电铃声,Android实现积极连接蓝牙耳机

Android实现主动连接蓝牙耳机在Android程序中可以实现自动扫描蓝牙、配对蓝牙、建立数据通道。蓝牙分不同类型,这篇文字只讨论如何与蓝牙耳机连接。大致可以分三步:一、扫描蓝牙设备:1、注册并监听广播:BluetoothAdapter.ACTION_DISCOVERY_STARTEDBluetoothDevice.ACTION_FOUNDBluetoothAdapter.ACTION_DISC...

weixin_34024811的博客 1116

Android蓝牙耳机录音

Android蓝牙耳机录音 蓝牙耳机录音的步骤: 1)初始化音频对象: audiosource = MediaRecorder.AudioSource.VOICE_COMMUNICATION; this.bufferSize = AudioRecord.getMinBufferSize(VoiceConfig.SAMPLERATE, AudioFormat.CHANNEL_IN_MONO, Aud...

qq_37594666的博客 3504

android 蓝牙耳机 判断,Android实现蓝牙耳机连接

前言最近看了下蓝牙耳机连接的问题,查阅了相关资料,再此做一个总结。本文参考以下链接:Android实现主动连接蓝牙耳机再次对作者表示感谢。今天涉及的内容有:流程讲解新建广播BluetoothReceiver,用于监听处理蓝牙连接过程中各状态在MainActivity中调用注意的点效果图下面做以讲解一. 流程讲解在实现蓝牙耳机链接的时候,需要做一些前期工作,第一步,判断设备是否支持蓝牙。1.1 设备...

weixin_36284848的博客 1182

Android实现主动连接蓝牙耳机

在Android程序中可以实现自动扫描蓝牙、配对蓝牙、建立数据通道。 蓝牙分不同类型,可以参考(http://gqdy365.iteye.com/admin/blogs/2229304) 可以入下面方法获取蓝牙设备支持的类型: Java代码 BluetoothDevicedevice; Arrays.toString(device.getUuids()); 我的蓝牙音箱支持的...

feelinghappy的专栏 1075

安卓苹果通用超强兼容性蓝牙耳机,连接稳定音质卓越,双11必备

AirPods的诞生无疑是拉开了无线耳机和有线耳机的地位之战, 由于AirPods在无任何线材接驳的情况下实现左右耳朵单元同步独立工作,此类耳机也被赋予了“真无线”的称号。 AirPods虽然是2016年随iPhone 7一起推出的,可凭借苹果自主研发的W1芯片,使得AirPods在连接速率、稳定性、续航方面仍在同类产品中处于难以撼动的优势,能与其竞争的产品微乎其微。事实也证明了真无线耳机与有线耳机最大差别也仅仅是有线与无线,基本的稳定性才是真无线耳机的立足之本,音质的比重反而不是最大的,但AirPods

momo1996_233的博客 2702
上一篇: 调试Bluetooth时的一些札记
下一篇: 常量指针与指针常量的区别
likeping
博客等级 码龄25年 41粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值