Sat Mar 10 01:54:10 2012

Asterisk developer's documentation


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    <support_level>extended</support_level>   
00031  ***/
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00036 
00037 #include <sys/socket.h>
00038 #include <sys/time.h>
00039 #include <arpa/inet.h>
00040 #include <fcntl.h>
00041 #include <sys/ioctl.h>
00042 #include <nbs.h>
00043 
00044 #include "asterisk/lock.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/config.h"
00047 #include "asterisk/module.h"
00048 #include "asterisk/pbx.h"
00049 #include "asterisk/utils.h"
00050 
00051 static const char tdesc[] = "Network Broadcast Sound Driver";
00052 
00053 /* Only linear is allowed */
00054 static format_t prefformat = AST_FORMAT_SLINEAR;
00055 
00056 static char context[AST_MAX_EXTENSION] = "default";
00057 static const char type[] = "NBS";
00058 
00059 /* NBS creates private structures on demand */
00060    
00061 struct nbs_pvt {
00062    NBS *nbs;
00063    struct ast_channel *owner;    /* Channel we belong to, possibly NULL */
00064    char app[16];              /* Our app */
00065    char stream[80];           /* Our stream */
00066    struct ast_frame fr;       /* "null" frame */
00067    struct ast_module_user *u;    /*! for holding a reference to this module */
00068 };
00069 
00070 static struct ast_channel *nbs_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause);
00071 static int nbs_call(struct ast_channel *ast, char *dest, int timeout);
00072 static int nbs_hangup(struct ast_channel *ast);
00073 static struct ast_frame *nbs_xread(struct ast_channel *ast);
00074 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame);
00075 
00076 static const struct ast_channel_tech nbs_tech = {
00077    .type = type,
00078    .description = tdesc,
00079    .capabilities = AST_FORMAT_SLINEAR,
00080    .requester = nbs_request,
00081    .call = nbs_call,
00082    .hangup = nbs_hangup,
00083    .read = nbs_xread,
00084    .write = nbs_xwrite,
00085 };
00086 
00087 static int nbs_call(struct ast_channel *ast, char *dest, int timeout)
00088 {
00089    struct nbs_pvt *p;
00090 
00091    p = ast->tech_pvt;
00092 
00093    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
00094       ast_log(LOG_WARNING, "nbs_call called on %s, neither down nor reserved\n", ast->name);
00095       return -1;
00096    }
00097    /* When we call, it just works, really, there's no destination...  Just
00098       ring the phone and wait for someone to answer */
00099    ast_debug(1, "Calling %s on %s\n", dest, ast->name);
00100 
00101    /* If we can't connect, return congestion */
00102    if (nbs_connect(p->nbs)) {
00103       ast_log(LOG_WARNING, "NBS Connection failed on %s\n", ast->name);
00104       ast_queue_control(ast, AST_CONTROL_CONGESTION);
00105    } else {
00106       ast_setstate(ast, AST_STATE_RINGING);
00107       ast_queue_control(ast, AST_CONTROL_ANSWER);
00108    }
00109 
00110    return 0;
00111 }
00112 
00113 static void nbs_destroy(struct nbs_pvt *p)
00114 {
00115    if (p->nbs)
00116       nbs_delstream(p->nbs);
00117    ast_module_user_remove(p->u);
00118    ast_free(p);
00119 }
00120 
00121 static struct nbs_pvt *nbs_alloc(void *data)
00122 {
00123    struct nbs_pvt *p;
00124    int flags = 0;
00125    char stream[256];
00126    char *opts;
00127 
00128    ast_copy_string(stream, data, sizeof(stream));
00129    if ((opts = strchr(stream, ':'))) {
00130       *opts = '\0';
00131       opts++;
00132    } else
00133       opts = "";
00134    p = ast_calloc(1, sizeof(*p));
00135    if (p) {
00136       if (!ast_strlen_zero(opts)) {
00137          if (strchr(opts, 'm'))
00138             flags |= NBS_FLAG_MUTE;
00139          if (strchr(opts, 'o'))
00140             flags |= NBS_FLAG_OVERSPEAK;
00141          if (strchr(opts, 'e'))
00142             flags |= NBS_FLAG_EMERGENCY;
00143          if (strchr(opts, 'O'))
00144             flags |= NBS_FLAG_OVERRIDE;
00145       } else
00146          flags = NBS_FLAG_OVERSPEAK;
00147       
00148       ast_copy_string(p->stream, stream, sizeof(p->stream));
00149       p->nbs = nbs_newstream("asterisk", stream, flags);
00150       if (!p->nbs) {
00151          ast_log(LOG_WARNING, "Unable to allocate new NBS stream '%s' with flags %d\n", stream, flags);
00152          ast_free(p);
00153          p = NULL;
00154       } else {
00155          /* Set for 8000 hz mono, 640 samples */
00156          nbs_setbitrate(p->nbs, 8000);
00157          nbs_setchannels(p->nbs, 1);
00158          nbs_setblocksize(p->nbs, 640);
00159          nbs_setblocking(p->nbs, 0);
00160       }
00161    }
00162    return p;
00163 }
00164 
00165 static int nbs_hangup(struct ast_channel *ast)
00166 {
00167    struct nbs_pvt *p;
00168    p = ast->tech_pvt;
00169    ast_debug(1, "nbs_hangup(%s)\n", ast->name);
00170    if (!ast->tech_pvt) {
00171       ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
00172       return 0;
00173    }
00174    nbs_destroy(p);
00175    ast->tech_pvt = NULL;
00176    ast_setstate(ast, AST_STATE_DOWN);
00177    return 0;
00178 }
00179 
00180 static struct ast_frame  *nbs_xread(struct ast_channel *ast)
00181 {
00182    struct nbs_pvt *p = ast->tech_pvt;
00183    
00184 
00185    /* Some nice norms */
00186    p->fr.datalen = 0;
00187    p->fr.samples = 0;
00188    p->fr.data.ptr =  NULL;
00189    p->fr.src = type;
00190    p->fr.offset = 0;
00191    p->fr.mallocd=0;
00192    p->fr.delivery.tv_sec = 0;
00193    p->fr.delivery.tv_usec = 0;
00194 
00195    ast_debug(1, "Returning null frame on %s\n", ast->name);
00196 
00197    return &p->fr;
00198 }
00199 
00200 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
00201 {
00202    struct nbs_pvt *p = ast->tech_pvt;
00203    /* Write a frame of (presumably voice) data */
00204    if (frame->frametype != AST_FRAME_VOICE) {
00205       if (frame->frametype != AST_FRAME_IMAGE)
00206          ast_log(LOG_WARNING, "Don't know what to do with  frame type '%d'\n", frame->frametype);
00207       return 0;
00208    }
00209    if (!(frame->subclass.codec &
00210       (AST_FORMAT_SLINEAR))) {
00211       ast_log(LOG_WARNING, "Cannot handle frames in %s format\n", ast_getformatname(frame->subclass.codec));
00212       return 0;
00213    }
00214    if (ast->_state != AST_STATE_UP) {
00215       /* Don't try tos end audio on-hook */
00216       return 0;
00217    }
00218    if (nbs_write(p->nbs, frame->data.ptr, frame->datalen / 2) < 0) 
00219       return -1;
00220    return 0;
00221 }
00222 
00223 static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const char *linkedid)
00224 {
00225    struct ast_channel *tmp;
00226    tmp = ast_channel_alloc(1, state, 0, 0, "", "s", context, linkedid, 0, "NBS/%s", i->stream);
00227    if (tmp) {
00228       tmp->tech = &nbs_tech;
00229       ast_channel_set_fd(tmp, 0, nbs_fd(i->nbs));
00230       tmp->nativeformats = prefformat;
00231       tmp->rawreadformat = prefformat;
00232       tmp->rawwriteformat = prefformat;
00233       tmp->writeformat = prefformat;
00234       tmp->readformat = prefformat;
00235       if (state == AST_STATE_RING)
00236          tmp->rings = 1;
00237       tmp->tech_pvt = i;
00238       ast_copy_string(tmp->context, context, sizeof(tmp->context));
00239       ast_copy_string(tmp->exten, "s",  sizeof(tmp->exten));
00240       ast_string_field_set(tmp, language, "");
00241       i->owner = tmp;
00242       i->u = ast_module_user_add(tmp);
00243       if (state != AST_STATE_DOWN) {
00244          if (ast_pbx_start(tmp)) {
00245             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
00246             ast_hangup(tmp);
00247          }
00248       }
00249    } else
00250       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
00251    return tmp;
00252 }
00253 
00254 
00255 static struct ast_channel *nbs_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
00256 {
00257    format_t oldformat;
00258    struct nbs_pvt *p;
00259    struct ast_channel *tmp = NULL;
00260    
00261    oldformat = format;
00262    format &= (AST_FORMAT_SLINEAR);
00263    if (!format) {
00264       ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname(oldformat));
00265       return NULL;
00266    }
00267    p = nbs_alloc(data);
00268    if (p) {
00269       tmp = nbs_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
00270       if (!tmp)
00271          nbs_destroy(p);
00272    }
00273    return tmp;
00274 }
00275 
00276 static int unload_module(void)
00277 {
00278    /* First, take us out of the channel loop */
00279    ast_channel_unregister(&nbs_tech);
00280    return 0;
00281 }
00282 
00283 static int load_module(void)
00284 {
00285    /* Make sure we can register our channel type */
00286    if (ast_channel_register(&nbs_tech)) {
00287       ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
00288       return -1;
00289    }
00290    return 0;
00291 }
00292 
00293 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Network Broadcast Sound Support");

Generated on Sat Mar 10 01:54:10 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7