Sat Apr 26 2014 22:01:32

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: 356573 $")
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 struct ast_format prefformat;
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, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
00071 static int nbs_call(struct ast_channel *ast, const 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 struct ast_channel_tech nbs_tech = {
00077    .type = type,
00078    .description = tdesc,
00079    .requester = nbs_request,
00080    .call = nbs_call,
00081    .hangup = nbs_hangup,
00082    .read = nbs_xread,
00083    .write = nbs_xwrite,
00084 };
00085 
00086 static int nbs_call(struct ast_channel *ast, const char *dest, int timeout)
00087 {
00088    struct nbs_pvt *p;
00089 
00090    p = ast_channel_tech_pvt(ast);
00091 
00092    if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
00093       ast_log(LOG_WARNING, "nbs_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
00094       return -1;
00095    }
00096    /* When we call, it just works, really, there's no destination...  Just
00097       ring the phone and wait for someone to answer */
00098    ast_debug(1, "Calling %s on %s\n", dest, ast_channel_name(ast));
00099 
00100    /* If we can't connect, return congestion */
00101    if (nbs_connect(p->nbs)) {
00102       ast_log(LOG_WARNING, "NBS Connection failed on %s\n", ast_channel_name(ast));
00103       ast_queue_control(ast, AST_CONTROL_CONGESTION);
00104    } else {
00105       ast_setstate(ast, AST_STATE_RINGING);
00106       ast_queue_control(ast, AST_CONTROL_ANSWER);
00107    }
00108 
00109    return 0;
00110 }
00111 
00112 static void nbs_destroy(struct nbs_pvt *p)
00113 {
00114    if (p->nbs)
00115       nbs_delstream(p->nbs);
00116    ast_module_user_remove(p->u);
00117    ast_free(p);
00118 }
00119 
00120 static struct nbs_pvt *nbs_alloc(const char *data)
00121 {
00122    struct nbs_pvt *p;
00123    int flags = 0;
00124    char stream[256];
00125    char *opts;
00126 
00127    ast_copy_string(stream, data, sizeof(stream));
00128    if ((opts = strchr(stream, ':'))) {
00129       *opts = '\0';
00130       opts++;
00131    } else
00132       opts = "";
00133    p = ast_calloc(1, sizeof(*p));
00134    if (p) {
00135       if (!ast_strlen_zero(opts)) {
00136          if (strchr(opts, 'm'))
00137             flags |= NBS_FLAG_MUTE;
00138          if (strchr(opts, 'o'))
00139             flags |= NBS_FLAG_OVERSPEAK;
00140          if (strchr(opts, 'e'))
00141             flags |= NBS_FLAG_EMERGENCY;
00142          if (strchr(opts, 'O'))
00143             flags |= NBS_FLAG_OVERRIDE;
00144       } else
00145          flags = NBS_FLAG_OVERSPEAK;
00146       
00147       ast_copy_string(p->stream, stream, sizeof(p->stream));
00148       p->nbs = nbs_newstream("asterisk", stream, flags);
00149       if (!p->nbs) {
00150          ast_log(LOG_WARNING, "Unable to allocate new NBS stream '%s' with flags %d\n", stream, flags);
00151          ast_free(p);
00152          p = NULL;
00153       } else {
00154          /* Set for 8000 hz mono, 640 samples */
00155          nbs_setbitrate(p->nbs, 8000);
00156          nbs_setchannels(p->nbs, 1);
00157          nbs_setblocksize(p->nbs, 640);
00158          nbs_setblocking(p->nbs, 0);
00159       }
00160    }
00161    return p;
00162 }
00163 
00164 static int nbs_hangup(struct ast_channel *ast)
00165 {
00166    struct nbs_pvt *p;
00167    p = ast_channel_tech_pvt(ast);
00168    ast_debug(1, "nbs_hangup(%s)\n", ast_channel_name(ast));
00169    if (!ast_channel_tech_pvt(ast)) {
00170       ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
00171       return 0;
00172    }
00173    nbs_destroy(p);
00174    ast_channel_tech_pvt_set(ast, NULL);
00175    ast_setstate(ast, AST_STATE_DOWN);
00176    return 0;
00177 }
00178 
00179 static struct ast_frame  *nbs_xread(struct ast_channel *ast)
00180 {
00181    struct nbs_pvt *p = ast_channel_tech_pvt(ast);
00182    
00183 
00184    /* Some nice norms */
00185    p->fr.datalen = 0;
00186    p->fr.samples = 0;
00187    p->fr.data.ptr =  NULL;
00188    p->fr.src = type;
00189    p->fr.offset = 0;
00190    p->fr.mallocd=0;
00191    p->fr.delivery.tv_sec = 0;
00192    p->fr.delivery.tv_usec = 0;
00193 
00194    ast_debug(1, "Returning null frame on %s\n", ast_channel_name(ast));
00195 
00196    return &p->fr;
00197 }
00198 
00199 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
00200 {
00201    struct nbs_pvt *p = ast_channel_tech_pvt(ast);
00202    /* Write a frame of (presumably voice) data */
00203    if (frame->frametype != AST_FRAME_VOICE) {
00204       if (frame->frametype != AST_FRAME_IMAGE)
00205          ast_log(LOG_WARNING, "Don't know what to do with  frame type '%d'\n", frame->frametype);
00206       return 0;
00207    }
00208    if (frame->subclass.format.id != (AST_FORMAT_SLINEAR)) {
00209       ast_log(LOG_WARNING, "Cannot handle frames in %s format\n", ast_getformatname(&frame->subclass.format));
00210       return 0;
00211    }
00212    if (ast_channel_state(ast) != AST_STATE_UP) {
00213       /* Don't try tos end audio on-hook */
00214       return 0;
00215    }
00216    if (nbs_write(p->nbs, frame->data.ptr, frame->datalen / 2) < 0) 
00217       return -1;
00218    return 0;
00219 }
00220 
00221 static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const char *linkedid)
00222 {
00223    struct ast_channel *tmp;
00224    tmp = ast_channel_alloc(1, state, 0, 0, "", "s", context, linkedid, 0, "NBS/%s", i->stream);
00225    if (tmp) {
00226       ast_channel_tech_set(tmp, &nbs_tech);
00227       ast_channel_set_fd(tmp, 0, nbs_fd(i->nbs));
00228 
00229       ast_format_cap_add(ast_channel_nativeformats(tmp), &prefformat);
00230       ast_format_copy(ast_channel_rawreadformat(tmp), &prefformat);
00231       ast_format_copy(ast_channel_rawwriteformat(tmp), &prefformat);
00232       ast_format_copy(ast_channel_writeformat(tmp), &prefformat);
00233       ast_format_copy(ast_channel_readformat(tmp), &prefformat);
00234       if (state == AST_STATE_RING)
00235          ast_channel_rings_set(tmp, 1);
00236       ast_channel_tech_pvt_set(tmp, i);
00237       ast_channel_context_set(tmp, context);
00238       ast_channel_exten_set(tmp, "s");
00239       ast_channel_language_set(tmp, "");
00240       i->owner = tmp;
00241       i->u = ast_module_user_add(tmp);
00242       if (state != AST_STATE_DOWN) {
00243          if (ast_pbx_start(tmp)) {
00244             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
00245             ast_hangup(tmp);
00246          }
00247       }
00248    } else
00249       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
00250    return tmp;
00251 }
00252 
00253 
00254 static struct ast_channel *nbs_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
00255 {
00256    struct nbs_pvt *p;
00257    struct ast_channel *tmp = NULL;
00258 
00259    if (!(ast_format_cap_iscompatible(cap, &prefformat))) {
00260       char tmp[256];
00261       ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap));
00262       return NULL;
00263    }
00264    p = nbs_alloc(data);
00265    if (p) {
00266       tmp = nbs_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
00267       if (!tmp)
00268          nbs_destroy(p);
00269    }
00270    return tmp;
00271 }
00272 
00273 static int unload_module(void)
00274 {
00275    /* First, take us out of the channel loop */
00276    ast_channel_unregister(&nbs_tech);
00277    nbs_tech.capabilities = ast_format_cap_destroy(nbs_tech.capabilities);
00278    return 0;
00279 }
00280 
00281 static int load_module(void)
00282 {
00283    ast_format_set(&prefformat, AST_FORMAT_SLINEAR, 0);
00284    if (!(nbs_tech.capabilities = ast_format_cap_alloc())) {
00285       return AST_MODULE_LOAD_FAILURE;
00286    }
00287    ast_format_cap_add(nbs_tech.capabilities, &prefformat);
00288    /* Make sure we can register our channel type */
00289    if (ast_channel_register(&nbs_tech)) {
00290       ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
00291       return AST_MODULE_LOAD_DECLINE;
00292    }
00293    return AST_MODULE_LOAD_SUCCESS;
00294 }
00295 
00296 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Network Broadcast Sound Support");