sdp.c
来自「基于sip协议的网络电话源码」· C语言 代码 · 共 1,286 行 · 第 1/3 页
C
1,286 行
/* $Id: sdp.c 1195 2007-04-15 10:09:35Z bennylp $ *//* * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <pjmedia/sdp.h>#include <pjmedia/errno.h>#include <pjlib-util/scanner.h>#include <pj/array.h>#include <pj/except.h>#include <pj/log.h>#include <pj/os.h>#include <pj/string.h>#include <pj/pool.h>#include <pj/assert.h>#include <pj/ctype.h>enum { SKIP_WS = 0, SYNTAX_ERROR = 1,};#define TOKEN "-.!%*_=`'~"//#define TOKEN "'`-./:?\"#$&*;=@[]^_`{|}+~!"#define NTP_OFFSET ((pj_uint32_t)2208988800)#define THIS_FILE "sdp.c"typedef struct parse_context{ pj_status_t last_error;} parse_context;/* * Prototypes for line parser. */static void parse_version(pj_scanner *scanner, parse_context *ctx);static void parse_origin(pj_scanner *scanner, pjmedia_sdp_session *ses, parse_context *ctx);static void parse_time(pj_scanner *scanner, pjmedia_sdp_session *ses, parse_context *ctx);static void parse_generic_line(pj_scanner *scanner, pj_str_t *str, parse_context *ctx);static void parse_connection_info(pj_scanner *scanner, pjmedia_sdp_conn *conn, parse_context *ctx);static pjmedia_sdp_attr *parse_attr(pj_pool_t *pool, pj_scanner *scanner, parse_context *ctx);static void parse_media(pj_scanner *scanner, pjmedia_sdp_media *med, parse_context *ctx);static void on_scanner_error(pj_scanner *scanner);/* * Scanner character specification. */static int is_initialized;static pj_cis_buf_t cis_buf;static pj_cis_t cs_digit, cs_token;static void init_sdp_parser(void){ if (is_initialized != 0) return; pj_enter_critical_section(); if (is_initialized != 0) { pj_leave_critical_section(); return; } pj_cis_buf_init(&cis_buf); pj_cis_init(&cis_buf, &cs_token); pj_cis_add_alpha(&cs_token); pj_cis_add_num(&cs_token); pj_cis_add_str(&cs_token, TOKEN); pj_cis_init(&cis_buf, &cs_digit); pj_cis_add_num(&cs_digit); is_initialized = 1; pj_leave_critical_section();}PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_create( pj_pool_t *pool, const char *name, const pj_str_t *value){ pjmedia_sdp_attr *attr; PJ_ASSERT_RETURN(pool && name, NULL); attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr)); pj_strdup2(pool, &attr->name, name); if (value) pj_strdup_with_null(pool, &attr->value, value); else { attr->value.ptr = NULL; attr->value.slen = 0; } return attr;}PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_clone(pj_pool_t *pool, const pjmedia_sdp_attr *rhs){ pjmedia_sdp_attr *attr; PJ_ASSERT_RETURN(pool && rhs, NULL); attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr)); pj_strdup(pool, &attr->name, &rhs->name); pj_strdup_with_null(pool, &attr->value, &rhs->value); return attr;}PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_find (unsigned count, pjmedia_sdp_attr *const attr_array[], const pj_str_t *name, const pj_str_t *c_fmt){ unsigned i; unsigned c_pt = 0xFFFF; if (c_fmt) c_pt = pj_strtoul(c_fmt); for (i=0; i<count; ++i) { if (pj_strcmp(&attr_array[i]->name, name) == 0) { const pjmedia_sdp_attr *a = attr_array[i]; if (c_fmt) { unsigned pt = (unsigned) pj_strtoul2(&a->value, NULL, 10); if (pt == c_pt) { return (pjmedia_sdp_attr*)a; } } else return (pjmedia_sdp_attr*)a; } } return NULL;}PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_find2(unsigned count, pjmedia_sdp_attr *const attr_array[], const char *c_name, const pj_str_t *c_fmt){ pj_str_t name; name.ptr = (char*)c_name; name.slen = pj_ansi_strlen(c_name); return pjmedia_sdp_attr_find(count, attr_array, &name, c_fmt);}PJ_DEF(pj_status_t) pjmedia_sdp_attr_add(unsigned *count, pjmedia_sdp_attr *attr_array[], pjmedia_sdp_attr *attr){ PJ_ASSERT_RETURN(count && attr_array && attr, PJ_EINVAL); PJ_ASSERT_RETURN(*count < PJMEDIA_MAX_SDP_ATTR, PJ_ETOOMANY); attr_array[*count] = attr; (*count)++; return PJ_SUCCESS;}PJ_DEF(unsigned) pjmedia_sdp_attr_remove_all(unsigned *count, pjmedia_sdp_attr *attr_array[], const char *name){ unsigned i, removed = 0; pj_str_t attr_name; PJ_ASSERT_RETURN(count && attr_array && name, PJ_EINVAL); attr_name.ptr = (char*)name; attr_name.slen = pj_ansi_strlen(name); for (i=0; i<*count; ) { if (pj_strcmp(&attr_array[i]->name, &attr_name)==0) { pj_array_erase(attr_array, sizeof(pjmedia_sdp_attr*), *count, i); --(*count); ++removed; } else { ++i; } } return removed;}PJ_DEF(pj_status_t) pjmedia_sdp_attr_remove( unsigned *count, pjmedia_sdp_attr *attr_array[], pjmedia_sdp_attr *attr ){ unsigned i, removed=0; PJ_ASSERT_RETURN(count && attr_array && attr, PJ_EINVAL); for (i=0; i<*count; ) { if (attr_array[i] == attr) { pj_array_erase(attr_array, sizeof(pjmedia_sdp_attr*), *count, i); --(*count); ++removed; } else { ++i; } } return removed ? PJ_SUCCESS : PJ_ENOTFOUND;}PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_rtpmap( const pjmedia_sdp_attr *attr, pjmedia_sdp_rtpmap *rtpmap){ pj_scanner scanner; pj_str_t token; pj_status_t status = -1; char term = 0; PJ_USE_EXCEPTION; PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "rtpmap")==0, PJ_EINVALIDOP); PJ_ASSERT_RETURN(attr->value.slen != 0, PJMEDIA_SDP_EINATTR); /* Check if input is null terminated, and null terminate if * necessary. Unfortunately this may crash the application if * attribute was allocated from a read-only memory location. * But this shouldn't happen as attribute's value normally is * null terminated. */ if (attr->value.ptr[attr->value.slen] != 0 && attr->value.ptr[attr->value.slen] != '\r') { pj_assert(!"Shouldn't happen"); term = attr->value.ptr[attr->value.slen]; attr->value.ptr[attr->value.slen] = '\0'; } pj_scan_init(&scanner, (char*)attr->value.ptr, attr->value.slen, PJ_SCAN_AUTOSKIP_WS, &on_scanner_error); /* rtpmap sample: * a=rtpmap:98 L16/16000/2. */ /* Init */ rtpmap->pt.slen = rtpmap->param.slen = rtpmap->enc_name.slen = 0; rtpmap->clock_rate = 0; /* Parse */ PJ_TRY { /* Get payload type. */ pj_scan_get(&scanner, &cs_token, &rtpmap->pt); /* Get encoding name. */ pj_scan_get(&scanner, &cs_token, &rtpmap->enc_name); /* Expecting '/' after encoding name. */ if (pj_scan_get_char(&scanner) != '/') { status = PJMEDIA_SDP_EINRTPMAP; goto on_return; } /* Get the clock rate. */ pj_scan_get(&scanner, &cs_digit, &token); rtpmap->clock_rate = pj_strtoul(&token); /* Expecting either '/' or EOF */ if (*scanner.curptr == '/') { pj_scan_get_char(&scanner); rtpmap->param.ptr = scanner.curptr; rtpmap->param.slen = scanner.end - scanner.curptr; } else { rtpmap->param.slen = 0; } status = PJ_SUCCESS; } PJ_CATCH(SYNTAX_ERROR) { status = PJMEDIA_SDP_EINRTPMAP; } PJ_END;on_return: pj_scan_fini(&scanner); if (term) { attr->value.ptr[attr->value.slen] = term; } return status;}PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_fmtp( const pjmedia_sdp_attr *attr, pjmedia_sdp_fmtp *fmtp){ const char *p = attr->value.ptr; const char *end = attr->value.ptr + attr->value.slen; pj_str_t token; PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "fmtp")==0, PJ_EINVALIDOP); /* fmtp BNF: * a=fmtp:<format> <format specific parameter> */ /* Get format. */ token.ptr = (char*)p; while (pj_isdigit(*p) && p!=end) ++p; token.slen = p - token.ptr; if (token.slen == 0) return PJMEDIA_SDP_EINFMTP; fmtp->fmt = token; /* Expecting space after format. */ if (*p != ' ') return PJMEDIA_SDP_EINFMTP; /* Get space. */ ++p; /* Set the remaining string as fmtp format parameter. */ fmtp->fmt_param.ptr = (char*)p; fmtp->fmt_param.slen = end - p; return PJ_SUCCESS;}PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_rtcp(const pjmedia_sdp_attr *attr, pjmedia_sdp_rtcp_attr *rtcp){ pj_scanner scanner; pj_str_t token; pj_status_t status = -1; PJ_USE_EXCEPTION; PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "rtcp")==0, PJ_EINVALIDOP); /* fmtp BNF: * a=rtcp:<port> [nettype addrtype address] */ pj_scan_init(&scanner, (char*)attr->value.ptr, attr->value.slen, PJ_SCAN_AUTOSKIP_WS, &on_scanner_error); /* Init */ rtcp->net_type.slen = rtcp->addr_type.slen = rtcp->addr.slen = 0; /* Parse */ PJ_TRY { /* Get the port */ pj_scan_get(&scanner, &cs_token, &token); rtcp->port = pj_strtoul(&token); /* Have address? */ if (!pj_scan_is_eof(&scanner)) { /* Get network type */ pj_scan_get(&scanner, &cs_token, &rtcp->net_type); /* Get address type */ pj_scan_get(&scanner, &cs_token, &rtcp->addr_type); /* Get the address */ pj_scan_get(&scanner, &cs_token, &rtcp->addr); } status = PJ_SUCCESS; } PJ_CATCH(SYNTAX_ERROR) { status = PJMEDIA_SDP_EINRTCP; } PJ_END; pj_scan_fini(&scanner); return status;}PJ_DEF(pj_status_t) pjmedia_sdp_attr_to_rtpmap(pj_pool_t *pool, const pjmedia_sdp_attr *attr, pjmedia_sdp_rtpmap **p_rtpmap){ PJ_ASSERT_RETURN(pool && attr && p_rtpmap, PJ_EINVAL); *p_rtpmap = pj_pool_alloc(pool, sizeof(pjmedia_sdp_rtpmap)); PJ_ASSERT_RETURN(*p_rtpmap, PJ_ENOMEM); return pjmedia_sdp_attr_get_rtpmap(attr, *p_rtpmap);}PJ_DEF(pj_status_t) pjmedia_sdp_rtpmap_to_attr(pj_pool_t *pool,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?