aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylvain Munaut <tnt@246tNt.com>2015-12-27 15:05:41 +0100
committerSylvain Munaut <tnt@246tNt.com>2015-12-27 15:44:25 +0100
commitb21bf53788397012f220311af61db8632efa059b (patch)
treec0363512d4a67cfce7dca135d460f9377b694f94
parentcdc548cb0ac79a6eef3903872cc6e73eaf6f59ae (diff)
osmo-nitb support for codec negotiation
The caller's most preferred codec is selected out of the union of codecs, which both parties support. Since codec negotiation is done automatically, there is no need to define codec for TCH/F and TCH/H via VTY anymore.
-rw-r--r--openbsc/include/openbsc/mncc.h4
-rw-r--r--openbsc/src/libmsc/mncc_builtin.c107
2 files changed, 98 insertions, 13 deletions
diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index 10192addd..fd1f2badd 100644
--- a/openbsc/include/openbsc/mncc.h
+++ b/openbsc/include/openbsc/mncc.h
@@ -44,6 +44,10 @@ struct gsm_call {
uint32_t callref;
/* the 'remote' transaction */
uint32_t remote_ref;
+
+ /* the capabilities */
+ uint8_t lchan_type;
+ struct gsm_mncc_bearer_cap bcap;
};
#define MNCC_SETUP_REQ 0x0101
diff --git a/openbsc/src/libmsc/mncc_builtin.c b/openbsc/src/libmsc/mncc_builtin.c
index 77df6fba3..1d27a5204 100644
--- a/openbsc/src/libmsc/mncc_builtin.c
+++ b/openbsc/src/libmsc/mncc_builtin.c
@@ -67,17 +67,60 @@ static struct gsm_call *get_call_ref(uint32_t callref)
uint8_t mncc_codec_for_mode(int lchan_type)
{
- /* FIXME: check codec capabilities of the phone */
-
if (lchan_type != GSM_LCHAN_TCH_H)
return mncc_int.def_codec[0];
else
return mncc_int.def_codec[1];
+
}
-static uint8_t determine_lchan_mode(struct gsm_mncc *setup)
+static void store_bearer_cap(struct gsm_call *call, struct gsm_mncc *mncc)
{
- return mncc_codec_for_mode(setup->lchan_type);
+ call->lchan_type = mncc->lchan_type;
+ memcpy(&call->bcap, &mncc->bearer_cap, sizeof(struct gsm_mncc_bearer_cap));
+}
+
+#define is_speech_ver_tch_h(speech_ver) ((speech_ver & 1) == 1)
+
+#define speech_ver_to_lchan_mode(speech_ver) (((speech_ver & 0xe) << 4) | 1)
+
+static int determine_lchan_mode(struct gsm_call *calling,
+ struct gsm_call *called)
+{
+ int i, j;
+
+ /* FIXME: dynamic channel configuration */
+ if (calling->lchan_type != called->lchan_type) {
+ LOGP(DMNCC, LOGL_NOTICE, "Not equal lchan_types\n");
+ return -ENOTSUP;
+ }
+ if (calling->lchan_type != GSM_LCHAN_TCH_F
+ && calling->lchan_type != GSM_LCHAN_TCH_H) {
+ LOGP(DMNCC, LOGL_NOTICE, "Not TCH lchan_types\n");
+ return -ENOTSUP;
+ }
+
+ /* select best codec, as prefered by the caller and supporte by both. */
+ for (i = 0; calling->bcap.speech_ver[i] >= 0; i++) {
+ /* omit capability of different channel type
+ * FIXME: dynamic channel configuration */
+ if (calling->lchan_type == GSM_LCHAN_TCH_F
+ && is_speech_ver_tch_h(calling->bcap.speech_ver[i]))
+ continue;
+ if (calling->lchan_type == GSM_LCHAN_TCH_H
+ && !is_speech_ver_tch_h(calling->bcap.speech_ver[i]))
+ continue;
+ for (j = 0; called->bcap.speech_ver[j] >= 0; j++) {
+ if (calling->bcap.speech_ver[i]
+ == called->bcap.speech_ver[j]) {
+ /* convert speech version to lchan mode */
+ return speech_ver_to_lchan_mode(
+ calling->bcap.speech_ver[i]);
+ }
+ }
+ }
+
+ return -ENOTSUP;
}
/* on incoming call, look up database and send setup to remote subscr. */
@@ -134,12 +177,8 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type,
DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
mncc_tx_to_cc(call->net, MNCC_CALL_PROC_REQ, &mncc);
- /* modify mode */
- memset(&mncc, 0, sizeof(struct gsm_mncc));
- mncc.callref = call->callref;
- mncc.lchan_mode = determine_lchan_mode(setup);
- DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
- mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
+ /* store bearer capabilites of supported modes */
+ store_bearer_cap(call, setup);
/* send setup to remote */
// setup->fields |= MNCC_F_SIGNAL;
@@ -154,6 +193,50 @@ out_reject:
return 0;
}
+static int mncc_call_conf_ind(struct gsm_call *call, int msg_type,
+ struct gsm_mncc *conf)
+{
+ struct gsm_call *remote;
+ struct gsm_mncc mncc;
+ int mode;
+
+ memset(&mncc, 0, sizeof(struct gsm_mncc));
+ mncc.callref = call->callref;
+
+ /* send alerting to remote */
+ if (!(remote = get_call_ref(call->remote_ref)))
+ return 0;
+
+ /* store bearer capabilites of supported modes */
+ store_bearer_cap(call, conf);
+
+ mode = determine_lchan_mode(call, remote);
+ if (mode < 0) {
+ LOGP(DMNCC, LOGL_NOTICE, "(call %x,%x) There is no commonly "
+ "supported speech version\n", call->callref,
+ remote->callref);
+ mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
+ GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
+ goto out_release;
+ }
+
+ /* modify mode */
+ mncc.lchan_mode = mode;
+ DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
+ mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
+ mncc.callref = remote->callref;
+ DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", remote->callref);
+ mncc_tx_to_cc(remote->net, MNCC_LCHAN_MODIFY, &mncc);
+
+ return 0;
+
+out_release:
+ mncc_tx_to_cc(call->net, MNCC_REL_REQ, &mncc);
+ free_call(call);
+ mncc_tx_to_cc(remote->net, MNCC_REL_REQ, &mncc);
+ free_call(remote);
+ return 0;
+}
static int mncc_alert_ind(struct gsm_call *call, int msg_type,
struct gsm_mncc *alert)
{
@@ -362,9 +445,7 @@ int int_mncc_recv(struct gsm_network *net, struct msgb *msg)
case MNCC_SETUP_COMPL_IND:
break;
case MNCC_CALL_CONF_IND:
- /* we now need to MODIFY the channel */
- data->lchan_mode = determine_lchan_mode(data);
- mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, data);
+ rc = mncc_call_conf_ind(call, msg_type, arg);
break;
case MNCC_ALERT_IND:
rc = mncc_alert_ind(call, msg_type, arg);