Thu Apr 28 2011 17:13:36

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"
Include dependency graph for app_dahdiscan.c:

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
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Scan DAHDI channels application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, }
static char * app = "DAHDIScan"
static struct ast_module_infoast_module_info = &__mod_info

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 73 of file app_dahdiscan.c.

Referenced by conf_run().


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 377 of file app_dahdiscan.c.

static void __unreg_module ( void  ) [static]

Definition at line 377 of file app_dahdiscan.c.

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

Definition at line 82 of file app_dahdiscan.c.

References ast_log(), errno, and LOG_WARNING.

Referenced by conf_run().

{
   int res;
   while (len) {
      res = write(fd, data, len);
      if (res < 1) {
         if (errno != EAGAIN) {
            ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
            return -1;
         } else {
            return 0;
         }
      }
      len -= res;
      data += res;
   }
   return 0;
}
static int conf_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 290 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(), conf_run(), f, ast_frame::frametype, get_dahdi_channel_locked(), input(), ast_channel::language, ast_channel::name, pbx_builtin_getvar_helper(), ast_frame::subclass, ast_channel::tech, and ast_channel_tech::type.

Referenced by load_module().

{
   int res=-1;
   int confflags = 0;
   int confno = 0;
   char confnostr[80] = "", *tmp = NULL;
   struct ast_channel *tempchan = NULL, *lastchan = NULL, *ichan = NULL;
   struct ast_frame *f;
   char *desired_group;
   int input = 0, search_group = 0;

   if (chan->_state != AST_STATE_UP)
      ast_answer(chan);

   desired_group = ast_strdupa(data);
   if (!ast_strlen_zero(desired_group)) {
      ast_verb(3, "Scanning for group %s\n", desired_group);
      search_group = 1;
   }

   for (;;) {
      if (ast_waitfor(chan, 100) < 0)
         break;

      f = ast_read(chan);
      if (!f)
         break;
      if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
         ast_frfree(f);
         break;
      }
      ast_frfree(f);
      ichan = NULL;
      if(input) {
         ichan = get_dahdi_channel_locked(input);
         input = 0;
      }

      tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan);

      if (!tempchan && !lastchan) {
         break;
      }

      if (tempchan && search_group) {
         const char *mygroup;
         if ((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) {
            ast_verb(3, "Found Matching Channel %s in group %s\n", tempchan->name, desired_group);
         } else {
            ast_channel_unlock(tempchan);
            lastchan = tempchan;
            continue;
         }
      }
      if (tempchan && (!strcmp(tempchan->tech->type, "DAHDI")) && (tempchan != chan)) {
         ast_verb(3, "DAHDI channel %s is in-use, monitoring...\n", tempchan->name);
         ast_copy_string(confnostr, tempchan->name, sizeof(confnostr));
         ast_channel_unlock(tempchan);
         if ((tmp = strchr(confnostr, '-'))) {
            *tmp = '\0';
         }
         confno = atoi(strchr(confnostr, '/') + 1);
         ast_stopstream(chan);
         ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL);
         res = conf_run(chan, confno, confflags);
         if (res < 0) {
            break;
         }
         input = res;
      } else if (tempchan) {
         ast_channel_unlock(tempchan);
      }
      lastchan = tempchan;
   }
   return res;
}
static int conf_run ( struct ast_channel chan,
int  confno,
int  confflags 
) [static]

Definition at line 101 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(), CONF_SIZE, ast_frame::data, ast_frame::datalen, errno, f, ast_channel::fds, ast_frame::flags, ast_frame::frametype, input(), LOG_WARNING, ast_channel::name, ast_frame::offset, ast_frame::ptr, ast_frame::samples, ast_frame::subclass, ast_channel::tech, and ast_channel_tech::type.

Referenced by conf_exec().

{
   int fd;
   struct dahdi_confinfo dahdic;
   struct ast_frame *f;
   struct ast_channel *c;
   struct ast_frame fr;
   int outfd;
   int ms;
   int nfds;
   int res;
   int flags;
   int retrydahdi;
   int origfd;
   int ret = -1;
   char input[4];
   int ic = 0;
   
   struct dahdi_bufferinfo bi;
   char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
   char *buf = __buf + AST_FRIENDLY_OFFSET;
   
   /* Set it into U-law mode (write) */
   if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
      ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
      goto outrun;
   }
   
   /* Set it into U-law mode (read) */
   if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
      ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
      goto outrun;
   }
   ast_indicate(chan, -1);
   retrydahdi = strcasecmp(chan->tech->type, "DAHDI");
 dahdiretry:
   origfd = chan->fds[0];
   if (retrydahdi) {
      fd = open("/dev/dahdi/pseudo", O_RDWR);
      if (fd < 0) {
         ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
         goto outrun;
      }
      /* Make non-blocking */
      flags = fcntl(fd, F_GETFL);
      if (flags < 0) {
         ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
         close(fd);
         goto outrun;
      }
      if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
         ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
         close(fd);
         goto outrun;
      }
      /* Setup buffering information */
      memset(&bi, 0, sizeof(bi));
      bi.bufsize = CONF_SIZE;
      bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
      bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
      bi.numbufs = 4;
      if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
         ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
         close(fd);
         goto outrun;
      }
      nfds = 1;
   } else {
      /* XXX Make sure we're not running on a pseudo channel XXX */
      fd = chan->fds[0];
      nfds = 0;
   }
   memset(&dahdic, 0, sizeof(dahdic));
   /* Check to see if we're in a conference... */
   dahdic.chan = 0;
   if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
      ast_log(LOG_WARNING, "Error getting conference\n");
      close(fd);
      goto outrun;
   }
   if (dahdic.confmode) {
      /* Whoa, already in a conference...  Retry... */
      if (!retrydahdi) {
         ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
         retrydahdi = 1;
         goto dahdiretry;
      }
   }
   memset(&dahdic, 0, sizeof(dahdic));
   /* Add us to the conference */
   dahdic.chan = 0;
   dahdic.confno = confno;
   dahdic.confmode = DAHDI_CONF_MONITORBOTH;

   if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
      ast_log(LOG_WARNING, "Error setting conference\n");
      close(fd);
      goto outrun;
   }
   ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", chan->name, confno);

   for (;;) {
      outfd = -1;
      ms = -1;
      c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
      if (c) {
         if (c->fds[0] != origfd) {
            if (retrydahdi) {
               /* Kill old pseudo */
               close(fd);
            }
            ast_debug(1, "Ooh, something swapped out under us, starting over\n");
            retrydahdi = 0;
            goto dahdiretry;
         }
         f = ast_read(c);
         if (!f) {
            break;
         }
         if (f->frametype == AST_FRAME_DTMF) {
            if (f->subclass == '#') {
               ret = 0;
               break;
            } else if (f->subclass == '*') {
               ret = -1;
               break;
            } else {
               input[ic++] = f->subclass;
            }
            if (ic == 3) {
               input[ic++] = '\0';
               ic = 0;
               ret = atoi(input);
               ast_verb(3, "DAHDIScan: change channel to %d\n", ret);
               break;
            }
         }

         if (fd != chan->fds[0]) {
            if (f->frametype == AST_FRAME_VOICE) {
               if (f->subclass == AST_FORMAT_ULAW) {
                  /* Carefully write */
                  careful_write(fd, f->data.ptr, f->datalen);
               } else {
                  ast_log(LOG_WARNING, "Huh?  Got a non-ulaw (%d) frame in the conference\n", f->subclass);
               }
            }
         }
         ast_frfree(f);
      } else if (outfd > -1) {
         res = read(outfd, buf, CONF_SIZE);
         if (res > 0) {
            memset(&fr, 0, sizeof(fr));
            fr.frametype = AST_FRAME_VOICE;
            fr.subclass = AST_FORMAT_ULAW;
            fr.datalen = res;
            fr.samples = res;
            fr.data.ptr = buf;
            fr.offset = AST_FRIENDLY_OFFSET;
            if (ast_write(chan, &fr) < 0) {
               ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
               /* break; */
            }
         } else {
            ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
         }
      }
   }
   if (f) {
      ast_frfree(f);
   }
   if (fd != chan->fds[0]) {
      close(fd);
   } else {
      /* Take out of conference */
      /* Add us to the conference */
      dahdic.chan = 0;
      dahdic.confno = 0;
      dahdic.confmode = 0;
      if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
         ast_log(LOG_WARNING, "Error setting conference\n");
      }
   }

 outrun:

   return ret;
}
static struct ast_channel* get_dahdi_channel_locked ( int  num) [static, read]

Definition at line 75 of file app_dahdiscan.c.

References ast_get_channel_by_name_locked(), and name.

Referenced by conf_exec().

                                                             {
   char name[80];
   
   snprintf(name, sizeof(name), "DAHDI/%d-1", num);
   return ast_get_channel_by_name_locked(name);
}
static int unload_module ( void  ) [static]

Definition at line 367 of file app_dahdiscan.c.

References ast_unregister_application().


Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Scan DAHDI channels application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static]

Definition at line 377 of file app_dahdiscan.c.

char* app = "DAHDIScan" [static]

Definition at line 71 of file app_dahdiscan.c.

Definition at line 377 of file app_dahdiscan.c.