Change in osmo-bsc[master]: codec_pref: move match_codec_pref() to separate c-file and add unit-test

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Harald Welte gerrit-no-reply at lists.osmocom.org
Sun Jul 22 06:16:11 UTC 2018


Harald Welte has submitted this change and it was merged. ( https://gerrit.osmocom.org/10010 )

Change subject: codec_pref: move match_codec_pref() to separate c-file and add unit-test
......................................................................

codec_pref: move match_codec_pref() to separate c-file and add unit-test

At the moment there are three sources that may advertise a list of
supported audio codec/rate settings. There is the MS that advertises
advertises a speech codec list and the MSC that sends a channel type
information element over A and there are also settings in the bsc
configuration file that may restrict the codec/rate types that are
allowed to use.

The function match_codec_pref() looks at all of the three buckets and
selects a codec that satisfies all three. This is already a somewhat
complicated process, overit is very isolated, so lets give it its own
c-file.

Due to the lack of unit-tests it is very hard to make changes here so
lets add also unit-test to make sure that regressions are catched early.

- Put match_codec_pref() and all its helper functions into a separate
  c-file.
- Add a unit test.

Change-Id: Iabedfdcec8b99a319f2d57cbea45c5e36c7b6e29
Related: OS#3361
---
M configure.ac
M include/osmocom/bsc/Makefile.am
A include/osmocom/bsc/codec_pref.h
M src/osmo-bsc/Makefile.am
A src/osmo-bsc/codec_pref.c
M src/osmo-bsc/osmo_bsc_bssap.c
M tests/Makefile.am
A tests/codec_pref/Makefile.am
A tests/codec_pref/codec_pref_test.c
A tests/codec_pref/codec_pref_test.ok
M tests/testsuite.at
11 files changed, 1,431 insertions(+), 160 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/configure.ac b/configure.ac
index 25bcad7..a99e143 100644
--- a/configure.ac
+++ b/configure.ac
@@ -176,6 +176,7 @@
     tests/atlocal
     tests/gsm0408/Makefile
     tests/bsc/Makefile
+    tests/codec_pref/Makefile
     tests/abis/Makefile
     tests/subscr/Makefile
     tests/nanobts_omlattr/Makefile
diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am
index 5fa39eb..dfab592 100644
--- a/include/osmocom/bsc/Makefile.am
+++ b/include/osmocom/bsc/Makefile.am
@@ -12,6 +12,7 @@
 	bss.h \
 	bts_ipaccess_nanobts_omlattr.h \
 	chan_alloc.h \
+	codec_pref.h \
 	ctrl.h \
 	debug.h \
 	e1_config.h \
diff --git a/include/osmocom/bsc/codec_pref.h b/include/osmocom/bsc/codec_pref.h
new file mode 100644
index 0000000..6933cea
--- /dev/null
+++ b/include/osmocom/bsc/codec_pref.h
@@ -0,0 +1,6 @@
+#pragma once
+
+int match_codec_pref(int *full_rate, enum gsm48_chan_mode *chan_mode,
+		     const struct gsm0808_channel_type *ct,
+		     const struct gsm0808_speech_codec_list *scl,
+		     const struct bsc_msc_data *msc);
diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am
index a459a92..db63a99 100644
--- a/src/osmo-bsc/Makefile.am
+++ b/src/osmo-bsc/Makefile.am
@@ -53,6 +53,7 @@
 	bts_sysmobts.c \
 	bts_unknown.c \
 	chan_alloc.c \
+	codec_pref.c \
 	e1_config.c \
 	gsm_04_08_utils.c \
 	gsm_04_80_utils.c \
diff --git a/src/osmo-bsc/codec_pref.c b/src/osmo-bsc/codec_pref.c
new file mode 100644
index 0000000..ee0760a
--- /dev/null
+++ b/src/osmo-bsc/codec_pref.c
@@ -0,0 +1,175 @@
+/*
+ * (C) 2017-2018 by sysmocom s.f.m.c. GmbH <info at sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/gsm0808_utils.h>
+#include <osmocom/bsc/bsc_msc_data.h>
+#include <osmocom/bsc/codec_pref.h>
+
+/* Helper function for match_codec_pref(), looks up a matching chan mode for
+ * a given permitted speech value */
+enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech)
+{
+	switch (speech) {
+	case GSM0808_PERM_HR1:
+	case GSM0808_PERM_FR1:
+		return GSM48_CMODE_SPEECH_V1;
+		break;
+	case GSM0808_PERM_HR2:
+	case GSM0808_PERM_FR2:
+		return GSM48_CMODE_SPEECH_EFR;
+		break;
+	case GSM0808_PERM_HR3:
+	case GSM0808_PERM_FR3:
+		return GSM48_CMODE_SPEECH_AMR;
+		break;
+	default:
+		LOGP(DMSC, LOGL_FATAL, "Unsupported permitted speech selected, assuming AMR as channel mode...\n");
+		return GSM48_CMODE_SPEECH_AMR;
+	}
+}
+
+/* Helper function for match_codec_pref(), looks up a matching permitted speech
+ * value for a given msc audio codec pref */
+enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support *audio)
+{
+	if (audio->hr) {
+		switch (audio->ver) {
+		case 1:
+			return GSM0808_PERM_HR1;
+			break;
+		case 2:
+			return GSM0808_PERM_HR2;
+			break;
+		case 3:
+			return GSM0808_PERM_HR3;
+			break;
+		default:
+			LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: hr%d, using hr1 instead\n", audio->ver);
+			return GSM0808_PERM_HR1;
+		}
+	} else {
+		switch (audio->ver) {
+		case 1:
+			return GSM0808_PERM_FR1;
+			break;
+		case 2:
+			return GSM0808_PERM_FR2;
+			break;
+		case 3:
+			return GSM0808_PERM_FR3;
+			break;
+		default:
+			LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: fr%d, using fr1 instead\n", audio->ver);
+			return GSM0808_PERM_FR1;
+		}
+	}
+}
+
+/* Helper function for match_codec_pref(), tests if a given audio support
+ * matches one of the permitted speech settings of the channel type element.
+ * The matched permitted speech value is then also compared against the
+ * speech codec list. (optional, only relevant for AoIP) */
+static bool test_codec_pref(const struct gsm0808_channel_type *ct,
+			    const struct gsm0808_speech_codec_list *scl, uint8_t perm_spch)
+{
+	unsigned int i;
+	bool match = false;
+	struct gsm0808_speech_codec sc;
+	int rc;
+
+	/* Try to find the given permitted speech value in the
+	 * codec list of the channel type element */
+	for (i = 0; i < ct->perm_spch_len; i++) {
+		if (ct->perm_spch[i] == perm_spch) {
+			match = true;
+			break;
+		}
+	}
+
+	/* If we do not have a speech codec list to test against,
+	 * we just exit early (will be always the case in non-AoIP networks) */
+	if (!scl)
+		return match;
+
+	/* If we failed to match until here, there is no
+	 * point in testing further */
+	if (match == false)
+		return false;
+
+	/* Extrapolate speech codec data */
+	rc = gsm0808_speech_codec_from_chan_type(&sc, perm_spch);
+	if (rc < 0)
+		return false;
+
+	/* Try to find extrapolated speech codec data in
+	 * the speech codec list */
+	for (i = 0; i < scl->len; i++) {
+		if (sc.type == scl->codec[i].type)
+			return true;
+	}
+
+	return false;
+}
+
+/*! Helper function for bssmap_handle_assignm_req(), matches the codec
+ *  preferences from the MSC with the codec preferences
+ *  \param[out] full_rate '1' if full-rate, '0' if half-rate, '-1' if no match
+ *  \param[out] chan_mode GSM 04.08 channel mode
+ *  \param[in] ct GSM 08.08 channel type
+ *  \param[in] scl GSM 08.08 speech codec list
+ *  \param[in] msc MSC data [for configuration]
+ *  \returns 0 on success, -1 in case no match was found */
+int match_codec_pref(int *full_rate, enum gsm48_chan_mode *chan_mode,
+		     const struct gsm0808_channel_type *ct,
+		     const struct gsm0808_speech_codec_list *scl, const struct bsc_msc_data *msc)
+{
+	unsigned int i;
+	uint8_t perm_spch;
+	bool match = false;
+
+	for (i = 0; i < msc->audio_length; i++) {
+		perm_spch = audio_support_to_gsm88(msc->audio_support[i]);
+		if (test_codec_pref(ct, scl, perm_spch)) {
+			match = true;
+			break;
+		}
+	}
+
+	/* Exit without result, in case no match can be deteched */
+	if (!match) {
+		*full_rate = -1;
+		*chan_mode = GSM48_CMODE_SIGN;
+		return -1;
+	}
+
+	/* Check if the result is a half or full rate codec */
+	if (perm_spch == GSM0808_PERM_HR1 || perm_spch == GSM0808_PERM_HR2 || perm_spch == GSM0808_PERM_HR3
+	    || perm_spch == GSM0808_PERM_HR4 || perm_spch == GSM0808_PERM_HR6)
+		*full_rate = 0;
+	else
+		*full_rate = 1;
+
+	/* Lookup a channel mode for the selected codec */
+	*chan_mode = gsm88_to_chan_mode(perm_spch);
+
+	return 0;
+}
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index c2d51b5..96cc2c5 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -22,17 +22,13 @@
 #include <osmocom/bsc/osmo_bsc.h>
 #include <osmocom/bsc/osmo_bsc_grace.h>
 #include <osmocom/bsc/osmo_bsc_rf.h>
-#include <osmocom/bsc/bsc_msc_data.h>
 #include <osmocom/bsc/debug.h>
 #include <osmocom/bsc/bsc_subscriber.h>
 #include <osmocom/bsc/paging.h>
 #include <osmocom/bsc/gsm_04_08_utils.h>
 #include <osmocom/bsc/bsc_subscr_conn_fsm.h>
-
-#include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/bsc/codec_pref.h>
 #include <osmocom/gsm/gsm0808.h>
-#include <osmocom/gsm/gsm0808_utils.h>
-#include <osmocom/gsm/gsm48.h>
 #include <osmocom/bsc/osmo_bsc_sigtran.h>
 #include <osmocom/bsc/osmo_bsc_lcls.h>
 #include <osmocom/bsc/a_reset.h>
@@ -45,161 +41,6 @@
  * helpers for the assignment command
  */
 
-/* Helper function for match_codec_pref(), looks up a matching permitted speech
- * value for a given msc audio codec pref */
-enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support *audio)
-{
-	if (audio->hr) {
-		switch (audio->ver) {
-		case 1:
-			return GSM0808_PERM_HR1;
-			break;
-		case 2:
-			return GSM0808_PERM_HR2;
-			break;
-		case 3:
-			return GSM0808_PERM_HR3;
-			break;
-		default:
-			LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: hr%d, using hr1 instead\n",
-			     audio->ver);
-			return GSM0808_PERM_HR1;
-		}
-	} else {
-		switch (audio->ver) {
-		case 1:
-			return GSM0808_PERM_FR1;
-			break;
-		case 2:
-			return GSM0808_PERM_FR2;
-			break;
-		case 3:
-			return GSM0808_PERM_FR3;
-			break;
-		default:
-			LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: fr%d, using fr1 instead\n",
-			     audio->ver);
-			return GSM0808_PERM_FR1;
-		}
-	}
-}
-
-/* Helper function for match_codec_pref(), looks up a matching chan mode for
- * a given permitted speech value */
-enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech)
-{
-	switch (speech) {
-	case GSM0808_PERM_HR1:
-	case GSM0808_PERM_FR1:
-		return GSM48_CMODE_SPEECH_V1;
-		break;
-	case GSM0808_PERM_HR2:
-	case GSM0808_PERM_FR2:
-		return GSM48_CMODE_SPEECH_EFR;
-		break;
-	case GSM0808_PERM_HR3:
-	case GSM0808_PERM_FR3:
-		return GSM48_CMODE_SPEECH_AMR;
-		break;
-	default:
-		LOGP(DMSC, LOGL_FATAL,
-		     "Unsupported permitted speech selected, assuming AMR as channel mode...\n");
-		return GSM48_CMODE_SPEECH_AMR;
-	}
-}
-
-/* Helper function for match_codec_pref(), tests if a given audio support
- * matches one of the permitted speech settings of the channel type element.
- * The matched permitted speech value is then also compared against the
- * speech codec list. (optional, only relevant for AoIP) */
-static bool test_codec_pref(const struct gsm0808_channel_type *ct,
-			    const struct gsm0808_speech_codec_list *scl,
-			    uint8_t perm_spch)
-{
-	unsigned int i;
-	bool match = false;
-	struct gsm0808_speech_codec sc;
-	int rc;
-
-	/* Try to finde the given permitted speech value in the
-	 * codec list of the channel type element */
-	for (i = 0; i < ct->perm_spch_len; i++) {
-		if (ct->perm_spch[i] == perm_spch) {
-			match = true;
-			break;
-		}
-	}
-
-	/* If we do not have a speech codec list to test against,
-	 * we just exit early (will be always the case in non-AoIP networks) */
-	if (!scl)
-		return match;
-
-	/* If we failed to match until here, there is no
-	 * point in testing further */
-	if (match == false)
-		return false;
-
-	/* Extrapolate speech codec data */
-	rc = gsm0808_speech_codec_from_chan_type(&sc, perm_spch);
-	if (rc < 0)
-		return false;
-
-	/* Try to find extrapolated speech codec data in
-	 * the speech codec list */
-	for (i = 0; i < scl->len; i++) {
-		if (sc.type == scl->codec[i].type)
-			return true;
-	}
-
-	return false;
-}
-
-/*! Helper function for bssmap_handle_assignm_req(), matches the codec
- *  preferences from the MSC with the codec preferences
- *  \param[out] full_rate '1' if full-rate, '0' if half-rate, '-1' if no match
- *  \param[out] chan_mode GSM 04.08 channel mode
- *  \param[in] ct GSM 08.08 channel type
- *  \param[in] scl GSM 08.08 speech codec list
- *  \param[in] msc MSC data [for configuration]
- *  \returns 0 on success, -1 in case no match was found */
-static int match_codec_pref(int *full_rate, enum gsm48_chan_mode *chan_mode,
-			    const struct gsm0808_channel_type *ct,
-			    const struct gsm0808_speech_codec_list *scl,
-			    const struct bsc_msc_data *msc)
-{
-	unsigned int i;
-	uint8_t perm_spch;
-	bool match = false;
-
-	for (i = 0; i < msc->audio_length; i++) {
-		perm_spch = audio_support_to_gsm88(msc->audio_support[i]);
-		if (test_codec_pref(ct, scl, perm_spch)) {
-			match = true;
-			break;
-		}
-	}
-
-	/* Exit without result, in case no match can be deteched */
-	if (!match) {
-		*full_rate = -1;
-		*chan_mode = GSM48_CMODE_SIGN;
-		return -1;
-	}
-
-	/* Check if the result is a half or full rate codec */
-	if (perm_spch == GSM0808_PERM_HR1 || perm_spch == GSM0808_PERM_HR2
-	    || perm_spch == GSM0808_PERM_HR3 || perm_spch == GSM0808_PERM_HR4
-	    || perm_spch == GSM0808_PERM_HR6)
-		*full_rate = 0;
-	else
-		*full_rate = 1;
-
-	/* Lookup a channel mode for the selected codec */
-	*chan_mode = gsm88_to_chan_mode(perm_spch);
-
-	return 0;
-}
 
 static int bssmap_handle_reset_ack(struct bsc_msc_data *msc,
 				   struct msgb *msg, unsigned int length)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 95d836b..9b4cfe4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,5 +1,6 @@
 SUBDIRS = \
 	bsc \
+	codec_pref \
 	gsm0408 \
 	abis \
 	subscr \
diff --git a/tests/codec_pref/Makefile.am b/tests/codec_pref/Makefile.am
new file mode 100644
index 0000000..e000252
--- /dev/null
+++ b/tests/codec_pref/Makefile.am
@@ -0,0 +1,34 @@
+AM_CPPFLAGS = \
+	$(all_includes) \
+	-I$(top_srcdir)/include \
+	$(NULL)
+
+AM_CFLAGS = \
+	-Wall \
+	$(LIBOSMOCORE_CFLAGS) \
+	$(LIBOSMOGSM_CFLAGS) \
+	$(LIBOSMOABIS_CFLAGS) \
+	$(LIBOSMOSIGTRAN_CFLAGS) \
+	$(NULL)
+
+AM_LDFLAGS = \
+	$(NULL)
+
+EXTRA_DIST = \
+	codec_pref_test.ok \
+	$(NULL)
+
+noinst_PROGRAMS = \
+	codec_pref_test \
+	$(NULL)
+
+codec_pref_test_SOURCES = \
+	codec_pref_test.c \
+	$(NULL)
+
+codec_pref_test_LDADD = \
+	$(top_builddir)/src/osmo-bsc/codec_pref.o \
+	$(LIBOSMOCORE_LIBS) \
+	$(LIBOSMOGSM_LIBS) \
+	-lrt \
+	$(NULL)
diff --git a/tests/codec_pref/codec_pref_test.c b/tests/codec_pref/codec_pref_test.c
new file mode 100644
index 0000000..73547ad
--- /dev/null
+++ b/tests/codec_pref/codec_pref_test.c
@@ -0,0 +1,498 @@
+/*
+ * (C) 2018 by sysmocom s.f.m.c. GmbH <info at sysmocom.de>
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/bsc/osmo_bsc.h>
+#include <osmocom/bsc/bsc_msc_data.h>
+#include <osmocom/bsc/gsm_04_80.h>
+#include <osmocom/core/application.h>
+#include <osmocom/bsc/codec_pref.h>
+
+#include <stdio.h>
+
+void *ctx = NULL;
+
+#define MSC_AUDIO_SUPPORT_MAX 5
+#define N_CONFIG_VARIANTS 9
+
+/* Make sure that there is some memory to put our test configuration. */
+static void init_msc_config(struct bsc_msc_data *msc)
+{
+	unsigned int i;
+
+	msc->audio_support = talloc_zero_array(ctx, struct gsm_audio_support *, MSC_AUDIO_SUPPORT_MAX);
+	msc->audio_length = MSC_AUDIO_SUPPORT_MAX;
+	for (i = 0; i < MSC_AUDIO_SUPPORT_MAX; i++) {
+		msc->audio_support[i] = talloc_zero(msc->audio_support, struct gsm_audio_support);
+	}
+}
+
+/* Free memory that we have used for the test configuration. */
+static void free_msc_config(struct bsc_msc_data *msc)
+{
+	talloc_free(msc->audio_support);
+}
+
+/* The speech codec list is sent by the MS and lists the voice codec settings
+ * that the MS is able to support. The BSC must select one of this codecs
+ * depending on what the MSC is able to support. The following function
+ * generates some realistically made up speech codec lists. */
+static void make_scl_config(struct gsm0808_speech_codec_list *scl, uint8_t config_no)
+{
+	OSMO_ASSERT(config_no < N_CONFIG_VARIANTS);
+
+	switch (config_no) {
+	case 0:
+		/* FR1 only */
+		scl->codec[0].type = GSM0808_SCT_FR1;
+		scl->len = 1;
+		break;
+	case 1:
+		/* HR1 only */
+		scl->codec[0].type = GSM0808_SCT_HR1;
+		scl->len = 1;
+		break;
+	case 2:
+		/* FR2 only */
+		scl->codec[0].type = GSM0808_SCT_FR2;
+		scl->len = 1;
+		break;
+	case 3:
+		/* FR3 only */
+		scl->codec[0].type = GSM0808_SCT_FR3;
+		scl->len = 1;
+		break;
+	case 4:
+		/* HR3 only */
+		scl->codec[0].type = GSM0808_SCT_HR3;
+		scl->len = 1;
+		break;
+	case 5:
+		/* FR1 and HR1 */
+		scl->codec[0].type = GSM0808_SCT_FR1;
+		scl->codec[1].type = GSM0808_SCT_HR1;
+		scl->len = 2;
+		break;
+	case 6:
+		/* FR1, FR2 and HR1 */
+		scl->codec[0].type = GSM0808_SCT_FR1;
+		scl->codec[1].type = GSM0808_SCT_FR2;
+		scl->codec[2].type = GSM0808_SCT_HR1;
+		scl->len = 3;
+		break;
+	case 7:
+		/* FR1, FR3 and HR3 */
+		scl->codec[0].type = GSM0808_SCT_FR1;
+		scl->codec[1].type = GSM0808_SCT_FR3;
+		scl->codec[2].type = GSM0808_SCT_HR3;
+		scl->len = 3;
+		break;
+	case 8:
+		/* FR1, FR2, FR3, HR1 and HR3 */
+		scl->codec[0].type = GSM0808_SCT_FR1;
+		scl->codec[1].type = GSM0808_SCT_FR2;
+		scl->codec[2].type = GSM0808_SCT_FR3;
+		scl->codec[3].type = GSM0808_SCT_HR1;
+		scl->codec[4].type = GSM0808_SCT_HR3;
+		scl->len = 5;
+		break;
+	}
+}
+
+/* The channel type element which is sent to the BSC by the MSC lists all the
+ * codecs that the MSC is able to support. The following function generates
+ * a realistic permitted speech settings */
+static void make_ct_config(struct gsm0808_channel_type *ct, uint8_t config_no)
+{
+	OSMO_ASSERT(config_no < N_CONFIG_VARIANTS);
+
+	switch (config_no) {
+	case 0:
+		/* FR1 only */
+		ct->perm_spch[0] = GSM0808_PERM_FR1;
+		ct->perm_spch_len = 1;
+		break;
+	case 1:
+		/* HR1 only */
+		ct->perm_spch[0] = GSM0808_PERM_HR1;
+		ct->perm_spch_len = 1;
+		break;
+	case 2:
+		/* FR2 only */
+		ct->perm_spch[0] = GSM0808_PERM_FR2;
+		ct->perm_spch_len = 1;
+		break;
+	case 3:
+		/* FR3 only */
+		ct->perm_spch[0] = GSM0808_PERM_FR3;
+		ct->perm_spch_len = 1;
+		break;
+	case 4:
+		/* HR3 only */
+		ct->perm_spch[0] = GSM0808_PERM_HR3;
+		ct->perm_spch_len = 1;
+		break;
+	case 5:
+		/* FR1 and HR1 */
+		ct->perm_spch[0] = GSM0808_PERM_FR1;
+		ct->perm_spch[1] = GSM0808_PERM_HR1;
+		ct->perm_spch_len = 2;
+		break;
+	case 6:
+		/* FR1, FR2 and HR1 */
+		ct->perm_spch[0] = GSM0808_PERM_FR1;
+		ct->perm_spch[1] = GSM0808_PERM_FR2;
+		ct->perm_spch[2] = GSM0808_PERM_HR1;
+		ct->perm_spch_len = 3;
+		break;
+	case 7:
+		/* FR1, FR3 and HR3 */
+		ct->perm_spch[0] = GSM0808_PERM_FR1;
+		ct->perm_spch[1] = GSM0808_PERM_FR3;
+		ct->perm_spch[2] = GSM0808_PERM_HR3;
+		ct->perm_spch_len = 3;
+		break;
+	case 8:
+		/* FR1, FR2, FR3, HR1 and HR3 */
+		ct->perm_spch[0] = GSM0808_PERM_FR1;
+		ct->perm_spch[1] = GSM0808_PERM_FR2;
+		ct->perm_spch[2] = GSM0808_PERM_FR3;
+		ct->perm_spch[3] = GSM0808_PERM_HR1;
+		ct->perm_spch[4] = GSM0808_PERM_HR3;
+		ct->perm_spch_len = 5;
+		break;
+	}
+}
+
+/* Generate some realistic MSC configuration which one also could find in the
+ * real world. This configuration acts as a filter. While the MSC could in
+ * theory advertise codecs more codecs as we are able to support we have to
+ * make sure that only the codecs we have support for are considered. */
+static void make_msc_config(struct bsc_msc_data *msc, uint8_t config_no)
+{
+	/* 1 = FR1/HR1
+	 * 2 = FR2/HR2
+	 * 3 = FR2/HR3
+	 * Note: HR2 is deprecated */
+
+	OSMO_ASSERT(config_no < N_CONFIG_VARIANTS);
+
+	switch (config_no) {
+	case 0:
+		/* FR1 only */
+		msc->audio_support[0]->ver = 1;
+		msc->audio_support[0]->hr = 0;
+		msc->audio_length = 1;
+		break;
+	case 1:
+		/* HR1 only */
+		msc->audio_support[0]->ver = 1;
+		msc->audio_support[0]->hr = 1;
+		msc->audio_length = 1;
+		break;
+	case 2:
+		/* FR2 only */
+		msc->audio_support[0]->ver = 2;
+		msc->audio_support[0]->hr = 0;
+		msc->audio_length = 1;
+		break;
+	case 3:
+		/* FR3 only */
+		msc->audio_support[0]->ver = 3;
+		msc->audio_support[0]->hr = 0;
+		msc->audio_length = 1;
+		break;
+	case 4:
+		/* HR3 only */
+		msc->audio_support[0]->ver = 3;
+		msc->audio_support[0]->hr = 1;
+		msc->audio_length = 1;
+		break;
+	case 5:
+		/* FR1 and HR1 */
+		msc->audio_support[0]->ver = 1;
+		msc->audio_support[0]->hr = 0;
+		msc->audio_support[1]->ver = 1;
+		msc->audio_support[1]->hr = 1;
+		msc->audio_length = 2;
+		break;
+	case 6:
+		/* FR1, FR2 and HR1 */
+		msc->audio_support[0]->ver = 1;
+		msc->audio_support[0]->hr = 0;
+		msc->audio_support[1]->ver = 2;
+		msc->audio_support[1]->hr = 0;
+		msc->audio_support[2]->ver = 1;
+		msc->audio_support[2]->hr = 1;
+		msc->audio_length = 3;
+		break;
+	case 7:
+		/* FR1, FR3 and HR3 */
+		msc->audio_support[0]->ver = 1;
+		msc->audio_support[0]->hr = 0;
+		msc->audio_support[1]->ver = 3;
+		msc->audio_support[1]->hr = 0;
+		msc->audio_support[2]->ver = 3;
+		msc->audio_support[2]->hr = 1;
+		msc->audio_length = 3;
+		break;
+	case 8:
+		/* FR1, FR2, FR3, HR1 and HR3 */
+		msc->audio_support[0]->ver = 1;
+		msc->audio_support[0]->hr = 0;
+		msc->audio_support[1]->ver = 2;
+		msc->audio_support[1]->hr = 0;
+		msc->audio_support[2]->ver = 3;
+		msc->audio_support[2]->hr = 0;
+		msc->audio_support[3]->ver = 1;
+		msc->audio_support[3]->hr = 1;
+		msc->audio_support[4]->ver = 3;
+		msc->audio_support[4]->hr = 1;
+		msc->audio_length = 5;
+		break;
+	}
+}
+
+/* Try execute match_codec_pref(), display input and output parameters */
+static int test_match_codec_pref(const struct gsm0808_channel_type *ct,
+				 const struct gsm0808_speech_codec_list *scl, const struct bsc_msc_data *msc)
+{
+	int rc;
+	unsigned int i;
+	int full_rate;
+	enum gsm48_chan_mode chan_mode;
+
+	printf("Determining channel mode and rate:\n");
+
+	printf(" * MS: speech codec list (%u items):\n", scl->len);
+	for (i = 0; i < scl->len; i++)
+		printf("   codec[%u]->type=%s\n", i, gsm0808_speech_codec_type_name(scl->codec[i].type));
+
+	printf(" * MSC: channel type permitted speech (%u items):\n", ct->perm_spch_len);
+	for (i = 0; i < ct->perm_spch_len; i++)
+		printf("   perm_spch[%u]=%s\n", i, gsm0808_permitted_speech_name(ct->perm_spch[i]));
+
+	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);
+
+	rc = match_codec_pref(&full_rate, &chan_mode, ct, scl, msc);
+	printf(" * result: rc=%i, full_rate=%i, chan_mode=%s\n", rc, full_rate, gsm48_chan_mode_name(chan_mode));
+
+	printf("\n");
+
+	return rc;
+}
+
+/* MS, MSC and local MSC settings are the same */
+static void test_one_to_one(void)
+{
+	unsigned int i;
+	struct gsm0808_channel_type ct_msc;
+	struct gsm0808_speech_codec_list scl_ms;
+	struct bsc_msc_data msc_local;
+	int rc;
+
+	printf("============== test_one_to_one ==============\n\n");
+
+	init_msc_config(&msc_local);
+
+	for (i = 0; i < N_CONFIG_VARIANTS; i++) {
+		make_msc_config(&msc_local, i);
+		make_scl_config(&scl_ms, i);
+		make_ct_config(&ct_msc, i);
+		rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
+		OSMO_ASSERT(rc == 0);
+	}
+
+	free_msc_config(&msc_local);
+}
+
+/* Network supports all combinations, MS varies */
+static void test_ms(void)
+{
+	unsigned int i;
+	struct gsm0808_channel_type ct_msc;
+	struct gsm0808_speech_codec_list scl_ms;
+	struct bsc_msc_data msc_local;
+	int rc;
+
+	printf("============== test_ms ==============\n\n");
+
+	init_msc_config(&msc_local);
+
+	make_msc_config(&msc_local, 8);
+	make_ct_config(&ct_msc, 8);
+	for (i = 0; i < N_CONFIG_VARIANTS; i++) {
+		make_scl_config(&scl_ms, i);
+		rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
+		OSMO_ASSERT(rc == 0);
+	}
+
+	free_msc_config(&msc_local);
+}
+
+/* BSS and MS support all combinations, MSC varies */
+static void test_ct(void)
+{
+	unsigned int i;
+	struct gsm0808_channel_type ct_msc;
+	struct gsm0808_speech_codec_list scl_ms;
+	struct bsc_msc_data msc_local;
+	int rc;
+
+	printf("============== test_ct ==============\n\n");
+
+	init_msc_config(&msc_local);
+
+	make_msc_config(&msc_local, 8);
+	make_scl_config(&scl_ms, 8);
+	for (i = 0; i < N_CONFIG_VARIANTS; i++) {
+		make_ct_config(&ct_msc, i);
+		rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
+		OSMO_ASSERT(rc == 0);
+	}
+
+	free_msc_config(&msc_local);
+}
+
+/* MSC and MS support all combinations, BSS varies */
+static void test_msc(void)
+{
+	unsigned int i;
+	struct gsm0808_channel_type ct_msc;
+	struct gsm0808_speech_codec_list scl_ms;
+	struct bsc_msc_data msc_local;
+	int rc;
+
+	printf("============== test_msc ==============\n\n");
+
+	init_msc_config(&msc_local);
+
+	make_ct_config(&ct_msc, 8);
+	make_scl_config(&scl_ms, 8);
+	for (i = 0; i < N_CONFIG_VARIANTS; i++) {
+		make_msc_config(&msc_local, 8);
+		rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
+		OSMO_ASSERT(rc == 0);
+	}
+
+	free_msc_config(&msc_local);
+}
+
+/* Some mixed configurations that are supposed to work */
+static void test_selected_working(void)
+{
+	struct gsm0808_channel_type ct_msc;
+	struct gsm0808_speech_codec_list scl_ms;
+	struct bsc_msc_data msc_local;
+	int rc;
+
+	printf("============== test_selected_working ==============\n\n");
+
+	init_msc_config(&msc_local);
+
+	make_scl_config(&scl_ms, 6);
+	make_ct_config(&ct_msc, 5);
+	make_msc_config(&msc_local, 7);
+	rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
+	OSMO_ASSERT(rc == 0);
+
+	make_scl_config(&scl_ms, 0);
+	make_ct_config(&ct_msc, 5);
+	make_msc_config(&msc_local, 7);
+	rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
+	OSMO_ASSERT(rc == 0);
+
+	make_scl_config(&scl_ms, 1);
+	make_ct_config(&ct_msc, 5);
+	make_msc_config(&msc_local, 6);
+	rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
+	OSMO_ASSERT(rc == 0);
+
+	free_msc_config(&msc_local);
+}
+
+/* Some mixed configurations that can not work */
+static void test_selected_non_working(void)
+{
+	struct gsm0808_channel_type ct_msc;
+	struct gsm0808_speech_codec_list scl_ms;
+	struct bsc_msc_data msc_local;
+	int rc;
+
+	printf("============== test_selected_non_working ==============\n\n");
+
+	init_msc_config(&msc_local);
+
+	make_scl_config(&scl_ms, 1);
+	make_ct_config(&ct_msc, 5);
+	make_msc_config(&msc_local, 7);
+	rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
+	OSMO_ASSERT(rc == -1);
+
+	make_scl_config(&scl_ms, 1);
+	make_ct_config(&ct_msc, 5);
+	make_msc_config(&msc_local, 7);
+	rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
+	OSMO_ASSERT(rc == -1);
+
+	make_scl_config(&scl_ms, 1);
+	make_ct_config(&ct_msc, 4);
+	make_msc_config(&msc_local, 6);
+	rc = test_match_codec_pref(&ct_msc, &scl_ms, &msc_local);
+	OSMO_ASSERT(rc == -1);
+
+	free_msc_config(&msc_local);
+}
+
+static const struct log_info_cat log_categories[] = {
+	[DMSC] = {
+		  .name = "DMSC",
+		  .description = "Mobile Switching Center",
+		  .enabled = 1,.loglevel = LOGL_NOTICE,
+		  },
+};
+
+static const struct log_info log_info = {
+	.cat = log_categories,
+	.num_cat = ARRAY_SIZE(log_categories),
+};
+
+int main(int argc, char **argv)
+{
+	ctx = talloc_named_const(NULL, 0, "codec_pref_test");
+	msgb_talloc_ctx_init(ctx, 0);
+	osmo_init_logging2(ctx, &log_info);
+
+	test_one_to_one();
+	test_ms();
+	test_ct();
+	test_msc();
+	test_selected_working();
+	test_selected_non_working();
+
+	printf("Testing execution completed.\n");
+	talloc_free(ctx);
+	return 0;
+}
diff --git a/tests/codec_pref/codec_pref_test.ok b/tests/codec_pref/codec_pref_test.ok
new file mode 100644
index 0000000..f97fbb1
--- /dev/null
+++ b/tests/codec_pref/codec_pref_test.ok
@@ -0,0 +1,707 @@
+============== test_one_to_one ==============
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=FR1
+ * MSC: channel type permitted speech (1 items):
+   perm_spch[0]=FR1
+ * BSS: audio support settings (1 items):
+   audio_support[0]=FR1
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=HR1
+ * MSC: channel type permitted speech (1 items):
+   perm_spch[0]=HR1
+ * BSS: audio support settings (1 items):
+   audio_support[0]=HR1
+ * result: rc=0, full_rate=0, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=FR2
+ * MSC: channel type permitted speech (1 items):
+   perm_spch[0]=FR2
+ * BSS: audio support settings (1 items):
+   audio_support[0]=FR2
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_EFR
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=FR3
+ * MSC: channel type permitted speech (1 items):
+   perm_spch[0]=FR3
+ * BSS: audio support settings (1 items):
+   audio_support[0]=FR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_AMR
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=HR3
+ * MSC: channel type permitted speech (1 items):
+   perm_spch[0]=HR3
+ * BSS: audio support settings (1 items):
+   audio_support[0]=HR3
+ * result: rc=0, full_rate=0, chan_mode=SPEECH_AMR
+
+Determining channel mode and rate:
+ * MS: speech codec list (2 items):
+   codec[0]->type=FR1
+   codec[1]->type=HR1
+ * MSC: channel type permitted speech (2 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=HR1
+ * BSS: audio support settings (2 items):
+   audio_support[0]=FR1
+   audio_support[1]=HR1
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (3 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=HR1
+ * MSC: channel type permitted speech (3 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=HR1
+ * BSS: audio support settings (3 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=HR1
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (3 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR3
+   codec[2]->type=HR3
+ * MSC: channel type permitted speech (3 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR3
+   perm_spch[2]=HR3
+ * BSS: audio support settings (3 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR3
+   audio_support[2]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+============== test_ms ==============
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=FR1
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=HR1
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=0, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=FR2
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_EFR
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=FR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_AMR
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=0, chan_mode=SPEECH_AMR
+
+Determining channel mode and rate:
+ * MS: speech codec list (2 items):
+   codec[0]->type=FR1
+   codec[1]->type=HR1
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (3 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=HR1
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (3 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR3
+   codec[2]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+============== test_ct ==============
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (1 items):
+   perm_spch[0]=FR1
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (1 items):
+   perm_spch[0]=HR1
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=0, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (1 items):
+   perm_spch[0]=FR2
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_EFR
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (1 items):
+   perm_spch[0]=FR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_AMR
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (1 items):
+   perm_spch[0]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=0, chan_mode=SPEECH_AMR
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (2 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=HR1
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (3 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=HR1
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (3 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR3
+   perm_spch[2]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+============== test_msc ==============
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (5 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=FR3
+   codec[3]->type=HR1
+   codec[4]->type=HR3
+ * MSC: channel type permitted speech (5 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=FR2
+   perm_spch[2]=FR3
+   perm_spch[3]=HR1
+   perm_spch[4]=HR3
+ * BSS: audio support settings (5 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=FR3
+   audio_support[3]=HR1
+   audio_support[4]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+============== test_selected_working ==============
+
+Determining channel mode and rate:
+ * MS: speech codec list (3 items):
+   codec[0]->type=FR1
+   codec[1]->type=FR2
+   codec[2]->type=HR1
+ * MSC: channel type permitted speech (2 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=HR1
+ * BSS: audio support settings (3 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR3
+   audio_support[2]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=FR1
+ * MSC: channel type permitted speech (2 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=HR1
+ * BSS: audio support settings (3 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR3
+   audio_support[2]=HR3
+ * result: rc=0, full_rate=1, chan_mode=SPEECH_V1
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=HR1
+ * MSC: channel type permitted speech (2 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=HR1
+ * BSS: audio support settings (3 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=HR1
+ * result: rc=0, full_rate=0, chan_mode=SPEECH_V1
+
+============== test_selected_non_working ==============
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=HR1
+ * MSC: channel type permitted speech (2 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=HR1
+ * BSS: audio support settings (3 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR3
+   audio_support[2]=HR3
+ * result: rc=-1, full_rate=-1, chan_mode=SIGNALLING
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=HR1
+ * MSC: channel type permitted speech (2 items):
+   perm_spch[0]=FR1
+   perm_spch[1]=HR1
+ * BSS: audio support settings (3 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR3
+   audio_support[2]=HR3
+ * result: rc=-1, full_rate=-1, chan_mode=SIGNALLING
+
+Determining channel mode and rate:
+ * MS: speech codec list (1 items):
+   codec[0]->type=HR1
+ * MSC: channel type permitted speech (1 items):
+   perm_spch[0]=HR3
+ * BSS: audio support settings (3 items):
+   audio_support[0]=FR1
+   audio_support[1]=FR2
+   audio_support[2]=HR1
+ * result: rc=-1, full_rate=-1, chan_mode=SIGNALLING
+
+Testing execution completed.
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 515ffa0..f384655 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -26,6 +26,12 @@
 AT_CHECK([$abs_top_builddir/tests/bsc/bsc_test], [], [expout], [ignore])
 AT_CLEANUP
 
+AT_SETUP([codec_pref])
+AT_KEYWORDS([codec_pref])
+cat $abs_srcdir/codec_pref/codec_pref_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/codec_pref/codec_pref_test], [], [expout], [ignore])
+AT_CLEANUP
+
 AT_SETUP([nanobts_omlattr])
 AT_KEYWORDS([nanobts_omlattr])
 cat $abs_srcdir/nanobts_omlattr/nanobts_omlattr_test.ok > expout

-- 
To view, visit https://gerrit.osmocom.org/10010
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: Iabedfdcec8b99a319f2d57cbea45c5e36c7b6e29
Gerrit-Change-Number: 10010
Gerrit-PatchSet: 11
Gerrit-Owner: dexter <pmaier at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20180722/57e6b26a/attachment.htm>


More information about the gerrit-log mailing list