您的位置:首页 > 移动开发 > Android开发

Linphone 被叫方如何解析来电SIP消息中的自定义头消息

2017-12-01 15:38 1086 查看
linphone源码中其实暂无提供自定义头消息的解析功能,所以这里需要添加一部分代码,至于在什么地方添加自定义头消息,就需要了解linphone处理来电的sip请求的过程。

个人梳理了下大概分为以下几个过程:

接到请求后,从socket中解析出完整的SIP字符串,经过多次转换后生成event类型的结构体

归类到INVITE类型的event后,通过provider来处理,过程中会生成SalOp对象。

生成JAVA层可以使用的LinphoneCall对象后,通过callState()接口回调给java层;

第一部分

首先看接收到来电INVITE类型的SIP请求时,触发了什么?

通过底层的log,来电后大致会触发到belle_sip_channel_process_data,位于channel.c line 705;

int belle_sip_channel_process_data(belle_sip_channel_t *obj,unsigned int revents){
belle_sip_message("belle_sip_channel_process_data");
int ret=BELLE_SIP_CONTINUE;
if (revents & BELLE_SIP_EVENT_READ) {
int rret=belle_sip_channel_process_read_data(obj);
if (rret==BELLE_SIP_STOP) ret=BELLE_SIP_STOP;
}
if (revents & BELLE_SIP_EVENT_WRITE){
/*if we are here, this is because we had an EWOULDBLOCK while sending a message*/
/*continue to send pending messages but before check the channel is still alive because
it may have been closed by belle_sip_channel_process_read_data() above.*/
if (obj->state == BELLE_SIP_CHANNEL_READY){
channel_process_queue(obj);
}
}
return ret;
}


入参的obj是已经经过初步解析的来电请求,revents是来电的事件类别;这里是一个READ的事件;

进入belle_sip_channel_process_read_data(obj);

static int belle_sip_channel_process_read_data(belle_sip_channel_t *obj){
belle_sip_message("belle_sip_channel_process_read_data");
int num;
int ret=BELLE_SIP_CONTINUE;

/*prevent system to suspend the process until we have finish reading everything from the socket and notified the upper layer*/
if (obj->input_stream.state == WAITING_MESSAGE_START) {
channel_begin_recv_background_task(obj);
}

if (obj->simulated_recv_return>0) {
num=belle_sip_channel_recv(obj,obj->input_stream.write_ptr,belle_sip_channel_input_stream_get_buff_length(&obj->input_stream)-1);
} else {
belle_sip_message("channel [%p]: simulating recv() returning %i",obj,obj->simulated_recv_return);
num=obj->simulated_recv_return;
}
if (num>0){
char *begin=obj->input_stream.write_ptr;
obj->input_stream.write_ptr+=num;
/*first null terminate the read buff*/
*obj->input_stream.write_ptr='\0';
....
belle_sip_channel_process_stream(obj,FALSE);
if (obj->input_stream.state == WAITING_MESSAGE_START){
channel_end_recv_background_task(obj);
}/*if still in message acquisition state, keep the backgroud task*/
}
......
return ret;
}


过程分析:

1、因为是刚接收到来电,通过channel_begin_recv_background_task(obj),这个主要是开启android的wake lock,

2、进入belle_sip_channel_recv(xxxx),这个过程主要是根据obj中存的的channel_recv回调,我们这边使用的是udp,所以这里最终是调用了udp_channel_recv(obj,buf,buflen),在udp_channel.c中,将obj此时指定的socket中的sip消息读取并存到obj->input_stream.write_ptr中,返回值是读取的消息长度;

3、判断是否读取到消息,也就是num>0?如果有的话,调用belle_sip_channel_process_stream(obj,FALSE);

4、最后调用channel_end_recv_background_task(obj)来关闭android的wake lock;

接着看第三步的belle_sip_channel_process_stream(obj,FALSE);

static void belle_sip_channel_process_stream(belle_sip_channel_t *obj, int eos){
belle_sip_channel_parse_stream(obj,eos);
if (obj->incoming_messages) {
if (obj->simulated_recv_return == 1500) {
belle_sip_list_t *elem;
for(elem=obj->incoming_messages;elem!=NULL;elem=elem->next){
belle_sip_message_t *msg=(belle_sip_message_t*)elem->data;
char* dump = belle_sip_message_to_string(msg);
belle_sip_message("Silently discarding incoming message [%.50s...] on channel [%p]",dump, obj);
belle_sip_free(dump);
}
belle_sip_list_free_with_data(obj->incoming_messages,belle_sip_object_unref);
obj->incoming_messages=NULL;
} else {
notify_incoming_messages(obj);
}
}
}


过程分析:

1、调用belle_sip_channel_parse_stream(obj,eos)来进行第一次的解析;

2、调用notify_incoming_messages(obj)来通知有来电接入;

先看第一步的belle_sip_channel_parse_stream(obj,eos); 还在channel.c中;

void belle_sip_channel_parse_stream(belle_sip_channel_t *obj, int end_of_stream){
belle_sip_message("belle_sip_channel_parse_stream");
int offset;
size_t read_size=0;
int num;

while ((num=(int)(obj->input_stream.write_ptr-obj->input_stream.read_ptr))>0){
// belle_sip_message("num = %i",num);
if (obj->input_stream.state == WAITING_MESSAGE_START) {
int i;
/*first, make sure there is \r\n in the buffer, otherwise, micro parser cannot conclude, because we need a complete request or response line somewhere*/
for (i=0;i<num-1;i++) {
if ((obj->input_stream.read_ptr[i]=='\r' && obj->input_stream.read_ptr[i+1]=='\n')
|| belle_sip_channel_input_stream_get_buff_length(&obj->input_stream) <= 1 /*1 because null terminated*/  /*if buffer full try to parse in any case*/) {
/*good, now we can start searching  for request/response*/
if ((offset=get_message_start_pos(obj->input_stream.read_ptr,num)) >=0 ) {
// belle_sip_message("log 1");
/*message found !*/
if (offset>0) {
belle_sip_warning("trashing [%i] bytes in front of sip message on channel [%p]",offset,obj);
obj->input_stream.read_ptr+=offset;
}
obj->input_stream.state=MESSAGE_AQUISITION;
} else {
......
}
break;
}
}
......
if (obj->input_stream.state==MESSAGE_AQUISITION) {
/*search for \r\n\r\n*/
char* end_of_message=NULL;
if ((end_of_message=strstr(obj->input_stream.read_ptr,"\r\n\r\n"))){
......
obj->input_stream.msg=belle_sip_message_parse_raw(obj->input_stream.read_ptr
,bytes_to_parse
,&read_size);
*end_of_message=tmp;
obj->input_stream.read_ptr+=read_size;
....
}else break; /*The message isn't finished to be receive, we need more data*/
}

if (obj->input_stream.state==BODY_AQUISITION) {
if (acquire_body(obj,end_of_stream)==BELLE_SIP_STOP) break;
}
}
}


过程分析:

第一个if中,大致是在初始化obj->input_stream.read_ptr,并将obj->input_stream.state改为MESSAGE_AQUISITION;

第二个if中,通过belle_sip_message_parse_raw()来解析sip消息,并存储到obj->input_stream.msg中;

最后调用acquire_body(),内部调用acquire_body_simple(obj,eos),内部调用belle_sip_channel_message_ready(obj)来将obj->input_stream.msg中的数据设置到obj->incoming_messages中,并释放掉obj->input_stream中的资源;

关于第二个if中调用的belle_sip_message_parse_raw();

belle_sip_message_t* belle_sip_message_parse_raw (const char* buff, size_t buff_length,size_t* message_length ) { \
pANTLR3_INPUT_STREAM           input;
pbelle_sip_messageLexer               lex;
pANTLR3_COMMON_TOKEN_STREAM    tokens;
pbelle_sip_messageParser              parser;
belle_sip_message_t* l_parsed_object;
input  = ANTLR_STREAM_NEW("message",buff,buff_length);
lex    = belle_sip_messageLexerNew                (input);
tokens = antlr3CommonTokenStreamSourceNew  (1025, lex->pLexer->rec->state->tokSource);
parser = belle_sip_messageParserNew               (tokens);
belle_sip_message("belle_sip_message_parse_raw buff ");
l_parsed_object = parser->message_raw(parser,message_length);
belle_sip_message("belle_sip_message_parse_raw message_raw done ");
/* if (*message_length < buff_length) {*/
/*there is a body*/
/*    l_parsed_object->body_length=buff_length-*message_length;
l_parsed_object->body = belle_sip_malloc(l_parsed_object->body_length+1);
memcpy(l_parsed_object->body,buff+*message_length,l_parsed_object->body_length);
l_parsed_object->body[l_parsed_object->body_length]='\0';
}*/
parser ->free(parser);
tokens ->free(tokens);
lex    ->free(lex);
input  ->close(input);
return l_parsed_object;
}


这里具体是怎么执行的,不是很明确,大致会通过parse->message_raw()来读取sip消息,这个函数接口的最终实现是在belle_sip_messageParser.c中,有一个

message_header(pbelle_sip_messageParser ctx,belle_sip_message_t* message)

函数内有下面一段:

belle_sip_header_t* lheader = BELLE_SIP_HEADER(header_extension_base10);
do {
if (lheader == NULL) break; /*sanity check*/
belle_sip_message("message_header arm 167619");
belle_sip_message_add_header(message,lheader);
}
while((lheader=belle_sip_header_get_next(lheader)) != NULL);


所以这里会通过lheader指针,来遍历obj->input_streams.read_ptr指向的sip消息的每一行,然后将每一行的内容通过belle_sip_message_add_header()来添加到belle_sip_message_t*的结构体中,并最终返回给obj->input_stream.msg中;

到这里belle_sip_channel_parse_stream(obj,eos)过程结束;

sip消息被保存在obj->incoming_messages中了,是个belle_sip_list_t的结构体;

接着看第二步的notify_incoming_messages(obj);位于channel.c line513;

static void notify_incoming_messages(belle_sip_channel_t *obj){
belle_sip_list_t *elem,*l_it;

belle_sip_list_t *listeners=belle_sip_list_copy_with_data(obj->full_listeners,(void *(*)(void*))belle_sip_object_ref);

for(l_it=listeners;l_it!=NULL;l_it=l_it->next){
belle_sip_channel_listener_t *listener=(belle_sip_channel_listener_t*)l_it->data;
for(elem=obj->incoming_messages;elem!=NULL;elem=elem->next){
belle_sip_message_t *msg=(belle_sip_message_t*)elem->data;
BELLE_SIP_INTERFACE_METHODS_TYPE(belle_sip_channel_listener_t) *methods;
methods=BELLE_SIP_INTERFACE_GET_METHODS(listener,belle_sip_channel_listener_t);
if (methods->on_message)
methods->on_message(listener,obj,msg);
}
}
belle_sip_list_free_with_data(listeners,belle_sip_object_unref);
belle_sip_list_free_with_data(obj->incoming_messages,belle_sip_object_unref);
obj->incoming_messages=NULL;
}


过程分析:

1、首先找出obj->full_listeners下指定的所有需要处理sip消息的回调,

2、然后遍历listeners和obj->incoming_messages,执行listener下指定的on_message(listener,obj,msg),

3、最后释放到obj->incoming_messages;

对于来电呼叫,这里的msg实际上就是obj->incoming_messages里面的内容,这里的on_message对应的是channel_on_message() 位于provider.c中;

static void channel_on_message(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){
belle_sip_message("channel_on_message");
belle_sip_object_ref(msg);
belle_sip_provider_dispatch_message(BELLE_SIP_PROVIDER(obj),msg);
}


只是作了一个消息分发,同时将obj转成BELLE_SIP_PROVIDER_T结构体;

void belle_sip_provider_dispatch_message(belle_sip_provider_t *prov, belle_sip_message_t *msg){
belle_sip_message("belle_sip_provider_dispatch_message");
if (TRUE
#ifndef BELLE_SIP_DONT_CHECK_HEADERS_IN_MESSAGE
&& belle_sip_message_check_headers(msg)
#endif
){
if (belle_sip_message_is_request(msg)){
belle_sip_provider_dispatch_request(prov,(belle_sip_request_t*)msg);
}else{
belle_sip_provider_dispatch_response(prov,(belle_sip_response_t*)msg);
}
}else{
/* incorrect message received, answer bad request if it was a request.*/
if (belle_sip_message_is_request(msg)){
belle_sip_response_t *resp=belle_sip_response_create_from_request(BELLE_SIP_REQUEST(msg),400);
if (resp){
belle_sip_provider_send_response(prov,resp);
}
}/*otherwise what can we do ?*/
}
belle_sip_object_unref(msg);
}


因为是sip呼入,这里是一个request请求,进入belle_sip_provider_dispatch_request(prov,msg);

static void belle_sip_provider_dispatch_request(belle_sip_provider_t* prov, belle_sip_request_t *req){
belle_sip_message("belle_sip_provider_dispatch_request");
belle_sip_server_transaction_t *t;
belle_sip_request_event_t ev;
t=belle_sip_provider_find_matching_server_transaction(prov,req);
if (t){
belle_sip_object_ref(t);
belle_sip_server_transaction_on_request(t,req);
belle_sip_object_unref(t);
}else{
const char *method=belle_sip_request_get_method(req);
ev.dialog=NULL;
/* Should we limit to ACK ?  */
/*Search for a dialog if exist */

if (strcmp("CANCEL",method) == 0) {
/* Call leg does not exist */
belle_sip_server_transaction_t *tr = belle_sip_provider_create_server_transaction(prov, req);
belle_sip_server_transaction_send_response(tr, belle_sip_response_create_from_request(req, 481));
return;
}

......
if (prov->unconditional_answer_enabled && strcmp("ACK",method)!=0) { /*always answer predefined value (I.E 480 by default)*/
belle_sip_server_transaction_t *tr=belle_sip_provider_create_server_transaction(prov,req);
belle_sip_server_transaction_send_response(tr,belle_sip_response_create_from_request(req,prov->unconditional_answer));
return;
} else {
ev.source=(belle_sip_object_t*)prov;
ev.server_transaction=NULL;
ev.request=req;

BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_request_event,&ev);
}
}
}


过程简单分析:

1、第一个”CANCEL”判断的地方,创建了一个belle_sip_server_transaction_t对象,并执行了belle_sip_server_transaction_send_response()。是针对接收到来电后回执一个sip消息,具体的操作暂不细究了;

2、最后构建了一个belle_sip_request_event_t*对象,通过BELLE_SIP_PROVIDER_INVOKE_LISTENERS执行对应一个process_request_event()接口;

注意原来保存sip消息的msg已经被转换成belle_sip_message_t结构体,并保存在ev.request下了

到这里,个人理解,针对sip消息解析的第一个过程基本结束,完成了从socket中读取SIP消息字符串,生成了一个表示request事件的结构体,来保存完整的SIP消息。后面通过找到处理这一类event的provider来处理这个请求。

第二部分

BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_request_event,&ev)是个宏,prov是之前的ojb

#define BELLE_SIP_PROVIDER_INVOKE_LISTENERS(listeners,callback,event) \
BELLE_SIP_INVOKE_LISTENERS_ARG((listeners),belle_sip_listener_t,callback,(event))

#define BELLE_SIP_INVOKE_LISTENERS_ARG(list,interface_name,method,arg) \
__BELLE_SIP_INVOKE_LISTENER_BEGIN(list,interface_name,method)\
method(__obj,arg);\
__BELLE_SIP_INVOKE_LISTENER_END;


这个宏最终是调用method方法,这里的method的就是process_request_event()。入参的arg就是&ev,至于_obj是哪里来的,在上一句 __BELLE_SIP_INVOKE_LISTENER_BEGIN(XXXXX);

#define __BELLE_SIP_INVOKE_LISTENER_BEGIN(list,interface_name,method) \
if (list!=NULL) {\
belle_sip_list_t *__copy=belle_sip_list_copy_with_data((list), (void* (*)(void*))belle_sip_object_ref);\
const belle_sip_list_t *__elem=__copy;\
do{\
void *__method;\
interface_name *__obj=(interface_name*)__elem->data;\
__method=BELLE_SIP_INTERFACE_GET_METHODS(__obj,interface_name)->method;\
if (__method) BELLE_SIP_INTERFACE_GET_METHODS(__obj,interface_name)->

#define __BELLE_SIP_INVOKE_LISTENER_END \
__elem=__elem->next;\
}while(__elem!=NULL);\
belle_sip_list_free_with_data(__copy,belle_sip_object_unref);\
}


这里的_obj是通过遍历prov->listeners,找到每个listener下的data对象。

至于这个data对象在哪里设置的,暂时没找到,通过log找到这里的method调用的是sal_impl.c下的:

process_request_event(void*, belle_sip_request_event_t * event)

process_request_event(void*,   belle_sip_request_event_t * event);
static void process_request_event(void *ud, const belle_sip_request_event_t *event) {
Sal *sal=(Sal*)ud;
SalOp* op=NULL;
belle_sip_request_t* req = belle_sip_request_event_get_request(event);
......
if (strcmp("INVITE",method)==0) {
op=sal_op_new(sal);
op->dir=SalOpDirIncoming;
sal_op_call_fill_cbs(op);
}
sal_op_assign_recv_headers(op,(belle_sip_message_t*)req);
if (op->callbacks && op->callbacks->process_request_event) {
op->callbacks->process_request_event(op,event);
} else {
ms_error("sal process_request_event not implemented yet");
}
}


部分过程省略:

1、构建一个空SalOp对象,以及获取event中保存的完整sip消息结构体 request;

2、如果是invite类型的消息,初始化一个新的SalOp对象,然后通过sal_op_call_fill_cbs(op)补充op下的回调callbacks,这里的回调接口实现全部都在sal_op_call.c下;

3、填充op中的属性值,包括from、to等一系列基础信息;

4、调用sal_op_assign_recv_headers()将req中的消息头全部填入到op中,后面就直接使用op中的数据来反馈来电给java层了

5、调用op->callbacks中的process_request_event(op,event);

重点看一下过程4中的:

void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming){
if (incoming) belle_sip_object_ref(incoming);
if (op->base.recv_custom_headers){
belle_sip_object_unref(op->base.recv_custom_headers);
op->base.recv_custom_headers=NULL;
}
if (incoming){
op->base.recv_custom_headers=(SalCustomHeader*)incoming;
}
}


入参就是之前的request里面的message,将其保存到op->base.recv_custom_headers下;

接着就调用了op->callbacks下的process_requset_event();

static void process_request_event(void *op_base, const belle_sip_request_event_t *event) {
SalOp* op = (SalOp*)op_base;
belle_sip_server_transaction_t* server_transaction=NULL;
belle_sdp_session_description_t* sdp;
belle_sip_request_t* req = belle_sip_request_event_get_request(event);
belle_sip_dialog_state_t dialog_state;
belle_sip_response_t* resp;
belle_sip_header_t* call_info;
const char *method=belle_sip_request_get_method(req);
......
dialog_state=belle_sip_dialog_get_state(op->dialog);
switch(dialog_state) {
case BELLE_SIP_DIALOG_NULL: {
if (strcmp("INVITE",method)==0) {
......
if (process_sdp_for_invite(op,req) == 0) {
if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) {
if( strstr(belle_sip_header_get_unparsed_value(call_info),"answer-after=") != NULL) {
op->auto_answer_asked=TRUE;
ms_message("The caller asked to automatically answer the call(Emergency?)\n");
}
}
op->base.root->callbacks.call_received(op);
}else{
/*the INVITE was declined by process_sdp_for_invite(). As we are not inside an established dialog, we can drop the op immediately*/
drop_op = TRUE;
}
break;
} /* else same behavior as for EARLY state, thus NO BREAK*/
}
.......
default:
ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
break;
}
if (server_transaction) belle_sip_object_unref(server_transaction);
if (drop_op) sal_op_release(op);
}


部分过程省略了,关键两个步骤,

1、process_sdp_for_invite(op,req),判断这个request是不是invite类型的sdp请求;

2、如果是调用op下的base属性中的root->callbacks.call_received(op);

到这里,个人理解,第二个环节的处理基本完成,通过provider将接收到的event再次解析并重新构建了一个SalOp对象,而来电请求完整的SIP消息体,被保存在op->base.recv_custom_headers链表中。

第三部分

回调给JAVA层;

上一步最后执行的call_received(op)位于callbacks.c line263

static void call_received(SalOp *h){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
LinphoneCall *call;
LinphoneCall *replaced_call;
char *alt_contact;
LinphoneAddress *from_addr=NULL;
LinphoneAddress  *to_addr=NULL;
LinphoneAddress *from_address_to_search_if_me=NULL; /*address used to know if I'm the caller*/
SalMediaDescription *md;
const char * p_asserted_id;
..........
call=linphone_call_new_incoming(lc,from_addr,to_addr,h);
...
linphone_core_add_call(lc,call);
...
linphone_core_notify_incoming_call(lc,call);
}


过程分析:

1、根据传进来的SalOp,并解析了其中的通话信息,通过linphone_call_new_incoming()构建LinphoneCall对象;

2、通过linphone_core_add_call()将该call添加到linphonecore中;

3、最后通过linphone_core_notify_incoming_call(lc,call),将来电信息传递到上层java中;

先看第一步:linphone_call_new_incoming

LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
LinphoneCall *call = belle_sip_object_new(LinphoneCall);
SalMediaDescription *md;
LinphoneNatPolicy *nat_policy = NULL;
int i;
call->dir=LinphoneCallIncoming;
sal_op_set_user_pointer(op,call);
call->op=op;
call->core=lc;

call->dest_proxy = linphone_core_lookup_known_proxy(call->core, to);
linphone_call_incoming_select_ip_version(call, call->dest_proxy);
/*note that the choice of IP version for streams is later refined by
* linphone_call_set_compatible_incoming_call_parameters() when examining the remote offer, if any.
* If the remote offer contains IPv4 addresses, we should propose IPv4 as well*/

sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0));

md = sal_call_get_remote_media_description(op);

if (lc->sip_conf.ping_with_options){
#ifdef BUILD_UPNP
if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
#else //BUILD_UPNP
{
#endif //BUILD_UPNP
/*the following sends an option request back to the caller so that
we get a chance to discover our nat'd address before answering.*/
call->ping_op=sal_op_new(lc->sal);

linphone_configure_op(lc, call->ping_op, from, NULL, FALSE);

sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
sal_op_set_user_pointer(call->ping_op,call);

sal_ping(call->ping_op,sal_op_get_from(call->ping_op), sal_op_get_to(call->ping_op));
}
}

linphone_address_clean(from);
linphone_call_get_local_ip(call, from);
call->params = linphone_call_params_new();
linphone_call_init_common(call, from, to);
call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
linphone_core_init_default_params(lc, call->params);

/*增加自定义的消息头解析*/
const char * extra_data;
extra_data = sal_custom_header_find(sal_op_get_recv_custom_header(op),"x-extraData");
if(extra_data){
linphone_call_params_add_custom_header(call->params,"x-extraData",extra_data);
}

/*
* Initialize call parameters according to incoming call parameters. This is to avoid to ask later (during reINVITEs) for features that the remote
* end apparently does not support. This features are: privacy, video
*/
/*set privacy*/
call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op);
/*config params*/
call->current_params->update_call_when_ice_completed = call->params->update_call_when_ice_completed; /*copy config params*/

/*set video support */
call->params->has_video = linphone_core_video_enabled(lc) && lc->video_policy.automatically_accept;
if (md) {
......
}
......
discover_mtu(lc,linphone_address_get_domain(from));
return call;
}


a、通过belle_sip_object_new()构建一个空的LinphoneCall对象,然后关联SalOp和LinhoneCore;

b、然后通过linphone_call_params_new()构建一个LinphoneCallParams对象,并关联到call->params下,再通过linphone_call_init_common()和linphone_core_init_default_params()来初始化LinphoneCallParams的配置;

c、后面还有一些配置media属性的操作,暂时不看了。

参考发起呼叫时添加自定义头消息的过程,自定义的消息头是存放在LinphoneCall下的LinphoneCallParams的,并且通话过程中的状态回调每次都会回调LinphoneCall对象。

所以如果要解析来电中的自定义头消息,可以将解析出来的消息头存放在这里构建出来的LinphoneCallParams中;

/*增加自定义的消息头解析*/
const char * extra_data;
extra_data = sal_custom_header_find(sal_op_get_recv_custom_header(op),"x-extraData");
ms_message("extra_data = %s ",extra_data);
if(extra_data){
linphone_call_params_add_custom_header(call->params,"x-extraData",extra_data);
}


用的linphone源码中自带的一些函数

sal_op_get_recv_custom_header(op),是获取op.base->recv_custom_header对象,其实就是存的sip完整消息;

sal_custom_header_find(xx,”x-extraData”);查找sip消息中字段名为:x-extraData的字符串值;

如果这个字段存在,通过linphone_call_params_add_custom_header()将这个key和value保存到call->params下的custom_headers;

再看call_received中的第二步:linphone_core_add_call(lc,call)

其实就是关联lc和call,将当前的call保存到lc->calls下的链表中;

最后第三步:linphone_core_notify_incoming_call()

简单说这个过程的流程:

内部调用linphone_call_set_stata(LinphoneCall,LinphoneCallState,char

message),将当前的通话状态设置为LinphoneCallIncomingReceived

内部调用linphone_core_notify_call_state_changed(lc,call,cstate,message)来通知通话状态已修改,

内部调用NOTIFY_IF_EXIST(call_state_changed,lc,call,cstate,message);

NOTIFY_IF_EXIST是个宏,第一个参数是方法名,后面的是他的参数,这里调用的就是call_state_changed()接口,

NOTIFY_IF_EXIST宏内可以调用的方法,都定义在linphonecore_jni.cc中的LinphoneCoreTable下:

vTable->call_state_changed = callStateChange;


在callStateChange中通过反射的方式,加载了LinphoneCoreListenerBase下的call_State()回调。

最后我们就可以在java层获取来电sip消息中的自定义字段值,

public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) {
LinphoneCallParams params = VoipManager.getLc().createCallParams(call);
String extraData = StringTools.decodeStringFromBase64(params.getCustomHeader("x-extraData"));
}


使用LinphoneCallParams自带的getCustomHeader()就可以获取指定key的头消息值。

注意:如果自定义消息想直接传json或者xml等其他格式的字符串,会造成sip格式解析异常,所以这里做了base64编码转换,另外base64转码后会在字符串尾部多一个’\n’,也会影响sip解析,需要去掉

全流程总结:

来电的sip请求触发后,消息数据最先保存在一个belle_sip_channel_t下的input_stream中,经过初步解析成字符串后,保留到该结构体下的incoming_messages属性中,多次转换后生成一个表示event事件的belle_sip_request_event_t结构体,

通过预先设置的provider来处理这个event结构体,过程中构建了一个SalOp对象,将这部分消息头字符串保存到了这个op下的SalOpBase结构体中的recv_custom_headers属性下,通过provider分析后确认这是一个invite类型的call,后调用预先设置的call_received接口去处理。

在call_received()中构建一个java层可用的LinphoneCallParams和LinphoneCall对象,同时从op中解析需要传递给java层的数据,填充到LinphoneCallParams对象中,这个param也被关联到call下,

最终通过callState()回调接口,将来电信息回调给java层

linphone源码中是不包含自定义头的数据解析和填充的,我们只需要参考发起呼叫时添加的自定义头消息的存储方式,将来电的自定义头消息存储到相应的位置即可。也就是在linphone_call_new_incoming()添加需要解析的消息头,补充到params->custom_headers,结束。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android linphone