exosip是对osip的又一次封装,使得用户可以比较简单的构建自己的SIP协议栈,实现SIP协议。
下载和编译不说了,网上有很多的例子。
下面简要说下exosip的调用流程。
1)eXosip_init(),主要是进行网络的一些初始化,如判定本机地址,网络初始化等。
2)eXosip_set_user_agent() 设置user_agent(),可以不写,主要是在SIP request/response里填写user_agent字段用的。
3)eXosip_listen_addr()创建监听地址,可以直接写成eXosip_listen_addr(IPPROTO_UDP,0,0,AF_INET,0);
4)创建事件线程,用于接受处理sip消息
CreateThread(0,0,SIP_Event_Thread,this,0,0)
这里创建了一个SIP_Event_Thread线程并用于接受参数,传入一个this参数。
5)在下面的SIP线程里处理,类似的函数很多。
DWORDSIP_Event_Handler::PTC_SIP_Event_Thread(LPVOID param)
有关exosip需要注意的是
1)本机多网卡或多IP时,exosip猜测本机地址时经常会猜错,比如本机有一个公网的PPPOE的IP,另外配有一个私网IP如192.168.1.22 ,则exosip_guess_local_ip会一直返回PPPOE的IP,所以当exosip登陆私网的SIP服务器时,在后续的SIP处理中会一直出错。这里可以通过判断用户输入的SIP服务器是否位于公网,来设置正确的自己的IP地址。
2)eXosip_event_wait(0, WAIT_TIME );中的WAIT_TIME不要过小,否则在exosip工作时的定时器时间偏差会越来越大,没有太深入看过exosip和osip的源码,感觉可能是频繁的中断造成误差。
3) exosip处理有关401和407的错误,可以简单的用下面的函数:
eXosip_lock();
eXosip_default_action(je);
eXosip_unlock();
或者是
eXosip_lock();
eXosip_automatic_refresh();
eXosip_unlock();
下面这段代码示范了如何用exosip提取SDP里想要的值
SDP是会话初始协议,不仅用于SIP协议,也广泛用于如RTSP等多媒体描述协议。
boolget_audiog729_param(const eXosip_event_t *event,
string &audio_ip,
string &audio_port,
string &rtp_pt_type,
string &bitrate,
string &encode_type)
{
int dlgid = event->did;
sdp_message_t *sdp_msg = eXosip_get_remote_sdp(dlgid);
if ( !sdp_msg )
return false;
sdp_connection_t *connection = eXosip_get_audio_connection(sdp_msg);
if ( !connection )
return false;
audio_ip = connection->c_addr; //audio_ip
sdp_media_t * audio_sdp = eXosip_get_audio_media(sdp_msg);
if ( !audio_sdp )
return false;
audio_port = audio_sdp->m_port; //audio_port
for ( int i = 0 ; i < audio_sdp->a_attributes.nb_elt; i ++ )
{
sdp_attribute_t *attr = (sdp_attribute_t*)osip_list_get(&audio_sdp->a_attributes,i);
if ( attr )
{
string audio_filed = attr->a_att_field;
if ( audio_filed == "rtpmap")
{
string g726_value = attr->a_att_value;
if ( ! strstr(g726_value.c_str(),"726"))
continue;
string::size_type pt_idx =g726_value.find_first_of(0x20);
if ( pt_idx == string::npos )
return false;
rtp_pt_type = g726_value.substr(0,pt_idx);
string::size_type bitrate_idx = g726_value.find_first_of('/');
if (bitrate_idx == string::npos )
return false;
bitrate = g726_value.substr( bitrate_idx+ 1 );
encode_type = g726_value.substr(pt_idx+1,bitrate_idx - pt_idx -1);
return true;
}
}
}
return true;
}
其中event是在SIP_Event_Thread里得到的事件,其他的形参也作为结果传出来供调用者用。
对于SDP,重点了解以下几个字段的含义即可。
o= 表示发起者
c= 表示connector,比较重要
m = 表示媒体信息,每个media对应多个attribute("也就是a=")字段
a= 是m=的子属性