Ignore:
Timestamp:
Feb 2, 2006 7:16:07 PM (18 years ago)
Author:
bennylp
Message:

Added SDP negotiator and changed SDP structs (tested)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/sdp.c

    r121 r129  
    1818 */ 
    1919#include <pjmedia/sdp.h> 
     20#include <pjmedia/errno.h> 
    2021#include <pjlib-util/scanner.h> 
     22#include <pj/array.h> 
    2123#include <pj/except.h> 
    2224#include <pj/log.h> 
     
    2527#include <pj/pool.h> 
    2628#include <pj/assert.h> 
     29#include <pj/ctype.h> 
     30 
    2731 
    2832enum { 
     
    3236#define TOKEN           "-.!%*_=`'~" 
    3337#define NTP_OFFSET      ((pj_uint32_t)2208988800) 
    34 #define LOG_THIS        "sdp" 
     38#define THIS_FILE       "sdp.c" 
     39 
     40typedef struct parse_context 
     41{  
     42    pj_status_t last_error; 
     43} parse_context; 
     44 
    3545 
    3646/* 
    3747 * Prototypes for line parser. 
    3848 */ 
    39 static void parse_version(pj_scanner *scanner); 
    40 static void parse_origin(pj_scanner *scanner, pjsdp_session_desc *ses); 
    41 static void parse_time(pj_scanner *scanner, pjsdp_session_desc *ses); 
    42 static void parse_generic_line(pj_scanner *scanner, pj_str_t *str); 
    43 static void parse_connection_info(pj_scanner *scanner, pjsdp_conn_info *conn); 
    44 static pjsdp_attr *parse_attr(pj_pool_t *pool, pj_scanner *scanner); 
    45 static void parse_media(pj_scanner *scanner, pjsdp_media_desc *med); 
    46  
    47 /* 
    48  * Prototypes for attribute parsers. 
    49  */ 
    50 static pjsdp_rtpmap_attr *  parse_rtpmap_attr( pj_pool_t *pool, pj_scanner *scanner ); 
    51 static pjsdp_attr_string *  parse_generic_string_attr( pj_pool_t *pool, pj_scanner *scanner ); 
    52 static pjsdp_attr_num *     parse_generic_num_attr( pj_pool_t *pool, pj_scanner *scanner ); 
    53 static pjsdp_attr *         parse_name_only_attr( pj_pool_t *pool, pj_scanner *scanner ); 
    54 static pjsdp_fmtp_attr *    parse_fmtp_attr( pj_pool_t *pool, pj_scanner *scanner ); 
    55  
    56  
    57 /*  
    58  * Prototypes for functions to print attribute. 
    59  * All of them returns integer for the length printed, or -1 on error. 
    60  */ 
    61 static int print_rtpmap_attr(const pjsdp_rtpmap_attr *attr,  
    62                              char *buf, int length); 
    63 static int print_generic_string_attr(const pjsdp_attr_string *attr,  
    64                                      char *buf, int length); 
    65 static int print_generic_num_attr(const pjsdp_attr_num *attr,  
    66                                   char *buf, int length); 
    67 static int print_name_only_attr(const pjsdp_attr *attr,  
    68                                 char *buf, int length); 
    69 static int print_fmtp_attr(const pjsdp_fmtp_attr *attr,  
    70                            char *buf, int length); 
    71  
    72 /* 
    73  * Prototypes for cloning attributes. 
    74  */ 
    75 static pjsdp_attr* clone_rtpmap_attr (pj_pool_t *pool, const pjsdp_attr *rhs); 
    76 static pjsdp_attr* clone_generic_string_attr (pj_pool_t *pool, const pjsdp_attr *rhs); 
    77 static pjsdp_attr* clone_generic_num_attr (pj_pool_t *pool, const pjsdp_attr *rhs); 
    78 static pjsdp_attr* clone_name_only_attr (pj_pool_t *pool, const pjsdp_attr *rhs); 
    79 static pjsdp_attr* clone_fmtp_attr (pj_pool_t *pool, const pjsdp_attr *rhs); 
    80  
    81  
    82 /* 
    83  * Prototypes 
    84  */ 
    85 static void init_sdp_parser(void); 
    86  
    87  
    88 typedef void *  (*FPARSE)(pj_pool_t *pool, pj_scanner *scanner); 
    89 typedef int (*FPRINT)(const void *attr, char *buf, int length); 
    90 typedef pjsdp_attr*  (*FCLONE)(pj_pool_t *pool, const pjsdp_attr *rhs); 
    91  
    92 /* 
    93  * Array of functions to print attribute. 
    94  */ 
    95 static struct attr_map_rec 
    96 { 
    97     pj_str_t name; 
    98     FPARSE   parse_attr; 
    99     FPRINT   print_attr; 
    100     FCLONE   clone; 
    101 } attr_map[] =  
    102 { 
    103     {{"rtpmap", 6},    (FPARSE)&parse_rtpmap_attr,         (FPRINT)&print_rtpmap_attr,          (FCLONE)&clone_rtpmap_attr}, 
    104     {{"cat", 3},       (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,  (FCLONE)&clone_generic_string_attr}, 
    105     {{"keywds", 6},    (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,  (FCLONE)&clone_generic_string_attr}, 
    106     {{"tool", 4},      (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,  (FCLONE)&clone_generic_string_attr}, 
    107     {{"ptime", 5},     (FPARSE)&parse_generic_num_attr,    (FPRINT)&print_generic_num_attr,     (FCLONE)&clone_generic_num_attr}, 
    108     {{"recvonly", 8},  (FPARSE)&parse_name_only_attr,      (FPRINT)&print_name_only_attr,       (FCLONE)&clone_name_only_attr}, 
    109     {{"sendonly", 8},  (FPARSE)&parse_name_only_attr,      (FPRINT)&print_name_only_attr,       (FCLONE)&clone_name_only_attr}, 
    110     {{"sendrecv", 8},  (FPARSE)&parse_name_only_attr,      (FPRINT)&print_name_only_attr,       (FCLONE)&clone_name_only_attr}, 
    111     {{"orient", 6},    (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,  (FCLONE)&clone_generic_string_attr}, 
    112     {{"type", 4},      (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,  (FCLONE)&clone_generic_string_attr}, 
    113     {{"charset", 7},   (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,  (FCLONE)&clone_generic_string_attr}, 
    114     {{"sdplang", 7},   (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,  (FCLONE)&clone_generic_string_attr}, 
    115     {{"lang", 4},      (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,  (FCLONE)&clone_generic_string_attr}, 
    116     {{"framerate", 9}, (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,  (FCLONE)&clone_generic_string_attr}, 
    117     {{"quality", 7},   (FPARSE)&parse_generic_num_attr,    (FPRINT)&print_generic_num_attr,     (FCLONE)&clone_generic_num_attr}, 
    118     {{"fmtp", 4},      (FPARSE)&parse_fmtp_attr,           (FPRINT)&print_fmtp_attr,            (FCLONE)&clone_fmtp_attr}, 
    119     {{"inactive", 8},  (FPARSE)&parse_name_only_attr,      (FPRINT)&print_name_only_attr,       (FCLONE)&clone_name_only_attr}, 
    120     {{"", 0},          NULL, (FPRINT)&print_generic_string_attr,        (FCLONE)&clone_generic_string_attr} 
    121 }; 
     49static void parse_version(pj_scanner *scanner, parse_context *ctx); 
     50static void parse_origin(pj_scanner *scanner, pjmedia_sdp_session *ses, 
     51                         parse_context *ctx); 
     52static void parse_time(pj_scanner *scanner, pjmedia_sdp_session *ses, 
     53                       parse_context *ctx); 
     54static void parse_generic_line(pj_scanner *scanner, pj_str_t *str, 
     55                               parse_context *ctx); 
     56static void parse_connection_info(pj_scanner *scanner, pjmedia_sdp_conn *conn, 
     57                                  parse_context *ctx); 
     58static pjmedia_sdp_attr *parse_attr(pj_pool_t *pool, pj_scanner *scanner, 
     59                                    parse_context *ctx); 
     60static void parse_media(pj_scanner *scanner, pjmedia_sdp_media *med, 
     61                        parse_context *ctx); 
     62 
    12263 
    12364/* 
     
    14485} 
    14586 
    146 static int print_rtpmap_attr(const pjsdp_rtpmap_attr *rtpmap,  
    147                              char *buf, int len) 
    148 { 
    149     char *p = buf; 
    150  
    151     if (len < 16+rtpmap->encoding_name.slen+rtpmap->parameter.slen) { 
    152         return -1; 
    153     } 
     87PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_create( pj_pool_t *pool, 
     88                                                   const char *name, 
     89                                                   const pj_str_t *value) 
     90{ 
     91    pjmedia_sdp_attr *attr; 
     92 
     93    PJ_ASSERT_RETURN(pool && name, NULL); 
     94 
     95    attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr)); 
     96    pj_strdup2(pool, &attr->name, name); 
     97 
     98    if (value) 
     99        pj_strdup(pool, &attr->value, value); 
     100    else { 
     101        attr->value.ptr = NULL; 
     102        attr->value.slen = 0; 
     103    } 
     104 
     105    return attr; 
     106} 
     107 
     108PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_clone(pj_pool_t *pool,  
     109                                                 const pjmedia_sdp_attr *rhs) 
     110{ 
     111    pjmedia_sdp_attr *attr; 
    154112     
    155     /* colon and payload type. */ 
    156     *p++ = ':'; 
    157     len = pj_utoa(rtpmap->payload_type, p); 
    158     p += len; 
    159  
    160     /* space, encoding name */ 
     113    PJ_ASSERT_RETURN(pool && rhs, NULL); 
     114 
     115    attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr)); 
     116 
     117    pj_strdup(pool, &attr->name, &rhs->name); 
     118    pj_strdup(pool, &attr->value, &rhs->value); 
     119 
     120    return attr; 
     121} 
     122 
     123PJ_DEF(pjmedia_sdp_attr*)  
     124pjmedia_sdp_attr_find (unsigned count,  
     125                       const pjmedia_sdp_attr *const attr_array[], 
     126                       const pj_str_t *name, 
     127                       const pj_str_t *c_fmt) 
     128{ 
     129    char fmtbuf[16]; 
     130    pj_str_t fmt = { NULL, 0}; 
     131    unsigned i; 
     132 
     133    if (c_fmt) { 
     134        /* To search the format, we prepend the string with a colon and 
     135         * append space 
     136         */ 
     137        PJ_ASSERT_RETURN(c_fmt->slen<sizeof(fmtbuf)-2, NULL); 
     138        fmt.ptr = fmtbuf; 
     139        fmt.slen = c_fmt->slen + 2; 
     140        fmtbuf[0] = ':'; 
     141        pj_memcpy(fmt.ptr+1, c_fmt->ptr, c_fmt->slen); 
     142        fmtbuf[c_fmt->slen+1] = ' '; 
     143 
     144    }  
     145 
     146    for (i=0; i<count; ++i) { 
     147        if (pj_strcmp(&attr_array[i]->name, name) == 0) { 
     148            const pjmedia_sdp_attr *a = attr_array[i]; 
     149            if (c_fmt) { 
     150                if (a->value.slen > fmt.slen && 
     151                    pj_strncmp(&a->value, &fmt, fmt.slen)==0) 
     152                { 
     153                    return (pjmedia_sdp_attr*)a; 
     154                } 
     155            } else  
     156                return (pjmedia_sdp_attr*)a; 
     157        } 
     158    } 
     159    return NULL; 
     160} 
     161 
     162PJ_DEF(pjmedia_sdp_attr*)  
     163pjmedia_sdp_attr_find2(unsigned count,  
     164                       const pjmedia_sdp_attr *const attr_array[], 
     165                       const char *c_name, 
     166                       const pj_str_t *c_fmt) 
     167{ 
     168    pj_str_t name; 
     169 
     170    name.ptr = (char*)c_name; 
     171    name.slen = pj_native_strlen(c_name); 
     172 
     173    return pjmedia_sdp_attr_find(count, attr_array, &name, c_fmt); 
     174} 
     175 
     176 
     177PJ_DEF(pj_status_t) pjmedia_sdp_attr_add(unsigned *count, 
     178                                         pjmedia_sdp_attr *attr_array[], 
     179                                         pjmedia_sdp_attr *attr) 
     180{ 
     181    PJ_ASSERT_RETURN(count && attr_array && attr, PJ_EINVAL); 
     182    PJ_ASSERT_RETURN(*count < PJSDP_MAX_ATTR, PJ_ETOOMANY); 
     183 
     184    attr_array[*count] = attr; 
     185    (*count)++; 
     186 
     187    return PJ_SUCCESS; 
     188} 
     189 
     190 
     191PJ_DEF(unsigned) pjmedia_sdp_attr_remove_all(unsigned *count, 
     192                                             pjmedia_sdp_attr *attr_array[], 
     193                                             const char *name) 
     194{ 
     195    unsigned i, removed = 0; 
     196    pj_str_t attr_name; 
     197 
     198    PJ_ASSERT_RETURN(count && attr_array && name, PJ_EINVAL); 
     199 
     200    attr_name.ptr = (char*)name; 
     201    attr_name.slen = pj_native_strlen(name); 
     202 
     203    for (i=0; i<*count; ) { 
     204        if (pj_strcmp(&attr_array[i]->name, &attr_name)==0) { 
     205            pj_array_erase(attr_array, sizeof(pjmedia_sdp_attr*), 
     206                           *count, i); 
     207            --(*count); 
     208            ++removed; 
     209        } else { 
     210            ++i; 
     211        }    
     212    } 
     213 
     214    return removed; 
     215} 
     216 
     217 
     218PJ_DEF(pj_status_t) pjmedia_sdp_attr_remove( unsigned *count, 
     219                                             pjmedia_sdp_attr *attr_array[], 
     220                                             pjmedia_sdp_attr *attr ) 
     221{ 
     222    unsigned i, removed=0; 
     223 
     224    PJ_ASSERT_RETURN(count && attr_array && attr, PJ_EINVAL); 
     225 
     226    for (i=0; i<*count; ) { 
     227        if (attr_array[i] == attr) { 
     228            pj_array_erase(attr_array, sizeof(pjmedia_sdp_attr*), 
     229                           *count, i); 
     230            --(*count); 
     231            ++removed; 
     232        } else { 
     233            ++i; 
     234        } 
     235    } 
     236 
     237    return removed ? PJ_SUCCESS : PJ_ENOTFOUND; 
     238} 
     239 
     240 
     241PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_rtpmap( const pjmedia_sdp_attr *attr, 
     242                                                 pjmedia_sdp_rtpmap *rtpmap) 
     243{ 
     244    const char *p = attr->value.ptr; 
     245    const char *end = attr->value.ptr + attr->value.slen; 
     246    pj_str_t token; 
     247 
     248    PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "rtpmap")==0, PJ_EINVALIDOP); 
     249 
     250    /* rtpmap sample: 
     251     *  a=rtpmap:98 L16/16000/2. 
     252     */ 
     253 
     254    /* Eat the first ':' */ 
     255    if (*p != ':') return PJMEDIA_SDP_EINRTPMAP; 
     256 
     257    /* Get ':' */ 
     258    ++p; 
     259 
     260    /* Get payload type. */ 
     261    token.ptr = (char*)p; 
     262    while (pj_isdigit(*p) && p!=end) 
     263        ++p; 
     264    token.slen = p - token.ptr; 
     265    if (token.slen == 0) 
     266        return PJMEDIA_SDP_EINRTPMAP; 
     267 
     268    rtpmap->pt = token; 
     269 
     270    /* Expecting space after payload type. */ 
     271    if (*p != ' ') return PJMEDIA_SDP_EINRTPMAP; 
     272 
     273    /* Get space. */ 
     274    ++p; 
     275 
     276    /* Get encoding name. */ 
     277    token.ptr = (char*)p; 
     278    while (*p != '/' && p != end) 
     279        ++p; 
     280    token.slen = p - token.ptr; 
     281    if (token.slen == 0) 
     282        return PJMEDIA_SDP_EINRTPMAP; 
     283    rtpmap->enc_name = token; 
     284 
     285    /* Expecting '/' after encoding name. */ 
     286    if (*p != '/') return PJMEDIA_SDP_EINRTPMAP; 
     287 
     288    /* Get '/' */ 
     289    ++p; 
     290 
     291    /* Get the clock rate. */ 
     292    token.ptr = (char*)p; 
     293    while (pj_isdigit(*p) && p != end) 
     294        ++p; 
     295    token.slen = p - token.ptr; 
     296    if (token.slen == 0) 
     297        return PJMEDIA_SDP_EINRTPMAP; 
     298 
     299    rtpmap->clock_rate = pj_strtoul(&token); 
     300 
     301    /* Expecting either '/' or EOF */ 
     302    if (*p != '/' && p != end) 
     303        return PJMEDIA_SDP_EINRTPMAP; 
     304 
     305    if (*p == '/') { 
     306        ++p; 
     307        token.ptr = (char*)p; 
     308        token.slen = end-p; 
     309        rtpmap->param = token; 
     310    } else { 
     311        rtpmap->param.ptr = NULL; 
     312        rtpmap->param.slen = 0; 
     313    } 
     314 
     315    return PJ_SUCCESS; 
     316 
     317} 
     318 
     319PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_fmtp( const pjmedia_sdp_attr *attr, 
     320                                               pjmedia_sdp_fmtp *fmtp) 
     321{ 
     322    const char *p = attr->value.ptr; 
     323    const char *end = attr->value.ptr + attr->value.slen; 
     324    pj_str_t token; 
     325 
     326    PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "fmtp")==0, PJ_EINVALIDOP); 
     327 
     328    /* fmtp BNF: 
     329     *  a=fmtp:<format> <format specific parameter> 
     330     */ 
     331 
     332    /* Eat the first ':' */ 
     333    if (*p != ':') return PJMEDIA_SDP_EINFMTP; 
     334 
     335    /* Get ':' */ 
     336    ++p; 
     337 
     338    /* Get format. */ 
     339    token.ptr = (char*)p; 
     340    while (pj_isdigit(*p) && p!=end) 
     341        ++p; 
     342    token.slen = p - token.ptr; 
     343    if (token.slen == 0) 
     344        return PJMEDIA_SDP_EINFMTP; 
     345 
     346    fmtp->fmt = token; 
     347 
     348    /* Expecting space after format. */ 
     349    if (*p != ' ') return PJMEDIA_SDP_EINFMTP; 
     350 
     351    /* Get space. */ 
     352    ++p; 
     353 
     354    /* Set the remaining string as fmtp format parameter. */ 
     355    fmtp->fmt_param.ptr = (char*)p; 
     356    fmtp->fmt_param.slen = end - p; 
     357 
     358    return PJ_SUCCESS; 
     359} 
     360 
     361PJ_DEF(pj_status_t) pjmedia_sdp_attr_to_rtpmap(pj_pool_t *pool, 
     362                                               const pjmedia_sdp_attr *attr, 
     363                                               pjmedia_sdp_rtpmap **p_rtpmap) 
     364{ 
     365    PJ_ASSERT_RETURN(pool && attr && p_rtpmap, PJ_EINVAL); 
     366 
     367    *p_rtpmap = pj_pool_alloc(pool, sizeof(pjmedia_sdp_rtpmap)); 
     368    PJ_ASSERT_RETURN(*p_rtpmap, PJ_ENOMEM); 
     369 
     370    return pjmedia_sdp_attr_get_rtpmap(attr, *p_rtpmap); 
     371} 
     372 
     373 
     374PJ_DEF(pj_status_t) pjmedia_sdp_rtpmap_to_attr(pj_pool_t *pool, 
     375                                               const pjmedia_sdp_rtpmap *rtpmap, 
     376                                               pjmedia_sdp_attr **p_attr) 
     377{ 
     378    pjmedia_sdp_attr *attr; 
     379    char tempbuf[64], *p, *endbuf; 
     380    int i; 
     381 
     382    /* Check arguments. */ 
     383    PJ_ASSERT_RETURN(pool && rtpmap && p_attr, PJ_EINVAL); 
     384 
     385    /* Check that mandatory attributes are specified. */ 
     386    PJ_ASSERT_RETURN(rtpmap->enc_name.slen && rtpmap->clock_rate, 
     387                     PJMEDIA_SDP_EINRTPMAP); 
     388 
     389    /* Check size. */ 
     390    i = rtpmap->enc_name.slen + rtpmap->param.slen + 32; 
     391    if (i >= sizeof(tempbuf)-1) { 
     392        pj_assert(!"rtpmap attribute is too long"); 
     393        return PJMEDIA_SDP_ERTPMAPTOOLONG; 
     394    } 
     395 
     396    attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr)); 
     397    PJ_ASSERT_RETURN(attr != NULL, PJ_ENOMEM); 
     398 
     399    attr->name.ptr = "rtpmap"; 
     400    attr->name.slen = 6; 
     401 
     402    p = tempbuf; 
     403    endbuf = tempbuf+sizeof(tempbuf); 
     404 
     405    /* Add payload type. */ 
     406    pj_memcpy(p, rtpmap->pt.ptr, rtpmap->pt.slen); 
     407    p += rtpmap->pt.slen; 
    161408    *p++ = ' '; 
    162     pj_memcpy(p, rtpmap->encoding_name.ptr, rtpmap->encoding_name.slen); 
    163     p += rtpmap->encoding_name.slen; 
    164  
    165     /* slash, clock-rate. */ 
     409 
     410    /* Add encoding name. */ 
     411    for (i=0; i<rtpmap->enc_name.slen; ++i) 
     412        p[i] = rtpmap->enc_name.ptr[i]; 
     413    p += rtpmap->enc_name.slen; 
    166414    *p++ = '/'; 
    167     len = pj_utoa(rtpmap->clock_rate, p); 
    168     p += len; 
    169  
    170     /* optionally add encoding parameter. */ 
    171     if (rtpmap->parameter.slen) { 
     415 
     416    /* Add clock rate. */ 
     417    p += pj_utoa(rtpmap->clock_rate, p); 
     418 
     419    /* Add parameter if necessary. */ 
     420    if (rtpmap->param.slen > 0) { 
    172421        *p++ = '/'; 
    173         pj_memcpy(p, rtpmap->parameter.ptr, rtpmap->parameter.slen); 
    174         p += rtpmap->parameter.slen; 
    175     } 
    176  
    177     return p-buf; 
    178 } 
    179  
    180 static int print_generic_string_attr(const pjsdp_attr_string *attr,  
    181                                      char *buf, int len) 
    182 { 
    183     char *p = buf; 
    184  
    185     if (len < attr->value.slen + 4) { 
    186         return -1; 
    187     } 
    188  
    189     /* colon and attribute value. */ 
    190     *p++ = ':'; 
    191     pj_memcpy(p, attr->value.ptr, attr->value.slen); 
    192     p += attr->value.slen; 
    193  
    194     return p-buf; 
    195 } 
    196  
    197 static int print_generic_num_attr(const pjsdp_attr_num *attr, char *buf, int len) 
    198 { 
    199     char *p = buf; 
    200  
    201     if (len < 10) { 
    202         return -1; 
    203     } 
    204     *p++ = ':'; 
    205     return pj_utoa(attr->value, p); 
    206 } 
    207  
    208 static int print_name_only_attr(const pjsdp_attr *attr, char *buf, int len) 
    209 { 
    210     PJ_UNUSED_ARG(attr); 
    211     PJ_UNUSED_ARG(buf); 
    212     PJ_UNUSED_ARG(len); 
    213     return 0; 
    214 } 
    215  
    216 static int print_fmtp_attr(const pjsdp_fmtp_attr *fmtp, char *buf, int len) 
    217 { 
    218     char *p = buf; 
    219  
    220     if (len < 4+fmtp->format.slen+fmtp->param.slen) { 
    221         return -1; 
    222     } 
    223  
    224     /* colon and format. */ 
    225     *p++ = ':'; 
    226     pj_memcpy(p, fmtp->format.ptr, fmtp->format.slen); 
    227     p += fmtp->format.slen; 
    228  
    229     /* space and parameter. */ 
    230     *p++ = ' '; 
    231     pj_memcpy(p, fmtp->param.ptr, fmtp->param.slen); 
    232     p += fmtp->param.slen; 
    233  
    234     return p-buf; 
    235 } 
    236  
    237  
    238 static int print_attr(const pjsdp_attr *attr, char *buf, int len) 
    239 { 
    240     char *p = buf; 
    241     struct attr_map_rec *desc = &attr_map[attr->type]; 
    242  
    243     if (len < 16) { 
    244         return -1; 
    245     } 
    246  
    247     *p++ = 'a'; 
    248     *p++ = '='; 
    249     pj_memcpy(p, desc->name.ptr, desc->name.slen); 
    250     p += desc->name.slen; 
    251      
    252     len = (*desc->print_attr)(attr, p, (buf+len)-p); 
    253     if (len < 0) { 
    254         return -1; 
    255     } 
    256     p += len; 
    257     *p++ = '\r'; 
    258     *p++ = '\n'; 
    259     return p-buf; 
    260 } 
    261  
    262 static pjsdp_attr* clone_rtpmap_attr (pj_pool_t *pool, const pjsdp_attr *p) 
    263 { 
    264     const pjsdp_rtpmap_attr *rhs = (const pjsdp_rtpmap_attr*)p; 
    265     pjsdp_rtpmap_attr *attr = pj_pool_alloc (pool, sizeof(pjsdp_rtpmap_attr)); 
    266     if (!attr) 
    267         return NULL; 
    268  
    269     attr->type = rhs->type; 
    270     attr->payload_type = rhs->payload_type; 
    271     if (!pj_strdup (pool, &attr->encoding_name, &rhs->encoding_name)) return NULL; 
    272     attr->clock_rate = rhs->clock_rate; 
    273     if (!pj_strdup (pool, &attr->parameter, &rhs->parameter)) return NULL; 
    274  
    275     return (pjsdp_attr*)attr; 
    276 } 
    277  
    278 static pjsdp_attr* clone_generic_string_attr (pj_pool_t *pool, const pjsdp_attr *p) 
    279 { 
    280     const pjsdp_attr_string* rhs = (const pjsdp_attr_string*) p; 
    281     pjsdp_attr_string *attr = pj_pool_alloc (pool, sizeof(pjsdp_attr_string)); 
    282     if (!attr) 
    283         return NULL; 
    284  
    285     attr->type = rhs->type; 
    286     if (!pj_strdup (pool, &attr->value, &rhs->value)) return NULL; 
    287  
    288     return (pjsdp_attr*)attr; 
    289 } 
    290  
    291 static pjsdp_attr* clone_generic_num_attr (pj_pool_t *pool, const pjsdp_attr *p) 
    292 { 
    293     const pjsdp_attr_num* rhs = (const pjsdp_attr_num*) p; 
    294     pjsdp_attr_num *attr = pj_pool_alloc (pool, sizeof(pjsdp_attr_num)); 
    295     if (!attr) 
    296         return NULL; 
    297  
    298     attr->type = rhs->type; 
    299     attr->value = rhs->value; 
    300  
    301     return (pjsdp_attr*)attr; 
    302 } 
    303  
    304 static pjsdp_attr* clone_name_only_attr (pj_pool_t *pool, const pjsdp_attr *rhs) 
    305 { 
    306     pjsdp_attr *attr = pj_pool_alloc (pool, sizeof(pjsdp_attr)); 
    307     if (!attr) 
    308         return NULL; 
    309  
    310     attr->type = rhs->type; 
    311     return attr; 
    312 } 
    313  
    314 static pjsdp_attr* clone_fmtp_attr (pj_pool_t *pool, const pjsdp_attr *p) 
    315 { 
    316     const pjsdp_fmtp_attr* rhs = (const pjsdp_fmtp_attr*) p; 
    317     pjsdp_fmtp_attr *attr = pj_pool_alloc (pool, sizeof(pjsdp_fmtp_attr)); 
    318     if (!attr) 
    319         return NULL; 
    320  
    321     attr->type = rhs->type; 
    322     if (!pj_strdup (pool, &attr->format, &rhs->format)) return NULL; 
    323     if (!pj_strdup (pool, &attr->param, &rhs->param)) return NULL; 
    324  
    325     return (pjsdp_attr*)attr; 
    326 } 
    327  
    328 PJ_DEF(pjsdp_attr*) pjsdp_attr_clone (pj_pool_t *pool, const pjsdp_attr *rhs) 
    329 { 
    330     struct attr_map_rec *desc; 
    331  
    332     if (rhs->type >= PJSDP_END_OF_ATTR) { 
    333         pj_assert(0); 
    334         return NULL; 
    335     } 
    336  
    337     desc = &attr_map[rhs->type]; 
    338     return (*desc->clone) (pool, rhs); 
    339 } 
    340  
    341 PJ_DEF(const pjsdp_attr*) pjsdp_attr_find (int count, const pjsdp_attr *attr_array[], int type) 
    342 { 
    343     int i; 
    344  
    345     for (i=0; i<count; ++i) { 
    346         if (attr_array[i]->type == type) 
    347             return attr_array[i]; 
    348     } 
    349     return NULL; 
    350 } 
    351  
    352 static int print_connection_info( pjsdp_conn_info *c, char *buf, int len) 
     422        for (i=0; i<rtpmap->param.slen; ++i) 
     423            p[i] = rtpmap->param.ptr[i]; 
     424        p += rtpmap->param.slen; 
     425    } 
     426 
     427    *p = '\0'; 
     428 
     429    attr->value.slen = p-tempbuf; 
     430    attr->value.ptr = pj_pool_alloc(pool, attr->value.slen); 
     431    pj_memcpy(attr->value.ptr, tempbuf, attr->value.slen); 
     432 
     433    *p_attr = attr; 
     434    return PJ_SUCCESS; 
     435} 
     436 
     437 
     438static int print_connection_info( pjmedia_sdp_conn *c, char *buf, int len) 
    353439{ 
    354440    char *p = buf; 
     
    373459} 
    374460 
    375 PJ_DEF(pjsdp_conn_info*) pjsdp_conn_info_clone (pj_pool_t *pool, const pjsdp_conn_info *rhs) 
    376 { 
    377     pjsdp_conn_info *c = pj_pool_alloc (pool, sizeof(pjsdp_conn_info)); 
     461PJ_DEF(pjmedia_sdp_conn*) pjmedia_sdp_conn_clone (pj_pool_t *pool,  
     462                                                  const pjmedia_sdp_conn *rhs) 
     463{ 
     464    pjmedia_sdp_conn *c = pj_pool_alloc (pool, sizeof(pjmedia_sdp_conn)); 
    378465    if (!c) return NULL; 
    379466 
     
    385472} 
    386473 
    387 static int print_media_desc( pjsdp_media_desc *m, char *buf, int len) 
     474static pj_ssize_t print_attr(const pjmedia_sdp_attr *attr,  
     475                             char *buf, pj_size_t len) 
     476{ 
     477    char *p = buf; 
     478 
     479    if ((int)len < attr->name.slen + attr->value.slen + 10) 
     480        return -1; 
     481 
     482    *p++ = 'a'; 
     483    *p++ = '='; 
     484    pj_memcpy(p, attr->name.ptr, attr->name.slen); 
     485    p += attr->name.slen; 
     486     
     487 
     488    if (attr->value.slen) { 
     489        pj_memcpy(p, attr->value.ptr, attr->value.slen); 
     490        p += attr->value.slen; 
     491    } 
     492 
     493    *p++ = '\r'; 
     494    *p++ = '\n'; 
     495    return p-buf; 
     496} 
     497 
     498static int print_media_desc( pjmedia_sdp_media *m, char *buf, int len) 
    388499{ 
    389500    char *p = buf; 
     
    440551} 
    441552 
    442 PJ_DEF(pjsdp_media_desc*) pjsdp_media_desc_clone (pj_pool_t *pool,  
    443                                                   const pjsdp_media_desc *rhs) 
     553PJ_DEF(pjmedia_sdp_media*) pjmedia_sdp_media_clone( 
     554                                                 pj_pool_t *pool,  
     555                                                 const pjmedia_sdp_media *rhs) 
    444556{ 
    445557    unsigned int i; 
    446     pjsdp_media_desc *m = pj_pool_alloc (pool, sizeof(pjsdp_media_desc)); 
    447     if (!m) 
    448         return NULL; 
     558    pjmedia_sdp_media *m = pj_pool_alloc (pool, sizeof(pjmedia_sdp_media)); 
     559    PJ_ASSERT_RETURN(m != NULL, NULL); 
    449560 
    450561    pj_strdup (pool, &m->desc.media, &rhs->desc.media); 
     
    457568 
    458569    if (rhs->conn) { 
    459         m->conn = pjsdp_conn_info_clone (pool, rhs->conn); 
    460         if (!m->conn) 
    461             return NULL; 
     570        m->conn = pjmedia_sdp_conn_clone (pool, rhs->conn); 
     571        PJ_ASSERT_RETURN(m->conn != NULL, NULL); 
    462572    } else { 
    463573        m->conn = NULL; 
     
    466576    m->attr_count = rhs->attr_count; 
    467577    for (i=0; i < rhs->attr_count; ++i) { 
    468         m->attr[i] = pjsdp_attr_clone (pool, rhs->attr[i]); 
    469         if (!m->attr[i]) 
    470             return NULL; 
     578        m->attr[i] = pjmedia_sdp_attr_clone (pool, rhs->attr[i]); 
     579        PJ_ASSERT_RETURN(m->attr[i] != NULL, NULL); 
    471580    } 
    472581 
     
    474583} 
    475584 
    476 /** Check if the media description has the specified attribute. */ 
    477 PJ_DEF(pj_bool_t) pjsdp_media_desc_has_attr (const pjsdp_media_desc *m,  
    478                                              pjsdp_attr_type_e attr_type) 
    479 { 
    480     unsigned i; 
    481     for (i=0; i<m->attr_count; ++i) { 
    482         pjsdp_attr *attr = m->attr[i]; 
    483         if (attr->type == attr_type) 
    484             return 1; 
    485     } 
    486     return 0; 
    487 } 
    488  
    489 /** Find rtpmap attribute for the specified payload type. */ 
    490 PJ_DEF(const pjsdp_rtpmap_attr*)  
    491 pjsdp_media_desc_find_rtpmap (const pjsdp_media_desc *m, unsigned pt) 
    492 { 
    493     unsigned i; 
    494     for (i=0; i<m->attr_count; ++i) { 
    495         pjsdp_attr *attr = m->attr[i]; 
    496         if (attr->type == PJSDP_ATTR_RTPMAP) { 
    497             const pjsdp_rtpmap_attr* rtpmap = (const pjsdp_rtpmap_attr*)attr; 
    498             if (rtpmap->payload_type == pt) 
    499                 return rtpmap; 
    500         } 
    501     } 
    502     return NULL; 
    503 } 
    504  
    505  
    506 static int print_session(const pjsdp_session_desc *ses, char *buf, pj_ssize_t len) 
     585PJ_DEF(pjmedia_sdp_attr*)  
     586pjmedia_sdp_media_find_attr(const pjmedia_sdp_media *m, 
     587                            const pj_str_t *name, const pj_str_t *fmt) 
     588{ 
     589    PJ_ASSERT_RETURN(m && name, NULL); 
     590    return pjmedia_sdp_attr_find(m->attr_count, m->attr, name, fmt); 
     591} 
     592 
     593 
     594 
     595PJ_DEF(pjmedia_sdp_attr*)  
     596pjmedia_sdp_media_find_attr2(const pjmedia_sdp_media *m, 
     597                             const char *name, const pj_str_t *fmt) 
     598{ 
     599    PJ_ASSERT_RETURN(m && name, NULL); 
     600    return pjmedia_sdp_attr_find2(m->attr_count, m->attr, name, fmt); 
     601} 
     602 
     603 
     604PJ_DEF(pj_status_t) pjmedia_sdp_media_add_attr( pjmedia_sdp_media *m, 
     605                                                pjmedia_sdp_attr *attr) 
     606{ 
     607    return pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 
     608} 
     609 
     610PJ_DEF(unsigned)  
     611pjmedia_sdp_media_remove_all_attr(pjmedia_sdp_media *m, 
     612                                  const char *name) 
     613{ 
     614    return pjmedia_sdp_attr_remove_all(&m->attr_count, m->attr, name); 
     615} 
     616 
     617PJ_DEF(pj_status_t) 
     618pjmedia_sdp_media_remove_attr(pjmedia_sdp_media *m, 
     619                              pjmedia_sdp_attr *attr) 
     620{ 
     621    return pjmedia_sdp_attr_remove(&m->attr_count, m->attr, attr); 
     622} 
     623 
     624static int print_session(const pjmedia_sdp_session *ses,  
     625                         char *buf, pj_ssize_t len) 
    507626{ 
    508627    char *p = buf; 
     
    605724 */ 
    606725 
    607 static void parse_version(pj_scanner *scanner) 
    608 { 
     726static void parse_version(pj_scanner *scanner, parse_context *ctx) 
     727{ 
     728    ctx->last_error = PJMEDIA_SDP_EINVER; 
     729 
    609730    pj_scan_advance_n(scanner, 3, SKIP_WS); 
    610731    pj_scan_get_newline(scanner); 
    611732} 
    612733 
    613 static void parse_origin(pj_scanner *scanner, pjsdp_session_desc *ses) 
     734static void parse_origin(pj_scanner *scanner, pjmedia_sdp_session *ses, 
     735                         parse_context *ctx) 
    614736{ 
    615737    pj_str_t str; 
     738 
     739    ctx->last_error = PJMEDIA_SDP_EINORIGIN; 
    616740 
    617741    /* o= */ 
     
    647771} 
    648772 
    649 static void parse_time(pj_scanner *scanner, pjsdp_session_desc *ses) 
     773static void parse_time(pj_scanner *scanner, pjmedia_sdp_session *ses, 
     774                       parse_context *ctx) 
    650775{ 
    651776    pj_str_t str; 
     777 
     778    ctx->last_error = PJMEDIA_SDP_EINTIME; 
    652779 
    653780    /* t= */ 
     
    668795} 
    669796 
    670 static void parse_generic_line(pj_scanner *scanner, pj_str_t *str) 
    671 { 
     797static void parse_generic_line(pj_scanner *scanner, pj_str_t *str, 
     798                               parse_context *ctx) 
     799{ 
     800    ctx->last_error = PJMEDIA_SDP_EINSDP; 
     801 
    672802    /* x= */ 
    673803    pj_scan_advance_n(scanner, 2, SKIP_WS); 
     
    680810} 
    681811 
    682 static void parse_connection_info(pj_scanner *scanner, pjsdp_conn_info *conn) 
    683 { 
     812static void parse_connection_info(pj_scanner *scanner, pjmedia_sdp_conn *conn, 
     813                                  parse_context *ctx) 
     814{ 
     815    ctx->last_error = PJMEDIA_SDP_EINCONN; 
     816 
    684817    /* c= */ 
    685818    pj_scan_advance_n(scanner, 2, SKIP_WS); 
     
    700833} 
    701834 
    702 static void parse_media(pj_scanner *scanner, pjsdp_media_desc *med) 
     835static void parse_media(pj_scanner *scanner, pjmedia_sdp_media *med, 
     836                        parse_context *ctx) 
    703837{ 
    704838    pj_str_t str; 
     839 
     840    ctx->last_error = PJMEDIA_SDP_EINMEDIA; 
    705841 
    706842    /* m= */ 
     
    742878} 
    743879 
    744 static pjsdp_rtpmap_attr * parse_rtpmap_attr( pj_pool_t *pool, pj_scanner *scanner ) 
    745 { 
    746     pjsdp_rtpmap_attr *rtpmap; 
    747     pj_str_t str; 
    748  
    749     rtpmap = pj_pool_calloc(pool, 1, sizeof(*rtpmap)); 
    750     if (pj_scan_get_char(scanner) != ':') { 
    751         PJ_THROW(SYNTAX_ERROR); 
    752     } 
    753     pj_scan_get_until_ch(scanner, ' ', &str); 
    754     rtpmap->payload_type = pj_strtoul(&str); 
    755     pj_scan_get_char(scanner); 
    756  
    757     pj_scan_get_until_ch(scanner, '/', &rtpmap->encoding_name); 
    758     pj_scan_get_char(scanner); 
    759     pj_scan_get(scanner, &cs_token, &str); 
    760     rtpmap->clock_rate = pj_strtoul(&str); 
    761  
    762     if (*scanner->curptr == '/') { 
    763         pj_scan_get_char(scanner); 
    764         pj_scan_get_until_ch(scanner, '\r', &rtpmap->parameter); 
    765     } 
    766  
    767     return rtpmap; 
    768 } 
    769  
    770 static pjsdp_attr_string * parse_generic_string_attr( pj_pool_t *pool, pj_scanner *scanner ) 
    771 { 
    772     pjsdp_attr_string *attr; 
    773     attr = pj_pool_calloc(pool, 1, sizeof(*attr)); 
    774  
    775     if (pj_scan_get_char(scanner) != ':') { 
    776         PJ_THROW(SYNTAX_ERROR); 
    777     } 
    778     pj_scan_get_until_ch(scanner, '\r', &attr->value); 
    779     return attr; 
    780 } 
    781  
    782 static pjsdp_attr_num * parse_generic_num_attr( pj_pool_t *pool, pj_scanner *scanner ) 
    783 { 
    784     pjsdp_attr_num *attr; 
    785     pj_str_t str; 
    786  
    787     attr = pj_pool_calloc(pool, 1, sizeof(*attr)); 
    788  
    789     if (pj_scan_get_char(scanner) != ':') { 
    790         PJ_THROW(SYNTAX_ERROR); 
    791     } 
    792     pj_scan_get_until_ch(scanner, '\r', &str); 
    793     attr->value = pj_strtoul(&str); 
    794     return attr; 
    795 } 
    796  
    797 static pjsdp_attr * parse_name_only_attr( pj_pool_t *pool, pj_scanner *scanner ) 
    798 { 
    799     pjsdp_attr *attr; 
    800  
     880static void on_scanner_error(pj_scanner *scanner) 
     881{ 
    801882    PJ_UNUSED_ARG(scanner); 
    802     attr = pj_pool_calloc(pool, 1, sizeof(*attr)); 
    803     return attr; 
    804 } 
    805  
    806 static pjsdp_fmtp_attr * parse_fmtp_attr( pj_pool_t *pool, pj_scanner *scanner ) 
    807 { 
    808     pjsdp_fmtp_attr *fmtp; 
    809  
    810     fmtp = pj_pool_calloc(pool, 1, sizeof(*fmtp)); 
    811  
    812     if (pj_scan_get_char(scanner) != ':') { 
    813         PJ_THROW(SYNTAX_ERROR); 
    814     } 
    815     pj_scan_get_until_ch(scanner, ' ', &fmtp->format); 
    816     pj_scan_get_char(scanner); 
    817     pj_scan_get_until_ch(scanner, '\r', &fmtp->param); 
    818     return fmtp; 
    819 } 
    820  
    821 static pjsdp_attr *parse_attr( pj_pool_t *pool, pj_scanner *scanner) 
    822 { 
    823     void * (*parse_func)(pj_pool_t *pool, pj_scanner *scanner) = NULL; 
    824     pj_str_t attrname; 
    825     unsigned i; 
    826     pjsdp_attr *attr; 
     883 
     884    PJ_THROW(SYNTAX_ERROR); 
     885} 
     886 
     887static pjmedia_sdp_attr *parse_attr( pj_pool_t *pool, pj_scanner *scanner, 
     888                                    parse_context *ctx) 
     889{ 
     890    pjmedia_sdp_attr *attr; 
     891 
     892    ctx->last_error = PJMEDIA_SDP_EINATTR; 
     893 
     894    attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr)); 
    827895 
    828896    /* skip a= */ 
     
    830898     
    831899    /* get attr name. */ 
    832     pj_scan_get(scanner, &cs_token, &attrname); 
    833  
    834     /* find entry to handle attrname */ 
    835     for (i=0; i<PJ_ARRAY_SIZE(attr_map); ++i) { 
    836         struct attr_map_rec *p = &attr_map[i]; 
    837         if (pj_strcmp(&attrname, &p->name) == 0) { 
    838             parse_func = p->parse_attr; 
    839             break; 
    840         } 
    841     } 
    842  
    843     /* fallback to generic string parser. */ 
    844     if (parse_func == NULL) { 
    845         parse_func = &parse_generic_string_attr; 
    846     } 
    847  
    848     attr = (*parse_func)(pool, scanner); 
    849     attr->type = i; 
    850          
     900    pj_scan_get(scanner, &cs_token, &attr->name); 
     901 
     902    if (*scanner->curptr != '\r' && *scanner->curptr != '\n') { 
     903        /* get value */ 
     904        pj_scan_get_until_ch(scanner, '\r', &attr->value); 
     905    } else { 
     906        attr->value.ptr = NULL; 
     907        attr->value.slen = 0; 
     908    } 
     909 
    851910    /* newline */ 
    852911    pj_scan_get_newline(scanner); 
    853912 
    854913    return attr; 
    855 } 
    856  
    857 static void on_scanner_error(pj_scanner *scanner) 
    858 { 
    859     PJ_UNUSED_ARG(scanner); 
    860  
    861     PJ_THROW(SYNTAX_ERROR); 
    862914} 
    863915 
     
    865917 * Parse SDP message. 
    866918 */ 
    867 PJ_DEF(pjsdp_session_desc*) pjsdp_parse( char *buf, pj_size_t len,  
    868                                          pj_pool_t *pool) 
     919PJ_DEF(pj_status_t) pjmedia_sdp_parse( pj_pool_t *pool, 
     920                                       char *buf, pj_size_t len,  
     921                                       pjmedia_sdp_session **p_sdp) 
    869922{ 
    870923    pj_scanner scanner; 
    871     pjsdp_session_desc *session; 
    872     pjsdp_media_desc *media = NULL; 
     924    pjmedia_sdp_session *session; 
     925    pjmedia_sdp_media *media = NULL; 
    873926    void *attr; 
    874     pjsdp_conn_info *conn; 
     927    pjmedia_sdp_conn *conn; 
    875928    pj_str_t dummy; 
    876929    int cur_name = 254; 
     930    parse_context ctx; 
    877931    PJ_USE_EXCEPTION; 
    878932 
     933    ctx.last_error = PJ_SUCCESS; 
     934 
    879935    init_sdp_parser(); 
    880936 
    881937    pj_scan_init(&scanner, buf, len, 0, &on_scanner_error); 
    882     session = pj_pool_calloc(pool, 1, sizeof(*session)); 
     938    session = pj_pool_calloc(pool, 1, sizeof(pjmedia_sdp_session)); 
     939    PJ_ASSERT_RETURN(session != NULL, PJ_ENOMEM); 
    883940 
    884941    PJ_TRY { 
     
    887944                switch (cur_name) { 
    888945                case 'a': 
    889                     attr = parse_attr(pool, &scanner); 
     946                    attr = parse_attr(pool, &scanner, &ctx); 
    890947                    if (attr) { 
    891948                        if (media) { 
     
    897954                    break; 
    898955                case 'o': 
    899                     parse_origin(&scanner, session); 
     956                    parse_origin(&scanner, session, &ctx); 
    900957                    break; 
    901958                case 's': 
    902                     parse_generic_line(&scanner, &session->name); 
     959                    parse_generic_line(&scanner, &session->name, &ctx); 
    903960                    break; 
    904961                case 'c': 
    905962                    conn = pj_pool_calloc(pool, 1, sizeof(*conn)); 
    906                     parse_connection_info(&scanner, conn); 
     963                    parse_connection_info(&scanner, conn, &ctx); 
    907964                    if (media) { 
    908965                        media->conn = conn; 
     
    912969                    break; 
    913970                case 't': 
    914                     parse_time(&scanner, session); 
     971                    parse_time(&scanner, session, &ctx); 
    915972                    break; 
    916973                case 'm': 
    917974                    media = pj_pool_calloc(pool, 1, sizeof(*media)); 
    918                     parse_media(&scanner, media); 
     975                    parse_media(&scanner, media, &ctx); 
    919976                    session->media[ session->media_count++ ] = media; 
    920977                    break; 
    921978                case 'v': 
    922                     parse_version(&scanner); 
     979                    parse_version(&scanner, &ctx); 
    923980                    break; 
    924981                default: 
    925                     parse_generic_line(&scanner, &dummy); 
     982                    parse_generic_line(&scanner, &dummy, &ctx); 
    926983                    break; 
    927984                } 
    928985        } 
     986 
     987        ctx.last_error = PJ_SUCCESS; 
     988 
    929989    } 
    930990    PJ_CATCH(SYNTAX_ERROR) { 
    931         PJ_LOG(2, (LOG_THIS, "Syntax error in SDP parser '%c' line %d col %d", 
    932                 cur_name, scanner.line, pj_scan_get_col(&scanner))); 
    933         if (!pj_scan_is_eof(&scanner)) { 
    934             if (*scanner.curptr != '\r') { 
    935                 pj_scan_get_until_ch(&scanner, '\r', &dummy); 
    936             } 
    937             pj_scan_get_newline(&scanner); 
    938         } 
     991         
     992        char errmsg[PJMEDIA_ERR_MSG_SIZE]; 
     993        pjmedia_strerror(ctx.last_error, errmsg, sizeof(errmsg)); 
     994 
     995        PJ_LOG(4, (THIS_FILE, "Error parsing SDP in line %d col %d: %s", 
     996                   scanner.line, pj_scan_get_col(&scanner), 
     997                   errmsg)); 
     998 
     999        session = NULL; 
     1000 
    9391001    } 
    9401002    PJ_END; 
    9411003 
    9421004    pj_scan_fini(&scanner); 
    943     return session; 
     1005 
     1006    *p_sdp = session; 
     1007    return ctx.last_error; 
    9441008} 
    9451009 
     
    9471011 * Print SDP description. 
    9481012 */ 
    949 PJ_DEF(int) pjsdp_print( const pjsdp_session_desc *desc, char *buf, pj_size_t size) 
     1013PJ_DEF(int) pjmedia_sdp_print( const pjmedia_sdp_session *desc,  
     1014                               char *buf, pj_size_t size) 
    9501015{ 
    9511016    return print_session(desc, buf, size); 
     
    9531018 
    9541019 
     1020/* 
     1021 * Clone session 
     1022 */ 
     1023PJ_DEF(pjmedia_sdp_session*)  
     1024pjmedia_sdp_session_clone( pj_pool_t *pool, 
     1025                           const pjmedia_sdp_session *rhs) 
     1026{ 
     1027    pjmedia_sdp_session *sess; 
     1028    unsigned i; 
     1029 
     1030    PJ_ASSERT_RETURN(pool && rhs, NULL); 
     1031 
     1032    sess = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_session)); 
     1033    PJ_ASSERT_RETURN(sess != NULL, NULL); 
     1034 
     1035    /* Clone origin line. */ 
     1036    pj_strdup(pool, &sess->origin.user, &rhs->origin.user); 
     1037    sess->origin.id = rhs->origin.id; 
     1038    sess->origin.version = rhs->origin.version; 
     1039    pj_strdup(pool, &sess->origin.net_type, &rhs->origin.net_type); 
     1040    pj_strdup(pool, &sess->origin.addr_type, &rhs->origin.addr_type); 
     1041    pj_strdup(pool, &sess->origin.addr, &rhs->origin.addr); 
     1042 
     1043    /* Clone subject line. */ 
     1044    pj_strdup(pool, &sess->name, &rhs->name); 
     1045 
     1046    /* Clone connection line */ 
     1047    if (rhs->conn) { 
     1048        sess->conn = pjmedia_sdp_conn_clone(pool, rhs->conn); 
     1049        PJ_ASSERT_RETURN(sess->conn != NULL, NULL); 
     1050    } 
     1051 
     1052    /* Clone time line. */ 
     1053    sess->time.start = rhs->time.start; 
     1054    sess->time.stop = rhs->time.stop; 
     1055 
     1056    /* Duplicate session attributes. */ 
     1057    sess->attr_count = rhs->attr_count; 
     1058    for (i=0; i<rhs->attr_count; ++i) { 
     1059        sess->attr[i] = pjmedia_sdp_attr_clone(pool, rhs->attr[i]); 
     1060    } 
     1061 
     1062    /* Duplicate media descriptors. */ 
     1063    sess->media_count = rhs->media_count; 
     1064    for (i=0; i<rhs->media_count; ++i) { 
     1065        sess->media[i] = pjmedia_sdp_media_clone(pool, rhs->media[i]); 
     1066    } 
     1067 
     1068    return sess; 
     1069} 
     1070 
     1071 
     1072#define CHECK(exp,ret)  do {                    \ 
     1073                            pj_assert(exp);     \ 
     1074                            if (!(exp))         \ 
     1075                                return ret;     \ 
     1076                        } while (0) 
     1077 
     1078/* Validate SDP connetion info. */ 
     1079static pj_status_t validate_sdp_conn(const pjmedia_sdp_conn *c) 
     1080{ 
     1081    CHECK( c, PJ_EINVAL); 
     1082    CHECK( pj_strcmp2(&c->net_type, "IN")==0, PJMEDIA_SDP_EINCONN); 
     1083    CHECK( pj_strcmp2(&c->addr_type, "IP4")==0 || 
     1084           pj_strcmp2(&c->addr_type, "IP6")==0,  
     1085           PJMEDIA_SDP_EINCONN); 
     1086    CHECK( c->addr.slen != 0, PJMEDIA_SDP_EINCONN); 
     1087 
     1088    return PJ_SUCCESS; 
     1089} 
     1090 
     1091 
     1092/* Validate SDP session descriptor. */ 
     1093PJ_DEF(pj_status_t) pjmedia_sdp_validate(const pjmedia_sdp_session *sdp) 
     1094{ 
     1095    unsigned i; 
     1096 
     1097    CHECK( sdp != NULL, PJ_EINVAL); 
     1098 
     1099    /* Validate origin line. */ 
     1100    CHECK( sdp->origin.user.slen != 0, PJMEDIA_SDP_EINORIGIN); 
     1101    CHECK( pj_strcmp2(&sdp->origin.net_type, "IN")==0,  
     1102           PJMEDIA_SDP_EINORIGIN); 
     1103    CHECK( pj_strcmp2(&sdp->origin.addr_type, "IP4")==0 || 
     1104           pj_strcmp2(&sdp->origin.addr_type, "IP6")==0,  
     1105           PJMEDIA_SDP_EINORIGIN); 
     1106    CHECK( sdp->origin.addr.slen != 0, PJMEDIA_SDP_EINORIGIN); 
     1107 
     1108    /* Validate subject line. */ 
     1109    CHECK( sdp->name.slen != 0, PJMEDIA_SDP_EINNAME); 
     1110 
     1111    /* Ignore start and stop time. */ 
     1112 
     1113    /* If session level connection info is present, validate it. */ 
     1114    if (sdp->conn) { 
     1115        pj_status_t status = validate_sdp_conn(sdp->conn); 
     1116        if (status != PJ_SUCCESS) 
     1117            return status; 
     1118    } 
     1119 
     1120    /* Validate each media. */ 
     1121    for (i=0; i<sdp->media_count; ++i) { 
     1122        const pjmedia_sdp_media *m = sdp->media[i]; 
     1123        unsigned j; 
     1124 
     1125        /* Validate the m= line. */ 
     1126        CHECK( m->desc.media.slen != 0, PJMEDIA_SDP_EINMEDIA); 
     1127        CHECK( m->desc.transport.slen != 0, PJMEDIA_SDP_EINMEDIA); 
     1128        CHECK( m->desc.fmt_count != 0, PJMEDIA_SDP_ENOFMT); 
     1129 
     1130        /* If media level connection info is present, validate it. */ 
     1131        if (m->conn) { 
     1132            pj_status_t status = validate_sdp_conn(m->conn); 
     1133            if (status != PJ_SUCCESS) 
     1134                return status; 
     1135        } 
     1136 
     1137        /* If media doesn't have connection info, then connection info 
     1138         * must be present in the session. 
     1139         */ 
     1140        if (m->conn == NULL) { 
     1141            if (sdp->conn == NULL) 
     1142                return PJMEDIA_SDP_EMISSINGCONN; 
     1143        } 
     1144 
     1145        /* Verify payload type. */ 
     1146        for (j=0; j<m->desc.fmt_count; ++j) { 
     1147            unsigned pt = pj_strtoul(&m->desc.fmt[j]); 
     1148 
     1149            /* Payload type is between 0 and 127. */ 
     1150            CHECK( pt <= 127, PJMEDIA_SDP_EINPT); 
     1151 
     1152            /* If port is not zero, then for each dynamic payload type, an 
     1153             * rtpmap attribute must be specified. 
     1154             */ 
     1155            if (m->desc.port != 0 && pt >= 96) { 
     1156                const pjmedia_sdp_attr *a; 
     1157 
     1158                a = pjmedia_sdp_media_find_attr2(m, "rtpmap", &m->desc.fmt[j]); 
     1159                CHECK( a != NULL, PJMEDIA_SDP_EMISSINGRTPMAP); 
     1160            } 
     1161        } 
     1162    } 
     1163 
     1164    /* Looks good. */ 
     1165    return PJ_SUCCESS; 
     1166} 
     1167 
     1168 
Note: See TracChangeset for help on using the changeset viewer.