linphone sip 处理
来源:互联网 发布:sql中视图的作用 编辑:程序博客网 时间:2024/06/16 10:19
前言
linphone 是基于sip的voip call 方案,sip部分使用了exosip,本文分析一下linphone的sip部分。下文中简称为sip。
sip关键结构体
struct Sal{
SalCallbacks callbacks;
SalTransport transport;
MSList *calls; /*MSList of SalOp */
MSList *registers;/*MSList of SalOp */
MSList *out_subscribes;/*MSList of SalOp */
MSList *in_subscribes;/*MSList of SalOp */
MSList *pending_auths;/*MSList of SalOp */
MSList *other_transactions; /*MSList of SalOp */
int running;
int session_expires;
int keepalive_period;
void *up; /*user pointer*/
char* rootCa; /* File _or_ folder containing root CA */
int dscp;
bool_t one_matching_codec;
bool_t double_reg;
bool_t use_rports;
bool_t use_101;
bool_t reuse_authorization;
bool_t verify_server_certs;
bool_t verify_server_cn;
bool_t expire_old_contact;
bool_t add_dates;
bool_t tcp_tls_keepalive;
}
struct eXosip_t {
struct eXtl_protocol *eXtl;
char transport[10];
char *user_agent;
eXosip_call_t *j_calls; /* my calls */
#ifndef MINISIZE //未定义
eXosip_subscribe_t *j_subscribes; /* my friends */
eXosip_notify_t *j_notifies; /* my susbscribers */
#endif
osip_list_t j_transactions;
eXosip_reg_t *j_reg; /* my registrations */
#ifndef MINISIZE
eXosip_pub_t *j_pub; /* my publications */
#endif
#ifdef OSIP_MT //定义
void *j_cond;
void *j_mutexlock;
#endif
osip_t *j_osip;
int j_stop_ua;
#ifdef OSIP_MT
void *j_thread;
jpipe_t *j_socketctl;
jpipe_t *j_socketctl_event;
#endif
osip_fifo_t *j_events;
jauthinfo_t *authinfos;
int keep_alive;
int keep_alive_options;
int learn_port;
#ifndef MINISIZE
int http_port;
char http_proxy[256];
char http_outbound_proxy[256];
int dontsend_101;
#endif
int use_rport;
int dns_capabilities;
int dscp;
char ipv4_for_gateway[256];
char ipv6_for_gateway[256];
#ifndef MINISIZE
char event_package[256];
#endif
struct eXosip_dns_cache dns_entries[MAX_EXOSIP_DNS_ENTRY];
struct eXosip_account_info account_entries[MAX_EXOSIP_ACCOUNT_INFO];
struct eXosip_http_auth http_auths[MAX_EXOSIP_HTTP_AUTH];
CbSipCallback cbsipCallback;
}
struct SalOp{
SalOpBase base;
int cid;
int did;
int tid;
int rid;
int sid;
int nid;
int expires;
SalMediaDescription *result;
sdp_message_t *sdp_answer;
eXosip_event_t *pending_auth;
osip_call_id_t *call_id; /*used for out of calls transaction in order
to retrieve the operation when receiving a response*/
char *replaces;
char *referred_by;
const SalAuthInfo *auth_info;
const char *sipfrag_pending;
bool_t supports_session_timers;
bool_t sdp_offering;
bool_t reinvite;
bool_t masquerade_via;
bool_t auto_answer_asked;
bool_t terminated;
}
typedef struct SalOpBase{
Sal *root;
char *route; /*or request-uri for REGISTER*/
char *contact;
char *from;
char *to;
char *origin;
char *remote_ua;
SalMediaDescription *local_media;
SalMediaDescription *remote_media;
void *user_pointer;
const char* call_id;
} SalOpBase;
typedef struct SalMediaDescription{
int refcount;
char addr[64];
char username[64];
int n_active_streams;
int n_total_streams;
int bandwidth;
unsigned int session_ver;
unsigned int session_id;
SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS];
char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN];
char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN];
bool_t ice_lite;
bool_t ice_completed;
} SalMediaDescription;
typedef struct SalMessage{
const char *from;
const char *text;
const char *url;
const char *message_id;
}SalMessage;
SIP初始化
sip初始化流程从 linphone_core_init 开始,详细如下:
linphone_core_init(){
...
sal_init();//1
sal_set_user_pointer(lc->sal,lc);//2
sal_set_callbacks(lc->sal,&linphone_sal_callbacks);//3
sip_setup_register_all();//4
sip_config_read(lc);//5
...
}
1.初始化osip trace func,初始化Sal结构,初始化eXosip_t结构,初始化osip,向osip注册回调函数;
2.向Sal设置用户指针;
3.向Sal设置回调函数;
4.设置sip注册、注销相关的信息和回调函数;
5.读取sip相关的配置参数并设置给Sal;调用sal_listen_port启动线程开始监听sip端口;配置sip url;配置代理;配置心跳监测;
SIP主叫
sip呼叫流程从linphone_core_invite_address_with_params()开始,分为两个阶段,第一阶段添加一个invite事务到事务队列;
第二阶段是在_eXosip_thread线程里处理ict事务,调用真正的udp函数发送sip消息,详细如下:
第一阶段:
linphone_core_invite_address_with_params(){
...
sal_address_new(addr);//1
sal_op_new(lc->sal);//2
sal_op_set_user_pointer(call->op,call);//3
sal_op_set_route(call->op,route);//4
sal_op_set_contact(call->op, contact);//5
sal_call_set_local_media_description(call->op,call->localdesc);//6
err=sal_call(call->op,from,real_url);//7
->eXosip_call_send_initial_invite(osip_message_t * invite)
->osip_transaction_add_event(transaction, sipevent);
...
}
1.根据contact字符串构造SalAddress对象;
2.初始化SalOp结构;
3.将linphonecall指针配置到SalOp结构的SalOpBase;
4.将route字符串配置到SalOp结构的SalOpBase;
5.将contact字符串配置到SalOp结构的SalOpBase;
6.将SalMediaDescription配置到SalOp结构的SalOpBase;
7.此函数做了不少事情:
7.1配置SalOp的SalOpBase的from字段;
7.2配置SalOp的SalOpBase的to字段;
7.3分析并检验配置SalOp的SalOpBase的route字段;
7.4根据frome、to和route构造invite消息;
7.5如果设置了SalMediaDescription,则构造sdp消息;
7.6发送invite,具体过程如下:
7.6.1初始化eXosip_call_t;
7.6.2构造此invite的ICT事务;
7.6.3构造此invite的osip_event_t事件;
7.6.4将事务和事件添加进队列;
7.6.5将call添加进eXosip.j_calls队列;
7.6.6更新exosip的计时器和dialog;
7.6.7通过写pipe驱动exosip处理invite事务;
7.6.8将call增加到Sal结构的calls链表;
第二阶段:
_eXosip_thread(){
......
osip_ict_execute(eXosip.j_osip);//1
->osip_transaction_execute();//2
->fsm_callmethod()//3
即ict_snd_invite(osip_transaction_t * ict, osip_event_t * evt);//4
->osip->cb_send_message();//5
即cb_snd_message();//6
->eXosip.cbsipCallback(sip, 0);//7
->eXtl_udp.tl_send_message();//8
即udp_tl_send_message();//9
->sendto();//10
->__osip_message_callback(OSIP_ICT_INVITE_SENT, ict, ict->orig_request);//11
->config->msg_callbacks[type] (type, tr, msg);//12
即cb_sndinvite();//13
}
1.eXosip_thread线程循环执行事务处理;
2.调用事务处理的总入口函数;
3.根据事务类型(ict/ist/nict/nist)获取回调函数集,并调用相应的方法;
4.ict的事务处理函数定义在ict_fsm.c;(同样的,ist的事务处理函数定义在ist_fsm.c等等);
5.osip调用exosip设置的回调函数来处理;
6.此回调函数定义在jcallback.c;
7.调用cbsipCallback回调,此回调用于在发送sip消息前对消息做最后的处理;
8.调用udp的回调函数发送消息;
9.udp的回调函数定义在extl_udp.c;
10.调用socket函数真正的发送sip消息;
11、12调用OSIP_ICT_INVITE_SENT对应的回调函数,同样定义在jcallback.c;
13.此函数只是打印了一下。
SIP被叫
sip被叫流程从_eXosip_thread开始,第一阶段是从socket读取sip消息,然后分析消息,提炼出event,并写入队列。
第二阶段是在linphone_iterate线程里读取event并调用相应的回调函数来处理。详细代码流程如下。
第一阶段:
_eXosip_thread(){
eXosip_execute();//1
->eXosip_read_message();//2
->eXtl_udp.tl_read_message();//3
即udp_tl_read_message();//4
->recvfrom();//5
->_eXosip_handle_incoming_message();//6
->eXosip.cbsipCallback(se->sip, 1);//7
->osip_find_transaction_and_add_event(eXosip.j_osip, se);//8
->osip_fifo_add(transaction->transactionff, evt);//9
->eXosip_process_newrequest(se, socket);//10
->eXosip_process_new_invite();//11
->report_call_event(EXOSIP_CALL_INVITE, jc, jd, transaction);//12
->eXosip_event_add();//13
->osip_fifo_add(eXosip.j_events, (void *) je);//14
}
1._eXosip_thread线程里循环调用eXosip_execute();
2.调用读取sip消息的总入口函数;
3.调用udp的读取函数;
4.udp的回调函数定义在extl_udp.c;
5.调用socket函数,真正的读取消息;
6.对收到的消息进行处理,生成transaction和event;
7.调用cbsipCallback,此回调可以用来在收到消息后进行预处理;
8、9.把生成的transaction 和event加入队列;
10.如果是请求消息,调用eXosip_process_newrequest处理新请求消息;
11.如果是invite消息,则处理;
12、13、14.添加EXOSIP_CALL_INVITE event到队列;
第二阶段:
linphone_core_iterate(){
->sal_iterate(lc->sal);//1
->eXosip_event_wait();//2
->osip_fifo_tryget(eXosip.j_events);//3
->process_event();//4
->inc_new_call(Sal *sal, eXosip_event_t *ev);//5
->sal->callbacks.call_received(op);//6
即call_received(SalOp *h);//7
->linphone_call_new_incoming//8
}
1.linphone的iterate线程循环调用sal_iterate();
2、3.从event队列获取待处理的事件;
4.处理event的总入口函数;
5.如果是EXOSIP_CALL_INVITE,则调用inc_new_call();
6.分析eXosip_event_t,生成SalOp,并调用回调处理;
7.回调定义在callbacks.c;
8.解析SalOp,并调用linphone_call_new_incoming生成LinphoneCall;
- linphone sip 处理
- 开源sip电话 linphone
- linphone之sip分析
- Sip 注册和Linphone结构图
- How Does Linphone Toggle SIP Contact?
- LinPhone开发文档一:SIP和VOIP简单介绍
- Android上试用Linphone(Free SIP VOIP Client)
- linphone-获取sip:name@192.168.1.24中的name
- linphone
- linphone
- linphone
- linphone
- sip voip处理资料
- Linphone android去电增加自定义SIP消息头的流程分析
- Linphone 被叫方如何解析来电SIP消息中的自定义头消息
- Sip UAS 的处理流程
- [Linphone Android]Linphone介绍
- 一个基于SIP的Scenario处理流程
- Nova Scheduler 调度过程简述
- NYOJ 138 找球号(二)
- 利用curator实现的zookeeper分布式锁服务
- 解析xml文件的几种技术
- _Z5qFreePv mingwm10.dll,libgcc_s_dw2-1.dll 相关问题
- linphone sip 处理
- 关于eclipse打开一闪而过的解决方法
- 15款免费的HTML5编码工具推荐(附下载)
- greenplum
- MYSQL grant命令
- HTML5画时钟
- 线程,进程 区别
- 3) 一元/二元函数抽象function [原创,泛型编程,自由下载转载,需注明出处]
- Ruby 的循环的使用