一、首先看一下如何在发起去电的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