#include "asterisk.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <linux/telephony.h>
#include <linux/version.h>
#include <linux/ixjuser.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/callerid.h"
#include "asterisk/causes.h"
#include "asterisk/stringfields.h"
#include "asterisk/musiconhold.h"
#include "DialTone.h"
Go to the source code of this file.
Data Structures | |
struct | phone_pvt |
Defines | |
#define | DEFAULT_CALLER_ID "Unknown" |
#define | DEFAULT_GAIN 0x100 |
#define | IXJ_PHONE_RING_START(x) ioctl(p->fd, PHONE_RING_START, &x); |
#define | MODE_DIALTONE 1 |
#define | MODE_FXO 3 |
#define | MODE_FXS 4 |
#define | MODE_IMMEDIATE 2 |
#define | MODE_SIGMA 5 |
#define | PHONE_MAX_BUF 480 |
#define | QNDRV_VER 100 |
Functions | |
static void | __reg_module (void) |
static int | __unload_module (void) |
static void | __unreg_module (void) |
static void * | do_monitor (void *data) |
static int | load_module (void) |
static struct phone_pvt * | mkif (char *iface, int mode, int txgain, int rxgain) |
static int | parse_gain_value (char *gain_type, char *value) |
static int | phone_answer (struct ast_channel *ast) |
static int | phone_call (struct ast_channel *ast, char *dest, int timeout) |
static void | phone_check_exception (struct phone_pvt *i) |
static int | phone_digit_begin (struct ast_channel *ast, char digit) |
static int | phone_digit_end (struct ast_channel *ast, char digit, unsigned int duration) |
static struct ast_frame * | phone_exception (struct ast_channel *ast) |
static int | phone_fixup (struct ast_channel *old, struct ast_channel *new) |
static int | phone_hangup (struct ast_channel *ast) |
static int | phone_indicate (struct ast_channel *chan, int condition, const void *data, size_t datalen) |
static void | phone_mini_packet (struct phone_pvt *i) |
static struct ast_channel * | phone_new (struct phone_pvt *i, int state, char *context) |
static struct ast_frame * | phone_read (struct ast_channel *ast) |
static struct ast_channel * | phone_request (const char *type, int format, void *data, int *cause) |
static int | phone_send_text (struct ast_channel *ast, const char *text) |
static int | phone_setup (struct ast_channel *ast) |
static int | phone_write (struct ast_channel *ast, struct ast_frame *frame) |
static int | phone_write_buf (struct phone_pvt *p, const char *buf, int len, int frlen, int swap) |
static int | restart_monitor (void) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Linux Telephony API Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static char | cid_name [AST_MAX_EXTENSION] |
static char | cid_num [AST_MAX_EXTENSION] |
static const char | config [] = "phone.conf" |
static char | context [AST_MAX_EXTENSION] = "default" |
static struct ast_channel_tech * | cur_tech |
static int | echocancel = AEC_OFF |
static struct phone_pvt * | iflist |
static ast_mutex_t | iflock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) |
static char | language [MAX_LANGUAGE] = "" |
static unsigned int | monitor |
static pthread_t | monitor_thread = AST_PTHREADT_NULL |
static ast_mutex_t | monlock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) |
static struct ast_channel_tech | phone_tech |
static struct ast_channel_tech | phone_tech_fxs |
static int | prefformat = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW |
static int | silencesupression = 0 |
static const char | tdesc [] = "Standard Linux Telephony API Driver" |
Definition in file chan_phone.c.
#define DEFAULT_CALLER_ID "Unknown" |
#define DEFAULT_GAIN 0x100 |
#define IXJ_PHONE_RING_START | ( | x | ) | ioctl(p->fd, PHONE_RING_START, &x); |
#define MODE_DIALTONE 1 |
Definition at line 125 of file chan_phone.c.
Referenced by load_module(), and phone_check_exception().
#define MODE_FXO 3 |
Definition at line 127 of file chan_phone.c.
Referenced by load_module(), mkif(), phone_answer(), phone_exception(), and phone_hangup().
#define MODE_FXS 4 |
Definition at line 128 of file chan_phone.c.
Referenced by load_module(), mkif(), phone_call(), phone_check_exception(), phone_new(), phone_read(), phone_request(), phone_setup(), and phone_write().
#define MODE_IMMEDIATE 2 |
Definition at line 126 of file chan_phone.c.
Referenced by load_module(), and phone_check_exception().
#define MODE_SIGMA 5 |
Definition at line 129 of file chan_phone.c.
Referenced by do_monitor(), load_module(), and phone_check_exception().
#define PHONE_MAX_BUF 480 |
#define QNDRV_VER 100 |
Definition at line 74 of file chan_phone.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 1451 of file chan_phone.c.
static int __unload_module | ( | void | ) | [static] |
Definition at line 1281 of file chan_phone.c.
References ast_channel_unregister(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, cur_tech, phone_pvt::fd, free, iflist, iflock, LOG_WARNING, monlock, phone_pvt::next, and phone_pvt::owner.
01282 { 01283 struct phone_pvt *p, *pl; 01284 /* First, take us out of the channel loop */ 01285 if (cur_tech) 01286 ast_channel_unregister(cur_tech); 01287 if (!ast_mutex_lock(&iflock)) { 01288 /* Hangup all interfaces if they have an owner */ 01289 p = iflist; 01290 while(p) { 01291 if (p->owner) 01292 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 01293 p = p->next; 01294 } 01295 iflist = NULL; 01296 ast_mutex_unlock(&iflock); 01297 } else { 01298 ast_log(LOG_WARNING, "Unable to lock the monitor\n"); 01299 return -1; 01300 } 01301 if (!ast_mutex_lock(&monlock)) { 01302 if (monitor_thread > AST_PTHREADT_NULL) { 01303 monitor = 0; 01304 while (pthread_kill(monitor_thread, SIGURG) == 0) 01305 sched_yield(); 01306 pthread_join(monitor_thread, NULL); 01307 } 01308 monitor_thread = AST_PTHREADT_STOP; 01309 ast_mutex_unlock(&monlock); 01310 } else { 01311 ast_log(LOG_WARNING, "Unable to lock the monitor\n"); 01312 return -1; 01313 } 01314 01315 if (!ast_mutex_lock(&iflock)) { 01316 /* Destroy all the interfaces and free their memory */ 01317 p = iflist; 01318 while(p) { 01319 /* Close the socket, assuming it's real */ 01320 if (p->fd > -1) 01321 close(p->fd); 01322 pl = p; 01323 p = p->next; 01324 /* Free associated memory */ 01325 free(pl); 01326 } 01327 iflist = NULL; 01328 ast_mutex_unlock(&iflock); 01329 } else { 01330 ast_log(LOG_WARNING, "Unable to lock the monitor\n"); 01331 return -1; 01332 } 01333 01334 return 0; 01335 }
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1451 of file chan_phone.c.
static void* do_monitor | ( | void * | data | ) | [static] |
Definition at line 998 of file chan_phone.c.
References ast_log(), ast_mutex_lock(), ast_realloc, ast_tvzero(), DialTone, phone_pvt::dialtone, phone_pvt::fd, iflist, iflock, LOG_ERROR, LOG_WARNING, phone_pvt::mode, MODE_SIGMA, phone_pvt::next, and phone_pvt::owner.
00999 { 01000 struct pollfd *fds = NULL; 01001 int nfds = 0, inuse_fds = 0, res; 01002 struct phone_pvt *i; 01003 int tonepos = 0; 01004 /* The tone we're playing this round */ 01005 struct timeval tv = { 0, 0 }; 01006 int dotone; 01007 /* This thread monitors all the frame relay interfaces which are not yet in use 01008 (and thus do not have a separate thread) indefinitely */ 01009 while (monitor) { 01010 /* Don't let anybody kill us right away. Nobody should lock the interface list 01011 and wait for the monitor list, but the other way around is okay. */ 01012 /* Lock the interface list */ 01013 if (ast_mutex_lock(&iflock)) { 01014 ast_log(LOG_ERROR, "Unable to grab interface lock\n"); 01015 return NULL; 01016 } 01017 /* Build the stuff we're going to select on, that is the socket of every 01018 phone_pvt that does not have an associated owner channel */ 01019 i = iflist; 01020 dotone = 0; 01021 inuse_fds = 0; 01022 for (i = iflist; i; i = i->next) { 01023 if (!i->owner) { 01024 /* This needs to be watched, as it lacks an owner */ 01025 if (inuse_fds == nfds) { 01026 void *tmp = ast_realloc(fds, (nfds + 1) * sizeof(*fds)); 01027 if (!tmp) { 01028 /* Avoid leaking */ 01029 continue; 01030 } 01031 fds = tmp; 01032 nfds++; 01033 } 01034 fds[inuse_fds].fd = i->fd; 01035 fds[inuse_fds].events = POLLIN | POLLERR; 01036 fds[inuse_fds].revents = 0; 01037 inuse_fds++; 01038 01039 if (i->dialtone && i->mode != MODE_SIGMA) { 01040 /* Remember we're going to have to come back and play 01041 more dialtones */ 01042 if (ast_tvzero(tv)) { 01043 /* If we're due for a dialtone, play one */ 01044 if (write(i->fd, DialTone + tonepos, 240) != 240) { 01045 ast_log(LOG_WARNING, "Dial tone write error\n"); 01046 } 01047 } 01048 dotone++; 01049 } 01050 } 01051 } 01052 /* Okay, now that we know what to do, release the interface lock */ 01053 ast_mutex_unlock(&iflock); 01054 01055 /* Wait indefinitely for something to happen */ 01056 if (dotone && i && i->mode != MODE_SIGMA) { 01057 /* If we're ready to recycle the time, set it to 30 ms */ 01058 tonepos += 240; 01059 if (tonepos >= sizeof(DialTone)) { 01060 tonepos = 0; 01061 } 01062 if (ast_tvzero(tv)) { 01063 tv = ast_tv(0, 30000); 01064 } 01065 res = ast_poll2(fds, inuse_fds, &tv); 01066 } else { 01067 res = ast_poll(fds, inuse_fds, -1); 01068 tv = ast_tv(0, 0); 01069 tonepos = 0; 01070 } 01071 /* Okay, select has finished. Let's see what happened. */ 01072 if (res < 0) { 01073 ast_log(LOG_DEBUG, "poll returned %d: %s\n", res, strerror(errno)); 01074 continue; 01075 } 01076 /* If there are no fd's changed, just continue, it's probably time 01077 to play some more dialtones */ 01078 if (!res) { 01079 continue; 01080 } 01081 /* Alright, lock the interface list again, and let's look and see what has 01082 happened */ 01083 if (ast_mutex_lock(&iflock)) { 01084 ast_log(LOG_WARNING, "Unable to lock the interface list\n"); 01085 continue; 01086 } 01087 01088 for (i = iflist; i; i = i->next) { 01089 int j; 01090 /* Find the record */ 01091 for (j = 0; j < inuse_fds; j++) { 01092 if (fds[j].fd == i->fd) { 01093 break; 01094 } 01095 } 01096 01097 /* Not found? */ 01098 if (j == inuse_fds) { 01099 continue; 01100 } 01101 01102 if (fds[j].revents & POLLIN) { 01103 if (i->owner) { 01104 continue; 01105 } 01106 phone_mini_packet(i); 01107 } 01108 if (fds[j].revents & POLLERR) { 01109 if (i->owner) { 01110 continue; 01111 } 01112 phone_check_exception(i); 01113 } 01114 } 01115 ast_mutex_unlock(&iflock); 01116 } 01117 return NULL; 01118 }
static int load_module | ( | void | ) | [static] |
Definition at line 1342 of file chan_phone.c.
References __unload_module(), ast_callerid_split(), ast_channel_register(), ast_config_destroy(), ast_config_load(), ast_copy_string(), AST_FORMAT_G723_1, AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_mutex_lock(), ast_mutex_unlock(), ast_true(), ast_variable_browse(), ast_channel_tech::capabilities, cur_tech, DEFAULT_GAIN, iflist, iflock, LOG_ERROR, LOG_WARNING, mkif(), phone_pvt::mode, MODE_DIALTONE, MODE_FXO, MODE_FXS, MODE_IMMEDIATE, MODE_SIGMA, ast_variable::name, ast_variable::next, phone_pvt::next, parse_gain_value(), phone_tech, phone_tech_fxs, restart_monitor(), phone_pvt::rxgain, phone_pvt::txgain, and ast_variable::value.
01343 { 01344 struct ast_config *cfg; 01345 struct ast_variable *v; 01346 struct phone_pvt *tmp; 01347 int mode = MODE_IMMEDIATE; 01348 int txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; /* default gain 1.0 */ 01349 cfg = ast_config_load(config); 01350 01351 /* We *must* have a config file otherwise stop immediately */ 01352 if (!cfg) { 01353 ast_log(LOG_ERROR, "Unable to load config %s\n", config); 01354 return AST_MODULE_LOAD_DECLINE; 01355 } 01356 if (ast_mutex_lock(&iflock)) { 01357 /* It's a little silly to lock it, but we mind as well just to be sure */ 01358 ast_log(LOG_ERROR, "Unable to lock interface list???\n"); 01359 return AST_MODULE_LOAD_FAILURE; 01360 } 01361 v = ast_variable_browse(cfg, "interfaces"); 01362 while(v) { 01363 /* Create the interface list */ 01364 if (!strcasecmp(v->name, "device")) { 01365 tmp = mkif(v->value, mode, txgain, rxgain); 01366 if (tmp) { 01367 tmp->next = iflist; 01368 iflist = tmp; 01369 01370 } else { 01371 ast_log(LOG_ERROR, "Unable to register channel '%s'\n", v->value); 01372 ast_config_destroy(cfg); 01373 ast_mutex_unlock(&iflock); 01374 __unload_module(); 01375 return AST_MODULE_LOAD_FAILURE; 01376 } 01377 } else if (!strcasecmp(v->name, "silencesupression")) { 01378 silencesupression = ast_true(v->value); 01379 } else if (!strcasecmp(v->name, "language")) { 01380 ast_copy_string(language, v->value, sizeof(language)); 01381 } else if (!strcasecmp(v->name, "callerid")) { 01382 ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num)); 01383 } else if (!strcasecmp(v->name, "mode")) { 01384 if (!strncasecmp(v->value, "di", 2)) 01385 mode = MODE_DIALTONE; 01386 else if (!strncasecmp(v->value, "sig", 3)) 01387 mode = MODE_SIGMA; 01388 else if (!strncasecmp(v->value, "im", 2)) 01389 mode = MODE_IMMEDIATE; 01390 else if (!strncasecmp(v->value, "fxs", 3)) { 01391 mode = MODE_FXS; 01392 prefformat = 0x01ff0000; /* All non-voice */ 01393 } 01394 else if (!strncasecmp(v->value, "fx", 2)) 01395 mode = MODE_FXO; 01396 else 01397 ast_log(LOG_WARNING, "Unknown mode: %s\n", v->value); 01398 } else if (!strcasecmp(v->name, "context")) { 01399 ast_copy_string(context, v->value, sizeof(context)); 01400 } else if (!strcasecmp(v->name, "format")) { 01401 if (!strcasecmp(v->value, "g723.1")) { 01402 prefformat = AST_FORMAT_G723_1; 01403 } else if (!strcasecmp(v->value, "slinear")) { 01404 if (mode == MODE_FXS) 01405 prefformat |= AST_FORMAT_SLINEAR; 01406 else prefformat = AST_FORMAT_SLINEAR; 01407 } else if (!strcasecmp(v->value, "ulaw")) { 01408 prefformat = AST_FORMAT_ULAW; 01409 } else 01410 ast_log(LOG_WARNING, "Unknown format '%s'\n", v->value); 01411 } else if (!strcasecmp(v->name, "echocancel")) { 01412 if (!strcasecmp(v->value, "off")) { 01413 echocancel = AEC_OFF; 01414 } else if (!strcasecmp(v->value, "low")) { 01415 echocancel = AEC_LOW; 01416 } else if (!strcasecmp(v->value, "medium")) { 01417 echocancel = AEC_MED; 01418 } else if (!strcasecmp(v->value, "high")) { 01419 echocancel = AEC_HIGH; 01420 } else 01421 ast_log(LOG_WARNING, "Unknown echo cancellation '%s'\n", v->value); 01422 } else if (!strcasecmp(v->name, "txgain")) { 01423 txgain = parse_gain_value(v->name, v->value); 01424 } else if (!strcasecmp(v->name, "rxgain")) { 01425 rxgain = parse_gain_value(v->name, v->value); 01426 } 01427 v = v->next; 01428 } 01429 ast_mutex_unlock(&iflock); 01430 01431 if (mode == MODE_FXS) { 01432 phone_tech_fxs.capabilities = prefformat; 01433 cur_tech = &phone_tech_fxs; 01434 } else 01435 cur_tech = (struct ast_channel_tech *) &phone_tech; 01436 01437 /* Make sure we can register our Adtranphone channel type */ 01438 01439 if (ast_channel_register(cur_tech)) { 01440 ast_log(LOG_ERROR, "Unable to register channel class 'Phone'\n"); 01441 ast_config_destroy(cfg); 01442 __unload_module(); 01443 return AST_MODULE_LOAD_FAILURE; 01444 } 01445 ast_config_destroy(cfg); 01446 /* And start the monitor for the first time */ 01447 restart_monitor(); 01448 return AST_MODULE_LOAD_SUCCESS; 01449 }
static struct phone_pvt* mkif | ( | char * | iface, | |
int | mode, | |||
int | txgain, | |||
int | rxgain | |||
) | [static] |
Definition at line 1157 of file chan_phone.c.
References ast_copy_string(), ast_log(), phone_pvt::cid_name, phone_pvt::cid_num, phone_pvt::context, phone_pvt::cpt, phone_pvt::dev, phone_pvt::dialtone, errno, phone_pvt::ext, phone_pvt::fd, free, phone_pvt::language, phone_pvt::lastformat, phone_pvt::lastinput, LOG_DEBUG, LOG_WARNING, malloc, phone_pvt::ministate, phone_pvt::mode, MODE_FXO, MODE_FXS, phone_pvt::next, phone_pvt::obuflen, phone_pvt::owner, phone_pvt::rxgain, phone_pvt::silencesupression, and phone_pvt::txgain.
Referenced by load_module().
01158 { 01159 /* Make a phone_pvt structure for this interface */ 01160 struct phone_pvt *tmp; 01161 int flags; 01162 01163 tmp = malloc(sizeof(struct phone_pvt)); 01164 if (tmp) { 01165 tmp->fd = open(iface, O_RDWR); 01166 if (tmp->fd < 0) { 01167 ast_log(LOG_WARNING, "Unable to open '%s'\n", iface); 01168 free(tmp); 01169 return NULL; 01170 } 01171 if (mode == MODE_FXO) { 01172 if (ioctl(tmp->fd, IXJCTL_PORT, PORT_PSTN)) 01173 ast_log(LOG_DEBUG, "Unable to set port to PSTN\n"); 01174 } else { 01175 if (ioctl(tmp->fd, IXJCTL_PORT, PORT_POTS)) 01176 if (mode != MODE_FXS) 01177 ast_log(LOG_DEBUG, "Unable to set port to POTS\n"); 01178 } 01179 ioctl(tmp->fd, PHONE_PLAY_STOP); 01180 ioctl(tmp->fd, PHONE_REC_STOP); 01181 ioctl(tmp->fd, PHONE_RING_STOP); 01182 ioctl(tmp->fd, PHONE_CPT_STOP); 01183 if (ioctl(tmp->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK)) 01184 ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",iface, strerror(errno)); 01185 if (echocancel != AEC_OFF) 01186 ioctl(tmp->fd, IXJCTL_AEC_START, echocancel); 01187 if (silencesupression) 01188 tmp->silencesupression = 1; 01189 #ifdef PHONE_VAD 01190 ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression); 01191 #endif 01192 tmp->mode = mode; 01193 flags = fcntl(tmp->fd, F_GETFL); 01194 fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK); 01195 tmp->owner = NULL; 01196 tmp->lastformat = -1; 01197 tmp->lastinput = -1; 01198 tmp->ministate = 0; 01199 memset(tmp->ext, 0, sizeof(tmp->ext)); 01200 ast_copy_string(tmp->language, language, sizeof(tmp->language)); 01201 ast_copy_string(tmp->dev, iface, sizeof(tmp->dev)); 01202 ast_copy_string(tmp->context, context, sizeof(tmp->context)); 01203 tmp->next = NULL; 01204 tmp->obuflen = 0; 01205 tmp->dialtone = 0; 01206 tmp->cpt = 0; 01207 ast_copy_string(tmp->cid_num, cid_num, sizeof(tmp->cid_num)); 01208 ast_copy_string(tmp->cid_name, cid_name, sizeof(tmp->cid_name)); 01209 tmp->txgain = txgain; 01210 ioctl(tmp->fd, PHONE_PLAY_VOLUME, tmp->txgain); 01211 tmp->rxgain = rxgain; 01212 ioctl(tmp->fd, PHONE_REC_VOLUME, tmp->rxgain); 01213 } 01214 return tmp; 01215 }
static int parse_gain_value | ( | char * | gain_type, | |
char * | value | |||
) | [static] |
Definition at line 1259 of file chan_phone.c.
References ast_log(), DEFAULT_GAIN, and LOG_ERROR.
Referenced by load_module().
01260 { 01261 float gain; 01262 01263 /* try to scan number */ 01264 if (sscanf(value, "%30f", &gain) != 1) 01265 { 01266 ast_log(LOG_ERROR, "Invalid %s value '%s' in '%s' config\n", 01267 value, gain_type, config); 01268 return DEFAULT_GAIN; 01269 } 01270 01271 /* multiplicate gain by 1.0 gain value */ 01272 gain = gain * (float)DEFAULT_GAIN; 01273 01274 /* percentage? */ 01275 if (value[strlen(value) - 1] == '%') 01276 return (int)(gain / (float)100); 01277 01278 return (int)gain; 01279 }
static int phone_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 458 of file chan_phone.c.
References ast_log(), ast_setstate(), AST_STATE_UP, errno, phone_pvt::fd, LOG_DEBUG, phone_pvt::mode, MODE_FXO, ast_channel::name, option_debug, phone_setup(), ast_channel::rings, and ast_channel::tech_pvt.
00459 { 00460 struct phone_pvt *p; 00461 p = ast->tech_pvt; 00462 /* In case it's a LineJack, take it off hook */ 00463 if (p->mode == MODE_FXO) { 00464 if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_OFF_HOOK)) 00465 ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n", ast->name, strerror(errno)); 00466 else 00467 ast_log(LOG_DEBUG, "Took linejack off hook\n"); 00468 } 00469 phone_setup(ast); 00470 if (option_debug) 00471 ast_log(LOG_DEBUG, "phone_answer(%s)\n", ast->name); 00472 ast->rings = 0; 00473 ast_setstate(ast, AST_STATE_UP); 00474 return 0; 00475 }
static int phone_call | ( | struct ast_channel * | ast, | |
char * | dest, | |||
int | timeout | |||
) | [static] |
Definition at line 294 of file chan_phone.c.
References ast_channel::_state, AST_CONTROL_RINGING, ast_copy_string(), ast_localtime(), ast_log(), ast_queue_control(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RINGING, ast_strlen_zero(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, DEFAULT_CALLER_ID, ast_channel::fds, IXJ_PHONE_RING_START, LOG_DEBUG, LOG_WARNING, phone_pvt::mode, MODE_FXS, ast_channel::name, option_debug, phone_digit_end(), and ast_channel::tech_pvt.
00295 { 00296 struct phone_pvt *p; 00297 00298 PHONE_CID cid; 00299 time_t UtcTime; 00300 struct tm tm; 00301 int start; 00302 00303 time(&UtcTime); 00304 ast_localtime(&UtcTime, &tm, NULL); 00305 00306 memset(&cid, 0, sizeof(PHONE_CID)); 00307 if(&tm != NULL) { 00308 snprintf(cid.month, sizeof(cid.month), "%02d",(tm.tm_mon + 1)); 00309 snprintf(cid.day, sizeof(cid.day), "%02d", tm.tm_mday); 00310 snprintf(cid.hour, sizeof(cid.hour), "%02d", tm.tm_hour); 00311 snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min); 00312 } 00313 /* the standard format of ast->callerid is: "name" <number>, but not always complete */ 00314 if (ast_strlen_zero(ast->cid.cid_name)) 00315 strcpy(cid.name, DEFAULT_CALLER_ID); 00316 else 00317 ast_copy_string(cid.name, ast->cid.cid_name, sizeof(cid.name)); 00318 00319 if (ast->cid.cid_num) 00320 ast_copy_string(cid.number, ast->cid.cid_num, sizeof(cid.number)); 00321 00322 p = ast->tech_pvt; 00323 00324 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) { 00325 ast_log(LOG_WARNING, "phone_call called on %s, neither down nor reserved\n", ast->name); 00326 return -1; 00327 } 00328 if (option_debug) 00329 ast_log(LOG_DEBUG, "Ringing %s on %s (%d)\n", dest, ast->name, ast->fds[0]); 00330 00331 start = IXJ_PHONE_RING_START(cid); 00332 if (start == -1) 00333 return -1; 00334 00335 if (p->mode == MODE_FXS) { 00336 char *digit = strchr(dest, '/'); 00337 if (digit) 00338 { 00339 digit++; 00340 while (*digit) 00341 phone_digit_end(ast, *digit++, 0); 00342 } 00343 } 00344 00345 ast_setstate(ast, AST_STATE_RINGING); 00346 ast_queue_control(ast, AST_CONTROL_RINGING); 00347 return 0; 00348 }
static void phone_check_exception | ( | struct phone_pvt * | i | ) | [static] |
Definition at line 904 of file chan_phone.c.
References ast_canmatch_extension(), ast_exists_extension(), ast_log(), AST_MAX_EXTENSION, ast_module_ref(), ast_module_unref(), AST_STATE_RING, ast_verbose(), phone_pvt::cid_num, phone_pvt::context, phone_pvt::cpt, phone_pvt::dialtone, phone_pvt::ext, phone_pvt::fd, phone_pvt::lastformat, LOG_DEBUG, phone_pvt::mode, MODE_DIALTONE, MODE_FXS, MODE_IMMEDIATE, MODE_SIGMA, option_debug, and phone_new().
00905 { 00906 int offhook=0; 00907 char digit[2] = {0 , 0}; 00908 union telephony_exception phonee; 00909 /* XXX Do something XXX */ 00910 #if 0 00911 ast_log(LOG_DEBUG, "Exception!\n"); 00912 #endif 00913 phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION); 00914 if (phonee.bits.dtmf_ready) { 00915 digit[0] = ioctl(i->fd, PHONE_GET_DTMF_ASCII); 00916 if (i->mode == MODE_DIALTONE || i->mode == MODE_FXS || i->mode == MODE_SIGMA) { 00917 ioctl(i->fd, PHONE_PLAY_STOP); 00918 ioctl(i->fd, PHONE_REC_STOP); 00919 ioctl(i->fd, PHONE_CPT_STOP); 00920 i->dialtone = 0; 00921 if (strlen(i->ext) < AST_MAX_EXTENSION - 1) 00922 strncat(i->ext, digit, sizeof(i->ext) - strlen(i->ext) - 1); 00923 if ((i->mode != MODE_FXS || 00924 !(phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION)) || 00925 !phonee.bits.dtmf_ready) && 00926 ast_exists_extension(NULL, i->context, i->ext, 1, i->cid_num)) { 00927 /* It's a valid extension in its context, get moving! */ 00928 phone_new(i, AST_STATE_RING, i->context); 00929 /* No need to restart monitor, we are the monitor */ 00930 } else if (!ast_canmatch_extension(NULL, i->context, i->ext, 1, i->cid_num)) { 00931 /* There is nothing in the specified extension that can match anymore. 00932 Try the default */ 00933 if (ast_exists_extension(NULL, "default", i->ext, 1, i->cid_num)) { 00934 /* Check the default, too... */ 00935 phone_new(i, AST_STATE_RING, "default"); 00936 /* XXX This should probably be justified better XXX */ 00937 } else if (!ast_canmatch_extension(NULL, "default", i->ext, 1, i->cid_num)) { 00938 /* It's not a valid extension, give a busy signal */ 00939 if (option_debug) 00940 ast_log(LOG_DEBUG, "%s can't match anything in %s or default\n", i->ext, i->context); 00941 ioctl(i->fd, PHONE_BUSY); 00942 i->cpt = 1; 00943 } 00944 } 00945 #if 0 00946 ast_verbose("Extension is %s\n", i->ext); 00947 #endif 00948 } 00949 } 00950 if (phonee.bits.hookstate) { 00951 offhook = ioctl(i->fd, PHONE_HOOKSTATE); 00952 if (offhook) { 00953 if (i->mode == MODE_IMMEDIATE) { 00954 phone_new(i, AST_STATE_RING, i->context); 00955 } else if (i->mode == MODE_DIALTONE) { 00956 ast_module_ref(ast_module_info->self); 00957 /* Reset the extension */ 00958 i->ext[0] = '\0'; 00959 /* Play the dialtone */ 00960 i->dialtone++; 00961 ioctl(i->fd, PHONE_PLAY_STOP); 00962 ioctl(i->fd, PHONE_PLAY_CODEC, ULAW); 00963 ioctl(i->fd, PHONE_PLAY_START); 00964 i->lastformat = -1; 00965 } else if (i->mode == MODE_SIGMA) { 00966 ast_module_ref(ast_module_info->self); 00967 /* Reset the extension */ 00968 i->ext[0] = '\0'; 00969 /* Play the dialtone */ 00970 i->dialtone++; 00971 ioctl(i->fd, PHONE_DIALTONE); 00972 } 00973 } else { 00974 if (i->dialtone) 00975 ast_module_unref(ast_module_info->self); 00976 memset(i->ext, 0, sizeof(i->ext)); 00977 if (i->cpt) 00978 { 00979 ioctl(i->fd, PHONE_CPT_STOP); 00980 i->cpt = 0; 00981 } 00982 ioctl(i->fd, PHONE_PLAY_STOP); 00983 ioctl(i->fd, PHONE_REC_STOP); 00984 i->dialtone = 0; 00985 i->lastformat = -1; 00986 } 00987 } 00988 if (phonee.bits.pstn_ring) { 00989 ast_verbose("Unit is ringing\n"); 00990 phone_new(i, AST_STATE_RING, i->context); 00991 } 00992 if (phonee.bits.caller_id) 00993 ast_verbose("We have caller ID\n"); 00994 00995 00996 }
static int phone_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 246 of file chan_phone.c.
00247 { 00248 /* XXX Modify this callback to let Asterisk support controlling the length of DTMF */ 00249 return 0; 00250 }
static int phone_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 252 of file chan_phone.c.
References ast_log(), phone_pvt::fd, phone_pvt::lastformat, LOG_DEBUG, LOG_WARNING, and ast_channel::tech_pvt.
Referenced by phone_call().
00253 { 00254 struct phone_pvt *p; 00255 int outdigit; 00256 p = ast->tech_pvt; 00257 ast_log(LOG_DEBUG, "Dialed %c\n", digit); 00258 switch(digit) { 00259 case '0': 00260 case '1': 00261 case '2': 00262 case '3': 00263 case '4': 00264 case '5': 00265 case '6': 00266 case '7': 00267 case '8': 00268 case '9': 00269 outdigit = digit - '0'; 00270 break; 00271 case '*': 00272 outdigit = 11; 00273 break; 00274 case '#': 00275 outdigit = 12; 00276 break; 00277 case 'f': /*flash*/ 00278 case 'F': 00279 ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK); 00280 usleep(320000); 00281 ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK); 00282 p->lastformat = -1; 00283 return 0; 00284 default: 00285 ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit); 00286 return -1; 00287 } 00288 ast_log(LOG_DEBUG, "Dialed %d\n", outdigit); 00289 ioctl(p->fd, PHONE_PLAY_TONE, outdigit); 00290 p->lastformat = -1; 00291 return 0; 00292 }
static struct ast_frame * phone_exception | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 491 of file chan_phone.c.
References ast_channel::_state, AST_CONTROL_ANSWER, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_NULL, ast_log(), ast_setstate(), AST_STATE_RINGING, AST_STATE_UP, ast_tv(), ast_verbose(), ast_frame::data, ast_frame::datalen, ast_frame::delivery, phone_pvt::fd, phone_pvt::fr, ast_frame::frametype, LOG_DEBUG, LOG_WARNING, ast_frame::mallocd, phone_pvt::mode, MODE_FXO, ast_frame::offset, option_debug, phone_setup(), ast_frame::samples, ast_frame::src, ast_frame::subclass, and ast_channel::tech_pvt.
00492 { 00493 int res; 00494 union telephony_exception phonee; 00495 struct phone_pvt *p = ast->tech_pvt; 00496 char digit; 00497 00498 /* Some nice norms */ 00499 p->fr.datalen = 0; 00500 p->fr.samples = 0; 00501 p->fr.data = NULL; 00502 p->fr.src = "Phone"; 00503 p->fr.offset = 0; 00504 p->fr.mallocd=0; 00505 p->fr.delivery = ast_tv(0,0); 00506 00507 phonee.bytes = ioctl(p->fd, PHONE_EXCEPTION); 00508 if (phonee.bits.dtmf_ready) { 00509 if (option_debug) 00510 ast_log(LOG_DEBUG, "phone_exception(): DTMF\n"); 00511 00512 /* We've got a digit -- Just handle this nicely and easily */ 00513 digit = ioctl(p->fd, PHONE_GET_DTMF_ASCII); 00514 p->fr.subclass = digit; 00515 p->fr.frametype = AST_FRAME_DTMF; 00516 return &p->fr; 00517 } 00518 if (phonee.bits.hookstate) { 00519 if (option_debug) 00520 ast_log(LOG_DEBUG, "Hookstate changed\n"); 00521 res = ioctl(p->fd, PHONE_HOOKSTATE); 00522 /* See if we've gone on hook, if so, notify by returning NULL */ 00523 if (option_debug) 00524 ast_log(LOG_DEBUG, "New hookstate: %d\n", res); 00525 if (!res && (p->mode != MODE_FXO)) 00526 return NULL; 00527 else { 00528 if (ast->_state == AST_STATE_RINGING) { 00529 /* They've picked up the phone */ 00530 p->fr.frametype = AST_FRAME_CONTROL; 00531 p->fr.subclass = AST_CONTROL_ANSWER; 00532 phone_setup(ast); 00533 ast_setstate(ast, AST_STATE_UP); 00534 return &p->fr; 00535 } else 00536 ast_log(LOG_WARNING, "Got off hook in weird state %d\n", ast->_state); 00537 } 00538 } 00539 #if 1 00540 if (phonee.bits.pstn_ring) 00541 ast_verbose("Unit is ringing\n"); 00542 if (phonee.bits.caller_id) { 00543 ast_verbose("We have caller ID\n"); 00544 } 00545 if (phonee.bits.pstn_wink) 00546 ast_verbose("Detected Wink\n"); 00547 #endif 00548 /* Strange -- nothing there.. */ 00549 p->fr.frametype = AST_FRAME_NULL; 00550 p->fr.subclass = 0; 00551 return &p->fr; 00552 }
static int phone_fixup | ( | struct ast_channel * | old, | |
struct ast_channel * | new | |||
) | [static] |
Definition at line 238 of file chan_phone.c.
References phone_pvt::owner, and ast_channel::tech_pvt.
00239 { 00240 struct phone_pvt *pvt = old->tech_pvt; 00241 if (pvt && pvt->owner == old) 00242 pvt->owner = new; 00243 return 0; 00244 }
static int phone_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 350 of file chan_phone.c.
References ast_log(), ast_module_unref(), ast_setstate(), AST_STATE_DOWN, ast_verbose(), phone_pvt::cpt, phone_pvt::dialtone, errno, phone_pvt::ext, phone_pvt::fd, phone_pvt::lastformat, phone_pvt::lastinput, LOG_DEBUG, LOG_WARNING, phone_pvt::ministate, phone_pvt::mode, MODE_FXO, ast_channel::name, phone_pvt::obuflen, option_debug, option_verbose, phone_pvt::owner, restart_monitor(), ast_channel::tech_pvt, and VERBOSE_PREFIX_3.
00351 { 00352 struct phone_pvt *p; 00353 p = ast->tech_pvt; 00354 if (option_debug) 00355 ast_log(LOG_DEBUG, "phone_hangup(%s)\n", ast->name); 00356 if (!ast->tech_pvt) { 00357 ast_log(LOG_WARNING, "Asked to hangup channel not connected\n"); 00358 return 0; 00359 } 00360 /* XXX Is there anything we can do to really hang up except stop recording? */ 00361 ast_setstate(ast, AST_STATE_DOWN); 00362 if (ioctl(p->fd, PHONE_REC_STOP)) 00363 ast_log(LOG_WARNING, "Failed to stop recording\n"); 00364 if (ioctl(p->fd, PHONE_PLAY_STOP)) 00365 ast_log(LOG_WARNING, "Failed to stop playing\n"); 00366 if (ioctl(p->fd, PHONE_RING_STOP)) 00367 ast_log(LOG_WARNING, "Failed to stop ringing\n"); 00368 if (ioctl(p->fd, PHONE_CPT_STOP)) 00369 ast_log(LOG_WARNING, "Failed to stop sounds\n"); 00370 00371 /* If it's an FXO, hang them up */ 00372 if (p->mode == MODE_FXO) { 00373 if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK)) 00374 ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",ast->name, strerror(errno)); 00375 } 00376 00377 /* If they're off hook, give a busy signal */ 00378 if (ioctl(p->fd, PHONE_HOOKSTATE)) { 00379 if (option_debug) 00380 ast_log(LOG_DEBUG, "Got hunghup, giving busy signal\n"); 00381 ioctl(p->fd, PHONE_BUSY); 00382 p->cpt = 1; 00383 } 00384 p->lastformat = -1; 00385 p->lastinput = -1; 00386 p->ministate = 0; 00387 p->obuflen = 0; 00388 p->dialtone = 0; 00389 memset(p->ext, 0, sizeof(p->ext)); 00390 ((struct phone_pvt *)(ast->tech_pvt))->owner = NULL; 00391 ast_module_unref(ast_module_info->self); 00392 if (option_verbose > 2) 00393 ast_verbose( VERBOSE_PREFIX_3 "Hungup '%s'\n", ast->name); 00394 ast->tech_pvt = NULL; 00395 ast_setstate(ast, AST_STATE_DOWN); 00396 restart_monitor(); 00397 return 0; 00398 }
static int phone_indicate | ( | struct ast_channel * | chan, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 210 of file chan_phone.c.
References AST_CONTROL_FLASH, AST_CONTROL_HOLD, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, ast_log(), ast_moh_start(), ast_moh_stop(), phone_pvt::fd, phone_pvt::lastformat, LOG_DEBUG, LOG_WARNING, ast_channel::name, and ast_channel::tech_pvt.
00211 { 00212 struct phone_pvt *p = chan->tech_pvt; 00213 int res=-1; 00214 ast_log(LOG_DEBUG, "Requested indication %d on channel %s\n", condition, chan->name); 00215 switch(condition) { 00216 case AST_CONTROL_FLASH: 00217 ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK); 00218 usleep(320000); 00219 ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK); 00220 p->lastformat = -1; 00221 res = 0; 00222 break; 00223 case AST_CONTROL_HOLD: 00224 ast_moh_start(chan, data, NULL); 00225 break; 00226 case AST_CONTROL_UNHOLD: 00227 ast_moh_stop(chan); 00228 break; 00229 case AST_CONTROL_SRCUPDATE: 00230 res = 0; 00231 break; 00232 default: 00233 ast_log(LOG_WARNING, "Condition %d is not supported on channel %s\n", condition, chan->name); 00234 } 00235 return res; 00236 }
static void phone_mini_packet | ( | struct phone_pvt * | i | ) | [static] |
Definition at line 892 of file chan_phone.c.
References ast_log(), errno, phone_pvt::fd, and LOG_WARNING.
00893 { 00894 int res; 00895 char buf[1024]; 00896 /* Ignore stuff we read... */ 00897 res = read(i->fd, buf, sizeof(buf)); 00898 if (res < 1) { 00899 ast_log(LOG_WARNING, "Read returned %d: %s\n", res, strerror(errno)); 00900 return; 00901 } 00902 }
static struct ast_channel* phone_new | ( | struct phone_pvt * | i, | |
int | state, | |||
char * | context | |||
) | [static] |
Definition at line 831 of file chan_phone.c.
References ast_channel_alloc(), ast_copy_string(), AST_FORMAT_SLINEAR, ast_hangup(), ast_log(), ast_module_ref(), ast_pbx_start(), AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_string_field_set, ast_strlen_zero(), phone_pvt::cid_name, phone_pvt::cid_num, phone_pvt::context, phone_pvt::cpt, cur_tech, phone_pvt::dev, phone_pvt::ext, phone_pvt::fd, phone_pvt::language, LOG_WARNING, phone_pvt::mode, MODE_FXS, and phone_pvt::owner.
Referenced by phone_check_exception(), and phone_request().
00832 { 00833 struct ast_channel *tmp; 00834 struct phone_codec_data codec; 00835 tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", i->ext, i->context, 0, "Phone/%s", i->dev + 5); 00836 if (tmp) { 00837 tmp->tech = cur_tech; 00838 tmp->fds[0] = i->fd; 00839 /* XXX Switching formats silently causes kernel panics XXX */ 00840 if (i->mode == MODE_FXS && 00841 ioctl(i->fd, PHONE_QUERY_CODEC, &codec) == 0) { 00842 if (codec.type == LINEAR16) 00843 tmp->nativeformats = 00844 tmp->rawreadformat = 00845 tmp->rawwriteformat = 00846 AST_FORMAT_SLINEAR; 00847 else { 00848 tmp->nativeformats = 00849 tmp->rawreadformat = 00850 tmp->rawwriteformat = 00851 prefformat & ~AST_FORMAT_SLINEAR; 00852 } 00853 } 00854 else { 00855 tmp->nativeformats = prefformat; 00856 tmp->rawreadformat = prefformat; 00857 tmp->rawwriteformat = prefformat; 00858 } 00859 /* no need to call ast_setstate: the channel_alloc already did its job */ 00860 if (state == AST_STATE_RING) 00861 tmp->rings = 1; 00862 tmp->tech_pvt = i; 00863 ast_copy_string(tmp->context, context, sizeof(tmp->context)); 00864 if (!ast_strlen_zero(i->ext)) 00865 ast_copy_string(tmp->exten, i->ext, sizeof(tmp->exten)); 00866 else 00867 strcpy(tmp->exten, "s"); 00868 if (!ast_strlen_zero(i->language)) 00869 ast_string_field_set(tmp, language, i->language); 00870 00871 /* Don't use ast_set_callerid() here because it will 00872 * generate a NewCallerID event before the NewChannel event */ 00873 tmp->cid.cid_ani = ast_strdup(i->cid_num); 00874 00875 i->owner = tmp; 00876 ast_module_ref(ast_module_info->self); 00877 if (state != AST_STATE_DOWN) { 00878 if (state == AST_STATE_RING) { 00879 ioctl(tmp->fds[0], PHONE_RINGBACK); 00880 i->cpt = 1; 00881 } 00882 if (ast_pbx_start(tmp)) { 00883 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); 00884 ast_hangup(tmp); 00885 } 00886 } 00887 } else 00888 ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); 00889 return tmp; 00890 }
static struct ast_frame * phone_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 554 of file chan_phone.c.
References ast_clear_flag, AST_FLAG_BLOCKING, AST_FORMAT_MAX_AUDIO, AST_FORMAT_PNG, AST_FORMAT_SLINEAR, ast_frame_byteswap_le, AST_FRAME_IMAGE, AST_FRAME_NULL, AST_FRAME_VIDEO, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_tv(), phone_pvt::buf, CHECK_BLOCKING, ast_frame::data, ast_frame::datalen, ast_frame::delivery, errno, phone_pvt::fd, phone_pvt::fr, ast_frame::frametype, phone_pvt::lastinput, LOG_WARNING, ast_frame::mallocd, phone_pvt::mode, MODE_FXS, ast_frame::offset, PHONE_MAX_BUF, ast_frame::samples, ast_frame::src, ast_frame::subclass, and ast_channel::tech_pvt.
00555 { 00556 int res; 00557 struct phone_pvt *p = ast->tech_pvt; 00558 00559 00560 /* Some nice norms */ 00561 p->fr.datalen = 0; 00562 p->fr.samples = 0; 00563 p->fr.data = NULL; 00564 p->fr.src = "Phone"; 00565 p->fr.offset = 0; 00566 p->fr.mallocd=0; 00567 p->fr.delivery = ast_tv(0,0); 00568 00569 /* Try to read some data... */ 00570 CHECK_BLOCKING(ast); 00571 res = read(p->fd, p->buf, PHONE_MAX_BUF); 00572 ast_clear_flag(ast, AST_FLAG_BLOCKING); 00573 if (res < 0) { 00574 #if 0 00575 if (errno == EAGAIN) { 00576 ast_log(LOG_WARNING, "Null frame received\n"); 00577 p->fr.frametype = AST_FRAME_NULL; 00578 p->fr.subclass = 0; 00579 return &p->fr; 00580 } 00581 #endif 00582 ast_log(LOG_WARNING, "Error reading: %s\n", strerror(errno)); 00583 return NULL; 00584 } 00585 p->fr.data = p->buf; 00586 if (p->mode != MODE_FXS) 00587 switch(p->buf[0] & 0x3) { 00588 case '0': 00589 case '1': 00590 /* Normal */ 00591 break; 00592 case '2': 00593 case '3': 00594 /* VAD/CNG, only send two words */ 00595 res = 4; 00596 break; 00597 } 00598 p->fr.samples = 240; 00599 p->fr.datalen = res; 00600 p->fr.frametype = p->lastinput <= AST_FORMAT_MAX_AUDIO ? 00601 AST_FRAME_VOICE : 00602 p->lastinput <= AST_FORMAT_PNG ? AST_FRAME_IMAGE 00603 : AST_FRAME_VIDEO; 00604 p->fr.subclass = p->lastinput; 00605 p->fr.offset = AST_FRIENDLY_OFFSET; 00606 /* Byteswap from little-endian to native-endian */ 00607 if (p->fr.subclass == AST_FORMAT_SLINEAR) 00608 ast_frame_byteswap_le(&p->fr); 00609 return &p->fr; 00610 }
static struct ast_channel * phone_request | ( | const char * | type, | |
int | format, | |||
void * | data, | |||
int * | cause | |||
) | [static] |
Definition at line 1217 of file chan_phone.c.
References AST_CAUSE_BUSY, AST_FORMAT_G723_1, AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_STATE_DOWN, phone_pvt::context, phone_pvt::dev, iflist, iflock, LOG_ERROR, LOG_NOTICE, phone_pvt::mode, MODE_FXS, name, phone_pvt::next, phone_pvt::owner, phone_new(), and restart_monitor().
01218 { 01219 int oldformat; 01220 struct phone_pvt *p; 01221 struct ast_channel *tmp = NULL; 01222 char *name = data; 01223 01224 /* Search for an unowned channel */ 01225 if (ast_mutex_lock(&iflock)) { 01226 ast_log(LOG_ERROR, "Unable to lock interface list???\n"); 01227 return NULL; 01228 } 01229 p = iflist; 01230 while(p) { 01231 if (p->mode == MODE_FXS || 01232 format & (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW)) { 01233 size_t length = strlen(p->dev + 5); 01234 if (strncmp(name, p->dev + 5, length) == 0 && 01235 !isalnum(name[length])) { 01236 if (!p->owner) { 01237 tmp = phone_new(p, AST_STATE_DOWN, p->context); 01238 break; 01239 } else 01240 *cause = AST_CAUSE_BUSY; 01241 } 01242 } 01243 p = p->next; 01244 } 01245 ast_mutex_unlock(&iflock); 01246 restart_monitor(); 01247 if (tmp == NULL) { 01248 oldformat = format; 01249 format &= (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW); 01250 if (!format) { 01251 ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat); 01252 return NULL; 01253 } 01254 } 01255 return tmp; 01256 }
static int phone_send_text | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 646 of file chan_phone.c.
References phone_write_buf(), and ast_channel::tech_pvt.
00647 { 00648 int length = strlen(text); 00649 return phone_write_buf(ast->tech_pvt, text, length, length, 0) == 00650 length ? 0 : -1; 00651 }
static int phone_setup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 400 of file chan_phone.c.
References AST_FORMAT_G723_1, AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, ast_getformatname(), ast_log(), phone_pvt::fd, phone_pvt::lastinput, LOG_WARNING, phone_pvt::mode, MODE_FXS, ast_channel::rawreadformat, and ast_channel::tech_pvt.
Referenced by phone_answer(), phone_exception(), and phone_write().
00401 { 00402 struct phone_pvt *p; 00403 p = ast->tech_pvt; 00404 ioctl(p->fd, PHONE_CPT_STOP); 00405 /* Nothing to answering really, just start recording */ 00406 if (ast->rawreadformat == AST_FORMAT_G723_1) { 00407 /* Prefer g723 */ 00408 ioctl(p->fd, PHONE_REC_STOP); 00409 if (p->lastinput != AST_FORMAT_G723_1) { 00410 p->lastinput = AST_FORMAT_G723_1; 00411 if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) { 00412 ast_log(LOG_WARNING, "Failed to set codec to g723.1\n"); 00413 return -1; 00414 } 00415 } 00416 } else if (ast->rawreadformat == AST_FORMAT_SLINEAR) { 00417 ioctl(p->fd, PHONE_REC_STOP); 00418 if (p->lastinput != AST_FORMAT_SLINEAR) { 00419 p->lastinput = AST_FORMAT_SLINEAR; 00420 if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) { 00421 ast_log(LOG_WARNING, "Failed to set codec to signed linear 16\n"); 00422 return -1; 00423 } 00424 } 00425 } else if (ast->rawreadformat == AST_FORMAT_ULAW) { 00426 ioctl(p->fd, PHONE_REC_STOP); 00427 if (p->lastinput != AST_FORMAT_ULAW) { 00428 p->lastinput = AST_FORMAT_ULAW; 00429 if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) { 00430 ast_log(LOG_WARNING, "Failed to set codec to uLaw\n"); 00431 return -1; 00432 } 00433 } 00434 } else if (p->mode == MODE_FXS) { 00435 ioctl(p->fd, PHONE_REC_STOP); 00436 if (p->lastinput != ast->rawreadformat) { 00437 p->lastinput = ast->rawreadformat; 00438 if (ioctl(p->fd, PHONE_REC_CODEC, ast->rawreadformat)) { 00439 ast_log(LOG_WARNING, "Failed to set codec to %d\n", 00440 ast->rawreadformat); 00441 return -1; 00442 } 00443 } 00444 } else { 00445 ast_log(LOG_WARNING, "Can't do format %s\n", ast_getformatname(ast->rawreadformat)); 00446 return -1; 00447 } 00448 if (ioctl(p->fd, PHONE_REC_START)) { 00449 ast_log(LOG_WARNING, "Failed to start recording\n"); 00450 return -1; 00451 } 00452 /* set the DTMF times (the default is too short) */ 00453 ioctl(p->fd, PHONE_SET_TONE_ON_TIME, 300); 00454 ioctl(p->fd, PHONE_SET_TONE_OFF_TIME, 200); 00455 return 0; 00456 }
static int phone_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | frame | |||
) | [static] |
Definition at line 653 of file chan_phone.c.
References ast_channel::_state, AST_FORMAT_G723_1, AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, AST_FRAME_IMAGE, AST_FRAME_VOICE, ast_log(), ast_setstate(), AST_STATE_UP, ast_frame::data, ast_frame::datalen, errno, phone_pvt::fd, ast_frame::frametype, phone_pvt::lastformat, phone_pvt::lastinput, LOG_WARNING, phone_pvt::mode, MODE_FXS, phone_pvt::obuflen, phone_setup(), phone_write_buf(), phone_pvt::silencesupression, ast_frame::subclass, and ast_channel::tech_pvt.
00654 { 00655 struct phone_pvt *p = ast->tech_pvt; 00656 int res; 00657 int maxfr=0; 00658 char *pos; 00659 int sofar; 00660 int expected; 00661 int codecset = 0; 00662 char tmpbuf[4]; 00663 /* Write a frame of (presumably voice) data */ 00664 if (frame->frametype != AST_FRAME_VOICE && p->mode != MODE_FXS) { 00665 if (frame->frametype != AST_FRAME_IMAGE) 00666 ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype); 00667 return 0; 00668 } 00669 if (!(frame->subclass & 00670 (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW)) && 00671 p->mode != MODE_FXS) { 00672 ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass); 00673 return -1; 00674 } 00675 #if 0 00676 /* If we're not in up mode, go into up mode now */ 00677 if (ast->_state != AST_STATE_UP) { 00678 ast_setstate(ast, AST_STATE_UP); 00679 phone_setup(ast); 00680 } 00681 #else 00682 if (ast->_state != AST_STATE_UP) { 00683 /* Don't try tos end audio on-hook */ 00684 return 0; 00685 } 00686 #endif 00687 if (frame->subclass == AST_FORMAT_G723_1) { 00688 if (p->lastformat != AST_FORMAT_G723_1) { 00689 ioctl(p->fd, PHONE_PLAY_STOP); 00690 ioctl(p->fd, PHONE_REC_STOP); 00691 if (ioctl(p->fd, PHONE_PLAY_CODEC, G723_63)) { 00692 ast_log(LOG_WARNING, "Unable to set G723.1 mode\n"); 00693 return -1; 00694 } 00695 if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) { 00696 ast_log(LOG_WARNING, "Unable to set G723.1 mode\n"); 00697 return -1; 00698 } 00699 p->lastformat = AST_FORMAT_G723_1; 00700 p->lastinput = AST_FORMAT_G723_1; 00701 /* Reset output buffer */ 00702 p->obuflen = 0; 00703 codecset = 1; 00704 } 00705 if (frame->datalen > 24) { 00706 ast_log(LOG_WARNING, "Frame size too large for G.723.1 (%d bytes)\n", frame->datalen); 00707 return -1; 00708 } 00709 maxfr = 24; 00710 } else if (frame->subclass == AST_FORMAT_SLINEAR) { 00711 if (p->lastformat != AST_FORMAT_SLINEAR) { 00712 ioctl(p->fd, PHONE_PLAY_STOP); 00713 ioctl(p->fd, PHONE_REC_STOP); 00714 if (ioctl(p->fd, PHONE_PLAY_CODEC, LINEAR16)) { 00715 ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n"); 00716 return -1; 00717 } 00718 if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) { 00719 ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n"); 00720 return -1; 00721 } 00722 p->lastformat = AST_FORMAT_SLINEAR; 00723 p->lastinput = AST_FORMAT_SLINEAR; 00724 codecset = 1; 00725 /* Reset output buffer */ 00726 p->obuflen = 0; 00727 } 00728 maxfr = 480; 00729 } else if (frame->subclass == AST_FORMAT_ULAW) { 00730 if (p->lastformat != AST_FORMAT_ULAW) { 00731 ioctl(p->fd, PHONE_PLAY_STOP); 00732 ioctl(p->fd, PHONE_REC_STOP); 00733 if (ioctl(p->fd, PHONE_PLAY_CODEC, ULAW)) { 00734 ast_log(LOG_WARNING, "Unable to set uLaw mode\n"); 00735 return -1; 00736 } 00737 if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) { 00738 ast_log(LOG_WARNING, "Unable to set uLaw mode\n"); 00739 return -1; 00740 } 00741 p->lastformat = AST_FORMAT_ULAW; 00742 p->lastinput = AST_FORMAT_ULAW; 00743 codecset = 1; 00744 /* Reset output buffer */ 00745 p->obuflen = 0; 00746 } 00747 maxfr = 240; 00748 } else { 00749 if (p->lastformat != frame->subclass) { 00750 ioctl(p->fd, PHONE_PLAY_STOP); 00751 ioctl(p->fd, PHONE_REC_STOP); 00752 if (ioctl(p->fd, PHONE_PLAY_CODEC, frame->subclass)) { 00753 ast_log(LOG_WARNING, "Unable to set %d mode\n", 00754 frame->subclass); 00755 return -1; 00756 } 00757 if (ioctl(p->fd, PHONE_REC_CODEC, frame->subclass)) { 00758 ast_log(LOG_WARNING, "Unable to set %d mode\n", 00759 frame->subclass); 00760 return -1; 00761 } 00762 p->lastformat = frame->subclass; 00763 p->lastinput = frame->subclass; 00764 codecset = 1; 00765 /* Reset output buffer */ 00766 p->obuflen = 0; 00767 } 00768 maxfr = 480; 00769 } 00770 if (codecset) { 00771 ioctl(p->fd, PHONE_REC_DEPTH, 3); 00772 ioctl(p->fd, PHONE_PLAY_DEPTH, 3); 00773 if (ioctl(p->fd, PHONE_PLAY_START)) { 00774 ast_log(LOG_WARNING, "Failed to start playback\n"); 00775 return -1; 00776 } 00777 if (ioctl(p->fd, PHONE_REC_START)) { 00778 ast_log(LOG_WARNING, "Failed to start recording\n"); 00779 return -1; 00780 } 00781 } 00782 /* If we get here, we have a frame of Appropriate data */ 00783 sofar = 0; 00784 pos = frame->data; 00785 while(sofar < frame->datalen) { 00786 /* Write in no more than maxfr sized frames */ 00787 expected = frame->datalen - sofar; 00788 if (maxfr < expected) 00789 expected = maxfr; 00790 /* XXX Internet Phone Jack does not handle the 4-byte VAD frame properly! XXX 00791 we have to pad it to 24 bytes still. */ 00792 if (frame->datalen == 4) { 00793 if (p->silencesupression) { 00794 memset(tmpbuf, 0, sizeof(tmpbuf)); 00795 memcpy(tmpbuf, frame->data, 4); 00796 expected = 24; 00797 res = phone_write_buf(p, tmpbuf, expected, maxfr, 0); 00798 } 00799 res = 4; 00800 expected=4; 00801 } else { 00802 int swap = 0; 00803 #if __BYTE_ORDER == __BIG_ENDIAN 00804 if (frame->subclass == AST_FORMAT_SLINEAR) 00805 swap = 1; /* Swap big-endian samples to little-endian as we copy */ 00806 #endif 00807 res = phone_write_buf(p, pos, expected, maxfr, swap); 00808 } 00809 if (res != expected) { 00810 if ((errno != EAGAIN) && (errno != EINTR)) { 00811 if (res < 0) 00812 ast_log(LOG_WARNING, "Write returned error (%s)\n", strerror(errno)); 00813 /* 00814 * Card is in non-blocking mode now and it works well now, but there are 00815 * lot of messages like this. So, this message is temporarily disabled. 00816 */ 00817 #if 0 00818 else 00819 ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frame->datalen); 00820 #endif 00821 return -1; 00822 } else /* Pretend it worked */ 00823 res = expected; 00824 } 00825 sofar += res; 00826 pos += res; 00827 } 00828 return 0; 00829 }
static int phone_write_buf | ( | struct phone_pvt * | p, | |
const char * | buf, | |||
int | len, | |||
int | frlen, | |||
int | swap | |||
) | [static] |
Definition at line 612 of file chan_phone.c.
References ast_log(), ast_swapcopy_samples(), phone_pvt::fd, LOG_WARNING, phone_pvt::obuf, and phone_pvt::obuflen.
Referenced by phone_send_text(), and phone_write().
00613 { 00614 int res; 00615 /* Store as much of the buffer as we can, then write fixed frames */ 00616 int space = sizeof(p->obuf) - p->obuflen; 00617 /* Make sure we have enough buffer space to store the frame */ 00618 if (space < len) 00619 len = space; 00620 if (swap) 00621 ast_swapcopy_samples(p->obuf+p->obuflen, buf, len/2); 00622 else 00623 memcpy(p->obuf + p->obuflen, buf, len); 00624 p->obuflen += len; 00625 while(p->obuflen > frlen) { 00626 res = write(p->fd, p->obuf, frlen); 00627 if (res != frlen) { 00628 if (res < 1) { 00629 /* 00630 * Card is in non-blocking mode now and it works well now, but there are 00631 * lot of messages like this. So, this message is temporarily disabled. 00632 */ 00633 return 0; 00634 } else { 00635 ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frlen); 00636 } 00637 } 00638 p->obuflen -= frlen; 00639 /* Move memory if necessary */ 00640 if (p->obuflen) 00641 memmove(p->obuf, p->obuf + frlen, p->obuflen); 00642 } 00643 return len; 00644 }
static int restart_monitor | ( | void | ) | [static] |
Definition at line 1120 of file chan_phone.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, AST_PTHREADT_NULL, AST_PTHREADT_STOP, do_monitor(), iflock, LOG_ERROR, LOG_WARNING, and monlock.
01121 { 01122 /* If we're supposed to be stopped -- stay stopped */ 01123 if (monitor_thread == AST_PTHREADT_STOP) 01124 return 0; 01125 if (ast_mutex_lock(&monlock)) { 01126 ast_log(LOG_WARNING, "Unable to lock monitor\n"); 01127 return -1; 01128 } 01129 if (monitor_thread == pthread_self()) { 01130 ast_mutex_unlock(&monlock); 01131 ast_log(LOG_WARNING, "Cannot kill myself\n"); 01132 return -1; 01133 } 01134 if (monitor_thread != AST_PTHREADT_NULL) { 01135 if (ast_mutex_lock(&iflock)) { 01136 ast_mutex_unlock(&monlock); 01137 ast_log(LOG_WARNING, "Unable to lock the interface list\n"); 01138 return -1; 01139 } 01140 monitor = 0; 01141 while (pthread_kill(monitor_thread, SIGURG) == 0) 01142 sched_yield(); 01143 pthread_join(monitor_thread, NULL); 01144 ast_mutex_unlock(&iflock); 01145 } 01146 monitor = 1; 01147 /* Start a new monitor */ 01148 if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) { 01149 ast_mutex_unlock(&monlock); 01150 ast_log(LOG_ERROR, "Unable to start monitor thread.\n"); 01151 return -1; 01152 } 01153 ast_mutex_unlock(&monlock); 01154 return 0; 01155 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1337 of file chan_phone.c.
References __unload_module().
01338 { 01339 return __unload_module(); 01340 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Linux Telephony API Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 1451 of file chan_phone.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1451 of file chan_phone.c.
char cid_name[AST_MAX_EXTENSION] [static] |
Definition at line 158 of file chan_phone.c.
char cid_num[AST_MAX_EXTENSION] [static] |
Definition at line 157 of file chan_phone.c.
const char config[] = "phone.conf" [static] |
Definition at line 92 of file chan_phone.c.
char context[AST_MAX_EXTENSION] = "default" [static] |
Definition at line 95 of file chan_phone.c.
struct ast_channel_tech* cur_tech [static] |
Definition at line 208 of file chan_phone.c.
Referenced by __unload_module(), load_module(), and phone_new().
int echocancel = AEC_OFF [static] |
Definition at line 100 of file chan_phone.c.
ast_mutex_t iflock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static] |
Definition at line 107 of file chan_phone.c.
char language[MAX_LANGUAGE] = "" [static] |
Definition at line 98 of file chan_phone.c.
unsigned int monitor [static] |
pthread_t monitor_thread = AST_PTHREADT_NULL [static] |
Definition at line 118 of file chan_phone.c.
ast_mutex_t monlock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static] |
Definition at line 111 of file chan_phone.c.
struct ast_channel_tech phone_tech [static] |
struct ast_channel_tech phone_tech_fxs [static] |
int prefformat = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW [static] |
Definition at line 104 of file chan_phone.c.
int silencesupression = 0 [static] |
Definition at line 102 of file chan_phone.c.
const char tdesc[] = "Standard Linux Telephony API Driver" [static] |
Definition at line 91 of file chan_phone.c.