您的位置:首页 > 其它

基于osip2/eXosip2协议栈的应用开发之(1):翻译:eXosip开发手册

2016-10-27 18:07 411 查看

扩展协议栈eXosip

1.1 如何初始化libeXsip2库

    当使用eXosip是,你首先要完成的工作就是初始化eXsip上下文和libosip库(解析器和状态机)。在使用libeXosip前这个工作必须完成。那么如何初始化呢,我们看下面的代码:
include <eXosip2/eXosip.h>
...
int i;
TRACE_INITIALIZE (6, stdout);
i=eXosip_init();
if (i!=0)
return-1;

i = eXosip_listen_addr (IPPROTO_UDP, NULL,port, AF_INET, 0);
if (i!=0)
{
eXosip_quit();
fprintf(stderr, "could not initialize transport layer\n");
return-1;
}
...然后你可以发送消息了,然后等待eXosip事件...

在上面这段代码中,你可以学到:
1、如何初始化osip调试trace跟踪器(编译时加上-DENABLE_TRACE选项);
2、如何初始化eXosip(和osip)协议栈;
3、怎样为信令打开一个socket套接字;
 
现在你需要处理eXsip事件了。下面有一些代码,教你如何从eXosip2协议栈中获取eXsip_event(eXosip事件:译者注):
eXosip_event_t *je;
for (;;)
{
je= eXosip_event_wait (0, 50);
eXosip_lock();
eXosip_automatic_action();
eXosip_unlock();
if(je == NULL)
break;

if (je->type == EXOSIP_CALL_NEW)
{
....
....
}
else if (je->type == EXOSIP_CALL_ACK)
{
....
....
}
else if (je->type ==EXOSIP_CALL_ANSWERED)
{
....
....
}
else .....
....
....
eXosip_event_free(je);
}
你每发送一个SIP消息,都会收到一个事件。每个事件都包含相关事务的原始请求和可用时触发事件的最后一个响应。
你可以访问这些消息的所有头域(header翻译为头域:译者注),并把它们存储在您自己的上下文中,用于其他操作或图形显示。

举个例子,当你在一个呼叫事务中收到一个REFER请求时,通常的做法是检索“refer-To”的头域。osip_header_t *referto_head = NULL;
i = osip_message_header_get_byname(evt->sip, "refer-to", 0,
&referto_head);
if(referto_head == NULL || referto_head->hvalue == NULL)
eXosip_event同样包含了一些标识符(id),用来标识‘呼叫’,‘注册’,‘输入事务’,‘输出事务’。这些标识符通常配合API使用,来控制‘呼叫’,‘注册’等事务。利用常用的头域(From,To,Call-ID,CSeq,Route,Record-Route,Max-Forward)这些API可以创建默认的messages,并且发送这些messages。

1.2 如何初始化,修改或中止一个呼叫

eXosip提供了灵活的API来帮助你控制呼叫过程。

1.2.1 初始化一个呼叫

为了建立一个呼叫,你通常需要一些头域来满足eXosip2创建一个默认的SIP INVITE请求。下面的代码用来开始一个呼叫:
osip_message_t *invite;
int i;
i = eXosip_call_build_initial_invite(&invite, "<sip:to@antisip.com>",
"<sip:from@antisip.com>",
NULL,// optionnal route header
"Thisis a call for a conversation");
if (i != 0)
{
return-1;
}

osip_message_set_supported (invite,"100rel");
{
chartmp[4096];
charlocalip[128];
eXosip_guess_localip(AF_INET, localip, 128);
snprintf(tmp, 4096,
"v=0\r\n"
"o=josua0 0 IN IP4 %s\r\n"
"s=conversation\r\n"
"c=IN IP4 %s\r\n"
"t=00\r\n"
"m=audio%s RTP/AVP 0 8 101\r\n"
"a=rtpmap:0PCMU/8000\r\n"
"a=rtpmap:8PCMA/8000\r\n"
"a=rtpmap:101telephone-event/8000\r\n"
"a=fmtp:1010-11\r\n", localip, localip, port);
osip_message_set_body(invite, tmp, strlen (tmp));
osip_message_set_content_type(invite, "application/sdp");
}

eXosip_lock();
i= eXosip_call_send_initial_invite (invite);
if(i > 0)
{
eXosip_call_set_reference(i, reference);
}

eXosip_unlock();
return i;

    上面的代码使用了eXosip_call_build_initial_invite来创建一个默认的SIPINVITE请求,从而形成一个新的呼叫,但还需要嵌入一个SDP体来描述RTP流中的音频参数信息。上面的代码同样展示了eXosip2 API的灵活性,它可以嵌入额外的头域,比如“Supported:100rel”(声明支持SIP扩展).因此,你可以完全的控制SIP请求的创建。
    eXosip_call_send_initial_invite的返回值叫做Call-ID,有了Call-ID你可以发送CANCEL信令,来取消一个呼叫。在未来的事件中,除了100Tring事件,你还会得到dialog-ID,而这个dialog-ID在控制已经建立的会话时十分有用。

1.2.2 回答一个呼叫

下面的代码给出了如何回答一个到达的呼叫。
当收到一个SIP INVITE信令的时候,通常需要回复一个“180 Ringing”信令。回复代码如下示例:
eXosip_lock ();
eXosip_call_send_answer (ca->tid, 180,NULL);
eXosip_unlock (); 
注意:通过上面的代码可以看出,有时候协议栈创建和发送一个SIP信令只需要调用一个API接口函数。
 
当回复一个呼叫时,需要发送200 OK信令,同时将SDP描述体嵌入到这个SIP回复信令中去。示例代码如下所示:osip_message_t *answer = NULL;

eXosip_lock ();
i = eXosip_call_build_answer (ca->tid,200, &answer);
if (i != 0)
{
eXosip_call_send_answer(ca->tid, 400, NULL);
}
else
{
i= sdp_complete_200ok (ca->did, answer);
if(i != 0)
{
osip_message_free (answer);
eXosip_call_send_answer (ca->tid,415, NULL);
}
else
eXosip_call_send_answer(ca->tid, 200, answer);
}

eXosip_unlock ();
注意1:从上面的代码可以看出,当响应一个呼叫时,需要使用的是事务ID(transaction identifier:TID:译者注),而不是使用呼叫ID(Call-ID or CID:译者注)或者会话ID(dialog-ID or DID:译者注)。
注意2:上面讲到,通常发送一个200 OK信令的时候需要嵌入一个SDP体,而在这之前,需要协商通话主体支持的媒体参数,比如发送的SIP INVITE信令中视频类型有H264,MPEG-2,音频有G711,G729,AAC-LC,被叫通话主体需要根据自身能力选择视频类型和音频类型,比如视频选择H264,音频选择AAC-LC,然后将这些选择信息写在SDP中,嵌入到200 OK的回复里。

1.2.3 发送其他请求

在会话过程中,通过调用API可以发送或接收REFER, UPDATE, INFO, OPTIONS, NOTIFY 和 INVITES 信令。在会话中回答其他请求仍然存在一些限制,但它应该已经可以发送任何类型的请求。
下面代码给出如何发送一个INFO请求信令。
osip_message_t *info;
char dtmf_body[1000];
int i;
eXosip_lock ();
i = eXosip_call_build_info (ca->did,&info);
if(i == 0)
{
snprintf(dtmf_body, 999, "Signal=%c\r\nDuration=250\r\n", c);
osip_message_set_content_type(info, "application/dtmf-relay");
osip_message_set_body(info, dtmf_body, strlen (dtmf_body));
i= eXosip_call_send_request (ca->did, info);
}
eXosip_unlock (); 

1.3 如何发送和维护注册事务

eXosip2 提供了一套灵活的API来帮助你实现注册事务。

1.3.1 初始化一个注册

开始注册时,需要提供一些必要的头域来创建一个默认的REGISTER信令。示例代码如下所示:
osip_message_t *reg = NULL;
int id;
int i;

eXosip_lock ();
id = eXosip_register_build_initial_register(identity, registrar, NULL, 1800, ®);
if (id < 0)
{
eXosip_unlock();
return-1;
}

osip_message_set_supported (reg,"100rel");
osip_message_set_supported(reg,"path");
i = eXosip_register_send_register (id,reg);

eXosip_unlock ();

return i; 
eXosip_register_build_initial_register的返回值叫做注册ID(registration identifier,库源码中的rid译者注)。在以后的关于此注册的事件中,都可以适时的查看注册ID(在同一个注册会话事件中,注册ID(rid)是相同的:译者注)。

1.3.2 更新一个注册

只需要重复使用注册ID就可以实现跟新一个注册事务。示例代码如下:
int i;
eXosip_lock ();
i = eXosip_register_build_register (id,1800, ®);
if (i < 0)
{
eXosip_unlock();
return-1;
}
eXosip_register_send_register (id, reg);
eXosip_unlock ();

1.3.3关闭一个注册

当软电话中止使用时,需要再SIP服务器上删除自己的注册状态。如何做呢,只需要将头域中的‘expires’字段设置为‘0’,然后重新发送一个REGISTER信令到服务器,这个过程也叫注销。其代码与更新注册类似:
int i;
eXosip_lock ();
i = eXosip_register_build_register (id, 0,®);
if (i < 0)
{
eXosip_unlock();
return-1;
}
eXosip_register_send_register (id, reg);
eXosip_unlock ();
如上代码所示,将‘1800’参数改写为‘0’即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  SIP osip2eXosip2 教程