diff options
Diffstat (limited to 'src/gsm/gsm0808_utils.c')
-rw-r--r-- | src/gsm/gsm0808_utils.c | 108 |
1 files changed, 105 insertions, 3 deletions
diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c index efa9305f..c8037ebd 100644 --- a/src/gsm/gsm0808_utils.c +++ b/src/gsm/gsm0808_utils.c @@ -1657,8 +1657,104 @@ int gsm0808_speech_codec_from_chan_type(struct gsm0808_speech_codec *sc, return 0; } -/*! Determine a set of AMR speech codec configuration bits (S0-S15) from a - * given GSM 04.08 AMR configuration struct. +/*! Determine a set of AMR speech codec configuration bits (S0-S15) from a given set of AMR modes. + * Enable each of the S0..S15 bits that is a subset of the given modes. + * In other words, there must be no S0..S15 bit enabled that includes a mode that is disabled in modes. + * See 3GPP TS 28.062 Table 7.11.3.1.3-2, where each column defines one of the S0..S15 bits. + * The bits in 'modes' are a binary match for the mX_XX flags in struct gsm48_multi_rate_conf.mX_XX. + * + * Example: + * uint8_t modes = gsm48_multi_rate_conf_get_amr_modes(my_cfg); + * uint16_t s15_s0 = gsm0808_sc_cfg_from_amr_modes(modes, full_rate); + * + * \param[in] modes Set of modes, bitmask of (1 << GSM0808_AMR_MODE_4_75) | (1 << GSM0808_AMR_MODE_5_90) | ... + * \param[in] full_rate When false, apply special HR AMR exceptions. + * \returns configuration bits (S0-S15) */ +uint16_t gsm0808_sc_cfg_from_amr_modes(uint8_t modes, bool full_rate) +{ + uint16_t s15_s0 = 0; + int s_bit; + + for (s_bit = 0; s_bit < 16; s_bit++) { + uint8_t s_modes = gsm0808_amr_modes_from_cfg[full_rate ? 1 : 0][s_bit]; + /* When s_modes is a non-zero subset of the input modes, add this configuration to s15_s0. + * Some Sn are empty, because they are not supported for HR, or not at all in GSM. */ + if (s_modes && ((s_modes & modes) == s_modes)) + s15_s0 |= (1 << s_bit); + } + return s15_s0; +} + +/*! Return all AMR modes present in any of the given s15_s0 configurations. + * The returned bits are a binary match for the mX_XX flags in struct gsm48_multi_rate_conf.mX_XX. + * + * Example: + * uint8_t modes = gsm0808_sc_cfg_get_all_amr_modes(s15_s0, full_rate); + * gsm48_multi_rate_conf_set_amr_modes(&my_cfg, modes); + * + * \param[in] s15_s0 S15-S0 configuration bits, see gsm0808_amr_modes_from_cfg. + * \param[in] full_rate When false, return only modes compatible with HR AMR, and only observe Sn bits marked as + * supported by HR AMR, as in gsm0808_amr_modes_from_cfg. + * \return Bitmask of modes present in s15_s0, as in (1 << GSM0808_AMR_MODE_X_XX). + */ +uint8_t gsm0808_sc_cfg_get_all_amr_modes(uint16_t s15_s0, bool full_rate) +{ + uint8_t modes = 0; + int s_bit; + for (s_bit = 0; s_bit < 16; s_bit++) { + if (!(s15_s0 & (1 << s_bit))) + continue; + modes |= gsm0808_amr_modes_from_cfg[full_rate ? 1 : 0][s_bit]; + } + return modes; +} + +/*! Return "the best choice" of at most four AMR modes present in the given s15_s0 configurations. + * This is useful to determine which four or less modes to send in the MR CFG IE during GSM channel activation. + * + * "The best choice": return the modes for the highest Sn present in s15_s0, with these exceptions: + * - Skip any Sn that is not supported; e.g. HR does not support S6, and GSM never supports S11. See API doc of + * gsm0808_amr_modes_from_cfg for an explanation. + * - S1 ranks higher than S2..S9 -- S1 has a more favorable variety of rates than the latter ones. + * + * For example: + * - if S8 and S9 are set, return the modes for S9. + * - if S0 thru S9 are set, return the modes for S1 (because S1 ranks higher than S9). + * - if S0 thru S11 are set, return the modes for S10 (because S11 is not supported). + * + * Code example: + * uint8_t modes = gsm0808_sc_cfg_get_best_amr_modes(s15_s0, full_rate); + * gsm48_multi_rate_conf_set_amr_modes(&my_cfg, modes); + * + * \param[in] s15_s0 S15-S0 configuration bits, see gsm0808_amr_modes_from_cfg. + * \param[in] full_rate When false, return only modes compatible with HR AMR, and only observe Sn bits marked as + * supported by HR AMR, as in gsm0808_amr_modes_from_cfg. + * \return Bitmask of modes chosen from s15_s0, as in (1 << GSM0808_AMR_MODE_X_XX) | (1 << ...), or 0 if no modes are + * viable. + */ +uint8_t gsm0808_sc_cfg_get_best_amr_modes(uint16_t s15_s0, bool full_rate) +{ + /* Could skip S15, S13, S11 here, but let's rather rely on the definition of gsm0808_amr_modes_from_cfg. */ + const int s_bit_preference[] = { 15, 14, 13, 12, 11, 10, 1, 9, 8, 7, 6, 5, 4, 3, 2, 0 }; + int i; + uint8_t modes = 0; + for (i = 0; (!modes) && (i < ARRAY_SIZE(s_bit_preference)); i++) { + int s_bit = s_bit_preference[i]; + if (!(s15_s0 & s_bit)) + continue; + modes = gsm0808_amr_modes_from_cfg[full_rate ? 1 : 0][s_bit]; + } + return modes; +} + +/*! Deprecated, use gsm0808_sc_cfg_from_amr_modes(); The following code is an equivalent replacement for a call to + * s15_s0 = gsm0808_sc_cfg_from_gsm48_mr_cfg(cfg, fr): + * + * s15_s0 = gsm0808_sc_cfg_from_amr_modes(gsm48_multi_rate_conf_get_amr_modes(cfg), fr); + * + * Determine a set of AMR speech codec configuration bits (S0-S15) from a given GSM 04.08 AMR configuration struct. + * Enable all those AMR configurations where at least one of its AMR rates is enabled in cfg. + * This is usually undesired behavior, use gsm0808_sc_cfg_from_amr_modes() instead. * \param[in] cfg AMR configuration in GSM 04.08 format. * \param[in] hint if the resulting configuration shall be used with a FR or HR TCH. * \returns configuration bits (S0-S15) */ @@ -1710,7 +1806,13 @@ uint16_t gsm0808_sc_cfg_from_gsm48_mr_cfg(const struct gsm48_multi_rate_conf *cf return s15_s0; } -/*! Determine a GSM 04.08 AMR configuration struct from a set of speech codec +/*! Deprecated, use gsm0808_sc_cfg_get_best_amr_modes(); The following code is an equivalent replacement for a call to + * gsm48_mr_cfg_from_gsm0808_sc_cfg(cfg, s15_s0): + * + * *cfg = (struct gsm48_multi_rate_conf){ .ver = 1, .icmi = 1 }; + * gsm48_multi_rate_conf_set_amr_modes(cfg, gsm0808_sc_cfg_get_best_amr_modes(s15_s0, true)); + * + * Determine a GSM 04.08 AMR configuration struct from a set of speech codec * configuration bits (S0-S15) * \param[out] cfg AMR configuration in GSM 04.08 format. * \param[in] s15_s0 configuration bits (S15-S0, non-ambiguous). |