From 593d20d637312dbae152aa28618a62cfe396ac67 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Wed, 7 Sep 2022 02:26:47 +0200 Subject: [PATCH] add gsm0808_amr_modes_from_cfg Provide the definitions from 3GPP TS 28.062, Table 7.11.3.1.3-2 as generally usable API. Likely users: - upcoming patch to improve conversion between S0-S15 and MultiRate config, I900fda192742fa8f6dd54e9131ef1704b14cc41a - osmo-msc to figure out conversion between SDP AMR mode-set and 3GPP TS 48.008 Permitted Speech S0-S15. - osmo-bsc to choose AMR modes for channel activation from cfg / permitted speech from MSC. Related: SYS#5066 Change-Id: Icef7dd626d3d4641c66b8dd87e2047fc0ab547d1 --- include/osmocom/gsm/protocol/gsm_08_08.h | 23 ++++++ src/gsm/gsm0808.c | 97 ++++++++++++++++++++++++ src/gsm/libosmogsm.map | 2 + 3 files changed, 122 insertions(+) diff --git a/include/osmocom/gsm/protocol/gsm_08_08.h b/include/osmocom/gsm/protocol/gsm_08_08.h index 5060915b9..88ac610dc 100644 --- a/include/osmocom/gsm/protocol/gsm_08_08.h +++ b/include/osmocom/gsm/protocol/gsm_08_08.h @@ -687,6 +687,29 @@ enum gsm0808_speech_codec_rate { GSM0808_SC_CFG_AMR_12_2 = 0x0080, }; +/* Bit index of a mode as returned by gsm0808_amr_modes_from_cfg[]. + * Example: + * if (gsm0808_amr_modes_from_cfg[full_rate ? 1 : 0][9] & GSM0808_AMR_MODE_4_75) + * printf("S9 supports 4k75"); + */ +enum gsm0808_amr_mode { + GSM0808_AMR_MODE_4_75 = 0, + GSM0808_AMR_MODE_5_15, + GSM0808_AMR_MODE_5_90, + GSM0808_AMR_MODE_6_70, + GSM0808_AMR_MODE_7_40, + GSM0808_AMR_MODE_7_95, + GSM0808_AMR_MODE_10_2, + GSM0808_AMR_MODE_12_2, +}; +extern const struct value_string gsm0808_amr_mode_names[]; +static inline const char *gsm0808_amr_mode_name(enum gsm0808_amr_mode val) +{ + return get_value_string(gsm0808_amr_mode_names, val); +} + +extern const uint8_t gsm0808_amr_modes_from_cfg[2][16]; + /* 3GPP TS 48.008 3.2.2.103 Speech Codec List */ #define SPEECH_CODEC_MAXLEN 255 struct gsm0808_speech_codec_list { diff --git a/src/gsm/gsm0808.c b/src/gsm/gsm0808.c index ec4c39b7d..e1768c1ad 100644 --- a/src/gsm/gsm0808.c +++ b/src/gsm/gsm0808.c @@ -2028,4 +2028,101 @@ const struct value_string gsm0808_lcls_status_names[] = { { 0, NULL } }; +/* Convert one S0-S15 bit to its set of AMR modes, for HR AMR and FR AMR. + * This is 3GPP TS 28.062 Table 7.11.3.1.3-2: "Preferred Configurations", with some configurations removed as specified + * in 3GPP TS 48.008 3.2.2.103: + * + * FR_AMR is coded ‘0011’. + * S11, S13 and S15 are reserved and coded with zeroes. + * + * HR_AMR is coded ‘0100’. + * S6 - S7 and S11 – S15 are reserved and coded with zeroes. + * + * Meaning: for FR, exclude all Optimisation Mode configurations. + * For HR, exclude all that are not supported by HR AMR -- drop all that include at least one of + * 10.2 or 12.2. + * + * Also, for HR, drop 12.2k from S1. + * + * The first array dimension is 0 for half rate and 1 for full rate. + * The second array dimension is the configuration number (0..15) aka Sn. + * The values are bitmask combinations of (1 << GSM0808_AMR_MODE_nnnn). + * + * For example, accumulate all modes that are possible in a given my_s15_s0: + * + * uint8_t modes = 0; + * for (s_bit = 0; s_bit < 15; s_bit++) + * if (my_s15_s0 & (1 << s_bit)) + * modes |= gsm0808_amr_modes_from_cfg[full_rate ? 1 : 0][s_bit]; + * for (i = 0; i < 8; i++) + * if (modes & (1 << i)) + * printf(" %s", gsm0808_amr_mode_name(i)); + */ +const uint8_t gsm0808_amr_modes_from_cfg[2][16] = { +#define B(X) (1 << (GSM0808_AMR_MODE_##X)) + /* HR */ + { + /* Sn = modes */ + [0] = B(4_75), + [1] = B(4_75) | B(5_90) | B(7_40), + [2] = B(5_90), + [3] = B(6_70), + [4] = B(7_40), + [5] = B(7_95), + [6] = 0, + [7] = 0, + + [8] = B(4_75) | B(5_90), + [9] = B(4_75) | B(5_90) | B(6_70), + [10] = B(4_75) | B(5_90) | B(6_70) | B(7_40), + [11] = 0, + [12] = 0, + [13] = 0, + [14] = 0, + [15] = 0, + }, + /* FR */ + { + /* Sn = modes */ + [0] = B(4_75), + [1] = B(4_75) | B(5_90) | B(7_40) | B(12_2), + [2] = B(5_90), + [3] = B(6_70), + [4] = B(7_40), + [5] = B(7_95), + [6] = B(10_2), + [7] = B(12_2), + + [8] = B(4_75) | B(5_90), + [9] = B(4_75) | B(5_90) | B(6_70), + [10] = B(4_75) | B(5_90) | B(6_70) | B(7_40), + [11] = 0, + [12] = B(4_75) | B(5_90) | B(6_70) | B(10_2), + [13] = 0, + [14] = B(4_75) | B(5_90) | B(7_95) | B(12_2), + [15] = 0, + } +}; + +/* AMR mode names from GSM0808_AMR_MODE_*, for use with gsm0808_amr_modes_from_cfg. + * + * For example: + * printf("S9: "); + * uint8_t s9_modes = gsm0808_amr_modes_from_cfg[full_rate ? 1 : 0][9]; + * for (bit = 0; bit < 8; bit++) + * if (s9_modes & (1 << bit)) + * printf("%s,", gsm0808_amr_mode_name(bit)); + */ +const struct value_string gsm0808_amr_mode_names[] = { + { GSM0808_AMR_MODE_4_75, "4.75" }, + { GSM0808_AMR_MODE_5_15, "5.15" }, + { GSM0808_AMR_MODE_5_90, "5.90" }, + { GSM0808_AMR_MODE_6_70, "6.70" }, + { GSM0808_AMR_MODE_7_40, "7.40" }, + { GSM0808_AMR_MODE_7_95, "7.95" }, + { GSM0808_AMR_MODE_10_2, "10.2" }, + { GSM0808_AMR_MODE_12_2, "12.2" }, + {} +}; + /*! @} */ diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 21f8e1529..6ad363faa 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -252,6 +252,8 @@ gsm0808_chan_type_to_speech_codec; gsm0808_speech_codec_from_chan_type; gsm0808_sc_cfg_from_gsm48_mr_cfg; gsm48_mr_cfg_from_gsm0808_sc_cfg; +gsm0808_amr_modes_from_cfg; +gsm0808_amr_mode_names; gsm0808_speech_codec_type_names; gsm0808_permitted_speech_names; gsm0808_chosen_enc_alg_names;