summaryrefslogtreecommitdiffstats
path: root/src/host/layer23/src
diff options
context:
space:
mode:
authorAndreas.Eversberg <jolly@eversberg.eu>2010-09-26 17:08:10 +0000
committerAndreas.Eversberg <jolly@eversberg.eu>2010-09-26 17:08:10 +0000
commitb0336cd4849a4b0bf963372060de0a467b398a7a (patch)
tree3832a7f29b15372f44795844ecc87416fdc69ecb /src/host/layer23/src
parent602dcf4d0d94ffc7f7f9f3f6865541c385077bcf (diff)
[layer23] Speech codec selection and negotiation with network
Diffstat (limited to 'src/host/layer23/src')
-rw-r--r--src/host/layer23/src/mobile/gsm48_cc.c5
-rw-r--r--src/host/layer23/src/mobile/gsm48_rr.c133
-rw-r--r--src/host/layer23/src/mobile/mnccms.c192
-rw-r--r--src/host/layer23/src/mobile/settings.c4
-rw-r--r--src/host/layer23/src/mobile/support.c7
-rw-r--r--src/host/layer23/src/mobile/vty_interface.c103
6 files changed, 412 insertions, 32 deletions
diff --git a/src/host/layer23/src/mobile/gsm48_cc.c b/src/host/layer23/src/mobile/gsm48_cc.c
index 4b8db53e..a58f627a 100644
--- a/src/host/layer23/src/mobile/gsm48_cc.c
+++ b/src/host/layer23/src/mobile/gsm48_cc.c
@@ -550,9 +550,10 @@ static int gsm48_cc_tx_setup(struct gsm_trans *trans)
*/
gsm48_start_cc_timer(trans, 0x303, GSM48_T303_MS);
- if (!setup->emergency) {
- /* bearer capability */
+ /* bearer capability (optional for emergency calls only) */
+ if (setup->fields & MNCC_F_BEARER_CAP)
gsm48_encode_bearer_cap(nmsg, 0, &setup->bearer_cap);
+ if (!setup->emergency) {
/* facility */
if (setup->fields & MNCC_F_FACILITY)
gsm48_encode_facility(nmsg, 0, &setup->facility);
diff --git a/src/host/layer23/src/mobile/gsm48_rr.c b/src/host/layer23/src/mobile/gsm48_rr.c
index 333b379b..656d4c2b 100644
--- a/src/host/layer23/src/mobile/gsm48_rr.c
+++ b/src/host/layer23/src/mobile/gsm48_rr.c
@@ -86,6 +86,8 @@ static void stop_rr_t3124(struct gsm48_rrlayer *rr);
static int gsm48_rcv_rsl(struct osmocom_ms *ms, struct msgb *msg);
static int gsm48_rr_dl_est(struct osmocom_ms *ms);
static int gsm48_rr_tx_meas_rep(struct osmocom_ms *ms);
+static int gsm48_rr_set_mode(struct osmocom_ms *ms, uint8_t chan_nr,
+ uint8_t mode);
/*
* support
@@ -278,6 +280,79 @@ static int gsm48_apply_v_sd(struct gsm48_rrlayer *rr, struct msgb *msg)
return 0;
}
+/* set channel mode if supported, or return error cause */
+static uint8_t gsm48_rr_check_mode(struct osmocom_ms *ms, uint8_t chan_nr,
+ uint8_t mode)
+{
+ struct gsm_support *sup = &ms->support;
+ uint8_t ch_type, ch_subch, ch_ts;
+
+ /* only complain if we use TCH/F or TCH/H */
+ rsl_dec_chan_nr(chan_nr, &ch_type, &ch_subch, &ch_ts);
+ if (ch_type != RSL_CHAN_Bm_ACCHs
+ && ch_type != RSL_CHAN_Lm_ACCHs)
+ return 0;
+
+ switch (mode) {
+ case GSM48_CMODE_SIGN:
+ LOGP(DRR, LOGL_INFO, "Mode: signalling\n");
+ break;
+ case GSM48_CMODE_SPEECH_V1:
+ if (ch_type == RSL_CHAN_Bm_ACCHs) {
+ if (!sup->full_v1) {
+ LOGP(DRR, LOGL_NOTICE, "Not supporting "
+ "full-rate speech V1\n");
+ return GSM48_RR_CAUSE_CHAN_MODE_UNACCT;
+ }
+ LOGP(DRR, LOGL_INFO, "Mode: full-rate speech V1\n");
+ } else {
+ if (!sup->half_v1) {
+ LOGP(DRR, LOGL_NOTICE, "Not supporting "
+ "half-rate speech V1\n");
+ return GSM48_RR_CAUSE_CHAN_MODE_UNACCT;
+ }
+ LOGP(DRR, LOGL_INFO, "Mode: half-rate speech V1\n");
+ }
+ break;
+ case GSM48_CMODE_SPEECH_EFR:
+ if (ch_type == RSL_CHAN_Bm_ACCHs) {
+ if (!sup->full_v2) {
+ LOGP(DRR, LOGL_NOTICE, "Not supporting "
+ "full-rate speech V2\n");
+ return GSM48_RR_CAUSE_CHAN_MODE_UNACCT;
+ }
+ LOGP(DRR, LOGL_INFO, "Mode: full-rate speech V2\n");
+ } else {
+ LOGP(DRR, LOGL_NOTICE, "Not supporting "
+ "half-rate speech V2\n");
+ return GSM48_RR_CAUSE_CHAN_MODE_UNACCT;
+ }
+ break;
+ case GSM48_CMODE_SPEECH_AMR:
+ if (ch_type == RSL_CHAN_Bm_ACCHs) {
+ if (!sup->full_v3) {
+ LOGP(DRR, LOGL_NOTICE, "Not supporting "
+ "full-rate speech V3\n");
+ return GSM48_RR_CAUSE_CHAN_MODE_UNACCT;
+ }
+ LOGP(DRR, LOGL_INFO, "Mode: full-rate speech V3\n");
+ } else {
+ if (!sup->half_v3) {
+ LOGP(DRR, LOGL_NOTICE, "Not supporting "
+ "half-rate speech V3\n");
+ return GSM48_RR_CAUSE_CHAN_MODE_UNACCT;
+ }
+ LOGP(DRR, LOGL_INFO, "Mode: half-rate speech V3\n");
+ }
+ break;
+ default:
+ LOGP(DRR, LOGL_ERROR, "Mode 0x%02x not supported!\n", mode);
+ return GSM48_RR_CAUSE_CHAN_MODE_UNACCT;
+ }
+
+ return 0;
+}
+
/*
* state transition
*/
@@ -883,7 +958,7 @@ static int gsm48_rr_rx_cip_mode_cmd(struct osmocom_ms *ms, struct msgb *msg)
|| (alg_id == GSM_CIPHER_A5_7 && !sup->a5_7))) {
LOGP(DRR, LOGL_NOTICE, "algo not supported\n");
return gsm48_rr_tx_rr_status(ms,
- GSM48_RR_CAUSE_CHAN_MODE_UNACCT);
+ GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
}
/* check if we have no key */
@@ -3093,7 +3168,8 @@ static int gsm48_rr_activate_channel(struct osmocom_ms *ms,
if (rr->cipher_on)
l1ctl_tx_crypto_req(ms, rr->cipher_type + 1, subscr->key, 8);
-#warning FIXME: channel mode
+
+ gsm48_rr_set_mode(ms, cd->chan_nr, cd->mode);
return 0;
}
@@ -3113,7 +3189,8 @@ static int gsm48_rr_channel_after_time(struct osmocom_ms *ms,
if (rr->cipher_on)
l1ctl_tx_crypto_req(ms, rr->cipher_type + 1, subscr->key, 8);
-#warning FIXME: channel mode
+
+ gsm48_rr_set_mode(ms, cd->chan_nr, cd->mode);
return 0;
}
@@ -3473,6 +3550,25 @@ static int gsm48_rr_rx_chan_rel(struct osmocom_ms *ms, struct msgb *msg)
* frequency redefition, chanel mode modify, assignment, and handover
*/
+/* set channel mode in case of TCH */
+static int gsm48_rr_set_mode(struct osmocom_ms *ms, uint8_t chan_nr,
+ uint8_t mode)
+{
+ uint8_t ch_type, ch_subch, ch_ts;
+
+ /* only apply mode to TCH/F or TCH/H */
+ rsl_dec_chan_nr(chan_nr, &ch_type, &ch_subch, &ch_ts);
+ if (ch_type != RSL_CHAN_Bm_ACCHs
+ && ch_type != RSL_CHAN_Lm_ACCHs)
+ return -ENOTSUP;
+
+ /* setting (new) timing advance */
+ LOGP(DRR, LOGL_INFO, "setting TCH mode to %d\n", mode);
+ l1ctl_tx_tch_mode_req(ms, mode);
+
+ return 0;
+}
+
/* 9.1.13 FREQUENCY REDEFINITION is received */
static int gsm48_rr_rx_frq_redef(struct osmocom_ms *ms, struct msgb *msg)
{
@@ -3589,7 +3685,7 @@ static int gsm48_rr_rx_chan_modify(struct osmocom_ms *ms, struct msgb *msg)
int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*cm);
struct gsm48_rr_cd *cd = &rr->cd_now;
uint8_t ch_type, ch_subch, ch_ts;
- uint8_t mode;
+ uint8_t cause;
LOGP(DRR, LOGL_INFO, "CHANNEL MODE MODIFY\n");
@@ -3619,21 +3715,13 @@ static int gsm48_rr_rx_chan_modify(struct osmocom_ms *ms, struct msgb *msg)
ch_ts, ch_subch, cd->tsc, cm->mode);
}
/* mode */
- mode = cm->mode;
- switch (mode) {
- case GSM48_CMODE_SIGN:
- LOGP(DRR, LOGL_INFO, "Mode set to signalling.\n");
- break;
- case GSM48_CMODE_SPEECH_V1:
- LOGP(DRR, LOGL_INFO, "Mode set to GSM full-rate codec.\n");
- break;
- default:
- LOGP(DRR, LOGL_ERROR, "Mode %u not supported!\n", mode);
- }
- rr->cd_now.mode = mode;
-#warning FIXME: channel mode
+ cause = gsm48_rr_check_mode(ms, cd->chan_nr, cm->mode);
+ if (cause)
+ return gsm48_rr_tx_rr_status(ms, cause);
+ cd->mode = cm->mode;
+ gsm48_rr_set_mode(ms, cd->chan_nr, cd->mode);
- return gsm48_rr_tx_chan_modify_ack(ms, &cm->chan_desc, mode);
+ return gsm48_rr_tx_chan_modify_ack(ms, &cm->chan_desc, cm->mode);
}
/* 9.1.3 sending ASSIGNMENT COMPLETE */
@@ -3860,6 +3948,7 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
"mobile allocation after time\n");
memcpy(&cdb->mob_alloc_lv, &cda->mob_alloc_lv,
sizeof(cdb->mob_alloc_lv));
+ } else
if (cda->freq_list_lv[0]) {
LOGP(DRR, LOGL_INFO, " before: hopping required and "
"frequency list not available, using "
@@ -3901,7 +3990,7 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
cda->mode = cdb->mode = rr->cd_now.mode;
/* cipher mode setting */
- if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET))
+ if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET)) {
cda->cipher = cdb->cipher =
*TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET);
LOGP(DRR, LOGL_INFO, " both: changing cipher mode 0x%02x\n",
@@ -3943,6 +4032,9 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
}
/* check if channels are valid */
+ cause = gsm48_rr_check_mode(ms, cda->chan_nr, cda->mode);
+ if (cause)
+ return gsm48_rr_tx_ass_fail(ms, cause);
if (before_time) {
cause = gsm48_rr_render_ma(ms, cdb, ma, &ma_len);
if (cause)
@@ -4231,6 +4323,7 @@ static int gsm48_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
"mobile allocation after time\n");
memcpy(&cdb->mob_alloc_lv, &cda->mob_alloc_lv,
sizeof(cdb->mob_alloc_lv));
+ } else
if (cda->freq_list_lv[0]) {
LOGP(DRR, LOGL_INFO, " before: hopping required and "
"frequency list not available, using "
@@ -4272,7 +4365,7 @@ static int gsm48_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
cda->mode = cdb->mode = rr->cd_now.mode;
/* cipher mode setting */
- if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET))
+ if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET)) {
cda->cipher = cdb->cipher =
*TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET);
LOGP(DRR, LOGL_INFO, " both: changing cipher mode 0x%02x\n",
diff --git a/src/host/layer23/src/mobile/mnccms.c b/src/host/layer23/src/mobile/mnccms.c
index 6940ed12..9aeaf4dc 100644
--- a/src/host/layer23/src/mobile/mnccms.c
+++ b/src/host/layer23/src/mobile/mnccms.c
@@ -61,6 +61,117 @@ struct gsm_call *get_call_ref(uint32_t callref)
return NULL;
}
+static int8_t mncc_get_bearer(struct gsm_support *sup, uint8_t speech_ver)
+{
+ switch (speech_ver) {
+ case 4:
+ if (sup->full_v3)
+ LOGP(DMNCC, LOGL_INFO, " net suggests full rate v3\n");
+ else {
+ LOGP(DMNCC, LOGL_INFO, " full rate v3 not supported\n");
+ speech_ver = -1;
+ }
+ break;
+ case 2:
+ if (sup->full_v2)
+ LOGP(DMNCC, LOGL_INFO, " net suggests full rate v2\n");
+ else {
+ LOGP(DMNCC, LOGL_INFO, " full rate v2 not supported\n");
+ speech_ver = -1;
+ }
+ break;
+ case 0: /* mandatory */
+ if (sup->full_v1)
+ LOGP(DMNCC, LOGL_INFO, " net suggests full rate v1\n");
+ else {
+ LOGP(DMNCC, LOGL_INFO, " full rate v1 not supported\n");
+ speech_ver = -1;
+ }
+ break;
+ case 5:
+ if (sup->half_v3)
+ LOGP(DMNCC, LOGL_INFO, " net suggests half rate v3\n");
+ else {
+ LOGP(DMNCC, LOGL_INFO, " half rate v3 not supported\n");
+ speech_ver = -1;
+ }
+ break;
+ case 1:
+ if (sup->half_v1)
+ LOGP(DMNCC, LOGL_INFO, " net suggests half rate v1\n");
+ else {
+ LOGP(DMNCC, LOGL_INFO, " half rate v1 not supported\n");
+ speech_ver = -1;
+ }
+ break;
+ default:
+ LOGP(DMNCC, LOGL_INFO, " net suggests unknown speech version "
+ "%d\n", speech_ver);
+ speech_ver = -1;
+ }
+
+ return speech_ver;
+}
+
+static void mncc_set_bearer(struct osmocom_ms *ms, int8_t speech_ver,
+ struct gsm_mncc *mncc)
+{
+ struct gsm_support *sup = &ms->support;
+ struct gsm_settings *set = &ms->settings;
+ int i = 0;
+
+ mncc->fields |= MNCC_F_BEARER_CAP;
+ mncc->bearer_cap.coding = 0;
+ if (sup->ch_cap == GSM_CAP_SDCCH_TCHF_TCHH
+ && (sup->half_v1 || sup->half_v3)) {
+ mncc->bearer_cap.radio = 3;
+ LOGP(DMNCC, LOGL_INFO, " support TCH/H also\n");
+ } else {
+ mncc->bearer_cap.radio = 1;
+ LOGP(DMNCC, LOGL_INFO, " support TCH/F only\n");
+ }
+ mncc->bearer_cap.speech_ctm = 0;
+ /* if no specific speech_ver is given */
+ if (speech_ver < 0) {
+ /* if half rate is supported and prefered */
+ if (sup->half_v3 && set->half && set->half_prefer) {
+ mncc->bearer_cap.speech_ver[i++] = 5;
+ LOGP(DMNCC, LOGL_INFO, " support half rate v3\n");
+ }
+ if (sup->half_v1 && set->half && set->half_prefer) {
+ mncc->bearer_cap.speech_ver[i++] = 1;
+ LOGP(DMNCC, LOGL_INFO, " support half rate v1\n");
+ }
+ /* if full rate is supported */
+ if (sup->full_v3) {
+ mncc->bearer_cap.speech_ver[i++] = 4;
+ LOGP(DMNCC, LOGL_INFO, " support full rate v3\n");
+ }
+ if (sup->full_v2) {
+ mncc->bearer_cap.speech_ver[i++] = 2;
+ LOGP(DMNCC, LOGL_INFO, " support full rate v2\n");
+ }
+ if (sup->full_v1) { /* mandatory, so it's always true */
+ mncc->bearer_cap.speech_ver[i++] = 0;
+ LOGP(DMNCC, LOGL_INFO, " support full rate v1\n");
+ }
+ /* if half rate is supported and not prefered */
+ if (sup->half_v3 && set->half && !set->half_prefer) {
+ mncc->bearer_cap.speech_ver[i++] = 5;
+ LOGP(DMNCC, LOGL_INFO, " support half rate v3\n");
+ }
+ if (sup->half_v1 && set->half && !set->half_prefer) {
+ mncc->bearer_cap.speech_ver[i++] = 1;
+ LOGP(DMNCC, LOGL_INFO, " support half rate v1\n");
+ }
+ /* if specific speech_ver is given (it must be supported) */
+ } else
+ mncc->bearer_cap.speech_ver[i++] = speech_ver;
+ mncc->bearer_cap.speech_ver[i] = -1; /* end of list */
+ mncc->bearer_cap.transfer = 0;
+ mncc->bearer_cap.mode = 0;
+}
+
/*
* MNCCms dummy application
*/
@@ -92,10 +203,13 @@ int mncc_recv_dummy(struct osmocom_ms *ms, int msg_type, void *arg)
int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg)
{
+ struct gsm_settings *set = &ms->settings;
+ struct gsm_support *sup = &ms->support;
struct gsm_mncc *data = arg;
struct gsm_call *call = get_call_ref(data->callref);
struct gsm_mncc mncc;
uint8_t cause;
+ int8_t speech_ver = -1, speech_ver_half = -1, temp;
int first_call = 0;
/* call does not exist */
@@ -203,6 +317,10 @@ int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg)
vty_notify(ms, NULL);
vty_notify(ms, "Call is proceeding\n");
LOGP(DMNCC, LOGL_INFO, "Call is proceeding\n");
+ if ((data->fields & MNCC_F_BEARER_CAP)
+ && data->bearer_cap.speech_ver[0] >= 0) {
+ mncc_get_bearer(sup, data->bearer_cap.speech_ver[0]);
+ }
break;
case MNCC_ALERT_IND:
vty_notify(ms, NULL);
@@ -222,6 +340,59 @@ int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg)
cause = GSM48_CC_CAUSE_USER_BUSY;
goto release;
}
+ /* select first supported speech_ver */
+ if ((data->fields & MNCC_F_BEARER_CAP)) {
+ int i;
+
+ for (i = 0; data->bearer_cap.speech_ver[i] >= 0; i++) {
+
+ temp = mncc_get_bearer(sup,
+ data->bearer_cap.speech_ver[i]);
+ if (temp < 0)
+ continue;
+ if (temp == 5 || temp == 1) { /* half */
+ /* only the first half rate */
+ if (speech_ver_half < 0)
+ speech_ver_half = temp;
+ } else {
+ /* only the first full rate */
+ if (speech_ver < 0)
+ speech_ver = temp;
+ }
+ }
+ /* half and full given */
+ if (speech_ver_half >= 0 && speech_ver >= 0) {
+ if (set->half_prefer) {
+ LOGP(DMNCC, LOGL_INFO, " both supported"
+ " codec rates are given, using "
+ "preferred half rate\n");
+ speech_ver = speech_ver_half;
+ } else
+ LOGP(DMNCC, LOGL_INFO, " both supported"
+ " codec rates are given, using "
+ "preferred full rate\n");
+ } else if (speech_ver_half < 0 && speech_ver < 0) {
+ LOGP(DMNCC, LOGL_INFO, " no supported codec "
+ "rate is given\n");
+ /* only half rate is given, use it */
+ } else if (speech_ver_half >= 0) {
+ LOGP(DMNCC, LOGL_INFO, " only supported half "
+ "rate codec is given, using it\n");
+ speech_ver = speech_ver_half;
+ /* only full rate is given, use it */
+ } else {
+ LOGP(DMNCC, LOGL_INFO, " only supported full "
+ "rate codec is given, using it\n");
+ }
+ if (speech_ver < 0) {
+ vty_notify(ms, "Incomming call rejected, no "
+ "voice call\n");
+ LOGP(DMNCC, LOGL_INFO, "Incomming call "
+ "rejected, no voice call\n");
+ cause = GSM48_CC_CAUSE_BEARERSERV_UNIMPL;
+ goto release;
+ }
+ }
/* presentation allowed if present == 0 */
if (data->calling.present || !data->calling.number[0])
vty_notify(ms, "Incomming call (anonymous)\n");
@@ -238,6 +409,16 @@ int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg)
data->calling.number, call->callref);
memset(&mncc, 0, sizeof(struct gsm_mncc));
mncc.callref = call->callref;
+ /* only include bearer cap, if not given in setup
+ * or if multiple codecs are given
+ * or if not only full rate
+ * or if given codec is unimplemented
+ */
+ if (!(data->fields & MNCC_F_BEARER_CAP) || speech_ver < 0)
+ mncc_set_bearer(ms, -1, &mncc);
+ else if (data->bearer_cap.speech_ver[1] >= 0
+ || speech_ver != 0)
+ mncc_set_bearer(ms, speech_ver, &mncc);
mncc_send(ms, MNCC_CALL_CONF_REQ, &mncc);
if (first_call)
LOGP(DMNCC, LOGL_INFO, "Ring!\n");
@@ -324,20 +505,13 @@ int mncc_call(struct osmocom_ms *ms, char *number)
setup.called.type = 1; /* international */
} else
setup.called.type = 0; /* auto/unknown - prefix must be
- used */
+ used */
setup.called.plan = 1; /* ISDN */
strncpy(setup.called.number, number,
sizeof(setup.called.number) - 1);
/* bearer capability (mandatory) */
- setup.fields |= MNCC_F_BEARER_CAP;
- setup.bearer_cap.coding = 0;
- setup.bearer_cap.radio = 1;
- setup.bearer_cap.speech_ctm = 0;
- setup.bearer_cap.speech_ver[0] = 0;
- setup.bearer_cap.speech_ver[1] = -1; /* end of list */
- setup.bearer_cap.transfer = 0;
- setup.bearer_cap.mode = 0;
+ mncc_set_bearer(ms, -1, &setup);
if (ms->settings.clir)
setup.clir.sup = 1;
else if (ms->settings.clip)
diff --git a/src/host/layer23/src/mobile/settings.c b/src/host/layer23/src/mobile/settings.c
index 1aef48b0..6b6a9325 100644
--- a/src/host/layer23/src/mobile/settings.c
+++ b/src/host/layer23/src/mobile/settings.c
@@ -31,6 +31,7 @@
int gsm_settings_init(struct osmocom_ms *ms)
{
struct gsm_settings *set = &ms->settings;
+ struct gsm_support *sup = &ms->support;
/* IMEI */
sprintf(set->imei, "000000000000000");
@@ -40,6 +41,9 @@ int gsm_settings_init(struct osmocom_ms *ms)
strcpy(set->test_imsi, "001010000000000");
set->test_rplmn_mcc = set->test_rplmn_mnc = 1;
+ if (sup->half_v1 || sup->half_v3)
+ set->half = 1;
+
return 0;
}
diff --git a/src/host/layer23/src/mobile/support.c b/src/host/layer23/src/mobile/support.c
index 3fd581d9..631fd5bf 100644
--- a/src/host/layer23/src/mobile/support.c
+++ b/src/host/layer23/src/mobile/support.c
@@ -104,6 +104,13 @@ void gsm_support_init(struct osmocom_ms *ms)
sup->min_rxlev_db = -100; // TODO
sup->sync_to = 6; /* how long to wait sync (0.9 s) */
sup->scan_to = 4; /* how long to wait for all sysinfos (>=4 s) */
+
+ /* codec */
+ sup->full_v1 = 1;
+ sup->full_v2 = 1;
+ sup->full_v3 = 0;
+ sup->half_v1 = 0;
+ sup->half_v3 = 0;
}
/* (3.2.1) maximum channels to scan within each band */
diff --git a/src/host/layer23/src/mobile/vty_interface.c b/src/host/layer23/src/mobile/vty_interface.c
index 366094f7..eda2d81f 100644
--- a/src/host/layer23/src/mobile/vty_interface.c
+++ b/src/host/layer23/src/mobile/vty_interface.c
@@ -756,6 +756,7 @@ DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME",
static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms)
{
+ struct gsm_support *sup = &ms->support;
struct gsm_settings *set = &ms->settings;
vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE);
@@ -833,6 +834,20 @@ static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms)
vty_out(vty, " no location-updating%s", VTY_NEWLINE);
else
vty_out(vty, " location-updating%s", VTY_NEWLINE);
+ if (sup->full_v1 || sup->full_v2 || sup->full_v3) {
+ /* mandatory anyway */
+ vty_out(vty, " codec full-speed%s%s",
+ (!set->half_prefer) ? " prefer" : "",
+ VTY_NEWLINE);
+ }
+ if (sup->half_v1 || sup->half_v3) {
+ if (set->half)
+ vty_out(vty, " codec half-speed%s%s",
+ (set->half_prefer) ? " prefer" : "",
+ VTY_NEWLINE);
+ else
+ vty_out(vty, " no codec half-speed%s", VTY_NEWLINE);
+ }
vty_out(vty, "exit%s", VTY_NEWLINE);
vty_out(vty, "!%s", VTY_NEWLINE);
}
@@ -1130,6 +1145,88 @@ DEFUN(cfg_ms_no_lupd, cfg_ms_no_lupd_cmd, "no location-updating",
return CMD_SUCCESS;
}
+DEFUN(cfg_codec_full, cfg_ms_codec_full_cmd, "codec full-speed",
+ "Enable codec\nFull speed speech codec")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_support *sup = &ms->support;
+
+ if (!sup->full_v1 && !sup->full_v2 && !sup->full_v3) {
+ vty_out(vty, "Full-rate codec not supported%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_codec_full_pref, cfg_ms_codec_full_pref_cmd, "codec full-speed "
+ "prefer",
+ "Enable codec\nFull speed speech codec\nPrefer this codec")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_support *sup = &ms->support;
+
+ if (!sup->full_v1 && !sup->full_v2 && !sup->full_v3) {
+ vty_out(vty, "Full-rate codec not supported%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ms->settings.half_prefer = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_codec_half, cfg_ms_codec_half_cmd, "codec half-speed",
+ "Enable codec\nHalf speed speech codec")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_support *sup = &ms->support;
+
+ if (!sup->half_v1 && !sup->half_v3) {
+ vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ms->settings.half = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_codec_half_pref, cfg_ms_codec_half_pref_cmd, "codec half-speed "
+ "prefer",
+ "Enable codec\nHalf speed speech codec\nPrefer this codec")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_support *sup = &ms->support;
+
+ if (!sup->half_v1 && !sup->half_v3) {
+ vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ms->settings.half = 1;
+ ms->settings.half_prefer = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_codec_half, cfg_ms_no_codec_half_cmd, "no codec half-speed",
+ NO_STR "Disable codec\nHalf speed speech codec")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_support *sup = &ms->support;
+
+ if (!sup->half_v1 && !sup->half_v3) {
+ vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ms->settings.half = 0;
+ ms->settings.half_prefer = 0;
+
+ return CMD_SUCCESS;
+}
+
/* per testsim config */
DEFUN(cfg_ms_testsim, cfg_ms_testsim_cmd, "test-sim",
"Configure test SIM emulation")
@@ -1409,7 +1506,11 @@ int ms_vty_init(void)
install_element(MS_NODE, &cfg_ms_no_stick_cmd);
install_element(MS_NODE, &cfg_ms_lupd_cmd);
install_element(MS_NODE, &cfg_ms_no_lupd_cmd);
-
+ install_element(MS_NODE, &cfg_ms_codec_full_cmd);
+ install_element(MS_NODE, &cfg_ms_codec_full_pref_cmd);
+ install_element(MS_NODE, &cfg_ms_codec_half_cmd);
+ install_element(MS_NODE, &cfg_ms_codec_half_pref_cmd);
+ install_element(MS_NODE, &cfg_ms_no_codec_half_cmd);
install_node(&testsim_node, config_write_dummy);
install_default(TESTSIM_NODE);
install_element(TESTSIM_NODE, &ournode_exit_cmd);