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