From a56e9705c9830cc8cbbfc071fa9ab063a1a0cd3d 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. - 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. Related: SYS#5066 Change-Id: Icef7dd626d3d4641c66b8dd87e2047fc0ab547d1 --- include/osmocom/gsm/protocol/gsm_08_08.h | 19 ++++++ src/gsm/gsm0808.c | 87 ++++++++++++++++++++++++ src/gsm/libosmogsm.map | 2 + 3 files changed, 108 insertions(+) diff --git a/include/osmocom/gsm/protocol/gsm_08_08.h b/include/osmocom/gsm/protocol/gsm_08_08.h index d169e7b92..aba1b84f5 100644 --- a/include/osmocom/gsm/protocol/gsm_08_08.h +++ b/include/osmocom/gsm/protocol/gsm_08_08.h @@ -649,6 +649,25 @@ 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 uint8_t gsm0808_amr_modes_from_cfg[2][16]; +extern const char *gsm0808_amr_mode_str[8]; + /* 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 4bb73038f..cb1fe6fa0 100644 --- a/src/gsm/gsm0808.c +++ b/src/gsm/gsm0808.c @@ -1968,4 +1968,91 @@ 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_str[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_str[bit]); + */ +const char *gsm0808_amr_mode_str[8] = {"4.75", "5.15", "5.90", "6.70", "7.40", "7.95", "10.2", "12.2"}; + /*! @} */ diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index b971ca016..aa5df90b8 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -246,6 +246,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_str; gsm0808_speech_codec_type_names; gsm0808_permitted_speech_names; gsm0808_chosen_enc_alg_names;