#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"
Go to the source code of this file.
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) |
|
Definition at line 34 of file app.c. Referenced by ast_play_and_prepend(), and ast_play_and_record(). |
|
Plays a stream and gets DTMF data from a channel.
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 }
|
|
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 }
|
|
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 }
|
|
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 }
|
|
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 }
|
|
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 }
|
|
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 }
|
|
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 }
|
|
Definition at line 969 of file app.c. References ast_log(), LOG_DEBUG, LOG_WARNING, and s. 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 }
|
|
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 737 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. 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 }
|
|
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 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 }
|
|
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 }
|
|
Definition at line 1001 of file app.c. References ast_log(), LOG_DEBUG, and s. Referenced by ast_play_and_record(). 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 }
|