Sat Aug 6 00:39:47 2011

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

static int __unload_module ( void   )  [static]

Definition at line 1281 of file chan_phone.c.

References ast_channel_unregister(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, cur_tech, phone_pvt::fd, free, iflist, iflock, LOG_WARNING, monlock, phone_pvt::next, and phone_pvt::owner.

01282 {
01283    struct phone_pvt *p, *pl;
01284    /* First, take us out of the channel loop */
01285    if (cur_tech)
01286       ast_channel_unregister(cur_tech);
01287    if (!ast_mutex_lock(&iflock)) {
01288       /* Hangup all interfaces if they have an owner */
01289       p = iflist;
01290       while(p) {
01291          if (p->owner)
01292             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
01293          p = p->next;
01294       }
01295       iflist = NULL;
01296       ast_mutex_unlock(&iflock);
01297    } else {
01298       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
01299       return -1;
01300    }
01301    if (!ast_mutex_lock(&monlock)) {
01302       if (monitor_thread > AST_PTHREADT_NULL) {
01303          monitor = 0;
01304          while (pthread_kill(monitor_thread, SIGURG) == 0)
01305             sched_yield();
01306          pthread_join(monitor_thread, NULL);
01307       }
01308       monitor_thread = AST_PTHREADT_STOP;
01309       ast_mutex_unlock(&monlock);
01310    } else {
01311       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
01312       return -1;
01313    }
01314 
01315    if (!ast_mutex_lock(&iflock)) {
01316       /* Destroy all the interfaces and free their memory */
01317       p = iflist;
01318       while(p) {
01319          /* Close the socket, assuming it's real */
01320          if (p->fd > -1)
01321             close(p->fd);
01322          pl = p;
01323          p = p->next;
01324          /* Free associated memory */
01325          free(pl);
01326       }
01327       iflist = NULL;
01328       ast_mutex_unlock(&iflock);
01329    } else {
01330       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
01331       return -1;
01332    }
01333       
01334    return 0;
01335 }

static void __unreg_module ( void   )  [static]

Definition at line 1451 of file chan_phone.c.

static void* do_monitor ( void *  data  )  [static]

Definition at line 998 of file chan_phone.c.

References ast_log(), ast_mutex_lock(), ast_realloc, ast_tvzero(), DialTone, phone_pvt::dialtone, phone_pvt::fd, iflist, iflock, LOG_ERROR, LOG_WARNING, phone_pvt::mode, MODE_SIGMA, phone_pvt::next, and phone_pvt::owner.

00999 {
01000    struct pollfd *fds = NULL;
01001    int nfds = 0, inuse_fds = 0, res;
01002    struct phone_pvt *i;
01003    int tonepos = 0;
01004    /* The tone we're playing this round */
01005    struct timeval tv = { 0, 0 };
01006    int dotone;
01007    /* This thread monitors all the frame relay interfaces which are not yet in use
01008       (and thus do not have a separate thread) indefinitely */
01009    while (monitor) {
01010       /* Don't let anybody kill us right away.  Nobody should lock the interface list
01011          and wait for the monitor list, but the other way around is okay. */
01012       /* Lock the interface list */
01013       if (ast_mutex_lock(&iflock)) {
01014          ast_log(LOG_ERROR, "Unable to grab interface lock\n");
01015          return NULL;
01016       }
01017       /* Build the stuff we're going to select on, that is the socket of every
01018          phone_pvt that does not have an associated owner channel */
01019       i = iflist;
01020       dotone = 0;
01021       inuse_fds = 0;
01022       for (i = iflist; i; i = i->next) {
01023          if (!i->owner) {
01024             /* This needs to be watched, as it lacks an owner */
01025             if (inuse_fds == nfds) {
01026                void *tmp = ast_realloc(fds, (nfds + 1) * sizeof(*fds));
01027                if (!tmp) {
01028                   /* Avoid leaking */
01029                   continue;
01030                }
01031                fds = tmp;
01032                nfds++;
01033             }
01034             fds[inuse_fds].fd = i->fd;
01035             fds[inuse_fds].events = POLLIN | POLLERR;
01036             fds[inuse_fds].revents = 0;
01037             inuse_fds++;
01038 
01039             if (i->dialtone && i->mode != MODE_SIGMA) {
01040                /* Remember we're going to have to come back and play
01041                   more dialtones */
01042                if (ast_tvzero(tv)) {
01043                   /* If we're due for a dialtone, play one */
01044                   if (write(i->fd, DialTone + tonepos, 240) != 240) {
01045                      ast_log(LOG_WARNING, "Dial tone write error\n");
01046                   }
01047                }
01048                dotone++;
01049             }
01050          }
01051       }
01052       /* Okay, now that we know what to do, release the interface lock */
01053       ast_mutex_unlock(&iflock);
01054 
01055       /* Wait indefinitely for something to happen */
01056       if (dotone && i && i->mode != MODE_SIGMA) {
01057          /* If we're ready to recycle the time, set it to 30 ms */
01058          tonepos += 240;
01059          if (tonepos >= sizeof(DialTone)) {
01060             tonepos = 0;
01061          }
01062          if (ast_tvzero(tv)) {
01063             tv = ast_tv(0, 30000);
01064          }
01065          res = ast_poll2(fds, inuse_fds, &tv);
01066       } else {
01067          res = ast_poll(fds, inuse_fds, -1);
01068          tv = ast_tv(0, 0);
01069          tonepos = 0;
01070       }
01071       /* Okay, select has finished.  Let's see what happened.  */
01072       if (res < 0) {
01073          ast_log(LOG_DEBUG, "poll returned %d: %s\n", res, strerror(errno));
01074          continue;
01075       }
01076       /* If there are no fd's changed, just continue, it's probably time
01077          to play some more dialtones */
01078       if (!res) {
01079          continue;
01080       }
01081       /* Alright, lock the interface list again, and let's look and see what has
01082          happened */
01083       if (ast_mutex_lock(&iflock)) {
01084          ast_log(LOG_WARNING, "Unable to lock the interface list\n");
01085          continue;
01086       }
01087 
01088       for (i = iflist; i; i = i->next) {
01089          int j;
01090          /* Find the record */
01091          for (j = 0; j < inuse_fds; j++) {
01092             if (fds[j].fd == i->fd) {
01093                break;
01094             }
01095          }
01096 
01097          /* Not found? */
01098          if (j == inuse_fds) {
01099             continue;
01100          }
01101 
01102          if (fds[j].revents & POLLIN) {
01103             if (i->owner) {
01104                continue;
01105             }
01106             phone_mini_packet(i);
01107          }
01108          if (fds[j].revents & POLLERR) {
01109             if (i->owner) {
01110                continue;
01111             }
01112             phone_check_exception(i);
01113          }
01114       }
01115       ast_mutex_unlock(&iflock);
01116    }
01117    return NULL;
01118 }

static int load_module ( void   )  [static]

Definition at line 1342 of file chan_phone.c.

References __unload_module(), ast_callerid_split(), ast_channel_register(), ast_config_destroy(), ast_config_load(), ast_copy_string(), AST_FORMAT_G723_1, AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_mutex_lock(), ast_mutex_unlock(), ast_true(), ast_variable_browse(), ast_channel_tech::capabilities, cur_tech, DEFAULT_GAIN, iflist, iflock, LOG_ERROR, LOG_WARNING, mkif(), phone_pvt::mode, MODE_DIALTONE, MODE_FXO, MODE_FXS, MODE_IMMEDIATE, MODE_SIGMA, ast_variable::name, ast_variable::next, phone_pvt::next, parse_gain_value(), phone_tech, phone_tech_fxs, restart_monitor(), phone_pvt::rxgain, phone_pvt::txgain, and ast_variable::value.

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

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

Definition at line 1157 of file chan_phone.c.

References ast_copy_string(), ast_log(), phone_pvt::cid_name, phone_pvt::cid_num, phone_pvt::context, phone_pvt::cpt, phone_pvt::dev, phone_pvt::dialtone, errno, phone_pvt::ext, phone_pvt::fd, free, phone_pvt::language, phone_pvt::lastformat, phone_pvt::lastinput, LOG_DEBUG, LOG_WARNING, malloc, phone_pvt::ministate, phone_pvt::mode, MODE_FXO, MODE_FXS, phone_pvt::next, phone_pvt::obuflen, phone_pvt::owner, phone_pvt::rxgain, phone_pvt::silencesupression, and phone_pvt::txgain.

Referenced by load_module().

01158 {
01159    /* Make a phone_pvt structure for this interface */
01160    struct phone_pvt *tmp;
01161    int flags;  
01162    
01163    tmp = malloc(sizeof(struct phone_pvt));
01164    if (tmp) {
01165       tmp->fd = open(iface, O_RDWR);
01166       if (tmp->fd < 0) {
01167          ast_log(LOG_WARNING, "Unable to open '%s'\n", iface);
01168          free(tmp);
01169          return NULL;
01170       }
01171       if (mode == MODE_FXO) {
01172          if (ioctl(tmp->fd, IXJCTL_PORT, PORT_PSTN)) 
01173             ast_log(LOG_DEBUG, "Unable to set port to PSTN\n");
01174       } else {
01175          if (ioctl(tmp->fd, IXJCTL_PORT, PORT_POTS)) 
01176              if (mode != MODE_FXS)
01177                   ast_log(LOG_DEBUG, "Unable to set port to POTS\n");
01178       }
01179       ioctl(tmp->fd, PHONE_PLAY_STOP);
01180       ioctl(tmp->fd, PHONE_REC_STOP);
01181       ioctl(tmp->fd, PHONE_RING_STOP);
01182       ioctl(tmp->fd, PHONE_CPT_STOP);
01183       if (ioctl(tmp->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK)) 
01184          ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",iface, strerror(errno));
01185       if (echocancel != AEC_OFF)
01186          ioctl(tmp->fd, IXJCTL_AEC_START, echocancel);
01187       if (silencesupression) 
01188          tmp->silencesupression = 1;
01189 #ifdef PHONE_VAD
01190       ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression);
01191 #endif
01192       tmp->mode = mode;
01193       flags = fcntl(tmp->fd, F_GETFL);
01194       fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK);
01195       tmp->owner = NULL;
01196       tmp->lastformat = -1;
01197       tmp->lastinput = -1;
01198       tmp->ministate = 0;
01199       memset(tmp->ext, 0, sizeof(tmp->ext));
01200       ast_copy_string(tmp->language, language, sizeof(tmp->language));
01201       ast_copy_string(tmp->dev, iface, sizeof(tmp->dev));
01202       ast_copy_string(tmp->context, context, sizeof(tmp->context));
01203       tmp->next = NULL;
01204       tmp->obuflen = 0;
01205       tmp->dialtone = 0;
01206       tmp->cpt = 0;
01207       ast_copy_string(tmp->cid_num, cid_num, sizeof(tmp->cid_num));
01208       ast_copy_string(tmp->cid_name, cid_name, sizeof(tmp->cid_name));
01209       tmp->txgain = txgain;
01210       ioctl(tmp->fd, PHONE_PLAY_VOLUME, tmp->txgain);
01211       tmp->rxgain = rxgain;
01212       ioctl(tmp->fd, PHONE_REC_VOLUME, tmp->rxgain);
01213    }
01214    return tmp;
01215 }

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

Definition at line 1259 of file chan_phone.c.

References ast_log(), DEFAULT_GAIN, and LOG_ERROR.

Referenced by load_module().

01260 {
01261    float gain;
01262 
01263    /* try to scan number */
01264    if (sscanf(value, "%30f", &gain) != 1)
01265    {
01266       ast_log(LOG_ERROR, "Invalid %s value '%s' in '%s' config\n",
01267          value, gain_type, config);
01268       return DEFAULT_GAIN;
01269    }
01270 
01271    /* multiplicate gain by 1.0 gain value */ 
01272    gain = gain * (float)DEFAULT_GAIN;
01273 
01274    /* percentage? */
01275    if (value[strlen(value) - 1] == '%')
01276       return (int)(gain / (float)100);
01277 
01278    return (int)gain;
01279 }

static int phone_answer ( struct ast_channel ast  )  [static]

Definition at line 458 of file chan_phone.c.

References ast_log(), ast_setstate(), AST_STATE_UP, errno, phone_pvt::fd, LOG_DEBUG, phone_pvt::mode, MODE_FXO, ast_channel::name, option_debug, phone_setup(), ast_channel::rings, and ast_channel::tech_pvt.

00459 {
00460    struct phone_pvt *p;
00461    p = ast->tech_pvt;
00462    /* In case it's a LineJack, take it off hook */
00463    if (p->mode == MODE_FXO) {
00464       if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_OFF_HOOK)) 
00465          ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n", ast->name, strerror(errno));
00466       else
00467          ast_log(LOG_DEBUG, "Took linejack off hook\n");
00468    }
00469    phone_setup(ast);
00470    if (option_debug)
00471       ast_log(LOG_DEBUG, "phone_answer(%s)\n", ast->name);
00472    ast->rings = 0;
00473    ast_setstate(ast, AST_STATE_UP);
00474    return 0;
00475 }

static int phone_call ( struct ast_channel ast,
char *  dest,
int  timeout 
) [static]

Definition at line 294 of file chan_phone.c.

References ast_channel::_state, AST_CONTROL_RINGING, ast_copy_string(), ast_localtime(), ast_log(), ast_queue_control(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RINGING, ast_strlen_zero(), ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, DEFAULT_CALLER_ID, ast_channel::fds, IXJ_PHONE_RING_START, LOG_DEBUG, LOG_WARNING, phone_pvt::mode, MODE_FXS, ast_channel::name, option_debug, phone_digit_end(), and ast_channel::tech_pvt.

00295 {
00296    struct phone_pvt *p;
00297 
00298    PHONE_CID cid;
00299    time_t UtcTime;
00300    struct tm tm;
00301    int start;
00302 
00303    time(&UtcTime);
00304    ast_localtime(&UtcTime, &tm, NULL);
00305 
00306    memset(&cid, 0, sizeof(PHONE_CID));
00307    if(&tm != NULL) {
00308       snprintf(cid.month, sizeof(cid.month), "%02d",(tm.tm_mon + 1));
00309       snprintf(cid.day, sizeof(cid.day),     "%02d", tm.tm_mday);
00310       snprintf(cid.hour, sizeof(cid.hour),   "%02d", tm.tm_hour);
00311       snprintf(cid.min, sizeof(cid.min),     "%02d", tm.tm_min);
00312    }
00313    /* the standard format of ast->callerid is:  "name" <number>, but not always complete */
00314    if (ast_strlen_zero(ast->cid.cid_name))
00315       strcpy(cid.name, DEFAULT_CALLER_ID);
00316    else
00317       ast_copy_string(cid.name, ast->cid.cid_name, sizeof(cid.name));
00318 
00319    if (ast->cid.cid_num) 
00320       ast_copy_string(cid.number, ast->cid.cid_num, sizeof(cid.number));
00321 
00322    p = ast->tech_pvt;
00323 
00324    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
00325       ast_log(LOG_WARNING, "phone_call called on %s, neither down nor reserved\n", ast->name);
00326       return -1;
00327    }
00328    if (option_debug)
00329       ast_log(LOG_DEBUG, "Ringing %s on %s (%d)\n", dest, ast->name, ast->fds[0]);
00330 
00331    start = IXJ_PHONE_RING_START(cid);
00332    if (start == -1)
00333       return -1;
00334    
00335    if (p->mode == MODE_FXS) {
00336       char *digit = strchr(dest, '/');
00337       if (digit)
00338       {
00339         digit++;
00340         while (*digit)
00341           phone_digit_end(ast, *digit++, 0);
00342       }
00343    }
00344  
00345    ast_setstate(ast, AST_STATE_RINGING);
00346    ast_queue_control(ast, AST_CONTROL_RINGING);
00347    return 0;
00348 }

static void phone_check_exception ( struct phone_pvt i  )  [static]

Definition at line 904 of file chan_phone.c.

References ast_canmatch_extension(), ast_exists_extension(), ast_log(), AST_MAX_EXTENSION, ast_module_ref(), ast_module_unref(), AST_STATE_RING, ast_verbose(), phone_pvt::cid_num, phone_pvt::context, phone_pvt::cpt, phone_pvt::dialtone, phone_pvt::ext, phone_pvt::fd, phone_pvt::lastformat, LOG_DEBUG, phone_pvt::mode, MODE_DIALTONE, MODE_FXS, MODE_IMMEDIATE, MODE_SIGMA, option_debug, and phone_new().

00905 {
00906    int offhook=0;
00907    char digit[2] = {0 , 0};
00908    union telephony_exception phonee;
00909    /* XXX Do something XXX */
00910 #if 0
00911    ast_log(LOG_DEBUG, "Exception!\n");
00912 #endif
00913    phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION);
00914    if (phonee.bits.dtmf_ready)  {
00915       digit[0] = ioctl(i->fd, PHONE_GET_DTMF_ASCII);
00916       if (i->mode == MODE_DIALTONE || i->mode == MODE_FXS || i->mode == MODE_SIGMA) {
00917          ioctl(i->fd, PHONE_PLAY_STOP);
00918          ioctl(i->fd, PHONE_REC_STOP);
00919          ioctl(i->fd, PHONE_CPT_STOP);
00920          i->dialtone = 0;
00921          if (strlen(i->ext) < AST_MAX_EXTENSION - 1)
00922             strncat(i->ext, digit, sizeof(i->ext) - strlen(i->ext) - 1);
00923          if ((i->mode != MODE_FXS ||
00924               !(phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION)) ||
00925               !phonee.bits.dtmf_ready) &&
00926              ast_exists_extension(NULL, i->context, i->ext, 1, i->cid_num)) {
00927             /* It's a valid extension in its context, get moving! */
00928             phone_new(i, AST_STATE_RING, i->context);
00929             /* No need to restart monitor, we are the monitor */
00930          } else if (!ast_canmatch_extension(NULL, i->context, i->ext, 1, i->cid_num)) {
00931             /* There is nothing in the specified extension that can match anymore.
00932                Try the default */
00933             if (ast_exists_extension(NULL, "default", i->ext, 1, i->cid_num)) {
00934                /* Check the default, too... */
00935                phone_new(i, AST_STATE_RING, "default");
00936                /* XXX This should probably be justified better XXX */
00937             }  else if (!ast_canmatch_extension(NULL, "default", i->ext, 1, i->cid_num)) {
00938                /* It's not a valid extension, give a busy signal */
00939                if (option_debug)
00940                   ast_log(LOG_DEBUG, "%s can't match anything in %s or default\n", i->ext, i->context);
00941                ioctl(i->fd, PHONE_BUSY);
00942                i->cpt = 1;
00943             }
00944          }
00945 #if 0
00946          ast_verbose("Extension is %s\n", i->ext);
00947 #endif
00948       }
00949    }
00950    if (phonee.bits.hookstate) {
00951       offhook = ioctl(i->fd, PHONE_HOOKSTATE);
00952       if (offhook) {
00953          if (i->mode == MODE_IMMEDIATE) {
00954             phone_new(i, AST_STATE_RING, i->context);
00955          } else if (i->mode == MODE_DIALTONE) {
00956             ast_module_ref(ast_module_info->self);
00957             /* Reset the extension */
00958             i->ext[0] = '\0';
00959             /* Play the dialtone */
00960             i->dialtone++;
00961             ioctl(i->fd, PHONE_PLAY_STOP);
00962             ioctl(i->fd, PHONE_PLAY_CODEC, ULAW);
00963             ioctl(i->fd, PHONE_PLAY_START);
00964             i->lastformat = -1;
00965          } else if (i->mode == MODE_SIGMA) {
00966             ast_module_ref(ast_module_info->self);
00967             /* Reset the extension */
00968             i->ext[0] = '\0';
00969             /* Play the dialtone */
00970             i->dialtone++;
00971             ioctl(i->fd, PHONE_DIALTONE);
00972          }
00973       } else {
00974          if (i->dialtone)
00975             ast_module_unref(ast_module_info->self);
00976          memset(i->ext, 0, sizeof(i->ext));
00977          if (i->cpt)
00978          {
00979             ioctl(i->fd, PHONE_CPT_STOP);
00980             i->cpt = 0;
00981          }
00982          ioctl(i->fd, PHONE_PLAY_STOP);
00983          ioctl(i->fd, PHONE_REC_STOP);
00984          i->dialtone = 0;
00985          i->lastformat = -1;
00986       }
00987    }
00988    if (phonee.bits.pstn_ring) {
00989       ast_verbose("Unit is ringing\n");
00990       phone_new(i, AST_STATE_RING, i->context);
00991    }
00992    if (phonee.bits.caller_id)
00993       ast_verbose("We have caller ID\n");
00994    
00995    
00996 }

static int phone_digit_begin ( struct ast_channel ast,
char  digit 
) [static]

Definition at line 246 of file chan_phone.c.

00247 {
00248    /* XXX Modify this callback to let Asterisk support controlling the length of DTMF */
00249    return 0;
00250 }

static int phone_digit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
) [static]

Definition at line 252 of file chan_phone.c.

References ast_log(), phone_pvt::fd, phone_pvt::lastformat, LOG_DEBUG, LOG_WARNING, and ast_channel::tech_pvt.

Referenced by phone_call().

00253 {
00254    struct phone_pvt *p;
00255    int outdigit;
00256    p = ast->tech_pvt;
00257    ast_log(LOG_DEBUG, "Dialed %c\n", digit);
00258    switch(digit) {
00259    case '0':
00260    case '1':
00261    case '2':
00262    case '3':
00263    case '4':
00264    case '5':
00265    case '6':
00266    case '7':
00267    case '8':
00268    case '9':
00269       outdigit = digit - '0';
00270       break;
00271    case '*':
00272       outdigit = 11;
00273       break;
00274    case '#':
00275       outdigit = 12;
00276       break;
00277    case 'f':   /*flash*/
00278    case 'F':
00279       ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
00280       usleep(320000);
00281       ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
00282       p->lastformat = -1;
00283       return 0;
00284    default:
00285       ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit);
00286       return -1;
00287    }
00288    ast_log(LOG_DEBUG, "Dialed %d\n", outdigit);
00289    ioctl(p->fd, PHONE_PLAY_TONE, outdigit);
00290    p->lastformat = -1;
00291    return 0;
00292 }

static struct ast_frame * phone_exception ( struct ast_channel ast  )  [static]

Definition at line 491 of file chan_phone.c.

References ast_channel::_state, AST_CONTROL_ANSWER, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_NULL, ast_log(), ast_setstate(), AST_STATE_RINGING, AST_STATE_UP, ast_tv(), ast_verbose(), ast_frame::data, ast_frame::datalen, ast_frame::delivery, phone_pvt::fd, phone_pvt::fr, ast_frame::frametype, LOG_DEBUG, LOG_WARNING, ast_frame::mallocd, phone_pvt::mode, MODE_FXO, ast_frame::offset, option_debug, phone_setup(), ast_frame::samples, ast_frame::src, ast_frame::subclass, and ast_channel::tech_pvt.

00492 {
00493    int res;
00494    union telephony_exception phonee;
00495    struct phone_pvt *p = ast->tech_pvt;
00496    char digit;
00497 
00498    /* Some nice norms */
00499    p->fr.datalen = 0;
00500    p->fr.samples = 0;
00501    p->fr.data =  NULL;
00502    p->fr.src = "Phone";
00503    p->fr.offset = 0;
00504    p->fr.mallocd=0;
00505    p->fr.delivery = ast_tv(0,0);
00506    
00507    phonee.bytes = ioctl(p->fd, PHONE_EXCEPTION);
00508    if (phonee.bits.dtmf_ready)  {
00509       if (option_debug)
00510          ast_log(LOG_DEBUG, "phone_exception(): DTMF\n");
00511    
00512       /* We've got a digit -- Just handle this nicely and easily */
00513       digit =  ioctl(p->fd, PHONE_GET_DTMF_ASCII);
00514       p->fr.subclass = digit;
00515       p->fr.frametype = AST_FRAME_DTMF;
00516       return &p->fr;
00517    }
00518    if (phonee.bits.hookstate) {
00519       if (option_debug)
00520          ast_log(LOG_DEBUG, "Hookstate changed\n");
00521       res = ioctl(p->fd, PHONE_HOOKSTATE);
00522       /* See if we've gone on hook, if so, notify by returning NULL */
00523       if (option_debug)
00524          ast_log(LOG_DEBUG, "New hookstate: %d\n", res);
00525       if (!res && (p->mode != MODE_FXO))
00526          return NULL;
00527       else {
00528          if (ast->_state == AST_STATE_RINGING) {
00529             /* They've picked up the phone */
00530             p->fr.frametype = AST_FRAME_CONTROL;
00531             p->fr.subclass = AST_CONTROL_ANSWER;
00532             phone_setup(ast);
00533             ast_setstate(ast, AST_STATE_UP);
00534             return &p->fr;
00535          }  else 
00536             ast_log(LOG_WARNING, "Got off hook in weird state %d\n", ast->_state);
00537       }
00538    }
00539 #if 1
00540    if (phonee.bits.pstn_ring)
00541       ast_verbose("Unit is ringing\n");
00542    if (phonee.bits.caller_id) {
00543       ast_verbose("We have caller ID\n");
00544    }
00545    if (phonee.bits.pstn_wink)
00546       ast_verbose("Detected Wink\n");
00547 #endif
00548    /* Strange -- nothing there.. */
00549    p->fr.frametype = AST_FRAME_NULL;
00550    p->fr.subclass = 0;
00551    return &p->fr;
00552 }

static int phone_fixup ( struct ast_channel old,
struct ast_channel new 
) [static]

Definition at line 238 of file chan_phone.c.

References phone_pvt::owner, and ast_channel::tech_pvt.

00239 {
00240    struct phone_pvt *pvt = old->tech_pvt;
00241    if (pvt && pvt->owner == old)
00242       pvt->owner = new;
00243    return 0;
00244 }

static int phone_hangup ( struct ast_channel ast  )  [static]

Definition at line 350 of file chan_phone.c.

References ast_log(), ast_module_unref(), ast_setstate(), AST_STATE_DOWN, ast_verbose(), phone_pvt::cpt, phone_pvt::dialtone, errno, phone_pvt::ext, phone_pvt::fd, phone_pvt::lastformat, phone_pvt::lastinput, LOG_DEBUG, LOG_WARNING, phone_pvt::ministate, phone_pvt::mode, MODE_FXO, ast_channel::name, phone_pvt::obuflen, option_debug, option_verbose, phone_pvt::owner, restart_monitor(), ast_channel::tech_pvt, and VERBOSE_PREFIX_3.

00351 {
00352    struct phone_pvt *p;
00353    p = ast->tech_pvt;
00354    if (option_debug)
00355       ast_log(LOG_DEBUG, "phone_hangup(%s)\n", ast->name);
00356    if (!ast->tech_pvt) {
00357       ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
00358       return 0;
00359    }
00360    /* XXX Is there anything we can do to really hang up except stop recording? */
00361    ast_setstate(ast, AST_STATE_DOWN);
00362    if (ioctl(p->fd, PHONE_REC_STOP))
00363       ast_log(LOG_WARNING, "Failed to stop recording\n");
00364    if (ioctl(p->fd, PHONE_PLAY_STOP))
00365       ast_log(LOG_WARNING, "Failed to stop playing\n");
00366    if (ioctl(p->fd, PHONE_RING_STOP))
00367       ast_log(LOG_WARNING, "Failed to stop ringing\n");
00368    if (ioctl(p->fd, PHONE_CPT_STOP))
00369       ast_log(LOG_WARNING, "Failed to stop sounds\n");
00370 
00371    /* If it's an FXO, hang them up */
00372    if (p->mode == MODE_FXO) {
00373       if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK)) 
00374          ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",ast->name, strerror(errno));
00375    }
00376 
00377    /* If they're off hook, give a busy signal */
00378    if (ioctl(p->fd, PHONE_HOOKSTATE)) {
00379       if (option_debug)
00380          ast_log(LOG_DEBUG, "Got hunghup, giving busy signal\n");
00381       ioctl(p->fd, PHONE_BUSY);
00382       p->cpt = 1;
00383    }
00384    p->lastformat = -1;
00385    p->lastinput = -1;
00386    p->ministate = 0;
00387    p->obuflen = 0;
00388    p->dialtone = 0;
00389    memset(p->ext, 0, sizeof(p->ext));
00390    ((struct phone_pvt *)(ast->tech_pvt))->owner = NULL;
00391    ast_module_unref(ast_module_info->self);
00392    if (option_verbose > 2) 
00393       ast_verbose( VERBOSE_PREFIX_3 "Hungup '%s'\n", ast->name);
00394    ast->tech_pvt = NULL;
00395    ast_setstate(ast, AST_STATE_DOWN);
00396    restart_monitor();
00397    return 0;
00398 }

static int phone_indicate ( struct ast_channel chan,
int  condition,
const void *  data,
size_t  datalen 
) [static]

Definition at line 210 of file chan_phone.c.

References AST_CONTROL_FLASH, AST_CONTROL_HOLD, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, ast_log(), ast_moh_start(), ast_moh_stop(), phone_pvt::fd, phone_pvt::lastformat, LOG_DEBUG, LOG_WARNING, ast_channel::name, and ast_channel::tech_pvt.

00211 {
00212    struct phone_pvt *p = chan->tech_pvt;
00213    int res=-1;
00214    ast_log(LOG_DEBUG, "Requested indication %d on channel %s\n", condition, chan->name);
00215    switch(condition) {
00216    case AST_CONTROL_FLASH:
00217       ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
00218       usleep(320000);
00219       ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
00220          p->lastformat = -1;
00221          res = 0;
00222          break;
00223    case AST_CONTROL_HOLD:
00224       ast_moh_start(chan, data, NULL);
00225       break;
00226    case AST_CONTROL_UNHOLD:
00227       ast_moh_stop(chan);
00228       break;
00229    case AST_CONTROL_SRCUPDATE:
00230       res = 0;
00231       break;
00232    default:
00233       ast_log(LOG_WARNING, "Condition %d is not supported on channel %s\n", condition, chan->name);
00234    }
00235    return res;
00236 }

static void phone_mini_packet ( struct phone_pvt i  )  [static]

Definition at line 892 of file chan_phone.c.

References ast_log(), errno, phone_pvt::fd, and LOG_WARNING.

00893 {
00894    int res;
00895    char buf[1024];
00896    /* Ignore stuff we read... */
00897    res = read(i->fd, buf, sizeof(buf));
00898    if (res < 1) {
00899       ast_log(LOG_WARNING, "Read returned %d: %s\n", res, strerror(errno));
00900       return;
00901    }
00902 }

static struct ast_channel* phone_new ( struct phone_pvt i,
int  state,
char *  context 
) [static]

Definition at line 831 of file chan_phone.c.

References ast_channel_alloc(), ast_copy_string(), AST_FORMAT_SLINEAR, ast_hangup(), ast_log(), ast_module_ref(), ast_pbx_start(), AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_string_field_set, ast_strlen_zero(), phone_pvt::cid_name, phone_pvt::cid_num, phone_pvt::context, phone_pvt::cpt, cur_tech, phone_pvt::dev, phone_pvt::ext, phone_pvt::fd, phone_pvt::language, LOG_WARNING, phone_pvt::mode, MODE_FXS, and phone_pvt::owner.

Referenced by phone_check_exception(), and phone_request().

00832 {
00833    struct ast_channel *tmp;
00834    struct phone_codec_data codec;
00835    tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", i->ext, i->context, 0, "Phone/%s", i->dev + 5);
00836    if (tmp) {
00837       tmp->tech = cur_tech;
00838       tmp->fds[0] = i->fd;
00839       /* XXX Switching formats silently causes kernel panics XXX */
00840       if (i->mode == MODE_FXS &&
00841           ioctl(i->fd, PHONE_QUERY_CODEC, &codec) == 0) {
00842          if (codec.type == LINEAR16)
00843             tmp->nativeformats =
00844             tmp->rawreadformat =
00845             tmp->rawwriteformat =
00846             AST_FORMAT_SLINEAR;
00847          else {
00848             tmp->nativeformats =
00849             tmp->rawreadformat =
00850             tmp->rawwriteformat =
00851             prefformat & ~AST_FORMAT_SLINEAR;
00852          }
00853       }
00854       else {
00855          tmp->nativeformats = prefformat;
00856          tmp->rawreadformat = prefformat;
00857          tmp->rawwriteformat = prefformat;
00858       }
00859       /* no need to call ast_setstate: the channel_alloc already did its job */
00860       if (state == AST_STATE_RING)
00861          tmp->rings = 1;
00862       tmp->tech_pvt = i;
00863       ast_copy_string(tmp->context, context, sizeof(tmp->context));
00864       if (!ast_strlen_zero(i->ext))
00865          ast_copy_string(tmp->exten, i->ext, sizeof(tmp->exten));
00866       else
00867          strcpy(tmp->exten, "s");
00868       if (!ast_strlen_zero(i->language))
00869          ast_string_field_set(tmp, language, i->language);
00870 
00871       /* Don't use ast_set_callerid() here because it will
00872        * generate a NewCallerID event before the NewChannel event */
00873       tmp->cid.cid_ani = ast_strdup(i->cid_num);
00874 
00875       i->owner = tmp;
00876       ast_module_ref(ast_module_info->self);
00877       if (state != AST_STATE_DOWN) {
00878          if (state == AST_STATE_RING) {
00879             ioctl(tmp->fds[0], PHONE_RINGBACK);
00880             i->cpt = 1;
00881          }
00882          if (ast_pbx_start(tmp)) {
00883             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
00884             ast_hangup(tmp);
00885          }
00886       }
00887    } else
00888       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
00889    return tmp;
00890 }

static struct ast_frame * phone_read ( struct ast_channel ast  )  [static]

Definition at line 554 of file chan_phone.c.

References ast_clear_flag, AST_FLAG_BLOCKING, AST_FORMAT_MAX_AUDIO, AST_FORMAT_PNG, AST_FORMAT_SLINEAR, ast_frame_byteswap_le, AST_FRAME_IMAGE, AST_FRAME_NULL, AST_FRAME_VIDEO, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_tv(), phone_pvt::buf, CHECK_BLOCKING, ast_frame::data, ast_frame::datalen, ast_frame::delivery, errno, phone_pvt::fd, phone_pvt::fr, ast_frame::frametype, phone_pvt::lastinput, LOG_WARNING, ast_frame::mallocd, phone_pvt::mode, MODE_FXS, ast_frame::offset, PHONE_MAX_BUF, ast_frame::samples, ast_frame::src, ast_frame::subclass, and ast_channel::tech_pvt.

00555 {
00556    int res;
00557    struct phone_pvt *p = ast->tech_pvt;
00558    
00559 
00560    /* Some nice norms */
00561    p->fr.datalen = 0;
00562    p->fr.samples = 0;
00563    p->fr.data =  NULL;
00564    p->fr.src = "Phone";
00565    p->fr.offset = 0;
00566    p->fr.mallocd=0;
00567    p->fr.delivery = ast_tv(0,0);
00568 
00569    /* Try to read some data... */
00570    CHECK_BLOCKING(ast);
00571    res = read(p->fd, p->buf, PHONE_MAX_BUF);
00572    ast_clear_flag(ast, AST_FLAG_BLOCKING);
00573    if (res < 0) {
00574 #if 0
00575       if (errno == EAGAIN) {
00576          ast_log(LOG_WARNING, "Null frame received\n");
00577          p->fr.frametype = AST_FRAME_NULL;
00578          p->fr.subclass = 0;
00579          return &p->fr;
00580       }
00581 #endif
00582       ast_log(LOG_WARNING, "Error reading: %s\n", strerror(errno));
00583       return NULL;
00584    }
00585    p->fr.data = p->buf;
00586    if (p->mode != MODE_FXS)
00587    switch(p->buf[0] & 0x3) {
00588    case '0':
00589    case '1':
00590       /* Normal */
00591       break;
00592    case '2':
00593    case '3':
00594       /* VAD/CNG, only send two words */
00595       res = 4;
00596       break;
00597    }
00598    p->fr.samples = 240;
00599    p->fr.datalen = res;
00600    p->fr.frametype = p->lastinput <= AST_FORMAT_MAX_AUDIO ?
00601                           AST_FRAME_VOICE : 
00602            p->lastinput <= AST_FORMAT_PNG ? AST_FRAME_IMAGE 
00603            : AST_FRAME_VIDEO;
00604    p->fr.subclass = p->lastinput;
00605    p->fr.offset = AST_FRIENDLY_OFFSET;
00606    /* Byteswap from little-endian to native-endian */
00607    if (p->fr.subclass == AST_FORMAT_SLINEAR)
00608       ast_frame_byteswap_le(&p->fr);
00609    return &p->fr;
00610 }

static struct ast_channel * phone_request ( const char *  type,
int  format,
void *  data,
int *  cause 
) [static]

Definition at line 1217 of file chan_phone.c.

References AST_CAUSE_BUSY, AST_FORMAT_G723_1, AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_STATE_DOWN, phone_pvt::context, phone_pvt::dev, iflist, iflock, LOG_ERROR, LOG_NOTICE, phone_pvt::mode, MODE_FXS, name, phone_pvt::next, phone_pvt::owner, phone_new(), and restart_monitor().

01218 {
01219    int oldformat;
01220    struct phone_pvt *p;
01221    struct ast_channel *tmp = NULL;
01222    char *name = data;
01223 
01224    /* Search for an unowned channel */
01225    if (ast_mutex_lock(&iflock)) {
01226       ast_log(LOG_ERROR, "Unable to lock interface list???\n");
01227       return NULL;
01228    }
01229    p = iflist;
01230    while(p) {
01231       if (p->mode == MODE_FXS ||
01232           format & (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW)) {
01233           size_t length = strlen(p->dev + 5);
01234          if (strncmp(name, p->dev + 5, length) == 0 &&
01235              !isalnum(name[length])) {
01236              if (!p->owner) {
01237                      tmp = phone_new(p, AST_STATE_DOWN, p->context);
01238                      break;
01239                 } else
01240                      *cause = AST_CAUSE_BUSY;
01241             }
01242       }
01243       p = p->next;
01244    }
01245    ast_mutex_unlock(&iflock);
01246    restart_monitor();
01247    if (tmp == NULL) {
01248       oldformat = format;
01249       format &= (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW);
01250       if (!format) {
01251          ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
01252          return NULL;
01253       }
01254    }
01255    return tmp;
01256 }

static int phone_send_text ( struct ast_channel ast,
const char *  text 
) [static]

Definition at line 646 of file chan_phone.c.

References phone_write_buf(), and ast_channel::tech_pvt.

00647 {
00648     int length = strlen(text);
00649     return phone_write_buf(ast->tech_pvt, text, length, length, 0) == 
00650            length ? 0 : -1;
00651 }

static int phone_setup ( struct ast_channel ast  )  [static]

Definition at line 400 of file chan_phone.c.

References AST_FORMAT_G723_1, AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, ast_getformatname(), ast_log(), phone_pvt::fd, phone_pvt::lastinput, LOG_WARNING, phone_pvt::mode, MODE_FXS, ast_channel::rawreadformat, and ast_channel::tech_pvt.

Referenced by phone_answer(), phone_exception(), and phone_write().

00401 {
00402    struct phone_pvt *p;
00403    p = ast->tech_pvt;
00404    ioctl(p->fd, PHONE_CPT_STOP);
00405    /* Nothing to answering really, just start recording */
00406    if (ast->rawreadformat == AST_FORMAT_G723_1) {
00407       /* Prefer g723 */
00408       ioctl(p->fd, PHONE_REC_STOP);
00409       if (p->lastinput != AST_FORMAT_G723_1) {
00410          p->lastinput = AST_FORMAT_G723_1;
00411          if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
00412             ast_log(LOG_WARNING, "Failed to set codec to g723.1\n");
00413             return -1;
00414          }
00415       }
00416    } else if (ast->rawreadformat == AST_FORMAT_SLINEAR) {
00417       ioctl(p->fd, PHONE_REC_STOP);
00418       if (p->lastinput != AST_FORMAT_SLINEAR) {
00419          p->lastinput = AST_FORMAT_SLINEAR;
00420          if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
00421             ast_log(LOG_WARNING, "Failed to set codec to signed linear 16\n");
00422             return -1;
00423          }
00424       }
00425    } else if (ast->rawreadformat == AST_FORMAT_ULAW) {
00426       ioctl(p->fd, PHONE_REC_STOP);
00427       if (p->lastinput != AST_FORMAT_ULAW) {
00428          p->lastinput = AST_FORMAT_ULAW;
00429          if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) {
00430             ast_log(LOG_WARNING, "Failed to set codec to uLaw\n");
00431             return -1;
00432          }
00433       }
00434    } else if (p->mode == MODE_FXS) {
00435       ioctl(p->fd, PHONE_REC_STOP);
00436       if (p->lastinput != ast->rawreadformat) {
00437          p->lastinput = ast->rawreadformat;
00438          if (ioctl(p->fd, PHONE_REC_CODEC, ast->rawreadformat)) {
00439             ast_log(LOG_WARNING, "Failed to set codec to %d\n", 
00440                ast->rawreadformat);
00441             return -1;
00442          }
00443       }
00444    } else {
00445       ast_log(LOG_WARNING, "Can't do format %s\n", ast_getformatname(ast->rawreadformat));
00446       return -1;
00447    }
00448    if (ioctl(p->fd, PHONE_REC_START)) {
00449       ast_log(LOG_WARNING, "Failed to start recording\n");
00450       return -1;
00451    }
00452    /* set the DTMF times (the default is too short) */
00453    ioctl(p->fd, PHONE_SET_TONE_ON_TIME, 300);
00454    ioctl(p->fd, PHONE_SET_TONE_OFF_TIME, 200);
00455    return 0;
00456 }

static int phone_write ( struct ast_channel ast,
struct ast_frame frame 
) [static]

Definition at line 653 of file chan_phone.c.

References ast_channel::_state, AST_FORMAT_G723_1, AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, AST_FRAME_IMAGE, AST_FRAME_VOICE, ast_log(), ast_setstate(), AST_STATE_UP, ast_frame::data, ast_frame::datalen, errno, phone_pvt::fd, ast_frame::frametype, phone_pvt::lastformat, phone_pvt::lastinput, LOG_WARNING, phone_pvt::mode, MODE_FXS, phone_pvt::obuflen, phone_setup(), phone_write_buf(), phone_pvt::silencesupression, ast_frame::subclass, and ast_channel::tech_pvt.

00654 {
00655    struct phone_pvt *p = ast->tech_pvt;
00656    int res;
00657    int maxfr=0;
00658    char *pos;
00659    int sofar;
00660    int expected;
00661    int codecset = 0;
00662    char tmpbuf[4];
00663    /* Write a frame of (presumably voice) data */
00664    if (frame->frametype != AST_FRAME_VOICE && p->mode != MODE_FXS) {
00665       if (frame->frametype != AST_FRAME_IMAGE)
00666          ast_log(LOG_WARNING, "Don't know what to do with  frame type '%d'\n", frame->frametype);
00667       return 0;
00668    }
00669    if (!(frame->subclass &
00670       (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW)) && 
00671        p->mode != MODE_FXS) {
00672       ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
00673       return -1;
00674    }
00675 #if 0
00676    /* If we're not in up mode, go into up mode now */
00677    if (ast->_state != AST_STATE_UP) {
00678       ast_setstate(ast, AST_STATE_UP);
00679       phone_setup(ast);
00680    }
00681 #else
00682    if (ast->_state != AST_STATE_UP) {
00683       /* Don't try tos end audio on-hook */
00684       return 0;
00685    }
00686 #endif   
00687    if (frame->subclass == AST_FORMAT_G723_1) {
00688       if (p->lastformat != AST_FORMAT_G723_1) {
00689          ioctl(p->fd, PHONE_PLAY_STOP);
00690          ioctl(p->fd, PHONE_REC_STOP);
00691          if (ioctl(p->fd, PHONE_PLAY_CODEC, G723_63)) {
00692             ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
00693             return -1;
00694          }
00695          if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
00696             ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
00697             return -1;
00698          }
00699          p->lastformat = AST_FORMAT_G723_1;
00700          p->lastinput = AST_FORMAT_G723_1;
00701          /* Reset output buffer */
00702          p->obuflen = 0;
00703          codecset = 1;
00704       }
00705       if (frame->datalen > 24) {
00706          ast_log(LOG_WARNING, "Frame size too large for G.723.1 (%d bytes)\n", frame->datalen);
00707          return -1;
00708       }
00709       maxfr = 24;
00710    } else if (frame->subclass == AST_FORMAT_SLINEAR) {
00711       if (p->lastformat != AST_FORMAT_SLINEAR) {
00712          ioctl(p->fd, PHONE_PLAY_STOP);
00713          ioctl(p->fd, PHONE_REC_STOP);
00714          if (ioctl(p->fd, PHONE_PLAY_CODEC, LINEAR16)) {
00715             ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
00716             return -1;
00717          }
00718          if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
00719             ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
00720             return -1;
00721          }
00722          p->lastformat = AST_FORMAT_SLINEAR;
00723          p->lastinput = AST_FORMAT_SLINEAR;
00724          codecset = 1;
00725          /* Reset output buffer */
00726          p->obuflen = 0;
00727       }
00728       maxfr = 480;
00729    } else if (frame->subclass == AST_FORMAT_ULAW) {
00730       if (p->lastformat != AST_FORMAT_ULAW) {
00731          ioctl(p->fd, PHONE_PLAY_STOP);
00732          ioctl(p->fd, PHONE_REC_STOP);
00733          if (ioctl(p->fd, PHONE_PLAY_CODEC, ULAW)) {
00734             ast_log(LOG_WARNING, "Unable to set uLaw mode\n");
00735             return -1;
00736          }
00737          if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) {
00738             ast_log(LOG_WARNING, "Unable to set uLaw mode\n");
00739             return -1;
00740          }
00741          p->lastformat = AST_FORMAT_ULAW;
00742          p->lastinput = AST_FORMAT_ULAW;
00743          codecset = 1;
00744          /* Reset output buffer */
00745          p->obuflen = 0;
00746       }
00747       maxfr = 240;
00748    } else {
00749       if (p->lastformat != frame->subclass) {
00750          ioctl(p->fd, PHONE_PLAY_STOP);
00751          ioctl(p->fd, PHONE_REC_STOP);
00752          if (ioctl(p->fd, PHONE_PLAY_CODEC, frame->subclass)) {
00753             ast_log(LOG_WARNING, "Unable to set %d mode\n",
00754                frame->subclass);
00755             return -1;
00756          }
00757          if (ioctl(p->fd, PHONE_REC_CODEC, frame->subclass)) {
00758             ast_log(LOG_WARNING, "Unable to set %d mode\n",
00759                frame->subclass);
00760             return -1;
00761          }
00762          p->lastformat = frame->subclass;
00763          p->lastinput = frame->subclass;
00764          codecset = 1;
00765          /* Reset output buffer */
00766          p->obuflen = 0;
00767       }
00768       maxfr = 480;
00769    }
00770    if (codecset) {
00771       ioctl(p->fd, PHONE_REC_DEPTH, 3);
00772       ioctl(p->fd, PHONE_PLAY_DEPTH, 3);
00773       if (ioctl(p->fd, PHONE_PLAY_START)) {
00774          ast_log(LOG_WARNING, "Failed to start playback\n");
00775          return -1;
00776       }
00777       if (ioctl(p->fd, PHONE_REC_START)) {
00778          ast_log(LOG_WARNING, "Failed to start recording\n");
00779          return -1;
00780       }
00781    }
00782    /* If we get here, we have a frame of Appropriate data */
00783    sofar = 0;
00784    pos = frame->data;
00785    while(sofar < frame->datalen) {
00786       /* Write in no more than maxfr sized frames */
00787       expected = frame->datalen - sofar;
00788       if (maxfr < expected)
00789          expected = maxfr;
00790       /* XXX Internet Phone Jack does not handle the 4-byte VAD frame properly! XXX 
00791          we have to pad it to 24 bytes still.  */
00792       if (frame->datalen == 4) {
00793          if (p->silencesupression) {
00794             memset(tmpbuf, 0, sizeof(tmpbuf));
00795             memcpy(tmpbuf, frame->data, 4);
00796             expected = 24;
00797             res = phone_write_buf(p, tmpbuf, expected, maxfr, 0);
00798          }
00799          res = 4;
00800          expected=4;
00801       } else {
00802          int swap = 0;
00803 #if __BYTE_ORDER == __BIG_ENDIAN
00804          if (frame->subclass == AST_FORMAT_SLINEAR)
00805             swap = 1; /* Swap big-endian samples to little-endian as we copy */
00806 #endif
00807          res = phone_write_buf(p, pos, expected, maxfr, swap);
00808       }
00809       if (res != expected) {
00810          if ((errno != EAGAIN) && (errno != EINTR)) {
00811             if (res < 0) 
00812                ast_log(LOG_WARNING, "Write returned error (%s)\n", strerror(errno));
00813    /*
00814     * Card is in non-blocking mode now and it works well now, but there are
00815     * lot of messages like this. So, this message is temporarily disabled.
00816     */
00817 #if 0
00818             else
00819                ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frame->datalen);
00820 #endif
00821             return -1;
00822          } else /* Pretend it worked */
00823             res = expected;
00824       }
00825       sofar += res;
00826       pos += res;
00827    }
00828    return 0;
00829 }

static int phone_write_buf ( struct phone_pvt p,
const char *  buf,
int  len,
int  frlen,
int  swap 
) [static]

Definition at line 612 of file chan_phone.c.

References ast_log(), ast_swapcopy_samples(), phone_pvt::fd, LOG_WARNING, phone_pvt::obuf, and phone_pvt::obuflen.

Referenced by phone_send_text(), and phone_write().

00613 {
00614    int res;
00615    /* Store as much of the buffer as we can, then write fixed frames */
00616    int space = sizeof(p->obuf) - p->obuflen;
00617    /* Make sure we have enough buffer space to store the frame */
00618    if (space < len)
00619       len = space;
00620    if (swap)
00621       ast_swapcopy_samples(p->obuf+p->obuflen, buf, len/2);
00622    else
00623       memcpy(p->obuf + p->obuflen, buf, len);
00624    p->obuflen += len;
00625    while(p->obuflen > frlen) {
00626       res = write(p->fd, p->obuf, frlen);
00627       if (res != frlen) {
00628          if (res < 1) {
00629 /*
00630  * Card is in non-blocking mode now and it works well now, but there are
00631  * lot of messages like this. So, this message is temporarily disabled.
00632  */
00633             return 0;
00634          } else {
00635             ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frlen);
00636          }
00637       }
00638       p->obuflen -= frlen;
00639       /* Move memory if necessary */
00640       if (p->obuflen) 
00641          memmove(p->obuf, p->obuf + frlen, p->obuflen);
00642    }
00643    return len;
00644 }

static int restart_monitor ( void   )  [static]

Definition at line 1120 of file chan_phone.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, AST_PTHREADT_NULL, AST_PTHREADT_STOP, do_monitor(), iflock, LOG_ERROR, LOG_WARNING, and monlock.

01121 {
01122    /* If we're supposed to be stopped -- stay stopped */
01123    if (monitor_thread == AST_PTHREADT_STOP)
01124       return 0;
01125    if (ast_mutex_lock(&monlock)) {
01126       ast_log(LOG_WARNING, "Unable to lock monitor\n");
01127       return -1;
01128    }
01129    if (monitor_thread == pthread_self()) {
01130       ast_mutex_unlock(&monlock);
01131       ast_log(LOG_WARNING, "Cannot kill myself\n");
01132       return -1;
01133    }
01134    if (monitor_thread != AST_PTHREADT_NULL) {
01135       if (ast_mutex_lock(&iflock)) {
01136          ast_mutex_unlock(&monlock);
01137          ast_log(LOG_WARNING, "Unable to lock the interface list\n");
01138          return -1;
01139       }
01140       monitor = 0;
01141       while (pthread_kill(monitor_thread, SIGURG) == 0)
01142          sched_yield();
01143       pthread_join(monitor_thread, NULL);
01144       ast_mutex_unlock(&iflock);
01145    }
01146    monitor = 1;
01147    /* Start a new monitor */
01148    if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
01149       ast_mutex_unlock(&monlock);
01150       ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
01151       return -1;
01152    }
01153    ast_mutex_unlock(&monlock);
01154    return 0;
01155 }

static int unload_module ( void   )  [static]

Definition at line 1337 of file chan_phone.c.

References __unload_module().

01338 {
01339    return __unload_module();
01340 }


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

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1451 of file chan_phone.c.

char cid_name[AST_MAX_EXTENSION] [static]

Definition at line 158 of file chan_phone.c.

char cid_num[AST_MAX_EXTENSION] [static]

Definition at line 157 of file chan_phone.c.

const char config[] = "phone.conf" [static]

Definition at line 92 of file chan_phone.c.

char context[AST_MAX_EXTENSION] = "default" [static]

Definition at line 95 of file chan_phone.c.

struct ast_channel_tech* cur_tech [static]

Definition at line 208 of file chan_phone.c.

Referenced by __unload_module(), load_module(), and phone_new().

int echocancel = AEC_OFF [static]

Definition at line 100 of file chan_phone.c.

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 Sat Aug 6 00:39:47 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7