eXosip2提供灵活的API,以帮助用户控制呼叫。
1.2.1 初始化呼叫
要启动一个呼出,用户通常需要一些eXosip2用到的头部,以建立默认的INVITE请求。以下的代码用于启动一个呼叫:
osip_message_t *invite;
int i;
i = eXosip_call_build_initial_invite (&invite,
"<sip:to@antisip.com>",
"<sip:from@antisip.com>",
NULL, // optional route header
"This is a call for a conversation");
if (i != 0)
{
return -1;
}
osip_message_set_supported (invite, "100rel");
{
char tmp[4096];
char localip[128];
eXosip_guess_localip (AF_INET, localip, 128); // 获取本地IP
// 格式化SDP信息体
snprintf (tmp, 4096,
"v=0\r\n" // SDP版本
"o=josua 0 0 IN IP4 %s\r\n" // 用户名、ID、版本、网络类型、地址类型、IP地址
"s=conversation\r\n" // 会话名称
"c=IN IP4 %s\r\n"
"t=0 0\r\n" // 开始时间、结束时间。此处不需要设置
"m=audio %s RTP/AVP 0 8 101\r\n" // 音频、传输端口、传输类型、格式列表
"a=rtpmap:0 PCMU/8000\r\n" // 以下为具体描述格式列表中的
"a=rtpmap:8 PCMA/8000\r\n"
"a=rtpmap:101 telephone-event/8000\r\n"
"a=fmtp:101 0-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); // 发送INVITE请求
if (i > 0)
{
eXosip_call_set_reference (i, reference);
}
eXosip_unlock ();
return i;
上面代码使用eXosip_call_build_initial_invite函数为新的呼叫建立一个默认的SIP INVITE请求。用户需要插入SDP信息体,以指示RTP流的音频参数。
同时上述代码演示了eXosip2 API的灵活性,它允许您插入额外的头部,比如:"Supported: 100rel"(宣布支持SIP扩展)。因此,您可以完全的控制SIP请求的创建。
eXosip_call_send_initial_invite函数的返回值为呼叫标识(call identifier),该标识可以用于发送CANCEL请求。之后的事件中(除了100 Trying),用户可以获得会话标识(dialog identifier),该标识用于控制已建立的呼叫。
eXosip_call_set_reference函数将用户自己的环境(context)与呼叫联系起来,这样用户可以从eXosip_event取回指针。
1.2.2 应答呼叫
下面的代码教您如何应答一个到来的呼叫。当接收到SIP INVITE请求后,用户通常需要发送一个 "180 Ringing" SIP应答。
eXosip_lock ();
eXosip_call_send_answer (ca->tid, 180, NULL);
eXosip_unlock ();
上述代码表明,协议栈有时只需要一个API函数就可以建立和发送默认的SIP消息。
然后,当用户想要回复呼叫时,需要发送“200 OK”,同时在回复中插入SDP信息体:
osip_message_t *answer = NULL;
eXosip_lock ();
i = eXosip_call_build_answer (ca->tid, 200, &answer);// 建立200 OK应答
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); // 发送200 OK应答
}
eXosip_unlock ();
注1:上述代码中,注意到给请求发送应答时用到了传送标识(transaction identifier)(不是呼叫标识,也不是会话标识)。
注2:为了发送“200 OK”,通常需要在回复中插入SDP信息体,而且是在回复前插入,目的是为了协商支持的参数和编码。在test tool目录下,eXosip2提供的josua应用程序中,可以找到一个非常基本的SDP协商操作。
1.2.3 发送其他请求
呼叫控制API允许发送和接收REFER、UPDATE、INFO、OPTIONS、NOTIFY、INVITE。当回复其他请求时,仍然存在一些限制,但可以发送任何类型的请求。
以下的代码是发送INFO请求,用于在不同信号层发送不同信道的dtmf。
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 ();