当前位置:   article > 正文

Linphone android去电增加自定义SIP消息头的流程分析_linphone 电话 callparams参数设置

linphone 电话 callparams参数设置

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

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

发起呼叫的示例如下:

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

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

  1. extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_addCustomHeader(JNIEnv *env, jobject thiz, jlong lcp, jstring         jheader_name, jstring jheader_value){
  2.    const char* header_name = GetStringUTFChars(env, jheader_name);
  3.    const char* header_value = GetStringUTFChars(env, jheader_value);
  4.    linphone_call_params_add_custom_header((LinphoneCallParams*)lcp,header_name,header_value);
  5.    ReleaseStringUTFChars(env, jheader_name, header_name);
  6.    ReleaseStringUTFChars(env, jheader_value, header_value);
  7. }

linphone_call_params_add_custom_header(),位于call_params.c中;

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

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

  1. SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){
  2.    belle_sip_message_t *msg=(belle_sip_message_t*)ch;
  3.    belle_sip_header_t *h;
  4.    if (msg==NULL){
  5.       msg=(belle_sip_message_t*)belle_sip_request_new();
  6.       belle_sip_object_ref(msg);
  7.    }
  8.    h=belle_sip_header_create(name,value);
  9.    if (h==NULL){
  10.       belle_sip_error("Fail to parse custom header.");
  11.       return (SalCustomHeader*)msg;
  12.    }
  13.    belle_sip_message_add_header(msg,h);
  14.    return (SalCustomHeader*)msg;
  15. }

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

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。

  1. LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params){
  2.     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);
  3.    const char *from=NULL;
  4.    LinphoneProxyConfig *proxy=NULL;
  5.    LinphoneAddress *parsed_url2=NULL;
  6.    char *real_url=NULL;
  7.    LinphoneCall *call;
  8.    bool_t defer = FALSE;
  9.    LinphoneCallParams *cp;
  10.    ......
  11.    cp = linphone_call_params_copy(params);
  12.     ......
  13.    /* if no proxy or no identity defined for this proxy, default to primary contact*/
  14.    if (from==NULL) from=linphone_core_get_primary_contact(lc);
  15.    parsed_url2=linphone_address_new(from);
  16.    call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),cp,proxy);
  17.    ......
  18.    /* this call becomes now the current one*/
  19.    lc->current_call=call;
  20.    linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call");
  21.    call->log->start_date_time=ms_time(NULL);
  22.    linphone_call_init_media_streams(call);
  23. ...
  24.    if (defer==FALSE) {
  25.       if (linphone_core_start_invite(lc,call,NULL) != 0){
  26.          /*the call has already gone to error and released state, so do not return it*/
  27.          call = NULL;
  28.       }
  29.    }
  30.    if (real_url!=NULL) ms_free(real_url);
  31.    linphone_call_params_destroy(cp);
  32.    return call;
  33. }

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

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

  1. LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){
  2.    ms_message("linphone_call_new_outgoing");
  3.    LinphoneCall *call = belle_sip_object_new(LinphoneCall);
  4.    call->dir=LinphoneCallOutgoing;
  5.    call->core=lc;
  6.    call->dest_proxy=cfg;
  7.    linphone_call_outgoing_select_ip_version(call,to,cfg);
  8.    linphone_call_get_local_ip(call, to);
  9.    call->params = linphone_call_params_copy(params);
  10.    linphone_call_init_common(call, from, to);
  11. ...
  12.    discover_mtu(lc,linphone_address_get_domain (to));
  13.    if (params->referer){
  14.       call->referer=linphone_call_ref(params->referer);
  15.    }
  16.    linphone_call_create_op(call);
  17.    return call;
  18. }

这里会构建一个新的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;

  1. void linphone_call_create_op(LinphoneCall *call){
  2.     if (call->op) sal_op_release(call->op);
  3.     call->op=sal_op_new(call->core->sal);
  4.     sal_op_set_user_pointer(call->op,call);
  5.     if (call->params->referer)
  6.         sal_call_set_referer(call->op,call->params->referer->op);
  7.     linphone_configure_op(call->core,call->op,call->log->to,call->params->custom_headers,FALSE);
  8.     if (call->params->privacy != LinphonePrivacyDefault)
  9.         sal_op_set_privacy(call->op,(SalPrivacyMask)call->params->privacy);
  10.     /*else privacy might be set by proxy */
  11. }

这里会通过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;

  1. void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact){
  2.    ms_message("linphone_config_op");
  3.    bctbx_list_t *routes=NULL;
  4.    LinphoneProxyConfig *proxy=linphone_core_lookup_known_proxy(lc,dest);
  5.    const char *identity;
  6.     ......
  7.    sal_op_set_to_address(op,dest);
  8.    sal_op_set_token(op,token);
  9.    sal_op_set_from(op,identity);
  10.    ms_message("identity = %s  sal_token = %s",identity,((SalOpBase*)op)->token);
  11.    sal_op_set_sent_custom_header(op,headers);
  12.    sal_op_set_realm(op,linphone_proxy_config_get_realm(proxy));
  13.     ......
  14. }

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

  1. void sal_op_set_sent_custom_header(SalOp *op, SalCustomHeader* ch){
  2.    SalOpBase *b=(SalOpBase *)op;
  3.    if (b->sent_custom_headers){
  4.       sal_custom_header_free(b->sent_custom_headers);   
  5.       b->sent_custom_headers=NULL;      
  6.    }
  7.    if (ch) belle_sip_object_ref((belle_sip_message_t*)ch);
  8.    b->sent_custom_headers=ch;
  9. }

过程比较简单,就是将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,

  1. int sal_call(SalOp *op, const char *from, const char *to){
  2. ......
  3.    invite=sal_op_build_request(op,"INVITE");
  4.    sal_op_fill_invite(op,invite);
  5.    sal_op_call_fill_cbs(op);
  6.  ...
  7.    return sal_op_send_request(op,invite);
  8. }


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

  1. int sal_op_send_request(SalOp* op, belle_sip_request_t* request)  {
  2.     belle_sip_message("sal_op_send_request");
  3.    bool_t need_contact=FALSE;
  4.    if (request==NULL) {
  5.       return -1; /*sanity check*/
  6.    }
  7.    if (strcmp(belle_sip_request_get_method(request),"INVITE")==0
  8.          ||strcmp(belle_sip_request_get_method(request),"REGISTER")==0
  9.          ||strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0
  10.          ||strcmp(belle_sip_request_get_method(request),"OPTIONS")==0
  11.          ||strcmp(belle_sip_request_get_method(request),"REFER")==0) /* Despite contact seems not mandatory, call flow example show a Contact in REFER requests*/
  12.       need_contact=TRUE;
  13.    return _sal_op_send_request_with_contact(op, request,need_contact);
  14. }

因为是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),

  1. void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){
  2.     ms_message("_sal_op_add_custom_headers");
  3.    if (op->base.sent_custom_headers){
  4.       belle_sip_message_t *ch=(belle_sip_message_t*)op->base.sent_custom_headers;
  5.       belle_sip_list_t *l=belle_sip_message_get_all_headers(ch);
  6.       belle_sip_list_t *elem;
  7.       for(elem=l;elem!=NULL;elem=elem->next){
  8.          add_headers(op,(belle_sip_header_t*)elem->data,msg);
  9.       }
  10.       belle_sip_list_free(l);
  11.    }
  12. }

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

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

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

  1. void belle_sip_message_set_header(belle_sip_message_t *msg, belle_sip_header_t* header){
  2.     char* header_string=belle_sip_object_to_string(header);
  3.     belle_sip_message("belle_sip_message_set_header [%s]",header_string);
  4.    headers_container_t *headers_container=get_or_create_container(msg,belle_sip_header_get_name(header));
  5.    belle_sip_object_ref(header);
  6.    headers_container->header_list=belle_sip_list_free_with_data(headers_container->header_list,belle_sip_object_unref);
  7.    headers_container->header_list=belle_sip_list_append(headers_container->header_list,header);
  8. }

到这里自定义的头消息就通过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()接口来回调通话过程状态变化的

  1. public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) {
  2.             Logs.d(TAG, "callState state = [" + state + "] , message = " + message);
  3.             LinphoneCallParams params = VoipManager.getLc().createCallParams(call);
  4.             String extraData = StringTools.decodeStringFromBase64(params.getCustomHeader("x-extraData"));
  5.         }

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

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

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

下一篇:Linphone 被叫方如何解析来电SIP消息中的自定义头消息_今人不见古时月,今月曾经照古人的博客-CSDN博客

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

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号