Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:37 2007

Asterisk developer's documentation :: Codename Pineapple


chan_nbs.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Network broadcast sound support channel driver
00022  * 
00023  * \author Mark Spencer <markster@digium.com>
00024  *
00025  * \ingroup channel_drivers
00026  */
00027 
00028 /*** MODULEINFO
00029    <depend>nbs</depend>
00030  ***/
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 47362 $")
00035 
00036 #include <stdio.h>
00037 #include <string.h>
00038 #include <sys/socket.h>
00039 #include <sys/time.h>
00040 #include <errno.h>
00041 #include <unistd.h>
00042 #include <stdlib.h>
00043 #include <arpa/inet.h>
00044 #include <fcntl.h>
00045 #include <sys/ioctl.h>
00046 #include <nbs.h>
00047 
00048 #include "asterisk/lock.h"
00049 #include "asterisk/channel.h"
00050 #include "asterisk/config.h"
00051 #include "asterisk/logger.h"
00052 #include "asterisk/module.h"
00053 #include "asterisk/pbx.h"
00054 #include "asterisk/options.h"
00055 #include "asterisk/utils.h"
00056 
00057 static const char tdesc[] = "Network Broadcast Sound Driver";
00058 
00059 /* Only linear is allowed */
00060 static int prefformat = AST_FORMAT_SLINEAR;
00061 
00062 static char context[AST_MAX_EXTENSION] = "default";
00063 static char type[] = "NBS";
00064 
00065 /* NBS creates private structures on demand */
00066    
00067 struct nbs_pvt {
00068    NBS *nbs;
00069    struct ast_channel *owner;    /* Channel we belong to, possibly NULL */
00070    char app[16];              /* Our app */
00071    char stream[80];           /* Our stream */
00072    struct ast_frame fr;       /* "null" frame */
00073    struct ast_module_user *u;    /*! for holding a reference to this module */
00074 };
00075 
00076 static struct ast_channel *nbs_request(const char *type, int format, void *data, int *cause);
00077 static int nbs_call(struct ast_channel *ast, char *dest, int timeout);
00078 static int nbs_hangup(struct ast_channel *ast);
00079 static struct ast_frame *nbs_xread(struct ast_channel *ast);
00080 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame);
00081 
00082 static const struct ast_channel_tech nbs_tech = {
00083    .type = type,
00084    .description = tdesc,
00085    .capabilities = AST_FORMAT_SLINEAR,
00086    .requester = nbs_request,
00087    .call = nbs_call,
00088    .hangup = nbs_hangup,
00089    .read = nbs_xread,
00090    .write = nbs_xwrite,
00091 };
00092 
00093 static int nbs_call(struct ast_channel *ast, char *dest, int timeout)
00094 {
00095    struct nbs_pvt *p;
00096 
00097    p = ast->tech_pvt;
00098 
00099    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
00100       ast_log(LOG_WARNING, "nbs_call called on %s, neither down nor reserved\n", ast->name);
00101       return -1;
00102    }
00103    /* When we call, it just works, really, there's no destination...  Just
00104       ring the phone and wait for someone to answer */
00105    if (option_debug)
00106       ast_log(LOG_DEBUG, "Calling %s on %s\n", dest, ast->name);
00107 
00108    /* If we can't connect, return congestion */
00109    if (nbs_connect(p->nbs)) {
00110       ast_log(LOG_WARNING, "NBS Connection failed on %s\n", ast->name);
00111       ast_queue_control(ast, AST_CONTROL_CONGESTION);
00112    } else {
00113       ast_setstate(ast, AST_STATE_RINGING);
00114       ast_queue_control(ast, AST_CONTROL_ANSWER);
00115    }
00116 
00117    return 0;
00118 }
00119 
00120 static void nbs_destroy(struct nbs_pvt *p)
00121 {
00122    if (p->nbs)
00123       nbs_delstream(p->nbs);
00124    ast_module_user_remove(p->u);
00125    free(p);
00126 }
00127 
00128 static struct nbs_pvt *nbs_alloc(void *data)
00129 {
00130    struct nbs_pvt *p;
00131    int flags = 0;
00132    char stream[256];
00133    char *opts;
00134 
00135    ast_copy_string(stream, data, sizeof(stream));
00136    if ((opts = strchr(stream, ':'))) {
00137       *opts = '\0';
00138       opts++;
00139    } else
00140       opts = "";
00141    p = malloc(sizeof(struct nbs_pvt));
00142    if (p) {
00143       memset(p, 0, sizeof(struct nbs_pvt));
00144       if (!ast_strlen_zero(opts)) {
00145          if (strchr(opts, 'm'))
00146             flags |= NBS_FLAG_MUTE;
00147          if (strchr(opts, 'o'))
00148             flags |= NBS_FLAG_OVERSPEAK;
00149          if (strchr(opts, 'e'))
00150             flags |= NBS_FLAG_EMERGENCY;
00151          if (strchr(opts, 'O'))
00152             flags |= NBS_FLAG_OVERRIDE;
00153       } else
00154          flags = NBS_FLAG_OVERSPEAK;
00155       
00156       ast_copy_string(p->stream, stream, sizeof(p->stream));
00157       p->nbs = nbs_newstream("asterisk", stream, flags);
00158       if (!p->nbs) {
00159          ast_log(LOG_WARNING, "Unable to allocate new NBS stream '%s' with flags %d\n", stream, flags);
00160          free(p);
00161          p = NULL;
00162       } else {
00163          /* Set for 8000 hz mono, 640 samples */
00164          nbs_setbitrate(p->nbs, 8000);
00165          nbs_setchannels(p->nbs, 1);
00166          nbs_setblocksize(p->nbs, 640);
00167          nbs_setblocking(p->nbs, 0);
00168       }
00169    }
00170    return p;
00171 }
00172 
00173 static int nbs_hangup(struct ast_channel *ast)
00174 {
00175    struct nbs_pvt *p;
00176    p = ast->tech_pvt;
00177    if (option_debug)
00178       ast_log(LOG_DEBUG, "nbs_hangup(%s)\n", ast->name);
00179    if (!ast->tech_pvt) {
00180       ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
00181       return 0;
00182    }
00183    nbs_destroy(p);
00184    ast->tech_pvt = NULL;
00185    ast_setstate(ast, AST_STATE_DOWN);
00186    return 0;
00187 }
00188 
00189 static struct ast_frame  *nbs_xread(struct ast_channel *ast)
00190 {
00191    struct nbs_pvt *p = ast->tech_pvt;
00192    
00193 
00194    /* Some nice norms */
00195    p->fr.datalen = 0;
00196    p->fr.samples = 0;
00197    p->fr.data =  NULL;
00198    p->fr.src = type;
00199    p->fr.offset = 0;
00200    p->fr.mallocd=0;
00201    p->fr.delivery.tv_sec = 0;
00202    p->fr.delivery.tv_usec = 0;
00203 
00204    if (option_debug)
00205       ast_log(LOG_DEBUG, "Returning null frame on %s\n", ast->name);
00206 
00207    return &p->fr;
00208 }
00209 
00210 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
00211 {
00212    struct nbs_pvt *p = ast->tech_pvt;
00213    /* Write a frame of (presumably voice) data */
00214    if (frame->frametype != AST_FRAME_VOICE) {
00215       if (frame->frametype != AST_FRAME_IMAGE)
00216          ast_log(LOG_WARNING, "Don't know what to do with  frame type '%d'\n", frame->frametype);
00217       return 0;
00218    }
00219    if (!(frame->subclass &
00220       (AST_FORMAT_SLINEAR))) {
00221       ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
00222       return 0;
00223    }
00224    if (ast->_state != AST_STATE_UP) {
00225       /* Don't try tos end audio on-hook */
00226       return 0;
00227    }
00228    if (nbs_write(p->nbs, frame->data, frame->datalen / 2) < 0) 
00229       return -1;
00230    return 0;
00231 }
00232 
00233 static struct ast_channel *nbs_new(struct nbs_pvt *i, int state)
00234 {
00235    struct ast_channel *tmp;
00236    tmp = ast_channel_alloc(1, state, 0, 0, "NBS/%s", i->stream);
00237    if (tmp) {
00238       tmp->tech = &nbs_tech;
00239       tmp->fds[0] = nbs_fd(i->nbs);
00240       tmp->nativeformats = prefformat;
00241       tmp->rawreadformat = prefformat;
00242       tmp->rawwriteformat = prefformat;
00243       tmp->writeformat = prefformat;
00244       tmp->readformat = prefformat;
00245       if (state == AST_STATE_RING)
00246          tmp->rings = 1;
00247       tmp->tech_pvt = i;
00248       ast_copy_string(tmp->context, context, sizeof(tmp->context));
00249       ast_copy_string(tmp->exten, "s",  sizeof(tmp->exten));
00250       ast_string_field_set(tmp, language, "");
00251       i->owner = tmp;
00252       i->u = ast_module_user_add(tmp);
00253       if (state != AST_STATE_DOWN) {
00254          if (ast_pbx_start(tmp)) {
00255             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
00256             ast_hangup(tmp);
00257          }
00258       }
00259    } else
00260       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
00261    return tmp;
00262 }
00263 
00264 
00265 static struct ast_channel *nbs_request(const char *type, int format, void *data, int *cause)
00266 {
00267    int oldformat;
00268    struct nbs_pvt *p;
00269    struct ast_channel *tmp = NULL;
00270    
00271    oldformat = format;
00272    format &= (AST_FORMAT_SLINEAR);
00273    if (!format) {
00274       ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
00275       return NULL;
00276    }
00277    p = nbs_alloc(data);
00278    if (p) {
00279       tmp = nbs_new(p, AST_STATE_DOWN);
00280       if (!tmp)
00281          nbs_destroy(p);
00282    }
00283    return tmp;
00284 }
00285 
00286 static int unload_module(void)
00287 {
00288    /* First, take us out of the channel loop */
00289    ast_channel_unregister(&nbs_tech);
00290    return 0;
00291 }
00292 
00293 static int load_module(void)
00294 {
00295    /* Make sure we can register our channel type */
00296    if (ast_channel_register(&nbs_tech)) {
00297       ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
00298       return -1;
00299    }
00300    return 0;
00301 }
00302 
00303 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Network Broadcast Sound Support");

Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen