Android HeadSet端的通话建立过程

蓝牙的HFP协议定义了两个角色,一个是HF端,如蓝牙耳机、车机端等免提设备;一个是AG端,通常指的就是手机端。在Android系统里面,也有对应的两个Profile,HF端对应HeadsetClient Profile,而AG端对应Headset Profile。下面我们就通过拨号指令,梳理Headset端的处理过程。
首先来看一下整体的流程图:
在这里插入图片描述
1.
首先拨号的指令在HF端发出,经过两端蓝牙chip的信号传递,到达AG侧的协议栈中,在协议栈经过解析之后,已经明确了此为一个拨号的请求,于是就会通过JNI层回调到蓝牙服务中,具体是在HeadSetNativeInterface这个类里:

private void onDialCall(String number, byte[] address) {   //1.JNI把协议栈的信号回调
        HeadsetStackEvent event =
                new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_DIAL_CALL, number,
                        getDevice(address));
        sendMessageToService(event);
    }

HeadSetNativeInterface会把消息传递给HeadSetService去处理。
HeadSetService是整个HeadsetProfile的核心所在,它继承自ProfileService,作为一个后台服务在一直运行。在本进程内,连接HeadSetNativeInterface和HeadsetStateMachine;对外部进程,通过实现Binder的本地接口,提供远程服务。
接下来看请求拨号的消息在HeadSetService的处理:

 void messageFromNative(HeadsetStackEvent stackEvent) {
 			
			.......
		   stateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT, stackEvent);    //信号发送到状态机中
 
 }

实际上,HeadSetService只是做了中转,然后就把协议栈(STACK)中的消息给到了状态机(HeadsetStateMachine)去处理。

能够接收到拨号求情,此时状态机肯定处于HFP协议的连接状态。由于HFP协议不仅会建立基础的协议连接(Level Connection),还会在通话的时候建立通话链路(SCO链路),所以在HeadsetStateMachine状态机中,有一个ConnectedBase状态对象,它代表HFP协议连接之后所处的状态,它的子类有Connected(代表Level Connection,即无SCO链路)、AudioConnecting(代表SCO链路连接中)、AudioOn(代表SCO链路建立)、AudioDisconnecting代表SCO链路断开中)。
HeadsetStackEvent.EVENT_TYPE_DIAL_CALL类型的信号,会在ConnectedBase中得到处理:

private abstract class ConnectedBase extends HeadsetStateBase {
		......
		case HeadsetStackEvent.EVENT_TYPE_DIAL_CALL:
                            processDialCall(event.valueString);
                            break;
     }
 }

private void processDialCall(String number) {

	if (!mHeadsetService.dialOutgoingCall(mDevice, dialNumber)) {  //调用HeadsetService的方法
            Log.w(TAG, "processDialCall, failed to dial in service");
            mNativeInterface.atResponseCode(mDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 0);
            return;
        }

}

于是消息又回到了HeadsetService里面去处理,核心的代码如下:

public boolean dialOutgoingCall(BluetoothDevice fromDevice, String dialNumber) {

	Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
                    Uri.fromParts(PhoneAccount.SCHEME_TEL, dialNumber, null));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);  //这里去调用telecom拨打电话
            mDialingOutTimeoutEvent = new DialingOutTimeoutEvent(fromDevice);  //开启一个超时检测机制
            mStateMachinesThread.getThreadHandler()
                    .postDelayed(mDialingOutTimeoutEvent, DIALING_OUT_TIMEOUT_MS);

}

这里是去调用了telecom拨打电话的接口,真正地去呼叫一个号码。这是一个异步的过程,等到电话建立之后,就会通过telecom自身的回调机制通知给到感兴趣的监听者。在HeadSet端,这个telecom状态的监听者就是BluetoothInCallService。

BluetoothInCallService继承自InCallService,而telecom的通话建立或者移除有改变都会回调到InCallService相应的方法,自然也就会回调到BluetoothInCallService继承的方法:

public class BluetoothInCallService extends InCallService{
......
	public void onCallAdded(BluetoothCall call) {  //有新的通话创建的时候,telecom就会回调此方法
        if (call.isExternalCall()) {
            return;
        }
        if (!mBluetoothCallHashMap.containsKey(call.getId())) {
            Log.d(TAG, "onCallAdded");
            CallStateCallback callback = new CallStateCallback(call.getState());
            mCallbacks.put(call.getId(), callback);
            call.registerCallback(callback);                  //注册一个此通话状态改变的监听接口

            mBluetoothCallHashMap.put(call.getId(), call);
            updateHeadsetWithCallState(false /* force */);  //通知绑定上HeadSetService通话状态有变
        }
    }
}

以上是新建通话时候的回调实现,主要做了两件事,1.注册一个针对于本次通话状态改变的监听接口,例如DIALING、ALERTING、ACTIVE等通话状态 2.通知HeadSetService通话建立,当然,这里没有类似于callAdd的方法,而是通过统一的接口通知,因此这里就是通知HeadSetService有一个通话处于DIALING状态。

HeadSetService的内部的Binder接口的本地实现,负责接收外部的调用信息:

private static class BluetoothHeadsetBinder extends IBluetoothHeadset.Stub
            implements IProfileServiceBinder {
			
			 @Override
        public void phoneStateChanged(int numActive, int numHeld, int callState, String number,   //HeadSetService接收到BluetoothInCallService发过来的通话状态改变的通知
                int type, String name) {
            HeadsetService service = getService();
            if (service == null) {
                return;
            }
            service.phoneStateChanged(numActive, numHeld, callState, number, type, name, false);   
        }
			
}

然后把消息给到HeadSetService,HeadSetService又把消息给到HeadsetStateMachine处理:

private void phoneStateChanged(int numActive, int numHeld, int callState, String number,
            int type, String name, boolean isVirtualCall) {
           			 ........
					 doForStateMachine(mDialingOutTimeoutEvent.mDialingOutDevice,
                            stateMachine -> stateMachine.sendMessage(
                                    HeadsetStateMachine.DIALING_OUT_RESULT, 1 /* success */, 0,
                                    mDialingOutTimeoutEvent.mDialingOutDevice));  //首先反馈请求的操作成功			

					.........
					doForEachConnectedStateMachine(
                stateMachine -> stateMachine.sendMessage(HeadsetStateMachine.CALL_STATE_CHANGED,
                        new HeadsetCallState(numActive, numHeld, callState, number, type, name)));
		//把最新的通话状态作为参数传递进去
			
			}

这里有两次数据的反馈,首先对本次连接的设备发送一个拨号请求成功的反馈信息;然后再对连接上的每个设备都发送当前的状态信息。

在HeadsetStateMachine里面,都是在ConnectedBase这个连接状态基类里面处理的两个消息:

 case DIALING_OUT_RESULT: { //拨号请求的AT指令结果反馈
                    BluetoothDevice device = (BluetoothDevice) message.obj;
                        ......
                    mNativeInterface.atResponseCode(mDevice,
                                message.arg1 == 1 ? HeadsetHalConstants.AT_RESPONSE_OK
                                        : HeadsetHalConstants.AT_RESPONSE_ERROR, 0);
                }           
							
		 case CALL_STATE_CHANGED: {  //电话状态改变
                    HeadsetCallState callState = (HeadsetCallState) message.obj;
                    if (!mNativeInterface.phoneStateChange(mDevice, callState)) { //调用native方法,把最新电话发送到底层协议栈,然后发送给HF端设备
                        stateLogW("processCallState: failed to update call state " + callState);
                        break;
                    }
         
                }		

最后都是调用了JNI对应的方法,然后把消息发送到协议栈里面,协议栈通过HCI再把消息指令给到蓝牙chip,最后完成信号的发送。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值