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

app.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Convenient Application Routines
00005  * 
00006  * Copyright (C) 1999-2004, Digium, Inc.
00007  *
00008  * Mark Spencer <markster@digium.com>
00009  *
00010  * This program is free software, distributed under the terms of
00011  * the GNU General Public License
00012  */
00013 
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <sys/time.h>
00018 #include <signal.h>
00019 #include <errno.h>
00020 #include <unistd.h>
00021 #include <dirent.h>
00022 #include <asterisk/channel.h>
00023 #include <asterisk/pbx.h>
00024 #include <asterisk/file.h>
00025 #include <asterisk/app.h>
00026 #include <asterisk/dsp.h>
00027 #include <asterisk/logger.h>
00028 #include <asterisk/options.h>
00029 #include <asterisk/utils.h>
00030 #include <asterisk/lock.h>
00031 #include "asterisk.h"
00032 #include "astconf.h"
00033 
00034 #define MAX_OTHER_FORMATS 10
00035 
00036 /* set timeout to 0 for "standard" timeouts. Set timeout to -1 for 
00037    "ludicrous time" (essentially never times out) */
00038 int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
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 }
00057 
00058 
00059 int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
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 }
00074 
00075 int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
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 }
00150 
00151 int ast_app_has_voicemail(const char *mailbox)
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 }
00195 
00196 int ast_app_messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
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 }
00266 
00267 int ast_dtmf_stream(struct ast_channel *chan,struct ast_channel *peer,char *digits,int between) 
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 }
00310 
00311 struct linear_state {
00312    int fd;
00313    int autoclose;
00314    int allowoverride;
00315    int origwfmt;
00316 };
00317 
00318 static void linear_release(struct ast_channel *chan, void *params)
00319 {
00320    struct linear_state *ls = params;
00321    if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
00322       ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt);
00323    }
00324    if (ls->autoclose)
00325       close(ls->fd);
00326    free(params);
00327 }
00328 
00329 static int linear_generator(struct ast_channel *chan, void *data, int len, int samples)
00330 {
00331    struct ast_frame f;
00332    short buf[2048 + AST_FRIENDLY_OFFSET / 2];
00333    struct linear_state *ls = data;
00334    int res;
00335    len = samples * 2;
00336    if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
00337       ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len);
00338       len = sizeof(buf) - AST_FRIENDLY_OFFSET;
00339    }
00340    memset(&f, 0, sizeof(f));
00341    res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len);
00342    if (res > 0) {
00343       f.frametype = AST_FRAME_VOICE;
00344       f.subclass = AST_FORMAT_SLINEAR;
00345       f.data = buf + AST_FRIENDLY_OFFSET/2;
00346       f.datalen = res;
00347       f.samples = res / 2;
00348       f.offset = AST_FRIENDLY_OFFSET;
00349       ast_write(chan, &f);
00350       if (res == len)
00351          return 0;
00352    }
00353    return -1;
00354 }
00355 
00356 static void *linear_alloc(struct ast_channel *chan, void *params)
00357 {
00358    struct linear_state *ls;
00359    /* In this case, params is already malloc'd */
00360    if (params) {
00361       ls = params;
00362       if (ls->allowoverride)
00363          chan->writeinterrupt = 1;
00364       else
00365          chan->writeinterrupt = 0;
00366       ls->origwfmt = chan->writeformat;
00367       if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00368          ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
00369          free(ls);
00370          ls = params = NULL;
00371       }
00372    }
00373    return params;
00374 }
00375 
00376 static struct ast_generator linearstream = 
00377 {
00378    alloc: linear_alloc,
00379    release: linear_release,
00380    generate: linear_generator,
00381 };
00382 
00383 int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride)
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 }
00413 
00414 int ast_control_streamfile(struct ast_channel *chan, char *file, char *fwd, char *rev, char *stop, char *pause, int skipms) 
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 }
00506 
00507 int ast_play_and_wait(struct ast_channel *chan, char *fn)
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 }
00517 
00518 static int global_silence_threshold = 128;
00519 static int global_maxsilence = 0;
00520 
00521 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)
00522 {
00523    char d, *fmts;
00524    char comment[256];
00525    int x, fmtcnt=1, res=-1,outmsg=0;
00526    struct ast_frame *f;
00527    struct ast_filestream *others[MAX_OTHER_FORMATS];
00528    char *sfmt[MAX_OTHER_FORMATS];
00529    char *stringp=NULL;
00530    time_t start, end;
00531    struct ast_dsp *sildet=NULL;     /* silence detector dsp */
00532    int totalsilence = 0;
00533    int dspsilence = 0;
00534    int gotsilence = 0;     /* did we timeout for silence? */
00535    int rfmt=0;
00536 
00537    if (silencethreshold < 0)
00538       silencethreshold = global_silence_threshold;
00539 
00540    if (maxsilence < 0)
00541       maxsilence = global_maxsilence;
00542 
00543    /* barf if no pointer passed to store duration in */
00544    if (duration == NULL) {
00545       ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
00546       return -1;
00547    }
00548 
00549    ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00550    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00551 
00552    if (playfile) {
00553       d = ast_play_and_wait(chan, playfile);
00554       if (d > -1)
00555          d = ast_streamfile(chan, "beep",chan->language);
00556       if (!d)
00557          d = ast_waitstream(chan,"");
00558       if (d < 0)
00559          return -1;
00560    }
00561 
00562    fmts = ast_strdupa(fmt);
00563 
00564    stringp=fmts;
00565    strsep(&stringp, "|");
00566    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
00567    sfmt[0] = ast_strdupa(fmts);
00568 
00569    while((fmt = strsep(&stringp, "|"))) {
00570       if (fmtcnt > MAX_OTHER_FORMATS - 1) {
00571          ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
00572          break;
00573       }
00574       sfmt[fmtcnt++] = ast_strdupa(fmt);
00575    }
00576 
00577    time(&start);
00578    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
00579    for (x=0;x<fmtcnt;x++) {
00580       others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00581       ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
00582 
00583       if (!others[x]) {
00584          break;
00585       }
00586    }
00587 
00588    if (path)
00589       ast_unlock_path(path);
00590 
00591    
00592    if (maxsilence > 0) {
00593       sildet = ast_dsp_new(); /* Create the silence detector */
00594       if (!sildet) {
00595          ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00596          return -1;
00597       }
00598       ast_dsp_set_threshold(sildet, silencethreshold);
00599       rfmt = chan->readformat;
00600       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00601       if (res < 0) {
00602          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00603          ast_dsp_free(sildet);
00604          return -1;
00605       }
00606    }
00607 
00608    if (x == fmtcnt) {
00609    /* Loop forever, writing the packets we read to the writer(s), until
00610       we read a # or get a hangup */
00611       f = NULL;
00612       for(;;) {
00613          res = ast_waitfor(chan, 2000);
00614          if (!res) {
00615             ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
00616             /* Try one more time in case of masq */
00617             res = ast_waitfor(chan, 2000);
00618             if (!res) {
00619                ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00620                res = -1;
00621             }
00622          }
00623 
00624          if (res < 0) {
00625             f = NULL;
00626             break;
00627          }
00628          f = ast_read(chan);
00629          if (!f)
00630             break;
00631          if (f->frametype == AST_FRAME_VOICE) {
00632             /* write each format */
00633             for (x=0;x<fmtcnt;x++) {
00634                res = ast_writestream(others[x], f);
00635             }
00636 
00637             /* Silence Detection */
00638             if (maxsilence > 0) {
00639                dspsilence = 0;
00640                ast_dsp_silence(sildet, f, &dspsilence);
00641                if (dspsilence)
00642                   totalsilence = dspsilence;
00643                else
00644                   totalsilence = 0;
00645 
00646                if (totalsilence > maxsilence) {
00647                   /* Ended happily with silence */
00648                                           if (option_verbose > 2)
00649                                                    ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00650                   ast_frfree(f);
00651                   gotsilence = 1;
00652                   outmsg=2;
00653                   break;
00654                }
00655             }
00656             /* Exit on any error */
00657             if (res) {
00658                ast_log(LOG_WARNING, "Error writing frame\n");
00659                ast_frfree(f);
00660                break;
00661             }
00662          } else if (f->frametype == AST_FRAME_VIDEO) {
00663             /* Write only once */
00664             ast_writestream(others[0], f);
00665          } else if (f->frametype == AST_FRAME_DTMF) {
00666             if (f->subclass == '#') {
00667                if (option_verbose > 2)
00668                   ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
00669                res = '#';
00670                outmsg = 2;
00671                ast_frfree(f);
00672                break;
00673             }
00674          }
00675             if (f->subclass == '0') {
00676             /* Check for a '0' during message recording also, in case caller wants operator */
00677                if (option_verbose > 2)
00678                   ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
00679                res = '0';
00680                outmsg = 0;
00681                ast_frfree(f);
00682                break;
00683             }
00684          if (maxtime) {
00685             time(&end);
00686             if (maxtime < (end - start)) {
00687                if (option_verbose > 2)
00688                   ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00689                outmsg = 2;
00690                res = 't';
00691                ast_frfree(f);
00692                break;
00693             }
00694          }
00695          ast_frfree(f);
00696       }
00697       if (end == start) time(&end);
00698       if (!f) {
00699          if (option_verbose > 2)
00700             ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
00701          res = -1;
00702          outmsg=1;
00703       }
00704    } else {
00705       ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
00706    }
00707 
00708    *duration = end - start;
00709 
00710    for (x=0;x<fmtcnt;x++) {
00711       if (!others[x])
00712          break;
00713       if (res > 0) {
00714          if (totalsilence)
00715             ast_stream_rewind(others[x], totalsilence-200);
00716          else
00717             ast_stream_rewind(others[x], 200);
00718       }
00719       ast_truncstream(others[x]);
00720       ast_closestream(others[x]);
00721    }
00722    if (rfmt) {
00723       if (ast_set_read_format(chan, rfmt)) {
00724          ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00725       }
00726    }
00727    if (outmsg > 1) {
00728       /* Let them know recording is stopped */
00729       if(!ast_streamfile(chan, "auth-thankyou", chan->language))
00730          ast_waitstream(chan, "");
00731    }
00732    if (sildet)
00733       ast_dsp_free(sildet);
00734    return res;
00735 }
00736 
00737 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)
00738 {
00739    char d = 0, *fmts;
00740    char comment[256];
00741    int x, fmtcnt=1, res=-1,outmsg=0;
00742    struct ast_frame *f;
00743    struct ast_filestream *others[MAX_OTHER_FORMATS];
00744    struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
00745    char *sfmt[MAX_OTHER_FORMATS];
00746    char *stringp=NULL;
00747    time_t start, end;
00748    struct ast_dsp *sildet;    /* silence detector dsp */
00749    int totalsilence = 0;
00750    int dspsilence = 0;
00751    int gotsilence = 0;     /* did we timeout for silence? */
00752    int rfmt=0; 
00753    char prependfile[80];
00754    
00755    if (silencethreshold < 0)
00756       silencethreshold = global_silence_threshold;
00757 
00758    if (maxsilence < 0)
00759       maxsilence = global_maxsilence;
00760 
00761    /* barf if no pointer passed to store duration in */
00762    if (duration == NULL) {
00763       ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
00764       return -1;
00765    }
00766 
00767    ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00768    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00769 
00770    if (playfile || beep) { 
00771       if (!beep)
00772          d = ast_play_and_wait(chan, playfile);
00773       if (d > -1)
00774          d = ast_streamfile(chan, "beep",chan->language);
00775       if (!d)
00776          d = ast_waitstream(chan,"");
00777       if (d < 0)
00778          return -1;
00779    }
00780    strncpy(prependfile, recordfile, sizeof(prependfile) -1);   
00781    strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
00782          
00783    fmts = ast_strdupa(fmt);
00784    
00785    stringp=fmts;
00786    strsep(&stringp, "|");
00787    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);   
00788    sfmt[0] = ast_strdupa(fmts);
00789    
00790    while((fmt = strsep(&stringp, "|"))) {
00791       if (fmtcnt > MAX_OTHER_FORMATS - 1) {
00792          ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
00793          break;
00794       }
00795       sfmt[fmtcnt++] = ast_strdupa(fmt);
00796    }
00797 
00798    time(&start);
00799    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
00800    for (x=0;x<fmtcnt;x++) {
00801       others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00802       ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
00803       if (!others[x]) {
00804          break;
00805       }
00806    }
00807    
00808    sildet = ast_dsp_new(); /* Create the silence detector */
00809    if (!sildet) {
00810       ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00811       return -1;
00812    }
00813    ast_dsp_set_threshold(sildet, silencethreshold);
00814 
00815    if (maxsilence > 0) {
00816       rfmt = chan->readformat;
00817       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00818       if (res < 0) {
00819          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00820          return -1;
00821       }
00822    }
00823                   
00824    if (x == fmtcnt) {
00825    /* Loop forever, writing the packets we read to the writer(s), until
00826       we read a # or get a hangup */
00827       f = NULL;
00828       for(;;) {
00829          res = ast_waitfor(chan, 2000);
00830          if (!res) {
00831             ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
00832             /* Try one more time in case of masq */
00833             res = ast_waitfor(chan, 2000);
00834             if (!res) {
00835                ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00836                res = -1;
00837             }
00838          }
00839          
00840          if (res < 0) {
00841             f = NULL;
00842             break;
00843          }
00844          f = ast_read(chan);
00845          if (!f)
00846             break;
00847          if (f->frametype == AST_FRAME_VOICE) {
00848             /* write each format */
00849             for (x=0;x<fmtcnt;x++) {
00850                if (!others[x])
00851                   break;
00852                res = ast_writestream(others[x], f);
00853             }
00854             
00855             /* Silence Detection */
00856             if (maxsilence > 0) {
00857                dspsilence = 0;
00858                ast_dsp_silence(sildet, f, &dspsilence);
00859                if (dspsilence)
00860                   totalsilence = dspsilence;
00861                else
00862                   totalsilence = 0;
00863                
00864                if (totalsilence > maxsilence) {
00865                /* Ended happily with silence */
00866                if (option_verbose > 2) 
00867                   ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00868                ast_frfree(f);
00869                gotsilence = 1;
00870                outmsg=2;
00871                break;
00872                }
00873             }
00874             /* Exit on any error */
00875             if (res) {
00876                ast_log(LOG_WARNING, "Error writing frame\n");
00877                ast_frfree(f);
00878                break;
00879             }
00880          } else if (f->frametype == AST_FRAME_VIDEO) {
00881             /* Write only once */
00882             ast_writestream(others[0], f);
00883          } else if (f->frametype == AST_FRAME_DTMF) {
00884             /* stop recording with any digit */
00885             if (option_verbose > 2) 
00886                ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
00887             res = 't';
00888             outmsg = 2;
00889             ast_frfree(f);
00890             break;
00891          }
00892          if (maxtime) {
00893             time(&end);
00894             if (maxtime < (end - start)) {
00895                if (option_verbose > 2)
00896                   ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00897                res = 't';
00898                outmsg=2;
00899                ast_frfree(f);
00900                break;
00901             }
00902          }
00903          ast_frfree(f);
00904       }
00905       if (end == start) time(&end);
00906       if (!f) {
00907          if (option_verbose > 2) 
00908             ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
00909          res = -1;
00910          outmsg=1;
00911 #if 0
00912          /* delete all the prepend files */
00913          for (x=0;x<fmtcnt;x++) {
00914             if (!others[x])
00915                break;
00916             ast_closestream(others[x]);
00917             ast_filedelete(prependfile, sfmt[x]);
00918          }
00919 #endif
00920       }
00921    } else {
00922       ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]); 
00923    }
00924    *duration = end - start;
00925 #if 0
00926    if (outmsg > 1) {
00927 #else
00928    if (outmsg) {
00929 #endif
00930       struct ast_frame *fr;
00931       for (x=0;x<fmtcnt;x++) {
00932          snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
00933          realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
00934          if (!others[x] || !realfiles[x])
00935             break;
00936          if (totalsilence)
00937             ast_stream_rewind(others[x], totalsilence-200);
00938          else
00939             ast_stream_rewind(others[x], 200);
00940          ast_truncstream(others[x]);
00941          /* add the original file too */
00942          while ((fr = ast_readframe(realfiles[x]))) {
00943             ast_writestream(others[x],fr);
00944          }
00945          ast_closestream(others[x]);
00946          ast_closestream(realfiles[x]);
00947          ast_filerename(prependfile, recordfile, sfmt[x]);
00948 #if 0
00949          ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
00950 #endif
00951          ast_filedelete(prependfile, sfmt[x]);
00952       }
00953    }
00954    if (rfmt) {
00955       if (ast_set_read_format(chan, rfmt)) {
00956          ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00957       }
00958    }
00959    if (outmsg) {
00960       if (outmsg > 1) {
00961          /* Let them know it worked */
00962          ast_streamfile(chan, "auth-thankyou", chan->language);
00963          ast_waitstream(chan, "");
00964       }
00965    }  
00966    return res;
00967 }
00968 
00969 int ast_lock_path(const char *path)
00970 {
00971    char *s;
00972    char *fs;
00973    int res;
00974    int fd;
00975    time_t start;
00976    s = alloca(strlen(path) + 10);
00977    fs = alloca(strlen(path) + 20);
00978    if (!fs || !s) {
00979       ast_log(LOG_WARNING, "Out of memory!\n");
00980       return -1;
00981    }
00982    snprintf(fs, strlen(path) + 19, "%s/%s-%08x", path, ".lock", rand());
00983    fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
00984    if (fd < 0) {
00985       fprintf(stderr, "Unable to create lock file: %s\n", strerror(errno));
00986       return -1;
00987    }
00988    close(fd);
00989    snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
00990    time(&start);
00991    while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
00992       usleep(1);
00993    if (res < 0) {
00994       ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
00995    }
00996    unlink(fs);
00997    ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
00998    return res;
00999 }
01000 
01001 int ast_unlock_path(const char *path)
01002 {
01003    char *s;
01004    s = alloca(strlen(path) + 10);
01005    if (!s)
01006       return -1;
01007    snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
01008    ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
01009    return unlink(s);
01010 }
01011 

Generated on Sat Nov 25 19:09:28 2006 for Asterisk by  doxygen 1.4.2