diff options
author | Vadim Yanitskiy <vyanitskiy@sysmocom.de> | 2024-01-07 22:05:44 +0700 |
---|---|---|
committer | Vadim Yanitskiy <vyanitskiy@sysmocom.de> | 2024-01-18 03:51:35 +0700 |
commit | 129d0ea8024817193a0180c487e3394fbb6c7c3d (patch) | |
tree | 6bd783e87176c2b3d869021dbf5de38fb630fc5c /src/host/layer23/src | |
parent | 4038d3e42f6a9e0e92e3deeb675d6586b4d132db (diff) |
mobile: init/deinit GAPK I/O based on CC transaction events
Change-Id: I28f87f6a6de673611aa02a24e8985aee23d4498b
Related: OS#4396
Diffstat (limited to 'src/host/layer23/src')
-rw-r--r-- | src/host/layer23/src/mobile/app_mobile.c | 17 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gapk_io.c | 112 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gsm48_rr.c | 24 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/tch.c | 191 |
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; } |