aboutsummaryrefslogtreecommitdiffstats
path: root/channels/chan_nbs.c
diff options
context:
space:
mode:
authormarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2003-01-21 03:37:21 +0000
committermarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2003-01-21 03:37:21 +0000
commit185a3fdd7ecf8c3a4bcb49098cdb7223c9f0232e (patch)
tree8e22edef027adfb8595cf584c2dcaf6857f34e96 /channels/chan_nbs.c
parent94de4cbbe7bd96b0961e8c6fcd70bff74be5e612 (diff)
Version 0.3.0 from FTP
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@588 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/chan_nbs.c')
-rwxr-xr-xchannels/chan_nbs.c291
1 files changed, 291 insertions, 0 deletions
diff --git a/channels/chan_nbs.c b/channels/chan_nbs.c
new file mode 100755
index 000000000..f1fd22fcb
--- /dev/null
+++ b/channels/chan_nbs.c
@@ -0,0 +1,291 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Generic Linux Telephony Interface driver
+ *
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster@linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <string.h>
+#include <asterisk/lock.h>
+#include <asterisk/channel.h>
+#include <asterisk/channel_pvt.h>
+#include <asterisk/config.h>
+#include <asterisk/logger.h>
+#include <asterisk/module.h>
+#include <asterisk/pbx.h>
+#include <asterisk/options.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <nbs.h>
+
+static char *desc = "Network Broadcast Sound Support";
+static char *type = "NBS";
+static char *tdesc = "Network Broadcast Sound Driver";
+
+static int usecnt =0;
+
+/* Only linear is allowed */
+static int prefformat = AST_FORMAT_SLINEAR;
+
+static pthread_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
+
+static char context[AST_MAX_EXTENSION] = "default";
+
+/* NBS creates private structures on demand */
+
+struct nbs_pvt {
+ NBS *nbs;
+ struct ast_channel *owner; /* Channel we belong to, possibly NULL */
+ char app[16]; /* Our app */
+ char stream[80]; /* Our stream */
+ struct ast_frame fr; /* "null" frame */
+};
+
+static int nbs_call(struct ast_channel *ast, char *dest, int timeout)
+{
+ struct nbs_pvt *p;
+
+ p = ast->pvt->pvt;
+
+ if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
+ ast_log(LOG_WARNING, "nbs_call called on %s, neither down nor reserved\n", ast->name);
+ return -1;
+ }
+ /* When we call, it just works, really, there's no destination... Just
+ ring the phone and wait for someone to answer */
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Calling %s on %s\n", dest, ast->name);
+
+ /* If we can't connect, return congestion */
+ if (nbs_connect(p->nbs)) {
+ ast_log(LOG_WARNING, "NBS Connection failed on %s\n", ast->name);
+ ast_queue_control(ast, AST_CONTROL_CONGESTION, 0);
+ } else {
+ ast_setstate(ast, AST_STATE_RINGING);
+ ast_queue_control(ast, AST_CONTROL_ANSWER, 0);
+ }
+
+ return 0;
+}
+
+static void nbs_destroy(struct nbs_pvt *p)
+{
+ if (p->nbs)
+ nbs_delstream(p->nbs);
+ free(p);
+}
+
+static struct nbs_pvt *nbs_alloc(void *data)
+{
+ struct nbs_pvt *p;
+ int flags = 0;
+ char stream[256] = "";
+ char *opts;
+ strncpy(stream, data, sizeof(stream) - 1);
+ if ((opts = strchr(stream, ':'))) {
+ *opts = '\0';
+ opts++;
+ } else
+ opts = "";
+ p = malloc(sizeof(struct nbs_pvt));
+ if (p) {
+ memset(p, 0, sizeof(struct nbs_pvt));
+ if (strlen(opts)) {
+ if (strchr(opts, 'm'))
+ flags |= NBS_FLAG_MUTE;
+ if (strchr(opts, 'o'))
+ flags |= NBS_FLAG_OVERSPEAK;
+ if (strchr(opts, 'e'))
+ flags |= NBS_FLAG_EMERGENCY;
+ if (strchr(opts, 'O'))
+ flags |= NBS_FLAG_OVERRIDE;
+ } else
+ flags = NBS_FLAG_OVERSPEAK;
+
+ strncpy(p->stream, stream, sizeof(p->stream) - 1);
+ p->nbs = nbs_newstream("asterisk", stream, flags);
+ if (!p->nbs) {
+ ast_log(LOG_WARNING, "Unable to allocate new NBS stream '%s' with flags %d\n", stream, flags);
+ free(p);
+ p = NULL;
+ } else {
+ /* Set for 8000 hz mono, 640 samples */
+ nbs_setbitrate(p->nbs, 8000);
+ nbs_setchannels(p->nbs, 1);
+ nbs_setblocksize(p->nbs, 640);
+ nbs_setblocking(p->nbs, 0);
+ }
+ }
+ return p;
+}
+
+static int nbs_hangup(struct ast_channel *ast)
+{
+ struct nbs_pvt *p;
+ p = ast->pvt->pvt;
+ if (option_debug)
+ ast_log(LOG_DEBUG, "nbs_hangup(%s)\n", ast->name);
+ if (!ast->pvt->pvt) {
+ ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
+ return 0;
+ }
+ nbs_destroy(p);
+ ast->pvt->pvt = NULL;
+ ast_setstate(ast, AST_STATE_DOWN);
+ return 0;
+}
+
+static struct ast_frame *nbs_read(struct ast_channel *ast)
+{
+ struct nbs_pvt *p = ast->pvt->pvt;
+
+
+ /* Some nice norms */
+ p->fr.datalen = 0;
+ p->fr.samples = 0;
+ p->fr.data = NULL;
+ p->fr.src = type;
+ p->fr.offset = 0;
+ p->fr.mallocd=0;
+
+ ast_log(LOG_DEBUG, "Returning null frame on %s\n", ast->name);
+
+ return &p->fr;
+}
+
+static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
+{
+ struct nbs_pvt *p = ast->pvt->pvt;
+ /* Write a frame of (presumably voice) data */
+ if (frame->frametype != AST_FRAME_VOICE) {
+ if (frame->frametype != AST_FRAME_IMAGE)
+ ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
+ return 0;
+ }
+ if (!(frame->subclass &
+ (AST_FORMAT_SLINEAR))) {
+ ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
+ return 0;
+ }
+ if (ast->_state != AST_STATE_UP) {
+ /* Don't try tos end audio on-hook */
+ return 0;
+ }
+ if (nbs_write(p->nbs, frame->data, frame->datalen / 2) < 0)
+ return -1;
+ return 0;
+}
+
+static struct ast_channel *nbs_new(struct nbs_pvt *i, int state)
+{
+ struct ast_channel *tmp;
+ tmp = ast_channel_alloc(1);
+ if (tmp) {
+ snprintf(tmp->name, sizeof(tmp->name), "NBS/%s", i->stream);
+ tmp->type = type;
+ tmp->fds[0] = nbs_fd(i->nbs);
+ tmp->nativeformats = prefformat;
+ tmp->pvt->rawreadformat = prefformat;
+ tmp->pvt->rawwriteformat = prefformat;
+ tmp->writeformat = prefformat;
+ tmp->readformat = prefformat;
+ ast_setstate(tmp, state);
+ if (state == AST_STATE_RING)
+ tmp->rings = 1;
+ tmp->pvt->pvt = i;
+ tmp->pvt->call = nbs_call;
+ tmp->pvt->hangup = nbs_hangup;
+ tmp->pvt->read = nbs_read;
+ tmp->pvt->write = nbs_xwrite;
+ strncpy(tmp->context, context, sizeof(tmp->context)-1);
+ strncpy(tmp->exten, "s", sizeof(tmp->exten) - 1);
+ strcpy(tmp->language, "");
+ i->owner = tmp;
+ ast_pthread_mutex_lock(&usecnt_lock);
+ usecnt++;
+ ast_pthread_mutex_unlock(&usecnt_lock);
+ ast_update_use_count();
+ if (state != AST_STATE_DOWN) {
+ if (ast_pbx_start(tmp)) {
+ ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
+ ast_hangup(tmp);
+ }
+ }
+ } else
+ ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
+ return tmp;
+}
+
+
+static struct ast_channel *nbs_request(char *type, int format, void *data)
+{
+ int oldformat;
+ struct nbs_pvt *p;
+ struct ast_channel *tmp = NULL;
+
+ oldformat = format;
+ format &= (AST_FORMAT_SLINEAR);
+ if (!format) {
+ ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
+ return NULL;
+ }
+ p = nbs_alloc(data);
+ tmp = nbs_new(p, AST_STATE_DOWN);
+ if (!tmp)
+ nbs_destroy(p);
+ return tmp;
+}
+
+int load_module()
+{
+ /* Make sure we can register our Adtranphone channel type */
+ if (ast_channel_register(type, tdesc,
+ AST_FORMAT_SLINEAR, nbs_request)) {
+ ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
+ unload_module();
+ return -1;
+ }
+ return 0;
+}
+
+
+
+int unload_module()
+{
+ /* First, take us out of the channel loop */
+ ast_channel_unregister(type);
+ return 0;
+}
+
+int usecount()
+{
+ int res;
+ ast_pthread_mutex_lock(&usecnt_lock);
+ res = usecnt;
+ ast_pthread_mutex_unlock(&usecnt_lock);
+ return res;
+}
+
+char *description()
+{
+ return desc;
+}
+
+char *key()
+{
+ return ASTERISK_GPL_KEY;
+}