From 21f1bfb4a841a1b873e403f0b5c234e47c1e87f9 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Fri, 19 Jan 2024 05:51:53 +0100 Subject: [PATCH] add codec_mapping_next() and codec_mapping_foreach() So far, querying the codec mapping returns one match. For example: const struct codec_mapping *m; m = codec_mapping_by_speech_ver(GSM48_BCAP_SV_FR); if (!m) return -ENOENT; But when supporting various AMR rates, we need to find multiple matches in some code paths. Also to support AMR OA vs BE modes, we need to combine multiple criteria in some places. With this patch, and as soon as an upcoming patch implements codec_mapping_matches_speech_ver(), above code example becomes: const struct codec_mapping *m; codec_mapping_foreach (m) { if (codec_mapping_matches_speech_ver(m, GSM48_BCAP_SV_FR)) break; } if (!m) return -ENOENT; This pattern supports collecting multiple matches in a list: const struct codec_mapping *m; codec_mapping_foreach (m) { if (codec_mapping_matches_speech_ver(m, GSM48_BCAP_SV_FR)) sdp_audio_codecs_add_copy(my_list, m); } And this pattern also supports combining criteria: const struct codec_mapping *m; codec_mapping_foreach (m) { // only allow AMR in OA mode if (!osmo_sdp_fmtp_amr_is_octet_aligned(m->sdp.fmtp)) continue; if (codec_mapping_matches_speech_ver(m, GSM48_BCAP_SV_AMR_F) || codec_mapping_matches_speech_ver(m, GSM48_BCAP_SV_AMR_H)) sdp_audio_codecs_add_copy(my_list, m); } Change-Id: Iaaa59d4bf5a6126a1bfe4ae282b82f6cb3ec6f99 --- include/osmocom/msc/codec_mapping.h | 19 ++++++++++++++ src/libmsc/codec_mapping.c | 39 ++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/include/osmocom/msc/codec_mapping.h b/include/osmocom/msc/codec_mapping.h index 3b502a913..3fdec0934 100644 --- a/include/osmocom/msc/codec_mapping.h +++ b/include/osmocom/msc/codec_mapping.h @@ -39,6 +39,25 @@ struct codec_mapping { enum codec_frhr frhr; }; +const struct codec_mapping *codec_mapping_next(const struct codec_mapping *c); + +/* Iterate all known codec mappings. + * CODEC_MAPPING: const struct codec_mapping*. + * Example: + * + * const struct codec_mapping *m; + * codec_mapping_foreach (m) { + * if (codec_mapping_matches_speech_ver(m, GSM48_BCAP_SV_FR)) + * break; + * } + * if (!m) + * printf("not found\n"); + * else + * printf("%s\n", sdp_audio_codec_to_str(&m->sdp); + */ +#define codec_mapping_foreach(CODEC_MAPPING) \ + for ((CODEC_MAPPING) = codec_mapping_next(NULL); (CODEC_MAPPING); (CODEC_MAPPING) = codec_mapping_next(CODEC_MAPPING)) + const struct codec_mapping *codec_mapping_by_speech_ver(enum gsm48_bcap_speech_ver speech_ver); const struct codec_mapping *codec_mapping_by_gsm0808_speech_codec_type(enum gsm0808_speech_codec_type sct); const struct codec_mapping *codec_mapping_by_gsm0808_speech_codec(const struct gsm0808_speech_codec *sc); diff --git a/src/libmsc/codec_mapping.c b/src/libmsc/codec_mapping.c index e27407a5f..e142bccd4 100644 --- a/src/libmsc/codec_mapping.c +++ b/src/libmsc/codec_mapping.c @@ -202,8 +202,23 @@ const struct codec_mapping codec_map[] = { }, }; -#define foreach_codec_mapping(CODEC_MAPPING) \ - for ((CODEC_MAPPING) = codec_map; (CODEC_MAPPING) < codec_map + ARRAY_SIZE(codec_map); (CODEC_MAPPING)++) +/* Iterate the entire codec_map, one struct codec_mapping per call. + * Initiate iteration by passing c = NULL, and call repeatedly until NULL is returned: + * + * for (const struct codec_mapping *c = codec_mapping_next(NULL); c; c = codec_mapping_next(c)) + * handle(c); + */ +const struct codec_mapping *codec_mapping_next(const struct codec_mapping *c) +{ + if (!c) + return codec_map; + if (c < codec_map) + return NULL; + c++; + if (c >= codec_map + ARRAY_SIZE(codec_map)) + return NULL; + return c; +} const struct gsm_mncc_bearer_cap bearer_cap_empty = { .speech_ver = { -1 }, @@ -212,7 +227,7 @@ const struct gsm_mncc_bearer_cap bearer_cap_empty = { const struct codec_mapping *codec_mapping_by_speech_ver(enum gsm48_bcap_speech_ver speech_ver) { const struct codec_mapping *m; - foreach_codec_mapping(m) { + codec_mapping_foreach(m) { int i; for (i = 0; i < m->speech_ver_count; i++) if (m->speech_ver[i] == speech_ver) @@ -224,7 +239,7 @@ const struct codec_mapping *codec_mapping_by_speech_ver(enum gsm48_bcap_speech_v const struct codec_mapping *codec_mapping_by_gsm0808_speech_codec_type(enum gsm0808_speech_codec_type sct) { const struct codec_mapping *m; - foreach_codec_mapping(m) { + codec_mapping_foreach(m) { if (!m->has_gsm0808_speech_codec) continue; if (m->gsm0808_speech_codec.type == sct) @@ -236,7 +251,7 @@ const struct codec_mapping *codec_mapping_by_gsm0808_speech_codec_type(enum gsm0 const struct codec_mapping *codec_mapping_by_gsm0808_speech_codec(const struct gsm0808_speech_codec *sc) { const struct codec_mapping *m; - foreach_codec_mapping(m) { + codec_mapping_foreach(m) { if (!m->has_gsm0808_speech_codec) continue; if (m->gsm0808_speech_codec.type != sc->type) @@ -252,7 +267,7 @@ const struct codec_mapping *codec_mapping_by_gsm0808_speech_codec(const struct g const struct codec_mapping *codec_mapping_by_perm_speech(enum gsm0808_permitted_speech perm_speech) { const struct codec_mapping *m; - foreach_codec_mapping(m) { + codec_mapping_foreach(m) { if (m->perm_speech == perm_speech) return m; } @@ -262,7 +277,7 @@ const struct codec_mapping *codec_mapping_by_perm_speech(enum gsm0808_permitted_ const struct codec_mapping *codec_mapping_by_subtype_name(const char *subtype_name) { const struct codec_mapping *m; - foreach_codec_mapping(m) { + codec_mapping_foreach(m) { if (!strcmp(m->sdp.subtype_name, subtype_name)) return m; } @@ -272,7 +287,7 @@ const struct codec_mapping *codec_mapping_by_subtype_name(const char *subtype_na const struct codec_mapping *codec_mapping_by_mgcp_codec(enum mgcp_codecs mgcp) { const struct codec_mapping *m; - foreach_codec_mapping(m) { + codec_mapping_foreach(m) { if (m->mgcp == mgcp) return m; } @@ -332,7 +347,7 @@ int sdp_audio_codec_add_to_bearer_cap(struct gsm_mncc_bearer_cap *bearer_cap, co { const struct codec_mapping *m; int added = 0; - foreach_codec_mapping(m) { + codec_mapping_foreach(m) { int i; if (strcmp(m->sdp.subtype_name, codec->subtype_name)) continue; @@ -366,7 +381,7 @@ struct sdp_audio_codec *sdp_audio_codecs_add_speech_ver(struct sdp_audio_codecs { const struct codec_mapping *m; struct sdp_audio_codec *ret = NULL; - foreach_codec_mapping(m) { + codec_mapping_foreach(m) { int i; for (i = 0; i < m->speech_ver_count; i++) { if (m->speech_ver[i] == speech_ver) { @@ -486,7 +501,7 @@ int sdp_audio_codecs_to_gsm0808_channel_type(struct gsm0808_channel_type *ct, co int i; bool dup; idx++; - foreach_codec_mapping(m) { + codec_mapping_foreach(m) { if (strcmp(m->sdp.subtype_name, codec->subtype_name)) continue; @@ -548,7 +563,7 @@ int sdp_audio_codecs_to_gsm0808_channel_type(struct gsm0808_channel_type *ct, co enum mgcp_codecs sdp_audio_codec_to_mgcp_codec(const struct sdp_audio_codec *codec) { const struct codec_mapping *m; - foreach_codec_mapping(m) { + codec_mapping_foreach(m) { if (!sdp_audio_codec_cmp(&m->sdp, codec, false, false)) return m->mgcp; }