From 04af6074f57aef76e1bb8138c3f3e362a6e78b2d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 16 Apr 2022 20:35:34 +0200 Subject: [PATCH] bchan_hdlr for spandsp soft-modem This needs spandsp >= 3.0.0 from https://github.com/freeswitch/spandsp --- Makefile | 6 +- bchan.c | 2 - bchan.h | 7 ++ capi.c | 5 -- hdlr_spandsp.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 180 insertions(+), 10 deletions(-) create mode 100644 hdlr_spandsp.c diff --git a/Makefile b/Makefile index a78795a..23c1848 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ LIBS = -lasan CFLAGS = -g -Wall -LIBS += $(shell pkg-config --libs talloc libosmocore capi20) -CFLAGS += $(shell pkg-config --cflags talloc libosmocore capi20) +LIBS += $(shell pkg-config --libs talloc libosmocore capi20 spandsp) +CFLAGS += $(shell pkg-config --cflags talloc libosmocore capi20 spandsp) all: capi-test @@ -15,7 +15,7 @@ clean: libprbs.a: prbs/prbs.o prbs/rx.o prbs/tx.o $(AR) r $@ $^ -capi-test: capi.o capiconn.o bchan.o hdlr_raw_loop.o hdlr_raw_prbs.o libprbs.a +capi-test: capi.o capiconn.o bchan.o hdlr_raw_loop.o hdlr_raw_prbs.o libprbs.a hdlr_spandsp.o $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) diff --git a/bchan.c b/bchan.c index 783bfb9..88ce685 100644 --- a/bchan.c +++ b/bchan.c @@ -16,8 +16,6 @@ static LLIST_HEAD(g_handlers); static LLIST_HEAD(g_routes); -extern void *g_ctx; - struct bchan_handler *bchan_handler_find(const char *name) { struct bchan_handler *bch; diff --git a/bchan.h b/bchan.h index 55a04b3..ead307d 100644 --- a/bchan.h +++ b/bchan.h @@ -13,6 +13,13 @@ #include "capi_misc_defs.h" +enum log_subsys { + DLCAPI20, + DCAPI, +}; + +extern void *g_ctx; + struct capi_connection; struct bchan_handler_cfg { diff --git a/capi.c b/capi.c index 7303f7d..79a91a9 100644 --- a/capi.c +++ b/capi.c @@ -28,11 +28,6 @@ void *g_ctx; -enum log_subsys { - DLCAPI20, - DCAPI, -}; - struct capi_inst { unsigned int applid; capiconn_context *cc_ctx; diff --git a/hdlr_spandsp.c b/hdlr_spandsp.c new file mode 100644 index 0000000..6a781cd --- /dev/null +++ b/hdlr_spandsp.c @@ -0,0 +1,170 @@ +/* soft-modem B-channel based on spandsp library */ + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "bchan.h" +#include "errno.h" + +/*********************************************************************** + * spandsp callbacks + ***********************************************************************/ + +static int cb_at_tx_handler(void *user_data, const uint8_t *buf, size_t len) +{ + /* write to stdout for now */ + return write(1, buf, len); +} + +static int cb_modem_ctrl_hdlr(data_modems_state_t *ms, void *user_data, int op, const char *num) +{ + printf("MODEM CONTROL: %s\n", at_modem_control_to_str(op)); + switch (op) { + case AT_MODEM_CONTROL_CALL: + data_modems_call_event(ms, AT_CALL_EVENT_CONNECTED); + break; + case AT_MODEM_CONTROL_ANSWER: + data_modems_call_event(ms, AT_CALL_EVENT_ANSWERED); + break; + } + return 0; +} + +static void cb_put_msg(void *user_data, const uint8_t msg[], int len) +{ + if (len < 0) + printf("Status %s\n", signal_status_to_str(len)); + else + printf("Put %d '%s'\n", len, msg); +} + +static int cb_get_msg(void *user_data, uint8_t msg[], int len) +{ + return 0; +} + +/*********************************************************************** + * bchan integration + ***********************************************************************/ + +struct spandsp_priv { + data_modems_state_t *ms; + g711_state_t *g711; +}; + +static int spandsp_init(struct call_state *cst) +{ + struct spandsp_priv *rpp; + logging_state_t *logging; + + rpp = cst->priv = talloc_zero(cst, struct spandsp_priv); + if (!rpp) + return -ENOMEM; + + rpp->ms = data_modems_init(NULL, false, cb_at_tx_handler, NULL, cb_modem_ctrl_hdlr, + NULL, cb_put_msg, cb_get_msg, rpp); + OSMO_ASSERT(rpp->ms); + logging = data_modems_get_logging_state(rpp->ms); + span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); + span_log_set_tag(logging, "modem"); + /* this is the default, but calling it now applies above-mentioned log level */ + data_modems_set_modem_type(rpp->ms, DATA_MODEM_V8, 0, 0); + //data_modems_set_modem_type(rpp->ms, DATA_MODEM_BELL103, 0, 0); + rpp->g711 = g711_init(NULL, G711_ALAW); + data_modems_call_event(rpp->ms, AT_CALL_EVENT_ANSWERED); + + return 0; +} + +static void spandsp_rx(struct call_state *cst, const uint8_t *data, size_t len) +{ + struct spandsp_priv *rpp = cst->priv; + int16_t s16_buf[len]; + uint8_t tx_buf[len]; + int rc; + + /* mISDN/CAPI bit order != spandsp order */ + osmo_revbytebits_buf((uint8_t *)data, len); + + /* A-law -> S16 */ + rc = g711_decode(rpp->g711, s16_buf, data, len); + OSMO_ASSERT(rc == len); + + rc = data_modems_rx(rpp->ms, s16_buf, len); + OSMO_ASSERT(rc == 0); + + /* generate respective number of output samples and transmit them */ + rc = data_modems_tx(rpp->ms, s16_buf, len); + OSMO_ASSERT(rc == len); + + /* A-law <- S16 */ + rc = g711_encode(rpp->g711, tx_buf, s16_buf, len); + OSMO_ASSERT(rc == len); + + /* mISDN/CAPI bit order != spandsp order */ + osmo_revbytebits_buf(tx_buf, len); + + bchan_call_tx(cst, tx_buf, len); +} + +static void spandsp_fini(struct call_state *cst) +{ + struct spandsp_priv *rpp = cst->priv; + g711_free(rpp->g711); + data_modems_free(rpp->ms); + talloc_free(rpp); + cst->priv = NULL; +} + +static void spandsp_log_cb(void *user_data, int level, const char *text) +{ + LOGP(DCAPI, LOGL_INFO, text); +} + +static struct bchan_handler bch_spandsp = { + .name = "spandsp", + .cfg = { + .proto = { CAPI_B1_64k_TRANSPARENT, CAPI_B2_TRANSPARENT, CAPI_B3_TRANSPARENT }, + .ncpi = NULL, + .max_b_data_blocks = 10, + .max_b_data_len = 32, + }, + .ops = { + .init = spandsp_init, + .rx_data = spandsp_rx, + .fini = spandsp_fini, + }, +}; + +static void *span_alloc_cb(size_t size) +{ + return talloc_size(g_ctx, size); +} + +static void span_free_cb(void *ptr) +{ + talloc_free(ptr); +} + +static __attribute__((constructor)) void hdlr_spandsp_init(void) +{ + /* memory allocator */ + span_mem_allocators(span_alloc_cb, NULL, span_free_cb, NULL, NULL); + + /* logging */ + //span_set_message_handler(spandsp_log_cb, NULL); + + bchan_handler_register(&bch_spandsp); +}