sdp_audio_codecs(): add 'once', 'pick_unused_pt_nr' args

So far the API is pivoting on the payload type numbers as the "primary
key" for codec lists. However, working with variants of codecs, the
payload type numbers are just incidental, and the API isn't helpful.

- change the behavior to regard the subtype name and fmtp as the
  defining identity of a codec: use sdp_audio_codec_cmp() to match.
- add argument 'once': flag to make sure a given subtype+fmtp exists
  only once, regardless of payload type nr.
- add argument 'pick_unused_pt_nr': flag to make sure a new entry
  doesn't duplicate payload type numbers.

This is preparation to properly match AMR variants, in order to fix the
expected error currently visible in msc_vlr_test_call.c:875.

Change-Id: I87db779dbab39dfdef2724488ccdb6959e6731ed
This commit is contained in:
Neels Hofmeyr 2024-01-29 02:26:06 +01:00
parent d5c45dc580
commit 314cc11a45
5 changed files with 78 additions and 46 deletions

View File

@ -56,9 +56,11 @@ int sdp_audio_codecs_cmp(const struct sdp_audio_codecs *a, const struct sdp_audi
bool cmp_fmtp, bool cmp_payload_type);
struct sdp_audio_codec *sdp_audio_codecs_add(struct sdp_audio_codecs *ac, unsigned int payload_type,
const char *subtype_name, unsigned int rate, const char *fmtp);
const char *subtype_name, unsigned int rate, const char *fmtp,
bool once, bool pick_unused_pt_nr);
struct sdp_audio_codec *sdp_audio_codecs_add_copy(struct sdp_audio_codecs *ac,
const struct sdp_audio_codec *codec);
const struct sdp_audio_codec *codec,
bool once, bool pick_unused_pt_nr);
int sdp_audio_codecs_remove(struct sdp_audio_codecs *ac, const struct sdp_audio_codec *codec);
struct sdp_audio_codec *sdp_audio_codecs_by_payload_type(struct sdp_audio_codecs *ac,
unsigned int payload_type, bool create);

View File

@ -494,7 +494,7 @@ struct sdp_audio_codec *sdp_audio_codecs_add_speech_ver(struct sdp_audio_codecs
int i;
for (i = 0; i < m->speech_ver_count; i++) {
if (m->speech_ver[i] == speech_ver) {
ret = sdp_audio_codecs_add_copy(ac, &m->sdp);
ret = sdp_audio_codecs_add_copy(ac, &m->sdp, true, true);
break;
}
}
@ -507,7 +507,7 @@ struct sdp_audio_codec *sdp_audio_codecs_add_mgcp_codec(struct sdp_audio_codecs
const struct codec_mapping *m = codec_mapping_by_mgcp_codec(mgcp_codec);
if (!m)
return NULL;
return sdp_audio_codecs_add_copy(ac, &m->sdp);
return sdp_audio_codecs_add_copy(ac, &m->sdp, true, true);
}
void sdp_audio_codecs_from_bearer_cap(struct sdp_audio_codecs *ac, const struct gsm_mncc_bearer_cap *bc)
@ -589,7 +589,7 @@ void sdp_audio_codecs_from_speech_codec_list(struct sdp_audio_codecs *ac, const
codec_mapping_foreach (m) {
if (!codec_mapping_matches_gsm0808_speech_codec(m, sc))
continue;
sdp_audio_codecs_add_copy(ac, &m->sdp);
sdp_audio_codecs_add_copy(ac, &m->sdp, true, true);
}
}
}

View File

@ -449,7 +449,7 @@ void rtp_stream_set_mode(struct rtp_stream *rtps, enum mgcp_connection_mode mode
void rtp_stream_set_one_codec(struct rtp_stream *rtps, const struct sdp_audio_codec *codec)
{
struct sdp_audio_codecs codecs = {};
sdp_audio_codecs_add_copy(&codecs, codec);
sdp_audio_codecs_add_copy(&codecs, codec, false, false);
rtp_stream_set_codecs(rtps, &codecs);
}

View File

@ -119,51 +119,81 @@ int sdp_audio_codecs_cmp(const struct sdp_audio_codecs *a, const struct sdp_audi
return 0;
}
/* Given a predefined fixed payload_type number, add an SDP audio codec entry, if not present yet.
* The payload_type must exist in sdp_msg_payload_type_names.
* Return the audio codec created or already existing for this payload type number.
/* Add an SDP audio codec entry.
* If 'once' == true, do not add an entry if an identical entry (except for the payload_type number) already exists.
* If 'pick_unused_pt_nr' == true, pick an unused PT nr in case 'payload_type' is already taken in 'ac'.
* Return the new entry, or NULL if there is no more space in the list.
*/
struct sdp_audio_codec *sdp_audio_codecs_add(struct sdp_audio_codecs *ac, unsigned int payload_type,
const char *subtype_name, unsigned int rate, const char *fmtp)
const char *subtype_name, unsigned int rate, const char *fmtp,
bool once, bool pick_unused_pt_nr)
{
struct sdp_audio_codec *codec;
/* Does an entry already exist? */
codec = sdp_audio_codecs_by_payload_type(ac, payload_type, false);
if (codec) {
/* Already exists, sanity check */
if (!codec->subtype_name[0])
OSMO_STRLCPY_ARRAY(codec->subtype_name, subtype_name);
else if (strcmp(codec->subtype_name, subtype_name)) {
/* There already is an entry with this payload_type number but a mismatching subtype_name. That is
* weird, rather abort. */
return NULL;
}
if (codec->rate != rate
|| (fmtp && strcmp(fmtp, codec->fmtp))) {
/* Mismatching details. Rather abort */
return NULL;
}
return codec;
}
/* None exists, create codec entry for this payload type number */
codec = sdp_audio_codecs_by_payload_type(ac, payload_type, true);
/* NULL means unable to add an entry */
if (!codec)
return NULL;
OSMO_STRLCPY_ARRAY(codec->subtype_name, subtype_name);
if (fmtp)
OSMO_STRLCPY_ARRAY(codec->fmtp, fmtp);
codec->rate = rate;
return codec;
struct sdp_audio_codec c = {
.payload_type = payload_type,
.rate = rate,
};
OSMO_STRLCPY_ARRAY(c.subtype_name, subtype_name);
if (fmtp && *fmtp)
OSMO_STRLCPY_ARRAY(c.fmtp, fmtp);
return sdp_audio_codecs_add_copy(ac, &c, once, pick_unused_pt_nr);
}
struct sdp_audio_codec *sdp_audio_codecs_add_copy(struct sdp_audio_codecs *ac, const struct sdp_audio_codec *codec)
struct sdp_audio_codec *sdp_audio_codecs_add_copy(struct sdp_audio_codecs *ac,
const struct sdp_audio_codec *codec,
bool once, bool pick_unused_pt_nr)
{
return sdp_audio_codecs_add(ac, codec->payload_type, codec->subtype_name, codec->rate,
codec->fmtp[0] ? codec->fmtp : NULL);
struct sdp_audio_codec *new_entry;
if (once) {
struct sdp_audio_codec *exists;
exists = sdp_audio_codecs_by_descr(ac, codec);
if (exists)
return exists;
}
if (ac->count >= ARRAY_SIZE(ac->codec))
return NULL;
/* Compose new_entry in an unused entry, and increment 'count' further below. */
new_entry = &ac->codec[ac->count];
/* Take provided entry as-is. */
*new_entry = *codec;
/* Adjust payload_type number? */
if (pick_unused_pt_nr) {
const struct sdp_audio_codec *c;
bool exists = false;
unsigned int existing_pt_max = 96;
sdp_audio_codecs_foreach(c, ac) {
if (c->payload_type == new_entry->payload_type)
exists = true;
existing_pt_max = OSMO_MAX(existing_pt_max, c->payload_type);
/* For dynamic allocations, skip these predefined numbers, taken from enum mgcp_codecs:
* CODEC_GSMEFR_8000_1 = 110, 3GPP TS 48.103 table 5.4.2.2.1
* CODEC_GSMHR_8000_1 = 111, 3GPP TS 48.103 table 5.4.2.2.1
* CODEC_AMR_8000_1 = 112, 3GPP TS 48.103 table 5.4.2.2.1
* CODEC_AMRWB_16000_1 = 113, 3GPP TS 48.103 table 5.4.2.2.1
* CODEC_IUFP = 96,
* CODEC_CLEARMODE = 120, 3GPP TS 48.103 table 5.4.2.2.1
*/
if (existing_pt_max >= 110 && existing_pt_max < 113)
existing_pt_max = 113;
else if (existing_pt_max == 120)
existing_pt_max++;
}
if (exists)
new_entry->payload_type = existing_pt_max + 1;
}
/* new_entry is complete, increment list count. */
ac->count++;
return new_entry;
}
/* Find or create an entry for the given payload_type number in the given list of codecs.

View File

@ -1340,7 +1340,7 @@ static struct sdp_msg *sdp_from_codec_strs(const char *const *codec_strs)
BTW("ERROR: unknown codec_str: %s", *codec_str);
abort();
}
if (!sdp_audio_codecs_add_copy(&sdp.audio_codecs, &c)) {
if (!sdp_audio_codecs_add_copy(&sdp.audio_codecs, &c, false, false)) {
BTW("ERROR: list full, cannot add %s", *codec_str);
abort();
}