aboutsummaryrefslogtreecommitdiffstats
path: root/src/gsm/gsm0808_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gsm/gsm0808_utils.c')
-rw-r--r--src/gsm/gsm0808_utils.c108
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).