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

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;
      }
   }
}

过程分析:

1、第一个if中,大致是在初始化obj->input_stream.read_ptr,并将obj->input_stream.state改为MESSAGE_AQUISITION;
2、第二个if中,通过belle_sip_message_parse_raw()来解析sip消息,并存储到obj->input_stream.msg中;
3、最后调用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源码中自带的一些函数

1、sal_op_get_recv_custom_header(op),是获取op.base->recv_custom_header对象,其实就是存的sip完整消息;
2、sal_custom_header_find(xx,”x-extraData”);查找sip消息中字段名为:x-extraData的字符串值;
3、如果这个字段存在,通过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()
简单说这个过程的流程:

1、内部调用linphone_call_set_stata(LinphoneCall,LinphoneCallState,char
message),将当前的通话状态设置为LinphoneCallIncomingReceived
2、内部调用linphone_core_notify_call_state_changed(lc,call,cstate,message)来通知通话状态已修改,
3、内部调用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解析,需要去掉

全流程总结:

1、来电的sip请求触发后,消息数据最先保存在一个belle_sip_channel_t下的input_stream中,经过初步解析成字符串后,保留到该结构体下的incoming_messages属性中,多次转换后生成一个表示event事件的belle_sip_request_event_t结构体,
2、通过预先设置的provider来处理这个event结构体,过程中构建了一个SalOp对象,将这部分消息头字符串保存到了这个op下的SalOpBase结构体中的recv_custom_headers属性下,通过provider分析后确认这是一个invite类型的call,后调用预先设置的call_received接口去处理。
3、在call_received()中构建一个java层可用的LinphoneCallParams和LinphoneCall对象,同时从op中解析需要传递给java层的数据,填充到LinphoneCallParams对象中,这个param也被关联到call下,
4、最终通过callState()回调接口,将来电信息回调给java层

linphone源码中是不包含自定义头的数据解析和填充的,我们只需要参考发起呼叫时添加的自定义头消息的存储方式,将来电的自定义头消息存储到相应的位置即可。也就是在linphone_call_new_incoming()添加需要解析的消息头,补充到params->custom_headers,结束。
————————————————
下一篇:Linphone android去电增加自定义SIP消息头的流程分析_今人不见古时月,今月曾经照古人的博客-CSDN博客

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

猜你喜欢

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