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: 419592 $")
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 #include "asterisk/format_cache.h"
00051 
00052 static const char tdesc[] = "Network Broadcast Sound Driver";
00053 
00054 static char context[AST_MAX_EXTENSION] = "default";
00055 static const char type[] = "NBS";
00056 
00057 /* NBS creates private structures on demand */
00058    
00059 struct nbs_pvt {
00060    NBS *nbs;
00061    struct ast_channel *owner;    /* Channel we belong to, possibly NULL */
00062    char app[16];              /* Our app */
00063    char stream[80];           /* Our stream */
00064    struct ast_module_user *u;    /*! for holding a reference to this module */
00065 };
00066 
00067 static struct ast_channel *nbs_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
00068 static int nbs_call(struct ast_channel *ast, const char *dest, int timeout);
00069 static int nbs_hangup(struct ast_channel *ast);
00070 static struct ast_frame *nbs_xread(struct ast_channel *ast);
00071 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame);
00072 
00073 static struct ast_channel_tech nbs_tech = {
00074    .type = type,
00075    .description = tdesc,
00076    .requester = nbs_request,
00077    .call = nbs_call,
00078    .hangup = nbs_hangup,
00079    .read = nbs_xread,
00080    .write = nbs_xwrite,
00081 };
00082 
00083 static int nbs_call(struct ast_channel *ast, const char *dest, int timeout)
00084 {
00085    struct nbs_pvt *p;
00086 
00087    p = ast_channel_tech_pvt(ast);
00088 
00089    if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
00090       ast_log(LOG_WARNING, "nbs_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
00091       return -1;
00092    }
00093    /* When we call, it just works, really, there's no destination...  Just
00094       ring the phone and wait for someone to answer */
00095    ast_debug(1, "Calling %s on %s\n", dest, ast_channel_name(ast));
00096 
00097    /* If we can't connect, return congestion */
00098    if (nbs_connect(p->nbs)) {
00099       ast_log(LOG_WARNING, "NBS Connection failed on %s\n", ast_channel_name(ast));
00100       ast_queue_control(ast, AST_CONTROL_CONGESTION);
00101    } else {
00102       ast_setstate(ast, AST_STATE_RINGING);
00103       ast_queue_control(ast, AST_CONTROL_ANSWER);
00104    }
00105 
00106    return 0;
00107 }
00108 
00109 static void nbs_destroy(struct nbs_pvt *p)
00110 {
00111    if (p->nbs)
00112       nbs_delstream(p->nbs);
00113    ast_module_user_remove(p->u);
00114    ast_free(p);
00115 }
00116 
00117 static struct nbs_pvt *nbs_alloc(const char *data)
00118 {
00119    struct nbs_pvt *p;
00120    int flags = 0;
00121    char stream[256];
00122    char *opts;
00123 
00124    ast_copy_string(stream, data, sizeof(stream));
00125    if ((opts = strchr(stream, ':'))) {
00126       *opts = '\0';
00127       opts++;
00128    } else
00129       opts = "";
00130    p = ast_calloc(1, sizeof(*p));
00131    if (p) {
00132       if (!ast_strlen_zero(opts)) {
00133          if (strchr(opts, 'm'))
00134             flags |= NBS_FLAG_MUTE;
00135          if (strchr(opts, 'o'))
00136             flags |= NBS_FLAG_OVERSPEAK;
00137          if (strchr(opts, 'e'))
00138             flags |= NBS_FLAG_EMERGENCY;
00139          if (strchr(opts, 'O'))
00140             flags |= NBS_FLAG_OVERRIDE;
00141       } else
00142          flags = NBS_FLAG_OVERSPEAK;
00143       
00144       ast_copy_string(p->stream, stream, sizeof(p->stream));
00145       p->nbs = nbs_newstream("asterisk", stream, flags);
00146       if (!p->nbs) {
00147          ast_log(LOG_WARNING, "Unable to allocate new NBS stream '%s' with flags %d\n", stream, flags);
00148          ast_free(p);
00149          p = NULL;
00150       } else {
00151          /* Set for 8000 hz mono, 640 samples */
00152          nbs_setbitrate(p->nbs, 8000);
00153          nbs_setchannels(p->nbs, 1);
00154          nbs_setblocksize(p->nbs, 640);
00155          nbs_setblocking(p->nbs, 0);
00156       }
00157    }
00158    return p;
00159 }
00160 
00161 static int nbs_hangup(struct ast_channel *ast)
00162 {
00163    struct nbs_pvt *p;
00164    p = ast_channel_tech_pvt(ast);
00165    ast_debug(1, "nbs_hangup(%s)\n", ast_channel_name(ast));
00166    if (!ast_channel_tech_pvt(ast)) {
00167       ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
00168       return 0;
00169    }
00170    nbs_destroy(p);
00171    ast_channel_tech_pvt_set(ast, NULL);
00172    ast_setstate(ast, AST_STATE_DOWN);
00173    return 0;
00174 }
00175 
00176 static struct ast_frame  *nbs_xread(struct ast_channel *ast)
00177 {
00178    ast_debug(1, "Returning null frame on %s\n", ast_channel_name(ast));
00179 
00180    return &ast_null_frame;
00181 }
00182 
00183 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
00184 {
00185    struct nbs_pvt *p = ast_channel_tech_pvt(ast);
00186    if (ast_channel_state(ast) != AST_STATE_UP) {
00187       /* Don't try tos end audio on-hook */
00188       return 0;
00189    }
00190    if (nbs_write(p->nbs, frame->data.ptr, frame->datalen / 2) < 0) 
00191       return -1;
00192    return 0;
00193 }
00194 
00195 static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
00196 {
00197    struct ast_channel *tmp;
00198    tmp = ast_channel_alloc(1, state, 0, 0, "", "s", context, assignedids, requestor, 0, "NBS/%s", i->stream);
00199    if (tmp) {
00200       ast_channel_tech_set(tmp, &nbs_tech);
00201       ast_channel_set_fd(tmp, 0, nbs_fd(i->nbs));
00202 
00203       ast_channel_nativeformats_set(tmp, nbs_tech.capabilities);
00204       ast_channel_set_rawreadformat(tmp, ast_format_slin);
00205       ast_channel_set_rawwriteformat(tmp, ast_format_slin);
00206       ast_channel_set_writeformat(tmp, ast_format_slin);
00207       ast_channel_set_readformat(tmp, ast_format_slin);
00208       if (state == AST_STATE_RING)
00209          ast_channel_rings_set(tmp, 1);
00210       ast_channel_tech_pvt_set(tmp, i);
00211       ast_channel_context_set(tmp, context);
00212       ast_channel_exten_set(tmp, "s");
00213       ast_channel_language_set(tmp, "");
00214       i->owner = tmp;
00215       i->u = ast_module_user_add(tmp);
00216       ast_channel_unlock(tmp);
00217       if (state != AST_STATE_DOWN) {
00218          if (ast_pbx_start(tmp)) {
00219             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
00220             ast_hangup(tmp);
00221          }
00222       }
00223    } else
00224       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
00225    return tmp;
00226 }
00227 
00228 
00229 static struct ast_channel *nbs_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
00230 {
00231    struct nbs_pvt *p;
00232    struct ast_channel *tmp = NULL;
00233 
00234    if (ast_format_cap_iscompatible_format(cap, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) {
00235       struct ast_str *cap_buf = ast_str_alloca(64);
00236 
00237       ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n",
00238          ast_format_cap_get_names(cap, &cap_buf));
00239       return NULL;
00240    }
00241    p = nbs_alloc(data);
00242    if (p) {
00243       tmp = nbs_new(p, AST_STATE_DOWN, assignedids, requestor);
00244       if (!tmp)
00245          nbs_destroy(p);
00246    }
00247    return tmp;
00248 }
00249 
00250 static int unload_module(void)
00251 {
00252    /* First, take us out of the channel loop */
00253    ast_channel_unregister(&nbs_tech);
00254    ao2_ref(nbs_tech.capabilities, -1);
00255    nbs_tech.capabilities = NULL;
00256    return 0;
00257 }
00258 
00259 static int load_module(void)
00260 {
00261    if (!(nbs_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
00262       return AST_MODULE_LOAD_FAILURE;
00263    }
00264    ast_format_cap_append(nbs_tech.capabilities, ast_format_slin, 0);
00265    /* Make sure we can register our channel type */
00266    if (ast_channel_register(&nbs_tech)) {
00267       ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
00268       return AST_MODULE_LOAD_DECLINE;
00269    }
00270    return AST_MODULE_LOAD_SUCCESS;
00271 }
00272 
00273 AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Network Broadcast Sound Support");
00274 

Generated on Thu Apr 16 06:27:23 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6