Android13 BluetoothHeadset disconnectAudio流程分析

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流程就介绍完了。

  • 24
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值