📄 sdp_parse.c
字号:
*(CRLF repeat-fields) CRLF) [zone-adjustments CRLF] start-time = time | "0" stop-time = time | "0" time = POS-DIGIT 9*(DIGIT) ;sufficient for 2 more centuries */ PARSE_ALLOC(p, sdp_time_t, t); *result = t; if (parse_ul(p, &r, &t->t_start, 0) || parse_ul(p, &r, &t->t_stop, 0)) parsing_error(p, "invalid time"); else if (STRICT(p)) { PARSE_CHECK_REST(p, r, "t"); }}/** * Parse an "r=" field * * The function parse_repeat() parses an SDP repeat field. * * @param p pointer to SDP parser object * @param r pointer to record data * @param result pointer to which parsed record is assigned * */static void parse_repeat(sdp_parser_t *p, char *d, sdp_repeat_t **result){ /* repeat-fields = "r=" repeat-interval space typed-time 1*(space typed-time) repeat-interval = typed-time typed-time = 1*(DIGIT) [fixed-len-time-unit] fixed-len-time-unit = "d" | "h" | "m" | "s" */ unsigned long tt, *interval; size_t i; int n, N; char *s; sdp_repeat_t *r; /** Count number of intervals */ for (N = 0, s = d; *s; ) { if (!(is_posdigit(*s) || (!STRICT(p) && (*s) == '0'))) break; do { s++; } while (is_digit(*s)); if (*s && strchr("dhms", *s)) s++; N++; if (!(i = STRICT(p) ? is_space(*s) : strspn(s, SPACE TAB))) break; s += i; } PARSE_CHECK_REST(p, s, "r"); if (N < 2) { parsing_error(p, "invalid repeat"); return; } if (!(r = su_salloc(p->pr_home, offsetof(sdp_repeat_t, r_offsets[N - 1])))) { parse_alloc_error(p, "sdp_repeat_t"); return; } r->r_number_of_offsets = N - 2; r->r_offsets[N - 2] = 0; for (n = 0, interval = &r->r_interval; n < N; n++) { tt = strtoul(d, &d, 10); switch (*d) { case 'd': tt *= 24; case 'h': tt *= 60; case 'm': tt *= 60; case 's': d++; break; } interval[n] = tt; while (is_space(*d)) d++; } *result = r;}/* ------------------------------------------------------------------------- * Function parse_zone() - parse an "z=" field * * Description: * This function parses an SDP time zone field. * * Parameters: * p - pointer to SDP parser object * r - pointer to record data * result - pointer to which parsed record is assigned * */static void parse_zone(sdp_parser_t *p, char *r, sdp_zone_t **result){ char *s; size_t i; int n, N; sdp_zone_t *z; /* zone-adjustments = time space ["-"] typed-time *(space time space ["-"] typed-time) */ /** Count number of timezones, check syntax */ for (N = 0, s = r; *s;) { if (!(is_posdigit(*s) || (!STRICT(p) && (*s) == '0'))) break; do { s++; } while (is_digit(*s)); if (!(i = STRICT(p) ? is_space(*s) : strspn(s, SPACE TAB))) break; s += i; if (!(*s == '-' || is_posdigit(*s) || (!STRICT(p) && (*s) == '0'))) break; do { s++; } while (is_digit(*s)); if (*s && strchr("dhms", *s)) s++; N++; if (!(i = STRICT(p) ? is_space(*s) : strspn(s, SPACE TAB))) break; s += i; } PARSE_CHECK_REST(p, s, "z"); if (N < 1) { parsing_error(p, "invalid timezone"); return; } if (!(z = su_salloc(p->pr_home, offsetof(sdp_zone_t, z_adjustments[N])))) { parse_alloc_error(p, "sdp_zone_t"); return; } z->z_number_of_adjustments = N; for (n = 0; n < N; n++) { unsigned long at = strtoul(r, &r, 10); long offset = strtol(r, &r, 10); switch (*r) { case 'd': offset *= 24; case 'h': offset *= 60; case 'm': offset *= 60; case 's': r++; break; } z->z_adjustments[n].z_at = at; z->z_adjustments[n].z_offset = offset; } *result = z;}/* ------------------------------------------------------------------------- * Function parse_key() - parse an "k=" field * * Description: * This function parses an SDP key field. * * Parameters: * p - pointer to SDP parser object * r - pointer to record data * result - pointer to which parsed record is assigned * */static void parse_key(sdp_parser_t *p, char *r, sdp_key_t **result){ char *s; /* key-field = ["k=" key-type CRLF] key-type = "prompt" | "clear:" key-data | "base64:" key-data | "uri:" uri key-data = email-safe | "~" | " */ s = token(&r, ":", ALPHA DIGIT "-", SPACE TAB); if (!s) { parsing_error(p, "invalid key method"); return; } { PARSE_ALLOC(p, sdp_key_t, k); *result = k; if (strcasecmp(s, "clear") == 0) k->k_method = sdp_key_clear, k->k_method_name = "clear"; else if (strcasecmp(s, "base64") == 0) k->k_method = sdp_key_base64, k->k_method_name = "base64"; else if (strcasecmp(s, "uri") == 0) k->k_method = sdp_key_uri, k->k_method_name = "uri"; else if (strcasecmp(s, "prompt") == 0) k->k_method = sdp_key_prompt, k->k_method_name = "prompt"; else k->k_method = sdp_key_x, k->k_method_name = s; k->k_material = r; }}/* ------------------------------------------------------------------------- * Function parse_session_attr() - parse a session "a=" field * * Description: * This function parses an SDP attribute field regarding whole session. * * Parameters: * p - pointer to SDP parser object * r - pointer to record data * result - pointer to which parsed record is assigned */static void parse_session_attr(sdp_parser_t *p, char *r, sdp_attribute_t **result){ /* attribute-fields = *("a=" attribute CRLF) attribute = (att-field ":" att-value) | att-field att-field = 1*(alpha-numeric) att-value = byte-string */ char *name = NULL, *value = NULL; if (!(name = token(&r, ":", ALPHA DIGIT "-", SPACE TAB))) { parsing_error(p,"invalid attribute name"); return; } if (*r) value = r; else PARSE_CHECK_REST(p, r, "a"); if (strcasecmp(name, "charset") == 0) { p->pr_session->sdp_charset = value; return; } if (p->pr_mode_manual) ; else if (strcasecmp(name, "inactive") == 0) p->pr_session_mode = sdp_inactive; else if (strcasecmp(name, "sendonly") == 0) p->pr_session_mode = sdp_sendonly; else if (strcasecmp(name, "recvonly") == 0) p->pr_session_mode = sdp_recvonly; else if (strcasecmp(name, "sendrecv") == 0) p->pr_session_mode = sdp_sendrecv; { PARSE_ALLOC(p, sdp_attribute_t, a); *result = a; a->a_name = name; a->a_value = value; }}/* ------------------------------------------------------------------------- * Function parse_media() - parse an "m=" field * * Description: * This function parses an SDP media field. * * Parameters: * p - pointer to SDP parser object * r - pointer to record data * result - pointer to which parsed record is assigned */static void parse_media(sdp_parser_t *p, char *r, sdp_media_t **result){ /* media-descriptions = *( media-field information-field *(connection-field) bandwidth-fields key-field attribute-fields ) media-field = "m=" media space port ["/" integer] space proto 1*(space fmt) CRLF media = 1*(alpha-numeric) ;typically "audio", "video", "application" ;or "data" fmt = 1*(alpha-numeric) ;typically an RTP payload type for audio ;and video media proto = 1*(alpha-numeric) ;typically "RTP/AVP" or "udp" for IP4 port = 1*(DIGIT) ;should in the range "1024" to "65535" inclusive */ char *s; unsigned long value; PARSE_ALLOC(p, sdp_media_t, m); *result = m; m->m_mode = sdp_sendrecv; s = token(&r, SPACE, ALPHA DIGIT, NULL); if (s == NULL && p->pr_config) s = token(&r, SPACE, "*", NULL); if (!s) { parsing_error(p, "m= invalid media field"); return; } sdp_media_type(m, s); /* Accept m=* in configuration file */ if (p->pr_config && m->m_type == sdp_media_any) { r += strspn(r, SPACE TAB); if (r[0] == '\0') { m->m_proto = sdp_proto_any, m->m_proto_name = "*"; return; } } if (parse_ul(p, &r, &value, 0)) { parsing_error(p, "m= invalid port number"); return; } m->m_port = value; if (*r == '/') { r++; if (parse_ul(p, &r, &value, 0)) { parsing_error(p, "m= invalid port specification"); return; } m->m_number_of_ports = value; } /* alpha-numeric and "/" */ s = token(&r, SPACE, ALPHA DIGIT "/", SPACE); if (s == NULL && p->pr_config) s = token(&r, SPACE, "*", SPACE); if (s == NULL) { parsing_error(p, "m= missing protocol"); return; } if (!STRICT(p) && strcasecmp(s, "RTP") == 0) m->m_proto = sdp_proto_rtp, m->m_proto_name = "RTP/AVP"; else sdp_media_transport(m, s); /* RTP format list */ if (*r && sdp_media_has_rtp(m)) { parse_payload(p, r, &m->m_rtpmaps); return; } /* "normal" format list */ if (*r) { sdp_list_t **fmt = &m->m_format; while (r && *r) { PARSE_ALLOC(p, sdp_list_t, l); *fmt = l; l->l_text = next(&r, SPACE TAB, SPACE TAB); fmt = &l->l_next; } }}/** Set media type */void sdp_media_type(sdp_media_t *m, char const *s){ if (strcmp(s, "*") == 0) m->m_type = sdp_media_any, m->m_type_name = "*"; else if (strcasecmp(s, "audio") == 0) m->m_type = sdp_media_audio, m->m_type_name = "audio"; else if (strcasecmp(s, "video") == 0) m->m_type = sdp_media_video, m->m_type_name = "video"; else if (strcasecmp(s, "application") == 0) m->m_type = sdp_media_application, m->m_type_name = "application"; else if (strcasecmp(s, "data") == 0) m->m_type = sdp_media_data, m->m_type_name = "data"; else if (strcasecmp(s, "control") == 0) m->m_type = sdp_media_control, m->m_type_name = "control"; else if (strcasecmp(s, "message") == 0) m->m_type = sdp_media_message, m->m_type_name = "message"; else if (strcasecmp(s, "image") == 0) m->m_type = sdp_media_image, m->m_type_name = "image"; else if (strcasecmp(s, "red") == 0) m->m_type = sdp_media_red, m->m_type_name = "red"; else m->m_type = sdp_media_x, m->m_type_name = s;}void sdp_media_transport(sdp_media_t *m, char const *s){ if (strcasecmp(s, "*") == 0) m->m_proto = sdp_proto_any, m->m_proto_name = "*"; else if (strcasecmp(s, "RTP/AVP") == 0) m->m_proto = sdp_proto_rtp, m->m_proto_name = "RTP/AVP"; else if (strcasecmp(s, "RTP/SAVP") == 0) m->m_proto = sdp_proto_srtp, m->m_proto_name = "RTP/SAVP"; else if (strcasecmp(s, "UDPTL") == 0) m->m_proto = sdp_proto_udptl, m->m_proto_name = "UDPTL"; else if (strcasecmp(s, "UDP") == 0) m->m_proto = sdp_proto_udp, m->m_proto_name = "UDP"; else if (strcasecmp(s, "TCP") == 0) m->m_proto = sdp_proto_tcp, m->m_proto_name = "TCP"; else if (strcasecmp(s, "TLS") == 0) m->m_proto = sdp_proto_tls, m->m_proto_name = "TLS"; else m->m_proto = sdp_proto_x, m->m_proto_name = s;}/** Check if media uses RTP as its transport protocol. */int sdp_media_has_rtp(sdp_media_t const *m){ return m && (m->m_proto == sdp_proto_rtp || m->m_proto == sdp_proto_srtp);}#define RTPMAP(pt, encoding, rate, params) \ { sizeof(sdp_rtpmap_t), NULL, encoding, rate, (char *)params, NULL, 1, pt, 0 }/* rtpmaps for well-known codecs */static sdp_rtpmap_t const sdp_rtpmap_pcmu = RTPMAP(0, "PCMU", 8000, 0), sdp_rtpmap_1016 = RTPMAP(1, "1016", 8000, 0), sdp_rtpmap_g721 = RTPMAP(2, "G721", 8000, 0), sdp_rtpmap_gsm = RTPMAP(3, "GSM", 8000, 0), sdp_rtpmap_g723 = RTPMAP(4, "G723", 8000, 0), sdp_rtpmap_dvi4_8000 = RTPMAP(5, "DVI4", 8000, 0), sdp_rtpmap_dvi4_16000 = RTPMAP(6, "DVI4", 16000, 0), sdp_rtpmap_lpc = RTPMAP(7, "LPC", 8000, 0), sdp_rtpmap_pcma = RTPMAP(8, "PCMA", 8000, 0), sdp_rtpmap_g722 = RTPMAP(9, "G722", 8000, 0), sdp_rtpmap_l16_2 = RTPMAP(10, "L16", 44100, "2"), sdp_rtpmap_l16 = RTPMAP(11, "L16", 44100, 0), sdp_rtpmap_qcelp = RTPMAP(12, "QCELP", 8000, 0), sdp_rtpmap_cn = RTPMAP(13, "CN", 8000, 0), sdp_rtpmap_mpa = RTPMAP(14, "MPA", 90000, 0), sdp_rtpmap_g728 = RTPMAP(15, "G728", 8000, 0), sdp_rtpmap_dvi4_11025 = RTPMAP(16, "DVI4", 11025, 0), sdp_rtpmap_dvi4_22050 = RTPMAP(17, "DVI4", 22050, 0), sdp_rtpmap_g729 = RTPMAP(18, "G729", 8000, 0), sdp_rtpmap_reserved_cn = RTPMAP(19, "CN", 8000, 0), /* video codecs */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -