前段时间似乎所有的事情都赶在一起,回家、集体出游、出差,折腾了近一个月,终于算暂时清静了,但清静只是暂时,估计马上又要出差了,所以赶紧把蓝牙这一部分的文章了结下,按之前提到的目录,本文是关于蓝牙接打电话和听音乐的流程分析,对应蓝牙HFP/A2DP的profile,由于这部分也算是蓝牙的经典功能,所以代码流程并不是很复杂,当然不复杂仅是对于代码调用流程而言,对于HFP/A2DP协议相关的东东还没有精力去看,其难易程序也无法评价。下面从两个点HFP与A2DP来展开本文的代码跟踪:
 
        正文开始之前,先说点题外话,在android系统中蓝牙耳机和听筒两者的音频通道是不一样的,使用蓝牙耳机接听电话和听音乐不仅涉及到本文下面提到的流程,更要牵扯的音频通道的切换,这是一个相对比较复杂的过程,android的音频系统相关内容可不算少,个人感觉多少了下解相关知识可能有助于我们更好的蓝牙这部分功能,不过本文的主题当然还是下面两个。

1.蓝牙耳机接听电话

        这个就对应HFP(Hands-freeProfile),Free your Hand,蓝牙的初衷之一。先来看这个功能的场景,手机来电,手机与蓝牙耳机已连接,这时会优先触发蓝牙接听电话的代码流程,起步代码在phone\src\com\android\phone\nCallScreen.java的connectBluetoothAudio() /disconnectBluetoothAudio(),只看连接部分好了,注意下面代码里的注释,
[java] view plaincopy

 

  1. /* package */ void connectBluetoothAudio() {
  2. if (VDBG) log("connectBluetoothAudio()...");
  3. if (mBluetoothHeadset != null) {
  4. // TODO(BT) check return
  5. mBluetoothHeadset.connectAudio();
  6. }
  7. // Watch out: The bluetooth connection doesn't happen instantly;
  8. // the connectAudio() call returns instantly but does its real
  9. // work in another thread.  The mBluetoothConnectionPending flag
  10. // is just a little trickery to ensure that the onscreen UI updates
  11. // instantly. (See isBluetoothAudioConnectedOrPending() above.)
  12. mBluetoothConnectionPending = true;
  13. mBluetoothConnectionRequestTime = SystemClock.elapsedRealtime();

接下来就跳到蓝牙应用的管辖范围,代码在packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java,

[java] view plaincopy

 

  1. public boolean connectAudio() {
  2. HeadsetService service = getService();
  3. if (service == null) return false;
  4. return service.connectAudio();
  5. }

很明显下一个目标是HeadsetService,直接看具体实现,这部分代码跳转都比较清晰,下面代码会先判断当前状态是否正确,关于HeadsetStateMachine几个状态可以参持这个/packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java的最前的代码注释。

[java] view plaincopy

 

  1. boolean connectAudio() {
  2. // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission
  3. enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
  4. if (!mStateMachine.isConnected()) {
  5. return false;
  6. }
  7. if (mStateMachine.isAudioOn()) {
  8. return false;
  9. }
  10. mStateMachine.sendMessage(HeadsetStateMachine.CONNECT_AUDIO);
  11. return true;
  12. }

走进HeadsetStateMachine状态机,找到CONNECT_AUDIO分支,就看带Native的方法connectAudioNative(getByteAddress(mCurrentDevice));

[java] view plaincopy

 

  1. static jboolean connectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
  2. jbyte *addr;
  3. bt_status_t status;
  4. if (!sBluetoothHfpInterface) return JNI_FALSE;
  5. addr = env->GetByteArrayElements(address, NULL);
  6. if (!addr) {
  7. jniThrowIOException(env, EINVAL);
  8. return JNI_FALSE;
  9. }
  10. //连接在这里
  11. if ( (status = sBluetoothHfpInterface->connect_audio((bt_bdaddr_t *)addr)) !=
  12. BT_STATUS_SUCCESS) {
  13. ALOGE("Failed HF audio connection, status: %d", status);
  14. }
  15. env->ReleaseByteArrayElements(address, addr, 0);
  16. return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
  17. }

上面代码还可以进一步跟到下面/external/bluetooth/bluedroid/btif/src/btif_hf.c,到了这里其实流程已经结束了,对于这里消息流转估计要放到以后再写了

[java] view plaincopy

 

  1. static bt_status_t connect_audio( bt_bdaddr_t *bd_addr )
  2. {
  3. CHECK_BTHF_INIT();
  4. if (is_connected(bd_addr))
  5. {
  6. BTA_AgAudioOpen(btif_hf_cb.handle);
  7. /* Inform the application that the audio connection has been initiated successfully */
  8. btif_transfer_context(btif_in_hf_generic_evt, BTIF_HFP_CB_AUDIO_CONNECTING,
  9. (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
  10. return BT_STATUS_SUCCESS;
  11. }
  12. return BT_STATUS_FAIL;
  13. }
 

2.在蓝牙列表中连接蓝牙耳机

     A2dp的连接过程,在蓝牙搜索结果列表连接一个蓝牙耳机,既然是从设备列表开始,所以起步代码自然是这个了
[java] view plaincopy

 

  1. DevicePickerFragment.java (settings\src\com\android\settings\bluetooth)     3884     2013-6-26
  2. void onClicked() {
  3. int bondState = mCachedDevice.getBondState();
  4. if (mCachedDevice.isConnected()) {
  5. askDisconnect();
  6. } else if (bondState == BluetoothDevice.BOND_BONDED) {
  7. mCachedDevice.connect(true);
  8. } .......
  9. }
  10. void connect(boolean connectAllProfiles) {
  11. if (!ensurePaired()) {  //要先确保配对
  12. return;
  13. }
  14. mConnectAttempted = SystemClock.elapsedRealtime();
  15. connectWithoutResettingTimer(connectAllProfiles);//没别的了,只能看到这里
  16. }

代码路径这里packages/apps/Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java,具体代码看下面

[java] view plaincopy

 

  1. // Try to initialize the profiles if they were not.
  2. ...........
  3. // Reset the only-show-one-error-dialog tracking variable
  4. mIsConnectingErrorPossible = true;
  5. int preferredProfiles = 0;
  6. for (LocalBluetoothProfile profile : mProfiles) {
  7. if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
  8. if (profile.isPreferred(mDevice)) {
  9. ++preferredProfiles;
  10. connectInt(profile);//连接在这里,
  11. }
  12. }
  13. }
  14. .............

connectInt的实现很简单,直接跳过看里面的profile.connect(mDevice),这里的profile是指A2dpProfile,所以connet()方法的具体实现在

[java] view plaincopy

 

  1. public boolean connect(BluetoothDevice device) {
  2. if (mService == null) return false;
  3. List<BluetoothDevice> sinks = getConnectedDevices();
  4. if (sinks != null) {
  5. for (BluetoothDevice sink : sinks) {
  6. mService.disconnect(sink);
  7. }}
  8. return mService.connect(device);
  9. }

下面是 BluetoothA2dp.java (frameworks\base\core\java\android\bluetooth)  ,为什么是这样看下这个private BluetoothA2dp mService;就知道了

[java] view plaincopy

 

  1. public boolean connect(BluetoothDevice device) {
  2. if (mService != null && isEnabled() &&
  3. isValidDevice(device)) {
  4. try {
  5. return mService.connect(device);
  6. } catch (RemoteException e) {
  7. Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
  8. return false;
  9. }
  10. }...........
  11. return false;
  12. Binder跳转
  13. public boolean connect(BluetoothDevice device) {
  14. A2dpService service = getService();
  15. if (service == null) return false;
  16. return service.connect(device);
  17. }
  18. }

之后的跳转和第一部分蓝牙接听电话跳转过程类似,就不重复了,最后会来到packages/apps/Bluetooth/jni/com_android_bluetooth_a2dp.cpp的connectA2dpNative,同样到下面的代码,我们能看到的开放的代码也就是这些,再下面要看vendor的具体实现了。

[java] view plaincopy

 

  1. static jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) {
  2. jbyte *addr;
  3. bt_bdaddr_t * btAddr;
  4. bt_status_t status;
  5. ALOGI("%s: sBluetoothA2dpInterface: %p", __FUNCTION__, sBluetoothA2dpInterface);
  6. if (!sBluetoothA2dpInterface) return JNI_FALSE;
  7. addr = env->GetByteArrayElements(address, NULL);
  8. btAddr = (bt_bdaddr_t *) addr;
  9. if (!addr) {
  10. jniThrowIOException(env, EINVAL);
  11. return JNI_FALSE;
  12. }
  13. if ((status = sBluetoothA2dpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
  14. ALOGE("Failed HF connection, status: %d", status);
  15. }
  16. env->ReleaseByteArrayElements(address, addr, 0);
  17. return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;

那到此为止,本文关于蓝牙耳机与蓝牙接听电话的流程分析也就结束了,同时蓝牙这一系列的文章也暂时结束,当然后续依然会关注蓝牙。本系列的第一篇文章标题是入门,现在想想,这五篇文章下来也不过是刚刚入门而已,协议部分更是没怎么涉及呢,对于蓝牙BT需要深入研究的地方还有很多,仅希望这五篇文章可以帮你快速了解android蓝牙代码流程,回顾以前四篇文章请点击链接:

       android -- 蓝牙 bluetooth (一) 入门
       android -- 蓝牙 bluetooth (二) 打开蓝牙
       android -- 蓝牙 bluetooth (三)搜索蓝牙
       android -- 蓝牙 bluetooth (四)OPP文件传输    
       最后感谢在前面文章中网友的热心回复与纠正,学习路上一起分享是快乐的。谢谢!

转载于:https://www.cnblogs.com/Free-Thinker/p/4539978.html

android -- 蓝牙 bluetooth (五)接电话与听音乐相关推荐

  1. android -- 蓝牙 bluetooth (一) 入门

    android -- 蓝牙 bluetooth (一) 入门 分类: Android的原生应用分析 2013-05-19 21:44 19998人阅读 评论(42) 收藏 举报 bluetooth4. ...

  2. ZT android -- 蓝牙 bluetooth (四)OPP文件传输

    android -- 蓝牙 bluetooth (四)OPP文件传输 分类: Android的原生应用分析 2013-06-22 21:51 2599人阅读 评论(19) 收藏 举报 4.2源码AND ...

  3. 深入了解Android蓝牙Bluetooth——《基础篇》

    深入了解Android蓝牙Bluetooth--<基础篇> 什么是蓝牙?   也可以说是蓝牙技术.所谓蓝牙(Bluetooth)技术,实际上是一种短距离无线电技术,是由爱立信公司公司发明的 ...

  4. android -- 蓝牙 bluetooth解读

    入手一个新的模块或应用,当然首先要知道它都有什么了,与它相关的代码在那里,所以先一起看下蓝牙代码分布吧. 1. 代码分布: packages/apps/Bluetooth/ 看这路径肯定是蓝牙应用方面 ...

  5. android -- 蓝牙 bluetooth (四)OPP文件传输

    原址 在前面android -- 蓝牙 bluetooth (一) 入门文章结尾中提到了会按四个方面来写这系列的文章,前面已写了蓝牙打开和蓝牙搜索,这次一起来看下蓝牙文件分享的流程,也就是蓝牙应用op ...

  6. 深入了解Android蓝牙Bluetooth【基础+进阶】

    基础篇 什么是蓝牙? 也可以说是蓝牙技术.所谓蓝牙(Bluetooth)技术,实际上是一种短距离无线电技术,是由爱立信公司公司发明的.利用"蓝牙"技术,能够有效地简化掌上电脑.笔记 ...

  7. android 蓝牙 bluetooth OPP文件传输

    蓝牙文件分享的流程,也就是蓝牙应用opp目录下的代码,作为蓝牙最基本的一个功能,这部分的代码在之前的版本中就已经有了,新旧版本代码对比很多类名都是一样的,这一部分新东西不多,写在这里帮助大家梳理下流程 ...

  8. Android 蓝牙 Bluetooth 自动回连 取消pin码校验弹出框

    蓝牙深层次的也不太懂,主要是使用了 BluetoothAdapter 和 BluetoothDevice 这两类,一个表示本地蓝牙设备,一个表示远程蓝牙设备 相关说明:https://blog.csd ...

  9. Android 蓝牙(有线)耳机监听的问题

    MediaButtonReceive只是作为一种通俗的命名方式来响应插入耳机后,点击耳机上的按键(MEDIA_BUTTON)接受该广播事件类. 点击MEDIA_BUTTON发送的Intent Acti ...

  10. android -- 蓝牙 bluetooth (二) 打开蓝牙

    4.2的蓝牙打开流程这一部分还是有些变化的,从界面上看蓝牙开关就是设置settings里那个switch开关,widget开关当然也可以,起点不同而已,后续的流程是一样的.先来看systemServe ...

最新文章

  1. Google Pixel 超分辨率--Super Resolution Zoom
  2. ppt流程图字体太小_关于答辩PPT的制作技巧
  3. 仔细学习CSS(二)
  4. luogu_1002 过河卒
  5. tomcat7.0支持什么版本的jdk_JDK/Java 16 可能带来什么新特性?
  6. mysql搜索中文 有的匹配不出来_MYSQL-中文检索匹配与正则表达式
  7. 一些OEM的厂商的漏洞分析
  8. 执行力 - 快速反应
  9. 万能五笔输入法下载|万能五笔输入法电脑版下载
  10. Linux服务器下安装ANSYS
  11. 什么是埋点?我们为什么需要埋点?(原作者:知乎 原志Growing)
  12. linux编译firefox,linux安装firefox
  13. 国务院发展研究中心发布《中国云计算产业发展与应用白皮书》| 附下载
  14. 产品思维 -- 用户体验
  15. 【常用工具类】EasyExcel
  16. float与定位脱离文档流布局规则
  17. 服务器虚拟化书籍,服务器虚拟化解决方案书模板-精选版.doc
  18. div中图片下方的说明文字如何能添加的上去
  19. 深入HashMap源码
  20. php多张图合成一张图,PHP中多张图片合成一张图片例子

热门文章

  1. ubuntu16.04下ROS操作系统学习笔记(二)命令工具了解和仿真小海龟
  2. 冒号在MATLAB里基本意思
  3. Linux汇编调试器EDB
  4. 几个例子弄懂JS 的setInterval的运行方式
  5. css3模拟jq点击事件
  6. 以向量和矩阵的视角抽象万物
  7. django xadmin 集成DjangoUeditor富文本编辑器
  8. c++构造函数分类说明
  9. 前端面试之 判断 true == true 需要进行哪几步操作?
  10. 基于vitamio的网络电视直播源代码