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,結束。