BluetoothHeadsetClient disconnectAudio用于断开音频通道,若音频通道断开,则通话时发声端为手机端。代码如下:
//packages/modules/Bluetooth/framework/java/android/bluetooth/BluetoothHeadsetClient.java
public final class BluetoothHeadsetClient implements BluetoothProfile, AutoCloseable {
public boolean disconnectAudio(BluetoothDevice device) {
if (VDBG) log("disconnectAudio");
final IBluetoothHeadsetClient service = getService();
final boolean defaultValue = false;
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
if (DBG) log(Log.getStackTraceString(new Throwable()));
} else if (isEnabled()) {
try {
final SynchronousResultReceiver<Boolean> recv = SynchronousResultReceiver.get();
service.disconnectAudio(device, mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
} catch (RemoteException | TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
}
}
return defaultValue;
}
}
HeadsetClientService disconnectAudio
调用IBluetoothHeadsetClient的disconnectAudio,IBluetoothHeadsetClient是一个接口由HeadsetClientService的内部类BluetoothHeadsetClientBinder实现:
//packages/modules/Bluetooth/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
public class HeadsetClientService extends ProfileService {
private static class BluetoothHeadsetClientBinder extends IBluetoothHeadsetClient.Stub
implements IProfileServiceBinder {
private HeadsetClientService mService;
@Override
public boolean disconnectAudio(BluetoothDevice device) {
HeadsetClientStateMachine sm = getStateMachine(device); //获取状态机
if (sm == null) {
Log.e(TAG, "SM does not exist for device " + device);
return false;
}
if (!sm.isAudioOn()) { //如不是AudioOn
return false;
}
sm.sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO);
return true;
}
}
发送DISCONNECT_AUDIO消息,发送的消息会在HeadsetClientStateMachine内部类AudioOn的processMessage中处理:
//packages/modules/Bluetooth/android/app/srv/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
public class HeadsetClientStateMachine extends StateMachine {
private final NativeInterface mNativeInterface;
class AudioOn extends State {
public synchronized boolean processMessage(Message message) {
switch (message.what) {
case DISCONNECT_AUDIO:
/*
* just disconnect audio and wait for
* StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED, that triggers State
* Machines state changing
*/
if (mNativeInterface.disconnectAudio(mCurrentDevice)) {
routeHfpAudio(false);
returnAudioFocusIfNecessary();
}
break;
}
}
}
}
上面方法主要处理如下:
调用NativeInterface的disconnectAudio方法,通过蓝牙协议栈控制蓝牙芯片将通话音切换到手机侧。
调用HeadsetClientStateMachine的routeHfpAudio方法,通知AudioManager进行HfpAudio路由。
调用HeadsetClientStateMachine的returnAudioFocusIfNecessary方法,必要时返回音频焦点。
下面分别进行分析:
NativeInterface disconnectAudio
调用NativeInterface的disconnectAudio方法:
//packages/modules/Bluetooth/android/app/srv/com/android/bluetooth/hfpclient/NativeInterface.java
public class NativeInterface {
public boolean disconnectAudio(BluetoothDevice device) {
return disconnectAudioNative(getByteAddress(device));
}
}
调用disconnectAudioNative方法,并返回处理结果,disconnectAudioNative是Native方法,通过查表调用的是disconnectAudioNative方法:
static bthf_client_interface_t* sBluetoothHfpClientInterface = NULL;
//packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_hfpclient.cpp
static jboolean disconnectAudioNative(JNIEnv* env, jobject object,
jbyteArray address) {
std::shared_lock<std::shared_mutex> lock(interface_mutex);
if (!sBluetoothHfpClientInterface) return JNI_FALSE;
jbyte* addr = env->GetByteArrayElements(address, NULL);
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
bt_status_t status =
sBluetoothHfpClientInterface->disconnect_audio((const RawAddress*)addr);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed AG audio disconnection, status: %d", status);
}
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
调用bthf_client_interface_t的disconnect_audio函数,bthf_client_interface_t是个结构体,在bt_hf_client.h中定义,在bt_hf_client.cc中实现:
//packages/modules/Bluetooth/system/btif/src/bt_hf_client.cc
static bt_status_t disconnect_audio(const RawAddress* bd_addr) {
btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(*bd_addr);
if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
BTA_HfClientAudioClose(cb->handle);
return BT_STATUS_SUCCESS;
}
在之后就是蓝牙协议栈相关内容,在这里就不再分析了。
HeadsetClientStateMachine routeHfpAudio
调用HeadsetClientStateMachine的routeHfpAudio方法:
//packages/modules/Bluetooth/android/app/srv/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
public class HeadsetClientStateMachine extends StateMachine {
private final AudioManager mAudioManager;
synchronized void routeHfpAudio(boolean enable) {
if (mAudioManager == null) {
Log.e(TAG, "AudioManager is null!");
return;
}
logD("hfp_enable=" + enable);
if (enable && !sAudioIsRouted) {
mAudioManager.setHfpEnabled(true); //
} else if (!enable) {
mAudioManager.setHfpEnabled(false);
}
sAudioIsRouted = enable;
}
}
调用AudioManager的setHfpEnabled方法,这部分为Audio相关内容
待更新
HeadsetClientStateMachine returnAudioFocusIfNecessary
调用HeadsetClientStateMachine的returnAudioFocusIfNecessary方法:
//packages/modules/Bluetooth/android/app/srv/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
public class HeadsetClientStateMachine extends StateMachine {
private final AudioManager mAudioManager;
private void returnAudioFocusIfNecessary() {
if (mAudioFocusRequest == null) return;
mAudioManager.abandonAudioFocusRequest(mAudioFocusRequest);
mAudioFocusRequest = null;
}
}
调用AudioManager的abandonAudioFocusRequest方法,这部分为Audio相关内容
待更新
当蓝牙协议栈(BT Stack)处理完相关请求后,会调用NativeInterface的onAudioStateChanged方法:
//packages/modules/Bluetooth/android/app/srv/com/android/bluetooth/hfpclient/NativeInterface.java
public class NativeInterface {
private void onAudioStateChanged(int state, byte[] address) {
StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
event.valueInt = state;
event.device = getDevice(address);
if (DBG) {
Log.d(TAG, "onAudioStateChanged: address " + address + " event " + event);
}
HeadsetClientService service = HeadsetClientService.getHeadsetClientService();
if (service != null) {
service.messageFromNative(event);
} else {
Log.w(TAG, "onAudioStateChanged: Ignoring message because service not available: "
+ event);
}
}
}
发送EVENT_TYPE_AUDIO_STATE_CHANGED消息,发送的消息在HeadsetClientService的的messageFromNative中处理:
//packages/modules/Bluetooth/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
public class HeadsetClientService extends ProfileService {
// Handle messages from native (JNI) to java
public void messageFromNative(StackEvent stackEvent) {
Objects.requireNonNull(stackEvent.device,
"Device should never be null, event: " + stackEvent);
HeadsetClientStateMachine sm = getStateMachine(stackEvent.device,
isConnectionEvent(stackEvent));
if (sm == null) {
throw new IllegalStateException(
"State machine not found for stack event: " + stackEvent);
}
sm.sendMessage(StackEvent.STACK_EVENT, stackEvent);
}
}
发送STACK_EVENT消息,发送的消息会在HeadsetClientStateMachine的内部类Connecting的processMessage中处理:
//packages/modules/Bluetooth/android/app/srv/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
public class HeadsetClientStateMachine extends StateMachine {
class AudioOn extends State {
@Override
public synchronized boolean processMessage(Message message) {
switch (message.what) {
case StackEvent.STACK_EVENT:
StackEvent event = (StackEvent) message.obj;
logD("AudioOn: event type: " + event.type);
case StackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED:
logD("AudioOn audio state changed" + event.device + ": "
+ event.valueInt);
processAudioEvent(event.valueInt, event.device);
break;
default:
return NOT_HANDLED;
}
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
}
}
调用processAudioEvent方法:
//packages/modules/Bluetooth/android/app/srv/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
public class HeadsetClientStateMachine extends StateMachine {
// in AudioOn state
private void processAudioEvent(int state, BluetoothDevice device) {
if (!mCurrentDevice.equals(device)) {
Log.e(TAG, "Audio changed on disconnected device: " + device);
return;
}
switch (state) {
case HeadsetClientHalConstants.AUDIO_STATE_DISCONNECTED:
removeMessages(DISCONNECT_AUDIO);
mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
// Audio focus may still be held by the entity controlling the actual call
// (such as Telecom) and hence this will still keep the call around, there
// is not much we can do here since dropping the call without user consent
// even if the audio connection snapped may not be a good idea.
routeHfpAudio(false);
returnAudioFocusIfNecessary();
transitionTo(mConnected);
break;
default:
Log.e(TAG, "Audio State Device: " + device + " bad state: " + state);
break;
}
}
}
到这里BluetoothHeadsetClient的disconnectAudio流程就介绍完了。