我是靠谱客的博主 复杂花生,最近开发中收集的这篇文章主要介绍GB28181开发(二) pjsip库SDP协议扩展,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

项目使用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协议扩展所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部