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=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
00496 if (stop && strchr(stop, res)) {
00497
00498 break;
00499 }
00500 }
00501 if (chan)
00502 ast_stopstream(chan);
00503
00504 return res;
00505 }
00506
00507 int ast_play_and_wait(struct ast_channel *chan, char *fn)
00508 {
00509 int d;
00510 d = ast_streamfile(chan, fn, chan->language);
00511 if (d)
00512 return d;
00513 d = ast_waitstream(chan, AST_DIGIT_ANY);
00514 ast_stopstream(chan);
00515 return d;
00516 }
00517
00518 static int global_silence_threshold = 128;
00519 static int global_maxsilence = 0;
00520
00521 int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
00522 {
00523 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;
00533 int totalsilence = 0;
00534 int dspsilence = 0;
00535 int gotsilence = 0;
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
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;
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();
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
00611
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
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
00634 for (x=0;x<fmtcnt;x++) {
00635 res = ast_writestream(others[x], f);
00636 }
00637
00638
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
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
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
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
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
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 }
00737
00738 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)
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;
00751 int totalsilence = 0;
00752 int dspsilence = 0;
00753 int gotsilence = 0;
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
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;
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();
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
00828
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
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
00851 for (x=0;x<fmtcnt;x++) {
00852 if (!others[x])
00853 break;
00854 res = ast_writestream(others[x], f);
00855 }
00856
00857
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
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
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
00884 ast_writestream(others[0], f);
00885 } else if (f->frametype == AST_FRAME_DTMF) {
00886
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
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
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
00964 ast_streamfile(chan, "auth-thankyou", chan->language);
00965 ast_waitstream(chan, "");
00966 }
00967 }
00968 return res;
00969 }
00970
00971 int ast_lock_path(const char *path)
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 }
01002
01003 int ast_unlock_path(const char *path)
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 }
01013