Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

app.h File Reference

Go to the source code of this file.

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_safe_system (const char *s)
 Safely spawn an external program while closingn file descriptors.
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_sec, char *fmt, int *duration, int silencethreshold, int maxsilence_ms, 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_sec, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence_ms)
 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)


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.

References ast_readstring(), ast_streamfile(), ast_pbx::dtimeout, ast_channel::language, ast_channel::pbx, and ast_pbx::rtimeout.

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.

References ast_readstring_full(), ast_streamfile(), and ast_channel::language.

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.

References ast_closestream(), ast_dsp_free(), ast_dsp_new(), ast_dsp_silence(), AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree(), ast_log(), ast_read(), ast_set_read_format(), ast_streamfile(), ast_waitfor(), ast_waitstream(), ast_writefile(), ast_frame::frametype, ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, ast_channel::readformat, ast_frame::samples, and ast_frame::subclass.

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          }
00140          ast_frfree(f);
00141       }
00142    }
00143    res = ast_set_read_format(c, rfmt);
00144    if (res)
00145       ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
00146    ast_dsp_free(sildet);
00147    ast_closestream(writer);
00148    return 0;
00149 }

int ast_app_has_voicemail const char *  mailbox  ) 
 

Determine if a given mailbox has any voicemail.

Definition at line 151 of file app.c.

References ast_app_has_voicemail(), and ast_config_AST_SPOOL_DIR.

Referenced by ast_app_has_voicemail().

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

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

Determine number of new/old messages in a mailbox.

Definition at line 196 of file app.c.

References ast_app_messagecount(), and ast_config_AST_SPOOL_DIR.

Referenced by ast_app_messagecount().

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

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 414 of file app.c.

References ast_channel::_state, ast_answer(), ast_seekstream(), AST_STATE_UP, ast_stopstream(), ast_stream_fastforward(), ast_streamfile(), ast_waitfordigit(), and ast_waitstream_fr().

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

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 267 of file app.c.

References ast_autoservice_start(), ast_autoservice_stop(), AST_FRAME_DTMF, ast_log(), ast_safe_sleep(), ast_waitfor(), ast_write(), and LOG_WARNING.

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

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 383 of file app.c.

References ast_activate_generator(), ast_config_AST_VAR_DIR, ast_log(), linear_state::autoclose, LOG_WARNING, and malloc.

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

int ast_lock_path const char *  path  ) 
 

Definition at line 971 of file app.c.

References ast_log(), LOG_DEBUG, LOG_WARNING, and s.

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

int ast_play_and_prepend struct ast_channel chan,
char *  playfile,
char *  recordfile,
int  maxtime_sec,
char *  fmt,
int *  duration,
int  beep,
int  silencethreshold,
int  maxsilence_ms
 

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 738 of file app.c.

References ast_closestream(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), ast_filedelete(), ast_filerename(), AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree(), ast_getformatname(), ast_log(), ast_play_and_wait(), ast_read(), ast_readfile(), ast_readframe(), ast_set_read_format(), ast_stream_rewind(), ast_streamfile(), ast_truncstream(), ast_verbose(), ast_waitfor(), ast_waitstream(), ast_writefile(), ast_writestream(), ast_frame::frametype, ast_channel::language, LOG_DEBUG, LOG_WARNING, MAX_OTHER_FORMATS, ast_channel::name, option_verbose, ast_channel::readformat, ast_frame::subclass, ast_dsp::totalsilence, and VERBOSE_PREFIX_3.

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

int ast_play_and_record struct ast_channel chan,
char *  playfile,
char *  recordfile,
int  maxtime_sec,
char *  fmt,
int *  duration,
int  silencethreshold,
int  maxsilence_ms,
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 521 of file app.c.

References ast_closestream(), ast_dsp_free(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree(), ast_getformatname(), ast_log(), ast_play_and_wait(), ast_read(), ast_set_read_format(), ast_stream_rewind(), ast_streamfile(), ast_truncstream(), ast_unlock_path(), ast_verbose(), ast_waitfor(), ast_waitstream(), ast_writefile(), ast_writestream(), ast_frame::frametype, ast_channel::language, LOG_DEBUG, LOG_WARNING, MAX_OTHER_FORMATS, ast_channel::name, option_verbose, ast_channel::readformat, ast_frame::subclass, ast_dsp::totalsilence, and VERBOSE_PREFIX_3.

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

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 507 of file app.c.

References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_waitstream(), and ast_channel::language.

Referenced by ast_play_and_prepend(), and ast_play_and_record().

00508 {
00509    int d;
00510    d = ast_streamfile(chan, fn, chan->language);
00511    if (d)
00512       return d;
00513    d = ast_waitstream(chan, AST_DIGIT_ANY);
00514    ast_stopstream(chan);
00515    return d;
00516 }

int ast_safe_system const char *  s  ) 
 

Safely spawn an external program while closingn file descriptors.

Definition at line 182 of file asterisk.c.

References ast_log(), and LOG_WARNING.

Referenced by ast_closestream().

00183 {
00184    /* XXX This function needs some optimization work XXX */
00185    pid_t pid;
00186    int x;
00187    int res;
00188    struct rusage rusage;
00189    int status;
00190    void (*prev_handler) = signal(SIGCHLD, null_sig_handler);
00191    pid = fork();
00192    if (pid == 0) {
00193       /* Close file descriptors and launch system command */
00194       for (x=STDERR_FILENO + 1; x<4096;x++) {
00195          close(x);
00196       }
00197       res = execl("/bin/sh", "/bin/sh", "-c", s, NULL);
00198       exit(1);
00199    } else if (pid > 0) {
00200       for(;;) {
00201          res = wait4(pid, &status, 0, &rusage);
00202          if (res > -1) {
00203             if (WIFEXITED(status))
00204                res = WEXITSTATUS(status);
00205             else
00206                res = -1;
00207             break;
00208          } else {
00209             if (errno != EINTR) 
00210                break;
00211          }
00212       }
00213    } else {
00214       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00215       res = -1;
00216    }
00217    signal(SIGCHLD, prev_handler);
00218    return res;
00219 }

int ast_unlock_path const char *  path  ) 
 

Definition at line 1003 of file app.c.

References ast_log(), LOG_DEBUG, and s.

Referenced by ast_play_and_record().

01004 {
01005    char *s;
01006    s = alloca(strlen(path) + 10);
01007    if (!s)
01008       return -1;
01009    snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
01010    ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
01011    return unlink(s);
01012 }


Generated on Wed Aug 10 11:36:33 2005 for Asterisk by  doxygen 1.4.4