bchan_hdlr for spandsp soft-modem
This needs spandsp >= 3.0.0 from https://github.com/freeswitch/spandsp
This commit is contained in:
parent
ae530f762c
commit
04af6074f5
6
Makefile
6
Makefile
|
@ -1,8 +1,8 @@
|
||||||
LIBS = -lasan
|
LIBS = -lasan
|
||||||
CFLAGS = -g -Wall
|
CFLAGS = -g -Wall
|
||||||
|
|
||||||
LIBS += $(shell pkg-config --libs talloc libosmocore capi20)
|
LIBS += $(shell pkg-config --libs talloc libosmocore capi20 spandsp)
|
||||||
CFLAGS += $(shell pkg-config --cflags talloc libosmocore capi20)
|
CFLAGS += $(shell pkg-config --cflags talloc libosmocore capi20 spandsp)
|
||||||
|
|
||||||
all: capi-test
|
all: capi-test
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ clean:
|
||||||
libprbs.a: prbs/prbs.o prbs/rx.o prbs/tx.o
|
libprbs.a: prbs/prbs.o prbs/rx.o prbs/tx.o
|
||||||
$(AR) r $@ $^
|
$(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)
|
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
|
|
||||||
|
|
2
bchan.c
2
bchan.c
|
@ -16,8 +16,6 @@
|
||||||
static LLIST_HEAD(g_handlers);
|
static LLIST_HEAD(g_handlers);
|
||||||
static LLIST_HEAD(g_routes);
|
static LLIST_HEAD(g_routes);
|
||||||
|
|
||||||
extern void *g_ctx;
|
|
||||||
|
|
||||||
struct bchan_handler *bchan_handler_find(const char *name)
|
struct bchan_handler *bchan_handler_find(const char *name)
|
||||||
{
|
{
|
||||||
struct bchan_handler *bch;
|
struct bchan_handler *bch;
|
||||||
|
|
7
bchan.h
7
bchan.h
|
@ -13,6 +13,13 @@
|
||||||
|
|
||||||
#include "capi_misc_defs.h"
|
#include "capi_misc_defs.h"
|
||||||
|
|
||||||
|
enum log_subsys {
|
||||||
|
DLCAPI20,
|
||||||
|
DCAPI,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void *g_ctx;
|
||||||
|
|
||||||
struct capi_connection;
|
struct capi_connection;
|
||||||
|
|
||||||
struct bchan_handler_cfg {
|
struct bchan_handler_cfg {
|
||||||
|
|
5
capi.c
5
capi.c
|
@ -28,11 +28,6 @@
|
||||||
void *g_ctx;
|
void *g_ctx;
|
||||||
|
|
||||||
|
|
||||||
enum log_subsys {
|
|
||||||
DLCAPI20,
|
|
||||||
DCAPI,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct capi_inst {
|
struct capi_inst {
|
||||||
unsigned int applid;
|
unsigned int applid;
|
||||||
capiconn_context *cc_ctx;
|
capiconn_context *cc_ctx;
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
/* soft-modem B-channel based on spandsp library */
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/bits.h>
|
||||||
|
#include <osmocom/core/logging.h>
|
||||||
|
|
||||||
|
#include <spandsp/telephony.h>
|
||||||
|
#include <spandsp/g711.h>
|
||||||
|
#include <spandsp/logging.h>
|
||||||
|
|
||||||
|
#include <spandsp/alloc.h>
|
||||||
|
#include <spandsp/at_interpreter.h>
|
||||||
|
#include <spandsp/async.h>
|
||||||
|
#include <spandsp/data_modems.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
Loading…
Reference in New Issue