Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:48:34 2009

## Asterisk developer's documentation

# chan_phone.c File Reference

Generic Linux Telephony Interface driver. More...

`#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 <linux/telephony.h>`
`#include <linux/version.h>`
`#include <linux/ixjuser.h>`
`#include "asterisk.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 "DialTone.h"`

Include dependency graph for chan_phone.c:

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 | PHONE_MAX_BUF 480
#define | QNDRV_VER 100

## Functions

static int | __unload_module (void)
| AST_MUTEX_DEFINE_STATIC (monlock)
| AST_MUTEX_DEFINE_STATIC (iflock)
| AST_MUTEX_DEFINE_STATIC (usecnt_lock)
char * | description ()
| Provides a description of the module.
static void * | do_monitor (void *data)
char * | key ()
| Returns the ASTERISK_GPL_KEY.
int | load_module ()
| Initialize the module.
static struct phone_pvt * | mkif (char *iface, int mode, int txgain, int rxgain)
static int | parse_gain_value (char *gain_type, char *value)
static int | phone_answer (struct ast_channel *ast)
static int | phone_call (struct ast_channel *ast, char *dest, int timeout)
static void | phone_check_exception (struct phone_pvt *i)
static int | phone_digit (struct ast_channel *ast, char digit)
static struct ast_frame * | phone_exception (struct ast_channel *ast)
static int | phone_fixup (struct ast_channel *old, struct ast_channel *new)
static int | phone_hangup (struct ast_channel *ast)
static void | phone_mini_packet (struct phone_pvt *i)
static struct ast_channel * | phone_new (struct phone_pvt *i, int state, char *context)
static struct ast_frame * | phone_read (struct ast_channel *ast)
static struct ast_channel * | phone_request (const char *type, int format, void *data, int *cause)
static int | phone_send_text (struct ast_channel *ast, const char *text)
static int | phone_setup (struct ast_channel *ast)
static int | phone_write (struct ast_channel *ast, struct ast_frame *frame)
static int | phone_write_buf (struct phone_pvt *p, const char *buf, int len, int frlen, int swap)
static int | restart_monitor (void)
int | unload_module (void)
| Cleanup all module structures, sockets, etc.
int | usecount ()
| Provides a usecount.

## Variables

static char | cid_name [AST_MAX_EXTENSION]
static char | cid_num [AST_MAX_EXTENSION]
static const char | config [] = "phone.conf"
static char | context [AST_MAX_EXTENSION] = "default"
static struct ast_channel_tech * | cur_tech
static const char | desc [] = "Linux Telephony API Support"
static int | echocancel = AEC_OFF
static struct phone_pvt * | iflist
static char | language [MAX_LANGUAGE] = ""
static pthread_t | monitor_thread = AST_PTHREADT_NULL
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"
static const char | type [] = "Phone"
static int | usecnt = 0

## Detailed Description

Generic Linux Telephony Interface driver.

Definition in file chan_phone.c.

## Define Documentation

#define DEFAULT_CALLER_ID "Unknown"

Definition at line 77 of file chan_phone.c.

Referenced by phone_call().

#define DEFAULT_GAIN 0x100

Definition at line 79 of file chan_phone.c.

Referenced by load_module(), and parse_gain_value().

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

Definition at line 74 of file chan_phone.c.

Referenced by phone_call().

#define MODE_DIALTONE 1

Definition at line 117 of file chan_phone.c.

Referenced by load_module(), monitor_handle_notowned(), and phone_check_exception().

#define MODE_FXO 3

Definition at line 119 of file chan_phone.c.

Referenced by load_module(), mkif(), monitor_handle_notowned(), monitor_handle_owned(), phone_answer(), phone_exception(), phone_hangup(), vpb_answer(), vpb_call(), vpb_hangup(), and vpb_new().

#define MODE_FXS 4

Definition at line 120 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 118 of file chan_phone.c.

Referenced by load_module(), monitor_handle_notowned(), and phone_check_exception().

#define PHONE_MAX_BUF 480

Definition at line 78 of file chan_phone.c.

Referenced by phone_read().

#define QNDRV_VER 100

Definition at line 64 of file chan_phone.c.

## Function Documentation

static int __unload_module | ( | void |  | ) | `[static]`

Definition at line 1236 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, phone_pvt::fd, free, iflist, LOG_WARNING, phone_pvt::next, and phone_pvt::owner.

    01237 {
    01238    struct phone_pvt *p, *pl;
    01239    /* First, take us out of the channel loop */
    01240    ast_channel_unregister(cur_tech);
    01241    if (!ast_mutex_lock(&iflock)) {
    01242       /* Hangup all interfaces if they have an owner */
    01243       p = iflist;
    01244       while(p) {
    01245          if (p->owner)
    01246             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
    01247          p = p->next;
    01248       }
    01249       iflist = NULL;
    01250       ast_mutex_unlock(&iflock);
    01251    } else {
    01252       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
    01253       return -1;
    01254    }
    01255    if (!ast_mutex_lock(&monlock)) {
    01256       if (monitor_thread > AST_PTHREADT_NULL) {
    01257          pthread_cancel(monitor_thread);
    01258          pthread_join(monitor_thread, NULL);
    01259       }
    01260       monitor_thread = AST_PTHREADT_STOP;
    01261       ast_mutex_unlock(&monlock);
    01262    } else {
    01263       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
    01264       return -1;
    01265    }
    01266
    01267    if (!ast_mutex_lock(&iflock)) {
    01268       /* Destroy all the interfaces and free their memory */
    01269       p = iflist;
    01270       while(p) {
    01271          /* Close the socket, assuming it's real */
    01272          if (p->fd > -1)
    01273             close(p->fd);
    01274          pl = p;
    01275          p = p->next;
    01276          /* Free associated memory */
    01277          free(pl);
    01278       }
    01279       iflist = NULL;
    01280       ast_mutex_unlock(&iflock);
    01281    } else {
    01282       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
    01283       return -1;
    01284    }
    01285
    01286    return 0;
    01287 }

AST_MUTEX_DEFINE_STATIC | ( | monlock |  | ) |

AST_MUTEX_DEFINE_STATIC | ( | iflock |  | ) |

AST_MUTEX_DEFINE_STATIC | ( | usecnt_lock |  | ) |

char* description | ( | void |  | ) |

Provides a description of the module.

Returns:
  a short description of your module

Definition at line 1406 of file chan_phone.c.

    01407 {
    01408    return (char *) desc;
    01409 }

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

Definition at line 960 of file chan_phone.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_select(), phone_pvt::dev, DialTone, phone_pvt::dialtone, phone_pvt::fd, iflist, LOG_ERROR, LOG_WARNING, n, phone_pvt::next, phone_pvt::owner, phone_check_exception(), and phone_mini_packet().

    00961 {
    00962    fd_set rfds, efds;
    00963    int n, res;
    00964    struct phone_pvt *i;
    00965    int tonepos = 0;
    00966    /* The tone we're playing this round */
    00967    struct timeval tv = {0,0};
    00968    int dotone;
    00969    /* This thread monitors all the frame relay interfaces which are not yet in use
    00970       (and thus do not have a separate thread) indefinitely */
    00971    /* From here on out, we die whenever asked */
    00972    if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
    00973       ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
    00974       return NULL;
    00975    }
    00976    for(;;) {
    00977       /* Don't let anybody kill us right away.  Nobody should lock the interface list
    00978          and wait for the monitor list, but the other way around is okay. */
    00979       if (ast_mutex_lock(&monlock)) {
    00980          ast_log(LOG_ERROR, "Unable to grab monitor lock\n");
    00981          return NULL;
    00982       }
    00983       /* Lock the interface list */
    00984       if (ast_mutex_lock(&iflock)) {
    00985          ast_log(LOG_ERROR, "Unable to grab interface lock\n");
    00986          ast_mutex_unlock(&monlock);
    00987          return NULL;
    00988       }
    00989       /* Build the stuff we're going to select on, that is the socket of every
    00990          phone_pvt that does not have an associated owner channel */
    00991       n = -1;
    00992       FD_ZERO(&rfds);
    00993       FD_ZERO(&efds);
    00994       i = iflist;
    00995       dotone = 0;
    00996       while(i) {
    00997          if (FD_ISSET(i->fd, &rfds))
    00998             ast_log(LOG_WARNING, "Descriptor %d appears twice (%s)?\n", i->fd, i->dev);
    00999          if (!i->owner) {
    01000             /* This needs to be watched, as it lacks an owner */
    01001             FD_SET(i->fd, &rfds);
    01002             FD_SET(i->fd, &efds);
    01003             if (i->fd > n)
    01004                n = i->fd;
    01005             if (i->dialtone) {
    01006                /* Remember we're going to have to come back and play
    01007                   more dialtones */
    01008                if (ast_tvzero(tv)) {
    01009                   /* If we're due for a dialtone, play one */
    01010                   if (write(i->fd, DialTone + tonepos, 240) != 240)
    01011                      ast_log(LOG_WARNING, "Dial tone write error\n");
    01012                }
    01013                dotone++;
    01014             }
    01015          }
    01016
    01017          i = i->next;
    01018       }
    01019       /* Okay, now that we know what to do, release the interface lock */
    01020       ast_mutex_unlock(&iflock);
    01021
    01022       /* And from now on, we're okay to be killed, so release the monitor lock as well */
    01023       ast_mutex_unlock(&monlock);
    01024
    01025       /* Wait indefinitely for something to happen */
    01026       if (dotone) {
    01027          /* If we're ready to recycle the time, set it to 30 ms */
    01028          tonepos += 240;
    01029          if (tonepos >= sizeof(DialTone))
    01030                tonepos = 0;
    01031          if (ast_tvzero(tv)) {
    01032             tv = ast_tv(30000, 0);
    01033          }
    01034          res = ast_select(n + 1, &rfds, NULL, &efds, &tv);
    01035       } else {
    01036          res = ast_select(n + 1, &rfds, NULL, &efds, NULL);
    01037          tv = ast_tv(0,0);
    01038          tonepos = 0;
    01039       }
    01040       /* Okay, select has finished.  Let's see what happened.  */
    01041       if (res < 0) {
    01042          ast_log(LOG_WARNING, "select return %d: %s\n", res, strerror(errno));
    01043          continue;
    01044       }
    01045       /* If there are no fd's changed, just continue, it's probably time
    01046          to play some more dialtones */
    01047       if (!res)
    01048          continue;
    01049       /* Alright, lock the interface list again, and let's look and see what has
    01050          happened */
    01051       if (ast_mutex_lock(&iflock)) {
    01052          ast_log(LOG_WARNING, "Unable to lock the interface list\n");
    01053          continue;
    01054       }
    01055
    01056       i = iflist;
    01057       for(; i; i=i->next) {
    01058          if (FD_ISSET(i->fd, &rfds)) {
    01059             if (i->owner) {
    01060                continue;
    01061             }
    01062             phone_mini_packet(i);
    01063          }
    01064          if (FD_ISSET(i->fd, &efds)) {
    01065             if (i->owner) {
    01066                continue;
    01067             }
    01068             phone_check_exception(i);
    01069          }
    01070       }
    01071       ast_mutex_unlock(&iflock);
    01072    }
    01073    /* Never reached */
    01074    return NULL;
    01075
    01076 }

char* key | ( | void |  | ) |

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

     char *key(void) {
             return ASTERISK_GPL_KEY;
     }

Returns:
  ASTERISK_GPL_KEY

Definition at line 1411 of file chan_phone.c.

References ASTERISK_GPL_KEY.

    01412 {
    01413    return ASTERISK_GPL_KEY;
    01414 }

int load_module | ( | void |  | ) |

Initialize the module.

This function is called at module load time. Put all code in here that needs to set up your module's hardware, software, registrations, etc.

Returns:
  This function should return 0 on success and non-zero on failure. If the module is not loaded successfully, Asterisk will call its unload_module() function.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
  int Always 0.

TE STUFF END

Definition at line 1294 of file chan_phone.c.

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

    01295 {
    01296    struct ast_config *cfg;
    01297    struct ast_variable *v;
    01298    struct phone_pvt *tmp;
    01299    int mode = MODE_IMMEDIATE;
    01300    int txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; /* default gain 1.0 */
    01301    cfg = ast_config_load(config);
    01302
    01303    /* We *must* have a config file otherwise stop immediately */
    01304    if (!cfg) {
    01305       ast_log(LOG_ERROR, "Unable to load config %s\n", config);
    01306       return -1;
    01307    }
    01308    if (ast_mutex_lock(&iflock)) {
    01309       /* It's a little silly to lock it, but we mind as well just to be sure */
    01310       ast_log(LOG_ERROR, "Unable to lock interface list???\n");
    01311       return -1;
    01312    }
    01313    v = ast_variable_browse(cfg, "interfaces");
    01314    while(v) {
    01315       /* Create the interface list */
    01316       if (!strcasecmp(v->name, "device")) {
    01317             tmp = mkif(v->value, mode, txgain, rxgain);
    01318             if (tmp) {
    01319                tmp->next = iflist;
    01320                iflist = tmp;
    01321
    01322             } else {
    01323                ast_log(LOG_ERROR, "Unable to register channel '%s'\n", v->value);
    01324                ast_config_destroy(cfg);
    01325                ast_mutex_unlock(&iflock);
    01326                __unload_module();
    01327                return -1;
    01328             }
    01329       } else if (!strcasecmp(v->name, "silencesupression")) {
    01330          silencesupression = ast_true(v->value);
    01331       } else if (!strcasecmp(v->name, "language")) {
    01332          strncpy(language, v->value, sizeof(language)-1);
    01333       } else if (!strcasecmp(v->name, "callerid")) {
    01334          ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
    01335       } else if (!strcasecmp(v->name, "mode")) {
    01336          if (!strncasecmp(v->value, "di", 2))
    01337             mode = MODE_DIALTONE;
    01338          else if (!strncasecmp(v->value, "im", 2))
    01339             mode = MODE_IMMEDIATE;
    01340          else if (!strncasecmp(v->value, "fxs", 3)) {
    01341             mode = MODE_FXS;
    01342             prefformat = 0x01ff0000; /* All non-voice */
    01343          }
    01344          else if (!strncasecmp(v->value, "fx", 2))
    01345             mode = MODE_FXO;
    01346          else
    01347             ast_log(LOG_WARNING, "Unknown mode: %s\n", v->value);
    01348       } else if (!strcasecmp(v->name, "context")) {
    01349          strncpy(context, v->value, sizeof(context)-1);
    01350       } else if (!strcasecmp(v->name, "format")) {
    01351          if (!strcasecmp(v->value, "g723.1")) {
    01352             prefformat = AST_FORMAT_G723_1;
    01353          } else if (!strcasecmp(v->value, "slinear")) {
    01354             if (mode == MODE_FXS)
    01355                 prefformat |= AST_FORMAT_SLINEAR;
    01356             else prefformat = AST_FORMAT_SLINEAR;
    01357          } else if (!strcasecmp(v->value, "ulaw")) {
    01358             prefformat = AST_FORMAT_ULAW;
    01359          } else
    01360             ast_log(LOG_WARNING, "Unknown format '%s'\n", v->value);
    01361       } else if (!strcasecmp(v->name, "echocancel")) {
    01362          if (!strcasecmp(v->value, "off")) {
    01363             echocancel = AEC_OFF;
    01364          } else if (!strcasecmp(v->value, "low")) {
    01365             echocancel = AEC_LOW;
    01366          } else if (!strcasecmp(v->value, "medium")) {
    01367             echocancel = AEC_MED;
    01368          } else if (!strcasecmp(v->value, "high")) {
    01369             echocancel = AEC_HIGH;
    01370          } else
    01371             ast_log(LOG_WARNING, "Unknown echo cancellation '%s'\n", v->value);
    01372       } else if (!strcasecmp(v->name, "txgain")) {
    01373          txgain = parse_gain_value(v->name, v->value);
    01374       } else if (!strcasecmp(v->name, "rxgain")) {
    01375          rxgain = parse_gain_value(v->name, v->value);
    01376       }
    01377       v = v->next;
    01378    }
    01379    ast_mutex_unlock(&iflock);
    01380
    01381    if (mode == MODE_FXS) {
    01382       phone_tech_fxs.capabilities = prefformat;
    01383       cur_tech = &phone_tech_fxs;
    01384    } else
    01385       cur_tech = (struct ast_channel_tech *) &phone_tech;
    01386
    01387    /* Make sure we can register our Adtranphone channel type */
    01388
    01389    if (ast_channel_register(cur_tech)) {
    01390       ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
    01391       ast_config_destroy(cfg);
    01392       __unload_module();
    01393       return -1;
    01394    }
    01395    ast_config_destroy(cfg);
    01396    /* And start the monitor for the first time */
    01397    restart_monitor();
    01398    return 0;
    01399 }

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

Definition at line 1112 of file chan_phone.c.

References ast_log(), phone_pvt::cid_name, phone_pvt::cid_num, phone_pvt::context, phone_pvt::cpt, phone_pvt::dev, phone_pvt::dialtone, 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.

    01113 {
    01114    /* Make a phone_pvt structure for this interface */
    01115    struct phone_pvt *tmp;
    01116    int flags;
    01117
    01118    tmp = malloc(sizeof(struct phone_pvt));
    01119    if (tmp) {
    01120       tmp->fd = open(iface, O_RDWR);
    01121       if (tmp->fd < 0) {
    01122          ast_log(LOG_WARNING, "Unable to open '%s'\n", iface);
    01123          free(tmp);
    01124          return NULL;
    01125       }
    01126       if (mode == MODE_FXO) {
    01127          if (ioctl(tmp->fd, IXJCTL_PORT, PORT_PSTN))
    01128             ast_log(LOG_DEBUG, "Unable to set port to PSTN\n");
    01129       } else {
    01130          if (ioctl(tmp->fd, IXJCTL_PORT, PORT_POTS))
    01131              if (mode != MODE_FXS)
    01132                   ast_log(LOG_DEBUG, "Unable to set port to POTS\n");
    01133       }
    01134       ioctl(tmp->fd, PHONE_PLAY_STOP);
    01135       ioctl(tmp->fd, PHONE_REC_STOP);
    01136       ioctl(tmp->fd, PHONE_RING_STOP);
    01137       ioctl(tmp->fd, PHONE_CPT_STOP);
    01138       if (ioctl(tmp->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK))
    01139          ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",iface, strerror(errno));
    01140       if (echocancel != AEC_OFF)
    01141          ioctl(tmp->fd, IXJCTL_AEC_START, echocancel);
    01142       if (silencesupression)
    01143          tmp->silencesupression = 1;
    01144 #ifdef PHONE_VAD
    01145       ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression);
    01146 #endif
    01147       tmp->mode = mode;
    01148       flags = fcntl(tmp->fd, F_GETFL);
    01149       fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK);
    01150       tmp->owner = NULL;
    01151       tmp->lastformat = -1;
    01152       tmp->lastinput = -1;
    01153       tmp->ministate = 0;
    01154       memset(tmp->ext, 0, sizeof(tmp->ext));
    01155       strncpy(tmp->language, language, sizeof(tmp->language)-1);
    01156       strncpy(tmp->dev, iface, sizeof(tmp->dev)-1);
    01157       strncpy(tmp->context, context, sizeof(tmp->context)-1);
    01158       tmp->next = NULL;
    01159       tmp->obuflen = 0;
    01160       tmp->dialtone = 0;
    01161       tmp->cpt = 0;
    01162       strncpy(tmp->cid_num, cid_num, sizeof(tmp->cid_num)-1);
    01163       strncpy(tmp->cid_name, cid_name, sizeof(tmp->cid_name)-1);
    01164       tmp->txgain = txgain;
    01165       ioctl(tmp->fd, PHONE_PLAY_VOLUME, tmp->txgain);
    01166       tmp->rxgain = rxgain;
    01167       ioctl(tmp->fd, PHONE_REC_VOLUME, tmp->rxgain);
    01168    }
    01169    return tmp;
    01170 }

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

Definition at line 1214 of file chan_phone.c.

References ast_log(), DEFAULT_GAIN, and LOG_ERROR.

Referenced by load_module().

    01215 {
    01216    float gain;
    01217
    01218    /* try to scan number */
    01219    if (sscanf(value, "%30f", &gain) != 1)
    01220    {
    01221       ast_log(LOG_ERROR, "Invalid %s value '%s' in '%s' config\n",
    01222          value, gain_type, config);
    01223       return DEFAULT_GAIN;
    01224    }
    01225
    01226    /* multiplicate gain by 1.0 gain value */
    01227    gain = gain * (float)DEFAULT_GAIN;
    01228
    01229    /* percentage? */
    01230    if (value[strlen(value) - 1] == '%')
    01231       return (int)(gain / (float)100);
    01232
    01233    return (int)gain;
    01234 }

static int phone_answer | ( | struct ast_channel * | ast | ) | `[static]`

Definition at line 414 of file chan_phone.c.

References ast_log(), ast_setstate(), AST_STATE_UP, 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.

    00415 {
    00416    struct phone_pvt *p;
    00417    p = ast->tech_pvt;
    00418    /* In case it's a LineJack, take it off hook */
    00419    if (p->mode == MODE_FXO) {
    00420       if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_OFF_HOOK))
    00421          ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n", ast->name, strerror(errno));
    00422       else
    00423          ast_log(LOG_DEBUG, "Took linejack off hook\n");
    00424    }
    00425    phone_setup(ast);
    00426    if (option_debug)
    00427       ast_log(LOG_DEBUG, "phone_answer(%s)\n", ast->name);
    00428    ast->rings = 0;
    00429    ast_setstate(ast, AST_STATE_UP);
    00430    return 0;
    00431 }

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

Definition at line 245 of file chan_phone.c.

References ast_channel::_state, AST_CONTROL_RINGING, 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(), and ast_channel::tech_pvt.

    00246 {
    00247    struct phone_pvt *p;
    00248
    00249    PHONE_CID cid;
    00250    time_t UtcTime;
    00251    struct tm tm;
    00252    int start;
    00253
    00254    time(&UtcTime);
    00255    localtime_r(&UtcTime,&tm);
    00256
    00257    memset(&cid, 0, sizeof(PHONE_CID));
    00258    if(&tm != NULL) {
    00259       snprintf(cid.month, sizeof(cid.month), "%02d",(tm.tm_mon + 1));
    00260       snprintf(cid.day, sizeof(cid.day),     "%02d", tm.tm_mday);
    00261       snprintf(cid.hour, sizeof(cid.hour),   "%02d", tm.tm_hour);
    00262       snprintf(cid.min, sizeof(cid.min),     "%02d", tm.tm_min);
    00263    }
    00264    /* the standard format of ast->callerid is:  "name" <number>, but not always complete */
    00265    if (ast_strlen_zero(ast->cid.cid_name))
    00266       strncpy(cid.name, DEFAULT_CALLER_ID, sizeof(cid.name) - 1);
    00267    else
    00268       strncpy(cid.name, ast->cid.cid_name, sizeof(cid.name) - 1);
    00269
    00270    if (ast->cid.cid_num)
    00271       strncpy(cid.number, ast->cid.cid_num, sizeof(cid.number) - 1);
    00272
    00273    p = ast->tech_pvt;
    00274
    00275    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
    00276       ast_log(LOG_WARNING, "phone_call called on %s, neither down nor reserved\n", ast->name);
    00277       return -1;
    00278    }
    00279    if (option_debug)
    00280       ast_log(LOG_DEBUG, "Ringing %s on %s (%d)\n", dest, ast->name, ast->fds[0]);
    00281
    00282    start = IXJ_PHONE_RING_START(cid);
    00283    if (start == -1)
    00284       return -1;
    00285
    00286    if (p->mode == MODE_FXS) {
    00287       char *digit = strchr(dest, '/');
    00288       if (digit)
    00289       {
    00290         digit++;
    00291         while (*digit)
    00292           phone_digit(ast, *digit++);
    00293       }
    00294    }
    00295
    00296    ast_setstate(ast, AST_STATE_RINGING);
    00297    ast_queue_control(ast, AST_CONTROL_RINGING);
    00298    return 0;
    00299 }

static void phone_check_exception | ( | struct phone_pvt * | i | ) | `[static]`

Definition at line 866 of file chan_phone.c.

References ast_canmatch_extension(), ast_exists_extension(), ast_log(), AST_MAX_EXTENSION, ast_mutex_lock(), ast_mutex_unlock(), AST_STATE_RING, ast_update_use_count(), 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, option_debug, phone_new(), and usecnt_lock.

Referenced by do_monitor().

    00867 {
    00868    int offhook=0;
    00869    char digit[2] = {0 , 0};
    00870    union telephony_exception phonee;
    00871    /* XXX Do something XXX */
    00872 #if 0
    00873    ast_log(LOG_DEBUG, "Exception!\n");
    00874 #endif
    00875    phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION);
    00876    if (phonee.bits.dtmf_ready)  {
    00877       digit[0] = ioctl(i->fd, PHONE_GET_DTMF_ASCII);
    00878       if (i->mode == MODE_DIALTONE || i->mode == MODE_FXS) {
    00879          ioctl(i->fd, PHONE_PLAY_STOP);
    00880          ioctl(i->fd, PHONE_REC_STOP);
    00881          ioctl(i->fd, PHONE_CPT_STOP);
    00882          i->dialtone = 0;
    00883          if (strlen(i->ext) < AST_MAX_EXTENSION - 1)
    00884             strncat(i->ext, digit, sizeof(i->ext) - strlen(i->ext) - 1);
    00885          if ((i->mode != MODE_FXS ||
    00886               !(phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION)) ||
    00887               !phonee.bits.dtmf_ready) &&
    00888              ast_exists_extension(NULL, i->context, i->ext, 1, i->cid_num)) {
    00889             /* It's a valid extension in its context, get moving! */
    00890             phone_new(i, AST_STATE_RING, i->context);
    00891             /* No need to restart monitor, we are the monitor */
    00892          } else if (!ast_canmatch_extension(NULL, i->context, i->ext, 1, i->cid_num)) {
    00893             /* There is nothing in the specified extension that can match anymore.
    00894                Try the default */
    00895             if (ast_exists_extension(NULL, "default", i->ext, 1, i->cid_num)) {
    00896                /* Check the default, too... */
    00897                phone_new(i, AST_STATE_RING, "default");
    00898                /* XXX This should probably be justified better XXX */
    00899             }  else if (!ast_canmatch_extension(NULL, "default", i->ext, 1, i->cid_num)) {
    00900                /* It's not a valid extension, give a busy signal */
    00901                if (option_debug)
    00902                   ast_log(LOG_DEBUG, "%s can't match anything in %s or default\n", i->ext, i->context);
    00903                ioctl(i->fd, PHONE_BUSY);
    00904                i->cpt = 1;
    00905             }
    00906          }
    00907 #if 0
    00908          ast_verbose("Extension is %s\n", i->ext);
    00909 #endif
    00910       }
    00911    }
    00912    if (phonee.bits.hookstate) {
    00913       offhook = ioctl(i->fd, PHONE_HOOKSTATE);
    00914       if (offhook) {
    00915          if (i->mode == MODE_IMMEDIATE) {
    00916             phone_new(i, AST_STATE_RING, i->context);
    00917          } else if (i->mode == MODE_DIALTONE) {
    00918             ast_mutex_lock(&usecnt_lock);
    00919             usecnt++;
    00920             ast_mutex_unlock(&usecnt_lock);
    00921             ast_update_use_count();
    00922             /* Reset the extension */
    00923             i->ext[0] = '\0';
    00924             /* Play the dialtone */
    00925             i->dialtone++;
    00926             ioctl(i->fd, PHONE_PLAY_STOP);
    00927             ioctl(i->fd, PHONE_PLAY_CODEC, ULAW);
    00928             ioctl(i->fd, PHONE_PLAY_START);
    00929             i->lastformat = -1;
    00930          }
    00931       } else {
    00932          if (i->dialtone) {
    00933             ast_mutex_lock(&usecnt_lock);
    00934             usecnt--;
    00935             ast_mutex_unlock(&usecnt_lock);
    00936             ast_update_use_count();
    00937          }
    00938          memset(i->ext, 0, sizeof(i->ext));
    00939          if (i->cpt)
    00940          {
    00941             ioctl(i->fd, PHONE_CPT_STOP);
    00942             i->cpt = 0;
    00943          }
    00944          ioctl(i->fd, PHONE_PLAY_STOP);
    00945          ioctl(i->fd, PHONE_REC_STOP);
    00946          i->dialtone = 0;
    00947          i->lastformat = -1;
    00948       }
    00949    }
    00950    if (phonee.bits.pstn_ring) {
    00951       ast_verbose("Unit is ringing\n");
    00952       phone_new(i, AST_STATE_RING, i->context);
    00953    }
    00954    if (phonee.bits.caller_id)
    00955       ast_verbose("We have caller ID\n");
    00956
    00957
    00958 }

static int phone_digit | ( | struct ast_channel * | ast,
|  | char | digit |
| ) |  |  | `[static]`

Definition at line 203 of file chan_phone.c.

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

Referenced by phone_call().

    00204 {
    00205    struct phone_pvt *p;
    00206    int outdigit;
    00207    p = ast->tech_pvt;
    00208    ast_log(LOG_NOTICE, "Dialed %c\n", digit);
    00209    switch(digit) {
    00210    case '0':
    00211    case '1':
    00212    case '2':
    00213    case '3':
    00214    case '4':
    00215    case '5':
    00216    case '6':
    00217    case '7':
    00218    case '8':
    00219    case '9':
    00220       outdigit = digit - '0';
    00221       break;
    00222    case '*':
    00223       outdigit = 11;
    00224       break;
    00225    case '#':
    00226       outdigit = 12;
    00227       break;
    00228    case 'f':   /*flash*/
    00229    case 'F':
    00230       ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
    00231       usleep(320000);
    00232       ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
    00233       p->lastformat = -1;
    00234       return 0;
    00235    default:
    00236       ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit);
    00237       return -1;
    00238    }
    00239    ast_log(LOG_NOTICE, "Dialed %d\n", outdigit);
    00240    ioctl(p->fd, PHONE_PLAY_TONE, outdigit);
    00241    p->lastformat = -1;
    00242    return 0;
    00243 }

static struct ast_frame * phone_exception | ( | struct ast_channel * | ast | ) | `[static, read]`

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

    00448 {
    00449    int res;
    00450    union telephony_exception phonee;
    00451    struct phone_pvt *p = ast->tech_pvt;
    00452    char digit;
    00453
    00454    /* Some nice norms */
    00455    p->fr.datalen = 0;
    00456    p->fr.samples = 0;
    00457    p->fr.data =  NULL;
    00458    p->fr.src = type;
    00459    p->fr.offset = 0;
    00460    p->fr.mallocd=0;
    00461    p->fr.delivery = ast_tv(0,0);
    00462
    00463    phonee.bytes = ioctl(p->fd, PHONE_EXCEPTION);
    00464    if (phonee.bits.dtmf_ready)  {
    00465       if (option_debug)
    00466          ast_log(LOG_DEBUG, "phone_exception(): DTMF\n");
    00467
    00468       /* We've got a digit -- Just handle this nicely and easily */
    00469       digit =  ioctl(p->fd, PHONE_GET_DTMF_ASCII);
    00470       p->fr.subclass = digit;
    00471       p->fr.frametype = AST_FRAME_DTMF;
    00472       return &p->fr;
    00473    }
    00474    if (phonee.bits.hookstate) {
    00475       if (option_debug)
    00476          ast_log(LOG_DEBUG, "Hookstate changed\n");
    00477       res = ioctl(p->fd, PHONE_HOOKSTATE);
    00478       /* See if we've gone on hook, if so, notify by returning NULL */
    00479       if (option_debug)
    00480          ast_log(LOG_DEBUG, "New hookstate: %d\n", res);
    00481       if (!res && (p->mode != MODE_FXO))
    00482          return NULL;
    00483       else {
    00484          if (ast->_state == AST_STATE_RINGING) {
    00485             /* They've picked up the phone */
    00486             p->fr.frametype = AST_FRAME_CONTROL;
    00487             p->fr.subclass = AST_CONTROL_ANSWER;
    00488             phone_setup(ast);
    00489             ast_setstate(ast, AST_STATE_UP);
    00490             return &p->fr;
    00491          }  else
    00492             ast_log(LOG_WARNING, "Got off hook in weird state %d\n", ast->_state);
    00493       }
    00494    }
    00495 #if 1
    00496    if (phonee.bits.pstn_ring)
    00497       ast_verbose("Unit is ringing\n");
    00498    if (phonee.bits.caller_id) {
    00499       ast_verbose("We have caller ID\n");
    00500    }
    00501    if (phonee.bits.pstn_wink)
    00502       ast_verbose("Detected Wink\n");
    00503 #endif
    00504    /* Strange -- nothing there.. */
    00505    p->fr.frametype = AST_FRAME_NULL;
    00506    p->fr.subclass = 0;
    00507    return &p->fr;
    00508 }

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

Definition at line 195 of file chan_phone.c.

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

    00196 {
    00197    struct phone_pvt *pvt = old->tech_pvt;
    00198    if (pvt && pvt->owner == old)
    00199       pvt->owner = new;
    00200    return 0;
    00201 }

static int phone_hangup | ( | struct ast_channel * | ast | ) | `[static]`

Definition at line 301 of file chan_phone.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_setstate(), AST_STATE_DOWN, ast_update_use_count(), ast_verbose(), phone_pvt::cpt, phone_pvt::dialtone, 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, usecnt_lock, and VERBOSE_PREFIX_3.

    00302 {
    00303    struct phone_pvt *p;
    00304    p = ast->tech_pvt;
    00305    if (option_debug)
    00306       ast_log(LOG_DEBUG, "phone_hangup(%s)\n", ast->name);
    00307    if (!ast->tech_pvt) {
    00308       ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
    00309       return 0;
    00310    }
    00311    /* XXX Is there anything we can do to really hang up except stop recording? */
    00312    ast_setstate(ast, AST_STATE_DOWN);
    00313    if (ioctl(p->fd, PHONE_REC_STOP))
    00314       ast_log(LOG_WARNING, "Failed to stop recording\n");
    00315    if (ioctl(p->fd, PHONE_PLAY_STOP))
    00316       ast_log(LOG_WARNING, "Failed to stop playing\n");
    00317    if (ioctl(p->fd, PHONE_RING_STOP))
    00318       ast_log(LOG_WARNING, "Failed to stop ringing\n");
    00319    if (ioctl(p->fd, PHONE_CPT_STOP))
    00320       ast_log(LOG_WARNING, "Failed to stop sounds\n");
    00321
    00322    /* If it's an FXO, hang them up */
    00323    if (p->mode == MODE_FXO) {
    00324       if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK))
    00325          ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",ast->name, strerror(errno));
    00326    }
    00327
    00328    /* If they're off hook, give a busy signal */
    00329    if (ioctl(p->fd, PHONE_HOOKSTATE)) {
    00330       if (option_debug)
    00331          ast_log(LOG_DEBUG, "Got hunghup, giving busy signal\n");
    00332       ioctl(p->fd, PHONE_BUSY);
    00333       p->cpt = 1;
    00334    }
    00335    p->lastformat = -1;
    00336    p->lastinput = -1;
    00337    p->ministate = 0;
    00338    p->obuflen = 0;
    00339    p->dialtone = 0;
    00340    memset(p->ext, 0, sizeof(p->ext));
    00341    ((struct phone_pvt *)(ast->tech_pvt))->owner = NULL;
    00342    ast_mutex_lock(&usecnt_lock);
    00343    usecnt--;
    00344    if (usecnt < 0)
    00345       ast_log(LOG_WARNING, "Usecnt < 0???\n");
    00346    ast_mutex_unlock(&usecnt_lock);
    00347    ast_update_use_count();
    00348    if (option_verbose > 2)
    00349       ast_verbose( VERBOSE_PREFIX_3 "Hungup '%s'\n", ast->name);
    00350    ast->tech_pvt = NULL;
    00351    ast_setstate(ast, AST_STATE_DOWN);
    00352    restart_monitor();
    00353    return 0;
    00354 }

static void phone_mini_packet | ( | struct phone_pvt * | i | ) | `[static]`

Definition at line 854 of file chan_phone.c.

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

Referenced by do_monitor().

    00855 {
    00856    int res;
    00857    char buf[1024];
    00858    /* Ignore stuff we read... */
    00859    res = read(i->fd, buf, sizeof(buf));
    00860    if (res < 1) {
    00861       ast_log(LOG_WARNING, "Read returned %d: %s\n", res, strerror(errno));
    00862       return;
    00863    }
    00864 }

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

Definition at line 787 of file chan_phone.c.

References ast_channel_alloc(), AST_FORMAT_SLINEAR, ast_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RING, ast_strlen_zero(), ast_update_use_count(), phone_pvt::cid_name, phone_pvt::cid_num, phone_pvt::cpt, phone_pvt::dev, phone_pvt::ext, phone_pvt::fd, phone_pvt::language, LOG_WARNING, phone_pvt::mode, MODE_FXS, phone_pvt::owner, strdup, and usecnt_lock.

Referenced by phone_check_exception(), and phone_request().

    00788 {
    00789    struct ast_channel *tmp;
    00790    struct phone_codec_data codec;
    00791    tmp = ast_channel_alloc(1);
    00792    if (tmp) {
    00793       tmp->tech = cur_tech;
    00794       snprintf(tmp->name, sizeof(tmp->name), "Phone/%s", i->dev + 5);
    00795       tmp->type = type;
    00796       tmp->fds[0] = i->fd;
    00797       /* XXX Switching formats silently causes kernel panics XXX */
    00798       if (i->mode == MODE_FXS &&
    00799           ioctl(i->fd, PHONE_QUERY_CODEC, &codec) == 0) {
    00800          if (codec.type == LINEAR16)
    00801             tmp->nativeformats =
    00802             tmp->rawreadformat =
    00803             tmp->rawwriteformat =
    00804             AST_FORMAT_SLINEAR;
    00805          else {
    00806             tmp->nativeformats =
    00807             tmp->rawreadformat =
    00808             tmp->rawwriteformat =
    00809             prefformat & ~AST_FORMAT_SLINEAR;
    00810          }
    00811       }
    00812       else {
    00813          tmp->nativeformats = prefformat;
    00814          tmp->rawreadformat = prefformat;
    00815          tmp->rawwriteformat = prefformat;
    00816       }
    00817       ast_setstate(tmp, state);
    00818       if (state == AST_STATE_RING)
    00819          tmp->rings = 1;
    00820       tmp->tech_pvt = i;
    00821       strncpy(tmp->context, context, sizeof(tmp->context)-1);
    00822       if (!ast_strlen_zero(i->ext))
    00823          strncpy(tmp->exten, i->ext, sizeof(tmp->exten)-1);
    00824       else
    00825          strncpy(tmp->exten, "s",  sizeof(tmp->exten) - 1);
    00826       if (!ast_strlen_zero(i->language))
    00827          strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
    00828
    00829       if (!ast_strlen_zero(i->cid_num))
    00830          tmp->cid.cid_num = strdup(i->cid_num);
    00831       if (!ast_strlen_zero(i->cid_name))
    00832          tmp->cid.cid_name = strdup(i->cid_name);
    00833
    00834       i->owner = tmp;
    00835       ast_mutex_lock(&usecnt_lock);
    00836       usecnt++;
    00837       ast_mutex_unlock(&usecnt_lock);
    00838       ast_update_use_count();
    00839       if (state != AST_STATE_DOWN) {
    00840          if (state == AST_STATE_RING) {
    00841             ioctl(tmp->fds[0], PHONE_RINGBACK);
    00842             i->cpt = 1;
    00843          }
    00844          if (ast_pbx_start(tmp)) {
    00845             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
    00846             ast_hangup(tmp);
    00847          }
    00848       }
    00849    } else
    00850       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
    00851    return tmp;
    00852 }

static struct ast_frame * phone_read | ( | struct ast_channel * | ast | ) | `[static, read]`

Definition at line 510 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(), phone_pvt::buf, CHECK_BLOCKING, ast_frame::data, ast_frame::datalen, ast_frame::delivery, 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.

    00511 {
    00512    int res;
    00513    struct phone_pvt *p = ast->tech_pvt;
    00514
    00515
    00516    /* Some nice norms */
    00517    p->fr.datalen = 0;
    00518    p->fr.samples = 0;
    00519    p->fr.data =  NULL;
    00520    p->fr.src = type;
    00521    p->fr.offset = 0;
    00522    p->fr.mallocd=0;
    00523    p->fr.delivery = ast_tv(0,0);
    00524
    00525    /* Try to read some data... */
    00526    CHECK_BLOCKING(ast);
    00527    res = read(p->fd, p->buf, PHONE_MAX_BUF);
    00528    ast_clear_flag(ast, AST_FLAG_BLOCKING);
    00529    if (res < 0) {
    00530 #if 0
    00531       if (errno == EAGAIN) {
    00532          ast_log(LOG_WARNING, "Null frame received\n");
    00533          p->fr.frametype = AST_FRAME_NULL;
    00534          p->fr.subclass = 0;
    00535          return &p->fr;
    00536       }
    00537 #endif
    00538       ast_log(LOG_WARNING, "Error reading: %s\n", strerror(errno));
    00539       return NULL;
    00540    }
    00541    p->fr.data = p->buf;
    00542    if (p->mode != MODE_FXS)
    00543    switch(p->buf[0] & 0x3) {
    00544    case '0':
    00545    case '1':
    00546       /* Normal */
    00547       break;
    00548    case '2':
    00549    case '3':
    00550       /* VAD/CNG, only send two words */
    00551       res = 4;
    00552       break;
    00553    }
    00554    p->fr.samples = 240;
    00555    p->fr.datalen = res;
    00556    p->fr.frametype = p->lastinput <= AST_FORMAT_MAX_AUDIO ?
    00557                           AST_FRAME_VOICE :
    00558            p->lastinput <= AST_FORMAT_PNG ? AST_FRAME_IMAGE
    00559            : AST_FRAME_VIDEO;
    00560    p->fr.subclass = p->lastinput;
    00561    p->fr.offset = AST_FRIENDLY_OFFSET;
    00562    /* Byteswap from little-endian to native-endian */
    00563    if (p->fr.subclass == AST_FORMAT_SLINEAR)
    00564       ast_frame_byteswap_le(&p->fr);
    00565    return &p->fr;
    00566 }

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

Definition at line 1172 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, LOG_ERROR, LOG_NOTICE, phone_pvt::mode, MODE_FXS, name, phone_pvt::next, phone_pvt::owner, phone_new(), and restart_monitor().

    01173 {
    01174    int oldformat;
    01175    struct phone_pvt *p;
    01176    struct ast_channel *tmp = NULL;
    01177    char *name = data;
    01178
    01179    /* Search for an unowned channel */
    01180    if (ast_mutex_lock(&iflock)) {
    01181       ast_log(LOG_ERROR, "Unable to lock interface list???\n");
    01182       return NULL;
    01183    }
    01184    p = iflist;
    01185    while(p) {
    01186       if (p->mode == MODE_FXS ||
    01187           format & (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW)) {
    01188           size_t length = strlen(p->dev + 5);
    01189          if (strncmp(name, p->dev + 5, length) == 0 &&
    01190              !isalnum(name[length])) {
    01191              if (!p->owner) {
    01192                      tmp = phone_new(p, AST_STATE_DOWN, p->context);
    01193                      break;
    01194                 } else
    01195                      *cause = AST_CAUSE_BUSY;
    01196             }
    01197       }
    01198       p = p->next;
    01199    }
    01200    ast_mutex_unlock(&iflock);
    01201    restart_monitor();
    01202    if (tmp == NULL) {
    01203       oldformat = format;
    01204       format &= (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW);
    01205       if (!format) {
    01206          ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat);
    01207          return NULL;
    01208       }
    01209    }
    01210    return tmp;
    01211 }

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

Definition at line 602 of file chan_phone.c.

References phone_write_buf(), and ast_channel::tech_pvt.

    00603 {
    00604     int length = strlen(text);
    00605     return phone_write_buf(ast->tech_pvt, text, length, length, 0) ==
    00606            length ? 0 : -1;
    00607 }

static int phone_setup | ( | struct ast_channel * | ast | ) | `[static]`

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

    00357 {
    00358    struct phone_pvt *p;
    00359    p = ast->tech_pvt;
    00360    ioctl(p->fd, PHONE_CPT_STOP);
    00361    /* Nothing to answering really, just start recording */
    00362    if (ast->rawreadformat == AST_FORMAT_G723_1) {
    00363       /* Prefer g723 */
    00364       ioctl(p->fd, PHONE_REC_STOP);
    00365       if (p->lastinput != AST_FORMAT_G723_1) {
    00366          p->lastinput = AST_FORMAT_G723_1;
    00367          if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
    00368             ast_log(LOG_WARNING, "Failed to set codec to g723.1\n");
    00369             return -1;
    00370          }
    00371       }
    00372    } else if (ast->rawreadformat == AST_FORMAT_SLINEAR) {
    00373       ioctl(p->fd, PHONE_REC_STOP);
    00374       if (p->lastinput != AST_FORMAT_SLINEAR) {
    00375          p->lastinput = AST_FORMAT_SLINEAR;
    00376          if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
    00377             ast_log(LOG_WARNING, "Failed to set codec to signed linear 16\n");
    00378             return -1;
    00379          }
    00380       }
    00381    } else if (ast->rawreadformat == AST_FORMAT_ULAW) {
    00382       ioctl(p->fd, PHONE_REC_STOP);
    00383       if (p->lastinput != AST_FORMAT_ULAW) {
    00384          p->lastinput = AST_FORMAT_ULAW;
    00385          if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) {
    00386             ast_log(LOG_WARNING, "Failed to set codec to uLaw\n");
    00387             return -1;
    00388          }
    00389       }
    00390    } else if (p->mode == MODE_FXS) {
    00391       ioctl(p->fd, PHONE_REC_STOP);
    00392       if (p->lastinput != ast->rawreadformat) {
    00393          p->lastinput = ast->rawreadformat;
    00394          if (ioctl(p->fd, PHONE_REC_CODEC, ast->rawreadformat)) {
    00395             ast_log(LOG_WARNING, "Failed to set codec to %d\n",
    00396                ast->rawreadformat);
    00397             return -1;
    00398          }
    00399       }
    00400    } else {
    00401       ast_log(LOG_WARNING, "Can't do format %s\n", ast_getformatname(ast->rawreadformat));
    00402       return -1;
    00403    }
    00404    if (ioctl(p->fd, PHONE_REC_START)) {
    00405       ast_log(LOG_WARNING, "Failed to start recording\n");
    00406       return -1;
    00407    }
    00408    /* set the DTMF times (the default is too short) */
    00409    ioctl(p->fd, PHONE_SET_TONE_ON_TIME, 300);
    00410    ioctl(p->fd, PHONE_SET_TONE_OFF_TIME, 200);
    00411    return 0;
    00412 }

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

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

    00610 {
    00611    struct phone_pvt *p = ast->tech_pvt;
    00612    int res;
    00613    int maxfr=0;
    00614    char *pos;
    00615    int sofar;
    00616    int expected;
    00617    int codecset = 0;
    00618    char tmpbuf[4];
    00619    /* Write a frame of (presumably voice) data */
    00620    if (frame->frametype != AST_FRAME_VOICE && p->mode != MODE_FXS) {
    00621       if (frame->frametype != AST_FRAME_IMAGE)
    00622          ast_log(LOG_WARNING, "Don't know what to do with  frame type '%d'\n", frame->frametype);
    00623       return 0;
    00624    }
    00625    if (!(frame->subclass &
    00626       (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW)) &&
    00627        p->mode != MODE_FXS) {
    00628       ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
    00629       return -1;
    00630    }
    00631 #if 0
    00632    /* If we're not in up mode, go into up mode now */
    00633    if (ast->_state != AST_STATE_UP) {
    00634       ast_setstate(ast, AST_STATE_UP);
    00635       phone_setup(ast);
    00636    }
    00637 #else
    00638    if (ast->_state != AST_STATE_UP) {
    00639       /* Don't try tos end audio on-hook */
    00640       return 0;
    00641    }
    00642 #endif
    00643    if (frame->subclass == AST_FORMAT_G723_1) {
    00644       if (p->lastformat != AST_FORMAT_G723_1) {
    00645          ioctl(p->fd, PHONE_PLAY_STOP);
    00646          ioctl(p->fd, PHONE_REC_STOP);
    00647          if (ioctl(p->fd, PHONE_PLAY_CODEC, G723_63)) {
    00648             ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
    00649             return -1;
    00650          }
    00651          if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
    00652             ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
    00653             return -1;
    00654          }
    00655          p->lastformat = AST_FORMAT_G723_1;
    00656          p->lastinput = AST_FORMAT_G723_1;
    00657          /* Reset output buffer */
    00658          p->obuflen = 0;
    00659          codecset = 1;
    00660       }
    00661       if (frame->datalen > 24) {
    00662          ast_log(LOG_WARNING, "Frame size too large for G.723.1 (%d bytes)\n", frame->datalen);
    00663          return -1;
    00664       }
    00665       maxfr = 24;
    00666    } else if (frame->subclass == AST_FORMAT_SLINEAR) {
    00667       if (p->lastformat != AST_FORMAT_SLINEAR) {
    00668          ioctl(p->fd, PHONE_PLAY_STOP);
    00669          ioctl(p->fd, PHONE_REC_STOP);
    00670          if (ioctl(p->fd, PHONE_PLAY_CODEC, LINEAR16)) {
    00671             ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
    00672             return -1;
    00673          }
    00674          if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
    00675             ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
    00676             return -1;
    00677          }
    00678          p->lastformat = AST_FORMAT_SLINEAR;
    00679          p->lastinput = AST_FORMAT_SLINEAR;
    00680          codecset = 1;
    00681          /* Reset output buffer */
    00682          p->obuflen = 0;
    00683       }
    00684       maxfr = 480;
    00685    } else if (frame->subclass == AST_FORMAT_ULAW) {
    00686       if (p->lastformat != AST_FORMAT_ULAW) {
    00687          ioctl(p->fd, PHONE_PLAY_STOP);
    00688          ioctl(p->fd, PHONE_REC_STOP);
    00689          if (ioctl(p->fd, PHONE_PLAY_CODEC, ULAW)) {
    00690             ast_log(LOG_WARNING, "Unable to set uLaw mode\n");
    00691             return -1;
    00692          }
    00693          if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) {
    00694             ast_log(LOG_WARNING, "Unable to set uLaw mode\n");
    00695             return -1;
    00696          }
    00697          p->lastformat = AST_FORMAT_ULAW;
    00698          p->lastinput = AST_FORMAT_ULAW;
    00699          codecset = 1;
    00700          /* Reset output buffer */
    00701          p->obuflen = 0;
    00702       }
    00703       maxfr = 240;
    00704    } else {
    00705       if (p->lastformat != frame->subclass) {
    00706          ioctl(p->fd, PHONE_PLAY_STOP);
    00707          ioctl(p->fd, PHONE_REC_STOP);
    00708          if (ioctl(p->fd, PHONE_PLAY_CODEC, frame->subclass)) {
    00709             ast_log(LOG_WARNING, "Unable to set %d mode\n",
    00710                frame->subclass);
    00711             return -1;
    00712          }
    00713          if (ioctl(p->fd, PHONE_REC_CODEC, frame->subclass)) {
    00714             ast_log(LOG_WARNING, "Unable to set %d mode\n",
    00715                frame->subclass);
    00716             return -1;
    00717          }
    00718          p->lastformat = frame->subclass;
    00719          p->lastinput = frame->subclass;
    00720          codecset = 1;
    00721          /* Reset output buffer */
    00722          p->obuflen = 0;
    00723       }
    00724       maxfr = 480;
    00725    }
    00726    if (codecset) {
    00727       ioctl(p->fd, PHONE_REC_DEPTH, 3);
    00728       ioctl(p->fd, PHONE_PLAY_DEPTH, 3);
    00729       if (ioctl(p->fd, PHONE_PLAY_START)) {
    00730          ast_log(LOG_WARNING, "Failed to start playback\n");
    00731          return -1;
    00732       }
    00733       if (ioctl(p->fd, PHONE_REC_START)) {
    00734          ast_log(LOG_WARNING, "Failed to start recording\n");
    00735          return -1;
    00736       }
    00737    }
    00738    /* If we get here, we have a frame of Appropriate data */
    00739    sofar = 0;
    00740    pos = frame->data;
    00741    while(sofar < frame->datalen) {
    00742       /* Write in no more than maxfr sized frames */
    00743       expected = frame->datalen - sofar;
    00744       if (maxfr < expected)
    00745          expected = maxfr;
    00746       /* XXX Internet Phone Jack does not handle the 4-byte VAD frame properly! XXX
    00747          we have to pad it to 24 bytes still.  */
    00748       if (frame->datalen == 4) {
    00749          if (p->silencesupression) {
    00750             memset(tmpbuf + 4, 0, sizeof(tmpbuf) - 4);
    00751             memcpy(tmpbuf, frame->data, 4);
    00752             expected = 24;
    00753             res = phone_write_buf(p, tmpbuf, expected, maxfr, 0);
    00754          }
    00755          res = 4;
    00756          expected=4;
    00757       } else {
    00758          int swap = 0;
    00759 #if __BYTE_ORDER == __BIG_ENDIAN
    00760          if (frame->subclass == AST_FORMAT_SLINEAR)
    00761             swap = 1; /* Swap big-endian samples to little-endian as we copy */
    00762 #endif
    00763          res = phone_write_buf(p, pos, expected, maxfr, swap);
    00764       }
    00765       if (res != expected) {
    00766          if ((errno != EAGAIN) && (errno != EINTR)) {
    00767             if (res < 0)
    00768                ast_log(LOG_WARNING, "Write returned error (%s)\n", strerror(errno));
    00769    /*
    00770     * Card is in non-blocking mode now and it works well now, but there are
    00771     * lot of messages like this. So, this message is temporarily disabled.
    00772     */
    00773 #if 0
    00774             else
    00775                ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frame->datalen);
    00776 #endif
    00777             return -1;
    00778          } else /* Pretend it worked */
    00779             res = expected;
    00780       }
    00781       sofar += res;
    00782       pos += res;
    00783    }
    00784    return 0;
    00785 }

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

Definition at line 568 of file chan_phone.c.

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

Referenced by phone_send_text(), and phone_write().

    00569 {
    00570    int res;
    00571    /* Store as much of the buffer as we can, then write fixed frames */
    00572    int space = sizeof(p->obuf) - p->obuflen;
    00573    /* Make sure we have enough buffer space to store the frame */
    00574    if (space < len)
    00575       len = space;
    00576    if (swap)
    00577       ast_swapcopy_samples(p->obuf+p->obuflen, buf, len/2);
    00578    else
    00579       memcpy(p->obuf + p->obuflen, buf, len);
    00580    p->obuflen += len;
    00581    while(p->obuflen > frlen) {
    00582       res = write(p->fd, p->obuf, frlen);
    00583       if (res != frlen) {
    00584          if (res < 1) {
    00585 /*
    00586  * Card is in non-blocking mode now and it works well now, but there are
    00587  * lot of messages like this. So, this message is temporarily disabled.
    00588  */
    00589             return 0;
    00590          } else {
    00591             ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frlen);
    00592          }
    00593       }
    00594       p->obuflen -= frlen;
    00595       /* Move memory if necessary */
    00596       if (p->obuflen)
    00597          memmove(p->obuf, p->obuf + frlen, p->obuflen);
    00598    }
    00599    return len;
    00600 }

static int restart_monitor | ( | void |  | ) | `[static]`

Definition at line 1078 of file chan_phone.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create, AST_PTHREADT_NULL, AST_PTHREADT_STOP, do_monitor(), LOG_ERROR, and LOG_WARNING.

    01079 {
    01080    /* If we're supposed to be stopped -- stay stopped */
    01081    if (monitor_thread == AST_PTHREADT_STOP)
    01082       return 0;
    01083    if (ast_mutex_lock(&monlock)) {
    01084       ast_log(LOG_WARNING, "Unable to lock monitor\n");
    01085       return -1;
    01086    }
    01087    if (monitor_thread == pthread_self()) {
    01088       ast_mutex_unlock(&monlock);
    01089       ast_log(LOG_WARNING, "Cannot kill myself\n");
    01090       return -1;
    01091    }
    01092    if (monitor_thread != AST_PTHREADT_NULL) {
    01093       if (ast_mutex_lock(&iflock)) {
    01094         ast_mutex_unlock(&monlock);
    01095         ast_log(LOG_WARNING, "Unable to lock the interface list\n");
    01096         return -1;
    01097       }
    01098       /* Wake up the thread */
    01099       pthread_cancel(monitor_thread);
    01100       ast_mutex_unlock(&iflock);
    01101    }
    01102    /* Start a new monitor */
    01103    if (ast_pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) {
    01104       ast_mutex_unlock(&monlock);
    01105       ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
    01106       return -1;
    01107    }
    01108    ast_mutex_unlock(&monlock);
    01109    return 0;
    01110 }

int unload_module | ( | void |  | ) |

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
  Zero on success, or non-zero on error.

Definition at line 1289 of file chan_phone.c.

References __unload_module().

    01290 {
    01291    return __unload_module();
    01292 }

int usecount | ( | void |  | ) |

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
  The module's usecount.

Definition at line 1401 of file chan_phone.c.

    01402 {
    01403    return usecnt;
    01404 }

## Variable Documentation

char cid_name[AST_MAX_EXTENSION]`[static]`

Definition at line 149 of file chan_phone.c.

char cid_num[AST_MAX_EXTENSION]`[static]`

Definition at line 148 of file chan_phone.c.

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

Definition at line 84 of file chan_phone.c.

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

Definition at line 87 of file chan_phone.c.

struct ast_channel_tech* cur_tech`[static]`

Definition at line 193 of file chan_phone.c.

const char desc[] = "Linux Telephony API Support"`[static]`

Definition at line 81 of file chan_phone.c.

int echocancel = AEC_OFF`[static]`

Definition at line 93 of file chan_phone.c.

struct phone_pvt * iflist`[static]`

char language[MAX_LANGUAGE] = ""`[static]`

Definition at line 90 of file chan_phone.c.

pthread_t monitor_thread = AST_PTHREADT_NULL`[static]`

Definition at line 110 of file chan_phone.c.

struct ast_channel_tech phone_tech`[static]`

Definition at line 162 of file chan_phone.c.

struct ast_channel_tech phone_tech_fxs`[static]`

Definition at line 177 of file chan_phone.c.

int prefformat = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW`[static]`

Definition at line 97 of file chan_phone.c.

int silencesupression = 0`[static]`

Definition at line 95 of file chan_phone.c.

const char tdesc[] = "Standard Linux Telephony API Driver"`[static]`

Definition at line 83 of file chan_phone.c.

const char type[] = "Phone"`[static]`

Definition at line 82 of file chan_phone.c.

int usecnt = 0`[static]`

Definition at line 91 of file chan_phone.c.