summaryrefslogtreecommitdiffstats
path: root/src/host/layer23/src
diff options
context:
space:
mode:
authorVadim Yanitskiy <vyanitskiy@sysmocom.de>2024-01-07 22:05:44 +0700
committerVadim Yanitskiy <vyanitskiy@sysmocom.de>2024-01-18 03:51:35 +0700
commit129d0ea8024817193a0180c487e3394fbb6c7c3d (patch)
tree6bd783e87176c2b3d869021dbf5de38fb630fc5c /src/host/layer23/src
parent4038d3e42f6a9e0e92e3deeb675d6586b4d132db (diff)
mobile: init/deinit GAPK I/O based on CC transaction events
Diffstat (limited to 'src/host/layer23/src')
-rw-r--r--src/host/layer23/src/mobile/app_mobile.c17
-rw-r--r--src/host/layer23/src/mobile/gapk_io.c112
-rw-r--r--src/host/layer23/src/mobile/gsm48_rr.c24
-rw-r--r--src/host/layer23/src/mobile/tch.c191
4 files changed, 230 insertions, 114 deletions
diff --git a/src/host/layer23/src/mobile/app_mobile.c b/src/host/layer23/src/mobile/app_mobile.c
index e2ef56a1..453990ee 100644
--- a/src/host/layer23/src/mobile/app_mobile.c
+++ b/src/host/layer23/src/mobile/app_mobile.c
@@ -42,7 +42,6 @@
#include <osmocom/bb/mobile/app_mobile.h>
#include <osmocom/bb/mobile/mncc.h>
#include <osmocom/bb/mobile/tch.h>
-#include <osmocom/bb/mobile/gapk_io.h>
#include <osmocom/bb/mobile/primitives.h>
#include <osmocom/vty/vty.h>
@@ -82,10 +81,7 @@ int mobile_work(struct osmocom_ms *ms)
w |= gsm322_cs_dequeue(ms);
w |= gsm_sim_job_dequeue(ms);
w |= mncc_dequeue(ms);
-#ifdef WITH_GAPK_IO
- if (ms->gapk_io != NULL)
- w |= gapk_io_serve_ms(ms);
-#endif
+ w |= tch_serve_ms(ms);
if (w)
work = 1;
} while (w);
@@ -200,12 +196,6 @@ int mobile_exit(struct osmocom_ms *ms, int force)
return -EBUSY;
}
-#ifdef WITH_GAPK_IO
- /* Clean up GAPK state, if preset */
- if (ms->gapk_io != NULL)
- gapk_io_clean_up_ms(ms);
-#endif
-
gsm322_exit(ms);
gsm48_mm_exit(ms);
gsm48_rr_exit(ms);
@@ -494,11 +484,6 @@ int l23_app_init(void)
l23_app_exit = _mobile_app_exit;
osmo_gps_init();
-#ifdef WITH_GAPK_IO
- /* Init GAPK audio I/O */
- gapk_io_init();
-#endif
-
osmo_signal_register_handler(SS_GLOBAL, &global_signal_cb, NULL);
osmo_signal_register_handler(SS_L1CTL, &mobile_signal_cb, NULL);
osmo_signal_register_handler(SS_L1CTL, &gsm322_l1_signal, NULL);
diff --git a/src/host/layer23/src/mobile/gapk_io.c b/src/host/layer23/src/mobile/gapk_io.c
index 9a97639d..3dab46df 100644
--- a/src/host/layer23/src/mobile/gapk_io.c
+++ b/src/host/layer23/src/mobile/gapk_io.c
@@ -316,29 +316,26 @@ error:
* processing queues (chains), and deallocates the memory.
* Should be called when a voice call is finished...
*/
-int gapk_io_clean_up_ms(struct osmocom_ms *ms)
+void gapk_io_state_free(struct gapk_io_state *state)
{
struct msgb *msg;
- if (ms->gapk_io == NULL)
- return 0;
+ if (state == NULL)
+ return;
/* Flush TCH frame I/O buffers */
- while ((msg = msgb_dequeue(&ms->gapk_io->tch_dl_fb)))
+ while ((msg = msgb_dequeue(&state->tch_dl_fb)))
msgb_free(msg);
- while ((msg = msgb_dequeue(&ms->gapk_io->tch_ul_fb)))
+ while ((msg = msgb_dequeue(&state->tch_ul_fb)))
msgb_free(msg);
/* Destroy both audio I/O chains */
- if (ms->gapk_io->pq_source)
- osmo_gapk_pq_destroy(ms->gapk_io->pq_source);
- if (ms->gapk_io->pq_sink)
- osmo_gapk_pq_destroy(ms->gapk_io->pq_sink);
-
- talloc_free(ms->gapk_io);
- ms->gapk_io = NULL;
+ if (state->pq_source != NULL)
+ osmo_gapk_pq_destroy(state->pq_source);
+ if (state->pq_sink != NULL)
+ osmo_gapk_pq_destroy(state->pq_sink);
- return 0;
+ talloc_free(state);
}
/**
@@ -386,31 +383,31 @@ static enum osmo_gapk_format_type phy_fmt_pick_ti(enum osmo_gapk_codec_type code
* and prepares both processing queues (chains).
* Should be called when a voice call is initiated...
*/
-int gapk_io_init_ms(struct osmocom_ms *ms, enum osmo_gapk_codec_type codec)
+struct gapk_io_state *
+gapk_io_state_alloc(struct osmocom_ms *ms,
+ enum osmo_gapk_codec_type codec)
{
const struct osmo_gapk_format_desc *phy_fmt_desc;
const struct osmo_gapk_codec_desc *codec_desc;
- struct gsm_settings *set = &ms->settings;
+ const struct gsm_settings *set = &ms->settings;
enum osmo_gapk_format_type phy_fmt;
struct gapk_io_state *state;
int rc = 0;
LOGP(DGAPK, LOGL_NOTICE, "Initialize GAPK I/O\n");
- OSMO_ASSERT(ms->gapk_io == NULL);
-
/* Make sure that the chosen codec has description */
codec_desc = osmo_gapk_codec_get_from_type(codec);
if (codec_desc == NULL) {
LOGP(DGAPK, LOGL_ERROR, "Invalid codec type 0x%02x\n", codec);
- return -EINVAL;
+ return NULL;
}
/* Make sure that the chosen codec is supported */
if (codec_desc->codec_encode == NULL || codec_desc->codec_decode == NULL) {
LOGP(DGAPK, LOGL_ERROR,
"Codec '%s' is not supported by GAPK\n", codec_desc->name);
- return -ENOTSUP;
+ return NULL;
}
switch (set->tch_voice.io_format) {
@@ -423,20 +420,20 @@ int gapk_io_init_ms(struct osmocom_ms *ms, enum osmo_gapk_codec_type codec)
default:
LOGP(DGAPK, LOGL_ERROR, "Unhandled I/O format %s\n",
tch_voice_io_format_name(set->tch_voice.io_format));
- return -ENOTSUP;
+ return NULL;
}
phy_fmt_desc = osmo_gapk_fmt_get_from_type(phy_fmt);
if (phy_fmt_desc == NULL) {
LOGP(DGAPK, LOGL_ERROR, "Failed to pick the PHY specific "
"frame format for codec '%s'\n", codec_desc->name);
- return -EINVAL;
+ return NULL;
}
state = talloc_zero(ms, struct gapk_io_state);
if (state == NULL) {
LOGP(DGAPK, LOGL_ERROR, "Failed to allocate memory\n");
- return -ENOMEM;
+ return NULL;
}
/* Init TCH frame I/O buffers */
@@ -469,76 +466,41 @@ int gapk_io_init_ms(struct osmocom_ms *ms, enum osmo_gapk_codec_type codec)
talloc_free(state);
LOGP(DGAPK, LOGL_ERROR, "Failed to initialize GAPK I/O\n");
- return rc;
+ return NULL;
}
- /* Init pointers */
- ms->gapk_io = state;
-
LOGP(DGAPK, LOGL_NOTICE,
"GAPK I/O initialized for MS '%s', codec '%s'\n",
ms->name, codec_desc->name);
- return 0;
+ return state;
}
-/**
- * Wrapper around gapk_io_init_ms(), that maps both
- * given GSM 04.08 channel type (HR/FR) and channel
- * mode to a codec from 'osmo_gapk_codec_type' enum,
- * checks if a mapped codec is supported by GAPK,
- * and finally calls the wrapped function.
- */
-int gapk_io_init_ms_chan(struct osmocom_ms *ms,
- uint8_t ch_type, uint8_t ch_mode)
+/* gapk_io_init_ms() wrapper, selecting a codec based on channel mode and rate */
+struct gapk_io_state *
+gapk_io_state_alloc_mode_rate(struct osmocom_ms *ms,
+ enum gsm48_chan_mode ch_mode,
+ bool full_rate)
{
enum osmo_gapk_codec_type codec;
- /* Map GSM 04.08 channel mode to GAPK codec type */
switch (ch_mode) {
case GSM48_CMODE_SPEECH_V1: /* FR or HR */
- if (ch_type == RSL_CHAN_Bm_ACCHs)
- codec = CODEC_FR;
- else
- codec = CODEC_HR;
+ codec = full_rate ? CODEC_FR : CODEC_HR;
break;
-
case GSM48_CMODE_SPEECH_EFR:
codec = CODEC_EFR;
break;
-
case GSM48_CMODE_SPEECH_AMR:
codec = CODEC_AMR;
break;
-
- /* Signalling or CSD, do nothing */
- case GSM48_CMODE_DATA_14k5:
- case GSM48_CMODE_DATA_12k0:
- case GSM48_CMODE_DATA_6k0:
- case GSM48_CMODE_DATA_3k6:
- case GSM48_CMODE_SIGN:
- return 0;
default:
LOGP(DGAPK, LOGL_ERROR, "Unhandled channel mode 0x%02x (%s)\n",
ch_mode, get_value_string(gsm48_chan_mode_names, ch_mode));
- return -EINVAL;
+ return NULL;
}
- return gapk_io_init_ms(ms, codec);
-}
-
-/**
- * Performs basic initialization of GAPK library,
- * setting the talloc root context and a logging category.
- * Should be called during the application initialization...
- */
-void gapk_io_init(void)
-{
- /* Init logging subsystem */
- osmo_gapk_log_init(DGAPK);
-
- /* Make RAWPCM format info easy to access */
- rawpcm_fmt = osmo_gapk_fmt_get_from_type(FMT_RAWPCM_S16LE);
+ return gapk_io_state_alloc(ms, codec);
}
void gapk_io_enqueue_dl(struct gapk_io_state *state, struct msgb *msg)
@@ -554,9 +516,8 @@ void gapk_io_enqueue_dl(struct gapk_io_state *state, struct msgb *msg)
}
/* Serves both UL/DL TCH frame I/O buffers */
-int gapk_io_serve_ms(struct osmocom_ms *ms)
+int gapk_io_serve_ms(struct osmocom_ms *ms, struct gapk_io_state *state)
{
- struct gapk_io_state *state = ms->gapk_io;
int work = 0;
/**
@@ -596,3 +557,16 @@ int gapk_io_serve_ms(struct osmocom_ms *ms)
return work;
}
+
+/**
+ * Performs basic initialization of GAPK library,
+ * setting the talloc root context and a logging category.
+ */
+static __attribute__((constructor)) void gapk_io_init(void)
+{
+ /* Init logging subsystem */
+ osmo_gapk_log_init(DGAPK);
+
+ /* Make RAWPCM format info easy to access */
+ rawpcm_fmt = osmo_gapk_fmt_get_from_type(FMT_RAWPCM_S16LE);
+}
diff --git a/src/host/layer23/src/mobile/gsm48_rr.c b/src/host/layer23/src/mobile/gsm48_rr.c
index 46a143cd..4d879d6f 100644
--- a/src/host/layer23/src/mobile/gsm48_rr.c
+++ b/src/host/layer23/src/mobile/gsm48_rr.c
@@ -125,7 +125,6 @@
#include <osmocom/bb/common/utils.h>
#include <osmocom/bb/common/settings.h>
-#include <osmocom/bb/mobile/gapk_io.h>
#include <osmocom/bb/mobile/vty.h>
#include <osmocom/bb/mobile/gsm48_rr.h>
@@ -515,10 +514,6 @@ static void new_rr_state(struct gsm48_rrlayer *rr, int state)
memset(&rr->cd_now, 0, sizeof(rr->cd_now));
/* reset ciphering */
rr->cipher_on = 0;
-#ifdef WITH_GAPK_IO
- /* clean-up GAPK state */
- gapk_io_clean_up_ms(rr->ms);
-#endif
/* reset audio mode */
/* tell cell selection process to return to idle mode
* NOTE: this must be sent unbuffered, because it will
@@ -573,10 +568,6 @@ static void new_rr_state(struct gsm48_rrlayer *rr, int state)
gsm48_rr_render_ma(ms, &rr->cd_now, ma, &ma_len);
/* activate channel */
gsm48_rr_activate_channel(ms, &rr->cd_now, ma, ma_len);
-#ifdef WITH_GAPK_IO
- /* clean-up GAPK state */
- gapk_io_clean_up_ms(rr->ms);
-#endif
return;
}
}
@@ -4432,15 +4423,6 @@ static int gsm48_rr_set_mode(struct osmocom_ms *ms, uint8_t chan_nr, uint8_t mod
&& ch_type != RSL_CHAN_Lm_ACCHs)
return -ENOTSUP;
-#ifdef WITH_GAPK_IO
- /* Poke GAPK audio back-end, if it is chosen */
- if (ms->settings.tch_voice.io_handler == TCH_VOICE_IOH_GAPK) {
- int rc = gapk_io_init_ms_chan(ms, ch_type, mode);
- if (rc)
- return rc;
- }
-#endif
-
/* Apply indicated channel mode */
LOGP(DRR, LOGL_INFO, "setting TCH mode to %s, audio mode to %d, tch flags to %d\n",
get_value_string(gsm48_chan_mode_names, mode), rr->audio_mode, tch_flags);
@@ -4984,12 +4966,6 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
if (cause)
return gsm48_rr_tx_ass_fail(ms, cause, RSL_MT_DATA_REQ);
-#ifdef WITH_GAPK_IO
- /* Poke GAPK audio back-end, if it is chosen */
- if (ms->settings.tch_voice.io_handler == TCH_VOICE_IOH_GAPK)
- gapk_io_init_ms_chan(ms, ch_type, cda->mode);
-#endif
-
#ifdef TEST_FREQUENCY_MOD
LOGP(DRR, LOGL_INFO, " TESTING: frequency modify ASS.CMD\n");
before_time = 1;
diff --git a/src/host/layer23/src/mobile/tch.c b/src/host/layer23/src/mobile/tch.c
index f6530fba..0b9142e3 100644
--- a/src/host/layer23/src/mobile/tch.c
+++ b/src/host/layer23/src/mobile/tch.c
@@ -1,7 +1,7 @@
/*
* (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
* (C) 2017-2018 by Vadim Yanitskiy <axilirator@gmail.com>
- * (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * (C) 2022-2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
@@ -21,8 +21,10 @@
#include <errno.h>
#include <osmocom/core/msgb.h>
+#include <osmocom/core/signal.h>
#include <osmocom/codec/codec.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/protocol/gsm_08_58.h>
#include <osmocom/bb/common/logging.h>
@@ -31,6 +33,7 @@
#include <osmocom/bb/mobile/gapk_io.h>
#include <osmocom/bb/mobile/mncc.h>
#include <osmocom/bb/mobile/mncc_sock.h>
+#include <osmocom/bb/mobile/transaction.h>
#include <osmocom/bb/mobile/tch.h>
/* Forward a Downlink voice frame to the external MNCC handler */
@@ -76,7 +79,9 @@ exit_free:
/* Receive a Downlink voice frame from the lower layers */
static int tch_recv_voice(struct osmocom_ms *ms, struct msgb *msg)
{
- switch (ms->settings.tch_voice.io_handler) {
+ struct tch_state *state = ms->tch_state;
+
+ switch (state->voice.handler) {
case TCH_VOICE_IOH_LOOPBACK:
/* Remove the DL info header */
msgb_pull_to_l2(msg);
@@ -87,8 +92,8 @@ static int tch_recv_voice(struct osmocom_ms *ms, struct msgb *msg)
case TCH_VOICE_IOH_GAPK:
#ifdef WITH_GAPK_IO
/* Enqueue a frame to the DL TCH buffer */
- if (ms->gapk_io != NULL)
- gapk_io_enqueue_dl(ms->gapk_io, msg);
+ if (state->voice.gapk_io != NULL)
+ gapk_io_enqueue_dl(state->voice.gapk_io, msg);
else
msgb_free(msg);
break;
@@ -102,6 +107,25 @@ static int tch_recv_voice(struct osmocom_ms *ms, struct msgb *msg)
return 0;
}
+/* Receive a Downlink traffic (voice/data) frame from the lower layers */
+static int tch_recv_cb(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct tch_state *state = ms->tch_state;
+ int rc = 0;
+
+ if (state == NULL) {
+ msgb_free(msg);
+ return 0;
+ }
+
+ if (state->is_voice)
+ rc = tch_recv_voice(ms, msg);
+ else /* TODO: tch_recv_data() */
+ msgb_free(msg);
+
+ return rc;
+}
+
/* Send an Uplink voice frame to the lower layers */
int tch_send_voice_msg(struct osmocom_ms *ms, struct msgb *msg)
{
@@ -142,10 +166,167 @@ int tch_send_voice_frame(struct osmocom_ms *ms, const struct gsm_data_frame *fra
return tch_send_voice_msg(ms, nmsg);
}
+int tch_serve_ms(struct osmocom_ms *ms)
+{
+ struct tch_state *state = ms->tch_state;
+
+ if (state == NULL)
+ return 0;
+ if (state->is_voice) {
+#ifdef WITH_GAPK_IO
+ if (state->voice.handler == TCH_VOICE_IOH_GAPK)
+ return gapk_io_serve_ms(ms, state->voice.gapk_io);
+#endif
+ }
+
+ return 0;
+}
+
+static int tch_state_init_voice(struct osmocom_ms *ms,
+ struct tch_voice_state *state)
+{
+ const struct gsm48_rr_cd *cd = &ms->rrlayer.cd_now;
+
+ switch (state->handler) {
+#ifdef WITH_GAPK_IO
+ case TCH_VOICE_IOH_GAPK:
+ if ((cd->chan_nr & RSL_CHAN_NR_MASK) == RSL_CHAN_Bm_ACCHs)
+ state->gapk_io = gapk_io_state_alloc_mode_rate(ms, cd->mode, true);
+ else /* RSL_CHAN_Lm_ACCHs */
+ state->gapk_io = gapk_io_state_alloc_mode_rate(ms, cd->mode, false);
+ if (state->gapk_io == NULL)
+ return -1;
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void tch_state_free_voice(struct tch_voice_state *state)
+{
+ switch (state->handler) {
+#ifdef WITH_GAPK_IO
+ case TCH_VOICE_IOH_GAPK:
+ gapk_io_state_free(state->gapk_io);
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+static void tch_trans_cstate_active_cb(struct gsm_trans *trans)
+{
+ struct osmocom_ms *ms = trans->ms;
+ struct tch_state *state;
+ enum gsm48_chan_mode ch_mode;
+
+ if (ms->tch_state != NULL)
+ return; /* TODO: handle modify? */
+
+ state = talloc_zero(ms, struct tch_state);
+ OSMO_ASSERT(state != NULL);
+
+ ch_mode = ms->rrlayer.cd_now.mode;
+ switch (ch_mode) {
+ case GSM48_CMODE_SPEECH_V1:
+ case GSM48_CMODE_SPEECH_EFR:
+ case GSM48_CMODE_SPEECH_AMR:
+ state->is_voice = true;
+ state->voice.handler = ms->settings.tch_voice.io_handler;
+ if (tch_state_init_voice(ms, &state->voice) != 0)
+ goto exit_free;
+ break;
+ case GSM48_CMODE_DATA_14k5:
+ case GSM48_CMODE_DATA_12k0:
+ case GSM48_CMODE_DATA_6k0:
+ case GSM48_CMODE_DATA_3k6:
+#if 0
+ state->is_voice = false;
+ state->data.handler = ms->settings.tch_data.io_handler;
+ /* TODO: tch_state_init_data() */
+ if (tch_state_init_data(ms, &state->data) != 0)
+ goto exit_free;
+ break;
+#endif
+ case GSM48_CMODE_SIGN:
+ default:
+ LOGP(DL1C, LOGL_ERROR, "Unhandled channel mode %s\n",
+ get_value_string(gsm48_chan_mode_names, ch_mode));
+exit_free:
+ talloc_free(state);
+ return;
+ }
+
+ ms->tch_state = state;
+}
+
+static void tch_trans_free_cb(struct gsm_trans *trans)
+{
+ struct osmocom_ms *ms = trans->ms;
+ struct tch_state *state = ms->tch_state;
+
+ if (state == NULL)
+ return;
+ if (state->is_voice)
+ tch_state_free_voice(&state->voice);
+#if 0
+ else /* TODO: tch_state_free_data() */
+ tch_state_free_data(&state->data);
+#endif
+
+ talloc_free(state);
+ ms->tch_state = NULL;
+}
+
+static void tch_trans_state_chg_cb(struct gsm_trans *trans)
+{
+ switch (trans->cc.state) {
+ case GSM_CSTATE_ACTIVE:
+ tch_trans_cstate_active_cb(trans);
+ break;
+ case GSM_CSTATE_NULL:
+ tch_trans_free_cb(trans);
+ break;
+ }
+}
+
+/* a call-back for CC (Call Control) transaction related events */
+static int tch_trans_signal_cb(unsigned int subsys, unsigned int signal,
+ void *handler_data, void *signal_data)
+{
+ struct gsm_trans *trans = signal_data;
+
+ OSMO_ASSERT(subsys == SS_L23_TRANS);
+ OSMO_ASSERT(trans != NULL);
+
+ /* we only care about CC transactions here */
+ if (trans->protocol != GSM48_PDISC_CC)
+ return 0;
+
+ switch ((enum osmobb_l23_trans_sig)signal) {
+ case S_L23_CC_TRANS_ALLOC:
+ break;
+ case S_L23_CC_TRANS_FREE:
+ tch_trans_free_cb(trans);
+ break;
+ case S_L23_CC_TRANS_STATE_CHG:
+ tch_trans_state_chg_cb(trans);
+ break;
+ }
+
+ return 0;
+}
+
/* Initialize the TCH router */
int tch_init(struct osmocom_ms *ms)
{
- ms->l1_entity.l1_traffic_ind = tch_recv_voice;
+ ms->l1_entity.l1_traffic_ind = &tch_recv_cb;
+
+ osmo_signal_register_handler(SS_L23_TRANS, &tch_trans_signal_cb, ms);
return 0;
}