diff options
-rw-r--r-- | channels/chan_sip.c | 65 | ||||
-rw-r--r-- | include/asterisk/format.h | 40 | ||||
-rw-r--r-- | main/format.c | 45 | ||||
-rw-r--r-- | main/translate.c | 14 | ||||
-rw-r--r-- | res/res_format_attr_celt.c | 25 | ||||
-rw-r--r-- | res/res_format_attr_silk.c | 32 |
6 files changed, 180 insertions, 41 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index b28c0eed9..e006f06f9 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -10175,7 +10175,7 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_ int found = FALSE; int codec; char mimeSubtype[128]; - char fmtp_string[64]; + char fmtp_string[256]; unsigned int sample_rate; int debug = sip_debug_test_pvt(p); @@ -10222,12 +10222,17 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_ if (debug) ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec); } - } else if (sscanf(a, "fmtp: %30u %63s", &codec, fmtp_string) == 2) { + } else if (sscanf(a, "fmtp: %30u %255s", &codec, fmtp_string) == 2) { struct ast_format *format; if ((format = ast_rtp_codecs_get_payload_format(newaudiortp, codec))) { unsigned int bit_rate; - int val = 0; + + if (!ast_format_sdp_parse(format, fmtp_string)) { + found = TRUE; + } else { + ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec); + } switch ((int) format->id) { case AST_FORMAT_SIREN7: @@ -10260,21 +10265,6 @@ static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_ } } break; - case AST_FORMAT_CELT: - if (sscanf(fmtp_string, "framesize=%30u", &val) == 1) { - ast_format_append(format, CELT_ATTR_KEY_FRAME_SIZE, val, AST_FORMAT_ATTR_END); - } - case AST_FORMAT_SILK: - if (sscanf(fmtp_string, "maxaveragebitrate=%30u", &val) == 1) { - ast_format_append(format, SILK_ATTR_KEY_MAX_BITRATE, val, AST_FORMAT_ATTR_END); - } - if (sscanf(fmtp_string, "usedtx=%30u", &val) == 1) { - ast_format_append(format, SILK_ATTR_KEY_DTX, val ? 1 : 0, AST_FORMAT_ATTR_END); - } - if (sscanf(fmtp_string, "useinbandfec=%30u", &val) == 1) { - ast_format_append(format, SILK_ATTR_KEY_FEC, val ? 1 : 0, AST_FORMAT_ATTR_END); - } - break; } } } @@ -10289,6 +10279,7 @@ static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_ char mimeSubtype[128]; unsigned int sample_rate; int debug = sip_debug_test_pvt(p); + char fmtp_string[256]; if (sscanf(a, "rtpmap: %30u %127[^/]/%30u", &codec, mimeSubtype, &sample_rate) == 3) { /* We have a rtpmap to handle */ @@ -10311,6 +10302,16 @@ static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_ if (debug) ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec); } + } else if (sscanf(a, "fmtp: %30u %255s", &codec, fmtp_string) == 2) { + struct ast_format *format; + + if ((format = ast_rtp_codecs_get_payload_format(newvideortp, codec))) { + if (!ast_format_sdp_parse(format, fmtp_string)) { + found = TRUE; + } else { + ast_rtp_codecs_payloads_unset(newvideortp, NULL, codec); + } + } } return found; @@ -11747,7 +11748,6 @@ static void add_codec_to_sdp(const struct sip_pvt *p, { int rtp_code; struct ast_format_list fmt; - int val = 0; if (debug) ast_verbose("Adding codec %d (%s) to SDP\n", format->id, ast_getformatname(format)); @@ -11765,6 +11765,8 @@ static void add_codec_to_sdp(const struct sip_pvt *p, ast_rtp_lookup_mime_subtype2(1, format, 0, ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0), ast_rtp_lookup_sample_rate2(1, format, 0)); + ast_format_sdp_generate(format, rtp_code, a_buf); + switch ((int) format->id) { case AST_FORMAT_G729A: /* Indicate that we don't support VAD (G.729 annex B) */ @@ -11790,22 +11792,6 @@ static void add_codec_to_sdp(const struct sip_pvt *p, /* Indicate that we only expect 64Kbps */ ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=64000\r\n", rtp_code); break; - case AST_FORMAT_CELT: - if (!ast_format_get_value(format, CELT_ATTR_KEY_FRAME_SIZE, &val) && val > 0) { - ast_str_append(a_buf, 0, "a=fmtp:%d framesize=%u\r\n", rtp_code, val); - } - break; - case AST_FORMAT_SILK: - if (!ast_format_get_value(format, SILK_ATTR_KEY_MAX_BITRATE, &val) && val > 5000 && val < 40000) { - ast_str_append(a_buf, 0, "a=fmtp:%d maxaveragebitrate=%u\r\n", rtp_code, val); - } - if (!ast_format_get_value(format, SILK_ATTR_KEY_DTX, &val)) { - ast_str_append(a_buf, 0, "a=fmtp:%d usedtx=%u\r\n", rtp_code, val ? 1 : 0); - } - if (!ast_format_get_value(format, SILK_ATTR_KEY_FEC, &val)) { - ast_str_append(a_buf, 0, "a=fmtp:%d useinbandfec=%u\r\n", rtp_code, val ? 1 : 0); - } - break; } if (fmt.cur_ms && (fmt.cur_ms < *min_packet_size)) @@ -11837,7 +11823,8 @@ static void add_vcodec_to_sdp(const struct sip_pvt *p, struct ast_format *format ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code, ast_rtp_lookup_mime_subtype2(1, format, 0, 0), ast_rtp_lookup_sample_rate2(1, format, 0)); - /* Add fmtp code here */ + + ast_format_sdp_generate(format, rtp_code, a_buf); } /*! \brief Add text codec offer to SDP offer/answer body in INVITE or 200 OK */ @@ -12262,10 +12249,12 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int /* Start by sending our preferred audio/video codecs */ for (x = 0; x < AST_CODEC_PREF_SIZE; x++) { - if (!(ast_codec_pref_index(&p->prefs, x, &tmp_fmt))) + struct ast_format pref; + + if (!(ast_codec_pref_index(&p->prefs, x, &pref))) break; - if (!(ast_format_cap_iscompatible(tmpcap, &tmp_fmt))) + if (!ast_format_cap_get_compatible_format(tmpcap, &pref, &tmp_fmt)) continue; if (ast_format_cap_iscompatible(alreadysent, &tmp_fmt)) diff --git a/include/asterisk/format.h b/include/asterisk/format.h index d0f1021d5..9dd6eb8b2 100644 --- a/include/asterisk/format.h +++ b/include/asterisk/format.h @@ -131,7 +131,7 @@ enum ast_format_id { /*! \brief This structure contains the buffer used for format attributes */ struct ast_format_attr { /*! The buffer formats can use to represent attributes */ - uint8_t format_attr[AST_FORMAT_ATTR_SIZE]; + uint32_t format_attr[AST_FORMAT_ATTR_SIZE]; /*! If a format's payload needs to pass through that a new marker is required * for RTP, this variable will be set. */ uint8_t rtp_marker_bit; @@ -219,9 +219,47 @@ struct ast_format_attr_interface { * \retval -1 failure, Value was either not found, or not allowed to be accessed. */ int (* const format_attr_get_val)(const struct ast_format_attr *format_attr, int key, void *val); + + /* + * \brief Parse SDP attribute information, interpret it, and store it in ast_format_attr structure. + * + * \retval 0 Success, values were valid + * \retval -1 Failure, some values were not acceptable + */ + int (* const format_attr_sdp_parse)(struct ast_format_attr *format_attr, const char *attributes); + + /*! + * \brief Generate SDP attribute information from an ast_format_attr structure. + * + * \note This callback should generate a full fmtp line using the provided payload number. + */ + void (* const format_attr_sdp_generate)(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str); }; /*! + * \brief This function is used to have a media format aware module parse and interpret + * SDP attribute information. Once interpreted this information is stored on the format + * itself using Asterisk format attributes. + * + * \param format to set + * \param attributes string containing the fmtp line from the SDP + * + * \retval 0 success, attribute values were valid + * \retval -1 failure, values were not acceptable + */ +int ast_format_sdp_parse(struct ast_format *format, const char *attributes); + +/*! + * \brief This function is used to produce an fmtp SDP line for an Asterisk format. The + * attributes present on the Asterisk format are translated into the SDP equivalent. + * + * \param format to generate an fmtp line for + * \param payload numerical payload for the fmtp line + * \param str structure that the fmtp line will be appended to + */ +void ast_format_sdp_generate(const struct ast_format *format, unsigned int payload, struct ast_str **str); + +/*! * \brief This function is used to set an ast_format object to represent a media format * with optional format attributes represented by format specific key value pairs. * diff --git a/main/format.c b/main/format.c index 96afd3e18..2d37eb458 100644 --- a/main/format.c +++ b/main/format.c @@ -119,6 +119,51 @@ static int has_interface(const struct ast_format *format) return 1; } +int ast_format_sdp_parse(struct ast_format *format, const char *attributes) +{ + struct interface_ao2_wrapper *wrapper; + int res; + + if (!(wrapper = find_interface(format))) { + return 0; + } + + ao2_rdlock(wrapper); + if (!(wrapper->interface || !wrapper->interface->format_attr_sdp_parse)) { + ao2_unlock(wrapper); + ao2_ref(wrapper, -1); + return 0; + } + + res = wrapper->interface->format_attr_sdp_parse(&format->fattr, attributes); + + ao2_unlock(wrapper); + ao2_ref(wrapper, -1); + + return res; +} + +void ast_format_sdp_generate(const struct ast_format *format, unsigned int payload, struct ast_str **str) +{ + struct interface_ao2_wrapper *wrapper; + + if (!(wrapper = find_interface(format))) { + return; + } + + ao2_rdlock(wrapper); + if (!(wrapper->interface || !wrapper->interface->format_attr_sdp_generate)) { + ao2_unlock(wrapper); + ao2_ref(wrapper, -1); + return; + } + + wrapper->interface->format_attr_sdp_generate(&format->fattr, payload, str); + + ao2_unlock(wrapper); + ao2_ref(wrapper, -1); +} + /*! \internal * \brief set format attributes using an interface */ diff --git a/main/translate.c b/main/translate.c index 607fee77b..ce430ce97 100644 --- a/main/translate.c +++ b/main/translate.c @@ -1286,12 +1286,22 @@ unsigned int ast_translate_path_steps(struct ast_format *dst_format, struct ast_ void ast_translate_available_formats(struct ast_format_cap *dest, struct ast_format_cap *src, struct ast_format_cap *result) { struct ast_format tmp_fmt; - struct ast_format cur_src; + struct ast_format cur_dest, cur_src; int src_audio = 0; int src_video = 0; int index; - ast_format_cap_copy(result, dest); + ast_format_cap_iter_start(dest); + while (!ast_format_cap_iter_next(dest, &cur_dest)) { + /* We give preference to a joint format structure if possible */ + if (ast_format_cap_get_compatible_format(src, &cur_dest, &tmp_fmt)) { + ast_format_cap_add(result, &tmp_fmt); + } else { + /* Otherwise we just use the destination format */ + ast_format_cap_add(result, &cur_dest); + } + } + ast_format_cap_iter_end(dest); /* if we don't have a source format, we just have to try all possible destination formats */ diff --git a/res/res_format_attr_celt.c b/res/res_format_attr_celt.c index bd38b29e2..aea3eb482 100644 --- a/res/res_format_attr_celt.c +++ b/res/res_format_attr_celt.c @@ -45,6 +45,29 @@ struct celt_attr { unsigned int framesize; }; +static int celt_sdp_parse(struct ast_format_attr *format_attr, const char *attributes) +{ + struct celt_attr *attr = (struct celt_attr *) format_attr; + unsigned int val; + + if (sscanf(attributes, "framesize=%30u", &val) == 1) { + attr->framesize = val; + } + + return 0; +} + +static void celt_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str) +{ + struct celt_attr *attr = (struct celt_attr *) format_attr; + + if (!attr->framesize) { + return; + } + + ast_str_append(str, 0, "a=fmtp:%d framesize=%d\r\n", payload, attr->framesize); +} + static enum ast_format_cmp_res celt_cmp(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2) { struct celt_attr *attr1 = (struct celt_attr *) fattr1; @@ -161,6 +184,8 @@ static struct ast_format_attr_interface celt_interface = { .format_attr_set = celt_set, .format_attr_isset = celt_isset, .format_attr_get_val = celt_get_val, + .format_attr_sdp_parse = celt_sdp_parse, + .format_attr_sdp_generate = celt_sdp_generate, }; static int load_module(void) diff --git a/res/res_format_attr_silk.c b/res/res_format_attr_silk.c index 4f9bae739..7d4fa5bf8 100644 --- a/res/res_format_attr_silk.c +++ b/res/res_format_attr_silk.c @@ -47,6 +47,36 @@ struct silk_attr { unsigned int packetloss_percentage; }; +static int silk_sdp_parse(struct ast_format_attr *format_attr, const char *attributes) +{ + struct silk_attr *attr = (struct silk_attr *) format_attr; + unsigned int val; + + if (sscanf(attributes, "maxaveragebitrate=%30u", &val) == 1) { + attr->maxbitrate = val; + } + if (sscanf(attributes, "usedtx=%30u", &val) == 1) { + attr->dtx = val; + } + if (sscanf(attributes, "useinbandfec=%30u", &val) == 1) { + attr->fec = val; + } + + return 0; +} + +static void silk_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str) +{ + struct silk_attr *attr = (struct silk_attr *) format_attr; + + if ((attr->maxbitrate > 5000) && (attr->maxbitrate < 40000)) { + ast_str_append(str, 0, "a=fmtp:%d maxaveragebitrate=%d\r\n", payload, attr->maxbitrate); + } + + ast_str_append(str, 0, "a=fmtp:%d usedtx=%d\r\n", payload, attr->dtx); + ast_str_append(str, 0, "a=fmtp:%d useinbandfec=%d\r\n", payload, attr->fec); +} + static enum ast_format_cmp_res silk_cmp(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2) { struct silk_attr *attr1 = (struct silk_attr *) fattr1; @@ -195,6 +225,8 @@ static struct ast_format_attr_interface silk_interface = { .format_attr_set = silk_set, .format_attr_isset = silk_isset, .format_attr_get_val = silk_get_val, + .format_attr_sdp_parse = silk_sdp_parse, + .format_attr_sdp_generate = silk_sdp_generate, }; static int load_module(void) |