Generic Linux Telephony Interface driver. More...
#include "asterisk.h"#include <ctype.h>#include <sys/socket.h>#include <sys/time.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/module.h"#include "asterisk/pbx.h"#include "asterisk/utils.h"#include "asterisk/callerid.h"#include "asterisk/causes.h"#include "asterisk/stringfields.h"#include "asterisk/musiconhold.h"#include "chan_phone.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 (const char *iface, int mode, int txgain, int rxgain) |
| static int | parse_gain_value (const char *gain_type, const char *value) |
| static int | phone_answer (struct ast_channel *ast) |
| static int | phone_call (struct ast_channel *ast, const 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 *cntx, const char *linkedid) |
| static struct ast_frame * | phone_read (struct ast_channel *ast) |
| static struct ast_channel * | phone_request (const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *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_LOAD_ORDER , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
| static 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 = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } |
| static char | language [MAX_LANGUAGE] = "" |
| static unsigned int | monitor |
| static pthread_t | monitor_thread = AST_PTHREADT_NULL |
| static ast_mutex_t | monlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } |
| static struct ast_channel_tech | phone_tech |
| static struct ast_channel_tech | phone_tech_fxs |
| static struct ast_format_cap * | prefcap |
| static int | silencesupression = 0 |
| static const char | tdesc [] = "Standard Linux Telephony API Driver" |
Generic Linux Telephony Interface driver.
Definition in file chan_phone.c.
| #define DEFAULT_CALLER_ID "Unknown" |
Definition at line 81 of file chan_phone.c.
Referenced by phone_call().
| #define DEFAULT_GAIN 0x100 |
Definition at line 83 of file chan_phone.c.
Referenced by load_module(), and parse_gain_value().
| #define IXJ_PHONE_RING_START | ( | x | ) | ioctl(p->fd, PHONE_RING_START, &x); |
Definition at line 78 of file chan_phone.c.
Referenced by phone_call().
| #define MODE_DIALTONE 1 |
Definition at line 119 of file chan_phone.c.
Referenced by load_module(), and phone_check_exception().
| #define MODE_FXO 3 |
Definition at line 121 of file chan_phone.c.
Referenced by load_module(), mkif(), phone_answer(), phone_exception(), and phone_hangup().
| #define MODE_FXS 4 |
Definition at line 122 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 120 of file chan_phone.c.
Referenced by load_module(), and phone_check_exception().
| #define MODE_SIGMA 5 |
Definition at line 123 of file chan_phone.c.
Referenced by do_monitor(), load_module(), and phone_check_exception().
| #define PHONE_MAX_BUF 480 |
Definition at line 82 of file chan_phone.c.
Referenced by phone_read().
| #define QNDRV_VER 100 |
Definition at line 68 of file chan_phone.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 1497 of file chan_phone.c.
| static int __unload_module | ( | void | ) | [static] |
Definition at line 1297 of file chan_phone.c.
References ast_channel_unregister(), ast_format_cap_destroy(), ast_free, ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_channel_tech::capabilities, phone_pvt::fd, iflist, iflock, LOG_WARNING, monlock, phone_pvt::next, and phone_pvt::owner.
Referenced by load_module(), and unload_module().
{
struct phone_pvt *p, *pl;
/* First, take us out of the channel loop */
if (cur_tech)
ast_channel_unregister(cur_tech);
if (!ast_mutex_lock(&iflock)) {
/* Hangup all interfaces if they have an owner */
p = iflist;
while(p) {
if (p->owner)
ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
p = p->next;
}
iflist = NULL;
ast_mutex_unlock(&iflock);
} else {
ast_log(LOG_WARNING, "Unable to lock the monitor\n");
return -1;
}
if (!ast_mutex_lock(&monlock)) {
if (monitor_thread > AST_PTHREADT_NULL) {
monitor = 0;
while (pthread_kill(monitor_thread, SIGURG) == 0)
sched_yield();
pthread_join(monitor_thread, NULL);
}
monitor_thread = AST_PTHREADT_STOP;
ast_mutex_unlock(&monlock);
} else {
ast_log(LOG_WARNING, "Unable to lock the monitor\n");
return -1;
}
if (!ast_mutex_lock(&iflock)) {
/* Destroy all the interfaces and free their memory */
p = iflist;
while(p) {
/* Close the socket, assuming it's real */
if (p->fd > -1)
close(p->fd);
pl = p;
p = p->next;
/* Free associated memory */
ast_free(pl);
}
iflist = NULL;
ast_mutex_unlock(&iflock);
} else {
ast_log(LOG_WARNING, "Unable to lock the monitor\n");
return -1;
}
phone_tech.capabilities = ast_format_cap_destroy(phone_tech.capabilities);
phone_tech_fxs.capabilities = ast_format_cap_destroy(phone_tech_fxs.capabilities);
prefcap = ast_format_cap_destroy(prefcap);
return 0;
}
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1497 of file chan_phone.c.
| static void* do_monitor | ( | void * | data | ) | [static] |
Definition at line 1016 of file chan_phone.c.
References ast_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_poll, ast_poll2(), ast_realloc, ast_tv(), ast_tvzero(), phone_pvt::dialtone, DialTone, errno, phone_pvt::fd, iflist, iflock, LOG_ERROR, LOG_WARNING, phone_pvt::mode, MODE_SIGMA, phone_pvt::next, phone_pvt::owner, phone_check_exception(), and phone_mini_packet().
Referenced by restart_monitor().
{
struct pollfd *fds = NULL;
int nfds = 0, inuse_fds = 0, res;
struct phone_pvt *i;
int tonepos = 0;
/* The tone we're playing this round */
struct timeval to = { 0, 0 };
int dotone;
/* This thread monitors all the frame relay interfaces which are not yet in use
(and thus do not have a separate thread) indefinitely */
while (monitor) {
/* Don't let anybody kill us right away. Nobody should lock the interface list
and wait for the monitor list, but the other way around is okay. */
/* Lock the interface list */
if (ast_mutex_lock(&iflock)) {
ast_log(LOG_ERROR, "Unable to grab interface lock\n");
return NULL;
}
/* Build the stuff we're going to select on, that is the socket of every
phone_pvt that does not have an associated owner channel */
i = iflist;
dotone = 0;
inuse_fds = 0;
for (i = iflist; i; i = i->next) {
if (!i->owner) {
/* This needs to be watched, as it lacks an owner */
if (inuse_fds == nfds) {
void *tmp = ast_realloc(fds, (nfds + 1) * sizeof(*fds));
if (!tmp) {
/* Avoid leaking */
continue;
}
fds = tmp;
nfds++;
}
fds[inuse_fds].fd = i->fd;
fds[inuse_fds].events = POLLIN | POLLERR;
fds[inuse_fds].revents = 0;
inuse_fds++;
if (i->dialtone && i->mode != MODE_SIGMA) {
/* Remember we're going to have to come back and play
more dialtones */
if (ast_tvzero(to)) {
/* If we're due for a dialtone, play one */
if (write(i->fd, DialTone + tonepos, 240) != 240) {
ast_log(LOG_WARNING, "Dial tone write error\n");
}
}
dotone++;
}
}
}
/* Okay, now that we know what to do, release the interface lock */
ast_mutex_unlock(&iflock);
/* Wait indefinitely for something to happen */
if (dotone && i && i->mode != MODE_SIGMA) {
/* If we're ready to recycle the time, set it to 30 ms */
tonepos += 240;
if (tonepos >= sizeof(DialTone)) {
tonepos = 0;
}
if (ast_tvzero(to)) {
to = ast_tv(0, 30000);
}
res = ast_poll2(fds, inuse_fds, &to);
} else {
res = ast_poll(fds, inuse_fds, -1);
to = ast_tv(0, 0);
tonepos = 0;
}
/* Okay, select has finished. Let's see what happened. */
if (res < 0) {
ast_debug(1, "poll returned %d: %s\n", res, strerror(errno));
continue;
}
/* If there are no fd's changed, just continue, it's probably time
to play some more dialtones */
if (!res) {
continue;
}
/* Alright, lock the interface list again, and let's look and see what has
happened */
if (ast_mutex_lock(&iflock)) {
ast_log(LOG_WARNING, "Unable to lock the interface list\n");
continue;
}
for (i = iflist; i; i = i->next) {
int j;
/* Find the record */
for (j = 0; j < inuse_fds; j++) {
if (fds[j].fd == i->fd) {
break;
}
}
/* Not found? */
if (j == inuse_fds) {
continue;
}
if (fds[j].revents & POLLIN) {
if (i->owner) {
continue;
}
phone_mini_packet(i);
}
if (fds[j].revents & POLLERR) {
if (i->owner) {
continue;
}
phone_check_exception(i);
}
}
ast_mutex_unlock(&iflock);
}
return NULL;
}
| static int load_module | ( | void | ) | [static] |
Definition at line 1361 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_cap_add(), ast_format_cap_alloc(), ast_format_cap_copy(), ast_format_cap_remove_bytype(), ast_format_cap_set(), AST_FORMAT_G723_1, AST_FORMAT_G729A, ast_format_set(), AST_FORMAT_SLINEAR, AST_FORMAT_TYPE_AUDIO, 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, CONFIG_STATUS_FILEINVALID, 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_fxs, restart_monitor(), phone_pvt::rxgain, phone_pvt::txgain, and ast_variable::value.
{
struct ast_config *cfg;
struct ast_variable *v;
struct phone_pvt *tmp;
int mode = MODE_IMMEDIATE;
int txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; /* default gain 1.0 */
struct ast_flags config_flags = { 0 };
struct ast_format tmpfmt;
if (!(phone_tech.capabilities = ast_format_cap_alloc())) {
return AST_MODULE_LOAD_DECLINE;
}
ast_format_cap_add(phone_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0));
ast_format_cap_add(phone_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
ast_format_cap_add(phone_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
ast_format_cap_add(phone_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0));
if (!(prefcap = ast_format_cap_alloc())) {
return AST_MODULE_LOAD_DECLINE;
}
ast_format_cap_copy(prefcap, phone_tech.capabilities);
if (!(phone_tech_fxs.capabilities = ast_format_cap_alloc())) {
return AST_MODULE_LOAD_DECLINE;
}
if ((cfg = ast_config_load(config, config_flags)) == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config);
return AST_MODULE_LOAD_DECLINE;
}
/* We *must* have a config file otherwise stop immediately */
if (!cfg) {
ast_log(LOG_ERROR, "Unable to load config %s\n", config);
return AST_MODULE_LOAD_DECLINE;
}
if (ast_mutex_lock(&iflock)) {
/* It's a little silly to lock it, but we mind as well just to be sure */
ast_log(LOG_ERROR, "Unable to lock interface list???\n");
return AST_MODULE_LOAD_FAILURE;
}
v = ast_variable_browse(cfg, "interfaces");
while(v) {
/* Create the interface list */
if (!strcasecmp(v->name, "device")) {
tmp = mkif(v->value, mode, txgain, rxgain);
if (tmp) {
tmp->next = iflist;
iflist = tmp;
} else {
ast_log(LOG_ERROR, "Unable to register channel '%s'\n", v->value);
ast_config_destroy(cfg);
ast_mutex_unlock(&iflock);
__unload_module();
return AST_MODULE_LOAD_FAILURE;
}
} else if (!strcasecmp(v->name, "silencesupression")) {
silencesupression = ast_true(v->value);
} else if (!strcasecmp(v->name, "language")) {
ast_copy_string(language, v->value, sizeof(language));
} else if (!strcasecmp(v->name, "callerid")) {
ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
} else if (!strcasecmp(v->name, "mode")) {
if (!strncasecmp(v->value, "di", 2))
mode = MODE_DIALTONE;
else if (!strncasecmp(v->value, "sig", 3))
mode = MODE_SIGMA;
else if (!strncasecmp(v->value, "im", 2))
mode = MODE_IMMEDIATE;
else if (!strncasecmp(v->value, "fxs", 3)) {
mode = MODE_FXS;
ast_format_cap_remove_bytype(prefcap, AST_FORMAT_TYPE_AUDIO); /* All non-voice */
}
else if (!strncasecmp(v->value, "fx", 2))
mode = MODE_FXO;
else
ast_log(LOG_WARNING, "Unknown mode: %s\n", v->value);
} else if (!strcasecmp(v->name, "context")) {
ast_copy_string(context, v->value, sizeof(context));
} else if (!strcasecmp(v->name, "format")) {
if (!strcasecmp(v->value, "g729")) {
ast_format_cap_set(prefcap, ast_format_set(&tmpfmt, AST_FORMAT_G729A, 0));
} else if (!strcasecmp(v->value, "g723.1")) {
ast_format_cap_set(prefcap, ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0));
} else if (!strcasecmp(v->value, "slinear")) {
ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0);
if (mode == MODE_FXS) {
ast_format_cap_add(prefcap, &tmpfmt);
} else {
ast_format_cap_set(prefcap, &tmpfmt);
}
} else if (!strcasecmp(v->value, "ulaw")) {
ast_format_cap_set(prefcap, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
} else
ast_log(LOG_WARNING, "Unknown format '%s'\n", v->value);
} else if (!strcasecmp(v->name, "echocancel")) {
if (!strcasecmp(v->value, "off")) {
echocancel = AEC_OFF;
} else if (!strcasecmp(v->value, "low")) {
echocancel = AEC_LOW;
} else if (!strcasecmp(v->value, "medium")) {
echocancel = AEC_MED;
} else if (!strcasecmp(v->value, "high")) {
echocancel = AEC_HIGH;
} else
ast_log(LOG_WARNING, "Unknown echo cancellation '%s'\n", v->value);
} else if (!strcasecmp(v->name, "txgain")) {
txgain = parse_gain_value(v->name, v->value);
} else if (!strcasecmp(v->name, "rxgain")) {
rxgain = parse_gain_value(v->name, v->value);
}
v = v->next;
}
ast_mutex_unlock(&iflock);
if (mode == MODE_FXS) {
ast_format_cap_copy(phone_tech_fxs.capabilities, prefcap);
cur_tech = &phone_tech_fxs;
} else
cur_tech = (struct ast_channel_tech *) &phone_tech;
/* Make sure we can register our Adtranphone channel type */
if (ast_channel_register(cur_tech)) {
ast_log(LOG_ERROR, "Unable to register channel class 'Phone'\n");
ast_config_destroy(cfg);
__unload_module();
return AST_MODULE_LOAD_FAILURE;
}
ast_config_destroy(cfg);
/* And start the monitor for the first time */
restart_monitor();
return AST_MODULE_LOAD_SUCCESS;
}
| static struct phone_pvt* mkif | ( | const char * | iface, |
| int | mode, | ||
| int | txgain, | ||
| int | rxgain | ||
| ) | [static, read] |
Definition at line 1175 of file chan_phone.c.
References ast_calloc, ast_copy_string(), ast_debug, ast_format_clear(), ast_free, 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, phone_pvt::language, phone_pvt::lastformat, phone_pvt::lastinput, LOG_WARNING, 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().
{
/* Make a phone_pvt structure for this interface */
struct phone_pvt *tmp;
int flags;
tmp = ast_calloc(1, sizeof(*tmp));
if (tmp) {
tmp->fd = open(iface, O_RDWR);
if (tmp->fd < 0) {
ast_log(LOG_WARNING, "Unable to open '%s'\n", iface);
ast_free(tmp);
return NULL;
}
if (mode == MODE_FXO) {
if (ioctl(tmp->fd, IXJCTL_PORT, PORT_PSTN)) {
ast_debug(1, "Unable to set port to PSTN\n");
}
} else {
if (ioctl(tmp->fd, IXJCTL_PORT, PORT_POTS))
if (mode != MODE_FXS)
ast_debug(1, "Unable to set port to POTS\n");
}
ioctl(tmp->fd, PHONE_PLAY_STOP);
ioctl(tmp->fd, PHONE_REC_STOP);
ioctl(tmp->fd, PHONE_RING_STOP);
ioctl(tmp->fd, PHONE_CPT_STOP);
if (ioctl(tmp->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK))
ast_debug(1, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",iface, strerror(errno));
if (echocancel != AEC_OFF)
ioctl(tmp->fd, IXJCTL_AEC_START, echocancel);
if (silencesupression)
tmp->silencesupression = 1;
#ifdef PHONE_VAD
ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression);
#endif
tmp->mode = mode;
flags = fcntl(tmp->fd, F_GETFL);
fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK);
tmp->owner = NULL;
ast_format_clear(&tmp->lastformat);
ast_format_clear(&tmp->lastinput);
tmp->ministate = 0;
memset(tmp->ext, 0, sizeof(tmp->ext));
ast_copy_string(tmp->language, language, sizeof(tmp->language));
ast_copy_string(tmp->dev, iface, sizeof(tmp->dev));
ast_copy_string(tmp->context, context, sizeof(tmp->context));
tmp->next = NULL;
tmp->obuflen = 0;
tmp->dialtone = 0;
tmp->cpt = 0;
ast_copy_string(tmp->cid_num, cid_num, sizeof(tmp->cid_num));
ast_copy_string(tmp->cid_name, cid_name, sizeof(tmp->cid_name));
tmp->txgain = txgain;
ioctl(tmp->fd, PHONE_PLAY_VOLUME, tmp->txgain);
tmp->rxgain = rxgain;
ioctl(tmp->fd, PHONE_REC_VOLUME, tmp->rxgain);
}
return tmp;
}
| static int parse_gain_value | ( | const char * | gain_type, |
| const char * | value | ||
| ) | [static] |
Definition at line 1275 of file chan_phone.c.
References ast_log(), DEFAULT_GAIN, and LOG_ERROR.
Referenced by load_module().
{
float gain;
/* try to scan number */
if (sscanf(value, "%30f", &gain) != 1)
{
ast_log(LOG_ERROR, "Invalid %s value '%s' in '%s' config\n",
value, gain_type, config);
return DEFAULT_GAIN;
}
/* multiplicate gain by 1.0 gain value */
gain = gain * (float)DEFAULT_GAIN;
/* percentage? */
if (value[strlen(value) - 1] == '%')
return (int)(gain / (float)100);
return (int)gain;
}
| static int phone_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 458 of file chan_phone.c.
References ast_channel_name(), ast_channel_rings_set(), ast_channel_tech_pvt(), ast_debug, ast_setstate(), AST_STATE_UP, errno, phone_pvt::fd, phone_pvt::mode, MODE_FXO, and phone_setup().
{
struct phone_pvt *p;
p = ast_channel_tech_pvt(ast);
/* In case it's a LineJack, take it off hook */
if (p->mode == MODE_FXO) {
if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_OFF_HOOK))
ast_debug(1, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n", ast_channel_name(ast), strerror(errno));
else
ast_debug(1, "Took linejack off hook\n");
}
phone_setup(ast);
ast_debug(1, "phone_answer(%s)\n", ast_channel_name(ast));
ast_channel_rings_set(ast, 0);
ast_setstate(ast, AST_STATE_UP);
return 0;
}
| static int phone_call | ( | struct ast_channel * | ast, |
| const char * | dest, | ||
| int | timeout | ||
| ) | [static] |
Definition at line 289 of file chan_phone.c.
References ast_channel_connected(), ast_channel_fd(), ast_channel_name(), ast_channel_tech_pvt(), AST_CONTROL_RINGING, ast_copy_string(), ast_debug, ast_localtime(), ast_log(), ast_queue_control(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RINGING, ast_strlen_zero(), ast_tvnow(), DEFAULT_CALLER_ID, IXJ_PHONE_RING_START, LOG_WARNING, phone_pvt::mode, MODE_FXS, name, phone_digit_end(), ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, and ast_tm::tm_mon.
{
struct phone_pvt *p;
PHONE_CID cid;
struct timeval UtcTime = ast_tvnow();
struct ast_tm tm;
int start;
ast_localtime(&UtcTime, &tm, NULL);
memset(&cid, 0, sizeof(PHONE_CID));
snprintf(cid.month, sizeof(cid.month), "%02d",(tm.tm_mon + 1));
snprintf(cid.day, sizeof(cid.day), "%02d", tm.tm_mday);
snprintf(cid.hour, sizeof(cid.hour), "%02d", tm.tm_hour);
snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min);
/* the standard format of ast->callerid is: "name" <number>, but not always complete */
if (!ast_channel_connected(ast)->id.name.valid
|| ast_strlen_zero(ast_channel_connected(ast)->id.name.str)) {
strcpy(cid.name, DEFAULT_CALLER_ID);
} else {
ast_copy_string(cid.name, ast_channel_connected(ast)->id.name.str, sizeof(cid.name));
}
if (ast_channel_connected(ast)->id.number.valid && ast_channel_connected(ast)->id.number.str) {
ast_copy_string(cid.number, ast_channel_connected(ast)->id.number.str, sizeof(cid.number));
}
p = ast_channel_tech_pvt(ast);
if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
ast_log(LOG_WARNING, "phone_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
return -1;
}
ast_debug(1, "Ringing %s on %s (%d)\n", dest, ast_channel_name(ast), ast_channel_fd(ast, 0));
start = IXJ_PHONE_RING_START(cid);
if (start == -1)
return -1;
if (p->mode == MODE_FXS) {
const char *digit = strchr(dest, '/');
if (digit)
{
digit++;
while (*digit)
phone_digit_end(ast, *digit++, 0);
}
}
ast_setstate(ast, AST_STATE_RINGING);
ast_queue_control(ast, AST_CONTROL_RINGING);
return 0;
}
| static void phone_check_exception | ( | struct phone_pvt * | i | ) | [static] |
Definition at line 923 of file chan_phone.c.
References ast_canmatch_extension(), ast_debug, ast_exists_extension(), ast_format_clear(), 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, phone_pvt::mode, MODE_DIALTONE, MODE_FXS, MODE_IMMEDIATE, MODE_SIGMA, phone_new(), and ast_module_info::self.
Referenced by do_monitor().
{
int offhook=0;
char digit[2] = {0 , 0};
union telephony_exception phonee;
/* XXX Do something XXX */
#if 0
ast_debug(1, "Exception!\n");
#endif
phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION);
if (phonee.bits.dtmf_ready) {
digit[0] = ioctl(i->fd, PHONE_GET_DTMF_ASCII);
if (i->mode == MODE_DIALTONE || i->mode == MODE_FXS || i->mode == MODE_SIGMA) {
ioctl(i->fd, PHONE_PLAY_STOP);
ioctl(i->fd, PHONE_REC_STOP);
ioctl(i->fd, PHONE_CPT_STOP);
i->dialtone = 0;
if (strlen(i->ext) < AST_MAX_EXTENSION - 1)
strncat(i->ext, digit, sizeof(i->ext) - strlen(i->ext) - 1);
if ((i->mode != MODE_FXS ||
!(phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION)) ||
!phonee.bits.dtmf_ready) &&
ast_exists_extension(NULL, i->context, i->ext, 1, i->cid_num)) {
/* It's a valid extension in its context, get moving! */
phone_new(i, AST_STATE_RING, i->context, NULL);
/* No need to restart monitor, we are the monitor */
} else if (!ast_canmatch_extension(NULL, i->context, i->ext, 1, i->cid_num)) {
/* There is nothing in the specified extension that can match anymore.
Try the default */
if (ast_exists_extension(NULL, "default", i->ext, 1, i->cid_num)) {
/* Check the default, too... */
phone_new(i, AST_STATE_RING, "default", NULL);
/* XXX This should probably be justified better XXX */
} else if (!ast_canmatch_extension(NULL, "default", i->ext, 1, i->cid_num)) {
/* It's not a valid extension, give a busy signal */
ast_debug(1, "%s can't match anything in %s or default\n", i->ext, i->context);
ioctl(i->fd, PHONE_BUSY);
i->cpt = 1;
}
}
#if 0
ast_verbose("Extension is %s\n", i->ext);
#endif
}
}
if (phonee.bits.hookstate) {
offhook = ioctl(i->fd, PHONE_HOOKSTATE);
if (offhook) {
if (i->mode == MODE_IMMEDIATE) {
phone_new(i, AST_STATE_RING, i->context, NULL);
} else if (i->mode == MODE_DIALTONE) {
ast_module_ref(ast_module_info->self);
/* Reset the extension */
i->ext[0] = '\0';
/* Play the dialtone */
i->dialtone++;
ioctl(i->fd, PHONE_PLAY_STOP);
ioctl(i->fd, PHONE_PLAY_CODEC, ULAW);
ioctl(i->fd, PHONE_PLAY_START);
ast_format_clear(&i->lastformat);
} else if (i->mode == MODE_SIGMA) {
ast_module_ref(ast_module_info->self);
/* Reset the extension */
i->ext[0] = '\0';
/* Play the dialtone */
i->dialtone++;
ioctl(i->fd, PHONE_DIALTONE);
}
} else {
if (i->dialtone)
ast_module_unref(ast_module_info->self);
memset(i->ext, 0, sizeof(i->ext));
if (i->cpt)
{
ioctl(i->fd, PHONE_CPT_STOP);
i->cpt = 0;
}
ioctl(i->fd, PHONE_PLAY_STOP);
ioctl(i->fd, PHONE_REC_STOP);
i->dialtone = 0;
ast_format_clear(&i->lastformat);
}
}
if (phonee.bits.pstn_ring) {
ast_verbose("Unit is ringing\n");
phone_new(i, AST_STATE_RING, i->context, NULL);
}
if (phonee.bits.caller_id)
ast_verbose("We have caller ID\n");
}
| static int phone_digit_begin | ( | struct ast_channel * | ast, |
| char | digit | ||
| ) | [static] |
Definition at line 241 of file chan_phone.c.
{
/* XXX Modify this callback to let Asterisk support controlling the length of DTMF */
return 0;
}
| static int phone_digit_end | ( | struct ast_channel * | ast, |
| char | digit, | ||
| unsigned int | duration | ||
| ) | [static] |
Definition at line 247 of file chan_phone.c.
References ast_channel_tech_pvt(), ast_debug, ast_format_clear(), ast_log(), phone_pvt::fd, phone_pvt::lastformat, and LOG_WARNING.
Referenced by phone_call().
{
struct phone_pvt *p;
int outdigit;
p = ast_channel_tech_pvt(ast);
ast_debug(1, "Dialed %c\n", digit);
switch(digit) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
outdigit = digit - '0';
break;
case '*':
outdigit = 11;
break;
case '#':
outdigit = 12;
break;
case 'f': /*flash*/
case 'F':
ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
usleep(320000);
ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
ast_format_clear(&p->lastformat);
return 0;
default:
ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit);
return -1;
}
ast_debug(1, "Dialed %d\n", outdigit);
ioctl(p->fd, PHONE_PLAY_TONE, outdigit);
ast_format_clear(&p->lastformat);
return 0;
}
| static struct ast_frame * phone_exception | ( | struct ast_channel * | ast | ) | [static, read] |
Definition at line 490 of file chan_phone.c.
References ast_channel_tech_pvt(), AST_CONTROL_ANSWER, ast_debug, 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, ast_frame_subclass::integer, LOG_WARNING, ast_frame::mallocd, phone_pvt::mode, MODE_FXO, ast_frame::offset, phone_setup(), ast_frame::ptr, ast_frame::samples, ast_frame::src, and ast_frame::subclass.
{
int res;
union telephony_exception phonee;
struct phone_pvt *p = ast_channel_tech_pvt(ast);
char digit;
/* Some nice norms */
p->fr.datalen = 0;
p->fr.samples = 0;
p->fr.data.ptr = NULL;
p->fr.src = "Phone";
p->fr.offset = 0;
p->fr.mallocd=0;
p->fr.delivery = ast_tv(0,0);
phonee.bytes = ioctl(p->fd, PHONE_EXCEPTION);
if (phonee.bits.dtmf_ready) {
ast_debug(1, "phone_exception(): DTMF\n");
/* We've got a digit -- Just handle this nicely and easily */
digit = ioctl(p->fd, PHONE_GET_DTMF_ASCII);
p->fr.subclass.integer = digit;
p->fr.frametype = AST_FRAME_DTMF;
return &p->fr;
}
if (phonee.bits.hookstate) {
ast_debug(1, "Hookstate changed\n");
res = ioctl(p->fd, PHONE_HOOKSTATE);
/* See if we've gone on hook, if so, notify by returning NULL */
ast_debug(1, "New hookstate: %d\n", res);
if (!res && (p->mode != MODE_FXO))
return NULL;
else {
if (ast_channel_state(ast) == AST_STATE_RINGING) {
/* They've picked up the phone */
p->fr.frametype = AST_FRAME_CONTROL;
p->fr.subclass.integer = AST_CONTROL_ANSWER;
phone_setup(ast);
ast_setstate(ast, AST_STATE_UP);
return &p->fr;
} else
ast_log(LOG_WARNING, "Got off hook in weird state %d\n", ast_channel_state(ast));
}
}
#if 1
if (phonee.bits.pstn_ring)
ast_verbose("Unit is ringing\n");
if (phonee.bits.caller_id) {
ast_verbose("We have caller ID\n");
}
if (phonee.bits.pstn_wink)
ast_verbose("Detected Wink\n");
#endif
/* Strange -- nothing there.. */
p->fr.frametype = AST_FRAME_NULL;
p->fr.subclass.integer = 0;
return &p->fr;
}
| static int phone_fixup | ( | struct ast_channel * | old, |
| struct ast_channel * | new | ||
| ) | [static] |
Definition at line 233 of file chan_phone.c.
References ast_channel_tech_pvt(), and phone_pvt::owner.
{
struct phone_pvt *pvt = ast_channel_tech_pvt(old);
if (pvt && pvt->owner == old)
pvt->owner = new;
return 0;
}
| static int phone_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 344 of file chan_phone.c.
References ast_channel_name(), ast_channel_tech_pvt(), ast_channel_tech_pvt_set(), ast_debug, ast_format_clear(), ast_log(), ast_module_unref(), ast_setstate(), AST_STATE_DOWN, ast_verb, phone_pvt::cpt, phone_pvt::dialtone, errno, phone_pvt::ext, phone_pvt::fd, phone_pvt::lastformat, phone_pvt::lastinput, LOG_WARNING, phone_pvt::ministate, phone_pvt::mode, MODE_FXO, phone_pvt::obuflen, restart_monitor(), and ast_module_info::self.
{
struct phone_pvt *p;
p = ast_channel_tech_pvt(ast);
ast_debug(1, "phone_hangup(%s)\n", ast_channel_name(ast));
if (!ast_channel_tech_pvt(ast)) {
ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
return 0;
}
/* XXX Is there anything we can do to really hang up except stop recording? */
ast_setstate(ast, AST_STATE_DOWN);
if (ioctl(p->fd, PHONE_REC_STOP))
ast_log(LOG_WARNING, "Failed to stop recording\n");
if (ioctl(p->fd, PHONE_PLAY_STOP))
ast_log(LOG_WARNING, "Failed to stop playing\n");
if (ioctl(p->fd, PHONE_RING_STOP))
ast_log(LOG_WARNING, "Failed to stop ringing\n");
if (ioctl(p->fd, PHONE_CPT_STOP))
ast_log(LOG_WARNING, "Failed to stop sounds\n");
/* If it's an FXO, hang them up */
if (p->mode == MODE_FXO) {
if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK))
ast_debug(1, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",ast_channel_name(ast), strerror(errno));
}
/* If they're off hook, give a busy signal */
if (ioctl(p->fd, PHONE_HOOKSTATE)) {
ast_debug(1, "Got hunghup, giving busy signal\n");
ioctl(p->fd, PHONE_BUSY);
p->cpt = 1;
}
ast_format_clear(&p->lastformat);
ast_format_clear(&p->lastinput);
p->ministate = 0;
p->obuflen = 0;
p->dialtone = 0;
memset(p->ext, 0, sizeof(p->ext));
((struct phone_pvt *)(ast_channel_tech_pvt(ast)))->owner = NULL;
ast_module_unref(ast_module_info->self);
ast_verb(3, "Hungup '%s'\n", ast_channel_name(ast));
ast_channel_tech_pvt_set(ast, NULL);
ast_setstate(ast, AST_STATE_DOWN);
restart_monitor();
return 0;
}
| static int phone_indicate | ( | struct ast_channel * | chan, |
| int | condition, | ||
| const void * | data, | ||
| size_t | datalen | ||
| ) | [static] |
Definition at line 203 of file chan_phone.c.
References ast_channel_name(), ast_channel_tech_pvt(), AST_CONTROL_FLASH, AST_CONTROL_HOLD, AST_CONTROL_PVT_CAUSE_CODE, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, ast_debug, ast_format_clear(), ast_log(), ast_moh_start(), ast_moh_stop(), phone_pvt::fd, phone_pvt::lastformat, and LOG_WARNING.
{
struct phone_pvt *p = ast_channel_tech_pvt(chan);
int res=-1;
ast_debug(1, "Requested indication %d on channel %s\n", condition, ast_channel_name(chan));
switch(condition) {
case AST_CONTROL_FLASH:
ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
usleep(320000);
ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
ast_format_clear(&p->lastformat);
res = 0;
break;
case AST_CONTROL_HOLD:
ast_moh_start(chan, data, NULL);
break;
case AST_CONTROL_UNHOLD:
ast_moh_stop(chan);
break;
case AST_CONTROL_SRCUPDATE:
res = 0;
break;
case AST_CONTROL_PVT_CAUSE_CODE:
break;
default:
ast_log(LOG_WARNING, "Condition %d is not supported on channel %s\n", condition, ast_channel_name(chan));
}
return res;
}
| static void phone_mini_packet | ( | struct phone_pvt * | i | ) | [static] |
Definition at line 911 of file chan_phone.c.
References ast_log(), errno, phone_pvt::fd, and LOG_WARNING.
Referenced by do_monitor().
{
int res;
char buf[1024];
/* Ignore stuff we read... */
res = read(i->fd, buf, sizeof(buf));
if (res < 1) {
ast_log(LOG_WARNING, "Read returned %d: %s\n", res, strerror(errno));
return;
}
}
| static struct ast_channel* phone_new | ( | struct phone_pvt * | i, |
| int | state, | ||
| char * | cntx, | ||
| const char * | linkedid | ||
| ) | [static, read] |
Definition at line 850 of file chan_phone.c.
References ast_party_caller::ani, ast_best_codec(), ast_channel_alloc(), ast_channel_caller(), ast_channel_context_set(), ast_channel_exten_set(), ast_channel_fd(), ast_channel_name(), ast_channel_nativeformats(), ast_channel_rawreadformat(), ast_channel_rawwriteformat(), ast_channel_rings_set(), ast_channel_set_fd(), ast_channel_tech_pvt_set(), ast_channel_tech_set(), ast_format_cap_add(), ast_format_cap_copy(), ast_format_cap_remove(), ast_format_copy(), ast_format_set(), AST_FORMAT_SLINEAR, ast_hangup(), ast_log(), ast_module_ref(), ast_pbx_start(), AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_strlen_zero(), phone_pvt::cid_name, phone_pvt::cid_num, phone_pvt::context, phone_pvt::cpt, phone_pvt::dev, phone_pvt::ext, phone_pvt::fd, phone_pvt::language, LOG_WARNING, phone_pvt::mode, MODE_FXS, ast_party_id::number, phone_pvt::owner, ast_module_info::self, ast_party_number::str, and ast_party_number::valid.
Referenced by phone_check_exception(), and phone_request().
{
struct ast_channel *tmp;
struct phone_codec_data queried_codec;
struct ast_format tmpfmt;
tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", i->ext, i->context, linkedid, 0, "Phone/%s", i->dev + 5);
if (tmp) {
ast_channel_tech_set(tmp, cur_tech);
ast_channel_set_fd(tmp, 0, i->fd);
/* XXX Switching formats silently causes kernel panics XXX */
if (i->mode == MODE_FXS &&
ioctl(i->fd, PHONE_QUERY_CODEC, &queried_codec) == 0) {
if (queried_codec.type == LINEAR16) {
ast_format_cap_add(ast_channel_nativeformats(tmp), ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
} else {
ast_format_cap_remove(prefcap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
}
} else {
ast_format_cap_copy(ast_channel_nativeformats(tmp), prefcap);
ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
}
/* no need to call ast_setstate: the channel_alloc already did its job */
if (state == AST_STATE_RING)
ast_channel_rings_set(tmp, 1);
ast_channel_tech_pvt_set(tmp, i);
ast_channel_context_set(tmp, cntx);
if (!ast_strlen_zero(i->ext))
ast_channel_exten_set(tmp, i->ext);
else
ast_channel_exten_set(tmp, "s");
if (!ast_strlen_zero(i->language))
ast_channel_language_set(tmp, i->language);
/* Don't use ast_set_callerid() here because it will
* generate a NewCallerID event before the NewChannel event */
if (!ast_strlen_zero(i->cid_num)) {
ast_channel_caller(tmp)->ani.number.valid = 1;
ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num);
}
i->owner = tmp;
ast_module_ref(ast_module_info->self);
if (state != AST_STATE_DOWN) {
if (state == AST_STATE_RING) {
ioctl(ast_channel_fd(tmp, 0), PHONE_RINGBACK);
i->cpt = 1;
}
if (ast_pbx_start(tmp)) {
ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
ast_hangup(tmp);
}
}
} else
ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
return tmp;
}
| static struct ast_frame * phone_read | ( | struct ast_channel * | ast | ) | [static, read] |
Definition at line 550 of file chan_phone.c.
References ast_channel_flags(), ast_channel_tech_pvt(), ast_clear_flag, AST_FLAG_BLOCKING, ast_format_copy(), AST_FORMAT_GET_TYPE, AST_FORMAT_SLINEAR, AST_FORMAT_TYPE_AUDIO, AST_FORMAT_TYPE_IMAGE, 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, ast_frame_subclass::format, phone_pvt::fr, ast_frame::frametype, ast_format::id, phone_pvt::lastinput, LOG_WARNING, ast_frame::mallocd, phone_pvt::mode, MODE_FXS, ast_frame::offset, PHONE_MAX_BUF, ast_frame::ptr, ast_frame::samples, ast_frame::src, and ast_frame::subclass.
{
int res;
struct phone_pvt *p = ast_channel_tech_pvt(ast);
/* Some nice norms */
p->fr.datalen = 0;
p->fr.samples = 0;
p->fr.data.ptr = NULL;
p->fr.src = "Phone";
p->fr.offset = 0;
p->fr.mallocd=0;
p->fr.delivery = ast_tv(0,0);
/* Try to read some data... */
CHECK_BLOCKING(ast);
res = read(p->fd, p->buf, PHONE_MAX_BUF);
ast_clear_flag(ast_channel_flags(ast), AST_FLAG_BLOCKING);
if (res < 0) {
#if 0
if (errno == EAGAIN) {
ast_log(LOG_WARNING, "Null frame received\n");
p->fr.frametype = AST_FRAME_NULL;
p->fr.subclass = 0;
return &p->fr;
}
#endif
ast_log(LOG_WARNING, "Error reading: %s\n", strerror(errno));
return NULL;
}
p->fr.data.ptr = p->buf;
if (p->mode != MODE_FXS)
switch(p->buf[0] & 0x3) {
case '0':
case '1':
/* Normal */
break;
case '2':
case '3':
/* VAD/CNG, only send two words */
res = 4;
break;
}
p->fr.samples = 240;
p->fr.datalen = res;
p->fr.frametype = AST_FORMAT_GET_TYPE(p->lastinput.id) == AST_FORMAT_TYPE_AUDIO ?
AST_FRAME_VOICE : AST_FORMAT_GET_TYPE(p->lastinput.id) == AST_FORMAT_TYPE_IMAGE ?
AST_FRAME_IMAGE : AST_FRAME_VIDEO;
ast_format_copy(&p->fr.subclass.format, &p->lastinput);
p->fr.offset = AST_FRIENDLY_OFFSET;
/* Byteswap from little-endian to native-endian */
if (p->fr.subclass.format.id == AST_FORMAT_SLINEAR)
ast_frame_byteswap_le(&p->fr);
return &p->fr;
}
| static struct ast_channel * phone_request | ( | const char * | type, |
| struct ast_format_cap * | cap, | ||
| const struct ast_channel * | requestor, | ||
| const char * | data, | ||
| int * | cause | ||
| ) | [static, read] |
Definition at line 1236 of file chan_phone.c.
References AST_CAUSE_BUSY, ast_channel_linkedid(), ast_format_cap_has_joint(), ast_getformatname_multiple(), ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_STATE_DOWN, ast_channel_tech::capabilities, phone_pvt::context, ast_channel::data, 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().
{
struct phone_pvt *p;
struct ast_channel *tmp = NULL;
const char *name = data;
/* Search for an unowned channel */
if (ast_mutex_lock(&iflock)) {
ast_log(LOG_ERROR, "Unable to lock interface list???\n");
return NULL;
}
p = iflist;
while(p) {
if (p->mode == MODE_FXS || (ast_format_cap_has_joint(cap, phone_tech.capabilities))) {
size_t length = strlen(p->dev + 5);
if (strncmp(name, p->dev + 5, length) == 0 &&
!isalnum(name[length])) {
if (!p->owner) {
tmp = phone_new(p, AST_STATE_DOWN, p->context, requestor ? ast_channel_linkedid(requestor) : NULL);
break;
} else
*cause = AST_CAUSE_BUSY;
}
}
p = p->next;
}
ast_mutex_unlock(&iflock);
restart_monitor();
if (tmp == NULL) {
if (!(ast_format_cap_has_joint(cap, phone_tech.capabilities))) {
char buf[256];
ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), cap));
return NULL;
}
}
return tmp;
}
| static int phone_send_text | ( | struct ast_channel * | ast, |
| const char * | text | ||
| ) | [static] |
Definition at line 641 of file chan_phone.c.
References ast_channel_tech_pvt(), and phone_write_buf().
{
int length = strlen(text);
return phone_write_buf(ast_channel_tech_pvt(ast), text, length, length, 0) ==
length ? 0 : -1;
}
| static int phone_setup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 391 of file chan_phone.c.
References ast_channel_rawreadformat(), ast_channel_tech_pvt(), ast_format_cmp(), AST_FORMAT_CMP_NOT_EQUAL, ast_format_copy(), AST_FORMAT_G723_1, AST_FORMAT_G729A, ast_format_set(), AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, ast_getformatname(), ast_log(), phone_pvt::fd, ast_format::id, phone_pvt::lastinput, LOG_WARNING, phone_pvt::mode, and MODE_FXS.
Referenced by phone_answer(), phone_exception(), and phone_write().
{
struct phone_pvt *p;
p = ast_channel_tech_pvt(ast);
ioctl(p->fd, PHONE_CPT_STOP);
/* Nothing to answering really, just start recording */
if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_G729A) {
/* Prefer g729 */
ioctl(p->fd, PHONE_REC_STOP);
if (p->lastinput.id != AST_FORMAT_G729A) {
ast_format_set(&p->lastinput, AST_FORMAT_G729A, 0);
if (ioctl(p->fd, PHONE_REC_CODEC, G729)) {
ast_log(LOG_WARNING, "Failed to set codec to g729\n");
return -1;
}
}
} else if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_G723_1) {
ioctl(p->fd, PHONE_REC_STOP);
if (p->lastinput.id != AST_FORMAT_G723_1) {
ast_format_set(&p->lastinput, AST_FORMAT_G723_1, 0);
if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
ast_log(LOG_WARNING, "Failed to set codec to g723.1\n");
return -1;
}
}
} else if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_SLINEAR) {
ioctl(p->fd, PHONE_REC_STOP);
if (p->lastinput.id != AST_FORMAT_SLINEAR) {
ast_format_set(&p->lastinput, AST_FORMAT_SLINEAR, 0);
if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
ast_log(LOG_WARNING, "Failed to set codec to signed linear 16\n");
return -1;
}
}
} else if (ast_channel_rawreadformat(ast)->id == AST_FORMAT_ULAW) {
ioctl(p->fd, PHONE_REC_STOP);
if (p->lastinput.id != AST_FORMAT_ULAW) {
ast_format_set(&p->lastinput, AST_FORMAT_ULAW, 0);
if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) {
ast_log(LOG_WARNING, "Failed to set codec to uLaw\n");
return -1;
}
}
} else if (p->mode == MODE_FXS) {
ioctl(p->fd, PHONE_REC_STOP);
if (ast_format_cmp(&p->lastinput, ast_channel_rawreadformat(ast)) == AST_FORMAT_CMP_NOT_EQUAL) {
ast_format_copy(&p->lastinput, ast_channel_rawreadformat(ast));
if (ioctl(p->fd, PHONE_REC_CODEC, ast_channel_rawreadformat(ast))) {
ast_log(LOG_WARNING, "Failed to set codec to %s\n",
ast_getformatname(ast_channel_rawreadformat(ast)));
return -1;
}
}
} else {
ast_log(LOG_WARNING, "Can't do format %s\n", ast_getformatname(ast_channel_rawreadformat(ast)));
return -1;
}
if (ioctl(p->fd, PHONE_REC_START)) {
ast_log(LOG_WARNING, "Failed to start recording\n");
return -1;
}
/* set the DTMF times (the default is too short) */
ioctl(p->fd, PHONE_SET_TONE_ON_TIME, 300);
ioctl(p->fd, PHONE_SET_TONE_OFF_TIME, 200);
return 0;
}
| static int phone_write | ( | struct ast_channel * | ast, |
| struct ast_frame * | frame | ||
| ) | [static] |
Definition at line 648 of file chan_phone.c.
References ast_channel_tech_pvt(), ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_copy(), AST_FORMAT_G723_1, AST_FORMAT_G729A, ast_format_set(), AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, AST_FRAME_IMAGE, AST_FRAME_VOICE, ast_getformatname(), ast_log(), ast_setstate(), AST_STATE_UP, ast_frame::data, ast_frame::datalen, errno, phone_pvt::fd, ast_frame_subclass::format, ast_frame::frametype, ast_format::id, phone_pvt::lastformat, phone_pvt::lastinput, LOG_WARNING, phone_pvt::mode, MODE_FXS, phone_pvt::obuflen, phone_setup(), phone_write_buf(), ast_frame::ptr, phone_pvt::silencesupression, and ast_frame::subclass.
{
struct phone_pvt *p = ast_channel_tech_pvt(ast);
int res;
int maxfr=0;
char *pos;
int sofar;
int expected;
int codecset = 0;
char tmpbuf[4];
/* Write a frame of (presumably voice) data */
if (frame->frametype != AST_FRAME_VOICE && p->mode != MODE_FXS) {
if (frame->frametype != AST_FRAME_IMAGE)
ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
return 0;
}
if (!(frame->subclass.format.id == AST_FORMAT_G723_1 ||
frame->subclass.format.id == AST_FORMAT_SLINEAR ||
frame->subclass.format.id == AST_FORMAT_ULAW ||
frame->subclass.format.id == AST_FORMAT_G729A) &&
p->mode != MODE_FXS) {
ast_log(LOG_WARNING, "Cannot handle frames in %s format\n", ast_getformatname(&frame->subclass.format));
return -1;
}
#if 0
/* If we're not in up mode, go into up mode now */
if (ast->_state != AST_STATE_UP) {
ast_setstate(ast, AST_STATE_UP);
phone_setup(ast);
}
#else
if (ast_channel_state(ast) != AST_STATE_UP) {
/* Don't try tos end audio on-hook */
return 0;
}
#endif
if (frame->subclass.format.id == AST_FORMAT_G729A) {
if (p->lastformat.id != AST_FORMAT_G729A) {
ioctl(p->fd, PHONE_PLAY_STOP);
ioctl(p->fd, PHONE_REC_STOP);
if (ioctl(p->fd, PHONE_PLAY_CODEC, G729)) {
ast_log(LOG_WARNING, "Unable to set G729 mode\n");
return -1;
}
if (ioctl(p->fd, PHONE_REC_CODEC, G729)) {
ast_log(LOG_WARNING, "Unable to set G729 mode\n");
return -1;
}
ast_format_set(&p->lastformat, AST_FORMAT_G729A, 0);
ast_format_set(&p->lastinput, AST_FORMAT_G729A, 0);
/* Reset output buffer */
p->obuflen = 0;
codecset = 1;
}
if (frame->datalen > 80) {
ast_log(LOG_WARNING, "Frame size too large for G.729 (%d bytes)\n", frame->datalen);
return -1;
}
maxfr = 80;
} else if (frame->subclass.format.id == AST_FORMAT_G723_1) {
if (p->lastformat.id != AST_FORMAT_G723_1) {
ioctl(p->fd, PHONE_PLAY_STOP);
ioctl(p->fd, PHONE_REC_STOP);
if (ioctl(p->fd, PHONE_PLAY_CODEC, G723_63)) {
ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
return -1;
}
if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
return -1;
}
ast_format_set(&p->lastformat, AST_FORMAT_G723_1, 0);
ast_format_set(&p->lastinput, AST_FORMAT_G723_1, 0);
/* Reset output buffer */
p->obuflen = 0;
codecset = 1;
}
if (frame->datalen > 24) {
ast_log(LOG_WARNING, "Frame size too large for G.723.1 (%d bytes)\n", frame->datalen);
return -1;
}
maxfr = 24;
} else if (frame->subclass.format.id == AST_FORMAT_SLINEAR) {
if (p->lastformat.id != AST_FORMAT_SLINEAR) {
ioctl(p->fd, PHONE_PLAY_STOP);
ioctl(p->fd, PHONE_REC_STOP);
if (ioctl(p->fd, PHONE_PLAY_CODEC, LINEAR16)) {
ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
return -1;
}
if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
return -1;
}
ast_format_set(&p->lastformat, AST_FORMAT_SLINEAR, 0);
ast_format_set(&p->lastinput, AST_FORMAT_SLINEAR, 0);
codecset = 1;
/* Reset output buffer */
p->obuflen = 0;
}
maxfr = 480;
} else if (frame->subclass.format.id == AST_FORMAT_ULAW) {
if (p->lastformat.id != AST_FORMAT_ULAW) {
ioctl(p->fd, PHONE_PLAY_STOP);
ioctl(p->fd, PHONE_REC_STOP);
if (ioctl(p->fd, PHONE_PLAY_CODEC, ULAW)) {
ast_log(LOG_WARNING, "Unable to set uLaw mode\n");
return -1;
}
if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) {
ast_log(LOG_WARNING, "Unable to set uLaw mode\n");
return -1;
}
ast_format_set(&p->lastformat, AST_FORMAT_ULAW, 0);
ast_format_set(&p->lastinput, AST_FORMAT_ULAW, 0);
codecset = 1;
/* Reset output buffer */
p->obuflen = 0;
}
maxfr = 240;
} else {
if (ast_format_cmp(&p->lastformat, &frame->subclass.format) != AST_FORMAT_CMP_EQUAL) {
ioctl(p->fd, PHONE_PLAY_STOP);
ioctl(p->fd, PHONE_REC_STOP);
if (ioctl(p->fd, PHONE_PLAY_CODEC, (int) frame->subclass.format.id)) {
ast_log(LOG_WARNING, "Unable to set %s mode\n",
ast_getformatname(&frame->subclass.format));
return -1;
}
if (ioctl(p->fd, PHONE_REC_CODEC, (int) frame->subclass.format.id)) {
ast_log(LOG_WARNING, "Unable to set %s mode\n",
ast_getformatname(&frame->subclass.format));
return -1;
}
ast_format_copy(&p->lastformat, &frame->subclass.format);
ast_format_copy(&p->lastinput, &frame->subclass.format);
codecset = 1;
/* Reset output buffer */
p->obuflen = 0;
}
maxfr = 480;
}
if (codecset) {
ioctl(p->fd, PHONE_REC_DEPTH, 3);
ioctl(p->fd, PHONE_PLAY_DEPTH, 3);
if (ioctl(p->fd, PHONE_PLAY_START)) {
ast_log(LOG_WARNING, "Failed to start playback\n");
return -1;
}
if (ioctl(p->fd, PHONE_REC_START)) {
ast_log(LOG_WARNING, "Failed to start recording\n");
return -1;
}
}
/* If we get here, we have a frame of Appropriate data */
sofar = 0;
pos = frame->data.ptr;
while(sofar < frame->datalen) {
/* Write in no more than maxfr sized frames */
expected = frame->datalen - sofar;
if (maxfr < expected)
expected = maxfr;
/* XXX Internet Phone Jack does not handle the 4-byte VAD frame properly! XXX
we have to pad it to 24 bytes still. */
if (frame->datalen == 4) {
if (p->silencesupression) {
memcpy(tmpbuf, frame->data.ptr, 4);
expected = 24;
res = phone_write_buf(p, tmpbuf, expected, maxfr, 0);
}
res = 4;
expected=4;
} else {
int swap = 0;
#if __BYTE_ORDER == __BIG_ENDIAN
if (frame->subclass.format.id == AST_FORMAT_SLINEAR)
swap = 1; /* Swap big-endian samples to little-endian as we copy */
#endif
res = phone_write_buf(p, pos, expected, maxfr, swap);
}
if (res != expected) {
if ((errno != EAGAIN) && (errno != EINTR)) {
if (res < 0)
ast_log(LOG_WARNING, "Write returned error (%s)\n", strerror(errno));
/*
* Card is in non-blocking mode now and it works well now, but there are
* lot of messages like this. So, this message is temporarily disabled.
*/
#if 0
else
ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frame->datalen);
#endif
return -1;
} else /* Pretend it worked */
res = expected;
}
sofar += res;
pos += res;
}
return 0;
}
| static int phone_write_buf | ( | struct phone_pvt * | p, |
| const char * | buf, | ||
| int | len, | ||
| int | frlen, | ||
| int | swap | ||
| ) | [static] |
Definition at line 607 of file chan_phone.c.
References ast_log(), ast_swapcopy_samples(), phone_pvt::fd, len(), LOG_WARNING, phone_pvt::obuf, and phone_pvt::obuflen.
Referenced by phone_send_text(), and phone_write().
{
int res;
/* Store as much of the buffer as we can, then write fixed frames */
int space = sizeof(p->obuf) - p->obuflen;
/* Make sure we have enough buffer space to store the frame */
if (space < len)
len = space;
if (swap)
ast_swapcopy_samples(p->obuf+p->obuflen, buf, len/2);
else
memcpy(p->obuf + p->obuflen, buf, len);
p->obuflen += len;
while(p->obuflen > frlen) {
res = write(p->fd, p->obuf, frlen);
if (res != frlen) {
if (res < 1) {
/*
* Card is in non-blocking mode now and it works well now, but there are
* lot of messages like this. So, this message is temporarily disabled.
*/
return 0;
} else {
ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frlen);
}
}
p->obuflen -= frlen;
/* Move memory if necessary */
if (p->obuflen)
memmove(p->obuf, p->obuf + frlen, p->obuflen);
}
return len;
}
| static int restart_monitor | ( | void | ) | [static] |
Definition at line 1138 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.
Referenced by load_module(), phone_hangup(), and phone_request().
{
/* If we're supposed to be stopped -- stay stopped */
if (monitor_thread == AST_PTHREADT_STOP)
return 0;
if (ast_mutex_lock(&monlock)) {
ast_log(LOG_WARNING, "Unable to lock monitor\n");
return -1;
}
if (monitor_thread == pthread_self()) {
ast_mutex_unlock(&monlock);
ast_log(LOG_WARNING, "Cannot kill myself\n");
return -1;
}
if (monitor_thread != AST_PTHREADT_NULL) {
if (ast_mutex_lock(&iflock)) {
ast_mutex_unlock(&monlock);
ast_log(LOG_WARNING, "Unable to lock the interface list\n");
return -1;
}
monitor = 0;
while (pthread_kill(monitor_thread, SIGURG) == 0)
sched_yield();
pthread_join(monitor_thread, NULL);
ast_mutex_unlock(&iflock);
}
monitor = 1;
/* Start a new monitor */
if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
ast_mutex_unlock(&monlock);
ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
return -1;
}
ast_mutex_unlock(&monlock);
return 0;
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 1356 of file chan_phone.c.
References __unload_module().
{
return __unload_module();
}
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 1497 of file chan_phone.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1497 of file chan_phone.c.
char cid_name[AST_MAX_EXTENSION] [static] |
Definition at line 152 of file chan_phone.c.
char cid_num[AST_MAX_EXTENSION] [static] |
Definition at line 151 of file chan_phone.c.
const char config[] = "phone.conf" [static] |
Definition at line 86 of file chan_phone.c.
char context[AST_MAX_EXTENSION] = "default" [static] |
Definition at line 89 of file chan_phone.c.
struct ast_channel_tech* cur_tech [static] |
Definition at line 201 of file chan_phone.c.
int echocancel = AEC_OFF [static] |
Definition at line 94 of file chan_phone.c.
Referenced by __unload_module(), do_monitor(), load_module(), and phone_request().
ast_mutex_t iflock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static] |
Definition at line 101 of file chan_phone.c.
Referenced by __unload_module(), do_monitor(), load_module(), phone_request(), and restart_monitor().
char language[MAX_LANGUAGE] = "" [static] |
Definition at line 92 of file chan_phone.c.
unsigned int monitor [static] |
Definition at line 108 of file chan_phone.c.
Referenced by ast_cc_agent_set_interfaces_chanvar(), ast_cc_available_timer_expire(), ast_cc_call_init(), ast_cc_extension_monitor_add_dialstring(), ast_handle_cc_control_frame(), ast_monitor_start(), cc_cli_print_monitor_stats(), cc_device_monitor_init(), cc_extension_monitor_init(), cc_interface_tree_destroy(), cc_interfaces_datastore_init(), cc_monitor_destroy(), sig_pri_call(), sig_pri_cc_available(), sig_pri_cc_generic_check(), sig_pri_cc_link_canceled(), and sig_pri_handle_cis_subcmds().
pthread_t monitor_thread = AST_PTHREADT_NULL [static] |
Definition at line 112 of file chan_phone.c.
ast_mutex_t monlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static] |
Definition at line 105 of file chan_phone.c.
Referenced by __unload_module(), and restart_monitor().
struct ast_channel_tech phone_tech [static] |
Definition at line 167 of file chan_phone.c.
struct ast_channel_tech phone_tech_fxs [static] |
Definition at line 183 of file chan_phone.c.
Referenced by load_module().
struct ast_format_cap* prefcap [static] |
Definition at line 98 of file chan_phone.c.
int silencesupression = 0 [static] |
Definition at line 96 of file chan_phone.c.
const char tdesc[] = "Standard Linux Telephony API Driver" [static] |
Definition at line 85 of file chan_phone.c.