本文作者

张朋永博客地址:

http://blog.csdn.net/vnanyesheshou

接着上一篇hfp连接继续,查看蓝牙通话时如何进行处理的。hfp连接有两个连接,一个是hfp连接(在设置界面显示的是手机音频),另一个是蓝牙通话时进行的音频连接。这篇说下第二个连接,音频连接处理过程。 

该文章是基于Android源码4.3的

1 连接音频

在手机音频(hfp连接)正常连接时,接通电话,并选择蓝牙通话。从系统应用Phone开始分析。 

代码路径:packages/apps/Phone/src/com/Android/phone/InCallScreen.Java 
手机通话可以选择扬声器、听筒、蓝牙,我们选择蓝牙。 

跟我一起学hfp(二)_Java

蓝牙通话时选择蓝牙,会调到switchInCallAudio(),对于蓝牙通话模式,检查是否连接蓝牙耳机 headset(手机音频),检查蓝牙通话音频是否连接,如果有连接的蓝牙耳机,并且没有连接蓝牙音频(这个连接并不是设置界面中的手机音频连接,这是通话是需要的连接,该连接的前提是需要进行手机音频的连接),则满足条件。 

如果扬声器开着,则先关闭扬声器,然后连接蓝牙音频

跟我一起学hfp(二)_Java_02

接着看connectBluetoothAudio()函数。

跟我一起学hfp(二)_Java_03

mBluetoothHeadset是通过getProfileProxy获取的BluetoothHeadset代理对象。通过代理对象连接音频。

mBluetoothHeadset.connectAudio()会跳到应用Settings中HeadsetService内部类BluetoothHeadsetBinder中的connectAudio()方法,然后又跳到HeadsetService的connectAudio()函数中。 

HeadsetService的connectAudio()函数如下

跟我一起学hfp(二)_Java_04

在HeadsetService的connectAudio()函数中检查headset是否连接,音频是否连接。向状态机发送连接音频的消息。

此时headset是连接的,HeadsetStateMachine中的状态是Connected。 
接收到后CONNECT_AUDIO的消息进行如下处理:

//mCurrentDevice表示状态改变前连接的设备。connectAudioNative(getByteAddress(mCurrentDevice));

mCurrentDevice表示状态改变前连接的设备。通过getByteAddress获取该设备的蓝牙地址。然后调用native方法connectAudioNative连接音频,该方法会调用jni目录下的 
com_android_bluetooth_hfp.cpp中的connectAudioNative函数。

跟我一起学hfp(二)_Java_05

将byte数组类型的地址转换成jbyte*类型,然后向hardware、协议栈下进行连接。

2 音频连接状态

当音频连接状态改变会回调com_android_bluetooth_hfp.cpp中audio_state_callback函数。 
audio_state_callback函数如下:

跟我一起学hfp(二)_Java_06

audio_state_callback中参数state表示音频连接状态,address表示蓝牙的地址。

将address转换为jbyteArray类型,然后调用java层代码,调用HeadSetStateMachine中的onAudioStateChanged函数。onAudioStateChanged代码如下:

跟我一起学hfp(二)_Java_07

onAudioStateChanged向状态机发送消息。此时状态机处于Connected状态,收到该消息调用processAudioEvent(event.valueInt, event.device)函数。processAudioEvent代码如下:

跟我一起学hfp(二)_Java_08

音频连接回调,状态是HeadsetHalConstants.AUDIO_STATE_CONNECTING或HeadsetHalConstants.AUDIO_STATE_CONNECTED,向外发送audio连接状态改变的广播。状态是HeadsetHalConstants.AUDIO_STATE_CONNECTED,通过AudioManager设置蓝牙SCO进行音频通信,将状态机切换到AudioOn状态。

可以通过广播接收者注册BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED,监听音频到连接状态的改变。

3 音频断开连接 

蓝牙通话状态下,切换到听筒、扬声器或者停止通话,都会将音频断开连接。在应用Phone中的InCallScreen.java中调用disconnectBluetoothAudio,代码如下:

跟我一起学hfp(二)_Java_09

mBluetoothHeadset.disconnectAudio()通过代理对象调用disconnectAudio(),跳转到应用Bluetooth的HeadSetService内部类BluetoothHeadsetBinder中的disconnectAudio()中,然后跳到HeadSetService的disconnectAudio()函数中。

跟我一起学hfp(二)_Java_10

此时HeadsetStateMachine状态为AudioOn,接收到消息后处理如下:

跟我一起学hfp(二)_Java_11

disconnectAudioNative为native方法,调用到jni关闭音频连接。关闭蓝牙SCO耳机通讯,向外发送广播并向蓝牙耳机发送通话状态。

https://mp.weixin.qq.com/s/-d64iAJogD2w3WYqB_bFwA