diff options
Diffstat (limited to 'src/common/amr.c')
-rw-r--r-- | src/common/amr.c | 142 |
1 files changed, 125 insertions, 17 deletions
diff --git a/src/common/amr.c b/src/common/amr.c index 05d1aaac..47c9dcb5 100644 --- a/src/common/amr.c +++ b/src/common/amr.c @@ -6,6 +6,85 @@ #include <osmo-bts/logging.h> #include <osmo-bts/amr.h> +/* Reasonable defaults for AMR-FR and AMR-HR rate configuration. + * The values are taken from 3GPP TS 51.010-1 (version 13.11.0). + * See 14.2.19.4.1 and 14.2.20.4.1 for AMR-FR and AMR-HR, respectively. + * + * ^ C/I (dB) | FR / HR | + * | | + * | | + * MODE4 | | + * = | ----+---- THR_MX_Up(3) | 20.5 / 18.0 | + * | | | + * | = ----+---- THR_MX_Dn(4) | 18.5 / 16.0 | + * MODE3 | | + * | = ----+---- THR_MX_Up(2) | 14.5 / 14.0 | + * | | | + * = | ----+---- THR_MX_Dn(3) | 12.5 / 12.0 | + * MODE2 | | + * = | ----+---- THR_MX_Up(1) | 8.5 / 10.0 | + * | | | + * | = ----+---- THR_MX_Dn(2) | 6.5 / 8.0 | + * MODE1 | | + * | | + * | | + */ +static const struct gsm48_multi_rate_conf amr_fr_mr_cfg_def = { + .m4_75 = 1, + .m5_90 = 1, + .m7_95 = 1, + .m12_2 = 1, +}; +static const struct amr_mode amr_fr_bts_mode_def[] = { + { + .mode = 0, /* 4.75k */ + .threshold = 13, /* THR_MX_Dn(2): 6.5 dB */ + .hysteresis = 4, /* THR_MX_Up(1): 8.5 dB */ + }, + { + .mode = 2, /* 5.90k */ + .threshold = 25, /* THR_MX_Dn(3): 12.5 dB */ + .hysteresis = 4, /* THR_MX_Up(2): 14.5 dB */ + }, + { + .mode = 5, /* 7.95k */ + .threshold = 37, /* THR_MX_Dn(4): 18.5 dB */ + .hysteresis = 4, /* THR_MX_Up(3): 20.5 dB */ + }, + { + .mode = 7, /* 12.2k */ + /* this is the last mode, so no threshold */ + }, +}; + +static const struct gsm48_multi_rate_conf amr_hr_mr_cfg_def = { + .m4_75 = 1, + .m5_90 = 1, + .m6_70 = 1, + .m7_95 = 1, +}; +static const struct amr_mode amr_hr_bts_mode_def[] = { + { + .mode = 0, /* 4.75k */ + .threshold = 16, /* THR_MX_Dn(2): 8.0 dB */ + .hysteresis = 4, /* THR_MX_Up(1): 10.0 dB */ + }, + { + .mode = 2, /* 5.90k */ + .threshold = 24, /* THR_MX_Dn(3): 12.0 dB */ + .hysteresis = 4, /* THR_MX_Up(2): 14.0 dB */ + }, + { + .mode = 3, /* 6.70k */ + .threshold = 32, /* THR_MX_Dn(4): 16.0 dB */ + .hysteresis = 4, /* THR_MX_Up(3): 18.0 dB */ + }, + { + .mode = 5, /* 7.95k */ + /* this is the last mode, so no threshold */ + }, +}; + void amr_log_mr_conf(int ss, int logl, const char *pfx, struct amr_multirate_conf *amr_mrc) { @@ -16,9 +95,9 @@ void amr_log_mr_conf(int ss, int logl, const char *pfx, for (i = 0; i < amr_mrc->num_modes; i++) LOGPC(ss, logl, ", mode[%u] = %u/%u/%u", - i, amr_mrc->bts_mode[i].mode, - amr_mrc->bts_mode[i].threshold, - amr_mrc->bts_mode[i].hysteresis); + i, amr_mrc->mode[i].mode, + amr_mrc->mode[i].threshold, + amr_mrc->mode[i].hysteresis); LOGPC(ss, logl, "\n"); } @@ -27,7 +106,7 @@ static inline int get_amr_mode_idx(const struct amr_multirate_conf *amr_mrc, { unsigned int i; for (i = 0; i < amr_mrc->num_modes; i++) { - if (amr_mrc->bts_mode[i].mode == cmi) + if (amr_mrc->mode[i].mode == cmi) return i; } return -EINVAL; @@ -78,13 +157,16 @@ void amr_set_mode_pref(uint8_t *data, const struct amr_multirate_conf *amr_mrc, int amr_parse_mr_conf(struct amr_multirate_conf *amr_mrc, const uint8_t *mr_conf, unsigned int len) { - uint8_t mr_version = mr_conf[0] >> 5; uint8_t num_codecs = 0; int i, j = 0; - if (mr_version != 1) { - LOGP(DRSL, LOGL_ERROR, "AMR Multirate Version %u unknown\n", - mr_version); + if (len < 2) { + LOGP(DRSL, LOGL_ERROR, "AMR Multirate IE is too short (%u)\n", len); + goto ret_einval; + } + + if ((mr_conf[0] >> 5) != 1) { + LOGP(DRSL, LOGL_ERROR, "AMR Multirate Version %u unknown\n", (mr_conf[0] >> 5)); goto ret_einval; } @@ -114,23 +196,26 @@ int amr_parse_mr_conf(struct amr_multirate_conf *amr_mrc, for (i = 0; i < 8; i++) { if (mr_conf[1] & (1 << i)) { - amr_mrc->bts_mode[j++].mode = i; + amr_mrc->mode[j++].mode = i; } } + /* skip the first two octets of the IE */ + mr_conf += 2; + if (num_codecs >= 2) { - amr_mrc->bts_mode[0].threshold = mr_conf[1] & 0x3F; - amr_mrc->bts_mode[0].hysteresis = mr_conf[2] >> 4; + amr_mrc->mode[0].threshold = mr_conf[0] & 0x3F; + amr_mrc->mode[0].hysteresis = mr_conf[1] >> 4; } if (num_codecs >= 3) { - amr_mrc->bts_mode[1].threshold = - ((mr_conf[2] & 0xF) << 2) | (mr_conf[3] >> 6); - amr_mrc->bts_mode[1].hysteresis = (mr_conf[3] >> 2) & 0xF; + amr_mrc->mode[1].threshold = + ((mr_conf[1] & 0xF) << 2) | (mr_conf[2] >> 6); + amr_mrc->mode[1].hysteresis = (mr_conf[2] >> 2) & 0xF; } if (num_codecs >= 4) { - amr_mrc->bts_mode[2].threshold = - ((mr_conf[3] & 0x3) << 4) | (mr_conf[4] >> 4); - amr_mrc->bts_mode[2].hysteresis = mr_conf[4] & 0xF; + amr_mrc->mode[2].threshold = + ((mr_conf[2] & 0x3) << 4) | (mr_conf[3] >> 4); + amr_mrc->mode[2].hysteresis = mr_conf[3] & 0xF; } return num_codecs; @@ -168,3 +253,26 @@ unsigned int amr_get_initial_mode(struct gsm_lchan *lchan) } } } + +void amr_init_mr_conf_def(struct gsm_lchan *lchan) +{ + const struct gsm48_multi_rate_conf *mr_cfg; + const struct amr_mode *bts_mode; + unsigned int num_modes; + + if (lchan->type == GSM_LCHAN_TCH_F) { + num_modes = ARRAY_SIZE(amr_fr_bts_mode_def); + bts_mode = &amr_fr_bts_mode_def[0]; + mr_cfg = &amr_fr_mr_cfg_def; + } else { + num_modes = ARRAY_SIZE(amr_hr_bts_mode_def); + bts_mode = &amr_hr_bts_mode_def[0]; + mr_cfg = &amr_hr_mr_cfg_def; + } + + memcpy(lchan->tch.amr_mr.gsm48_ie, mr_cfg, + sizeof(lchan->tch.amr_mr.gsm48_ie)); + memcpy(&lchan->tch.amr_mr.mode[0], &bts_mode[0], + sizeof(lchan->tch.amr_mr.mode)); + lchan->tch.amr_mr.num_modes = num_modes; +} |