Asterisk - The Open Source Telephony Project  GIT-master-1f78ee9
Data Structures | Macros | Functions | Variables
chan_phone.c File Reference

Generic Linux Telephony Interface driver. More...

#include "asterisk.h"
#include <ctype.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <linux/telephony.h>
#include <linux/version.h>
#include <linux/ixjuser.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/callerid.h"
#include "asterisk/causes.h"
#include "asterisk/stringfields.h"
#include "asterisk/musiconhold.h"
#include "asterisk/format_cache.h"
#include "asterisk/format_compatibility.h"
#include "chan_phone.h"

Go to the source code of this file.

Data Structures

struct  phone_pvt
 

Macros

#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 int __unload_module (void)
 
 AST_MODULE_INFO_STANDARD_DEPRECATED (ASTERISK_GPL_KEY, "Linux Telephony API Support")
 
static void * do_monitor (void *data)
 
static int load_module (void)
 
static struct phone_pvtmkif (const char *iface, int mode, int txgain, int rxgain)
 
static int parse_gain_value (const char *gain_type, const char *value)
 
static int phone_answer (struct ast_channel *ast)
 
static int phone_call (struct ast_channel *ast, const char *dest, int timeout)
 
static void phone_check_exception (struct phone_pvt *i)
 
static int phone_digit_begin (struct ast_channel *ast, char digit)
 
static int phone_digit_end (struct ast_channel *ast, char digit, unsigned int duration)
 
static struct ast_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 *cntx, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
 
static struct ast_framephone_read (struct ast_channel *ast)
 
static struct ast_channelphone_request (const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
 
static int phone_send_text (struct ast_channel *ast, const char *text)
 
static int phone_setup (struct ast_channel *ast)
 
static int phone_write (struct ast_channel *ast, struct ast_frame *frame)
 
static int phone_write_buf (struct phone_pvt *p, const char *buf, int len, int frlen, int swap)
 
static int restart_monitor (void)
 
static int unload_module (void)
 

Variables

static 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 = NULL
 
static ast_mutex_t iflock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 
static char language [MAX_LANGUAGE] = ""
 
static unsigned int monitor
 
static pthread_t monitor_thread = AST_PTHREADT_NULL
 
static ast_mutex_t monlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 
static struct ast_channel_tech phone_tech
 
static struct ast_channel_tech phone_tech_fxs
 
static struct ast_format_capprefcap
 
static int silencesupression = 0
 
static const char tdesc [] = "Standard Linux Telephony API Driver"
 

Detailed Description

Generic Linux Telephony Interface driver.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Definition in file chan_phone.c.

Macro Definition Documentation

◆ DEFAULT_CALLER_ID

#define DEFAULT_CALLER_ID   "Unknown"

Definition at line 89 of file chan_phone.c.

Referenced by phone_call().

◆ DEFAULT_GAIN

#define DEFAULT_GAIN   0x100

Definition at line 91 of file chan_phone.c.

Referenced by load_module(), and parse_gain_value().

◆ IXJ_PHONE_RING_START

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

Definition at line 86 of file chan_phone.c.

Referenced by phone_call().

◆ MODE_DIALTONE

#define MODE_DIALTONE   1

Definition at line 127 of file chan_phone.c.

Referenced by load_module(), and phone_check_exception().

◆ MODE_FXO

#define MODE_FXO   3

Definition at line 129 of file chan_phone.c.

Referenced by load_module(), mkif(), phone_answer(), phone_exception(), and phone_hangup().

◆ MODE_FXS

#define MODE_FXS   4

◆ MODE_IMMEDIATE

#define MODE_IMMEDIATE   2

Definition at line 128 of file chan_phone.c.

Referenced by load_module(), and phone_check_exception().

◆ MODE_SIGMA

#define MODE_SIGMA   5

Definition at line 131 of file chan_phone.c.

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

◆ PHONE_MAX_BUF

#define PHONE_MAX_BUF   480

Definition at line 90 of file chan_phone.c.

Referenced by phone_read().

◆ QNDRV_VER

#define QNDRV_VER   100

Definition at line 76 of file chan_phone.c.

Function Documentation

◆ __unload_module()

static int __unload_module ( void  )
static

Definition at line 1313 of file chan_phone.c.

References ao2_ref, ast_channel_unregister(), ast_free, ast_log, ast_mutex_lock, ast_mutex_unlock, AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_channel_tech::capabilities, phone_pvt::fd, iflist, iflock, LOG_WARNING, monitor, monitor_thread, monlock, phone_pvt::next, NULL, and phone_pvt::owner.

Referenced by load_module(), and unload_module().

1314 {
1315  struct phone_pvt *p, *pl;
1316  /* First, take us out of the channel loop */
1317  if (cur_tech)
1319  if (!ast_mutex_lock(&iflock)) {
1320  /* Hangup all interfaces if they have an owner */
1321  p = iflist;
1322  while(p) {
1323  if (p->owner)
1325  p = p->next;
1326  }
1327  iflist = NULL;
1329  } else {
1330  ast_log(LOG_WARNING, "Unable to lock the monitor\n");
1331  return -1;
1332  }
1333  if (!ast_mutex_lock(&monlock)) {
1335  monitor = 0;
1336  while (pthread_kill(monitor_thread, SIGURG) == 0)
1337  sched_yield();
1338  pthread_join(monitor_thread, NULL);
1339  }
1342  } else {
1343  ast_log(LOG_WARNING, "Unable to lock the monitor\n");
1344  return -1;
1345  }
1346 
1347  if (!ast_mutex_lock(&iflock)) {
1348  /* Destroy all the interfaces and free their memory */
1349  p = iflist;
1350  while(p) {
1351  /* Close the socket, assuming it's real */
1352  if (p->fd > -1)
1353  close(p->fd);
1354  pl = p;
1355  p = p->next;
1356  /* Free associated memory */
1357  ast_free(pl);
1358  }
1359  iflist = NULL;
1361  } else {
1362  ast_log(LOG_WARNING, "Unable to lock the monitor\n");
1363  return -1;
1364  }
1365 
1368  ao2_ref(prefcap, -1);
1369 
1370  return 0;
1371 }
static pthread_t monitor_thread
Definition: chan_phone.c:120
static ast_mutex_t iflock
Definition: chan_phone.c:109
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:566
#define LOG_WARNING
Definition: logger.h:274
struct phone_pvt * next
Definition: chan_phone.c:141
static struct ast_format_cap * prefcap
Definition: chan_phone.c:106
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
static struct ast_channel_tech phone_tech
Definition: chan_phone.c:175
static ast_mutex_t monlock
Definition: chan_phone.c:113
static struct ast_channel_tech * cur_tech
Definition: chan_phone.c:209
#define ast_log
Definition: astobj2.c:42
struct ast_channel * owner
Definition: chan_phone.c:135
static struct ast_channel_tech phone_tech_fxs
Definition: chan_phone.c:191
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2451
static unsigned int monitor
Definition: chan_phone.c:116
struct ast_format_cap * capabilities
Definition: channel.h:633
#define ast_free(a)
Definition: astmm.h:182
static struct phone_pvt * iflist
#define AST_PTHREADT_STOP
Definition: lock.h:67
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ AST_MODULE_INFO_STANDARD_DEPRECATED()

AST_MODULE_INFO_STANDARD_DEPRECATED ( ASTERISK_GPL_KEY  ,
"Linux Telephony API Support"   
)

Referenced by load_module().

◆ do_monitor()

static void* do_monitor ( void *  data)
static

Definition at line 1031 of file chan_phone.c.

References ast_debug, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_poll, ast_poll2(), ast_realloc, ast_tv(), ast_tvzero(), DialTone, phone_pvt::dialtone, errno, phone_pvt::fd, iflist, iflock, LOG_ERROR, LOG_WARNING, phone_pvt::mode, MODE_SIGMA, monitor, phone_pvt::next, NULL, phone_pvt::owner, phone_check_exception(), phone_mini_packet(), and tmp().

Referenced by restart_monitor().

1032 {
1033  struct pollfd *fds = NULL;
1034  int nfds = 0, inuse_fds = 0, res;
1035  struct phone_pvt *i;
1036  int tonepos = 0;
1037  /* The tone we're playing this round */
1038  struct timeval to = { 0, 0 };
1039  int dotone;
1040  /* This thread monitors all the frame relay interfaces which are not yet in use
1041  (and thus do not have a separate thread) indefinitely */
1042  while (monitor) {
1043  /* Don't let anybody kill us right away. Nobody should lock the interface list
1044  and wait for the monitor list, but the other way around is okay. */
1045  /* Lock the interface list */
1046  if (ast_mutex_lock(&iflock)) {
1047  ast_log(LOG_ERROR, "Unable to grab interface lock\n");
1048  return NULL;
1049  }
1050  /* Build the stuff we're going to select on, that is the socket of every
1051  phone_pvt that does not have an associated owner channel */
1052  i = iflist;
1053  dotone = 0;
1054  inuse_fds = 0;
1055  for (i = iflist; i; i = i->next) {
1056  if (!i->owner) {
1057  /* This needs to be watched, as it lacks an owner */
1058  if (inuse_fds == nfds) {
1059  void *tmp = ast_realloc(fds, (nfds + 1) * sizeof(*fds));
1060  if (!tmp) {
1061  /* Avoid leaking */
1062  continue;
1063  }
1064  fds = tmp;
1065  nfds++;
1066  }
1067  fds[inuse_fds].fd = i->fd;
1068  fds[inuse_fds].events = POLLIN | POLLERR;
1069  fds[inuse_fds].revents = 0;
1070  inuse_fds++;
1071 
1072  if (i->dialtone && i->mode != MODE_SIGMA) {
1073  /* Remember we're going to have to come back and play
1074  more dialtones */
1075  if (ast_tvzero(to)) {
1076  /* If we're due for a dialtone, play one */
1077  if (write(i->fd, DialTone + tonepos, 240) != 240) {
1078  ast_log(LOG_WARNING, "Dial tone write error\n");
1079  }
1080  }
1081  dotone++;
1082  }
1083  }
1084  }
1085  /* Okay, now that we know what to do, release the interface lock */
1087 
1088  /* Wait indefinitely for something to happen */
1089  if (dotone && i && i->mode != MODE_SIGMA) {
1090  /* If we're ready to recycle the time, set it to 30 ms */
1091  tonepos += 240;
1092  if (tonepos >= sizeof(DialTone)) {
1093  tonepos = 0;
1094  }
1095  if (ast_tvzero(to)) {
1096  to = ast_tv(0, 30000);
1097  }
1098  res = ast_poll2(fds, inuse_fds, &to);
1099  } else {
1100  res = ast_poll(fds, inuse_fds, -1);
1101  to = ast_tv(0, 0);
1102  tonepos = 0;
1103  }
1104  /* Okay, select has finished. Let's see what happened. */
1105  if (res < 0) {
1106  ast_debug(1, "poll returned %d: %s\n", res, strerror(errno));
1107  continue;
1108  }
1109  /* If there are no fd's changed, just continue, it's probably time
1110  to play some more dialtones */
1111  if (!res) {
1112  continue;
1113  }
1114  /* Alright, lock the interface list again, and let's look and see what has
1115  happened */
1116  if (ast_mutex_lock(&iflock)) {
1117  ast_log(LOG_WARNING, "Unable to lock the interface list\n");
1118  continue;
1119  }
1120 
1121  for (i = iflist; i; i = i->next) {
1122  int j;
1123  /* Find the record */
1124  for (j = 0; j < inuse_fds; j++) {
1125  if (fds[j].fd == i->fd) {
1126  break;
1127  }
1128  }
1129 
1130  /* Not found? */
1131  if (j == inuse_fds) {
1132  continue;
1133  }
1134 
1135  if (fds[j].revents & POLLIN) {
1136  if (i->owner) {
1137  continue;
1138  }
1139  phone_mini_packet(i);
1140  }
1141  if (fds[j].revents & POLLERR) {
1142  if (i->owner) {
1143  continue;
1144  }
1146  }
1147  }
1149  }
1150  return NULL;
1151 }
static void phone_mini_packet(struct phone_pvt *i)
Definition: chan_phone.c:924
#define ast_realloc(p, len)
A wrapper for realloc()
Definition: astmm.h:228
static ast_mutex_t iflock
Definition: chan_phone.c:109
int dialtone
Definition: chan_phone.c:146
#define LOG_WARNING
Definition: logger.h:274
struct phone_pvt * next
Definition: chan_phone.c:141
static int tmp()
Definition: bt_open.c:389
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
static unsigned char DialTone[]
Definition: chan_phone.h:17
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
struct ast_channel * owner
Definition: chan_phone.c:135
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
#define LOG_ERROR
Definition: logger.h:285
static unsigned int monitor
Definition: chan_phone.c:116
int errno
#define MODE_SIGMA
Definition: chan_phone.c:131
static struct phone_pvt * iflist
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:226
static void phone_check_exception(struct phone_pvt *i)
Definition: chan_phone.c:936
int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv)
Same as poll(2), except the time is specified in microseconds and the tv argument is modified to indi...
Definition: poll.c:268
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ load_module()

static int load_module ( void  )
static

Definition at line 1378 of file chan_phone.c.

References __unload_module(), ast_callerid_split(), ast_channel_register(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_format_cap_alloc, ast_format_cap_append, ast_format_cap_append_from_cap(), AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_cap_remove_by_type(), ast_format_g723, ast_format_g729, ast_format_slin, ast_format_ulaw, ast_log, AST_MEDIA_TYPE_AUDIO, AST_MEDIA_TYPE_UNKNOWN, AST_MODULE_INFO_STANDARD_DEPRECATED(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_mutex_lock, ast_mutex_unlock, ast_true(), ast_variable_browse(), ASTERISK_GPL_KEY, ast_channel_tech::capabilities, phone_pvt::cid_name, phone_pvt::cid_num, config, CONFIG_STATUS_FILEINVALID, phone_pvt::context, DEFAULT_GAIN, echocancel, iflist, iflock, phone_pvt::language, LOG_ERROR, LOG_WARNING, mkif(), phone_pvt::mode, MODE_DIALTONE, MODE_FXO, MODE_FXS, MODE_IMMEDIATE, MODE_SIGMA, ast_variable::name, ast_variable::next, phone_pvt::next, parse_gain_value(), phone_tech_fxs, restart_monitor(), phone_pvt::rxgain, phone_pvt::silencesupression, tmp(), phone_pvt::txgain, and ast_variable::value.

1379 {
1380  struct ast_config *cfg;
1381  struct ast_variable *v;
1382  struct phone_pvt *tmp;
1383  int mode = MODE_IMMEDIATE;
1384  int txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; /* default gain 1.0 */
1385  struct ast_flags config_flags = { 0 };
1386 
1388  return AST_MODULE_LOAD_DECLINE;
1389  }
1390 
1395 
1397  return AST_MODULE_LOAD_DECLINE;
1398  }
1401  return AST_MODULE_LOAD_DECLINE;
1402  }
1403 
1404  if ((cfg = ast_config_load(config, config_flags)) == CONFIG_STATUS_FILEINVALID) {
1405  ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config);
1406  return AST_MODULE_LOAD_DECLINE;
1407  }
1408 
1409  /* We *must* have a config file otherwise stop immediately */
1410  if (!cfg) {
1411  ast_log(LOG_ERROR, "Unable to load config %s\n", config);
1412  return AST_MODULE_LOAD_DECLINE;
1413  }
1414  if (ast_mutex_lock(&iflock)) {
1415  /* It's a little silly to lock it, but we mind as well just to be sure */
1416  ast_log(LOG_ERROR, "Unable to lock interface list???\n");
1417  return AST_MODULE_LOAD_DECLINE;
1418  }
1419  v = ast_variable_browse(cfg, "interfaces");
1420  while(v) {
1421  /* Create the interface list */
1422  if (!strcasecmp(v->name, "device")) {
1423  tmp = mkif(v->value, mode, txgain, rxgain);
1424  if (tmp) {
1425  tmp->next = iflist;
1426  iflist = tmp;
1427 
1428  } else {
1429  ast_log(LOG_ERROR, "Unable to register channel '%s'\n", v->value);
1430  ast_config_destroy(cfg);
1432  __unload_module();
1433  return AST_MODULE_LOAD_DECLINE;
1434  }
1435  } else if (!strcasecmp(v->name, "silencesupression")) {
1437  } else if (!strcasecmp(v->name, "language")) {
1438  ast_copy_string(language, v->value, sizeof(language));
1439  } else if (!strcasecmp(v->name, "callerid")) {
1440  ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
1441  } else if (!strcasecmp(v->name, "mode")) {
1442  if (!strncasecmp(v->value, "di", 2))
1443  mode = MODE_DIALTONE;
1444  else if (!strncasecmp(v->value, "sig", 3))
1445  mode = MODE_SIGMA;
1446  else if (!strncasecmp(v->value, "im", 2))
1447  mode = MODE_IMMEDIATE;
1448  else if (!strncasecmp(v->value, "fxs", 3)) {
1449  mode = MODE_FXS;
1451  }
1452  else if (!strncasecmp(v->value, "fx", 2))
1453  mode = MODE_FXO;
1454  else
1455  ast_log(LOG_WARNING, "Unknown mode: %s\n", v->value);
1456  } else if (!strcasecmp(v->name, "context")) {
1457  ast_copy_string(context, v->value, sizeof(context));
1458  } else if (!strcasecmp(v->name, "format")) {
1459  if (!strcasecmp(v->value, "g729")) {
1462  } else if (!strcasecmp(v->value, "g723.1")) {
1465  } else if (!strcasecmp(v->value, "slinear")) {
1466  if (mode == MODE_FXS) {
1468  } else {
1471  }
1472  } else if (!strcasecmp(v->value, "ulaw")) {
1475  } else
1476  ast_log(LOG_WARNING, "Unknown format '%s'\n", v->value);
1477  } else if (!strcasecmp(v->name, "echocancel")) {
1478  if (!strcasecmp(v->value, "off")) {
1479  echocancel = AEC_OFF;
1480  } else if (!strcasecmp(v->value, "low")) {
1481  echocancel = AEC_LOW;
1482  } else if (!strcasecmp(v->value, "medium")) {
1483  echocancel = AEC_MED;
1484  } else if (!strcasecmp(v->value, "high")) {
1485  echocancel = AEC_HIGH;
1486  } else
1487  ast_log(LOG_WARNING, "Unknown echo cancellation '%s'\n", v->value);
1488  } else if (!strcasecmp(v->name, "txgain")) {
1489  txgain = parse_gain_value(v->name, v->value);
1490  } else if (!strcasecmp(v->name, "rxgain")) {
1491  rxgain = parse_gain_value(v->name, v->value);
1492  }
1493  v = v->next;
1494  }
1496 
1497  if (mode == MODE_FXS) {
1500  } else
1501  cur_tech = (struct ast_channel_tech *) &phone_tech;
1502 
1503  /* Make sure we can register our Adtranphone channel type */
1504 
1506  ast_log(LOG_ERROR, "Unable to register channel class 'Phone'\n");
1507  ast_config_destroy(cfg);
1508  __unload_module();
1509  return AST_MODULE_LOAD_DECLINE;
1510  }
1511  ast_config_destroy(cfg);
1512  /* And start the monitor for the first time */
1513  restart_monitor();
1514  return AST_MODULE_LOAD_SUCCESS;
1515 }
struct ast_variable * next
static char cid_num[AST_MAX_EXTENSION]
Definition: chan_phone.c:159
static int parse_gain_value(const char *gain_type, const char *value)
Definition: chan_phone.c:1291
struct ast_format * ast_format_g723
Built-in cached g723.1 format.
Definition: format_cache.c:151
static const char config[]
Definition: chan_phone.c:94
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
Definition: callerid.c:1092
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
static ast_mutex_t iflock
Definition: chan_phone.c:109
#define MODE_IMMEDIATE
Definition: chan_phone.c:128
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
Definition: format_cache.c:86
#define LOG_WARNING
Definition: logger.h:274
struct phone_pvt * next
Definition: chan_phone.c:141
#define CONFIG_STATUS_FILEINVALID
static int tmp()
Definition: bt_open.c:389
Structure for variables, used for configurations and for channel variables.
static struct ast_format_cap * prefcap
Definition: chan_phone.c:106
static int restart_monitor(void)
Definition: chan_phone.c:1153
static char language[MAX_LANGUAGE]
Definition: chan_phone.c:100
static char cid_name[AST_MAX_EXTENSION]
Definition: chan_phone.c:160
#define ast_mutex_lock(a)
Definition: lock.h:187
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
Definition: channel.c:535
static struct ast_channel_tech phone_tech
Definition: chan_phone.c:175
static struct ast_channel_tech * cur_tech
Definition: chan_phone.c:209
int txgain
Definition: chan_phone.c:147
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
int rxgain
Definition: chan_phone.c:147
static struct ast_channel_tech phone_tech_fxs
Definition: chan_phone.c:191
static int echocancel
Definition: chan_phone.c:102
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
static int __unload_module(void)
Definition: chan_phone.c:1313
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:629
void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type)
Remove all formats matching a specific format type.
Definition: format_cap.c:525
#define LOG_ERROR
Definition: logger.h:285
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1821
#define MODE_DIALTONE
Definition: chan_phone.c:127
struct ast_format_cap * capabilities
Definition: channel.h:633
#define MODE_FXS
Definition: chan_phone.c:130
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define MODE_SIGMA
Definition: chan_phone.c:131
static struct phone_pvt * mkif(const char *iface, int mode, int txgain, int rxgain)
Definition: chan_phone.c:1190
Structure used to handle boolean flags.
Definition: utils.h:199
static struct phone_pvt * iflist
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
static char context[AST_MAX_EXTENSION]
Definition: chan_phone.c:97
#define DEFAULT_GAIN
Definition: chan_phone.c:91
static int silencesupression
Definition: chan_phone.c:104
int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, enum ast_media_type type)
Append the formats of provided type in src to dst.
Definition: format_cap.c:269
struct ast_format * ast_format_g729
Built-in cached g729 format.
Definition: format_cache.c:156
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
#define MODE_FXO
Definition: chan_phone.c:129
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ mkif()

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

Definition at line 1190 of file chan_phone.c.

References ao2_cleanup, ast_calloc, ast_copy_string(), ast_debug, ast_fd_set_flags, ast_free, ast_log, phone_pvt::cid_name, phone_pvt::cid_num, phone_pvt::context, phone_pvt::cpt, phone_pvt::dev, phone_pvt::dialtone, echocancel, errno, phone_pvt::ext, phone_pvt::fd, phone_pvt::language, phone_pvt::lastformat, phone_pvt::lastinput, LOG_WARNING, phone_pvt::ministate, phone_pvt::mode, MODE_FXO, MODE_FXS, phone_pvt::next, NULL, phone_pvt::obuflen, phone_pvt::owner, phone_pvt::rxgain, phone_pvt::silencesupression, tmp(), and phone_pvt::txgain.

Referenced by load_module().

1191 {
1192  /* Make a phone_pvt structure for this interface */
1193  struct phone_pvt *tmp;
1194 
1195  tmp = ast_calloc(1, sizeof(*tmp));
1196  if (tmp) {
1197  tmp->fd = open(iface, O_RDWR);
1198  if (tmp->fd < 0) {
1199  ast_log(LOG_WARNING, "Unable to open '%s'\n", iface);
1200  ast_free(tmp);
1201  return NULL;
1202  }
1203  if (mode == MODE_FXO) {
1204  if (ioctl(tmp->fd, IXJCTL_PORT, PORT_PSTN)) {
1205  ast_debug(1, "Unable to set port to PSTN\n");
1206  }
1207  } else {
1208  if (ioctl(tmp->fd, IXJCTL_PORT, PORT_POTS))
1209  if (mode != MODE_FXS)
1210  ast_debug(1, "Unable to set port to POTS\n");
1211  }
1212  ioctl(tmp->fd, PHONE_PLAY_STOP);
1213  ioctl(tmp->fd, PHONE_REC_STOP);
1214  ioctl(tmp->fd, PHONE_RING_STOP);
1215  ioctl(tmp->fd, PHONE_CPT_STOP);
1216  if (ioctl(tmp->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK))
1217  ast_debug(1, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",iface, strerror(errno));
1218  if (echocancel != AEC_OFF)
1219  ioctl(tmp->fd, IXJCTL_AEC_START, echocancel);
1220  if (silencesupression)
1221  tmp->silencesupression = 1;
1222 #ifdef PHONE_VAD
1223  ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression);
1224 #endif
1225  tmp->mode = mode;
1226  ast_fd_set_flags(tmp->fd, O_NONBLOCK);
1227  tmp->owner = NULL;
1228  ao2_cleanup(tmp->lastformat);
1229  tmp->lastformat = NULL;
1230  ao2_cleanup(tmp->lastinput);
1231  tmp->lastinput = NULL;
1232  tmp->ministate = 0;
1233  memset(tmp->ext, 0, sizeof(tmp->ext));
1234  ast_copy_string(tmp->language, language, sizeof(tmp->language));
1235  ast_copy_string(tmp->dev, iface, sizeof(tmp->dev));
1236  ast_copy_string(tmp->context, context, sizeof(tmp->context));
1237  tmp->next = NULL;
1238  tmp->obuflen = 0;
1239  tmp->dialtone = 0;
1240  tmp->cpt = 0;
1241  ast_copy_string(tmp->cid_num, cid_num, sizeof(tmp->cid_num));
1242  ast_copy_string(tmp->cid_name, cid_name, sizeof(tmp->cid_name));
1243  tmp->txgain = txgain;
1244  ioctl(tmp->fd, PHONE_PLAY_VOLUME, tmp->txgain);
1245  tmp->rxgain = rxgain;
1246  ioctl(tmp->fd, PHONE_REC_VOLUME, tmp->rxgain);
1247  }
1248  return tmp;
1249 }
static char cid_num[AST_MAX_EXTENSION]
Definition: chan_phone.c:159
struct ast_format * lastformat
Definition: chan_phone.c:137
int ministate
Definition: chan_phone.c:139
int dialtone
Definition: chan_phone.c:146
int silencesupression
Definition: chan_phone.c:150
#define LOG_WARNING
Definition: logger.h:274
struct phone_pvt * next
Definition: chan_phone.c:141
static int tmp()
Definition: bt_open.c:389
static char language[MAX_LANGUAGE]
Definition: chan_phone.c:100
static char cid_name[AST_MAX_EXTENSION]
Definition: chan_phone.c:160
#define NULL
Definition: resample.c:96
int txgain
Definition: chan_phone.c:147
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
Definition: utils.h:949
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
struct ast_channel * owner
Definition: chan_phone.c:135
int rxgain
Definition: chan_phone.c:147
static int echocancel
Definition: chan_phone.c:102
char language[MAX_LANGUAGE]
Definition: chan_phone.c:154
char ext[AST_MAX_EXTENSION]
Definition: chan_phone.c:153
char context[AST_MAX_EXTENSION]
Definition: chan_phone.c:151
struct ast_format * lastinput
Definition: chan_phone.c:138
int errno
char dev[256]
Definition: chan_phone.c:140
char cid_num[AST_MAX_EXTENSION]
Definition: chan_phone.c:155
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define MODE_FXS
Definition: chan_phone.c:130
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
static char context[AST_MAX_EXTENSION]
Definition: chan_phone.c:97
static int silencesupression
Definition: chan_phone.c:104
char cid_name[AST_MAX_EXTENSION]
Definition: chan_phone.c:156
int obuflen
Definition: chan_phone.c:145
#define MODE_FXO
Definition: chan_phone.c:129

◆ parse_gain_value()

static int parse_gain_value ( const char *  gain_type,
const char *  value 
)
static

Definition at line 1291 of file chan_phone.c.

References ast_log, config, DEFAULT_GAIN, and LOG_ERROR.

Referenced by load_module().

1292 {
1293  float gain;
1294 
1295  /* try to scan number */
1296  if (sscanf(value, "%30f", &gain) != 1)
1297  {
1298  ast_log(LOG_ERROR, "Invalid %s value '%s' in '%s' config\n",
1299  value, gain_type, config);
1300  return DEFAULT_GAIN;
1301  }
1302 
1303  /* multiplicate gain by 1.0 gain value */
1304  gain = gain * (float)DEFAULT_GAIN;
1305 
1306  /* percentage? */
1307  if (value[strlen(value) - 1] == '%')
1308  return (int)(gain / (float)100);
1309 
1310  return (int)gain;
1311 }
static const char config[]
Definition: chan_phone.c:94
int value
Definition: syslog.c:37
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
#define DEFAULT_GAIN
Definition: chan_phone.c:91

◆ phone_answer()

static int phone_answer ( struct ast_channel ast)
static

Definition at line 471 of file chan_phone.c.

References ast_channel_name(), ast_channel_rings_set(), ast_channel_tech_pvt(), ast_debug, ast_setstate(), AST_STATE_UP, c, errno, phone_pvt::fd, phone_pvt::mode, MODE_FXO, and phone_setup().

472 {
473  struct phone_pvt *p;
474  p = ast_channel_tech_pvt(ast);
475  /* In case it's a LineJack, take it off hook */
476  if (p->mode == MODE_FXO) {
477  if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_OFF_HOOK))
478  ast_debug(1, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n", ast_channel_name(ast), strerror(errno));
479  else
480  ast_debug(1, "Took linejack off hook\n");
481  }
482  phone_setup(ast);
483  ast_debug(1, "phone_answer(%s)\n", ast_channel_name(ast));
484  ast_channel_rings_set(ast, 0);
486  return 0;
487 }
void * ast_channel_tech_pvt(const struct ast_channel *chan)
static int phone_setup(struct ast_channel *ast)
Definition: chan_phone.c:404
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
void ast_channel_rings_set(struct ast_channel *chan, int value)
int errno
const char * ast_channel_name(const struct ast_channel *chan)
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7325
#define MODE_FXO
Definition: chan_phone.c:129

◆ phone_call()

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

Definition at line 300 of file chan_phone.c.

References ast_channel_connected(), ast_channel_fd(), ast_channel_name(), ast_channel_tech_pvt(), AST_CONTROL_RINGING, ast_copy_string(), ast_debug, ast_localtime(), ast_log, ast_queue_control(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RINGING, ast_strlen_zero, ast_tvnow(), DEFAULT_CALLER_ID, digit, IXJ_PHONE_RING_START, LOG_WARNING, phone_pvt::mode, MODE_FXS, name, NULL, phone_digit_end(), ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, and ast_tm::tm_mon.

301 {
302  struct phone_pvt *p;
303 
304  PHONE_CID cid;
305  struct timeval UtcTime = ast_tvnow();
306  struct ast_tm tm;
307  int start;
308 
309  ast_localtime(&UtcTime, &tm, NULL);
310 
311  memset(&cid, 0, sizeof(PHONE_CID));
312  snprintf(cid.month, sizeof(cid.month), "%02d",(tm.tm_mon + 1));
313  snprintf(cid.day, sizeof(cid.day), "%02d", tm.tm_mday);
314  snprintf(cid.hour, sizeof(cid.hour), "%02d", tm.tm_hour);
315  snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min);
316  /* the standard format of ast->callerid is: "name" <number>, but not always complete */
317  if (!ast_channel_connected(ast)->id.name.valid
318  || ast_strlen_zero(ast_channel_connected(ast)->id.name.str)) {
319  strcpy(cid.name, DEFAULT_CALLER_ID);
320  } else {
321  ast_copy_string(cid.name, ast_channel_connected(ast)->id.name.str, sizeof(cid.name));
322  }
323 
324  if (ast_channel_connected(ast)->id.number.valid && ast_channel_connected(ast)->id.number.str) {
325  ast_copy_string(cid.number, ast_channel_connected(ast)->id.number.str, sizeof(cid.number));
326  }
327 
328  p = ast_channel_tech_pvt(ast);
329 
331  ast_log(LOG_WARNING, "phone_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
332  return -1;
333  }
334  ast_debug(1, "Ringing %s on %s (%d)\n", dest, ast_channel_name(ast), ast_channel_fd(ast, 0));
335 
336  start = IXJ_PHONE_RING_START(cid);
337  if (start == -1)
338  return -1;
339 
340  if (p->mode == MODE_FXS) {
341  const char *digit = strchr(dest, '/');
342  if (digit)
343  {
344  digit++;
345  while (*digit)
346  phone_digit_end(ast, *digit++, 0);
347  }
348  }
349 
352  return 0;
353 }
char digit
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition: channel.c:1227
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define LOG_WARNING
Definition: logger.h:274
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
ast_channel_state
ast_channel states
Definition: channelstate.h:35
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define NULL
Definition: resample.c:96
Number structure.
Definition: app_followme.c:154
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
#define ast_strlen_zero(a)
Definition: muted.c:73
static const char name[]
Definition: cdr_mysql.c:74
#define IXJ_PHONE_RING_START(x)
Definition: chan_phone.c:86
#define MODE_FXS
Definition: chan_phone.c:130
#define DEFAULT_CALLER_ID
Definition: chan_phone.c:89
int ast_channel_fd(const struct ast_channel *chan, int which)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const char * ast_channel_name(const struct ast_channel *chan)
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7325
static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
Definition: chan_phone.c:256

◆ phone_check_exception()

static void phone_check_exception ( struct phone_pvt i)
static

Definition at line 936 of file chan_phone.c.

References ao2_cleanup, ast_canmatch_extension(), ast_debug, ast_exists_extension(), 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, digit, phone_pvt::ext, phone_pvt::fd, phone_pvt::lastformat, phone_pvt::mode, MODE_DIALTONE, MODE_FXS, MODE_IMMEDIATE, MODE_SIGMA, NULL, phone_new(), and ast_module_info::self.

Referenced by do_monitor().

937 {
938  int offhook=0;
939  char digit[2] = {0 , 0};
940  union telephony_exception phonee;
941  /* XXX Do something XXX */
942 #if 0
943  ast_debug(1, "Exception!\n");
944 #endif
945  phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION);
946  if (phonee.bits.dtmf_ready) {
947  digit[0] = ioctl(i->fd, PHONE_GET_DTMF_ASCII);
948  if (i->mode == MODE_DIALTONE || i->mode == MODE_FXS || i->mode == MODE_SIGMA) {
949  ioctl(i->fd, PHONE_PLAY_STOP);
950  ioctl(i->fd, PHONE_REC_STOP);
951  ioctl(i->fd, PHONE_CPT_STOP);
952  i->dialtone = 0;
953  if (strlen(i->ext) < AST_MAX_EXTENSION - 1)
954  strncat(i->ext, digit, sizeof(i->ext) - strlen(i->ext) - 1);
955  if ((i->mode != MODE_FXS ||
956  !(phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION)) ||
957  !phonee.bits.dtmf_ready) &&
958  ast_exists_extension(NULL, i->context, i->ext, 1, i->cid_num)) {
959  /* It's a valid extension in its context, get moving! */
961  /* No need to restart monitor, we are the monitor */
962  } else if (!ast_canmatch_extension(NULL, i->context, i->ext, 1, i->cid_num)) {
963  /* There is nothing in the specified extension that can match anymore.
964  Try the default */
965  if (ast_exists_extension(NULL, "default", i->ext, 1, i->cid_num)) {
966  /* Check the default, too... */
967  phone_new(i, AST_STATE_RING, "default", NULL, NULL);
968  /* XXX This should probably be justified better XXX */
969  } else if (!ast_canmatch_extension(NULL, "default", i->ext, 1, i->cid_num)) {
970  /* It's not a valid extension, give a busy signal */
971  ast_debug(1, "%s can't match anything in %s or default\n", i->ext, i->context);
972  ioctl(i->fd, PHONE_BUSY);
973  i->cpt = 1;
974  }
975  }
976 #if 0
977  ast_verbose("Extension is %s\n", i->ext);
978 #endif
979  }
980  }
981  if (phonee.bits.hookstate) {
982  offhook = ioctl(i->fd, PHONE_HOOKSTATE);
983  if (offhook) {
984  if (i->mode == MODE_IMMEDIATE) {
986  } else if (i->mode == MODE_DIALTONE) {
988  /* Reset the extension */
989  i->ext[0] = '\0';
990  /* Play the dialtone */
991  i->dialtone++;
992  ioctl(i->fd, PHONE_PLAY_STOP);
993  ioctl(i->fd, PHONE_PLAY_CODEC, ULAW);
994  ioctl(i->fd, PHONE_PLAY_START);
996  i->lastformat = NULL;
997  } else if (i->mode == MODE_SIGMA) {
999  /* Reset the extension */
1000  i->ext[0] = '\0';
1001  /* Play the dialtone */
1002  i->dialtone++;
1003  ioctl(i->fd, PHONE_DIALTONE);
1004  }
1005  } else {
1006  if (i->dialtone)
1008  memset(i->ext, 0, sizeof(i->ext));
1009  if (i->cpt)
1010  {
1011  ioctl(i->fd, PHONE_CPT_STOP);
1012  i->cpt = 0;
1013  }
1014  ioctl(i->fd, PHONE_PLAY_STOP);
1015  ioctl(i->fd, PHONE_REC_STOP);
1016  i->dialtone = 0;
1017  ao2_cleanup(i->lastformat);
1018  i->lastformat = NULL;
1019  }
1020  }
1021  if (phonee.bits.pstn_ring) {
1022  ast_verbose("Unit is ringing\n");
1024  }
1025  if (phonee.bits.caller_id)
1026  ast_verbose("We have caller ID\n");
1027 
1028 
1029 }
char digit
struct ast_format * lastformat
Definition: chan_phone.c:137
#define MODE_IMMEDIATE
Definition: chan_phone.c:128
int dialtone
Definition: chan_phone.c:146
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2207
#define NULL
Definition: resample.c:96
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition: pbx.c:4185
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
struct ast_module * self
Definition: module.h:342
#define AST_MAX_EXTENSION
Definition: channel.h:135
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4170
char ext[AST_MAX_EXTENSION]
Definition: chan_phone.c:153
char context[AST_MAX_EXTENSION]
Definition: chan_phone.c:151
#define MODE_DIALTONE
Definition: chan_phone.c:127
char cid_num[AST_MAX_EXTENSION]
Definition: chan_phone.c:155
static struct ast_channel * phone_new(struct phone_pvt *i, int state, char *cntx, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
Definition: chan_phone.c:855
#define MODE_FXS
Definition: chan_phone.c:130
#define MODE_SIGMA
Definition: chan_phone.c:131
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443

◆ phone_digit_begin()

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

Definition at line 250 of file chan_phone.c.

251 {
252  /* XXX Modify this callback to let Asterisk support controlling the length of DTMF */
253  return 0;
254 }

◆ phone_digit_end()

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

Definition at line 256 of file chan_phone.c.

References ao2_cleanup, ast_channel_tech_pvt(), ast_debug, ast_log, phone_pvt::fd, phone_pvt::lastformat, LOG_WARNING, and NULL.

Referenced by phone_call().

257 {
258  struct phone_pvt *p;
259  int outdigit;
260  p = ast_channel_tech_pvt(ast);
261  ast_debug(1, "Dialed %c\n", digit);
262  switch(digit) {
263  case '0':
264  case '1':
265  case '2':
266  case '3':
267  case '4':
268  case '5':
269  case '6':
270  case '7':
271  case '8':
272  case '9':
273  outdigit = digit - '0';
274  break;
275  case '*':
276  outdigit = 11;
277  break;
278  case '#':
279  outdigit = 12;
280  break;
281  case 'f': /*flash*/
282  case 'F':
283  ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
284  usleep(320000);
285  ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
287  p->lastformat = NULL;
288  return 0;
289  default:
290  ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit);
291  return -1;
292  }
293  ast_debug(1, "Dialed %d\n", outdigit);
294  ioctl(p->fd, PHONE_PLAY_TONE, outdigit);
296  p->lastformat = NULL;
297  return 0;
298 }
char digit
struct ast_format * lastformat
Definition: chan_phone.c:137
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define LOG_WARNING
Definition: logger.h:274
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ phone_exception()

static struct ast_frame * phone_exception ( struct ast_channel ast)
static

Definition at line 503 of file chan_phone.c.

References ast_channel_tech_pvt(), AST_CONTROL_ANSWER, ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_NULL, ast_log, ast_setstate(), AST_STATE_RINGING, AST_STATE_UP, ast_tv(), ast_verbose(), ast_frame::data, ast_frame::datalen, ast_frame::delivery, digit, phone_pvt::fd, phone_pvt::fr, ast_frame::frametype, ast_frame_subclass::integer, LOG_WARNING, ast_frame::mallocd, phone_pvt::mode, MODE_FXO, NULL, ast_frame::offset, phone_setup(), ast_frame::ptr, ast_frame::samples, ast_frame::src, and ast_frame::subclass.

504 {
505  int res;
506  union telephony_exception phonee;
507  struct phone_pvt *p = ast_channel_tech_pvt(ast);
508  char digit;
509 
510  /* Some nice norms */
511  p->fr.datalen = 0;
512  p->fr.samples = 0;
513  p->fr.data.ptr = NULL;
514  p->fr.src = "Phone";
515  p->fr.offset = 0;
516  p->fr.mallocd=0;
517  p->fr.delivery = ast_tv(0,0);
518 
519  phonee.bytes = ioctl(p->fd, PHONE_EXCEPTION);
520  if (phonee.bits.dtmf_ready) {
521  ast_debug(1, "phone_exception(): DTMF\n");
522 
523  /* We've got a digit -- Just handle this nicely and easily */
524  digit = ioctl(p->fd, PHONE_GET_DTMF_ASCII);
525  p->fr.subclass.integer = digit;
527  return &p->fr;
528  }
529  if (phonee.bits.hookstate) {
530  ast_debug(1, "Hookstate changed\n");
531  res = ioctl(p->fd, PHONE_HOOKSTATE);
532  /* See if we've gone on hook, if so, notify by returning NULL */
533  ast_debug(1, "New hookstate: %d\n", res);
534  if (!res && (p->mode != MODE_FXO))
535  return NULL;
536  else {
537  if (ast_channel_state(ast) == AST_STATE_RINGING) {
538  /* They've picked up the phone */
541  phone_setup(ast);
543  return &p->fr;
544  } else
545  ast_log(LOG_WARNING, "Got off hook in weird state %u\n", ast_channel_state(ast));
546  }
547  }
548 #if 1
549  if (phonee.bits.pstn_ring)
550  ast_verbose("Unit is ringing\n");
551  if (phonee.bits.caller_id) {
552  ast_verbose("We have caller ID\n");
553  }
554  if (phonee.bits.pstn_wink)
555  ast_verbose("Detected Wink\n");
556 #endif
557  /* Strange -- nothing there.. */
559  p->fr.subclass.integer = 0;
560  return &p->fr;
561 }
char digit
void * ast_channel_tech_pvt(const struct ast_channel *chan)
static int phone_setup(struct ast_channel *ast)
Definition: chan_phone.c:404
#define LOG_WARNING
Definition: logger.h:274
ast_channel_state
ast_channel states
Definition: channelstate.h:35
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2207
struct ast_frame fr
Definition: chan_phone.c:142
#define NULL
Definition: resample.c:96
#define AST_FRAME_DTMF
struct ast_frame_subclass subclass
union ast_frame::@255 data
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
const char * src
struct timeval delivery
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:226
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7325
enum ast_frame_type frametype
#define MODE_FXO
Definition: chan_phone.c:129

◆ phone_fixup()

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

Definition at line 242 of file chan_phone.c.

References ast_channel_tech_pvt(), and phone_pvt::owner.

243 {
244  struct phone_pvt *pvt = ast_channel_tech_pvt(old);
245  if (pvt && pvt->owner == old)
246  pvt->owner = new;
247  return 0;
248 }
void * ast_channel_tech_pvt(const struct ast_channel *chan)
struct ast_channel * owner
Definition: chan_phone.c:135

◆ phone_hangup()

static int phone_hangup ( struct ast_channel ast)
static

Definition at line 355 of file chan_phone.c.

References ao2_cleanup, ast_channel_name(), ast_channel_tech_pvt(), ast_channel_tech_pvt_set(), ast_debug, ast_log, ast_module_unref, ast_setstate(), AST_STATE_DOWN, ast_verb, phone_pvt::cpt, phone_pvt::dialtone, errno, phone_pvt::ext, phone_pvt::fd, phone_pvt::lastformat, phone_pvt::lastinput, LOG_WARNING, phone_pvt::ministate, phone_pvt::mode, MODE_FXO, NULL, phone_pvt::obuflen, restart_monitor(), and ast_module_info::self.

356 {
357  struct phone_pvt *p;
358  p = ast_channel_tech_pvt(ast);
359  ast_debug(1, "phone_hangup(%s)\n", ast_channel_name(ast));
360  if (!ast_channel_tech_pvt(ast)) {
361  ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
362  return 0;
363  }
364  /* XXX Is there anything we can do to really hang up except stop recording? */
366  if (ioctl(p->fd, PHONE_REC_STOP))
367  ast_log(LOG_WARNING, "Failed to stop recording\n");
368  if (ioctl(p->fd, PHONE_PLAY_STOP))
369  ast_log(LOG_WARNING, "Failed to stop playing\n");
370  if (ioctl(p->fd, PHONE_RING_STOP))
371  ast_log(LOG_WARNING, "Failed to stop ringing\n");
372  if (ioctl(p->fd, PHONE_CPT_STOP))
373  ast_log(LOG_WARNING, "Failed to stop sounds\n");
374 
375  /* If it's an FXO, hang them up */
376  if (p->mode == MODE_FXO) {
377  if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK))
378  ast_debug(1, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",ast_channel_name(ast), strerror(errno));
379  }
380 
381  /* If they're off hook, give a busy signal */
382  if (ioctl(p->fd, PHONE_HOOKSTATE)) {
383  ast_debug(1, "Got hunghup, giving busy signal\n");
384  ioctl(p->fd, PHONE_BUSY);
385  p->cpt = 1;
386  }
388  p->lastformat = NULL;
390  p->lastinput = NULL;
391  p->ministate = 0;
392  p->obuflen = 0;
393  p->dialtone = 0;
394  memset(p->ext, 0, sizeof(p->ext));
395  ((struct phone_pvt *)(ast_channel_tech_pvt(ast)))->owner = NULL;
397  ast_verb(3, "Hungup '%s'\n", ast_channel_name(ast));
400  restart_monitor();
401  return 0;
402 }
struct ast_format * lastformat
Definition: chan_phone.c:137
int ministate
Definition: chan_phone.c:139
void * ast_channel_tech_pvt(const struct ast_channel *chan)
int dialtone
Definition: chan_phone.c:146
#define LOG_WARNING
Definition: logger.h:274
static int restart_monitor(void)
Definition: chan_phone.c:1153
#define NULL
Definition: resample.c:96
#define ast_verb(level,...)
Definition: logger.h:455
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
struct ast_module * self
Definition: module.h:342
char ext[AST_MAX_EXTENSION]
Definition: chan_phone.c:153
struct ast_format * lastinput
Definition: chan_phone.c:138
int errno
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
const char * ast_channel_name(const struct ast_channel *chan)
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7325
int obuflen
Definition: chan_phone.c:145
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
#define MODE_FXO
Definition: chan_phone.c:129

◆ phone_indicate()

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

Definition at line 211 of file chan_phone.c.

References ao2_cleanup, ast_channel_name(), ast_channel_tech_pvt(), AST_CONTROL_FLASH, AST_CONTROL_HOLD, AST_CONTROL_PVT_CAUSE_CODE, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, ast_debug, ast_log, ast_moh_start(), ast_moh_stop(), phone_pvt::fd, phone_pvt::lastformat, LOG_WARNING, and NULL.

212 {
213  struct phone_pvt *p = ast_channel_tech_pvt(chan);
214  int res=-1;
215  ast_debug(1, "Requested indication %d on channel %s\n", condition, ast_channel_name(chan));
216  switch(condition) {
217  case AST_CONTROL_FLASH:
218  ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);
219  usleep(320000);
220  ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);
222  p->lastformat = NULL;
223  res = 0;
224  break;
225  case AST_CONTROL_HOLD:
226  ast_moh_start(chan, data, NULL);
227  break;
228  case AST_CONTROL_UNHOLD:
229  ast_moh_stop(chan);
230  break;
232  res = 0;
233  break;
235  break;
236  default:
237  ast_log(LOG_WARNING, "Condition %d is not supported on channel %s\n", condition, ast_channel_name(chan));
238  }
239  return res;
240 }
struct ast_format * lastformat
Definition: chan_phone.c:137
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define LOG_WARNING
Definition: logger.h:274
#define NULL
Definition: resample.c:96
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7715
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7705
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
const char * ast_channel_name(const struct ast_channel *chan)

◆ phone_mini_packet()

static void phone_mini_packet ( struct phone_pvt i)
static

Definition at line 924 of file chan_phone.c.

References ast_log, phone_pvt::buf, errno, phone_pvt::fd, and LOG_WARNING.

Referenced by do_monitor().

925 {
926  int res;
927  char buf[1024];
928  /* Ignore stuff we read... */
929  res = read(i->fd, buf, sizeof(buf));
930  if (res < 1) {
931  ast_log(LOG_WARNING, "Read returned %d: %s\n", res, strerror(errno));
932  return;
933  }
934 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
#define ast_log
Definition: astobj2.c:42
int errno

◆ phone_new()

static struct ast_channel* phone_new ( struct phone_pvt i,
int  state,
char *  cntx,
const struct ast_assigned_ids assignedids,
const struct ast_channel requestor 
)
static

Definition at line 855 of file chan_phone.c.

References ast_party_caller::ani, ao2_cleanup, ao2_ref, ast_channel_alloc, ast_channel_caller(), ast_channel_context_set(), ast_channel_exten_set(), ast_channel_fd(), ast_channel_lock, ast_channel_name(), ast_channel_nativeformats_set(), ast_channel_rings_set(), ast_channel_set_fd(), ast_channel_set_rawreadformat(), ast_channel_set_rawwriteformat(), ast_channel_tech_pvt_set(), ast_channel_tech_set(), ast_channel_unlock, ast_format_cap_alloc, ast_format_cap_append, ast_format_cap_append_from_cap(), AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_cap_get_format(), ast_format_cap_remove(), ast_format_slin, ast_hangup(), ast_log, AST_MEDIA_TYPE_UNKNOWN, ast_module_ref, ast_pbx_start(), AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_strlen_zero, phone_pvt::cid_name, phone_pvt::cid_num, phone_pvt::context, phone_pvt::cpt, phone_pvt::dev, phone_pvt::ext, phone_pvt::fd, phone_pvt::language, LOG_WARNING, phone_pvt::mode, MODE_FXS, NULL, ast_party_id::number, phone_pvt::owner, ast_module_info::self, ast_party_number::str, tmp(), and ast_party_number::valid.

Referenced by phone_check_exception(), and phone_request().

856 {
857  struct ast_format_cap *caps = NULL;
858  struct ast_channel *tmp;
859  struct phone_codec_data queried_codec;
860  struct ast_format *tmpfmt;
862  tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", i->ext, i->context, assignedids, requestor, 0, "Phone/%s", i->dev + 5);
863  if (tmp && caps) {
864  ast_channel_lock(tmp);
866  ast_channel_set_fd(tmp, 0, i->fd);
867  /* XXX Switching formats silently causes kernel panics XXX */
868  if (i->mode == MODE_FXS &&
869  ioctl(i->fd, PHONE_QUERY_CODEC, &queried_codec) == 0) {
870  if (queried_codec.type == LINEAR16) {
872  } else {
875  }
876  } else {
878  }
879  tmpfmt = ast_format_cap_get_format(caps, 0);
881  ao2_ref(caps, -1);
882  ast_channel_set_rawreadformat(tmp, tmpfmt);
883  ast_channel_set_rawwriteformat(tmp, tmpfmt);
884  ao2_ref(tmpfmt, -1);
885  /* no need to call ast_setstate: the channel_alloc already did its job */
886  if (state == AST_STATE_RING)
887  ast_channel_rings_set(tmp, 1);
888  ast_channel_tech_pvt_set(tmp, i);
889  ast_channel_context_set(tmp, cntx);
890  if (!ast_strlen_zero(i->ext))
891  ast_channel_exten_set(tmp, i->ext);
892  else
893  ast_channel_exten_set(tmp, "s");
894  if (!ast_strlen_zero(i->language))
895  ast_channel_language_set(tmp, i->language);
896 
897  /* Don't use ast_set_callerid() here because it will
898  * generate a NewCallerID event before the NewChannel event */
899  if (!ast_strlen_zero(i->cid_num)) {
902  }
903 
904  i->owner = tmp;
906  ast_channel_unlock(tmp);
907  if (state != AST_STATE_DOWN) {
908  if (state == AST_STATE_RING) {
909  ioctl(ast_channel_fd(tmp, 0), PHONE_RINGBACK);
910  i->cpt = 1;
911  }
912  if (ast_pbx_start(tmp)) {
913  ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
914  ast_hangup(tmp);
915  }
916  }
917  } else {
918  ao2_cleanup(caps);
919  ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
920  }
921  return tmp;
922 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2837
Main Channel structure associated with a channel.
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
#define LOG_WARNING
Definition: logger.h:274
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4703
static int tmp()
Definition: bt_open.c:389
static struct ast_format_cap * prefcap
Definition: chan_phone.c:106
Definition of a media format.
Definition: format.c:43
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
static struct ast_channel_tech * cur_tech
Definition: chan_phone.c:209
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
#define ast_log
Definition: astobj2.c:42
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
struct ast_channel * owner
Definition: chan_phone.c:135
struct ast_module * self
Definition: module.h:342
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:428
void ast_channel_rings_set(struct ast_channel *chan, int value)
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
char language[MAX_LANGUAGE]
Definition: chan_phone.c:154
char ext[AST_MAX_EXTENSION]
Definition: chan_phone.c:153
char context[AST_MAX_EXTENSION]
Definition: chan_phone.c:151
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
char dev[256]
Definition: chan_phone.c:140
char cid_num[AST_MAX_EXTENSION]
Definition: chan_phone.c:155
#define ast_strlen_zero(a)
Definition: muted.c:73
#define ast_channel_unlock(chan)
Definition: channel.h:2838
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2523
#define MODE_FXS
Definition: chan_phone.c:130
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2406
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
int ast_channel_fd(const struct ast_channel *chan, int which)
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_channel_context_set(struct ast_channel *chan, const char *value)
const char * ast_channel_name(const struct ast_channel *chan)
int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
Remove format capability from capability structure.
Definition: format_cap.c:497
int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, enum ast_media_type type)
Append the formats of provided type in src to dst.
Definition: format_cap.c:269
char cid_name[AST_MAX_EXTENSION]
Definition: chan_phone.c:156
struct ast_format * ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
Get the format at a specific index.
Definition: format_cap.c:400
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1242
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443

◆ phone_read()

static struct ast_frame * phone_read ( struct ast_channel ast)
static

Definition at line 563 of file chan_phone.c.

References ast_channel_flags(), ast_channel_tech_pvt(), ast_clear_flag, AST_FLAG_BLOCKING, ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_get_type(), ast_format_slin, ast_frame_byteswap_le, AST_FRAME_IMAGE, AST_FRAME_NULL, AST_FRAME_VIDEO, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log, AST_MEDIA_TYPE_AUDIO, AST_MEDIA_TYPE_IMAGE, ast_tv(), phone_pvt::buf, CHECK_BLOCKING, ast_frame::data, ast_frame::datalen, ast_frame::delivery, errno, phone_pvt::fd, ast_frame_subclass::format, phone_pvt::fr, ast_frame::frametype, phone_pvt::lastinput, LOG_WARNING, ast_frame::mallocd, phone_pvt::mode, MODE_FXS, NULL, ast_frame::offset, PHONE_MAX_BUF, ast_frame::ptr, ast_frame::samples, ast_frame::src, and ast_frame::subclass.

564 {
565  int res;
566  struct phone_pvt *p = ast_channel_tech_pvt(ast);
567 
568 
569  /* Some nice norms */
570  p->fr.datalen = 0;
571  p->fr.samples = 0;
572  p->fr.data.ptr = NULL;
573  p->fr.src = "Phone";
574  p->fr.offset = 0;
575  p->fr.mallocd=0;
576  p->fr.delivery = ast_tv(0,0);
577 
578  /* Try to read some data... */
579  CHECK_BLOCKING(ast);
580  res = read(p->fd, p->buf, PHONE_MAX_BUF);
582  if (res < 0) {
583 #if 0
584  if (errno == EAGAIN) {
585  ast_log(LOG_WARNING, "Null frame received\n");
587  p->fr.subclass = 0;
588  return &p->fr;
589  }
590 #endif
591  ast_log(LOG_WARNING, "Error reading: %s\n", strerror(errno));
592  return NULL;
593  }
594  p->fr.data.ptr = p->buf;
595  if (p->mode != MODE_FXS)
596  switch(p->buf[0] & 0x3) {
597  case '0':
598  case '1':
599  /* Normal */
600  break;
601  case '2':
602  case '3':
603  /* VAD/CNG, only send two words */
604  res = 4;
605  break;
606  }
607  p->fr.samples = 240;
608  p->fr.datalen = res;
612  p->fr.subclass.format = p->lastinput;
614  /* Byteswap from little-endian to native-endian */
617  return &p->fr;
618 }
enum ast_media_type ast_format_get_type(const struct ast_format *format)
Get the media type of a format.
Definition: format.c:354
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define LOG_WARNING
Definition: logger.h:274
#define PHONE_MAX_BUF
Definition: chan_phone.c:90
struct ast_frame fr
Definition: chan_phone.c:142
#define NULL
Definition: resample.c:96
struct ast_frame_subclass subclass
char buf[PHONE_MAX_BUF]
Definition: chan_phone.c:144
union ast_frame::@255 data
#define ast_log
Definition: astobj2.c:42
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
const char * src
struct ast_format * lastinput
Definition: chan_phone.c:138
int errno
#define MODE_FXS
Definition: chan_phone.c:130
#define ast_clear_flag(p, flag)
Definition: utils.h:77
struct timeval delivery
#define CHECK_BLOCKING(c)
Set the blocking indication on the channel.
Definition: channel.h:2786
#define ast_frame_byteswap_le(fr)
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:226
enum ast_frame_type frametype
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
struct ast_format * format
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41

◆ phone_request()

static struct ast_channel * phone_request ( const char *  type,
struct ast_format_cap cap,
const struct ast_assigned_ids assignedids,
const struct ast_channel requestor,
const char *  data,
int *  cause 
)
static

Definition at line 1251 of file chan_phone.c.

References AST_CAUSE_BUSY, ast_format_cap_get_names(), ast_format_cap_iscompatible(), AST_FORMAT_CAP_NAMES_LEN, ast_log, ast_mutex_lock, ast_mutex_unlock, AST_STATE_DOWN, ast_str_alloca, ast_channel_tech::capabilities, phone_pvt::context, ast_channel::data, phone_pvt::dev, iflist, iflock, LOG_ERROR, LOG_NOTICE, phone_pvt::mode, MODE_FXS, name, phone_pvt::next, NULL, phone_pvt::owner, phone_new(), restart_monitor(), and tmp().

1252 {
1253  struct phone_pvt *p;
1254  struct ast_channel *tmp = NULL;
1255  const char *name = data;
1256 
1257  /* Search for an unowned channel */
1258  if (ast_mutex_lock(&iflock)) {
1259  ast_log(LOG_ERROR, "Unable to lock interface list???\n");
1260  return NULL;
1261  }
1262  p = iflist;
1263  while(p) {
1265  size_t length = strlen(p->dev + 5);
1266  if (strncmp(name, p->dev + 5, length) == 0 &&
1267  !isalnum(name[length])) {
1268  if (!p->owner) {
1269  tmp = phone_new(p, AST_STATE_DOWN, p->context, assignedids, requestor);
1270  break;
1271  } else
1272  *cause = AST_CAUSE_BUSY;
1273  }
1274  }
1275  p = p->next;
1276  }
1278  restart_monitor();
1279  if (tmp == NULL) {
1281  struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
1282  ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n",
1283  ast_format_cap_get_names(cap, &codec_buf));
1284  return NULL;
1285  }
1286  }
1287  return tmp;
1288 }
Main Channel structure associated with a channel.
static ast_mutex_t iflock
Definition: chan_phone.c:109
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:326
struct phone_pvt * next
Definition: chan_phone.c:141
static int tmp()
Definition: bt_open.c:389
static int restart_monitor(void)
Definition: chan_phone.c:1153
#define ast_mutex_lock(a)
Definition: lock.h:187
#define ast_str_alloca(init_len)
Definition: strings.h:800
#define NULL
Definition: resample.c:96
const char * data
static struct ast_channel_tech phone_tech
Definition: chan_phone.c:175
#define ast_log
Definition: astobj2.c:42
struct ast_channel * owner
Definition: chan_phone.c:135
#define LOG_ERROR
Definition: logger.h:285
char context[AST_MAX_EXTENSION]
Definition: chan_phone.c:151
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
char dev[256]
Definition: chan_phone.c:140
#define LOG_NOTICE
Definition: logger.h:263
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition: format_cap.c:736
struct ast_format_cap * capabilities
Definition: channel.h:633
static const char name[]
Definition: cdr_mysql.c:74
static struct ast_channel * phone_new(struct phone_pvt *i, int state, char *cntx, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
Definition: chan_phone.c:855
#define MODE_FXS
Definition: chan_phone.c:130
static struct phone_pvt * iflist
#define AST_CAUSE_BUSY
Definition: causes.h:148
#define ast_mutex_unlock(a)
Definition: lock.h:188
int ast_format_cap_iscompatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
Determine if any joint capabilities exist between two capabilities structures.
Definition: format_cap.c:655

◆ phone_send_text()

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

Definition at line 654 of file chan_phone.c.

References ast_channel_tech_pvt(), and phone_write_buf().

655 {
656  int length = strlen(text);
657  return phone_write_buf(ast_channel_tech_pvt(ast), text, length, length, 0) ==
658  length ? 0 : -1;
659 }
void * ast_channel_tech_pvt(const struct ast_channel *chan)
static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int frlen, int swap)
Definition: chan_phone.c:620
char * text
Definition: app_queue.c:1511

◆ phone_setup()

static int phone_setup ( struct ast_channel ast)
static

Definition at line 404 of file chan_phone.c.

References ao2_replace, ast_channel_rawreadformat(), ast_channel_tech_pvt(), ast_format_cmp(), AST_FORMAT_CMP_EQUAL, AST_FORMAT_CMP_NOT_EQUAL, ast_format_g723, ast_format_g729, ast_format_get_name(), ast_format_slin, ast_format_ulaw, ast_log, phone_pvt::fd, phone_pvt::lastinput, LOG_WARNING, phone_pvt::mode, and MODE_FXS.

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

405 {
406  struct phone_pvt *p;
407  p = ast_channel_tech_pvt(ast);
408  ioctl(p->fd, PHONE_CPT_STOP);
409  /* Nothing to answering really, just start recording */
411  /* Prefer g729 */
412  ioctl(p->fd, PHONE_REC_STOP);
415  if (ioctl(p->fd, PHONE_REC_CODEC, G729)) {
416  ast_log(LOG_WARNING, "Failed to set codec to g729\n");
417  return -1;
418  }
419  }
421  ioctl(p->fd, PHONE_REC_STOP);
424  if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
425  ast_log(LOG_WARNING, "Failed to set codec to g723.1\n");
426  return -1;
427  }
428  }
430  ioctl(p->fd, PHONE_REC_STOP);
433  if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
434  ast_log(LOG_WARNING, "Failed to set codec to signed linear 16\n");
435  return -1;
436  }
437  }
439  ioctl(p->fd, PHONE_REC_STOP);
442  if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) {
443  ast_log(LOG_WARNING, "Failed to set codec to uLaw\n");
444  return -1;
445  }
446  }
447  } else if (p->mode == MODE_FXS) {
448  ioctl(p->fd, PHONE_REC_STOP);
451  if (ioctl(p->fd, PHONE_REC_CODEC, ast_channel_rawreadformat(ast))) {
452  ast_log(LOG_WARNING, "Failed to set codec to %s\n",
454  return -1;
455  }
456  }
457  } else {
458  ast_log(LOG_WARNING, "Can't do format %s\n", ast_format_get_name(ast_channel_rawreadformat(ast)));
459  return -1;
460  }
461  if (ioctl(p->fd, PHONE_REC_START)) {
462  ast_log(LOG_WARNING, "Failed to start recording\n");
463  return -1;
464  }
465  /* set the DTMF times (the default is too short) */
466  ioctl(p->fd, PHONE_SET_TONE_ON_TIME, 300);
467  ioctl(p->fd, PHONE_SET_TONE_OFF_TIME, 200);
468  return 0;
469 }
struct ast_format * ast_format_g723
Built-in cached g723.1 format.
Definition: format_cache.c:151
void * ast_channel_tech_pvt(const struct ast_channel *chan)
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
Definition: format_cache.c:86
#define LOG_WARNING
Definition: logger.h:274
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
#define ast_log
Definition: astobj2.c:42
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
struct ast_format * ast_channel_rawreadformat(struct ast_channel *chan)
struct ast_format * lastinput
Definition: chan_phone.c:138
#define MODE_FXS
Definition: chan_phone.c:130
#define ao2_replace(dst, src)
Definition: astobj2.h:517
struct ast_format * ast_format_g729
Built-in cached g729 format.
Definition: format_cache.c:156
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41

◆ phone_write()

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

Definition at line 661 of file chan_phone.c.

References ao2_replace, ast_channel_tech_pvt(), ast_format_cmp(), AST_FORMAT_CMP_EQUAL, ast_format_compatibility_format2bitfield(), ast_format_g723, ast_format_g729, ast_format_get_name(), ast_format_slin, 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_subclass::format, ast_frame::frametype, phone_pvt::lastformat, phone_pvt::lastinput, LOG_WARNING, phone_pvt::mode, MODE_FXS, phone_pvt::obuflen, phone_setup(), phone_write_buf(), ast_frame::ptr, phone_pvt::silencesupression, and ast_frame::subclass.

662 {
663  struct phone_pvt *p = ast_channel_tech_pvt(ast);
664  int res;
665  int maxfr=0;
666  char *pos;
667  int sofar;
668  int expected;
669  int codecset = 0;
670  char tmpbuf[4];
671  /* Write a frame of (presumably voice) data */
672  if (frame->frametype != AST_FRAME_VOICE && p->mode != MODE_FXS) {
673  if (frame->frametype != AST_FRAME_IMAGE)
674  ast_log(LOG_WARNING, "Don't know what to do with frame type '%u'\n", frame->frametype);
675  return 0;
676  }
677 #if 0
678  /* If we're not in up mode, go into up mode now */
679  if (ast->_state != AST_STATE_UP) {
681  phone_setup(ast);
682  }
683 #else
684  if (ast_channel_state(ast) != AST_STATE_UP) {
685  /* Don't try tos end audio on-hook */
686  return 0;
687  }
688 #endif
691  ioctl(p->fd, PHONE_PLAY_STOP);
692  ioctl(p->fd, PHONE_REC_STOP);
693  if (ioctl(p->fd, PHONE_PLAY_CODEC, G729)) {
694  ast_log(LOG_WARNING, "Unable to set G729 mode\n");
695  return -1;
696  }
697  if (ioctl(p->fd, PHONE_REC_CODEC, G729)) {
698  ast_log(LOG_WARNING, "Unable to set G729 mode\n");
699  return -1;
700  }
703  /* Reset output buffer */
704  p->obuflen = 0;
705  codecset = 1;
706  }
707  if (frame->datalen > 80) {
708  ast_log(LOG_WARNING, "Frame size too large for G.729 (%d bytes)\n", frame->datalen);
709  return -1;
710  }
711  maxfr = 80;
714  ioctl(p->fd, PHONE_PLAY_STOP);
715  ioctl(p->fd, PHONE_REC_STOP);
716  if (ioctl(p->fd, PHONE_PLAY_CODEC, G723_63)) {
717  ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
718  return -1;
719  }
720  if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {
721  ast_log(LOG_WARNING, "Unable to set G723.1 mode\n");
722  return -1;
723  }
726  /* Reset output buffer */
727  p->obuflen = 0;
728  codecset = 1;
729  }
730  if (frame->datalen > 24) {
731  ast_log(LOG_WARNING, "Frame size too large for G.723.1 (%d bytes)\n", frame->datalen);
732  return -1;
733  }
734  maxfr = 24;
737  ioctl(p->fd, PHONE_PLAY_STOP);
738  ioctl(p->fd, PHONE_REC_STOP);
739  if (ioctl(p->fd, PHONE_PLAY_CODEC, LINEAR16)) {
740  ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
741  return -1;
742  }
743  if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {
744  ast_log(LOG_WARNING, "Unable to set 16-bit linear mode\n");
745  return -1;
746  }
749  codecset = 1;
750  /* Reset output buffer */
751  p->obuflen = 0;
752  }
753  maxfr = 480;
756  ioctl(p->fd, PHONE_PLAY_STOP);
757  ioctl(p->fd, PHONE_REC_STOP);
758  if (ioctl(p->fd, PHONE_PLAY_CODEC, ULAW)) {
759  ast_log(LOG_WARNING, "Unable to set uLaw mode\n");
760  return -1;
761  }
762  if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) {
763  ast_log(LOG_WARNING, "Unable to set uLaw mode\n");
764  return -1;
765  }
768  codecset = 1;
769  /* Reset output buffer */
770  p->obuflen = 0;
771  }
772  maxfr = 240;
773  } else {
775  ioctl(p->fd, PHONE_PLAY_STOP);
776  ioctl(p->fd, PHONE_REC_STOP);
777  if (ioctl(p->fd, PHONE_PLAY_CODEC, ast_format_compatibility_format2bitfield(frame->subclass.format))) {
778  ast_log(LOG_WARNING, "Unable to set %s mode\n",
780  return -1;
781  }
782  if (ioctl(p->fd, PHONE_REC_CODEC, ast_format_compatibility_format2bitfield(frame->subclass.format))) {
783  ast_log(LOG_WARNING, "Unable to set %s mode\n",
785  return -1;
786  }
788  ao2_replace(p->lastinput, frame->subclass.format);
789  codecset = 1;
790  /* Reset output buffer */
791  p->obuflen = 0;
792  }
793  maxfr = 480;
794  }
795  if (codecset) {
796  ioctl(p->fd, PHONE_REC_DEPTH, 3);
797  ioctl(p->fd, PHONE_PLAY_DEPTH, 3);
798  if (ioctl(p->fd, PHONE_PLAY_START)) {
799  ast_log(LOG_WARNING, "Failed to start playback\n");
800  return -1;
801  }
802  if (ioctl(p->fd, PHONE_REC_START)) {
803  ast_log(LOG_WARNING, "Failed to start recording\n");
804  return -1;
805  }
806  }
807  /* If we get here, we have a frame of Appropriate data */
808  sofar = 0;
809  pos = frame->data.ptr;
810  while(sofar < frame->datalen) {
811  /* Write in no more than maxfr sized frames */
812  expected = frame->datalen - sofar;
813  if (maxfr < expected)
814  expected = maxfr;
815  /* XXX Internet Phone Jack does not handle the 4-byte VAD frame properly! XXX
816  we have to pad it to 24 bytes still. */
817  if (frame->datalen == 4) {
818  if (p->silencesupression) {
819  memcpy(tmpbuf, frame->data.ptr, 4);
820  expected = 24;
821  res = phone_write_buf(p, tmpbuf, expected, maxfr, 0);
822  }
823  res = 4;
824  expected=4;
825  } else {
826  int swap = 0;
827 #if __BYTE_ORDER == __BIG_ENDIAN
829  swap = 1; /* Swap big-endian samples to little-endian as we copy */
830 #endif
831  res = phone_write_buf(p, pos, expected, maxfr, swap);
832  }
833  if (res != expected) {
834  if ((errno != EAGAIN) && (errno != EINTR)) {
835  if (res < 0)
836  ast_log(LOG_WARNING, "Write returned error (%s)\n", strerror(errno));
837  /*
838  * Card is in non-blocking mode now and it works well now, but there are
839  * lot of messages like this. So, this message is temporarily disabled.
840  */
841 #if 0
842  else
843  ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frame->datalen);
844 #endif
845  return -1;
846  } else /* Pretend it worked */
847  res = expected;
848  }
849  sofar += res;
850  pos += res;
851  }
852  return 0;
853 }
struct ast_format * ast_format_g723
Built-in cached g723.1 format.
Definition: format_cache.c:151
struct ast_format * lastformat
Definition: chan_phone.c:137
uint64_t ast_format_compatibility_format2bitfield(const struct ast_format *format)
Convert a format structure to its respective bitfield.
void * ast_channel_tech_pvt(const struct ast_channel *chan)
static int phone_setup(struct ast_channel *ast)
Definition: chan_phone.c:404
static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int frlen, int swap)
Definition: chan_phone.c:620
int silencesupression
Definition: chan_phone.c:150
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
Definition: format_cache.c:86
#define LOG_WARNING
Definition: logger.h:274
ast_channel_state
ast_channel states
Definition: channelstate.h:35
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
struct ast_frame_subclass subclass
union ast_frame::@255 data
#define ast_log
Definition: astobj2.c:42
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
struct ast_format * lastinput
Definition: chan_phone.c:138
int errno
#define MODE_FXS
Definition: chan_phone.c:130
#define ao2_replace(dst, src)
Definition: astobj2.h:517
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7325
enum ast_frame_type frametype
struct ast_format * ast_format_g729
Built-in cached g729 format.
Definition: format_cache.c:156
struct ast_format * format
int obuflen
Definition: chan_phone.c:145
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41

◆ phone_write_buf()

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

Definition at line 620 of file chan_phone.c.

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

Referenced by phone_send_text(), and phone_write().

621 {
622  int res;
623  /* Store as much of the buffer as we can, then write fixed frames */
624  int space = sizeof(p->obuf) - p->obuflen;
625  /* Make sure we have enough buffer space to store the frame */
626  if (space < len)
627  len = space;
628  if (swap)
630  else
631  memcpy(p->obuf + p->obuflen, buf, len);
632  p->obuflen += len;
633  while(p->obuflen > frlen) {
634  res = write(p->fd, p->obuf, frlen);
635  if (res != frlen) {
636  if (res < 1) {
637 /*
638  * Card is in non-blocking mode now and it works well now, but there are
639  * lot of messages like this. So, this message is temporarily disabled.
640  */
641  return 0;
642  } else {
643  ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frlen);
644  }
645  }
646  p->obuflen -= frlen;
647  /* Move memory if necessary */
648  if (p->obuflen)
649  memmove(p->obuf, p->obuf + frlen, p->obuflen);
650  }
651  return len;
652 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
void ast_swapcopy_samples(void *dst, const void *src, int samples)
Definition: main/frame.c:387
if(!yyg->yy_init)
Definition: ast_expr2f.c:868
#define ast_log
Definition: astobj2.c:42
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
char obuf[PHONE_MAX_BUF *2]
Definition: chan_phone.c:152
int obuflen
Definition: chan_phone.c:145

◆ restart_monitor()

static int restart_monitor ( void  )
static

Definition at line 1153 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, monitor, monitor_thread, monlock, and NULL.

Referenced by load_module(), phone_hangup(), and phone_request().

1154 {
1155  /* If we're supposed to be stopped -- stay stopped */
1157  return 0;
1158  if (ast_mutex_lock(&monlock)) {
1159  ast_log(LOG_WARNING, "Unable to lock monitor\n");
1160  return -1;
1161  }
1162  if (monitor_thread == pthread_self()) {
1164  ast_log(LOG_WARNING, "Cannot kill myself\n");
1165  return -1;
1166  }
1168  if (ast_mutex_lock(&iflock)) {
1170  ast_log(LOG_WARNING, "Unable to lock the interface list\n");
1171  return -1;
1172  }
1173  monitor = 0;
1174  while (pthread_kill(monitor_thread, SIGURG) == 0)
1175  sched_yield();
1176  pthread_join(monitor_thread, NULL);
1178  }
1179  monitor = 1;
1180  /* Start a new monitor */
1183  ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
1184  return -1;
1185  }
1187  return 0;
1188 }
static pthread_t monitor_thread
Definition: chan_phone.c:120
static void * do_monitor(void *data)
Definition: chan_phone.c:1031
static ast_mutex_t iflock
Definition: chan_phone.c:109
#define LOG_WARNING
Definition: logger.h:274
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
static ast_mutex_t monlock
Definition: chan_phone.c:113
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:507
#define ast_log
Definition: astobj2.c:42
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define LOG_ERROR
Definition: logger.h:285
static unsigned int monitor
Definition: chan_phone.c:116
#define AST_PTHREADT_STOP
Definition: lock.h:67
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1373 of file chan_phone.c.

References __unload_module().

1374 {
1375  return __unload_module();
1376 }
static int __unload_module(void)
Definition: chan_phone.c:1313

Variable Documentation

◆ cid_name

char cid_name[AST_MAX_EXTENSION]
static

Definition at line 160 of file chan_phone.c.

◆ cid_num

char cid_num[AST_MAX_EXTENSION]
static

Definition at line 159 of file chan_phone.c.

◆ config

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

Definition at line 94 of file chan_phone.c.

Referenced by load_module(), and parse_gain_value().

◆ context

char context[AST_MAX_EXTENSION] = "default"
static

Definition at line 97 of file chan_phone.c.

◆ cur_tech

struct ast_channel_tech* cur_tech
static

Definition at line 209 of file chan_phone.c.

◆ echocancel

int echocancel = AEC_OFF
static

Definition at line 102 of file chan_phone.c.

Referenced by load_module(), and mkif().

◆ iflist

struct phone_pvt * iflist = NULL
static

◆ iflock

ast_mutex_t iflock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
static

◆ language

char language[MAX_LANGUAGE] = ""
static

Definition at line 100 of file chan_phone.c.

◆ monitor

unsigned int monitor
static

◆ monitor_thread

pthread_t monitor_thread = AST_PTHREADT_NULL
static

Definition at line 120 of file chan_phone.c.

Referenced by __unload_module(), and restart_monitor().

◆ monlock

ast_mutex_t monlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
static

Definition at line 113 of file chan_phone.c.

Referenced by __unload_module(), and restart_monitor().

◆ phone_tech

struct ast_channel_tech phone_tech
static

Definition at line 175 of file chan_phone.c.

◆ phone_tech_fxs

struct ast_channel_tech phone_tech_fxs
static

Definition at line 191 of file chan_phone.c.

Referenced by load_module().

◆ prefcap

struct ast_format_cap* prefcap
static

Definition at line 106 of file chan_phone.c.

◆ silencesupression

int silencesupression = 0
static

Definition at line 104 of file chan_phone.c.

◆ tdesc

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

Definition at line 93 of file chan_phone.c.