aboutsummaryrefslogtreecommitdiffstats
path: root/app.c
diff options
context:
space:
mode:
authormarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2004-09-17 15:05:29 +0000
committermarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2004-09-17 15:05:29 +0000
commit7dfcccd83f47c21b0c794133bea3ab2490169225 (patch)
treee0f7eac014e0aa3922c773f3a5d88a14c57603cc /app.c
parenta151a370524a5951a69ddd0de3cf4ad5b23fce5f (diff)
Move routines from voicemail to app for general use (part of bug #752)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@3801 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'app.c')
-rwxr-xr-xapp.c466
1 files changed, 463 insertions, 3 deletions
diff --git a/app.c b/app.c
index 401b4451a..29f446fd5 100755
--- a/app.c
+++ b/app.c
@@ -1,11 +1,11 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
- * Channel Management
+ * Convenient Application Routines
*
- * Copyright (C) 1999, Mark Spencer
+ * Copyright (C) 1999-2004, Digium, Inc.
*
- * Mark Spencer <markster@linux-support.net>
+ * Mark Spencer <markster@digium.com>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
@@ -31,6 +31,8 @@
#include "asterisk.h"
#include "astconf.h"
+#define MAX_OTHER_FORMATS 10
+
/* set timeout to 0 for "standard" timeouts. Set timeout to -1 for
"ludicrous time" (essentially never times out) */
int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
@@ -485,3 +487,461 @@ int ast_control_streamfile(struct ast_channel *chan, char *file, char *fwd, char
return res;
}
+
+int ast_play_and_wait(struct ast_channel *chan, char *fn)
+{
+ int d;
+ d = ast_streamfile(chan, fn, chan->language);
+ if (d)
+ return d;
+ d = ast_waitstream(chan, AST_DIGIT_ANY);
+ ast_stopstream(chan);
+ return d;
+}
+
+static int global_silence_threshold = 128;
+static int global_maxsilence = 0;
+
+int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int silencethreshold, int maxsilence)
+{
+ char d, *fmts;
+ char comment[256];
+ int x, fmtcnt=1, res=-1,outmsg=0;
+ struct ast_frame *f;
+ struct ast_filestream *others[MAX_OTHER_FORMATS];
+ char *sfmt[MAX_OTHER_FORMATS];
+ char *stringp=NULL;
+ time_t start, end;
+ struct ast_dsp *sildet; /* silence detector dsp */
+ int totalsilence = 0;
+ int dspsilence = 0;
+ int gotsilence = 0; /* did we timeout for silence? */
+ int rfmt=0;
+
+ if (silencethreshold < 0)
+ silencethreshold = global_silence_threshold;
+
+ if (maxsilence < 0)
+ maxsilence = global_maxsilence;
+
+ /* barf if no pointer passed to store duration in */
+ if (duration == NULL) {
+ ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
+ return -1;
+ }
+
+ ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
+ snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
+
+ if (playfile) {
+ d = ast_play_and_wait(chan, playfile);
+ if (d > -1)
+ d = ast_streamfile(chan, "beep",chan->language);
+ if (!d)
+ d = ast_waitstream(chan,"");
+ if (d < 0)
+ return -1;
+ }
+
+ fmts = ast_strdupa(fmt);
+
+ stringp=fmts;
+ strsep(&stringp, "|");
+ ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
+ sfmt[0] = ast_strdupa(fmts);
+
+ while((fmt = strsep(&stringp, "|"))) {
+ if (fmtcnt > MAX_OTHER_FORMATS - 1) {
+ ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
+ break;
+ }
+ sfmt[fmtcnt++] = ast_strdupa(fmt);
+ }
+
+ time(&start);
+ end=start; /* pre-initialize end to be same as start in case we never get into loop */
+ for (x=0;x<fmtcnt;x++) {
+ others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
+ ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
+
+ if (!others[x]) {
+ break;
+ }
+ }
+
+ sildet = ast_dsp_new(); /* Create the silence detector */
+ if (!sildet) {
+ ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
+ return -1;
+ }
+ ast_dsp_set_threshold(sildet, silencethreshold);
+
+ if (maxsilence > 0) {
+ rfmt = chan->readformat;
+ res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
+ return -1;
+ }
+ }
+
+ if (x == fmtcnt) {
+ /* Loop forever, writing the packets we read to the writer(s), until
+ we read a # or get a hangup */
+ f = NULL;
+ for(;;) {
+ res = ast_waitfor(chan, 2000);
+ if (!res) {
+ ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
+ /* Try one more time in case of masq */
+ res = ast_waitfor(chan, 2000);
+ if (!res) {
+ ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
+ res = -1;
+ }
+ }
+
+ if (res < 0) {
+ f = NULL;
+ break;
+ }
+ f = ast_read(chan);
+ if (!f)
+ break;
+ if (f->frametype == AST_FRAME_VOICE) {
+ /* write each format */
+ for (x=0;x<fmtcnt;x++) {
+ res = ast_writestream(others[x], f);
+ }
+
+ /* Silence Detection */
+ if (maxsilence > 0) {
+ dspsilence = 0;
+ ast_dsp_silence(sildet, f, &dspsilence);
+ if (dspsilence)
+ totalsilence = dspsilence;
+ else
+ totalsilence = 0;
+
+ if (totalsilence > maxsilence) {
+ /* Ended happily with silence */
+ if (option_verbose > 2)
+ ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
+ ast_frfree(f);
+ gotsilence = 1;
+ outmsg=2;
+ break;
+ }
+ }
+ /* Exit on any error */
+ if (res) {
+ ast_log(LOG_WARNING, "Error writing frame\n");
+ ast_frfree(f);
+ break;
+ }
+ } else if (f->frametype == AST_FRAME_VIDEO) {
+ /* Write only once */
+ ast_writestream(others[0], f);
+ } else if (f->frametype == AST_FRAME_DTMF) {
+ if (f->subclass == '#') {
+ if (option_verbose > 2)
+ ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
+ res = '#';
+ outmsg = 2;
+ ast_frfree(f);
+ break;
+ }
+ }
+ if (f->subclass == '0') {
+ /* Check for a '0' during message recording also, in case caller wants operator */
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
+ res = '0';
+ outmsg = 0;
+ ast_frfree(f);
+ break;
+ }
+ if (maxtime) {
+ time(&end);
+ if (maxtime < (end - start)) {
+ if (option_verbose > 2)
+ ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
+ outmsg = 2;
+ res = 't';
+ ast_frfree(f);
+ break;
+ }
+ }
+ ast_frfree(f);
+ }
+ if (end == start) time(&end);
+ if (!f) {
+ if (option_verbose > 2)
+ ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
+ res = -1;
+ outmsg=1;
+ }
+ } else {
+ ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
+ }
+
+ *duration = end - start;
+
+ for (x=0;x<fmtcnt;x++) {
+ if (!others[x])
+ break;
+ if (totalsilence)
+ ast_stream_rewind(others[x], totalsilence-200);
+ else
+ ast_stream_rewind(others[x], 200);
+ ast_truncstream(others[x]);
+ ast_closestream(others[x]);
+ }
+ if (rfmt) {
+ if (ast_set_read_format(chan, rfmt)) {
+ ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
+ }
+ }
+ if (outmsg) {
+ if (outmsg > 1) {
+ /* Let them know recording is stopped */
+ ast_streamfile(chan, "auth-thankyou", chan->language);
+ ast_waitstream(chan, "");
+ }
+ }
+
+ return res;
+}
+
+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)
+{
+ char d = 0, *fmts;
+ char comment[256];
+ int x, fmtcnt=1, res=-1,outmsg=0;
+ struct ast_frame *f;
+ struct ast_filestream *others[MAX_OTHER_FORMATS];
+ struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
+ char *sfmt[MAX_OTHER_FORMATS];
+ char *stringp=NULL;
+ time_t start, end;
+ struct ast_dsp *sildet; /* silence detector dsp */
+ int totalsilence = 0;
+ int dspsilence = 0;
+ int gotsilence = 0; /* did we timeout for silence? */
+ int rfmt=0;
+ char prependfile[80];
+
+ if (silencethreshold < 0)
+ silencethreshold = global_silence_threshold;
+
+ if (maxsilence < 0)
+ maxsilence = global_maxsilence;
+
+ /* barf if no pointer passed to store duration in */
+ if (duration == NULL) {
+ ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
+ return -1;
+ }
+
+ ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
+ snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
+
+ if (playfile || beep) {
+ if (!beep)
+ d = ast_play_and_wait(chan, playfile);
+ if (d > -1)
+ d = ast_streamfile(chan, "beep",chan->language);
+ if (!d)
+ d = ast_waitstream(chan,"");
+ if (d < 0)
+ return -1;
+ }
+ strncpy(prependfile, recordfile, sizeof(prependfile) -1);
+ strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
+
+ fmts = ast_strdupa(fmt);
+
+ stringp=fmts;
+ strsep(&stringp, "|");
+ ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
+ sfmt[0] = ast_strdupa(fmts);
+
+ while((fmt = strsep(&stringp, "|"))) {
+ if (fmtcnt > MAX_OTHER_FORMATS - 1) {
+ ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
+ break;
+ }
+ sfmt[fmtcnt++] = ast_strdupa(fmt);
+ }
+
+ time(&start);
+ end=start; /* pre-initialize end to be same as start in case we never get into loop */
+ for (x=0;x<fmtcnt;x++) {
+ others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
+ ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
+ if (!others[x]) {
+ break;
+ }
+ }
+
+ sildet = ast_dsp_new(); /* Create the silence detector */
+ if (!sildet) {
+ ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
+ return -1;
+ }
+ ast_dsp_set_threshold(sildet, silencethreshold);
+
+ if (maxsilence > 0) {
+ rfmt = chan->readformat;
+ res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
+ return -1;
+ }
+ }
+
+ if (x == fmtcnt) {
+ /* Loop forever, writing the packets we read to the writer(s), until
+ we read a # or get a hangup */
+ f = NULL;
+ for(;;) {
+ res = ast_waitfor(chan, 2000);
+ if (!res) {
+ ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
+ /* Try one more time in case of masq */
+ res = ast_waitfor(chan, 2000);
+ if (!res) {
+ ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
+ res = -1;
+ }
+ }
+
+ if (res < 0) {
+ f = NULL;
+ break;
+ }
+ f = ast_read(chan);
+ if (!f)
+ break;
+ if (f->frametype == AST_FRAME_VOICE) {
+ /* write each format */
+ for (x=0;x<fmtcnt;x++) {
+ if (!others[x])
+ break;
+ res = ast_writestream(others[x], f);
+ }
+
+ /* Silence Detection */
+ if (maxsilence > 0) {
+ dspsilence = 0;
+ ast_dsp_silence(sildet, f, &dspsilence);
+ if (dspsilence)
+ totalsilence = dspsilence;
+ else
+ totalsilence = 0;
+
+ if (totalsilence > maxsilence) {
+ /* Ended happily with silence */
+ if (option_verbose > 2)
+ ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
+ ast_frfree(f);
+ gotsilence = 1;
+ outmsg=2;
+ break;
+ }
+ }
+ /* Exit on any error */
+ if (res) {
+ ast_log(LOG_WARNING, "Error writing frame\n");
+ ast_frfree(f);
+ break;
+ }
+ } else if (f->frametype == AST_FRAME_VIDEO) {
+ /* Write only once */
+ ast_writestream(others[0], f);
+ } else if (f->frametype == AST_FRAME_DTMF) {
+ /* stop recording with any digit */
+ if (option_verbose > 2)
+ ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
+ res = 't';
+ outmsg = 2;
+ ast_frfree(f);
+ break;
+ }
+ if (maxtime) {
+ time(&end);
+ if (maxtime < (end - start)) {
+ if (option_verbose > 2)
+ ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
+ res = 't';
+ outmsg=2;
+ ast_frfree(f);
+ break;
+ }
+ }
+ ast_frfree(f);
+ }
+ if (end == start) time(&end);
+ if (!f) {
+ if (option_verbose > 2)
+ ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
+ res = -1;
+ outmsg=1;
+#if 0
+ /* delete all the prepend files */
+ for (x=0;x<fmtcnt;x++) {
+ if (!others[x])
+ break;
+ ast_closestream(others[x]);
+ ast_filedelete(prependfile, sfmt[x]);
+ }
+#endif
+ }
+ } else {
+ ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
+ }
+ *duration = end - start;
+#if 0
+ if (outmsg > 1) {
+#else
+ if (outmsg) {
+#endif
+ struct ast_frame *fr;
+ for (x=0;x<fmtcnt;x++) {
+ snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
+ realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
+ if (!others[x] || !realfiles[x])
+ break;
+ if (totalsilence)
+ ast_stream_rewind(others[x], totalsilence-200);
+ else
+ ast_stream_rewind(others[x], 200);
+ ast_truncstream(others[x]);
+ /* add the original file too */
+ while ((fr = ast_readframe(realfiles[x]))) {
+ ast_writestream(others[x],fr);
+ }
+ ast_closestream(others[x]);
+ ast_closestream(realfiles[x]);
+ ast_filerename(prependfile, recordfile, sfmt[x]);
+#if 0
+ ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
+#endif
+ ast_filedelete(prependfile, sfmt[x]);
+ }
+ }
+ if (rfmt) {
+ if (ast_set_read_format(chan, rfmt)) {
+ ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
+ }
+ }
+ if (outmsg) {
+ if (outmsg > 1) {
+ /* Let them know it worked */
+ ast_streamfile(chan, "auth-thankyou", chan->language);
+ ast_waitstream(chan, "");
+ }
+ }
+ return res;
+}
+