📄 sdp.c
字号:
return 0;}/** Compare two media (m=) fields */int sdp_media_cmp(sdp_media_t const *a, sdp_media_t const *b){ int rv; sdp_connection_t const *ac, *bc; sdp_bandwidth_t const *ab, *bb; sdp_rtpmap_t const *arm, *brm; sdp_attribute_t const *aa, *ba; if (a == b) return 0; if ((rv = (a != NULL) - (b != NULL))) return rv; if (a->m_type != b->m_type) return a->m_type < b->m_type ? -1 : 1; if (a->m_type == sdp_media_x) if ((rv = str0cmp(a->m_type_name, b->m_type_name))) return rv; if (a->m_port != b->m_port) return a->m_port < b->m_port ? -1 : 1; if (a->m_port == 0 /* && b->m_port == 0 */) /* Ignore transport protocol and media list if media has been rejected */ return 0; if (a->m_number_of_ports != b->m_number_of_ports) return a->m_number_of_ports < b->m_number_of_ports ? -1 : 1; if (a->m_proto != b->m_proto) return a->m_proto < b->m_proto ? -1 : 1; if (a->m_proto == sdp_media_x) if ((rv = str0cmp(a->m_proto_name, b->m_proto_name))) return rv; if (a->m_mode != b->m_mode) return a->m_mode < b->m_mode ? -1 : 1; for (arm = a->m_rtpmaps, brm = b->m_rtpmaps; arm || brm; arm = arm->rm_next, brm = brm->rm_next) if ((rv = sdp_rtpmap_cmp(arm, brm))) return rv; if ((rv = sdp_list_cmp(a->m_format, b->m_format))) return rv; if ((rv = str0cmp(a->m_information, b->m_information))) return rv; for (ac = a->m_connections, bc = b->m_connections; ac || bc; ac = ac->c_next, bc = bc->c_next) if ((rv = sdp_connection_cmp(ac, bc))) return rv; for (ab = a->m_bandwidths, bb = b->m_bandwidths; ab || bb; ab = ab->b_next, bb = bb->b_next) if ((rv = sdp_bandwidth_cmp(a->m_bandwidths, b->m_bandwidths))) return rv; if ((rv = sdp_key_cmp(a->m_key, b->m_key))) return rv; for (aa = a->m_attributes, ba = b->m_attributes; aa || bb; aa = aa->a_next, ba = ba->a_next) if ((rv = sdp_attribute_cmp(aa, ba))) return rv; return 0;}/* ---------------------------------------------------------------------- */sdp_connection_t *sdp_media_connections(sdp_media_t const *m){ if (m) { if (m->m_connections) return m->m_connections; if (m->m_session) return m->m_session->sdp_connection; } return NULL;}/* ---------------------------------------------------------------------- *//** Find named attribute from given list. */sdp_attribute_t *sdp_attribute_find(sdp_attribute_t const *a, char const *name){ for (; a; a = a->a_next) { if (strcasecmp(a->a_name, name) == 0) break; } return (sdp_attribute_t *)a;}/** Find named attribute from given lists (a or a2). */sdp_attribute_t *sdp_attribute_find2(sdp_attribute_t const *a, sdp_attribute_t const *a2, char const *name){ for (; a; a = a->a_next) { if (strcasecmp(a->a_name, name) == 0) break; } if (a == 0) for (a = a2; a; a = a->a_next) { if (strcasecmp(a->a_name, name) == 0) break; } return (sdp_attribute_t *)a;}/** Get session mode from attribute list. */sdp_mode_t sdp_attribute_mode(sdp_attribute_t const *a, sdp_mode_t defmode){ for (; a; a = a->a_next) { if (strcasecmp(a->a_name, "sendrecv") == 0) return sdp_sendrecv; if (strcasecmp(a->a_name, "inactive") == 0) return sdp_inactive; if (strcasecmp(a->a_name, "recvonly") == 0) return sdp_recvonly; if (strcasecmp(a->a_name, "sendonly") == 0) return sdp_sendonly; } return defmode;}/** Convert session mode as #sdp_attribute_t structure. */sdp_attribute_t *sdp_attribute_by_mode(su_home_t *home, sdp_mode_t mode){ sdp_attribute_t *a; char const *name; if (mode == sdp_inactive) name = "inactive"; else if (mode == sdp_sendonly) name = "sendonly"; else if (mode == sdp_recvonly) name = "recvonly"; else if (mode == sdp_sendrecv) name = "sendrecv"; else return NULL; a = su_salloc(home, sizeof(*a)); if (a) a->a_name = name; return a;}/** Find a mapped attribute. * * A mapped attribute has form 'a=<name>:<pt> <value>' where pt is a RTP * payload type, integer in range 0..127. For example, "a=atmmap" [@RFC3108] * is a mapped attribute. Note that common mapped attributes, "a=rtpmap" and * "a=fmtp" are already parsed as list of #sdp_rtpmap_t in #sdp_media_t. * * @param a pointer to first attribute in the list * @param name name of the attribute * @param pt payload type number (must be 0..127) * @param return_result return value parameter for mapped attribute value * * @return Pointer to a matching attribute structure, or NULL. * * If a matching attribute is found, @a return_result will point to part of * the attribute after the payload type and whitespace. */sdp_attribute_t *sdp_attribute_mapped_find(sdp_attribute_t const *a, char const *name, int pt, char **return_result){ char pt_value[4]; size_t pt_len; if (return_result) *return_result = NULL; if (0 > pt || pt > 127) return NULL; snprintf(pt_value, sizeof(pt_value), "%u", (unsigned)pt); pt_len = strlen(pt_value); for (; (a = sdp_attribute_find(a, name)); a = a->a_next) { char const *value = a->a_value; size_t wlen; if (strncmp(value, pt_value, pt_len)) continue; wlen = strspn(value + pt_len, " \t"); if (wlen == 0 || value[pt_len + wlen] == '\0') continue; if (return_result) *return_result = (char *)value + pt_len + wlen; return (sdp_attribute_t *)a; } return NULL;}/** Append a (list of) attribute(s) to a list of attributes. */void sdp_attribute_append(sdp_attribute_t **list, sdp_attribute_t const *a){ assert(list); if (list == NULL || a == NULL) return; for (;*list; list = &(*list)->a_next) ; *list = (sdp_attribute_t *)a;}/**Replace or append a attribute within a list of attributes. * * @retval 1 if replaced existing attribute * @retval 0 if attribute was appended * @retval -1 upon an error */int sdp_attribute_replace(sdp_attribute_t **list, sdp_attribute_t *a, sdp_attribute_t **return_replaced){ sdp_attribute_t *replaced; assert(list); if (return_replaced) *return_replaced = NULL; if (list == NULL || a == NULL) return -1; assert(a->a_name != NULL); assert(a->a_next == NULL); for (; *list; list = &(*list)->a_next) { if (strcasecmp((*list)->a_name, a->a_name) == 0) break; } replaced = *list, *list = a; if (replaced) { a->a_next = replaced->a_next; replaced->a_next = NULL; if (return_replaced) *return_replaced = replaced; return 1; } return 0;}/** Remove a named attribute from a list of attributes. */sdp_attribute_t *sdp_attribute_remove(sdp_attribute_t **list, char const *name){ sdp_attribute_t *a; assert(list); if (list == NULL) return NULL; if (name == NULL) return NULL; for (a = *list; a; list = &a->a_next, a = *list) { if (strcasecmp(name, a->a_name) == 0) break; } if (a) { *list = a->a_next; a->a_next = NULL; } return a;}/* Return 1 if m= line struct matches with given type and name */unsigned sdp_media_match(sdp_media_t const *m, sdp_media_e type, sdp_text_t *type_name, sdp_proto_e proto, sdp_text_t *proto_name){ if (m == NULL) return 0; if (type == sdp_media_any || m->m_type == sdp_media_any) return 1; if (type_name == NULL) type_name = ""; if (type != m->m_type || (type == sdp_media_x && strcasecmp(m->m_type_name, type_name))) return 0; if (proto == sdp_proto_any || m->m_proto == sdp_proto_any) return 1; if (proto_name == NULL) proto_name = ""; if (proto != m->m_proto || (proto == sdp_proto_x && strcasecmp(m->m_proto_name, proto_name))) return 0; return 1;}/* Return 1 if media type and protocol of m= line structs matches */unsigned sdp_media_match_with(sdp_media_t const *a, sdp_media_t const *b){ if (a == NULL || b == NULL) return a == b; if (a->m_type == sdp_media_any || b->m_type == sdp_media_any) return 1; if (a->m_type != b->m_type || (a->m_type == sdp_media_x && strcasecmp(b->m_type_name, a->m_type_name))) return 0; if (a->m_proto == sdp_proto_any || b->m_proto == sdp_proto_any) return 1; if (a->m_proto != b->m_proto || (a->m_proto == sdp_proto_x && strcasecmp(b->m_proto_name, a->m_proto_name))) return 0; return 1;}/** Count matching media lines in SDP. */unsigned sdp_media_count(sdp_session_t const *sdp, sdp_media_e type, sdp_text_t *type_name, sdp_proto_e proto, sdp_text_t *proto_name){ unsigned count = 0; sdp_media_t const *m; if (sdp != NULL) for (m = sdp->sdp_media; m; m = m->m_next) count += sdp_media_match(m, type, type_name, proto, proto_name); return count;}/** Count matching media lines in SDP. */unsigned sdp_media_count_with(sdp_session_t const *sdp, sdp_media_t const *m0){ unsigned count = 0; sdp_media_t const *m; if (sdp != NULL) for (m = sdp->sdp_media; m; m = m->m_next) count += sdp_media_match_with(m, m0); return count;}/** Return true if media uses RTP */int sdp_media_uses_rtp(sdp_media_t const *m){ return m && (m->m_proto == sdp_proto_rtp || m->m_proto == sdp_proto_srtp || (m->m_proto == sdp_proto_x && m->m_proto_name && strncasecmp(m->m_proto_name, "RTP/", 4) == 0));}/** Check if payload type, rtp rate and parameters match in rtpmaps*/int sdp_rtpmap_match(sdp_rtpmap_t const *a, sdp_rtpmap_t const *b){ char const *aparam, *bparam; if (a == b) return 1; if (a == 0 || b == 0) return 0; if (a->rm_rate != b->rm_rate) return 0; if (strcasecmp(a->rm_encoding, b->rm_encoding)) return 0; aparam = a->rm_params; bparam = b->rm_params; if (aparam == bparam) return 1; if (!aparam) aparam = "1"; if (!bparam) bparam = "1"; if (strcasecmp(aparam, bparam)) return 0; return 1;}/** Search for matching rtpmap from list. * * @note * The a=fmtp: for the codecs are not compared. */sdp_rtpmap_t *sdp_rtpmap_find_matching(sdp_rtpmap_t const *list, sdp_rtpmap_t const *rm){ char const *lparam, *rparam; if (rm == NULL) return NULL; for (; list; list = list->rm_next) { if (rm->rm_rate != list->rm_rate) continue; if (strcasecmp(rm->rm_encoding, list->rm_encoding) != 0) continue; lparam = rm->rm_params; rparam = list->rm_params; if (lparam == rparam) break; if (!lparam) lparam = "1"; if (!rparam) rparam = "1"; if (strcasecmp(lparam, rparam)) continue; break; } return (sdp_rtpmap_t *)list;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -