Thu Dec 17 13:33:51 2009

Asterisk developer's documentation


chan_phone.c File Reference

Generic Linux Telephony Interface driver. More...

#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_pvtmkif (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_framephone_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_channelphone_new (struct phone_pvt *i, int state, char *context)
static struct ast_framephone_read (struct ast_channel *ast)
static struct ast_channelphone_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_infoast_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_techcur_tech
static int echocancel = AEC_OFF
static struct phone_pvtiflist
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"


Detailed Description

Generic Linux Telephony Interface driver.

Author:
Mark Spencer <markster@digium.com>

Definition in file chan_phone.c.


Define Documentation

#define DEFAULT_CALLER_ID   "Unknown"

Definition at line 87 of file chan_phone.c.

Referenced by phone_call().

#define DEFAULT_GAIN   0x100

Definition at line 89 of file chan_phone.c.

Referenced by load_module(), and parse_gain_value().

#define IXJ_PHONE_RING_START (  )     ioctl(p->fd, PHONE_RING_START, &x);

Definition at line 84 of file chan_phone.c.

Referenced by phone_call().

#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

Definition at line 88 of file chan_phone.c.

Referenced by phone_read().

#define QNDRV_VER   100

Definition at line 74 of file chan_phone.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1433 of file chan_phone.c.

static int __unload_module ( void   )  [static]

Definition at line 1263 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.

01264 {
01265    struct phone_pvt *p, *pl;
01266    /* First, take us out of the channel loop */
01267    if (cur_tech)
01268       ast_channel_unregister(cur_tech);
01269    if (!ast_mutex_lock(&iflock)) {
01270       /* Hangup all interfaces if they have an owner */
01271       p = iflist;
01272       while(p) {
01273          if (p->owner)
01274             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
01275          p = p->next;
01276       }
01277       iflist = NULL;
01278       ast_mutex_unlock(&iflock);
01279    } else {
01280       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
01281       return -1;
01282    }
01283    if (!ast_mutex_lock(&monlock)) {
01284       if (monitor_thread > AST_PTHREADT_NULL) {
01285          monitor = 0;
01286          while (pthread_kill(monitor_thread, SIGURG) == 0)
01287             sched_yield();
01288          pthread_join(monitor_thread, NULL);
01289       }
01290       monitor_thread = AST_PTHREADT_STOP;
01291       ast_mutex_unlock(&monlock);
01292    } else {
01293       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
01294       return -1;
01295    }
01296 
01297    if (!ast_mutex_lock(&iflock)) {
01298       /* Destroy all the interfaces and free their memory */
01299       p = iflist;
01300       while(p) {
01301          /* Close the socket, assuming it's real */
01302          if (p->fd > -1)
01303             close(p->fd);
01304          pl = p;
01305          p = p->next;
01306          /* Free associated memory */
01307          free(pl);
01308       }
01309       iflist = NULL;
01310       ast_mutex_unlock(&iflock);
01311    } else {
01312       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
01313       return -1;
01314    }
01315       
01316    return 0;
01317 }

static void __unreg_module ( void   )  [static]

Definition at line 1433 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_mutex_unlock(), ast_select(), ast_tv(), ast_tvzero(), phone_pvt::dev, DialTone, phone_pvt::dialtone, errno, phone_pvt::fd, iflist, iflock, LOG_DEBUG, LOG_ERROR, LOG_WARNING, phone_pvt::mode, MODE_SIGMA, phone_pvt::next, phone_pvt::owner, phone_check_exception(), and phone_mini_packet().

00999 {
01000    fd_set rfds, efds;
01001    int n, 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       n = -1;
01020       FD_ZERO(&rfds);
01021       FD_ZERO(&efds);
01022       i = iflist;
01023       dotone = 0;
01024       while (i) {
01025          if (FD_ISSET(i->fd, &rfds)) 
01026             ast_log(LOG_WARNING, "Descriptor %d appears twice (%s)?\n", i->fd, i->dev);
01027          if (!i->owner) {
01028             /* This needs to be watched, as it lacks an owner */
01029             FD_SET(i->fd, &rfds);
01030             FD_SET(i->fd, &efds);
01031             if (i->fd > n)
01032                n = i->fd;
01033             if (i->dialtone && i->mode != MODE_SIGMA) {
01034                /* Remember we're going to have to come back and play
01035                   more dialtones */
01036                if (ast_tvzero(tv)) {
01037                   /* If we're due for a dialtone, play one */
01038                   if (write(i->fd, DialTone + tonepos, 240) != 240)
01039                      ast_log(LOG_WARNING, "Dial tone write error\n");
01040                }
01041                dotone++;
01042             }
01043          }
01044          
01045          i = i->next;
01046       }
01047       /* Okay, now that we know what to do, release the interface lock */
01048       ast_mutex_unlock(&iflock);
01049 
01050       /* Wait indefinitely for something to happen */
01051       if (dotone && i && i->mode != MODE_SIGMA) {
01052          /* If we're ready to recycle the time, set it to 30 ms */
01053          tonepos += 240;
01054          if (tonepos >= sizeof(DialTone))
01055                tonepos = 0;
01056          if (ast_tvzero(tv)) {
01057             tv = ast_tv(30000, 0);
01058          }
01059          res = ast_select(n + 1, &rfds, NULL, &efds, &tv);
01060       } else {
01061          res = ast_select(n + 1, &rfds, NULL, &efds, NULL);
01062          tv = ast_tv(0,0);
01063          tonepos = 0;
01064       }
01065       /* Okay, select has finished.  Let's see what happened.  */
01066       if (res < 0) {
01067          ast_log(LOG_DEBUG, "select return %d: %s\n", res, strerror(errno));
01068          continue;
01069       }
01070       /* If there are no fd's changed, just continue, it's probably time
01071          to play some more dialtones */
01072       if (!res)
01073          continue;
01074       /* Alright, lock the interface list again, and let's look and see what has
01075          happened */
01076       if (ast_mutex_lock(&iflock)) {
01077          ast_log(LOG_WARNING, "Unable to lock the interface list\n");
01078          continue;
01079       }
01080 
01081       i = iflist;
01082       for(; i; i=i->next) {
01083          if (FD_ISSET(i->fd, &rfds)) {
01084             if (i->owner) {
01085                continue;
01086             }
01087             phone_mini_packet(i);
01088          }
01089          if (FD_ISSET(i->fd, &efds)) {
01090             if (i->owner) {
01091                continue;
01092             }
01093             phone_check_exception(i);
01094          }
01095       }
01096       ast_mutex_unlock(&iflock);
01097    }
01098    return NULL;
01099    
01100 }

static int load_module ( void   )  [static]

Definition at line 1324 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.

01325 {
01326    struct ast_config *cfg;
01327    struct ast_variable *v;
01328    struct phone_pvt *tmp;
01329    int mode = MODE_IMMEDIATE;
01330    int txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; /* default gain 1.0 */
01331    cfg = ast_config_load(config);
01332 
01333    /* We *must* have a config file otherwise stop immediately */
01334    if (!cfg) {
01335       ast_log(LOG_ERROR, "Unable to load config %s\n", config);
01336       return AST_MODULE_LOAD_DECLINE;
01337    }
01338    if (ast_mutex_lock(&iflock)) {
01339       /* It's a little silly to lock it, but we mind as well just to be sure */
01340       ast_log(LOG_ERROR, "Unable to lock interface list???\n");
01341       return AST_MODULE_LOAD_FAILURE;
01342    }
01343    v = ast_variable_browse(cfg, "interfaces");
01344    while(v) {
01345       /* Create the interface list */
01346       if (!strcasecmp(v->name, "device")) {
01347             tmp = mkif(v->value, mode, txgain, rxgain);
01348             if (tmp) {
01349                tmp->next = iflist;
01350                iflist = tmp;
01351                
01352             } else {
01353                ast_log(LOG_ERROR, "Unable to register channel '%s'\n", v->value);
01354                ast_config_destroy(cfg);
01355                ast_mutex_unlock(&iflock);
01356                __unload_module();
01357                return AST_MODULE_LOAD_FAILURE;
01358             }
01359       } else if (!strcasecmp(v->name, "silencesupression")) {
01360          silencesupression = ast_true(v->value);
01361       } else if (!strcasecmp(v->name, "language")) {
01362          ast_copy_string(language, v->value, sizeof(language));
01363       } else if (!strcasecmp(v->name, "callerid")) {
01364          ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
01365       } else if (!strcasecmp(v->name, "mode")) {
01366          if (!strncasecmp(v->value, "di", 2)) 
01367             mode = MODE_DIALTONE;
01368          else if (!strncasecmp(v->value, "sig", 3))
01369             mode = MODE_SIGMA;
01370          else if (!strncasecmp(v->value, "im", 2))
01371             mode = MODE_IMMEDIATE;
01372          else if (!strncasecmp(v->value, "fxs", 3)) {
01373             mode = MODE_FXS;
01374             prefformat = 0x01ff0000; /* All non-voice */
01375          }
01376          else if (!strncasecmp(v->value, "fx", 2))
01377             mode = MODE_FXO;
01378          else
01379             ast_log(LOG_WARNING, "Unknown mode: %s\n", v->value);
01380       } else if (!strcasecmp(v->name, "context")) {
01381          ast_copy_string(context, v->value, sizeof(context));
01382       } else if (!strcasecmp(v->name, "format")) {
01383          if (!strcasecmp(v->value, "g723.1")) {
01384             prefformat = AST_FORMAT_G723_1;
01385          } else if (!strcasecmp(v->value, "slinear")) {
01386             if (mode == MODE_FXS)
01387                 prefformat |= AST_FORMAT_SLINEAR;
01388             else prefformat = AST_FORMAT_SLINEAR;
01389          } else if (!strcasecmp(v->value, "ulaw")) {
01390             prefformat = AST_FORMAT_ULAW;
01391          } else
01392             ast_log(LOG_WARNING, "Unknown format '%s'\n", v->value);
01393       } else if (!strcasecmp(v->name, "echocancel")) {
01394          if (!strcasecmp(v->value, "off")) {
01395             echocancel = AEC_OFF;
01396          } else if (!strcasecmp(v->value, "low")) {
01397             echocancel = AEC_LOW;
01398          } else if (!strcasecmp(v->value, "medium")) {
01399             echocancel = AEC_MED;
01400          } else if (!strcasecmp(v->value, "high")) {
01401             echocancel = AEC_HIGH;
01402          } else 
01403             ast_log(LOG_WARNING, "Unknown echo cancellation '%s'\n", v->value);
01404       } else if (!strcasecmp(v->name, "txgain")) {
01405          txgain = parse_gain_value(v->name, v->value);
01406       } else if (!strcasecmp(v->name, "rxgain")) {
01407          rxgain = parse_gain_value(v->name, v->value);
01408       }  
01409       v = v->next;
01410    }
01411    ast_mutex_unlock(&iflock);
01412 
01413    if (mode == MODE_FXS) {
01414       phone_tech_fxs.capabilities = prefformat;
01415       cur_tech = &phone_tech_fxs;
01416    } else
01417       cur_tech = (struct ast_channel_tech *) &phone_tech;
01418 
01419    /* Make sure we can register our Adtranphone channel type */
01420 
01421    if (ast_channel_register(cur_tech)) {
01422       ast_log(LOG_ERROR, "Unable to register channel class 'Phone'\n");
01423       ast_config_destroy(cfg);
01424       __unload_module();
01425       return AST_MODULE_LOAD_FAILURE;
01426    }
01427    ast_config_destroy(cfg);
01428    /* And start the monitor for the first time */
01429    restart_monitor();
01430    return AST_MODULE_LOAD_SUCCESS;
01431 }

static struct phone_pvt* mkif ( char *  iface,
int  mode,
int  txgain,
int  rxgain 
) [static]

Definition at line 1139 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().

01140 {
01141    /* Make a phone_pvt structure for this interface */
01142    struct phone_pvt *tmp;
01143    int flags;  
01144    
01145    tmp = malloc(sizeof(struct phone_pvt));
01146    if (tmp) {
01147       tmp->fd = open(iface, O_RDWR);
01148       if (tmp->fd < 0) {
01149          ast_log(LOG_WARNING, "Unable to open '%s'\n", iface);
01150          free(tmp);
01151          return NULL;
01152       }
01153       if (mode == MODE_FXO) {
01154          if (ioctl(tmp->fd, IXJCTL_PORT, PORT_PSTN)) 
01155             ast_log(LOG_DEBUG, "Unable to set port to PSTN\n");
01156       } else {
01157          if (ioctl(tmp->fd, IXJCTL_PORT, PORT_POTS)) 
01158              if (mode != MODE_FXS)
01159                   ast_log(LOG_DEBUG, "Unable to set port to POTS\n");
01160       }
01161       ioctl(tmp->fd, PHONE_PLAY_STOP);
01162       ioctl(tmp->fd, PHONE_REC_STOP);
01163       ioctl(tmp->fd, PHONE_RING_STOP);
01164       ioctl(tmp->fd, PHONE_CPT_STOP);
01165       if (ioctl(tmp->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK)) 
01166          ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",iface, strerror(errno));
01167       if (echocancel != AEC_OFF)
01168          ioctl(tmp->fd, IXJCTL_AEC_START, echocancel);
01169       if (silencesupression) 
01170          tmp->silencesupression = 1;
01171 #ifdef PHONE_VAD
01172       ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression);
01173 #endif
01174       tmp->mode = mode;
01175       flags = fcntl(tmp->fd, F_GETFL);
01176       fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK);
01177       tmp->owner = NULL;
01178       tmp->lastformat = -1;
01179       tmp->lastinput = -1;
01180       tmp->ministate = 0;
01181       memset(tmp->ext, 0, sizeof(tmp->ext));
01182       ast_copy_string(tmp->language, language, sizeof(tmp->language));
01183       ast_copy_string(tmp->dev, iface, sizeof(tmp->dev));
01184       ast_copy_string(tmp->context, context, sizeof(tmp->context));
01185       tmp->next = NULL;
01186       tmp->obuflen = 0;
01187       tmp->dialtone = 0;
01188       tmp->cpt = 0;
01189       ast_copy_string(tmp->cid_num, cid_num, sizeof(tmp->cid_num));
01190       ast_copy_string(tmp->cid_name, cid_name, sizeof(tmp->cid_name));
01191       tmp->txgain = txgain;
01192       ioctl(tmp->fd, PHONE_PLAY_VOLUME, tmp->txgain);
01193       tmp->rxgain = rxgain;
01194       ioctl(tmp->fd, PHONE_REC_VOLUME, tmp->rxgain);
01195    }
01196    return tmp;
01197 }

static int parse_gain_value ( char *  gain_type,
char *  value 
) [static]

Definition at line 1241 of file chan_phone.c.

References ast_log(), DEFAULT_GAIN, and LOG_ERROR.

Referenced by load_module().

01242 {
01243    float gain;
01244 
01245    /* try to scan number */
01246    if (sscanf(value, "%30f", &gain) != 1)
01247    {
01248       ast_log(LOG_ERROR, "Invalid %s value '%s' in '%s' config\n",
01249          value, gain_type, config);
01250       return DEFAULT_GAIN;
01251    }
01252 
01253    /* multiplicate gain by 1.0 gain value */ 
01254    gain = gain * (float)DEFAULT_GAIN;
01255 
01256    /* percentage? */
01257    if (value[strlen(value) - 1] == '%')
01258       return (int)(gain / (float)100);
01259 
01260    return (int)gain;
01261 }

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().

Referenced by do_monitor().

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.

Referenced by do_monitor().

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 1199 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().

01200 {
01201    int oldformat;
01202    struct phone_pvt *p;
01203    struct ast_channel *tmp = NULL;
01204    char *name = data;
01205 
01206    /* Search for an unowned channel */
01207    if (ast_mutex_lock(&iflock)) {
01208       ast_log(LOG_ERROR, "Unable to lock interface list???\n");
01209       return NULL;
01210    }
01211    p = iflist;
01212    while(p) {
01213       if (p->mode == MODE_FXS ||
01214           format & (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW)) {
01215           size_t length = strlen(p->dev + 5);
01216          if (strncmp(name, p->dev + 5, length) == 0 &&
01217              !isalnum(name[length])) {
01218              if (!p->owner) {
01219                      tmp = phone_new(p, AST_STATE_DOWN, p->context);
01220                      break;
01221                 } else
01222                      *cause = AST_CAUSE_BUSY;
01223             }
01224       }
01225       p = p->next;
01226    }
01227    ast_mutex_unlock(&iflock);
01228    restart_monitor();
01229    if (tmp == NULL) {
01230       oldformat = format;
01231       format &= (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW);
01232       if (!format) {
01233          ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
01234          return NULL;
01235       }
01236    }
01237    return tmp;
01238 }

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 1102 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.

01103 {
01104    /* If we're supposed to be stopped -- stay stopped */
01105    if (monitor_thread == AST_PTHREADT_STOP)
01106       return 0;
01107    if (ast_mutex_lock(&monlock)) {
01108       ast_log(LOG_WARNING, "Unable to lock monitor\n");
01109       return -1;
01110    }
01111    if (monitor_thread == pthread_self()) {
01112       ast_mutex_unlock(&monlock);
01113       ast_log(LOG_WARNING, "Cannot kill myself\n");
01114       return -1;
01115    }
01116    if (monitor_thread != AST_PTHREADT_NULL) {
01117       if (ast_mutex_lock(&iflock)) {
01118          ast_mutex_unlock(&monlock);
01119          ast_log(LOG_WARNING, "Unable to lock the interface list\n");
01120          return -1;
01121       }
01122       monitor = 0;
01123       while (pthread_kill(monitor_thread, SIGURG) == 0)
01124          sched_yield();
01125       pthread_join(monitor_thread, NULL);
01126       ast_mutex_unlock(&iflock);
01127    }
01128    monitor = 1;
01129    /* Start a new monitor */
01130    if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
01131       ast_mutex_unlock(&monlock);
01132       ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
01133       return -1;
01134    }
01135    ast_mutex_unlock(&monlock);
01136    return 0;
01137 }

static int unload_module ( void   )  [static]

Definition at line 1319 of file chan_phone.c.

References __unload_module().

01320 {
01321    return __unload_module();
01322 }


Variable Documentation

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 1433 of file chan_phone.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1433 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.

struct phone_pvt * iflist [static]

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]

Definition at line 114 of file chan_phone.c.

Referenced by ast_monitor_start().

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]

Definition at line 173 of file chan_phone.c.

Referenced by load_module().

struct ast_channel_tech phone_tech_fxs [static]

Definition at line 190 of file chan_phone.c.

Referenced by load_module().

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.


Generated on Thu Dec 17 13:33:51 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7