00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00037
00038 int ast_app_getdata(
struct ast_channel *c,
char *prompt,
char *s,
int maxlen,
int timeout)
00039 {
00040
int res,to,fto;
00041
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
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
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
00129
ast_frfree(f);
00130
break;
00131 }
00132 totalms += f->samples / 8;
00133
if (totalms > maxsec * 1000) {
00134
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
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
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
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
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;
00419
int blen=2;
00420
int res=0;
00421
00422
if (stop)
00423 blen += strlen(stop);
00424
if (pause)
00425 blen += strlen(pause);
00426
00427 breaks = alloca(blen + 1);
00428 breaks[0] =
'\0';
00429 strcat(breaks, stop);
00430 strcat(breaks, pause);
00431
00432
if (chan->
_state !=
AST_STATE_UP)
00433 res =
ast_answer(chan);
00434
00435
if (chan)
00436
ast_stopstream(chan);
00437
00438
for (;;) {
00439 gettimeofday(&started,NULL);
00440
00441
if (chan)
00442
ast_stopstream(chan);
00443 res =
ast_streamfile(chan, file, chan->
language);
00444
if (!res) {
00445 res = 1;
00446
if (elapsed) {
00447
ast_stream_fastforward(chan->
stream, elapsed);
00448 last_elapsed = elapsed - 200;
00449 }
00450
if (res)
00451 res =
ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
00452
else
00453
break;
00454 }
00455
00456
if (res < 1)
00457
break;
00458
00459
if (pause != NULL && strchr(pause, res)) {
00460 gettimeofday(&ended, NULL);
00461 elapsed = (((ended.tv_sec * 1000) + ended.tv_usec / 1000) - ((started.tv_sec * 1000) + started.tv_usec / 1000) + last_elapsed);
00462
for(;;) {
00463
if (chan)
00464
ast_stopstream(chan);
00465 res =
ast_waitfordigit(chan, 1000);
00466
if(res == 0)
00467
continue;
00468
else if(res == -1 || strchr(pause, res) || (stop && strchr(stop, res)))
00469
break;
00470 }
00471
if (res == *pause) {
00472 res = 0;
00473
continue;
00474 }
00475 }
00476
if (res == -1)
00477
break;
00478
00479
00480
if (stop && strchr(stop, res)) {
00481
00482
break;
00483 }
00484 }
00485
if (chan)
00486
ast_stopstream(chan);
00487
00488
return res;
00489 }
00490
00491 int ast_play_and_wait(
struct ast_channel *chan,
char *fn)
00492 {
00493
int d;
00494 d =
ast_streamfile(chan, fn, chan->
language);
00495
if (d)
00496
return d;
00497 d =
ast_waitstream(chan,
AST_DIGIT_ANY);
00498
ast_stopstream(chan);
00499
return d;
00500 }
00501
00502
static int global_silence_threshold = 128;
00503
static int global_maxsilence = 0;
00504
00505 int ast_play_and_record(
struct ast_channel *chan,
char *playfile,
char *recordfile,
int maxtime,
char *fmt,
int *duration,
int silencethreshold,
int maxsilence)
00506 {
00507
char d, *fmts;
00508
char comment[256];
00509
int x, fmtcnt=1, res=-1,outmsg=0;
00510
struct ast_frame *f;
00511
struct ast_filestream *others[
MAX_OTHER_FORMATS];
00512
char *sfmt[
MAX_OTHER_FORMATS];
00513
char *stringp=NULL;
00514 time_t start, end;
00515
struct ast_dsp *sildet;
00516
int totalsilence = 0;
00517
int dspsilence = 0;
00518
int gotsilence = 0;
00519
int rfmt=0;
00520
00521
if (silencethreshold < 0)
00522 silencethreshold = global_silence_threshold;
00523
00524
if (maxsilence < 0)
00525 maxsilence = global_maxsilence;
00526
00527
00528
if (duration == NULL) {
00529
ast_log(
LOG_WARNING,
"Error play_and_record called without duration pointer\n");
00530
return -1;
00531 }
00532
00533
ast_log(
LOG_DEBUG,
"play_and_record: %s, %s, '%s'\n", playfile ? playfile :
"<None>", recordfile, fmt);
00534 snprintf(comment,
sizeof(comment),
"Playing %s, Recording to: %s on %s\n", playfile ? playfile :
"<None>", recordfile, chan->
name);
00535
00536
if (playfile) {
00537 d =
ast_play_and_wait(chan, playfile);
00538
if (d > -1)
00539 d =
ast_streamfile(chan,
"beep",chan->
language);
00540
if (!d)
00541 d =
ast_waitstream(chan,
"");
00542
if (d < 0)
00543
return -1;
00544 }
00545
00546 fmts = ast_strdupa(fmt);
00547
00548 stringp=fmts;
00549 strsep(&stringp,
"|");
00550
ast_log(
LOG_DEBUG,
"Recording Formats: sfmts=%s\n", fmts);
00551 sfmt[0] = ast_strdupa(fmts);
00552
00553
while((fmt = strsep(&stringp,
"|"))) {
00554
if (fmtcnt >
MAX_OTHER_FORMATS - 1) {
00555
ast_log(
LOG_WARNING,
"Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
00556
break;
00557 }
00558 sfmt[fmtcnt++] = ast_strdupa(fmt);
00559 }
00560
00561 time(&start);
00562 end=start;
00563
for (x=0;x<fmtcnt;x++) {
00564 others[x] =
ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00565
ast_verbose(
VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
00566
00567
if (!others[x]) {
00568
break;
00569 }
00570 }
00571
00572 sildet =
ast_dsp_new();
00573
if (!sildet) {
00574
ast_log(
LOG_WARNING,
"Unable to create silence detector :(\n");
00575
return -1;
00576 }
00577
ast_dsp_set_threshold(sildet, silencethreshold);
00578
00579
if (maxsilence > 0) {
00580 rfmt = chan->
readformat;
00581 res =
ast_set_read_format(chan,
AST_FORMAT_SLINEAR);
00582
if (res < 0) {
00583
ast_log(
LOG_WARNING,
"Unable to set to linear mode, giving up\n");
00584
return -1;
00585 }
00586 }
00587
00588
if (x == fmtcnt) {
00589
00590
00591 f = NULL;
00592
for(;;) {
00593 res =
ast_waitfor(chan, 2000);
00594
if (!res) {
00595
ast_log(
LOG_DEBUG,
"One waitfor failed, trying another\n");
00596
00597 res =
ast_waitfor(chan, 2000);
00598
if (!res) {
00599
ast_log(
LOG_WARNING,
"No audio available on %s??\n", chan->
name);
00600 res = -1;
00601 }
00602 }
00603
00604
if (res < 0) {
00605 f = NULL;
00606
break;
00607 }
00608 f =
ast_read(chan);
00609
if (!f)
00610
break;
00611
if (f->
frametype ==
AST_FRAME_VOICE) {
00612
00613
for (x=0;x<fmtcnt;x++) {
00614 res =
ast_writestream(others[x], f);
00615 }
00616
00617
00618
if (maxsilence > 0) {
00619 dspsilence = 0;
00620
ast_dsp_silence(sildet, f, &dspsilence);
00621
if (dspsilence)
00622 totalsilence = dspsilence;
00623
else
00624 totalsilence = 0;
00625
00626
if (totalsilence > maxsilence) {
00627
00628
if (
option_verbose > 2)
00629
ast_verbose(
VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00630
ast_frfree(f);
00631 gotsilence = 1;
00632 outmsg=2;
00633
break;
00634 }
00635 }
00636
00637
if (res) {
00638
ast_log(
LOG_WARNING,
"Error writing frame\n");
00639
ast_frfree(f);
00640
break;
00641 }
00642 }
else if (f->
frametype ==
AST_FRAME_VIDEO) {
00643
00644
ast_writestream(others[0], f);
00645 }
else if (f->
frametype ==
AST_FRAME_DTMF) {
00646
if (f->
subclass ==
'#') {
00647
if (
option_verbose > 2)
00648
ast_verbose(
VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->
subclass);
00649 res =
'#';
00650 outmsg = 2;
00651
ast_frfree(f);
00652
break;
00653 }
00654 }
00655
if (f->
subclass ==
'0') {
00656
00657
if (
option_verbose > 2)
00658
ast_verbose(
VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->
subclass);
00659 res =
'0';
00660 outmsg = 0;
00661
ast_frfree(f);
00662
break;
00663 }
00664
if (maxtime) {
00665 time(&end);
00666
if (maxtime < (end - start)) {
00667
if (
option_verbose > 2)
00668
ast_verbose(
VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00669 outmsg = 2;
00670 res =
't';
00671
ast_frfree(f);
00672
break;
00673 }
00674 }
00675
ast_frfree(f);
00676 }
00677
if (end == start) time(&end);
00678
if (!f) {
00679
if (
option_verbose > 2)
00680
ast_verbose(
VERBOSE_PREFIX_3 "User hung up\n");
00681 res = -1;
00682 outmsg=1;
00683 }
00684 }
else {
00685
ast_log(
LOG_WARNING,
"Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
00686 }
00687
00688 *duration = end - start;
00689
00690
for (x=0;x<fmtcnt;x++) {
00691
if (!others[x])
00692
break;
00693
if (totalsilence)
00694
ast_stream_rewind(others[x], totalsilence-200);
00695
else
00696
ast_stream_rewind(others[x], 200);
00697
ast_truncstream(others[x]);
00698
ast_closestream(others[x]);
00699 }
00700
if (rfmt) {
00701
if (
ast_set_read_format(chan, rfmt)) {
00702
ast_log(
LOG_WARNING,
"Unable to restore format %s to channel '%s'\n",
ast_getformatname(rfmt), chan->
name);
00703 }
00704 }
00705
if (outmsg) {
00706
if (outmsg > 1) {
00707
00708
ast_streamfile(chan,
"auth-thankyou", chan->
language);
00709
ast_waitstream(chan,
"");
00710 }
00711 }
00712
00713
return res;
00714 }
00715
00716 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)
00717 {
00718
char d = 0, *fmts;
00719
char comment[256];
00720
int x, fmtcnt=1, res=-1,outmsg=0;
00721
struct ast_frame *f;
00722
struct ast_filestream *others[
MAX_OTHER_FORMATS];
00723
struct ast_filestream *realfiles[
MAX_OTHER_FORMATS];
00724
char *sfmt[
MAX_OTHER_FORMATS];
00725
char *stringp=NULL;
00726 time_t start, end;
00727
struct ast_dsp *sildet;
00728
int totalsilence = 0;
00729
int dspsilence = 0;
00730
int gotsilence = 0;
00731
int rfmt=0;
00732
char prependfile[80];
00733
00734
if (silencethreshold < 0)
00735 silencethreshold = global_silence_threshold;
00736
00737
if (maxsilence < 0)
00738 maxsilence = global_maxsilence;
00739
00740
00741
if (duration == NULL) {
00742
ast_log(
LOG_WARNING,
"Error play_and_prepend called without duration pointer\n");
00743
return -1;
00744 }
00745
00746
ast_log(
LOG_DEBUG,
"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile :
"<None>", recordfile, fmt);
00747 snprintf(comment,
sizeof(comment),
"Playing %s, Recording to: %s on %s\n", playfile ? playfile :
"<None>", recordfile, chan->
name);
00748
00749
if (playfile || beep) {
00750
if (!beep)
00751 d =
ast_play_and_wait(chan, playfile);
00752
if (d > -1)
00753 d =
ast_streamfile(chan,
"beep",chan->
language);
00754
if (!d)
00755 d =
ast_waitstream(chan,
"");
00756
if (d < 0)
00757
return -1;
00758 }
00759 strncpy(prependfile, recordfile,
sizeof(prependfile) -1);
00760 strncat(prependfile,
"-prepend",
sizeof(prependfile) - strlen(prependfile) - 1);
00761
00762 fmts = ast_strdupa(fmt);
00763
00764 stringp=fmts;
00765 strsep(&stringp,
"|");
00766
ast_log(
LOG_DEBUG,
"Recording Formats: sfmts=%s\n", fmts);
00767 sfmt[0] = ast_strdupa(fmts);
00768
00769
while((fmt = strsep(&stringp,
"|"))) {
00770
if (fmtcnt >
MAX_OTHER_FORMATS - 1) {
00771
ast_log(
LOG_WARNING,
"Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
00772
break;
00773 }
00774 sfmt[fmtcnt++] = ast_strdupa(fmt);
00775 }
00776
00777 time(&start);
00778 end=start;
00779
for (x=0;x<fmtcnt;x++) {
00780 others[x] =
ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00781
ast_verbose(
VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
00782
if (!others[x]) {
00783
break;
00784 }
00785 }
00786
00787 sildet =
ast_dsp_new();
00788
if (!sildet) {
00789
ast_log(
LOG_WARNING,
"Unable to create silence detector :(\n");
00790
return -1;
00791 }
00792
ast_dsp_set_threshold(sildet, silencethreshold);
00793
00794
if (maxsilence > 0) {
00795 rfmt = chan->
readformat;
00796 res =
ast_set_read_format(chan,
AST_FORMAT_SLINEAR);
00797
if (res < 0) {
00798
ast_log(
LOG_WARNING,
"Unable to set to linear mode, giving up\n");
00799
return -1;
00800 }
00801 }
00802
00803
if (x == fmtcnt) {
00804
00805
00806 f = NULL;
00807
for(;;) {
00808 res =
ast_waitfor(chan, 2000);
00809
if (!res) {
00810
ast_log(
LOG_DEBUG,
"One waitfor failed, trying another\n");
00811
00812 res =
ast_waitfor(chan, 2000);
00813
if (!res) {
00814
ast_log(
LOG_WARNING,
"No audio available on %s??\n", chan->
name);
00815 res = -1;
00816 }
00817 }
00818
00819
if (res < 0) {
00820 f = NULL;
00821
break;
00822 }
00823 f =
ast_read(chan);
00824
if (!f)
00825
break;
00826
if (f->
frametype ==
AST_FRAME_VOICE) {
00827
00828
for (x=0;x<fmtcnt;x++) {
00829
if (!others[x])
00830
break;
00831 res =
ast_writestream(others[x], f);
00832 }
00833
00834
00835
if (maxsilence > 0) {
00836 dspsilence = 0;
00837
ast_dsp_silence(sildet, f, &dspsilence);
00838
if (dspsilence)
00839 totalsilence = dspsilence;
00840
else
00841 totalsilence = 0;
00842
00843
if (totalsilence > maxsilence) {
00844
00845
if (
option_verbose > 2)
00846
ast_verbose(
VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00847
ast_frfree(f);
00848 gotsilence = 1;
00849 outmsg=2;
00850
break;
00851 }
00852 }
00853
00854
if (res) {
00855
ast_log(
LOG_WARNING,
"Error writing frame\n");
00856
ast_frfree(f);
00857
break;
00858 }
00859 }
else if (f->
frametype ==
AST_FRAME_VIDEO) {
00860
00861
ast_writestream(others[0], f);
00862 }
else if (f->
frametype ==
AST_FRAME_DTMF) {
00863
00864
if (
option_verbose > 2)
00865
ast_verbose(
VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->
subclass);
00866 res =
't';
00867 outmsg = 2;
00868
ast_frfree(f);
00869
break;
00870 }
00871
if (maxtime) {
00872 time(&end);
00873
if (maxtime < (end - start)) {
00874
if (
option_verbose > 2)
00875
ast_verbose(
VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00876 res =
't';
00877 outmsg=2;
00878
ast_frfree(f);
00879
break;
00880 }
00881 }
00882
ast_frfree(f);
00883 }
00884
if (end == start) time(&end);
00885
if (!f) {
00886
if (
option_verbose > 2)
00887
ast_verbose(
VERBOSE_PREFIX_3 "User hung up\n");
00888 res = -1;
00889 outmsg=1;
00890
#if 0
00891
00892
for (x=0;x<fmtcnt;x++) {
00893
if (!others[x])
00894
break;
00895
ast_closestream(others[x]);
00896
ast_filedelete(prependfile, sfmt[x]);
00897 }
00898
#endif
00899
}
00900 }
else {
00901
ast_log(
LOG_WARNING,
"Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
00902 }
00903 *duration = end - start;
00904
#if 0
00905
if (outmsg > 1) {
00906
#else
00907
if (outmsg) {
00908
#endif
00909
struct ast_frame *fr;
00910
for (x=0;x<fmtcnt;x++) {
00911 snprintf(comment,
sizeof(comment),
"Opening the real file %s.%s\n", recordfile, sfmt[x]);
00912 realfiles[x] =
ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
00913
if (!others[x] || !realfiles[x])
00914
break;
00915
if (totalsilence)
00916
ast_stream_rewind(others[x], totalsilence-200);
00917
else
00918
ast_stream_rewind(others[x], 200);
00919
ast_truncstream(others[x]);
00920
00921
while ((fr =
ast_readframe(realfiles[x]))) {
00922
ast_writestream(others[x],fr);
00923 }
00924
ast_closestream(others[x]);
00925
ast_closestream(realfiles[x]);
00926
ast_filerename(prependfile, recordfile, sfmt[x]);
00927
#if 0
00928
ast_verbose(
"Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
00929
#endif
00930
ast_filedelete(prependfile, sfmt[x]);
00931 }
00932 }
00933
if (rfmt) {
00934
if (
ast_set_read_format(chan, rfmt)) {
00935
ast_log(
LOG_WARNING,
"Unable to restore format %s to channel '%s'\n",
ast_getformatname(rfmt), chan->
name);
00936 }
00937 }
00938
if (outmsg) {
00939
if (outmsg > 1) {
00940
00941
ast_streamfile(chan,
"auth-thankyou", chan->
language);
00942
ast_waitstream(chan,
"");
00943 }
00944 }
00945
return res;
00946 }
00947