Mon Mar 12 2012 21:25:21

Asterisk developer's documentation


app_talkdetect.c File Reference

Playback a file with audio detect. More...

#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/utils.h"
#include "asterisk/dsp.h"
#include "asterisk/app.h"
Include dependency graph for app_talkdetect.c:

Go to the source code of this file.

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int background_detect_exec (struct ast_channel *chan, const char *data)
static int load_module (void)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Playback with Talk Detection" , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
static char * app = "BackgroundDetect"
static struct ast_module_infoast_module_info = &__mod_info

Detailed Description

Playback a file with audio detect.

Author:
Mark Spencer <markster@digium.com>

Definition in file app_talkdetect.c.


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 256 of file app_talkdetect.c.

static void __unreg_module ( void  ) [static]

Definition at line 256 of file app_talkdetect.c.

static int background_detect_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 80 of file app_talkdetect.c.

References ast_channel::_state, args, ast_answer(), AST_APP_ARG, ast_canmatch_extension(), ast_debug, AST_DECLARE_APP_ARGS, ast_dsp_free(), ast_dsp_new(), ast_dsp_silence(), AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, ast_getformatname(), ast_goto_if_exists(), ast_log(), ast_read(), ast_sched_runq(), ast_sched_wait(), ast_set_read_format(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitfor(), ast_channel::caller, ast_frame_subclass::codec, ast_channel::context, ast_frame::frametype, ast_party_caller::id, ast_frame_subclass::integer, ast_channel::language, LOG_WARNING, ast_channel::name, ast_party_id::number, pbx_builtin_setvar_helper(), ast_channel::readformat, S_COR, ast_channel::sched, ast_party_number::str, ast_channel::stream, ast_frame::subclass, ast_channel::timingfunc, ast_dsp::totalsilence, and ast_party_number::valid.

Referenced by load_module().

{
   int res = 0;
   char *tmp;
   struct ast_frame *fr;
   int notsilent = 0;
   struct timeval start = { 0, 0 };
   struct timeval detection_start = { 0, 0 };
   int sil = 1000;
   int min = 100;
   int max = -1;
   int analysistime = -1;
   int continue_analysis = 1;
   int x;
   int origrformat = 0;
   struct ast_dsp *dsp = NULL;
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(filename);
      AST_APP_ARG(silence);
      AST_APP_ARG(min);
      AST_APP_ARG(max);
      AST_APP_ARG(analysistime);
   );
   
   if (ast_strlen_zero(data)) {
      ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n");
      return -1;
   }

   tmp = ast_strdupa(data);
   AST_STANDARD_APP_ARGS(args, tmp);

   if (!ast_strlen_zero(args.silence) && (sscanf(args.silence, "%30d", &x) == 1) && (x > 0)) {
      sil = x;
   }
   if (!ast_strlen_zero(args.min) && (sscanf(args.min, "%30d", &x) == 1) && (x > 0)) {
      min = x;
   }
   if (!ast_strlen_zero(args.max) && (sscanf(args.max, "%30d", &x) == 1) && (x > 0)) {
      max = x;
   }
   if (!ast_strlen_zero(args.analysistime) && (sscanf(args.analysistime, "%30d", &x) == 1) && (x > 0)) {
      analysistime = x;
   }

   ast_debug(1, "Preparing detect of '%s', sil=%d, min=%d, max=%d, analysistime=%d\n", args.filename, sil, min, max, analysistime);
   do {
      if (chan->_state != AST_STATE_UP) {
         if ((res = ast_answer(chan))) {
            break;
         }
      }

      origrformat = chan->readformat;
      if ((ast_set_read_format(chan, AST_FORMAT_SLINEAR))) {
         ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
         res = -1;
         break;
      }

      if (!(dsp = ast_dsp_new())) {
         ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
         res = -1;
         break;
      }
      ast_stopstream(chan);
      if (ast_streamfile(chan, tmp, chan->language)) {
         ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
         break;
      }
      detection_start = ast_tvnow();
      while (chan->stream) {
         res = ast_sched_wait(chan->sched);
         if ((res < 0) && !chan->timingfunc) {
            res = 0;
            break;
         }
         if (res < 0) {
            res = 1000;
         }
         res = ast_waitfor(chan, res);
         if (res < 0) {
            ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
            break;
         } else if (res > 0) {
            fr = ast_read(chan);
            if (continue_analysis && analysistime >= 0) {
               /* If we have a limit for the time to analyze voice
                * frames and the time has not expired */
               if (ast_tvdiff_ms(ast_tvnow(), detection_start) >= analysistime) {
                  continue_analysis = 0;
                  ast_verb(3, "BackgroundDetect: Talk analysis time complete on %s.\n", chan->name);
               }
            }
            
            if (!fr) {
               res = -1;
               break;
            } else if (fr->frametype == AST_FRAME_DTMF) {
               char t[2];
               t[0] = fr->subclass.integer;
               t[1] = '\0';
               if (ast_canmatch_extension(chan, chan->context, t, 1,
                  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
                  /* They entered a valid  extension, or might be anyhow */
                  res = fr->subclass.integer;
                  ast_frfree(fr);
                  break;
               }
            } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass.codec == AST_FORMAT_SLINEAR) && continue_analysis) {
               int totalsilence;
               int ms;
               res = ast_dsp_silence(dsp, fr, &totalsilence);
               if (res && (totalsilence > sil)) {
                  /* We've been quiet a little while */
                  if (notsilent) {
                     /* We had heard some talking */
                     ms = ast_tvdiff_ms(ast_tvnow(), start);
                     ms -= sil;
                     if (ms < 0)
                        ms = 0;
                     if ((ms > min) && ((max < 0) || (ms < max))) {
                        char ms_str[12];
                        ast_debug(1, "Found qualified token of %d ms\n", ms);

                        /* Save detected talk time (in milliseconds) */ 
                        snprintf(ms_str, sizeof(ms_str), "%d", ms);  
                        pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);

                        ast_goto_if_exists(chan, chan->context, "talk", 1);
                        res = 0;
                        ast_frfree(fr);
                        break;
                     } else {
                        ast_debug(1, "Found unqualified token of %d ms\n", ms);
                     }
                     notsilent = 0;
                  }
               } else {
                  if (!notsilent) {
                     /* Heard some audio, mark the begining of the token */
                     start = ast_tvnow();
                     ast_debug(1, "Start of voice token!\n");
                     notsilent = 1;
                  }
               }
            }
            ast_frfree(fr);
         }
         ast_sched_runq(chan->sched);
      }
      ast_stopstream(chan);
   } while (0);

   if (res > -1) {
      if (origrformat && ast_set_read_format(chan, origrformat)) {
         ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", 
            chan->name, ast_getformatname(origrformat));
      }
   }
   if (dsp) {
      ast_dsp_free(dsp);
   }
   return res;
}
static int load_module ( void  ) [static]
static int unload_module ( void  ) [static]

Definition at line 246 of file app_talkdetect.c.

References ast_unregister_application().


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Playback with Talk Detection" , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 256 of file app_talkdetect.c.

char* app = "BackgroundDetect" [static]

Definition at line 78 of file app_talkdetect.c.

Definition at line 256 of file app_talkdetect.c.