概述
项目使用pjsip库作为底层协议库,扩展支持GB28181协议,但pjsip的sdp编解码不支持额外参数解析,需要修改源代码,以便支持GB28181中关于SDP协议的扩展(例如y参数)。源码主要在pjmedia/include/pjmedia/sdp.h和pjmedia/src/pjmedia/sdp.c上修改。
1、在sdp.h中扩展pjmedia_sdp_session定义,增加other_count和other字段,后面的修改都是在sdp.c中
/**
* This structure describes SDP session description. A SDP session descriptor
* contains complete information about a session, and normally is exchanged
* with remote media peer using signaling protocol such as SIP.
*/
struct pjmedia_sdp_session
{
/** Session origin (o= line) */
struct
{
pj_str_t user; /**< User */
pj_uint32_t id; /**< Session ID */
pj_uint32_t version; /**< Session version */
pj_str_t net_type; /**< Network type ("IN") */
pj_str_t addr_type; /**< Address type ("IP4", "IP6") */
pj_str_t addr; /**< The address. */
} origin;
pj_str_t name; /**< Subject line (s=) */
pjmedia_sdp_conn *conn; /**< Connection line (c=) */
unsigned bandw_count; /**< Number of bandwidth info (b=) */
pjmedia_sdp_bandw *bandw[PJMEDIA_MAX_SDP_BANDW];
/**< Bandwidth info array (b=) */
/** Session time (t= line) */
struct
{
pj_uint32_t start; /**< Start time. */
pj_uint32_t stop; /**< Stop time. */
} time;
unsigned attr_count; /**< Number of attributes. */
pjmedia_sdp_attr *attr[PJMEDIA_MAX_SDP_ATTR]; /**< Attributes array. */
unsigned media_count; /**< Number of media. */
pjmedia_sdp_media *media[PJMEDIA_MAX_SDP_MEDIA]; /**< Media array. */
// 其他参数
unsigned other_count; /**< Number of Others. */
pjmedia_sdp_attr *other[PJMEDIA_MAX_SDP_ATTR]; /**< Others array. */
};
2、解码部分增加对other参数的解析,在解码函数pjmedia_sdp_parse里,处理其他参数的位置,调用新增加的函数
case 'b':
bandw = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_bandw);
parse_bandwidth_info(&scanner, bandw, &ctx);
if (media) {
if (media->bandw_count < PJMEDIA_MAX_SDP_BANDW)
media->bandw[media->bandw_count++] = bandw;
else
PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY,
"Error adding media bandwidth "
"info, info is ignored"));
} else {
if (session->bandw_count < PJMEDIA_MAX_SDP_BANDW)
session->bandw[session->bandw_count++] = bandw;
else
PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY,
"Error adding session bandwidth "
"info, info is ignored"));
}
break;
default:
if (cur_name >= 'a' && cur_name <= 'z') {
// 处理其他参数
parse_other_line(&scanner, session, &ctx, pool);
}
else {
ctx.last_error = PJMEDIA_SDP_EINSDP;
on_scanner_error(&scanner);
}
break;
}
新增parse_other_line函数处理其他参数的解析,这里参照attr参数的解析流程
增加函数定义和实现
static void parse_generic_line(pj_scanner *scanner, pj_str_t *str,
parse_context *ctx);
// 扩展支持其他参数的解析
static void parse_other_line(pj_scanner *scanner, pjmedia_sdp_session *ses,
parse_context *ctx, pj_pool_t *pool);
static void parse_connection_info(pj_scanner *scanner, pjmedia_sdp_conn *conn,
parse_context *ctx);
static void parse_other_line(pj_scanner *scanner, pjmedia_sdp_session *ses,
parse_context *ctx, pj_pool_t *pool)
{
pjmedia_sdp_attr *attr;
ctx->last_error = PJMEDIA_SDP_EINATTR;
attr = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_attr);
/* check equal sign */
if (*(scanner->curptr + 1) != '=') {
on_scanner_error(scanner);
return;
}
/* x= */
attr->name.ptr = (char*)pj_pool_alloc(pool, 1);
*(attr->name.ptr) = *(scanner->curptr);
attr->name.slen = 1;
pj_scan_advance_n(scanner, 2, SKIP_WS);
/* get anything until newline (including whitespaces). */
pj_scan_get_until_chr(scanner, "rn", &attr->value);
/* newline. */
pj_scan_get_newline(scanner);
if (ses->other_count < PJMEDIA_MAX_SDP_ATTR)
{
ses->other[ses->other_count] = attr;
++ses->other_count;
}
}
3、编码部分,在print_session函数中,增加输出其他参数
static int print_session(const pjmedia_sdp_session *ses,
char *buf, pj_ssize_t len)
{
char *p = buf;
char *end = buf+len;
unsigned i;
int printed;
/* Check length for v= and o= lines. */
if (len < 5+
2+ses->origin.user.slen+18+
ses->origin.net_type.slen+ses->origin.addr.slen + 2)
{
return -1;
}
/* SDP version (v= line) */
pj_memcpy(p, "v=0rn", 5);
p += 5;
/* Owner (o=) line. */
*p++ = 'o';
*p++ = '=';
pj_memcpy(p, ses->origin.user.ptr, ses->origin.user.slen);
p += ses->origin.user.slen;
*p++ = ' ';
printed = pj_utoa(ses->origin.id, p);
p += printed;
*p++ = ' ';
printed = pj_utoa(ses->origin.version, p);
p += printed;
*p++ = ' ';
pj_memcpy(p, ses->origin.net_type.ptr, ses->origin.net_type.slen);
p += ses->origin.net_type.slen;
*p++ = ' ';
pj_memcpy(p, ses->origin.addr_type.ptr, ses->origin.addr_type.slen);
p += ses->origin.addr_type.slen;
*p++ = ' ';
pj_memcpy(p, ses->origin.addr.ptr, ses->origin.addr.slen);
p += ses->origin.addr.slen;
*p++ = 'r';
*p++ = 'n';
/* Session name (s=) line. */
if ((end-p) < 8+ses->name.slen) {
return -1;
}
*p++ = 's';
*p++ = '=';
pj_memcpy(p, ses->name.ptr, ses->name.slen);
p += ses->name.slen;
*p++ = 'r';
*p++ = 'n';
/* Connection line (c=) if exist. */
if (ses->conn) {
printed = print_connection_info(ses->conn, p, (int)(end-p));
if (printed < 1) {
return -1;
}
p += printed;
}
/* print optional bandwidth info. */
for (i=0; i<ses->bandw_count; ++i) {
printed = (int)print_bandw(ses->bandw[i], p, end-p);
if (printed < 1) {
return -1;
}
p += printed;
}
/* Time */
if ((end-p) < 24) {
return -1;
}
*p++ = 't';
*p++ = '=';
printed = pj_utoa(ses->time.start, p);
p += printed;
*p++ = ' ';
printed = pj_utoa(ses->time.stop, p);
p += printed;
*p++ = 'r';
*p++ = 'n';
/* Print all attribute (a=) lines. */
for (i=0; i<ses->attr_count; ++i) {
printed = (int)print_attr(ses->attr[i], p, end-p);
if (printed < 0) {
return -1;
}
p += printed;
}
/* Print media (m=) lines. */
for (i=0; i<ses->media_count; ++i) {
printed = print_media_desc(ses->media[i], p, (int)(end-p));
if (printed < 0) {
return -1;
}
p += printed;
}
// 输出其他参数
for (i = 0; i < ses->other_count; ++i) {
if (0 >= ses->other[i]->name.slen)
{
continue;
}
pj_memcpy(p, ses->other[i]->name.ptr, ses->other[i]->name.slen);
p += ses->other[i]->name.slen;
*p++ = '=';
if (0 < ses->other[i]->value.slen)
{
pj_memcpy(p, ses->other[i]->value.ptr, ses->other[i]->value.slen);
p += ses->other[i]->value.slen;
}
*p++ = 'r';
*p++ = 'n';
}
return (int)(p-buf);
}
4、复制部分,在函数pjmedia_sdp_session_clone中,增加对其他参数的复制
/* Duplicate session attributes. */
sess->attr_count = rhs->attr_count;
for (i=0; i<rhs->attr_count; ++i) {
sess->attr[i] = pjmedia_sdp_attr_clone(pool, rhs->attr[i]);
}
/* Duplicate media descriptors. */
sess->media_count = rhs->media_count;
for (i=0; i<rhs->media_count; ++i) {
sess->media[i] = pjmedia_sdp_media_clone(pool, rhs->media[i]);
}
// 复制其他参数
sess->other_count = rhs->other_count;
for (i = 0; i < rhs->other_count; ++i) {
sess->other[i] = pjmedia_sdp_attr_clone(pool, rhs->other[i]);
}
最后
以上就是复杂花生为你收集整理的GB28181开发(二) pjsip库SDP协议扩展的全部内容,希望文章能够帮你解决GB28181开发(二) pjsip库SDP协议扩展所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复