aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylvain Munaut <tnt@246tNt.com>2009-09-29 08:33:29 +0200
committerSylvain Munaut <tnt@246tNt.com>2009-09-29 08:33:29 +0200
commiteadc625b8844665884cc1537de8977bbe503865e (patch)
tree0ffb6f52513e33279a732ff88d1f3518c640a8f2
parent28eed215bd7579198623ac199e8fcedfa75022c2 (diff)
Add code for RTP setup/cleanup and basic channel integration
This pretty much handles all the setup and cleanup and media frames RX/TX. This doesn't yet start a RTP stream but not much is missing. Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
-rw-r--r--chan_openbsc.c203
-rw-r--r--openbsc.conf.sample2
2 files changed, 198 insertions, 7 deletions
diff --git a/chan_openbsc.c b/chan_openbsc.c
index bdc439e..bbff907 100644
--- a/chan_openbsc.c
+++ b/chan_openbsc.c
@@ -29,9 +29,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: $")
#include <openbsc/talloc.h>
#include "asterisk/channel.h"
+#include "asterisk/io.h"
#include "asterisk/linkedlists.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
+#include "asterisk/rtp.h"
+#include "asterisk/sched.h"
+#include "asterisk/utils.h"
enum call_direction {
@@ -46,12 +50,20 @@ struct openbsc_chan_priv {
u_int32_t callref;
enum call_direction dir;
+ struct ast_rtp *rtp;
+
AST_LIST_ENTRY(openbsc_chan_priv) _list;
};
static AST_RWLIST_HEAD_STATIC(g_privs, openbsc_chan_priv);
static u_int32_t g_nextcallref = 0x00000001; /* uses g_privs lock */
+static struct sched_context *g_sched_ctx = NULL;
+static struct io_context *g_io_ctx = NULL;
+
+static struct sockaddr_in g_bindaddr = { 0, };
+static struct in_addr g_ourip;
+
AST_MUTEX_DEFINE_STATIC(g_openbsc_lock);
@@ -65,6 +77,7 @@ struct openbsc_config {
char db_file[PATH_MAX];
char pcap_file[PATH_MAX];
char debug_filter[128];
+ char bindaddr[128];
int debug_color;
int debug_timestamp;
int reject_cause;
@@ -224,6 +237,9 @@ _openbsc_chan_new(struct openbsc_chan_priv *p, int state)
chan->tech_pvt = p;
p->owner = chan;
+ ast_channel_set_fd(chan, 0, ast_rtp_fd(p->rtp));
+ ast_channel_set_fd(chan, 1, ast_rtcp_fd(p->rtp));
+
ast_module_ref(ast_module_info->self);
return chan;
@@ -234,6 +250,9 @@ _openbsc_chan_detach(struct ast_channel *chan)
{
struct openbsc_chan_priv *p = chan->tech_pvt;
+ ast_channel_set_fd(chan, 0, -1);
+ ast_channel_set_fd(chan, 1, -1);
+
chan->tech_pvt = NULL;
p->owner = NULL;
@@ -263,6 +282,15 @@ _openbsc_chan_priv_new(u_int32_t callref, enum call_direction dir)
p->callref = callref;
p->dir = dir;
+ /* RTP init */
+ p->rtp = ast_rtp_new_with_bindaddr(g_sched_ctx, g_io_ctx, 1, 0, g_bindaddr.sin_addr);
+ if (!p->rtp) {
+ ast_log(LOG_ERROR, "Failed to allocate channel RTP stream\n");
+ goto error;
+ }
+
+ ast_rtp_pt_clear(p->rtp);
+
/* Finally add to the list */
AST_RWLIST_INSERT_HEAD(&g_privs, p, _list);
@@ -285,6 +313,9 @@ _openbsc_chan_priv_destroy(struct openbsc_chan_priv *p)
AST_RWLIST_REMOVE(&g_privs, p, _list);
AST_RWLIST_UNLOCK(&g_privs);
+ /* Destroy rtp */
+ ast_rtp_destroy(p->rtp);
+
/* Free memory */
ast_free(p);
}
@@ -372,12 +403,26 @@ openbsc_chan_answer(struct ast_channel *chan)
static struct ast_frame *
openbsc_chan_read(struct ast_channel *chan)
{
- return 0;
+ struct openbsc_chan_priv *p = chan->tech_pvt;
+ return p->rtp ? ast_rtp_read(p->rtp) : &ast_null_frame;
}
static int
openbsc_chan_write(struct ast_channel *chan, struct ast_frame *frame)
{
+ struct openbsc_chan_priv *p = chan->tech_pvt;
+
+ switch (frame->frametype) {
+ case AST_FRAME_VOICE:
+ return p->rtp ? ast_rtp_write(p->rtp, frame) : 0;
+
+ default:
+ ast_log(LOG_WARNING,
+ "Can't send %d type frames with write\n",
+ frame->frametype
+ );
+ }
+
return 0;
}
@@ -540,6 +585,87 @@ static const struct ast_channel_tech openbsc_tech = {
/* ------------------------------------------------------------------------ */
+/* RTP interface */
+/* ---------------------------------------------------------------------{{{ */
+
+/* Main thread */
+static pthread_t g_rtp_tid;
+
+static void *
+openbsc_rtp_main(void *data)
+{
+ int rv;
+
+ while(1) {
+ pthread_testcancel();
+ /* Wait for sched or io */
+ rv = ast_sched_wait(g_sched_ctx);
+ if ((rv < 0) || (rv > 1000)) {
+ rv = 1000;
+ }
+ rv = ast_io_wait(g_io_ctx, rv);
+ if (rv >= 0) {
+ ast_sched_runq(g_sched_ctx);
+ }
+ }
+
+ return NULL; /* Never reached */
+}
+
+static int
+openbsc_rtp_start(void)
+{
+ return ast_pthread_create(&g_rtp_tid, NULL, openbsc_rtp_main, NULL);
+}
+
+static void
+openbsc_rtp_stop(void)
+{
+ pthread_cancel(g_rtp_tid);
+ pthread_join(g_rtp_tid, NULL);
+}
+
+
+/* Interface implementation */
+static enum ast_rtp_get_result
+openbsc_rtp_get_peer(struct ast_channel *chan, struct ast_rtp **rtp)
+{
+ struct openbsc_chan_priv *p = chan->tech_pvt;
+ if (p && p->rtp) {
+ *rtp = p->rtp;
+ return AST_RTP_TRY_PARTIAL;
+ }
+ return AST_RTP_GET_FAILED;
+}
+
+static int
+openbsc_rtp_set_peer(struct ast_channel *chan,
+ struct ast_rtp *peer, struct ast_rtp *vpeer, struct ast_rtp *tpeer,
+ int codecs, int nat_active)
+{
+ /* Direct media path not supported */
+ ast_log(LOG_WARNING, "set_rtp_peer is not supported for now");
+ return 0;
+}
+
+static int
+openbsc_rtp_get_codec(struct ast_channel *chan)
+{
+ return chan->nativeformats;
+}
+
+
+static struct ast_rtp_protocol openbsc_rtp = {
+ .type = "OpenBSC",
+ .get_rtp_info = openbsc_rtp_get_peer,
+ .set_rtp_peer = openbsc_rtp_set_peer,
+ .get_codec = openbsc_rtp_get_codec,
+};
+
+/* }}} */
+
+
+/* ------------------------------------------------------------------------ */
/* Asterisk Module */
/* ---------------------------------------------------------------------{{{ */
@@ -595,6 +721,8 @@ config_module(void)
cfg->reject_cause = atoi(v->value);
} else if (!strcasecmp(v->name, "pcap_file")) {
ast_copy_string(cfg->pcap_file, v->value, sizeof(cfg->pcap_file));
+ } else if (!strcasecmp(v->name, "bindaddr")) {
+ ast_copy_string(cfg->bindaddr, v->value, sizeof(cfg->bindaddr));
} else {
ast_log(LOG_WARNING, "Unknown config key %s ignored\n", v->name);
}
@@ -610,35 +738,91 @@ static int
load_module(void)
{
struct openbsc_config *cfg;
+ struct ast_hostent ahp;
+ struct hostent *hp;
int rv;
cfg = config_module();
if (!cfg)
return AST_MODULE_LOAD_DECLINE;
- rv = openbsc_init(cfg);
+ if (cfg->bindaddr[0]) {
+ if (!(hp = ast_gethostbyname(cfg->bindaddr, &ahp))) {
+ ast_log(LOG_WARNING, "Invalid address: %s\n", cfg->bindaddr);
+ } else {
+ memcpy(&g_bindaddr.sin_addr, hp->h_addr, sizeof(g_bindaddr.sin_addr));
+ }
+ }
- free(cfg);
+ if (ast_find_ourip(&g_ourip, g_bindaddr)) {
+ ast_log(LOG_ERROR, "Unable to get own IP address, OpenBSC disabled\n");
+ goto error_free_cfg;
+ }
+ rv = openbsc_init(cfg);
if (rv) {
ast_log(LOG_ERROR, "Failed to initialize OpenBSC\n");
- return AST_MODULE_LOAD_FAILURE;
+ goto error_free_cfg;
+ }
+
+ g_io_ctx = io_context_create();
+ if (!g_io_ctx) {
+ ast_log(LOG_ERROR, "Unable to create IO context\n");
+ goto error_free;
+ }
+
+ g_sched_ctx = sched_context_create();
+ if (!g_sched_ctx) {
+ ast_log(LOG_ERROR, "Unable to create Scheduling context\n");
+ goto error_free;
+ }
+
+ if (ast_rtp_proto_register(&openbsc_rtp)) {
+ ast_log(LOG_ERROR, "Unable to RTP protocol class 'OpenBSC'\n");
+ goto error_free;
}
if (ast_channel_register(&openbsc_tech)) {
ast_log(LOG_ERROR, "Unable to register channel class 'OpenBSC'\n");
- return AST_MODULE_LOAD_FAILURE;
+ goto error_unreg_rtp;
+ }
+
+ if (openbsc_rtp_start()) {
+ ast_log(LOG_ERROR, "Unable to start OpenBSC RTP thread\n");
+ goto error_unreg_chan;
}
if (openbsc_start()) {
- ast_channel_unregister(&openbsc_tech);
ast_log(LOG_ERROR, "Unable to start OpenBSC main thread\n");
- return AST_MODULE_LOAD_FAILURE;
+ goto error_stoprtp;
}
ast_log(LOG_NOTICE, "OpenBSC channel driver loaded\n");
return AST_MODULE_LOAD_SUCCESS;
+
+error_stoprtp:
+ openbsc_rtp_stop();
+
+error_unreg_chan:
+ ast_channel_unregister(&openbsc_tech);
+
+error_unreg_rtp:
+ ast_rtp_proto_unregister(&openbsc_rtp);
+
+error_free:
+ if (g_sched_ctx)
+ sched_context_destroy(g_sched_ctx);
+
+ if (g_io_ctx)
+ io_context_destroy(g_io_ctx);
+
+ openbsc_destroy();
+
+error_free_cfg:
+ free(cfg);
+
+ return AST_MODULE_LOAD_FAILURE;
}
@@ -649,7 +833,12 @@ unload_module(void)
openbsc_stop();
+ openbsc_rtp_stop();
+
ast_channel_unregister(&openbsc_tech);
+ ast_rtp_proto_unregister(&openbsc_rtp);
+ sched_context_destroy(g_sched_ctx);
+ io_context_destroy(g_io_ctx);
openbsc_destroy();
diff --git a/openbsc.conf.sample b/openbsc.conf.sample
index 304788d..e429d6d 100644
--- a/openbsc.conf.sample
+++ b/openbsc.conf.sample
@@ -25,3 +25,5 @@ db_file = /path/to/hlr.sqlite3
; PCAP file
; pcap_file = /path/to/log.pcap
+; Bind Address
+; bindaddr = 192.168.0.1