neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-mgw/+/34900?usp=email )
Change subject: add fmtp string to ptmap: allow all possible fmtp ......................................................................
add fmtp string to ptmap: allow all possible fmtp
Remove the limit of having only one AMR octet-aligned fmtp parameter per MGCP message. Instead allow any arbitrary fmtp options, one per every codec.
Deprecate all use of struct mgcp_codec_param. Instead, store and pass plain fmtp strings.
We need to know fmtp details only for AMR, and only to probe whether it is octet-aligned. So add a separate fmtp string parser that returns that information flexibly, as in
if (osmo_mgcp_fmtp_get_int("octet-aligned", 0) == 1) ...
Provide legacy shims that still act correctly for any callers that may pass the old struct mgcp_codec_param. (I'm not sure if we need to keep this, but we can always drop it in another patch.)
Adjust one mgcp_test.c: instead of returning only the octet-aligned parameter, now osmo-mgw keeps and returns all the fmtp parameters that the user provided. So add the missing "mode-change-capability".
Related: OS#6171 Change-Id: If58590bda8627519ff07e0b6f43aa47a274f052b --- M include/osmocom/mgcp/Makefile.am A include/osmocom/mgcp/fmtp.h M include/osmocom/mgcp/mgcp_codec.h M include/osmocom/mgcp/mgcp_network.h M include/osmocom/mgcp_client/mgcp_client.h M src/libosmo-mgcp-client/mgcp_client.c M src/libosmo-mgcp/Makefile.am A src/libosmo-mgcp/fmtp.c M src/libosmo-mgcp/mgcp_codec.c M src/libosmo-mgcp/mgcp_network.c M src/libosmo-mgcp/mgcp_protocol.c M src/libosmo-mgcp/mgcp_sdp.c M tests/mgcp/mgcp_test.c 13 files changed, 264 insertions(+), 93 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-mgw refs/changes/00/34900/1
diff --git a/include/osmocom/mgcp/Makefile.am b/include/osmocom/mgcp/Makefile.am index 15ff01a..5d77c09 100644 --- a/include/osmocom/mgcp/Makefile.am +++ b/include/osmocom/mgcp/Makefile.am @@ -13,4 +13,5 @@ mgcp_network.h \ mgcp_protocol.h \ mgcp_iuup.h \ + fmtp.h \ $(NULL) diff --git a/include/osmocom/mgcp/fmtp.h b/include/osmocom/mgcp/fmtp.h new file mode 100644 index 0000000..95a7504 --- /dev/null +++ b/include/osmocom/mgcp/fmtp.h @@ -0,0 +1,11 @@ +#pragma once + +#include <stddef.h> +#include <stdbool.h> + +int osmo_mgcp_fmtp_get_val(char *val, size_t val_size, const char *fmtp, const char *option_name); +int osmo_mgcp_fmtp_get_int(const char *fmtp, const char *option_name, int default_value); +bool osmo_mgcp_fmtp_is_octet_aligned(const char *fmtp); + +#define OSMO_MGCP_OCTET_ALIGNED_STR "octet-aligned" +#define OSMO_MGCP_OCTET_ALIGNED_EQUALS_STR(VAL) OSMO_MGCP_OCTET_ALIGNED_STR "=" VAL diff --git a/include/osmocom/mgcp/mgcp_codec.h b/include/osmocom/mgcp/mgcp_codec.h index cfc8ecf..4702f6d 100644 --- a/include/osmocom/mgcp/mgcp_codec.h +++ b/include/osmocom/mgcp/mgcp_codec.h @@ -13,6 +13,7 @@ void mgcp_codec_summary(struct mgcp_conn_rtp *conn); void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn); int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param); +int mgcp_codec_add2(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const char *fmtp); int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst); const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn, const char *subtype_name, unsigned int match_nr); diff --git a/include/osmocom/mgcp/mgcp_network.h b/include/osmocom/mgcp/mgcp_network.h index e95907d..7f87224 100644 --- a/include/osmocom/mgcp/mgcp_network.h +++ b/include/osmocom/mgcp/mgcp_network.h @@ -83,8 +83,11 @@ char audio_name[64]; char subtype_name[64];
+ /* Deprecated. Use the new fmtp string instead. */ bool param_present; struct mgcp_codec_param param; + + char fmtp[256]; };
/* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */ diff --git a/include/osmocom/mgcp_client/mgcp_client.h b/include/osmocom/mgcp_client/mgcp_client.h index 31f4ae7..c238dc2 100644 --- a/include/osmocom/mgcp_client/mgcp_client.h +++ b/include/osmocom/mgcp_client/mgcp_client.h @@ -77,6 +77,11 @@
/*! payload type number (96-127) */ unsigned int pt; + + /*! the MGCP 'a=fmtp:N <...>' string, e.g. "mode-set=1,2,3;octet-align=0". + * Suggested storage: talloc allocated string with the struct mgcp_conn_peer or struct mgcp_response as talloc + * ctx. */ + const char *fmtp; };
struct mgcp_response_head { @@ -158,7 +163,8 @@ uint8_t rate, uint8_t offset);
/* Invoked when an MGCP response is received or sending failed. When the - * response is passed as NULL, this indicates failure during transmission. */ + * response is passed as NULL, this indicates failure during transmission. + * Not all pointers contained in the mgcp_response */ typedef void (* mgcp_response_cb_t )(struct mgcp_response *response, void *priv); int mgcp_response_parse_params(struct mgcp_response *r);
diff --git a/src/libosmo-mgcp-client/mgcp_client.c b/src/libosmo-mgcp-client/mgcp_client.c index a66b499..a1a2662 100644 --- a/src/libosmo-mgcp-client/mgcp_client.c +++ b/src/libosmo-mgcp-client/mgcp_client.c @@ -1369,19 +1369,27 @@ } MSGB_PRINTF_OR_RET("\r\n");
- /* Add optional codec parameters (fmtp) */ - if (mgcp_msg->param_present) { - for (i = 0; i < mgcp_msg->ptmap_len; i++) { - /* The following is only applicable for AMR */ - if (mgcp_msg->ptmap[i].codec != CODEC_AMR_8000_1 - && mgcp_msg->ptmap[i].codec != CODEC_AMRWB_16000_1) - continue; - pt = mgcp_msg->ptmap[i].pt; - if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned) - MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=1\r\n", pt); - else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned) - MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=0\r\n", pt); + for (i = 0; i < mgcp_msg->ptmap_len; i++) { + if (!mgcp_msg->ptmap[i].fmtp) { + + /* LEGACY COMPAT. Fill in fmtp with the legacy mgcp_msg->param, if any, when no individual fmtp + * is set on the codec. */ + if (mgcp_msg->param_present + && (mgcp_msg->ptmap[i].codec == CODEC_AMR_8000_1 + || mgcp_msg->ptmap[i].codec != CODEC_AMRWB_16000_1)) { + pt = mgcp_msg->ptmap[i].pt; + + if (mgcp_msg->param.amr_octet_aligned_present && mgcp_msg->param.amr_octet_aligned) + MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=1\r\n", pt); + else if (mgcp_msg->param.amr_octet_aligned_present && !mgcp_msg->param.amr_octet_aligned) + MSGB_PRINTF_OR_RET("a=fmtp:%u octet-align=0\r\n", pt); + + } + + continue; } + + MSGB_PRINTF_OR_RET("a=fmtp:%u %s\r\n", mgcp_msg->ptmap[i].pt, mgcp_msg->ptmap[i].fmtp); }
for (i = 0; i < mgcp_msg->ptmap_len; i++) { diff --git a/src/libosmo-mgcp/Makefile.am b/src/libosmo-mgcp/Makefile.am index fa9a8eb..df7ed1d 100644 --- a/src/libosmo-mgcp/Makefile.am +++ b/src/libosmo-mgcp/Makefile.am @@ -42,4 +42,5 @@ mgcp_ratectr.c \ mgcp_e1.c \ mgcp_iuup.c \ + fmtp.c \ $(NULL) diff --git a/src/libosmo-mgcp/fmtp.c b/src/libosmo-mgcp/fmtp.c new file mode 100644 index 0000000..6899d01 --- /dev/null +++ b/src/libosmo-mgcp/fmtp.c @@ -0,0 +1,89 @@ +/* + * (C) 2023-2015 by sysmocom - s.f.m.c. GmbH info@sysmocom.de + * All Rights Reserved + * + * Author: Neels Hofmeyr + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ +#include <string.h> +#include <ctype.h> +#include <osmocom/core/utils.h> +#include <osmocom/core/logging.h> +#include <osmocom/mgcp/fmtp.h> + +static const char *fmtp_next_option(const char *fmtp) +{ + for (; fmtp && *fmtp && *fmtp != ';'; fmtp++); + for (; fmtp && isspace(*fmtp); fmtp++); + return fmtp; +} + +int osmo_mgcp_fmtp_get_val(char *val, size_t val_size, const char *fmtp, const char *option_name) +{ + const char *pos = fmtp; + const char *end; + int option_name_len = strlen(option_name); + for (; pos && *pos; pos = fmtp_next_option(pos)) { + if (!osmo_str_startswith(pos, option_name)) + continue; + pos += option_name_len; + if (*pos != '=') + continue; + pos++; + break; + } + + if (!pos || !*pos) + return 0; + + end = fmtp_next_option(pos); + OSMO_ASSERT(end); + if (val && val_size) + osmo_strlcpy(val, pos, OSMO_MIN(val_size, end - pos + 1)); + return end - pos; +} + +int osmo_mgcp_fmtp_get_int(const char *fmtp, const char *option_name, int default_value) +{ + char val[128]; + if (!osmo_mgcp_fmtp_get_val(val, sizeof(val), fmtp, option_name)) + return default_value; + if (!val[0]) + return default_value; + int i; + if (osmo_str_to_int(&i, val, 10, 0, 1)) { + /* error parsing number */ + LOGP(DLMGCP, LOGL_ERROR, "Invalid number in fmtp parameter '%s': '%s'\n", + option_name, val); + return default_value; + } + return i; +} + +/* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode. + * See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB + * Media Type Registration": + * + * octet-align: Permissible values are 0 and 1. If 1, octet-aligned + * operation SHALL be used. If 0 or if not present, + * bandwidth-efficient operation is employed. + * + * https://tools.ietf.org/html/rfc4867 + */ +bool osmo_mgcp_fmtp_is_octet_aligned(const char *fmtp) +{ + return osmo_mgcp_fmtp_get_int(fmtp, OSMO_MGCP_OCTET_ALIGNED_STR, 0) == 1; +} diff --git a/src/libosmo-mgcp/mgcp_codec.c b/src/libosmo-mgcp/mgcp_codec.c index d340e11..714a7c5 100644 --- a/src/libosmo-mgcp/mgcp_codec.c +++ b/src/libosmo-mgcp/mgcp_codec.c @@ -24,6 +24,7 @@ #include <osmocom/mgcp/mgcp_endp.h> #include <osmocom/mgcp/mgcp_trunk.h> #include <osmocom/mgcp/mgcp_codec.h> +#include <osmocom/mgcp/fmtp.h> #include <errno.h>
/* Helper function to dump codec information of a specified codec to a printable @@ -116,9 +117,9 @@ * \param[out] conn related rtp-connection. * \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined). * \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1"). - * \param[in] param optional codec parameters (set to NULL when unused). + * \param[in] fmtp optional codec parameters (set to NULL when unused). * \returns 0 on success, -EINVAL on failure. */ -int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param) +int mgcp_codec_add2(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const char *fmtp) { int rate; int channels; @@ -261,12 +262,16 @@ } }
- /* Copy over optional codec parameters */ - if (param) { - codec->param = *param; - codec->param_present = true; - } else - codec->param_present = false; + if (fmtp) { + OSMO_STRLCPY_ARRAY(codec->fmtp, fmtp); + if (strlen(codec->fmtp) != strlen(fmtp)) { + LOGP(DLMGCP, LOGL_ERROR, "fmtp too long: %zu > %zu\n", strlen(fmtp), strlen(codec->fmtp)); + /* let's just hope what is there is still useful, worst case the call's audio doesn't work */ + } + } + + /* legacy */ + codec->param_present = false;
conn->end.codecs_assigned++; return 0; @@ -276,6 +281,28 @@ return -EINVAL; }
+/*! Legacy compat, use mgcp_codec_add2() instead to be able to pass any fmtp besides AMR octet-aligned=1. + * Add codec configuration depending on payload type and/or codec name. This + * function uses the input parameters to extrapolate the full codec information. + * \param[out] codec configuration (caller provided memory). + * \param[out] conn related rtp-connection. + * \param[in] payload_type codec type id (e.g. 3 for GSM, -1 when undefined). + * \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1"). + * \param[in] param optional codec parameters (set to NULL when unused). + * \returns 0 on success, -EINVAL on failure. */ +int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param) +{ + const char *fmtp = NULL; + if (param && param->amr_octet_aligned_present) { + if (param->amr_octet_aligned) + fmtp = OSMO_MGCP_OCTET_ALIGNED_EQUALS_STR("1"); + else + fmtp = OSMO_MGCP_OCTET_ALIGNED_EQUALS_STR("0"); + } + + return mgcp_codec_add2(conn, payload_type, audio_name, fmtp); +} + /* Return true if octet-aligned is set in the given codec. Default to octet-aligned=0, i.e. bandwidth-efficient mode. * See RFC4867 "RTP Payload Format for AMR and AMR-WB" sections "8.1. AMR Media Type Registration" and "8.2. AMR-WB * Media Type Registration": @@ -288,11 +315,14 @@ */ bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec) { - if (!codec->param_present) + if (!codec->fmtp[0]) { + /* Legacy */ + if (codec->param_present && codec->param.amr_octet_aligned_present) + return codec->param.amr_octet_aligned; return false; - if (!codec->param.amr_octet_aligned_present) - return false; - return codec->param.amr_octet_aligned; + } + + return osmo_mgcp_fmtp_get_int(codec->fmtp, OSMO_MGCP_OCTET_ALIGNED_STR, 0) == 1; }
/* Compare two codecs, all parameters must match up */ @@ -462,13 +492,12 @@ /* Check if the codec has a specific AMR mode (octet-aligned or bandwith-efficient) set. */ bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec) { - if (codec->param_present == false) - return false; - if (!codec->param.amr_octet_aligned_present) - return false; - if (strcmp(codec->subtype_name, "AMR") != 0) - return false; - return true; + if (!codec->fmtp[0]) { + /* Legacy */ + return codec->param_present && codec->param.amr_octet_aligned_present; + } + + return osmo_mgcp_fmtp_get_val(NULL, 0, codec->fmtp, OSMO_MGCP_OCTET_ALIGNED_STR) > 0; }
/* Find the payload type number configured for a specific codec by SDP. diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c index 46d0cb4..2ff7631 100644 --- a/src/libosmo-mgcp/mgcp_network.c +++ b/src/libosmo-mgcp/mgcp_network.c @@ -1212,12 +1212,12 @@ if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) { /* the iuup code will correctly transform to the correct AMR mode */ } else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) { - rc = amr_oa_bwe_convert(endp, msg, - conn_dst->end.codec->param.amr_octet_aligned); + bool oa = mgcp_codec_amr_is_octet_aligned(conn_dst->end.codec); + rc = amr_oa_bwe_convert(endp, msg, oa); if (rc < 0) { LOGPENDP(endp, DRTP, LOGL_ERROR, "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n", - conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient"); + oa ? "octet-aligned" : "bandwidth-efficient"); break; } } else if (rtp_end->rfc5993_hr_convert && @@ -1527,16 +1527,18 @@ /* Handle AMR frame format conversion (octet-aligned vs. bandwith-efficient) */ if (mc->proto == MGCP_PROTO_RTP && mgcp_codec_amr_align_mode_is_indicated(conn_src->end.codec)) { + bool src_oa; /* Make sure that the incoming AMR frame format matches the frame format that the call agent has * communicated via SDP when the connection was created/modfied. */ int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg)); if (oa < 0) return -1; - if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned) { + src_oa = mgcp_codec_amr_is_octet_aligned(conn_src->end.codec); + if (((bool)oa) != src_oa) { LOG_CONN_RTP(conn_src, LOGL_NOTICE, "rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u." " check the config of your call-agent!\n", - msgb_length(msg), conn_src->end.codec->param.amr_octet_aligned, oa); + msgb_length(msg), src_oa, oa); return -1; } } diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c index 809622b..136787b 100644 --- a/src/libosmo-mgcp/mgcp_protocol.c +++ b/src/libosmo-mgcp/mgcp_protocol.c @@ -1134,6 +1134,10 @@
LOGPCONN(_conn, DLMGCP, LOGL_NOTICE, "CRCX: connection successfully created\n"); + + for (int i = 0; i < conn->end.codecs_assigned; i++) + LOGPCONN(_conn, DLMGCP, LOGL_NOTICE, "fmtp=%s\n", conn->end.codecs[i].fmtp); + rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_SUCCESS)); mgcp_endp_update(endp);
diff --git a/src/libosmo-mgcp/mgcp_sdp.c b/src/libosmo-mgcp/mgcp_sdp.c index 10822e5..4345a27 100644 --- a/src/libosmo-mgcp/mgcp_sdp.c +++ b/src/libosmo-mgcp/mgcp_sdp.c @@ -34,6 +34,7 @@ #include <osmocom/mgcp/mgcp_codec.h> #include <osmocom/mgcp/mgcp_sdp.h> #include <osmocom/mgcp/mgcp_protocol.h> +#include <osmocom/mgcp/fmtp.h>
#include <errno.h> #include <stdlib.h> @@ -55,7 +56,7 @@ }; struct sdp_fmtp_param { int payload_type; - struct mgcp_codec_param param; + const char *fmtp; };
@@ -195,11 +196,7 @@ { char *str; char *str_ptr; - char *param_str; unsigned int pt; - unsigned int count = 0; - char delimiter; - unsigned int amr_octet_aligned;
memset(fmtp_param, 0, sizeof(*fmtp_param));
@@ -218,40 +215,13 @@ goto error; fmtp_param->payload_type = pt;
- /* Advance pointer to the beginning of the parameter section and - * tokenize string */ + /* Advance pointer to the beginning of the parameter section */ str_ptr = strstr(str_ptr, " "); if (!str_ptr) goto error; str_ptr++;
- param_str = strtok(str_ptr, " "); - if (!param_str) - goto exit; - - while (1) { - /* Make sure that we don't get trapped in an endless loop */ - if (count > 256) - goto error; - - /* Chop off delimiters ';' at the end */ - delimiter = str_ptr[strlen(str_ptr) - 1]; - if (delimiter == ';' || delimiter == ',') - str_ptr[strlen(str_ptr) - 1] = '\0'; - - /* AMR octet aligned parameter (see also RFC 3267, section 8.3) */ - if (sscanf(param_str, "octet-align=%d", &amr_octet_aligned) == 1) { - fmtp_param->param.amr_octet_aligned_present = true; - fmtp_param->param.amr_octet_aligned = false; - if (amr_octet_aligned == 1) - fmtp_param->param.amr_octet_aligned = true; - } - - param_str = strtok(NULL, " "); - if (!param_str) - break; - count++; - } + fmtp_param->fmtp = talloc_strdup(ctx, str_ptr);
exit: talloc_free(str); @@ -299,13 +269,13 @@
/* Pick optional fmtp parameters by payload type, if there are no fmtp * parameters, a nullpointer is returned */ -static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len) +static const char *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_params, unsigned int fmtp_params_len) { unsigned int i;
for (i = 0; i < fmtp_params_len; i++) { if (fmtp_params[i].payload_type == pt) - return &fmtp_params[i].param; + return fmtp_params[i].fmtp; }
return NULL; @@ -326,7 +296,6 @@ unsigned int codecs_used = 0; struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS]; unsigned int fmtp_used = 0; - struct mgcp_codec_param *codec_param; char ipbuf[INET6_ADDRSTRLEN]; char *line; unsigned int i; @@ -421,8 +390,8 @@
/* Store parsed codec information */ for (i = 0; i < codecs_used; i++) { - codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used); - rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param); + const char *fmtp = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used); + rc = mgcp_codec_add2(conn, codecs[i].payload_type, codecs[i].map_line, fmtp); if (rc < 0) LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n"); } @@ -436,10 +405,12 @@ if (codecs_used == 0) LOGPC(DLMGCP, LOGL_NOTICE, "none"); for (i = 0; i < codecs_used; i++) { - LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s", + LOGPC(DLMGCP, LOGL_NOTICE, " %d=%s%s%s%s", rtp->codecs[i].payload_type, - strlen(rtp->codecs[i].subtype_name) ? rtp->codecs[i].subtype_name : "unknown"); - LOGPC(DLMGCP, LOGL_NOTICE, " "); + strlen(rtp->codecs[i].subtype_name) ? rtp->codecs[i].subtype_name : "unknown", + rtp->codecs[i].fmtp[0] ? ",fmtp='" : "", + rtp->codecs[i].fmtp, + rtp->codecs[i].fmtp[0] ? "'" : ""); } LOGPC(DLMGCP, LOGL_NOTICE, "\n");
@@ -518,23 +489,23 @@ }
for (i = 0; i < fmtp_params_len; i++) { + bool first = true; rc = msgb_printf(sdp, "a=fmtp:%u", fmtp_params[i].payload_type); if (rc < 0) return -EINVAL;
/* Add amr octet align parameter */ - if (fmtp_params[i].param.amr_octet_aligned_present) { - if (fmtp_params[i].param.amr_octet_aligned) - rc = msgb_printf(sdp, " octet-align=1"); - else - rc = msgb_printf(sdp, " octet-align=0"); - if (rc < 0) - return -EINVAL; + if (fmtp_params[i].fmtp) { + msgb_printf(sdp, "%s%s", first ? " " : ";", fmtp_params[i].fmtp); + first = false; }
/* Append extra parameters from fmtp extra */ if (fmtp_params[i].payload_type == fmtp_extra_pt) { - rc = msgb_printf(sdp, " %s", fmtp_extra_pars); + rc = msgb_printf(sdp, "%s%s", + first ? " " : ";", + fmtp_extra_pars); + first = false; if (rc < 0) return -EINVAL; } @@ -561,7 +532,6 @@ const char *fmtp_extra; const char *audio_name; int payload_type; - struct sdp_fmtp_param fmtp_param; int rc; int payload_types[1]; int local_port; @@ -613,12 +583,25 @@ goto buffer_too_small; }
- if (codec->param_present) { - fmtp_param.payload_type = payload_type; - fmtp_param.param = codec->param; - fmtp_params[0] = fmtp_param; + if (codec->fmtp[0]) { + fmtp_params[0] = (struct sdp_fmtp_param){ + .payload_type = payload_type, + .fmtp = codec->fmtp, + }; fmtp_params_len = 1; } + else if (codec->param_present) { + /* Legacy */ + fmtp_params[0] = (struct sdp_fmtp_param){ + .payload_type = payload_type, + }; + fmtp_params_len = 1; + if (codec->param.amr_octet_aligned) + fmtp_params[0].fmtp = OSMO_MGCP_OCTET_ALIGNED_EQUALS_STR("1"); + else + fmtp_params[0].fmtp = OSMO_MGCP_OCTET_ALIGNED_EQUALS_STR("0"); + } + rc = add_fmtp(sdp, fmtp_params, fmtp_params_len, fmtp_extra); if (rc < 0) goto buffer_too_small; diff --git a/tests/mgcp/mgcp_test.c b/tests/mgcp/mgcp_test.c index e37bb57..f88b3e2 100644 --- a/tests/mgcp/mgcp_test.c +++ b/tests/mgcp/mgcp_test.c @@ -552,7 +552,7 @@ "t=0 0\r\n" \ "m=audio 16012 RTP/AVP 111\r\n" \ "a=rtpmap:111 AMR/8000/1\r\n" \ - "a=fmtp:111 octet-align=1\r\n" \ + "a=fmtp:111 mode-change-capability=2; octet-align=1\r\n" \ "a=ptime:20\r\n"
#define CRCX_NO_LCO_NO_SDP_RET \ @@ -845,6 +845,8 @@ } } else if (check_response(msg->data, t->exp_resp) != 0) { printf("%s failed.\n", t->name); + fflush(stderr); + fflush(stdout); OSMO_ASSERT(false); }