Linphone android去电增加自定义SIP消息头的流程分析

一、首先看一下如何在发起去电的sip请求中添加自定义的消息头

增加自定义头消息发方法,so已经提供了native方法,

发起呼叫的示例如下:

LinphoneCallParams params = lc.createCallParams(null);
if(!TextUtils.isEmpty(extraData)){
   params.addCustomHeader("x-extraData",extraData);
}
lc.inviteAddressWithParams(lAddress, params);

extraData是待增加的头消息。
addCustomHeader(key,value)在native下的实现如下: native接口申明全部在linphonecore_jni.cc

extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_addCustomHeader(JNIEnv *env, jobject thiz, jlong lcp, jstring         jheader_name, jstring jheader_value){
   const char* header_name = GetStringUTFChars(env, jheader_name);
   const char* header_value = GetStringUTFChars(env, jheader_value);
   linphone_call_params_add_custom_header((LinphoneCallParams*)lcp,header_name,header_value);
   ReleaseStringUTFChars(env, jheader_name, header_name);
   ReleaseStringUTFChars(env, jheader_value, header_value);
}

linphone_call_params_add_custom_header(),位于call_params.c中;

void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char     *header_value){
   params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
}

使用了sal_custon_header_append()来将传入的head_key/value构建成call中使用的结构体

SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){
   belle_sip_message_t *msg=(belle_sip_message_t*)ch;
   belle_sip_header_t *h;

   if (msg==NULL){
      msg=(belle_sip_message_t*)belle_sip_request_new();
      belle_sip_object_ref(msg);
   }
   h=belle_sip_header_create(name,value);
   if (h==NULL){
      belle_sip_error("Fail to parse custom header.");
      return (SalCustomHeader*)msg;
   }
   belle_sip_message_add_header(msg,h);
   return (SalCustomHeader*)msg;
}

这是一个追加消息头的过程,

1.params下的custom_headers链表,如果不存在,则在这里先进行初始化belle_sip_request_new(),

2.通过belle_sip_header_create(name,value)生成一个belle_sip_header_t* 结构体h;

3.通过belle_sip_message_add_header(msg,h)将生成的h追加到msg后面,最后返回;

总结下添加过程:
添加的自定义头消息的key-value,首先被保存在LinphoneCallParam对象中,存放在params->custom_headers中了,custom_headers是一个链表结构

二、分析是如何将LinphoneCallParam中配置的参数,加载到发起呼叫的SIP请求中。

发起呼叫是通过 inviteAddressWithParams(LinphoneAddress address, LinphoneCallParams params)来实现的native实现在linphonecore.c line3387。

LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params){
    ms_message("linphone_core_invite_address_with_params playcard = %s, captcard = %s",lc->sound_conf.play_sndcard->desc->driver_type,lc->sound_conf.capt_sndcard->desc->driver_type);
   const char *from=NULL;
   LinphoneProxyConfig *proxy=NULL;
   LinphoneAddress *parsed_url2=NULL;
   char *real_url=NULL;
   LinphoneCall *call;
   bool_t defer = FALSE;
   LinphoneCallParams *cp;
   ......

   cp = linphone_call_params_copy(params);
    ......
   /* if no proxy or no identity defined for this proxy, default to primary contact*/
   if (from==NULL) from=linphone_core_get_primary_contact(lc);
   parsed_url2=linphone_address_new(from);

   call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),cp,proxy);
   ......
   /* this call becomes now the current one*/
   lc->current_call=call;
   linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call");
   call->log->start_date_time=ms_time(NULL);
   linphone_call_init_media_streams(call);
...
   if (defer==FALSE) {
      if (linphone_core_start_invite(lc,call,NULL) != 0){
         /*the call has already gone to error and released state, so do not return it*/
         call = NULL;
      }
   }
   if (real_url!=NULL) ms_free(real_url);
   linphone_call_params_destroy(cp);
   return call;
}

这个接口下只看三个环节:

1. LinphoneCallParams *cp = linphone_call_params_copy(params);
2. linphone_cal_new_outgoing(lc, fromaddress, toaddress, cp, proxy);
3. linphone_core_start_invite(lc,call,Null);

首先分析第二环节的具体流程;
linphone_cal_new_outgoing()位于linphonecall.c line1236

LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){
   ms_message("linphone_call_new_outgoing");
   LinphoneCall *call = belle_sip_object_new(LinphoneCall);
   call->dir=LinphoneCallOutgoing;
   call->core=lc;
   call->dest_proxy=cfg;
   linphone_call_outgoing_select_ip_version(call,to,cfg);
   linphone_call_get_local_ip(call, to);
   call->params = linphone_call_params_copy(params);
   linphone_call_init_common(call, from, to);
...

   discover_mtu(lc,linphone_address_get_domain (to));
   if (params->referer){
      call->referer=linphone_call_ref(params->referer);
   }

   linphone_call_create_op(call);
   return call;
}

这里会构建一个新的LinphoneCall对象,并根据传入address和cp将通话信息全部填入到call中;
call->params = linphone_call_params_copy(params);
最后调用linphone_call_create_op(call),完成后返回call对象;

linphone_call_create_op(call)位于linphonecall.c line1070;

void linphone_call_create_op(LinphoneCall *call){
    if (call->op) sal_op_release(call->op);
    call->op=sal_op_new(call->core->sal);
    sal_op_set_user_pointer(call->op,call);
    if (call->params->referer)
        sal_call_set_referer(call->op,call->params->referer->op);
    linphone_configure_op(call->core,call->op,call->log->to,call->params->custom_headers,FALSE);
    if (call->params->privacy != LinphonePrivacyDefault)
        sal_op_set_privacy(call->op,(SalPrivacyMask)call->params->privacy);
    /*else privacy might be set by proxy */
}

这里会通过sal_op_new()初始化call->op结构体,
然后调用 linphone_configure_op(call->core, call->op, call->log->to, call->params->custom_headers, FALSE)来填充信息到call->op,
到这里,再次出现了call->params->custom_headers,发起呼叫时添加的头消息就是保存在这里的。

linphone_configure_op(lc, SalOp* op, dest, SalCustomHeader *header, with_contact) 位于linphonecore.c line 3338;

void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact){
   ms_message("linphone_config_op");
   bctbx_list_t *routes=NULL;
   LinphoneProxyConfig *proxy=linphone_core_lookup_known_proxy(lc,dest);
   const char *identity;
    ......
   sal_op_set_to_address(op,dest);
   sal_op_set_token(op,token);
   sal_op_set_from(op,identity);
   ms_message("identity = %s  sal_token = %s",identity,((SalOpBase*)op)->token);
   sal_op_set_sent_custom_header(op,headers);
   sal_op_set_realm(op,linphone_proxy_config_get_realm(proxy));
    ......
}

这个函数主要是将通话中的一些配置信息设置到SalOp中,
过程中包含一步: sal_op_set_sent_custom_header(op,headers);

void sal_op_set_sent_custom_header(SalOp *op, SalCustomHeader* ch){
   SalOpBase *b=(SalOpBase *)op;
   if (b->sent_custom_headers){
      sal_custom_header_free(b->sent_custom_headers);   
      b->sent_custom_headers=NULL;      
   }
   if (ch) belle_sip_object_ref((belle_sip_message_t*)ch);
   b->sent_custom_headers=ch;
}

过程比较简单,就是将SalCustomHeaders的自定义头消息保存到op->sent_custom_headers中;

继续分析linphone_core_invite_address_with_params()中的第三环节:linphone_core_start_invite(lc,call,Null);

代码太长,省略其他部分,此函数关键调用了 sal_call(call->op,from,real_url)来发起呼叫;

sal_call位于sal_op_call.c line772,

int sal_call(SalOp *op, const char *from, const char *to){
......
   invite=sal_op_build_request(op,"INVITE");

   sal_op_fill_invite(op,invite);

   sal_op_call_fill_cbs(op);
 ...
   return sal_op_send_request(op,invite);
}


1. 通过sal_op_build_request(op,”INVITE”),来创建一个INVITE类型的请求结构体belle_sip_request_t;
2. 然后向这个结构体中填充op中存储的部分基础信息;
3. 配置当前这个op需要的呼叫过程中的各类处理回调,这些回调很重要,会频繁用到,在这里的流程分析上暂时不介绍了
4. 返回sal_op_send_request(op,invite)

直接看sal_op_send_request()位于sal_op_impl.c line405

int sal_op_send_request(SalOp* op, belle_sip_request_t* request)  {
    belle_sip_message("sal_op_send_request");
   bool_t need_contact=FALSE;
   if (request==NULL) {
      return -1; /*sanity check*/
   }
   if (strcmp(belle_sip_request_get_method(request),"INVITE")==0
         ||strcmp(belle_sip_request_get_method(request),"REGISTER")==0
         ||strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0
         ||strcmp(belle_sip_request_get_method(request),"OPTIONS")==0
         ||strcmp(belle_sip_request_get_method(request),"REFER")==0) /* Despite contact seems not mandatory, call flow example show a Contact in REFER requests*/
      need_contact=TRUE;

   return _sal_op_send_request_with_contact(op, request,need_contact);
}

因为是INVITE类型的请求,这里的need_contact是TRUE;

sal_op_send_request_with_contact(op,request,bool_); 位于sal_op_impl.c line315;
函数内会调用_sal_op_add_custom_headers(op,request),

void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){
    ms_message("_sal_op_add_custom_headers");
   if (op->base.sent_custom_headers){
      belle_sip_message_t *ch=(belle_sip_message_t*)op->base.sent_custom_headers;
      belle_sip_list_t *l=belle_sip_message_get_all_headers(ch);
      belle_sip_list_t *elem;
      for(elem=l;elem!=NULL;elem=elem->next){
         add_headers(op,(belle_sip_header_t*)elem->data,msg);
      }
      belle_sip_list_free(l);
   }
}

此处会检查op->base.sent_custom_headers是否存在自定义头消息,
如果有,调用add_headers去添加到request结构体里面, sal_op_impl.c line286;

static void add_headers(SalOp *op, belle_sip_header_t *h, belle_sip_message_t *msg){
    char* header_string=belle_sip_object_to_string(h);
    ms_message("add_headers  [%s]",header_string);
   if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_contact_t)){
      belle_sip_header_contact_t* newct;
      /*special case for contact, we want to keep everything from the custom contact but set automatic mode and add our own parameters as well*/
      sal_op_set_contact_address(op,(SalAddress*)BELLE_SIP_HEADER_ADDRESS(h));
      newct = sal_op_create_contact(op);
      belle_sip_message_set_header(BELLE_SIP_MESSAGE(msg),BELLE_SIP_HEADER(newct));
      return;
   }
   /*if a header already exists in the message, replace it*/
   belle_sip_message_set_header(msg,h);
}

此处自定义头消息非联系人类型的,所以直接进入最下面的belle_sip_message_set_header(msg,h);

void belle_sip_message_set_header(belle_sip_message_t *msg, belle_sip_header_t* header){
    char* header_string=belle_sip_object_to_string(header);
    belle_sip_message("belle_sip_message_set_header [%s]",header_string);
   headers_container_t *headers_container=get_or_create_container(msg,belle_sip_header_get_name(header));
   belle_sip_object_ref(header);
   headers_container->header_list=belle_sip_list_free_with_data(headers_container->header_list,belle_sip_object_unref);
   headers_container->header_list=belle_sip_list_append(headers_container->header_list,header);
}

到这里自定义的头消息就通过belle_sip_list_append追加到msg下了, msg就是之前创建的request结构体。

后面的sip消息发送就是通过request中的元素去拼接的,这里暂时不看了,

总结:
1、首先通过创建一个LinphoneCall对象,并将LinphoneCallParam保存到call->params下面,
2、然后创建一个SalOp对象,并见call->params中的很多配置信息复制到op中,其中包括将params->custom_headers链表中的很多头消息SalCustomHeader对象,保存到op.base->sent_custom_headers链表中;
3、最后通过sal_op_send_request()来构建一个belle_sip_request_t结构体,并将op.base->sent_custom_headers中的头消息保存到request->headers_container->header_list里面。
4、linphone最终发送sip请求的时候都是从这个request中来取值并完成消息体的拼接的。

三、如何在java层获取去电请求中增加的自定义头消息

linphone的java层提供了直接读取自定义头的方法。
首先需要知道的是,发起去掉后,linphone会通过LinphoneCoreListener中的callState()接口来回调通话过程状态变化的

public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) {
            Logs.d(TAG, "callState state = [" + state + "] , message = " + message);

            LinphoneCallParams params = VoipManager.getLc().createCallParams(call);
            String extraData = StringTools.decodeStringFromBase64(params.getCustomHeader("x-extraData"));

        }

只要是按照linphone提供的LinphoneCallParam.addCustomHeader(“name”,”value”)添加的自定义头消息,都可以通过LinphoneCallParam.getCustomHeader(“name”),来读取到对应的name值。

注:这里我们在读取数据后进行了base64解码,主要是因为如果想在sip消息体中添加json、xml等其他格式的字符串时,会造成SIP消息格式的异常,所以需要进行base64的转码传输,另外base64在转后后会在字符串尾部追加一个’\n’,需要剔除,否则也会造成sip格式异常
————————————————

上一篇:Linphone-android 登录过程增加自定义消息头流程分析_今人不见古时月,今月曾经照古人的博客-CSDN博客

转载于:https://blog.csdn.net/yfloctar/article/details/78684535

猜你喜欢

转载自blog.csdn.net/weixin_42602900/article/details/126059375