aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2020-03-07 20:32:08 +0100
committerHarald Welte <laforge@osmocom.org>2020-03-08 17:56:52 +0100
commit58d79e88ad58887c92ecc98024f537e3efbb9469 (patch)
treedddadd0c08cb3ddc84f9056a38c2d9748c9a2866
parent6a5039674f3d3253133ada666368b9342cc18a93 (diff)
osmo-bts-virtual: implement GSMTAP_CHANNEL_VOICE
GSMTAP_CHANNEL_VOICE is the mechanism by which GSMTAP can [finally!] be used to transport circuit-switched voice codec payload, and not just signalling. Original patch by Neels Hofmeyr, heavily extended by Harald Welte. Depends: libosmocore.git I952044a17334f35712e087dc41781805000aebc1 Change-Id: I1cd9a251ce0b87181a0822d7940bbfc9f1428543
-rw-r--r--src/osmo-bts-virtual/l1_if.c20
-rw-r--r--src/osmo-bts-virtual/scheduler_virtbts.c71
2 files changed, 79 insertions, 12 deletions
diff --git a/src/osmo-bts-virtual/l1_if.c b/src/osmo-bts-virtual/l1_if.c
index ab2cb762..b6a3507d 100644
--- a/src/osmo-bts-virtual/l1_if.c
+++ b/src/osmo-bts-virtual/l1_if.c
@@ -128,12 +128,7 @@ static void virt_um_rcv_cb(struct virt_um_inst *vui, struct msgb *msg)
break;
case GSMTAP_CHANNEL_TCH_F:
case GSMTAP_CHANNEL_TCH_H:
-#if 0
- /* TODO: handle voice messages */
- if (!facch && ! tch_acch) {
- osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_TCH, PRIM_OP_INDICATION, msg);
- }
-#endif
+ /* This is TCH signalling, for voice frames see GSMTAP_CHANNEL_VOICE */
case GSMTAP_CHANNEL_SDCCH4:
case GSMTAP_CHANNEL_SDCCH8:
case GSMTAP_CHANNEL_PACCH:
@@ -151,6 +146,19 @@ static void virt_um_rcv_cb(struct virt_um_inst *vui, struct msgb *msg)
l1sap.u.data.pdch_presence_info = PRES_INFO_BOTH;
l1if_process_meas_res(pinst->trx, timeslot, fn, chan_nr, 0, 0, 0, 0);
break;
+ case GSMTAP_CHANNEL_VOICE_F:
+ case GSMTAP_CHANNEL_VOICE_H:
+ /* the first byte indicates the type of voice codec (gsmtap_um_voice_type) */
+ msg->l2h = msgb_pull(msg, 1);
+ osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_TCH, PRIM_OP_INDICATION, msg);
+ l1sap.u.tch.chan_nr = chan_nr;
+ l1sap.u.tch.fn = fn;
+ l1sap.u.tch.rssi = 0; /* Radio Signal Strength Indicator. Best -> 0 */
+ l1sap.u.tch.ber10k = 0; /* Bit Error Rate in 0.01%. Best -> 0 */
+ l1sap.u.tch.ta_offs_256bits = 0; /* Burst time of arrival in quarter bits. Probably used for Timing Advance calc. Best -> 0 */
+ l1sap.u.tch.lqual_cb = 10 * signal_dbm; /* Link quality in centiBel = 10 * dB. */
+ l1if_process_meas_res(pinst->trx, timeslot, fn, chan_nr, 0, 0, 0, 0);
+ break;
case GSMTAP_CHANNEL_AGCH:
case GSMTAP_CHANNEL_PCH:
case GSMTAP_CHANNEL_BCCH:
diff --git a/src/osmo-bts-virtual/scheduler_virtbts.c b/src/osmo-bts-virtual/scheduler_virtbts.c
index 90288d1a..72a68744 100644
--- a/src/osmo-bts-virtual/scheduler_virtbts.c
+++ b/src/osmo-bts-virtual/scheduler_virtbts.c
@@ -52,8 +52,8 @@
* This will at first wrap the msg with a GSMTAP header and then write it to the declared multicast socket.
* TODO: we might want to remove unused argument uint8_t tn
*/
-static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, struct msgb *msg)
+static void _tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
+ enum trx_chan_type chan, struct msgb *msg, bool is_voice_frame)
{
const struct trx_chan_desc *chdesc = &trx_chan_desc[chan];
struct msgb *outmsg; /* msg to send with gsmtap header prepended */
@@ -76,7 +76,7 @@ static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
l1sap_fn2ccch_block(fn) >= num_agch(l1t->trx, "PH-DATA-REQ"))
gsmtap_chantype = GSMTAP_CHANNEL_PCH;
else
- gsmtap_chantype = chantype_rsl2gsmtap(rsl_chantype, chdesc->link_id); /* the logical channel type */
+ gsmtap_chantype = chantype_rsl2gsmtap2(rsl_chantype, chdesc->link_id, is_voice_frame); /* the logical channel type */
#if MODULO_HYPERFRAME
/* Restart fn after every superframe (26 * 51 frames) to simulate hyperframe overflow each 6 seconds. */
@@ -105,6 +105,65 @@ static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
msgb_free(msg);
}
+static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
+ enum trx_chan_type chan, struct msgb *msg)
+{
+ _tx_to_virt_um(l1t, tn, fn, chan, msg, false);
+}
+
+
+static struct gsm_lchan *lchan_from_l1t(struct l1sched_trx *l1t, uint8_t tn, enum trx_chan_type chan)
+{
+ struct gsm_bts_trx_ts *ts;
+ uint8_t subslot = 0;
+
+ OSMO_ASSERT(l1t && l1t->trx);
+
+ if (chan == TRXC_TCHH_1)
+ subslot = 1;
+
+ ts = &l1t->trx->ts[tn];
+ return &ts->lchan[subslot];
+}
+
+/* Determine the gsmtap_um_voice_type of a gsm_lchan */
+static int get_um_voice_type(const struct gsm_lchan *lchan)
+{
+ switch (lchan->tch_mode) {
+ case GSM48_CMODE_SPEECH_V1:
+ if (lchan->type == GSM_LCHAN_TCH_H)
+ return GSMTAP_UM_VOICE_HR;
+ else
+ return GSMTAP_UM_VOICE_FR;
+ case GSM48_CMODE_SPEECH_EFR:
+ return GSMTAP_UM_VOICE_EFR;
+ case GSM48_CMODE_SPEECH_AMR:
+ return GSMTAP_UM_VOICE_AMR;
+ default:
+ return -1;
+ }
+}
+
+static void tx_to_virt_um_voice_frame(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
+ enum trx_chan_type chan, struct msgb *msg)
+{
+ struct gsm_lchan *lchan = lchan_from_l1t(l1t, tn, chan);
+ int um_voice_type;
+
+ OSMO_ASSERT(lchan);
+ um_voice_type = get_um_voice_type(lchan);
+ if (um_voice_type < 0) {
+ LOGPLCHAN(lchan, DL1P, LOGL_ERROR, "Cannot determine Um voice type from lchan\n");
+ um_voice_type = 0xff;
+ }
+
+ /* the first byte indicates the type of voice codec (gsmtap_um_voice_type) */
+ msgb_pull_to_l2(msg);
+ msgb_push_u8(msg, um_voice_type);
+ msg->l2h = msg->data;
+ _tx_to_virt_um(l1t, tn, fn, chan, msg, true);
+}
+
/*
* TX on downlink
*/
@@ -414,8 +473,8 @@ ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
if (msg_facch) {
tx_to_virt_um(l1t, tn, fn, chan, msg_facch);
msgb_free(msg_tch);
- } else
- tx_to_virt_um(l1t, tn, fn, chan, msg_tch);
+ } else if (msg_tch)
+ tx_to_virt_um_voice_frame(l1t, tn, fn, chan, msg_tch);
send_burst:
@@ -456,7 +515,7 @@ ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
tx_to_virt_um(l1t, tn, fn, chan, msg_facch);
msgb_free(msg_tch);
} else if (msg_tch)
- tx_to_virt_um(l1t, tn, fn, chan, msg_tch);
+ tx_to_virt_um_voice_frame(l1t, tn, fn, chan, msg_tch);
send_burst:
return NULL;