codec_pref: Add Codec List to COMPLETE LAYER 3 INFORMATION
The COMPLETE LAYER 3 INFORMATION message lacks the Codec List (BSS Supported) information element. This information element is mandatory for networks that use an IP based user plane (AoIP). - Add function to generate the speech codec list from the current codec settings (Available codecs) - Generate and embed information element in L3 Compl. message Depends: libosmocore I4e656731b16621736c7a2f4e64d9ce63b1064e98 Change-Id: Id6f2af3fdab45bf05f06aec03e222734d7a4cf70 Related: OS#3548
This commit is contained in:
parent
5a43b55a8e
commit
67e47c6076
|
@ -7,6 +7,8 @@ struct gsm0808_channel_type;
|
|||
struct gsm0808_speech_codec_list;
|
||||
struct gsm_audio_support;
|
||||
struct bts_codec_conf;
|
||||
struct bsc_msc_data;
|
||||
struct gsm_bts;
|
||||
|
||||
int match_codec_pref(enum gsm48_chan_mode *chan_mode,
|
||||
bool *full_rate,
|
||||
|
@ -15,3 +17,7 @@ int match_codec_pref(enum gsm48_chan_mode *chan_mode,
|
|||
struct gsm_audio_support * const *audio_support,
|
||||
int audio_length,
|
||||
const struct bts_codec_conf *bts_codec);
|
||||
|
||||
void gen_bss_supported_codec_list(struct gsm0808_speech_codec_list *scl,
|
||||
const struct bsc_msc_data *msc,
|
||||
const struct gsm_bts *bts);
|
||||
|
|
|
@ -242,3 +242,68 @@ int match_codec_pref(enum gsm48_chan_mode *chan_mode,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Determine the BSS supported speech codec list that is sent to the MSC with
|
||||
* the COMPLETE LAYER 3 INFORMATION message.
|
||||
* \param[out] scl GSM 08.08 speech codec list with BSS supported codecs.
|
||||
* \param[in] msc associated msc (current codec settings).
|
||||
* \param[in] bts associated bts (current codec settings). */
|
||||
void gen_bss_supported_codec_list(struct gsm0808_speech_codec_list *scl,
|
||||
const struct bsc_msc_data *msc, const struct gsm_bts *bts)
|
||||
{
|
||||
uint8_t perm_spch;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
uint16_t amr_s15_s0_bts;
|
||||
uint16_t amr_s15_s0_msc;
|
||||
uint16_t amr_s15_s0;
|
||||
const struct gsm48_multi_rate_conf *amr_cfg_bts;
|
||||
const struct gsm48_multi_rate_conf *amr_cfg_msc;
|
||||
|
||||
memset(scl, 0, sizeof(*scl));
|
||||
|
||||
for (i = 0; i < msc->audio_length; i++) {
|
||||
|
||||
/* Pick a permitted speech value from the global codec configuration list */
|
||||
perm_spch = audio_support_to_gsm88(msc->audio_support[i]);
|
||||
|
||||
/* Check this permitted speech value against the BTS specific parameters.
|
||||
* if the BTS does not support the codec, try the next one */
|
||||
if (!test_codec_support_bts(&bts->codec, perm_spch))
|
||||
continue;
|
||||
|
||||
/* Write item into codec list */
|
||||
rc = gsm0808_speech_codec_from_chan_type(&scl->codec[scl->len], perm_spch);
|
||||
if (rc != 0)
|
||||
continue;
|
||||
|
||||
/* AMR (HR/FR version 3) is the only codec that requires a codec
|
||||
* configuration (S0-S15). Determine the current configuration and update
|
||||
* the cfg flag. */
|
||||
if (msc->audio_support[i]->ver == 3) {
|
||||
|
||||
/* First lookup the BTS specific AMR rate configuration. Thsi config
|
||||
* is set via the VTY for each BTS individually. In cases where no
|
||||
* configuration is set we will assume a safe default */
|
||||
if (msc->audio_support[i]->hr) {
|
||||
amr_cfg_bts = (struct gsm48_multi_rate_conf *)&bts->mr_half.gsm48_ie;
|
||||
amr_s15_s0_bts = gsm0808_sc_cfg_from_gsm48_mr_cfg(amr_cfg_bts, false);
|
||||
} else {
|
||||
amr_cfg_bts = (struct gsm48_multi_rate_conf *)&bts->mr_full.gsm48_ie;
|
||||
amr_s15_s0_bts = gsm0808_sc_cfg_from_gsm48_mr_cfg(amr_cfg_bts, true);
|
||||
}
|
||||
|
||||
/* At next, lookup the AMR rate configuration that is set for the MSC */
|
||||
amr_cfg_msc = &msc->amr_conf;
|
||||
amr_s15_s0_msc = gsm0808_sc_cfg_from_gsm48_mr_cfg(amr_cfg_msc, true);
|
||||
|
||||
/* Calculate the intersection of the two configurations and update S0-S15
|
||||
* in the codec list. */
|
||||
amr_s15_s0 = amr_s15_s0_bts & amr_s15_s0_msc;
|
||||
scl->codec[scl->len].cfg = amr_s15_s0;
|
||||
}
|
||||
|
||||
scl->len++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <osmocom/bsc/debug.h>
|
||||
#include <osmocom/bsc/paging.h>
|
||||
#include <osmocom/bsc/gsm_08_08.h>
|
||||
#include <osmocom/bsc/codec_pref.h>
|
||||
|
||||
#include <osmocom/bsc/gsm_04_80.h>
|
||||
#include <osmocom/bsc/gsm_04_08_rr.h>
|
||||
|
@ -446,6 +447,7 @@ static bool complete_layer3(struct gsm_subscriber_connection *conn,
|
|||
char *imsi = NULL;
|
||||
struct msgb *resp;
|
||||
enum bsc_con ret;
|
||||
struct gsm0808_speech_codec_list scl;
|
||||
|
||||
/* Check the filter */
|
||||
rc = bsc_filter_initial(msc->network->bsc_data, msc, conn, msg,
|
||||
|
@ -491,7 +493,12 @@ static bool complete_layer3(struct gsm_subscriber_connection *conn,
|
|||
|
||||
bsc_scan_bts_msg(conn, msg);
|
||||
|
||||
resp = gsm0808_create_layer3_2(msg, cgi_for_msc(conn->sccp.msc, conn_get_bts(conn)), NULL);
|
||||
if (gscon_is_aoip(conn)) {
|
||||
gen_bss_supported_codec_list(&scl, msc, conn_get_bts(conn));
|
||||
resp = gsm0808_create_layer3_2(msg, cgi_for_msc(conn->sccp.msc, conn_get_bts(conn)), &scl);
|
||||
} else
|
||||
resp = gsm0808_create_layer3_2(msg, cgi_for_msc(conn->sccp.msc, conn_get_bts(conn)), NULL);
|
||||
|
||||
if (!resp) {
|
||||
LOGP(DMSC, LOGL_DEBUG, "Failed to create layer3 message.\n");
|
||||
return false;
|
||||
|
|
|
@ -201,6 +201,17 @@ static void make_msc_config(struct bsc_msc_data *msc, uint8_t config_no)
|
|||
|
||||
OSMO_ASSERT(config_no < N_CONFIG_VARIANTS);
|
||||
|
||||
/* Setup an AMR configuration, this configuration is separate and does
|
||||
* not influence other codecs than AMR */
|
||||
msc->amr_conf.m4_75 = 1;
|
||||
msc->amr_conf.m5_15 = 1;
|
||||
msc->amr_conf.m5_90 = 1;
|
||||
msc->amr_conf.m6_70 = 1;
|
||||
msc->amr_conf.m7_40 = 1;
|
||||
msc->amr_conf.m7_95 = 1;
|
||||
msc->amr_conf.m10_2 = 1;
|
||||
msc->amr_conf.m12_2 = 1;
|
||||
|
||||
switch (config_no) {
|
||||
case 0:
|
||||
/* FR1 only */
|
||||
|
@ -282,11 +293,36 @@ static void make_bts_config(struct gsm_bts *bts, uint8_t config_no)
|
|||
{
|
||||
/* Note: FR is supported by all BTSs, so there is no flag for it */
|
||||
|
||||
struct gsm48_multi_rate_conf *cfg;
|
||||
|
||||
OSMO_ASSERT(config_no < N_CONFIG_VARIANTS);
|
||||
|
||||
bts->codec.hr = 0;
|
||||
bts->codec.efr = 0;
|
||||
bts->codec.amr = 0;
|
||||
memset(&bts->mr_full.gsm48_ie, 0, sizeof(bts->mr_full.gsm48_ie));
|
||||
memset(&bts->mr_full.gsm48_ie, 0, sizeof(bts->mr_half.gsm48_ie));
|
||||
|
||||
/* Setup an AMR configuration, this configuration is separate and does
|
||||
* not influence other codecs than AMR */
|
||||
cfg = (struct gsm48_multi_rate_conf*) &bts->mr_full.gsm48_ie;
|
||||
cfg->m4_75 = 1;
|
||||
cfg->m5_15 = 1;
|
||||
cfg->m5_90 = 1;
|
||||
cfg->m6_70 = 1;
|
||||
cfg->m7_40 = 1;
|
||||
cfg->m7_95 = 1;
|
||||
cfg->m10_2 = 1;
|
||||
cfg->m12_2 = 1;
|
||||
cfg = (struct gsm48_multi_rate_conf*) &bts->mr_half.gsm48_ie;
|
||||
cfg->m4_75 = 1;
|
||||
cfg->m5_15 = 1;
|
||||
cfg->m5_90 = 1;
|
||||
cfg->m6_70 = 1;
|
||||
cfg->m7_40 = 1;
|
||||
cfg->m7_95 = 1;
|
||||
cfg->m10_2 = 0;
|
||||
cfg->m12_2 = 0;
|
||||
|
||||
switch (config_no) {
|
||||
case 0:
|
||||
|
@ -590,6 +626,62 @@ static void test_selected_non_working(void)
|
|||
free_msc_config(&msc_local);
|
||||
}
|
||||
|
||||
/* Try execute bss_supp_codec_list(), display input and output parameters */
|
||||
static void test_gen_bss_supported_codec_list(const struct bsc_msc_data *msc, struct gsm_bts *bts)
|
||||
{
|
||||
unsigned int i;
|
||||
struct gsm0808_speech_codec_list scl;
|
||||
|
||||
printf("Determining Codec List (BSS Supported):\n");
|
||||
|
||||
printf(" * BSS: audio support settings (%u items):\n", msc->audio_length);
|
||||
for (i = 0; i < msc->audio_length; i++)
|
||||
if (msc->audio_support[i]->hr)
|
||||
printf(" audio_support[%u]=HR%u\n", i, msc->audio_support[i]->ver);
|
||||
else
|
||||
printf(" audio_support[%u]=FR%u\n", i, msc->audio_support[i]->ver);
|
||||
|
||||
printf(" * BTS: audio support settings:\n");
|
||||
printf(" (GSM-FR implicitly supported)\n");
|
||||
printf(" codec->hr=%u\n", bts->codec.hr);
|
||||
printf(" codec->efr=%u\n", bts->codec.efr);
|
||||
printf(" codec->amr=%u\n", bts->codec.amr);
|
||||
|
||||
gen_bss_supported_codec_list(&scl, msc, bts);
|
||||
|
||||
printf(" * result: speech codec list (%u items):\n", scl.len);
|
||||
for (i = 0; i < scl.len; i++) {
|
||||
printf(" codec[%u]->type=%s", i, gsm0808_speech_codec_type_name(scl.codec[i].type));
|
||||
if (msc->audio_support[i]->ver == 3)
|
||||
printf(" S15-S0=%04x", scl.codec[i].cfg);
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Test gen_bss_supported_codec_list() with some mixed configurations */
|
||||
static void test_gen_bss_supported_codec_list_cfgs(void)
|
||||
{
|
||||
struct bsc_msc_data msc_local;
|
||||
struct gsm_bts bts_local;
|
||||
uint8_t i;
|
||||
uint8_t k;
|
||||
|
||||
printf("============== test_gen_bss_supp_codec_list_cfgs ==============\n\n");
|
||||
init_msc_config(&msc_local);
|
||||
|
||||
for (i = 0; i < N_CONFIG_VARIANTS; i++) {
|
||||
for (k = 0; k < N_CONFIG_VARIANTS; k++) {
|
||||
make_msc_config(&msc_local, i);
|
||||
make_bts_config(&bts_local, k);
|
||||
printf("MSC config: %u, BTS config: %u\n", i, k);
|
||||
test_gen_bss_supported_codec_list(&msc_local, &bts_local);
|
||||
}
|
||||
}
|
||||
|
||||
free_msc_config(&msc_local);
|
||||
}
|
||||
|
||||
static const struct log_info_cat log_categories[] = {
|
||||
[DMSC] = {
|
||||
.name = "DMSC",
|
||||
|
@ -615,6 +707,7 @@ int main(int argc, char **argv)
|
|||
test_msc();
|
||||
test_selected_working();
|
||||
test_selected_non_working();
|
||||
test_gen_bss_supported_codec_list_cfgs();
|
||||
|
||||
printf("Testing execution completed.\n");
|
||||
talloc_free(ctx);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue