转载至http://hi.csdn.net/hust_ch

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=的子属性