Fri Jun 19 12:09:56 2009

Asterisk developer's documentation


app_dahdiscan.c File Reference

DAHDI Scanner. More...

#include "asterisk.h"
#include <dahdi/user.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/options.h"

Go to the source code of this file.

Defines

#define CONF_SIZE   160

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int careful_write (int fd, unsigned char *data, int len)
static int conf_exec (struct ast_channel *chan, void *data)
static int conf_run (struct ast_channel *chan, int confno, int confflags)
static struct ast_channelget_dahdi_channel_locked (int num)
static int load_module (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Scan DAHDI channels application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, }
static char * app = "DAHDIScan"
static struct ast_module_infoast_module_info = &__mod_info
static char * descrip
static char * synopsis = "Scan DAHDI channels to monitor calls"


Detailed Description

DAHDI Scanner.

Author:
Mark Spencer <markster@digium.com>

Definition in file app_dahdiscan.c.


Define Documentation

#define CONF_SIZE   160

Definition at line 65 of file app_dahdiscan.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 369 of file app_dahdiscan.c.

static void __unreg_module ( void   )  [static]

Definition at line 369 of file app_dahdiscan.c.

static int careful_write ( int  fd,
unsigned char *  data,
int  len 
) [static]

Definition at line 74 of file app_dahdiscan.c.

References ast_log(), errno, and LOG_WARNING.

00075 {
00076    int res;
00077    while (len) {
00078       res = write(fd, data, len);
00079       if (res < 1) {
00080          if (errno != EAGAIN) {
00081             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00082             return -1;
00083          } else {
00084             return 0;
00085          }
00086       }
00087       len -= res;
00088       data += res;
00089    }
00090    return 0;
00091 }

static int conf_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 282 of file app_dahdiscan.c.

References ast_channel::_state, ast_answer(), ast_channel_unlock, ast_channel_walk_locked(), ast_copy_string(), AST_DIGIT_ANY, AST_FRAME_DTMF, ast_frfree, ast_read(), ast_say_number(), AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_waitfor(), chan, conf_run(), f, get_dahdi_channel_locked(), input(), ast_channel::name, pbx_builtin_getvar_helper(), ast_channel::tech, and ast_channel_tech::type.

00283 {
00284    int res=-1;
00285    int confflags = 0;
00286    int confno = 0;
00287    char confnostr[80] = "", *tmp = NULL;
00288    struct ast_channel *tempchan = NULL, *lastchan = NULL, *ichan = NULL;
00289    struct ast_frame *f;
00290    char *desired_group;
00291    int input = 0, search_group = 0;
00292 
00293    if (chan->_state != AST_STATE_UP)
00294       ast_answer(chan);
00295 
00296    desired_group = ast_strdupa(data);
00297    if (!ast_strlen_zero(desired_group)) {
00298       ast_verb(3, "Scanning for group %s\n", desired_group);
00299       search_group = 1;
00300    }
00301 
00302    for (;;) {
00303       if (ast_waitfor(chan, 100) < 0)
00304          break;
00305 
00306       f = ast_read(chan);
00307       if (!f)
00308          break;
00309       if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
00310          ast_frfree(f);
00311          break;
00312       }
00313       ast_frfree(f);
00314       ichan = NULL;
00315       if(input) {
00316          ichan = get_dahdi_channel_locked(input);
00317          input = 0;
00318       }
00319 
00320       tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan);
00321 
00322       if (!tempchan && !lastchan) {
00323          break;
00324       }
00325 
00326       if (tempchan && search_group) {
00327          const char *mygroup;
00328          if ((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) {
00329             ast_verb(3, "Found Matching Channel %s in group %s\n", tempchan->name, desired_group);
00330          } else {
00331             ast_channel_unlock(tempchan);
00332             lastchan = tempchan;
00333             continue;
00334          }
00335       }
00336       if (tempchan && (!strcmp(tempchan->tech->type, "DAHDI")) && (tempchan != chan)) {
00337          ast_verb(3, "DAHDI channel %s is in-use, monitoring...\n", tempchan->name);
00338          ast_copy_string(confnostr, tempchan->name, sizeof(confnostr));
00339          ast_channel_unlock(tempchan);
00340          if ((tmp = strchr(confnostr, '-'))) {
00341             *tmp = '\0';
00342          }
00343          confno = atoi(strchr(confnostr, '/') + 1);
00344          ast_stopstream(chan);
00345          ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL);
00346          res = conf_run(chan, confno, confflags);
00347          if (res < 0) {
00348             break;
00349          }
00350          input = res;
00351       } else if (tempchan) {
00352          ast_channel_unlock(tempchan);
00353       }
00354       lastchan = tempchan;
00355    }
00356    return res;
00357 }

static int conf_run ( struct ast_channel chan,
int  confno,
int  confflags 
) [static]

Definition at line 93 of file app_dahdiscan.c.

References ast_debug, AST_FORMAT_ULAW, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, AST_FRIENDLY_OFFSET, ast_indicate(), ast_log(), ast_read(), ast_set_read_format(), ast_set_write_format(), ast_verb, ast_waitfor_nandfds(), ast_write(), buf, careful_write(), chan, CONF_SIZE, errno, f, ast_channel::fds, ast_frame::flags, input(), LOG_WARNING, ast_channel::name, ast_channel::tech, and ast_channel_tech::type.

00094 {
00095    int fd;
00096    struct dahdi_confinfo dahdic;
00097    struct ast_frame *f;
00098    struct ast_channel *c;
00099    struct ast_frame fr;
00100    int outfd;
00101    int ms;
00102    int nfds;
00103    int res;
00104    int flags;
00105    int retrydahdi;
00106    int origfd;
00107    int ret = -1;
00108    char input[4];
00109    int ic = 0;
00110    
00111    struct dahdi_bufferinfo bi;
00112    char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
00113    char *buf = __buf + AST_FRIENDLY_OFFSET;
00114    
00115    /* Set it into U-law mode (write) */
00116    if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
00117       ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
00118       goto outrun;
00119    }
00120    
00121    /* Set it into U-law mode (read) */
00122    if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
00123       ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
00124       goto outrun;
00125    }
00126    ast_indicate(chan, -1);
00127    retrydahdi = strcasecmp(chan->tech->type, "DAHDI");
00128  dahdiretry:
00129    origfd = chan->fds[0];
00130    if (retrydahdi) {
00131       fd = open("/dev/dahdi/pseudo", O_RDWR);
00132       if (fd < 0) {
00133          ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
00134          goto outrun;
00135       }
00136       /* Make non-blocking */
00137       flags = fcntl(fd, F_GETFL);
00138       if (flags < 0) {
00139          ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
00140          close(fd);
00141          goto outrun;
00142       }
00143       if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
00144          ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
00145          close(fd);
00146          goto outrun;
00147       }
00148       /* Setup buffering information */
00149       memset(&bi, 0, sizeof(bi));
00150       bi.bufsize = CONF_SIZE;
00151       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
00152       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
00153       bi.numbufs = 4;
00154       if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
00155          ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
00156          close(fd);
00157          goto outrun;
00158       }
00159       nfds = 1;
00160    } else {
00161       /* XXX Make sure we're not running on a pseudo channel XXX */
00162       fd = chan->fds[0];
00163       nfds = 0;
00164    }
00165    memset(&dahdic, 0, sizeof(dahdic));
00166    /* Check to see if we're in a conference... */
00167    dahdic.chan = 0;
00168    if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
00169       ast_log(LOG_WARNING, "Error getting conference\n");
00170       close(fd);
00171       goto outrun;
00172    }
00173    if (dahdic.confmode) {
00174       /* Whoa, already in a conference...  Retry... */
00175       if (!retrydahdi) {
00176          ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
00177          retrydahdi = 1;
00178          goto dahdiretry;
00179       }
00180    }
00181    memset(&dahdic, 0, sizeof(dahdic));
00182    /* Add us to the conference */
00183    dahdic.chan = 0;
00184    dahdic.confno = confno;
00185    dahdic.confmode = DAHDI_CONF_MONITORBOTH;
00186 
00187    if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
00188       ast_log(LOG_WARNING, "Error setting conference\n");
00189       close(fd);
00190       goto outrun;
00191    }
00192    ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", chan->name, confno);
00193 
00194    for (;;) {
00195       outfd = -1;
00196       ms = -1;
00197       c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
00198       if (c) {
00199          if (c->fds[0] != origfd) {
00200             if (retrydahdi) {
00201                /* Kill old pseudo */
00202                close(fd);
00203             }
00204             ast_debug(1, "Ooh, something swapped out under us, starting over\n");
00205             retrydahdi = 0;
00206             goto dahdiretry;
00207          }
00208          f = ast_read(c);
00209          if (!f) {
00210             break;
00211          }
00212          if (f->frametype == AST_FRAME_DTMF) {
00213             if (f->subclass == '#') {
00214                ret = 0;
00215                break;
00216             } else if (f->subclass == '*') {
00217                ret = -1;
00218                break;
00219             } else {
00220                input[ic++] = f->subclass;
00221             }
00222             if (ic == 3) {
00223                input[ic++] = '\0';
00224                ic = 0;
00225                ret = atoi(input);
00226                ast_verb(3, "DAHDIScan: change channel to %d\n", ret);
00227                break;
00228             }
00229          }
00230 
00231          if (fd != chan->fds[0]) {
00232             if (f->frametype == AST_FRAME_VOICE) {
00233                if (f->subclass == AST_FORMAT_ULAW) {
00234                   /* Carefully write */
00235                   careful_write(fd, f->data.ptr, f->datalen);
00236                } else {
00237                   ast_log(LOG_WARNING, "Huh?  Got a non-ulaw (%d) frame in the conference\n", f->subclass);
00238                }
00239             }
00240          }
00241          ast_frfree(f);
00242       } else if (outfd > -1) {
00243          res = read(outfd, buf, CONF_SIZE);
00244          if (res > 0) {
00245             memset(&fr, 0, sizeof(fr));
00246             fr.frametype = AST_FRAME_VOICE;
00247             fr.subclass = AST_FORMAT_ULAW;
00248             fr.datalen = res;
00249             fr.samples = res;
00250             fr.data.ptr = buf;
00251             fr.offset = AST_FRIENDLY_OFFSET;
00252             if (ast_write(chan, &fr) < 0) {
00253                ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
00254                /* break; */
00255             }
00256          } else {
00257             ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
00258          }
00259       }
00260    }
00261    if (f) {
00262       ast_frfree(f);
00263    }
00264    if (fd != chan->fds[0]) {
00265       close(fd);
00266    } else {
00267       /* Take out of conference */
00268       /* Add us to the conference */
00269       dahdic.chan = 0;
00270       dahdic.confno = 0;
00271       dahdic.confmode = 0;
00272       if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
00273          ast_log(LOG_WARNING, "Error setting conference\n");
00274       }
00275    }
00276 
00277  outrun:
00278 
00279    return ret;
00280 }

static struct ast_channel* get_dahdi_channel_locked ( int  num  )  [static]

Definition at line 67 of file app_dahdiscan.c.

References ast_get_channel_by_name_locked(), and name.

Referenced by conf_exec().

00067                                                              {
00068    char name[80];
00069    
00070    snprintf(name, sizeof(name), "DAHDI/%d-1", num);
00071    return ast_get_channel_by_name_locked(name);
00072 }

static int load_module ( void   )  [static]

Definition at line 364 of file app_dahdiscan.c.

References AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_register_application, and conf_exec().

static int unload_module ( void   )  [static]

Definition at line 359 of file app_dahdiscan.c.

References ast_unregister_application().

00360 {
00361    return ast_unregister_application(app);
00362 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Scan DAHDI channels application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static]

Definition at line 369 of file app_dahdiscan.c.

char* app = "DAHDIScan" [static]

Definition at line 55 of file app_dahdiscan.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 369 of file app_dahdiscan.c.

char* descrip [static]

Initial value:

"  DAHDIScan([group]) allows a call center manager to monitor DAHDI channels in\n"
"a convenient way.  Use '#' to select the next channel and use '*' to exit\n"
"Limit scanning to a channel GROUP by setting the option group argument.\n"

Definition at line 59 of file app_dahdiscan.c.

char* synopsis = "Scan DAHDI channels to monitor calls" [static]

Definition at line 57 of file app_dahdiscan.c.


Generated on Fri Jun 19 12:09:56 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7