这是pjsip2.5.5的samples工程内提供包括媒体及完整UA功能的简单应用,文件位置:pjproject-2.5.5\pjsip-apps\src\samples\simpleua.c,用户代理(UA)在SDK协商成功后启动RTP媒体传输。
此程序不需要注册到SIP服务器,它能够完成:基本呼叫、在5060端口传输UDP、在4000端口传输RTP、SDP协商、语音编解码器只支持PCMA和PCMU、声卡的语音媒体。
Samples工程编译完成后,在命令行输入:
simpleua 要呼叫的sip地址
要呼叫的sip地址格式: sip:用户名@对端IP
*呼入的呼叫先以180自动应答,再以200自动应答,此程序单次呼叫后即退出。
#include <pjsip.h>
#include <pjmedia.h>
#include <pjmedia-codec.h>
#include <pjsip_ua.h>
#include <pjsip_simple.h>
#include <pjlib-util.h>
#include <pjlib.h>
#define THIS_FILE "simpleua.c"
#include "util.h"
//设置
#define AF pj_AF_INET()// 如果使用IPV6,将此行改为pj_AF_INET6()
//必须设置PJ_HAS_IPV6
//并且操作系统也需要支持 IPv6. */
#if 0
#define SIP_PORT 5080 //侦听的SIP端口
#define RTP_PORT 5000 // RTP端口
#else
#define SIP_PORT 5060 //侦听的SIP端口
#define RTP_PORT 4000 // RTP端口
#endif
#define MAX_MEDIA_CNT 2 //媒体数量,设置为1将支持音频,
//设置为2,即支持音频,又支持视频
//全局静态变量
static pj_bool_t g_complete; //退出状态
static pjsip_endpoint *g_endpt; // SIP终端
static pj_caching_pool cp; //全局pool factory
static pjmedia_endpt *g_med_endpt; // 媒体终端
staticpjmedia_transport_info g_med_tpinfo[MAX_MEDIA_CNT];
//媒体传输用套接字信息
staticpjmedia_transport *g_med_transport[MAX_MEDIA_CNT];
//媒体流传输端口
staticpjmedia_sock_info g_sock_info[MAX_MEDIA_CNT];
//套接字信息组
//呼叫部分变量
staticpjsip_inv_session *g_inv; //当前invite传话
static pjmedia_stream *g_med_stream; //语音流
static pjmedia_snd_port *g_snd_port; //声卡设备
#if defined(PJMEDIA_HAS_VIDEO)&& (PJMEDIA_HAS_VIDEO != 0)
staticpjmedia_vid_stream *g_med_vstream; //视频流
static pjmedia_vid_port *g_vid_capturer;//视频捕获设备
static pjmedia_vid_port *g_vid_renderer;//视频播放设备
#endif //PJMEDIA_HAS_VIDEO
//函数声明
//呼叫过程上,当SDP协商完成后,回调此函数
static void call_on_media_update( pjsip_inv_session *inv,
pj_status_t status);
//当invite会话状态变化后,回调此函数
static void call_on_state_changed( pjsip_inv_session *inv,
pjsip_event *e);
//当新对话建立后,回调此函数
static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
//对话之外,当收到请求时,回调此函数
static pj_bool_t on_rx_request( pjsip_rx_data *rdata );
//此PJSIP模块注册到应用用于处理对话或事务之外的请求,主要目的是处理INVITE请求消息,在那里将为它创建新的对话和INVITE会话
static pjsip_module mod_simpleua =
{
NULL, NULL, /*prev, next. */
{ "mod-simpleua", 12 }, /* Name. */
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
NULL, /* unload() */
&on_rx_request, /* on_rx_request() */
NULL, /* on_rx_response() */
NULL, /* on_tx_request. */
NULL, /* on_tx_response() */
NULL, /* on_tsx_state() */
};
//呼入消息通知
static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
{
PJ_LOG(4,(THIS_FILE, "RX %d bytes%s from %s %s:%d:\n"
"%.*s\n"
"--end msg--",
rdata->msg_info.len,
pjsip_rx_data_get_info(rdata),
rdata->tp_info.transport->type_name,
rdata->pkt_info.src_name,
rdata->pkt_info.src_port,
(int)rdata->msg_info.len,
rdata->msg_info.msg_buf));
//此处必须返回false,否则其它消息将不被处理
return PJ_FALSE;
}
//呼出消息通知
static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
{
/* Important note:
* tp_infofield is only valid after outgoing messages has passed
* transportlayer. So don't try to access tp_info when the module
* haslower priority than transport layer.
*/
PJ_LOG(4,(THIS_FILE, "TX %d bytes%s to %s %s:%d:\n"
"%.*s\n"
"--end msg--",
(tdata->buf.cur - tdata->buf.start),
pjsip_tx_data_get_info(tdata),
tdata->tp_info.transport->type_name,
tdata->tp_info.dst_name,
tdata->tp_info.dst_port,
(int)(tdata->buf.cur - tdata->buf.start),
tdata->buf.start));
/* Always return success, otherwise message w