赞
踩
增加自定义头消息发方法,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是一个链表结构
发起呼叫是通过 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中来取值并完成消息体的拼接的。
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博客
下一篇:Linphone 被叫方如何解析来电SIP消息中的自定义头消息_今人不见古时月,今月曾经照古人的博客-CSDN博客
转载于:https://blog.csdn.net/yfloctar/article/details/78684535
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。