linphone sip 处理

来源:互联网 发布:sql中视图的作用 编辑:程序博客网 时间:2024/06/16 02:30

前言

    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;

0 0