![]() |
Home page |
Mailing list |
Docs
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");