app.c File Reference

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <dirent.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/file.h>
#include <asterisk/app.h>
#include <asterisk/dsp.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/utils.h>
#include <asterisk/lock.h>
#include "asterisk.h"
#include "astconf.h"

Include dependency graph for app.c:

Go to the source code of this file.

Data Structures

struct  linear_state

Defines

#define MAX_OTHER_FORMATS   10

Functions

int ast_app_getdata (struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
 Plays a stream and gets DTMF data from a channel.
int ast_app_getdata_full (struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
int ast_app_getvoice (struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
 Record voice (after playing prompt if specified), waiting for silence (in ms) up to a given timeout (in s) or '#'.
int ast_app_has_voicemail (const char *mailbox)
 Determine if a given mailbox has any voicemail.
int ast_app_messagecount (const char *mailbox, int *newmsgs, int *oldmsgs)
 Determine number of new/old messages in a mailbox.
int ast_dtmf_stream (struct ast_channel *chan, struct ast_channel *peer, char *digits, int between)
 Send DTMF to chan (optionally entertain peer).
int ast_linear_stream (struct ast_channel *chan, const char *filename, int fd, int allowoverride)
 Stream a filename (or file descriptor) as a generator.
int ast_control_streamfile (struct ast_channel *chan, char *file, char *fwd, char *rev, char *stop, char *pause, int skipms)
 Stream a file with fast forward, pause, reverse.
int ast_play_and_wait (struct ast_channel *chan, char *fn)
 Play a stream and wait for a digit, returning the digit that was pressed.
int ast_play_and_record (struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
 Record a file for a max amount of time (in seconds), in a given list of formats separated by '|', outputting the duration of the recording, and with a maximum.
int ast_play_and_prepend (struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence)
 Record a message and prepend the message to the given record file after playing the optional playfile (or a beep), storing the duration in 'duration' and with a maximum.
int ast_lock_path (const char *path)
int ast_unlock_path (const char *path)


Define Documentation

#define MAX_OTHER_FORMATS   10

Definition at line 34 of file app.c.


Function Documentation

int ast_app_getdata ( struct ast_channel c,
char *  prompt,
char *  s,
int  maxlen,
int  timeout 
)

Plays a stream and gets DTMF data from a channel.

Parameters:
c Which channel one is interacting with
prompt File to pass to ast_streamfile (the one that you wish to play)
s The location where the DTMF data will be stored
maxlen Max Length of the data
timeout Timeout length waiting for data(in milliseconds). Set to 0 for standard timeout(six seconds), or -1 for no time out.
This function was designed for application programmers for situations where they need to play a message and then get some DTMF data in response to the message. If a digit is pressed during playback, it will immediately break out of the message and continue execution of your code.

Definition at line 38 of file app.c.

00039 {
00040    int res,to,fto;
00041    /* XXX Merge with full version? XXX */
00042    if (maxlen)
00043       s[0] = '\0';
00044    if (prompt) {
00045       res = ast_streamfile(c, prompt, c->language);
00046       if (res < 0)
00047          return res;
00048    }
00049    fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000;
00050    to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
00051 
00052    if (timeout > 0) fto = to = timeout;
00053    if (timeout < 0) fto = to = 1000000000;
00054    res = ast_readstring(c, s, maxlen, to, fto, "#");
00055    return res;
00056 }

int ast_app_getdata_full ( struct ast_channel c,
char *  prompt,
char *  s,
int  maxlen,
int  timeout,
int  audiofd,
int  ctrlfd 
)

Definition at line 59 of file app.c.

00060 {
00061    int res,to,fto;
00062    if (prompt) {
00063       res = ast_streamfile(c, prompt, c->language);
00064       if (res < 0)
00065          return res;
00066    }
00067    fto = 6000;
00068    to = 2000;
00069    if (timeout > 0) fto = to = timeout;
00070    if (timeout < 0) fto = to = 1000000000;
00071    res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
00072    return res;
00073 }

int ast_app_getvoice ( struct ast_channel c,
char *  dest,
char *  dstfmt,
char *  prompt,
int  silence,
int  maxsec 
)

Record voice (after playing prompt if specified), waiting for silence (in ms) up to a given timeout (in s) or '#'.

Definition at line 75 of file app.c.

00076 {
00077    int res;
00078    struct ast_filestream *writer;
00079    int rfmt;
00080    int totalms=0, total;
00081    
00082    struct ast_frame *f;
00083    struct ast_dsp *sildet;
00084    /* Play prompt if requested */
00085    if (prompt) {
00086       res = ast_streamfile(c, prompt, c->language);
00087       if (res < 0)
00088          return res;
00089       res = ast_waitstream(c,"");
00090       if (res < 0)
00091          return res;
00092    }
00093    rfmt = c->readformat;
00094    res = ast_set_read_format(c, AST_FORMAT_SLINEAR);
00095    if (res < 0) {
00096       ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00097       return -1;
00098    }
00099    sildet = ast_dsp_new();
00100    if (!sildet) {
00101       ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00102       return -1;
00103    }
00104    writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
00105    if (!writer) {
00106       ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
00107       ast_dsp_free(sildet);
00108       return -1;
00109    }
00110    for(;;) {
00111       if ((res = ast_waitfor(c, 2000)) < 0) {
00112          ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
00113          break;
00114       }
00115       if (res) {
00116          f = ast_read(c);
00117          if (!f) {
00118             ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
00119             break;
00120          }
00121          if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
00122             /* Ended happily with DTMF */
00123             ast_frfree(f);
00124             break;
00125          } else if (f->frametype == AST_FRAME_VOICE) {
00126             ast_dsp_silence(sildet, f, &total); 
00127             if (total > silence) {
00128                /* Ended happily with silence */
00129                ast_frfree(f);
00130                break;
00131             }
00132             totalms += f->samples / 8;
00133             if (totalms > maxsec * 1000) {
00134                /* Ended happily with too much stuff */
00135                ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
00136                ast_frfree(f);
00137                break;
00138             }
00139             res = ast_writestream(writer, f);
00140             if (res < 0) {
00141                ast_log(LOG_WARNING, "Failed to write to stream at %s!\n", dest);
00142                ast_frfree(f);
00143                break;
00144             }
00145                
00146          }
00147          ast_frfree(f);
00148       }
00149    }
00150    res = ast_set_read_format(c, rfmt);
00151    if (res)
00152       ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
00153    ast_dsp_free(sildet);
00154    ast_closestream(writer);
00155    return 0;
00156 }

int ast_app_has_voicemail ( const char *  mailbox  ) 

Determine if a given mailbox has any voicemail.

Definition at line 158 of file app.c.

00159 {
00160    DIR *dir;
00161    struct dirent *de;
00162    char fn[256];
00163    char tmp[256]="";
00164    char *mb, *cur;
00165    char *context;
00166    int ret;
00167    /* If no mailbox, return immediately */
00168    if (ast_strlen_zero(mailbox))
00169       return 0;
00170    if (strchr(mailbox, ',')) {
00171       strncpy(tmp, mailbox, sizeof(tmp) - 1);
00172       mb = tmp;
00173       ret = 0;
00174       while((cur = strsep(&mb, ","))) {
00175          if (!ast_strlen_zero(cur)) {
00176             if (ast_app_has_voicemail(cur))
00177                return 1; 
00178          }
00179       }
00180       return 0;
00181    }
00182    strncpy(tmp, mailbox, sizeof(tmp) - 1);
00183    context = strchr(tmp, '@');
00184    if (context) {
00185       *context = '\0';
00186       context++;
00187    } else
00188       context = "default";
00189    snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, context, tmp);
00190    dir = opendir(fn);
00191    if (!dir)
00192       return 0;
00193    while ((de = readdir(dir))) {
00194       if (!strncasecmp(de->d_name, "msg", 3))
00195          break;
00196    }
00197    closedir(dir);
00198    if (de)
00199       return 1;
00200    return 0;
00201 }

int ast_app_messagecount ( const char *  mailbox,
int *  newmsgs,
int *  oldmsgs 
)

Determine number of new/old messages in a mailbox.

Definition at line 203 of file app.c.

00204 {
00205    DIR *dir;
00206    struct dirent *de;
00207    char fn[256];
00208    char tmp[256]="";
00209    char *mb, *cur;
00210    char *context;
00211    int ret;
00212    if (newmsgs)
00213       *newmsgs = 0;
00214    if (oldmsgs)
00215       *oldmsgs = 0;
00216    /* If no mailbox, return immediately */
00217    if (ast_strlen_zero(mailbox))
00218       return 0;
00219    if (strchr(mailbox, ',')) {
00220       int tmpnew, tmpold;
00221       strncpy(tmp, mailbox, sizeof(tmp) - 1);
00222       mb = tmp;
00223       ret = 0;
00224       while((cur = strsep(&mb, ", "))) {
00225          if (!ast_strlen_zero(cur)) {
00226             if (ast_app_messagecount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
00227                return -1;
00228             else {
00229                if (newmsgs)
00230                   *newmsgs += tmpnew; 
00231                if (oldmsgs)
00232                   *oldmsgs += tmpold;
00233             }
00234          }
00235       }
00236       return 0;
00237    }
00238    strncpy(tmp, mailbox, sizeof(tmp) - 1);
00239    context = strchr(tmp, '@');
00240    if (context) {
00241       *context = '\0';
00242       context++;
00243    } else
00244       context = "default";
00245    if (newmsgs) {
00246       snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, context, tmp);
00247       dir = opendir(fn);
00248       if (dir) {
00249          while ((de = readdir(dir))) {
00250             if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) &&
00251                !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt"))
00252                   (*newmsgs)++;
00253                
00254          }
00255          closedir(dir);
00256       }
00257    }
00258    if (oldmsgs) {
00259       snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/Old", (char *)ast_config_AST_SPOOL_DIR, context, tmp);
00260       dir = opendir(fn);
00261       if (dir) {
00262          while ((de = readdir(dir))) {
00263             if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) &&
00264                !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt"))
00265                   (*oldmsgs)++;
00266                
00267          }
00268          closedir(dir);
00269       }
00270    }
00271    return 0;
00272 }

int ast_control_streamfile ( struct ast_channel chan,
char *  file,
char *  fwd,
char *  rev,
char *  stop,
char *  pause,
int  skipms 
)

Stream a file with fast forward, pause, reverse.

Definition at line 421 of file app.c.

00422 {
00423    struct timeval started, ended;
00424    long elapsed = 0,last_elapsed =0;
00425    char *breaks=NULL;
00426    char *end=NULL;
00427    int blen=2;
00428    int res=0;
00429 
00430    if (stop)
00431       blen += strlen(stop);
00432    if (pause)
00433       blen += strlen(pause);
00434 
00435    if (blen > 2) {
00436       breaks = alloca(blen + 1);
00437       breaks[0] = '\0';
00438       strcat(breaks, stop);
00439       strcat(breaks, pause);
00440    }
00441    if (chan->_state != AST_STATE_UP)
00442       res = ast_answer(chan);
00443 
00444    if (chan)
00445       ast_stopstream(chan);
00446 
00447 
00448    if (file) {
00449       if ((end = strchr(file,':'))) {
00450          if (!strcasecmp(end, ":end")) {
00451             *end = '\0';
00452             end++;
00453          }
00454       }
00455    }
00456 
00457    for (;;) {
00458       gettimeofday(&started,NULL);
00459 
00460       if (chan)
00461          ast_stopstream(chan);
00462       res = ast_streamfile(chan, file, chan->language);
00463       if (!res) {
00464          if (end) {
00465             ast_seekstream(chan->stream, 0, SEEK_END);
00466             end=NULL;
00467          }
00468          res = 1;
00469          if (elapsed) {
00470             ast_stream_fastforward(chan->stream, elapsed);
00471             last_elapsed = elapsed - 200;
00472          }
00473          if (res)
00474             res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
00475          else
00476             break;
00477       }
00478 
00479       if (res < 1)
00480          break;
00481 
00482       if (pause != NULL && strchr(pause, res)) {
00483          gettimeofday(&ended, NULL);
00484          elapsed = (((ended.tv_sec * 1000) + ended.tv_usec / 1000) - ((started.tv_sec * 1000) + started.tv_usec / 1000) + last_elapsed);
00485          for(;;) {
00486             if (chan)
00487                ast_stopstream(chan);
00488             res = ast_waitfordigit(chan, 1000);
00489             if (res == 0)
00490                continue;
00491             else if (res == -1 || strchr(pause, res) || (stop && strchr(stop, res)))
00492                break;
00493          }
00494          if (res == *pause) {
00495             res = 0;
00496             continue;
00497          }
00498       }
00499       if (res == -1)
00500          break;
00501 
00502       /* if we get one of our stop chars, return it to the calling function */
00503       if (stop && strchr(stop, res)) {
00504          /* res = 0; */
00505          break;
00506       }
00507    }
00508    if (chan)
00509       ast_stopstream(chan);
00510 
00511    return res;
00512 }

int ast_dtmf_stream ( struct ast_channel chan,
struct ast_channel peer,
char *  digits,
int  between 
)

Send DTMF to chan (optionally entertain peer).

Definition at line 274 of file app.c.

00275 {
00276    char *ptr=NULL;
00277    int res=0;
00278    struct ast_frame f;
00279    if (!between)
00280       between = 100;
00281 
00282    if (peer)
00283       res = ast_autoservice_start(peer);
00284 
00285    if (!res) {
00286       res = ast_waitfor(chan,100);
00287       if (res > -1) {
00288          for (ptr=digits; *ptr; ptr++) {
00289             if (*ptr == 'w') {
00290                res = ast_safe_sleep(chan, 500);
00291                if (res) 
00292                   break;
00293                continue;
00294             }
00295             memset(&f, 0, sizeof(f));
00296             f.frametype = AST_FRAME_DTMF;
00297             f.subclass = *ptr;
00298             f.src = "ast_dtmf_stream";
00299             if (strchr("0123456789*#abcdABCD",*ptr)==NULL) {
00300                ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr);
00301             } else {
00302                res = ast_write(chan, &f);
00303                if (res) 
00304                   break;
00305                /* pause between digits */
00306                res = ast_safe_sleep(chan,between);
00307                if (res) 
00308                   break;
00309             }
00310          }
00311       }
00312       if (peer)
00313          res = ast_autoservice_stop(peer);
00314    }
00315    return res;
00316 }

int ast_linear_stream ( struct ast_channel chan,
const char *  filename,
int  fd,
int  allowoverride 
)

Stream a filename (or file descriptor) as a generator.

Definition at line 390 of file app.c.

00391 {
00392    struct linear_state *lin;
00393    char tmpf[256] = "";
00394    int res = -1;
00395    int autoclose = 0;
00396    if (fd < 0) {
00397       if (!filename || ast_strlen_zero(filename))
00398          return -1;
00399       autoclose = 1;
00400       if (filename[0] == '/') 
00401          strncpy(tmpf, filename, sizeof(tmpf) - 1);
00402       else
00403          snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", (char *)ast_config_AST_VAR_DIR, "sounds", filename);
00404       fd = open(tmpf, O_RDONLY);
00405       if (fd < 0){
00406          ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
00407          return -1;
00408       }
00409    }
00410    lin = malloc(sizeof(struct linear_state));
00411    if (lin) {
00412       memset(lin, 0, sizeof(lin));
00413       lin->fd = fd;
00414       lin->allowoverride = allowoverride;
00415       lin->autoclose = autoclose;
00416       res = ast_activate_generator(chan, &linearstream, lin);
00417    }
00418    return res;
00419 }

int ast_lock_path ( const char *  path  ) 

Definition at line 978 of file app.c.

00979 {
00980    char *s;
00981    char *fs;
00982    int res;
00983    int fd;
00984    time_t start;
00985    s = alloca(strlen(path) + 10);
00986    fs = alloca(strlen(path) + 20);
00987    if (!fs || !s) {
00988       ast_log(LOG_WARNING, "Out of memory!\n");
00989       return -1;
00990    }
00991    snprintf(fs, strlen(path) + 19, "%s/%s-%08x", path, ".lock", rand());
00992    fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
00993    if (fd < 0) {
00994       fprintf(stderr, "Unable to create lock file: %s\n", strerror(errno));
00995       return -1;
00996    }
00997    close(fd);
00998    snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
00999    time(&start);
01000    while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
01001       usleep(1);
01002    if (res < 0) {
01003       ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
01004    }
01005    unlink(fs);
01006    ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
01007    return res;
01008 }

int ast_play_and_prepend ( struct ast_channel chan,
char *  playfile,
char *  recordfile,
int  maxtime,
char *  fmt,
int *  duration,
int  beep,
int  silencethreshold,
int  maxsilence 
)

Record a message and prepend the message to the given record file after playing the optional playfile (or a beep), storing the duration in 'duration' and with a maximum.

Definition at line 745 of file app.c.

00746 {
00747    int d = 0;
00748    char *fmts;
00749    char comment[256];
00750    int x, fmtcnt=1, res=-1,outmsg=0;
00751    struct ast_frame *f;
00752    struct ast_filestream *others[MAX_OTHER_FORMATS];
00753    struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
00754    char *sfmt[MAX_OTHER_FORMATS];
00755    char *stringp=NULL;
00756    time_t start, end;
00757    struct ast_dsp *sildet;    /* silence detector dsp */
00758    int totalsilence = 0;
00759    int dspsilence = 0;
00760    int gotsilence = 0;     /* did we timeout for silence? */
00761    int rfmt=0; 
00762    char prependfile[80];
00763    
00764    if (silencethreshold < 0)
00765       silencethreshold = global_silence_threshold;
00766 
00767    if (maxsilence < 0)
00768       maxsilence = global_maxsilence;
00769 
00770    /* barf if no pointer passed to store duration in */
00771    if (duration == NULL) {
00772       ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
00773       return -1;
00774    }
00775 
00776    ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00777    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00778 
00779    if (playfile || beep) { 
00780       if (!beep)
00781          d = ast_play_and_wait(chan, playfile);
00782       if (d > -1)
00783          d = ast_streamfile(chan, "beep",chan->language);
00784       if (!d)
00785          d = ast_waitstream(chan,"");
00786       if (d < 0)
00787          return -1;
00788    }
00789    strncpy(prependfile, recordfile, sizeof(prependfile) -1);   
00790    strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
00791          
00792    fmts = ast_strdupa(fmt);
00793    
00794    stringp=fmts;
00795    strsep(&stringp, "|");
00796    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);   
00797    sfmt[0] = ast_strdupa(fmts);
00798    
00799    while((fmt = strsep(&stringp, "|"))) {
00800       if (fmtcnt > MAX_OTHER_FORMATS - 1) {
00801          ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
00802          break;
00803       }
00804       sfmt[fmtcnt++] = ast_strdupa(fmt);
00805    }
00806 
00807    time(&start);
00808    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
00809    for (x=0;x<fmtcnt;x++) {
00810       others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00811       ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
00812       if (!others[x]) {
00813          break;
00814       }
00815    }
00816    
00817    sildet = ast_dsp_new(); /* Create the silence detector */
00818    if (!sildet) {
00819       ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00820       return -1;
00821    }
00822    ast_dsp_set_threshold(sildet, silencethreshold);
00823 
00824    if (maxsilence > 0) {
00825       rfmt = chan->readformat;
00826       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00827       if (res < 0) {
00828          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00829          return -1;
00830       }
00831    }
00832                   
00833    if (x == fmtcnt) {
00834    /* Loop forever, writing the packets we read to the writer(s), until
00835       we read a # or get a hangup */
00836       f = NULL;
00837       for(;;) {
00838          res = ast_waitfor(chan, 2000);
00839          if (!res) {
00840             ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
00841             /* Try one more time in case of masq */
00842             res = ast_waitfor(chan, 2000);
00843             if (!res) {
00844                ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00845                res = -1;
00846             }
00847          }
00848          
00849          if (res < 0) {
00850             f = NULL;
00851             break;
00852          }
00853          f = ast_read(chan);
00854          if (!f)
00855             break;
00856          if (f->frametype == AST_FRAME_VOICE) {
00857             /* write each format */
00858             for (x=0;x<fmtcnt;x++) {
00859                if (!others[x])
00860                   break;
00861                res = ast_writestream(others[x], f);
00862             }
00863             
00864             /* Silence Detection */
00865             if (maxsilence > 0) {
00866                dspsilence = 0;
00867                ast_dsp_silence(sildet, f, &dspsilence);
00868                if (dspsilence)
00869                   totalsilence = dspsilence;
00870                else
00871                   totalsilence = 0;
00872                
00873                if (totalsilence > maxsilence) {
00874                /* Ended happily with silence */
00875                if (option_verbose > 2) 
00876                   ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00877                ast_frfree(f);
00878                gotsilence = 1;
00879                outmsg=2;
00880                break;
00881                }
00882             }
00883             /* Exit on any error */
00884             if (res) {
00885                ast_log(LOG_WARNING, "Error writing frame\n");
00886                ast_frfree(f);
00887                break;
00888             }
00889          } else if (f->frametype == AST_FRAME_VIDEO) {
00890             /* Write only once */
00891             ast_writestream(others[0], f);
00892          } else if (f->frametype == AST_FRAME_DTMF) {
00893             /* stop recording with any digit */
00894             if (option_verbose > 2) 
00895                ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
00896             res = 't';
00897             outmsg = 2;
00898             ast_frfree(f);
00899             break;
00900          }
00901          if (maxtime) {
00902             time(&end);
00903             if (maxtime < (end - start)) {
00904                if (option_verbose > 2)
00905                   ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00906                res = 't';
00907                outmsg=2;
00908                ast_frfree(f);
00909                break;
00910             }
00911          }
00912          ast_frfree(f);
00913       }
00914       if (end == start) time(&end);
00915       if (!f) {
00916          if (option_verbose > 2) 
00917             ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
00918          res = -1;
00919          outmsg=1;
00920 #if 0
00921          /* delete all the prepend files */
00922          for (x=0;x<fmtcnt;x++) {
00923             if (!others[x])
00924                break;
00925             ast_closestream(others[x]);
00926             ast_filedelete(prependfile, sfmt[x]);
00927          }
00928 #endif
00929       }
00930    } else {
00931       ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]); 
00932    }
00933    *duration = end - start;
00934 #if 0
00935    if (outmsg > 1) {
00936 #else
00937    if (outmsg) {
00938 #endif
00939       struct ast_frame *fr;
00940       for (x=0;x<fmtcnt;x++) {
00941          snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
00942          realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
00943          if (!others[x] || !realfiles[x])
00944             break;
00945          if (totalsilence)
00946             ast_stream_rewind(others[x], totalsilence-200);
00947          else
00948             ast_stream_rewind(others[x], 200);
00949          ast_truncstream(others[x]);
00950          /* add the original file too */
00951          while ((fr = ast_readframe(realfiles[x]))) {
00952             ast_writestream(others[x],fr);
00953          }
00954          ast_closestream(others[x]);
00955          ast_closestream(realfiles[x]);
00956          ast_filerename(prependfile, recordfile, sfmt[x]);
00957 #if 0
00958          ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
00959 #endif
00960          ast_filedelete(prependfile, sfmt[x]);
00961       }
00962    }
00963    if (rfmt) {
00964       if (ast_set_read_format(chan, rfmt)) {
00965          ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00966       }
00967    }
00968    if (outmsg) {
00969       if (outmsg > 1) {
00970          /* Let them know it worked */
00971          ast_streamfile(chan, "auth-thankyou", chan->language);
00972          ast_waitstream(chan, "");
00973       }
00974    }  
00975    return res;
00976 }

int ast_play_and_record ( struct ast_channel chan,
char *  playfile,
char *  recordfile,
int  maxtime,
char *  fmt,
int *  duration,
int  silencethreshold,
int  maxsilence,
const char *  path 
)

Record a file for a max amount of time (in seconds), in a given list of formats separated by '|', outputting the duration of the recording, and with a maximum.

Definition at line 528 of file app.c.

00529 {
00530    int d;
00531    char *fmts;
00532    char comment[256];
00533    int x, fmtcnt=1, res=-1,outmsg=0;
00534    struct ast_frame *f;
00535    struct ast_filestream *others[MAX_OTHER_FORMATS];
00536    char *sfmt[MAX_OTHER_FORMATS];
00537    char *stringp=NULL;
00538    time_t start, end;
00539    struct ast_dsp *sildet=NULL;     /* silence detector dsp */
00540    int totalsilence = 0;
00541    int dspsilence = 0;
00542    int gotsilence = 0;     /* did we timeout for silence? */
00543    int rfmt=0;
00544 
00545    if (silencethreshold < 0)
00546       silencethreshold = global_silence_threshold;
00547 
00548    if (maxsilence < 0)
00549       maxsilence = global_maxsilence;
00550 
00551    /* barf if no pointer passed to store duration in */
00552    if (duration == NULL) {
00553       ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
00554       return -1;
00555    }
00556 
00557    ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00558    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00559 
00560    if (playfile) {
00561       d = ast_play_and_wait(chan, playfile);
00562       if (d > -1)
00563          d = ast_streamfile(chan, "beep",chan->language);
00564       if (!d)
00565          d = ast_waitstream(chan,"");
00566       if (d < 0)
00567          return -1;
00568    }
00569 
00570    fmts = ast_strdupa(fmt);
00571 
00572    stringp=fmts;
00573    strsep(&stringp, "|");
00574    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
00575    sfmt[0] = ast_strdupa(fmts);
00576 
00577    while((fmt = strsep(&stringp, "|"))) {
00578       if (fmtcnt > MAX_OTHER_FORMATS - 1) {
00579          ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
00580          break;
00581       }
00582       sfmt[fmtcnt++] = ast_strdupa(fmt);
00583    }
00584 
00585    time(&start);
00586    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
00587    for (x=0;x<fmtcnt;x++) {
00588       others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00589       ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
00590 
00591       if (!others[x]) {
00592          break;
00593       }
00594    }
00595 
00596    if (path)
00597       ast_unlock_path(path);
00598 
00599    
00600    if (maxsilence > 0) {
00601       sildet = ast_dsp_new(); /* Create the silence detector */
00602       if (!sildet) {
00603          ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00604          return -1;
00605       }
00606       ast_dsp_set_threshold(sildet, silencethreshold);
00607       rfmt = chan->readformat;
00608       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00609       if (res < 0) {
00610          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00611          ast_dsp_free(sildet);
00612          return -1;
00613       }
00614    }
00615 
00616    if (x == fmtcnt) {
00617    /* Loop forever, writing the packets we read to the writer(s), until
00618       we read a # or get a hangup */
00619       f = NULL;
00620       for(;;) {
00621          res = ast_waitfor(chan, 2000);
00622          if (!res) {
00623             ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
00624             /* Try one more time in case of masq */
00625             res = ast_waitfor(chan, 2000);
00626             if (!res) {
00627                ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00628                res = -1;
00629             }
00630          }
00631 
00632          if (res < 0) {
00633             f = NULL;
00634             break;
00635          }
00636          f = ast_read(chan);
00637          if (!f)
00638             break;
00639          if (f->frametype == AST_FRAME_VOICE) {
00640             /* write each format */
00641             for (x=0;x<fmtcnt;x++) {
00642                res = ast_writestream(others[x], f);
00643             }
00644 
00645             /* Silence Detection */
00646             if (maxsilence > 0) {
00647                dspsilence = 0;
00648                ast_dsp_silence(sildet, f, &dspsilence);
00649                if (dspsilence)
00650                   totalsilence = dspsilence;
00651                else
00652                   totalsilence = 0;
00653 
00654                if (totalsilence > maxsilence) {
00655                   /* Ended happily with silence */
00656                                           if (option_verbose > 2)
00657                                                    ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00658                   ast_frfree(f);
00659                   gotsilence = 1;
00660                   outmsg=2;
00661                   break;
00662                }
00663             }
00664             /* Exit on any error */
00665             if (res) {
00666                ast_log(LOG_WARNING, "Error writing frame\n");
00667                ast_frfree(f);
00668                break;
00669             }
00670          } else if (f->frametype == AST_FRAME_VIDEO) {
00671             /* Write only once */
00672             ast_writestream(others[0], f);
00673          } else if (f->frametype == AST_FRAME_DTMF) {
00674             if (f->subclass == '#') {
00675                if (option_verbose > 2)
00676                   ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
00677                res = '#';
00678                outmsg = 2;
00679                ast_frfree(f);
00680                break;
00681             }
00682          }
00683             if (f->subclass == '0') {
00684             /* Check for a '0' during message recording also, in case caller wants operator */
00685                if (option_verbose > 2)
00686                   ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
00687                res = '0';
00688                outmsg = 0;
00689                ast_frfree(f);
00690                break;
00691             }
00692          if (maxtime) {
00693             time(&end);
00694             if (maxtime < (end - start)) {
00695                if (option_verbose > 2)
00696                   ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00697                outmsg = 2;
00698                res = 't';
00699                ast_frfree(f);
00700                break;
00701             }
00702          }
00703          ast_frfree(f);
00704       }
00705       if (end == start) time(&end);
00706       if (!f) {
00707          if (option_verbose > 2)
00708             ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
00709          res = -1;
00710          outmsg=1;
00711       }
00712    } else {
00713       ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
00714    }
00715 
00716    *duration = end - start;
00717 
00718    for (x=0;x<fmtcnt;x++) {
00719       if (!others[x])
00720          break;
00721       if (res > 0) {
00722          if (totalsilence)
00723             ast_stream_rewind(others[x], totalsilence-200);
00724          else
00725             ast_stream_rewind(others[x], 200);
00726       }
00727       ast_truncstream(others[x]);
00728       ast_closestream(others[x]);
00729    }
00730    if (rfmt) {
00731       if (ast_set_read_format(chan, rfmt)) {
00732          ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00733       }
00734    }
00735    if (outmsg > 1) {
00736       /* Let them know recording is stopped */
00737       if(!ast_streamfile(chan, "auth-thankyou", chan->language))
00738          ast_waitstream(chan, "");
00739    }
00740    if (sildet)
00741       ast_dsp_free(sildet);
00742    return res;
00743 }

int ast_play_and_wait ( struct ast_channel chan,
char *  fn 
)

Play a stream and wait for a digit, returning the digit that was pressed.

Definition at line 514 of file app.c.

00515 {
00516    int d;
00517    d = ast_streamfile(chan, fn, chan->language);
00518    if (d)
00519       return d;
00520    d = ast_waitstream(chan, AST_DIGIT_ANY);
00521    ast_stopstream(chan);
00522    return d;
00523 }

int ast_unlock_path ( const char *  path  ) 

Definition at line 1010 of file app.c.

01011 {
01012    char *s;
01013    s = alloca(strlen(path) + 10);
01014    if (!s)
01015       return -1;
01016    snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
01017    ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
01018    return unlink(s);
01019 }


Generated on Wed Oct 28 17:00:49 2009 for Asterisk by  doxygen 1.5.6