00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <sys/time.h>
00029 #include <signal.h>
00030 #include <errno.h>
00031 #include <unistd.h>
00032 #include <dirent.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <regex.h>
00036
00037 #include "asterisk.h"
00038
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 74264 $")
00040
00041 #include "asterisk/channel.h"
00042 #include "asterisk/pbx.h"
00043 #include "asterisk/file.h"
00044 #include "asterisk/app.h"
00045 #include "asterisk/dsp.h"
00046 #include "asterisk/logger.h"
00047 #include "asterisk/options.h"
00048 #include "asterisk/utils.h"
00049 #include "asterisk/lock.h"
00050 #include "asterisk/indications.h"
00051 #include "asterisk/linkedlists.h"
00052
00053 #define MAX_OTHER_FORMATS 10
00054
00055 static AST_LIST_HEAD_STATIC(groups, ast_group_info);
00056
00057
00058
00059
00060
00061
00062
00063
00064 int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
00065 {
00066 struct tone_zone_sound *ts;
00067 int res=0, x=0;
00068
00069 if(maxlen > size)
00070 maxlen = size;
00071
00072 if(!timeout && chan->pbx)
00073 timeout = chan->pbx->dtimeout;
00074 else if(!timeout)
00075 timeout = 5;
00076
00077 ts = ast_get_indication_tone(chan->zone,"dial");
00078 if (ts && ts->data[0])
00079 res = ast_playtones_start(chan, 0, ts->data, 0);
00080 else
00081 ast_log(LOG_NOTICE,"Huh....? no dial for indications?\n");
00082
00083 for (x = strlen(collect); strlen(collect) < maxlen; ) {
00084 res = ast_waitfordigit(chan, timeout);
00085 if (!ast_ignore_pattern(context, collect))
00086 ast_playtones_stop(chan);
00087 if (res < 1)
00088 break;
00089 if (res == '#')
00090 break;
00091 collect[x++] = res;
00092 if (!ast_matchmore_extension(chan, context, collect, 1, chan->cid.cid_num))
00093 break;
00094 }
00095 if (res >= 0) {
00096 if (ast_exists_extension(chan, context, collect, 1, chan->cid.cid_num))
00097 res = 1;
00098 else
00099 res = 0;
00100 }
00101 return res;
00102 }
00103
00104
00105
00106
00107
00108 int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
00109 {
00110 int res,to,fto;
00111
00112 if (maxlen)
00113 s[0] = '\0';
00114 if (prompt) {
00115 res = ast_streamfile(c, prompt, c->language);
00116 if (res < 0)
00117 return res;
00118 }
00119 fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000;
00120 to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
00121
00122 if (timeout > 0)
00123 fto = to = timeout;
00124 if (timeout < 0)
00125 fto = to = 1000000000;
00126 res = ast_readstring(c, s, maxlen, to, fto, "#");
00127 return res;
00128 }
00129
00130
00131 int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
00132 {
00133 int res,to,fto;
00134 if (prompt) {
00135 res = ast_streamfile(c, prompt, c->language);
00136 if (res < 0)
00137 return res;
00138 }
00139 fto = 6000;
00140 to = 2000;
00141 if (timeout > 0)
00142 fto = to = timeout;
00143 if (timeout < 0)
00144 fto = to = 1000000000;
00145 res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
00146 return res;
00147 }
00148
00149 int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
00150 {
00151 int res;
00152 struct ast_filestream *writer;
00153 int rfmt;
00154 int totalms=0, total;
00155
00156 struct ast_frame *f;
00157 struct ast_dsp *sildet;
00158
00159 if (prompt) {
00160 res = ast_streamfile(c, prompt, c->language);
00161 if (res < 0)
00162 return res;
00163 res = ast_waitstream(c,"");
00164 if (res < 0)
00165 return res;
00166 }
00167 rfmt = c->readformat;
00168 res = ast_set_read_format(c, AST_FORMAT_SLINEAR);
00169 if (res < 0) {
00170 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00171 return -1;
00172 }
00173 sildet = ast_dsp_new();
00174 if (!sildet) {
00175 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00176 return -1;
00177 }
00178 writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
00179 if (!writer) {
00180 ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
00181 ast_dsp_free(sildet);
00182 return -1;
00183 }
00184 for(;;) {
00185 if ((res = ast_waitfor(c, 2000)) < 0) {
00186 ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
00187 break;
00188 }
00189 if (res) {
00190 f = ast_read(c);
00191 if (!f) {
00192 ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
00193 break;
00194 }
00195 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
00196
00197 ast_frfree(f);
00198 break;
00199 } else if (f->frametype == AST_FRAME_VOICE) {
00200 ast_dsp_silence(sildet, f, &total);
00201 if (total > silence) {
00202
00203 ast_frfree(f);
00204 break;
00205 }
00206 totalms += f->samples / 8;
00207 if (totalms > maxsec * 1000) {
00208
00209 ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
00210 ast_frfree(f);
00211 break;
00212 }
00213 res = ast_writestream(writer, f);
00214 if (res < 0) {
00215 ast_log(LOG_WARNING, "Failed to write to stream at %s!\n", dest);
00216 ast_frfree(f);
00217 break;
00218 }
00219
00220 }
00221 ast_frfree(f);
00222 }
00223 }
00224 res = ast_set_read_format(c, rfmt);
00225 if (res)
00226 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
00227 ast_dsp_free(sildet);
00228 ast_closestream(writer);
00229 return 0;
00230 }
00231
00232 static int (*ast_has_voicemail_func)(const char *mailbox, const char *folder) = NULL;
00233 static int (*ast_messagecount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL;
00234
00235 void ast_install_vm_functions(int (*has_voicemail_func)(const char *mailbox, const char *folder),
00236 int (*messagecount_func)(const char *mailbox, int *newmsgs, int *oldmsgs))
00237 {
00238 ast_has_voicemail_func = has_voicemail_func;
00239 ast_messagecount_func = messagecount_func;
00240 }
00241
00242 void ast_uninstall_vm_functions(void)
00243 {
00244 ast_has_voicemail_func = NULL;
00245 ast_messagecount_func = NULL;
00246 }
00247
00248 int ast_app_has_voicemail(const char *mailbox, const char *folder)
00249 {
00250 static int warned = 0;
00251 if (ast_has_voicemail_func)
00252 return ast_has_voicemail_func(mailbox, folder);
00253
00254 if ((option_verbose > 2) && !warned) {
00255 ast_verbose(VERBOSE_PREFIX_3 "Message check requested for mailbox %s/folder %s but voicemail not loaded.\n", mailbox, folder ? folder : "INBOX");
00256 warned++;
00257 }
00258 return 0;
00259 }
00260
00261
00262 int ast_app_messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
00263 {
00264 static int warned = 0;
00265 if (newmsgs)
00266 *newmsgs = 0;
00267 if (oldmsgs)
00268 *oldmsgs = 0;
00269 if (ast_messagecount_func)
00270 return ast_messagecount_func(mailbox, newmsgs, oldmsgs);
00271
00272 if (!warned && (option_verbose > 2)) {
00273 warned++;
00274 ast_verbose(VERBOSE_PREFIX_3 "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
00275 }
00276
00277 return 0;
00278 }
00279
00280 int ast_dtmf_stream(struct ast_channel *chan,struct ast_channel *peer,char *digits,int between)
00281 {
00282 char *ptr;
00283 int res = 0;
00284 struct ast_frame f;
00285 if (!between)
00286 between = 100;
00287
00288 if (peer)
00289 res = ast_autoservice_start(peer);
00290
00291 if (!res) {
00292 res = ast_waitfor(chan,100);
00293 if (res > -1) {
00294 for (ptr=digits; *ptr; ptr++) {
00295 if (*ptr == 'w') {
00296 res = ast_safe_sleep(chan, 500);
00297 if (res)
00298 break;
00299 continue;
00300 }
00301 memset(&f, 0, sizeof(f));
00302 f.frametype = AST_FRAME_DTMF;
00303 f.subclass = *ptr;
00304 f.src = "ast_dtmf_stream";
00305 if (strchr("0123456789*#abcdABCD",*ptr)==NULL) {
00306 ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr);
00307 } else {
00308 res = ast_write(chan, &f);
00309 if (res)
00310 break;
00311
00312 res = ast_safe_sleep(chan,between);
00313 if (res)
00314 break;
00315 }
00316 }
00317 }
00318 if (peer) {
00319
00320
00321 if (ast_autoservice_stop(peer) && !res)
00322 res = -1;
00323 }
00324 }
00325 return res;
00326 }
00327
00328 struct linear_state {
00329 int fd;
00330 int autoclose;
00331 int allowoverride;
00332 int origwfmt;
00333 };
00334
00335 static void linear_release(struct ast_channel *chan, void *params)
00336 {
00337 struct linear_state *ls = params;
00338 if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
00339 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt);
00340 }
00341 if (ls->autoclose)
00342 close(ls->fd);
00343 free(params);
00344 }
00345
00346 static int linear_generator(struct ast_channel *chan, void *data, int len, int samples)
00347 {
00348 struct ast_frame f;
00349 short buf[2048 + AST_FRIENDLY_OFFSET / 2];
00350 struct linear_state *ls = data;
00351 int res;
00352 len = samples * 2;
00353 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
00354 ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len);
00355 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
00356 }
00357 memset(&f, 0, sizeof(f));
00358 res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len);
00359 if (res > 0) {
00360 f.frametype = AST_FRAME_VOICE;
00361 f.subclass = AST_FORMAT_SLINEAR;
00362 f.data = buf + AST_FRIENDLY_OFFSET/2;
00363 f.datalen = res;
00364 f.samples = res / 2;
00365 f.offset = AST_FRIENDLY_OFFSET;
00366 ast_write(chan, &f);
00367 if (res == len)
00368 return 0;
00369 }
00370 return -1;
00371 }
00372
00373 static void *linear_alloc(struct ast_channel *chan, void *params)
00374 {
00375 struct linear_state *ls;
00376
00377 if (params) {
00378 ls = params;
00379 if (ls->allowoverride)
00380 ast_set_flag(chan, AST_FLAG_WRITE_INT);
00381 else
00382 ast_clear_flag(chan, AST_FLAG_WRITE_INT);
00383 ls->origwfmt = chan->writeformat;
00384 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00385 ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
00386 free(ls);
00387 ls = params = NULL;
00388 }
00389 }
00390 return params;
00391 }
00392
00393 static struct ast_generator linearstream =
00394 {
00395 alloc: linear_alloc,
00396 release: linear_release,
00397 generate: linear_generator,
00398 };
00399
00400 int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride)
00401 {
00402 struct linear_state *lin;
00403 char tmpf[256];
00404 int res = -1;
00405 int autoclose = 0;
00406 if (fd < 0) {
00407 if (ast_strlen_zero(filename))
00408 return -1;
00409 autoclose = 1;
00410 if (filename[0] == '/')
00411 ast_copy_string(tmpf, filename, sizeof(tmpf));
00412 else
00413 snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", (char *)ast_config_AST_VAR_DIR, "sounds", filename);
00414 fd = open(tmpf, O_RDONLY);
00415 if (fd < 0){
00416 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
00417 return -1;
00418 }
00419 }
00420 lin = malloc(sizeof(struct linear_state));
00421 if (lin) {
00422 memset(lin, 0, sizeof(lin));
00423 lin->fd = fd;
00424 lin->allowoverride = allowoverride;
00425 lin->autoclose = autoclose;
00426 res = ast_activate_generator(chan, &linearstream, lin);
00427 }
00428 return res;
00429 }
00430
00431 int ast_control_streamfile(struct ast_channel *chan, const char *file,
00432 const char *fwd, const char *rev,
00433 const char *stop, const char *pause,
00434 const char *restart, int skipms)
00435 {
00436 char *breaks = NULL;
00437 char *end = NULL;
00438 int blen = 2;
00439 int res;
00440 long pause_restart_point = 0;
00441
00442 if (stop)
00443 blen += strlen(stop);
00444 if (pause)
00445 blen += strlen(pause);
00446 if (restart)
00447 blen += strlen(restart);
00448
00449 if (blen > 2) {
00450 breaks = alloca(blen + 1);
00451 breaks[0] = '\0';
00452 if (stop)
00453 strcat(breaks, stop);
00454 if (pause)
00455 strcat(breaks, pause);
00456 if (restart)
00457 strcat(breaks, restart);
00458 }
00459 if (chan->_state != AST_STATE_UP)
00460 res = ast_answer(chan);
00461
00462 if (file) {
00463 if ((end = strchr(file,':'))) {
00464 if (!strcasecmp(end, ":end")) {
00465 *end = '\0';
00466 end++;
00467 }
00468 }
00469 }
00470
00471 for (;;) {
00472 ast_stopstream(chan);
00473 res = ast_streamfile(chan, file, chan->language);
00474 if (!res) {
00475 if (pause_restart_point) {
00476 ast_seekstream(chan->stream, pause_restart_point, SEEK_SET);
00477 pause_restart_point = 0;
00478 }
00479 else if (end) {
00480 ast_seekstream(chan->stream, 0, SEEK_END);
00481 end = NULL;
00482 };
00483 res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
00484 }
00485
00486 if (res < 1)
00487 break;
00488
00489
00490 if (restart && strchr(restart, res)) {
00491 ast_log(LOG_DEBUG, "we'll restart the stream here at next loop\n");
00492 pause_restart_point = 0;
00493 continue;
00494 }
00495
00496 if (pause && strchr(pause, res)) {
00497 pause_restart_point = ast_tellstream(chan->stream);
00498 for (;;) {
00499 ast_stopstream(chan);
00500 res = ast_waitfordigit(chan, 1000);
00501 if (!res)
00502 continue;
00503 else if (res == -1 || strchr(pause, res) || (stop && strchr(stop, res)))
00504 break;
00505 }
00506 if (res == *pause) {
00507 res = 0;
00508 continue;
00509 }
00510 }
00511
00512 if (res == -1)
00513 break;
00514
00515
00516 if (stop && strchr(stop, res))
00517 break;
00518 }
00519
00520 ast_stopstream(chan);
00521
00522 return res;
00523 }
00524
00525 int ast_play_and_wait(struct ast_channel *chan, const char *fn)
00526 {
00527 int d;
00528 d = ast_streamfile(chan, fn, chan->language);
00529 if (d)
00530 return d;
00531 d = ast_waitstream(chan, AST_DIGIT_ANY);
00532 ast_stopstream(chan);
00533 return d;
00534 }
00535
00536 static int global_silence_threshold = 128;
00537 static int global_maxsilence = 0;
00538
00539 int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf)
00540 {
00541 int d;
00542 char *fmts;
00543 char comment[256];
00544 int x, fmtcnt=1, res=-1,outmsg=0;
00545 struct ast_frame *f;
00546 struct ast_filestream *others[MAX_OTHER_FORMATS];
00547 char *sfmt[MAX_OTHER_FORMATS];
00548 char *stringp=NULL;
00549 time_t start, end;
00550 struct ast_dsp *sildet=NULL;
00551 int totalsilence = 0;
00552 int dspsilence = 0;
00553 int rfmt=0;
00554 struct ast_silence_generator *silgen = NULL;
00555
00556 if (silencethreshold < 0)
00557 silencethreshold = global_silence_threshold;
00558
00559 if (maxsilence < 0)
00560 maxsilence = global_maxsilence;
00561
00562
00563 if (duration == NULL) {
00564 ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
00565 return -1;
00566 }
00567
00568 ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00569 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00570
00571 if (playfile) {
00572 d = ast_play_and_wait(chan, playfile);
00573 if (d > -1)
00574 d = ast_streamfile(chan, "beep",chan->language);
00575 if (!d)
00576 d = ast_waitstream(chan,"");
00577 if (d < 0)
00578 return -1;
00579 }
00580
00581 fmts = ast_strdupa(fmt);
00582
00583 stringp=fmts;
00584 strsep(&stringp, "|");
00585 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
00586 sfmt[0] = ast_strdupa(fmts);
00587
00588 while((fmt = strsep(&stringp, "|"))) {
00589 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
00590 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
00591 break;
00592 }
00593 sfmt[fmtcnt++] = ast_strdupa(fmt);
00594 }
00595
00596 time(&start);
00597 end=start;
00598 for (x=0;x<fmtcnt;x++) {
00599 others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00600 ast_verbose( VERBOSE_PREFIX_3 "x=%d, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
00601
00602 if (!others[x]) {
00603 break;
00604 }
00605 }
00606
00607 if (path)
00608 ast_unlock_path(path);
00609
00610 if (maxsilence > 0) {
00611 sildet = ast_dsp_new();
00612 if (!sildet) {
00613 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00614 return -1;
00615 }
00616 ast_dsp_set_threshold(sildet, silencethreshold);
00617 rfmt = chan->readformat;
00618 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00619 if (res < 0) {
00620 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00621 ast_dsp_free(sildet);
00622 return -1;
00623 }
00624 }
00625
00626
00627 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
00628
00629 if (option_transmit_silence_during_record)
00630 silgen = ast_channel_start_silence_generator(chan);
00631
00632 if (x == fmtcnt) {
00633
00634
00635 f = NULL;
00636 for(;;) {
00637 res = ast_waitfor(chan, 2000);
00638 if (!res) {
00639 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
00640
00641 res = ast_waitfor(chan, 2000);
00642 if (!res) {
00643 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00644 res = -1;
00645 }
00646 }
00647
00648 if (res < 0) {
00649 f = NULL;
00650 break;
00651 }
00652 f = ast_read(chan);
00653 if (!f)
00654 break;
00655 if (f->frametype == AST_FRAME_VOICE) {
00656
00657 for (x=0;x<fmtcnt;x++) {
00658 res = ast_writestream(others[x], f);
00659 }
00660
00661
00662 if (maxsilence > 0) {
00663 dspsilence = 0;
00664 ast_dsp_silence(sildet, f, &dspsilence);
00665 if (dspsilence)
00666 totalsilence = dspsilence;
00667 else
00668 totalsilence = 0;
00669
00670 if (totalsilence > maxsilence) {
00671
00672 if (option_verbose > 2)
00673 ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00674 ast_frfree(f);
00675 res = 'S';
00676 outmsg=2;
00677 break;
00678 }
00679 }
00680
00681 if (res) {
00682 ast_log(LOG_WARNING, "Error writing frame\n");
00683 ast_frfree(f);
00684 break;
00685 }
00686 } else if (f->frametype == AST_FRAME_VIDEO) {
00687
00688 ast_writestream(others[0], f);
00689 } else if (f->frametype == AST_FRAME_DTMF) {
00690 if (strchr(acceptdtmf, f->subclass)) {
00691 if (option_verbose > 2)
00692 ast_verbose(VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
00693 res = f->subclass;
00694 outmsg = 2;
00695 ast_frfree(f);
00696 break;
00697 }
00698 if (strchr(canceldtmf, f->subclass)) {
00699 if (option_verbose > 2)
00700 ast_verbose(VERBOSE_PREFIX_3 "User cancelled message by pressing %c\n", f->subclass);
00701 res = f->subclass;
00702 outmsg = 0;
00703 ast_frfree(f);
00704 break;
00705 }
00706 }
00707 if (maxtime) {
00708 time(&end);
00709 if (maxtime < (end - start)) {
00710 if (option_verbose > 2)
00711 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00712 outmsg = 2;
00713 res = 't';
00714 ast_frfree(f);
00715 break;
00716 }
00717 }
00718 ast_frfree(f);
00719 }
00720 if (end == start) time(&end);
00721 if (!f) {
00722 if (option_verbose > 2)
00723 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
00724 res = -1;
00725 outmsg=1;
00726 }
00727 } else {
00728 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
00729 }
00730
00731 if (silgen)
00732 ast_channel_stop_silence_generator(chan, silgen);
00733
00734 *duration = end - start;
00735
00736 for (x=0;x<fmtcnt;x++) {
00737 if (!others[x])
00738 break;
00739 if (res > 0) {
00740 if (totalsilence)
00741 ast_stream_rewind(others[x], totalsilence-200);
00742 else
00743 ast_stream_rewind(others[x], 200);
00744 }
00745 ast_truncstream(others[x]);
00746 ast_closestream(others[x]);
00747 }
00748 if (rfmt) {
00749 if (ast_set_read_format(chan, rfmt)) {
00750 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00751 }
00752 }
00753 if (outmsg > 1) {
00754
00755 if(!ast_streamfile(chan, "auth-thankyou", chan->language))
00756 ast_waitstream(chan, "");
00757 }
00758 if (sildet)
00759 ast_dsp_free(sildet);
00760 return res;
00761 }
00762
00763 static char default_acceptdtmf[] = "#";
00764 static char default_canceldtmf[] = "0";
00765
00766 int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
00767 {
00768 return ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path, default_acceptdtmf, default_canceldtmf);
00769 }
00770
00771 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)
00772 {
00773 int d = 0;
00774 char *fmts;
00775 char comment[256];
00776 int x, fmtcnt=1, res=-1,outmsg=0;
00777 struct ast_frame *f;
00778 struct ast_filestream *others[MAX_OTHER_FORMATS];
00779 struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
00780 char *sfmt[MAX_OTHER_FORMATS];
00781 char *stringp=NULL;
00782 time_t start, end;
00783 struct ast_dsp *sildet;
00784 int totalsilence = 0;
00785 int dspsilence = 0;
00786 int rfmt=0;
00787 char prependfile[80];
00788
00789 if (silencethreshold < 0)
00790 silencethreshold = global_silence_threshold;
00791
00792 if (maxsilence < 0)
00793 maxsilence = global_maxsilence;
00794
00795
00796 if (duration == NULL) {
00797 ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
00798 return -1;
00799 }
00800
00801 ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00802 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00803
00804 if (playfile || beep) {
00805 if (!beep)
00806 d = ast_play_and_wait(chan, playfile);
00807 if (d > -1)
00808 d = ast_streamfile(chan, "beep",chan->language);
00809 if (!d)
00810 d = ast_waitstream(chan,"");
00811 if (d < 0)
00812 return -1;
00813 }
00814 ast_copy_string(prependfile, recordfile, sizeof(prependfile));
00815 strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
00816
00817 fmts = ast_strdupa(fmt);
00818
00819 stringp=fmts;
00820 strsep(&stringp, "|");
00821 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
00822 sfmt[0] = ast_strdupa(fmts);
00823
00824 while((fmt = strsep(&stringp, "|"))) {
00825 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
00826 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
00827 break;
00828 }
00829 sfmt[fmtcnt++] = ast_strdupa(fmt);
00830 }
00831
00832 time(&start);
00833 end=start;
00834 for (x=0;x<fmtcnt;x++) {
00835 others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00836 ast_verbose( VERBOSE_PREFIX_3 "x=%d, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
00837 if (!others[x]) {
00838 break;
00839 }
00840 }
00841
00842 sildet = ast_dsp_new();
00843 if (!sildet) {
00844 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00845 return -1;
00846 }
00847 ast_dsp_set_threshold(sildet, silencethreshold);
00848
00849 if (maxsilence > 0) {
00850 rfmt = chan->readformat;
00851 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00852 if (res < 0) {
00853 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00854 ast_dsp_free(sildet);
00855 return -1;
00856 }
00857 }
00858
00859 if (x == fmtcnt) {
00860
00861
00862 f = NULL;
00863 for(;;) {
00864 res = ast_waitfor(chan, 2000);
00865 if (!res) {
00866 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
00867
00868 res = ast_waitfor(chan, 2000);
00869 if (!res) {
00870 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00871 res = -1;
00872 }
00873 }
00874
00875 if (res < 0) {
00876 f = NULL;
00877 break;
00878 }
00879 f = ast_read(chan);
00880 if (!f)
00881 break;
00882 if (f->frametype == AST_FRAME_VOICE) {
00883
00884 for (x=0;x<fmtcnt;x++) {
00885 if (!others[x])
00886 break;
00887 res = ast_writestream(others[x], f);
00888 }
00889
00890
00891 if (maxsilence > 0) {
00892 dspsilence = 0;
00893 ast_dsp_silence(sildet, f, &dspsilence);
00894 if (dspsilence)
00895 totalsilence = dspsilence;
00896 else
00897 totalsilence = 0;
00898
00899 if (totalsilence > maxsilence) {
00900
00901 if (option_verbose > 2)
00902 ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00903 ast_frfree(f);
00904 res = 'S';
00905 outmsg=2;
00906 break;
00907 }
00908 }
00909
00910 if (res) {
00911 ast_log(LOG_WARNING, "Error writing frame\n");
00912 ast_frfree(f);
00913 break;
00914 }
00915 } else if (f->frametype == AST_FRAME_VIDEO) {
00916
00917 ast_writestream(others[0], f);
00918 } else if (f->frametype == AST_FRAME_DTMF) {
00919
00920 if (option_verbose > 2)
00921 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
00922 res = 't';
00923 outmsg = 2;
00924 ast_frfree(f);
00925 break;
00926 }
00927 if (maxtime) {
00928 time(&end);
00929 if (maxtime < (end - start)) {
00930 if (option_verbose > 2)
00931 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00932 res = 't';
00933 outmsg=2;
00934 ast_frfree(f);
00935 break;
00936 }
00937 }
00938 ast_frfree(f);
00939 }
00940 if (end == start) time(&end);
00941 if (!f) {
00942 if (option_verbose > 2)
00943 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
00944 res = -1;
00945 outmsg=1;
00946 #if 0
00947
00948 for (x=0;x<fmtcnt;x++) {
00949 if (!others[x])
00950 break;
00951 ast_closestream(others[x]);
00952 ast_filedelete(prependfile, sfmt[x]);
00953 }
00954 #endif
00955 }
00956 } else {
00957 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
00958 }
00959 ast_dsp_free(sildet);
00960 *duration = end - start;
00961 #if 0
00962 if (outmsg > 1) {
00963 #else
00964 if (outmsg) {
00965 #endif
00966 struct ast_frame *fr;
00967 for (x=0;x<fmtcnt;x++) {
00968 snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
00969 realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
00970 if (!others[x] || !realfiles[x])
00971 break;
00972 if (totalsilence)
00973 ast_stream_rewind(others[x], totalsilence-200);
00974 else
00975 ast_stream_rewind(others[x], 200);
00976 ast_truncstream(others[x]);
00977
00978 while ((fr = ast_readframe(realfiles[x]))) {
00979 ast_writestream(others[x],fr);
00980 }
00981 ast_closestream(others[x]);
00982 ast_closestream(realfiles[x]);
00983 ast_filerename(prependfile, recordfile, sfmt[x]);
00984 #if 0
00985 ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
00986 #endif
00987 ast_filedelete(prependfile, sfmt[x]);
00988 }
00989 }
00990 if (rfmt) {
00991 if (ast_set_read_format(chan, rfmt)) {
00992 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00993 }
00994 }
00995 if (outmsg) {
00996 if (outmsg > 1) {
00997
00998 ast_streamfile(chan, "auth-thankyou", chan->language);
00999 ast_waitstream(chan, "");
01000 }
01001 }
01002 return res;
01003 }
01004
01005
01006
01007 int ast_app_group_split_group(char *data, char *group, int group_max, char *category, int category_max)
01008 {
01009 int res=0;
01010 char tmp[256];
01011 char *grp=NULL, *cat=NULL;
01012
01013 if (!ast_strlen_zero(data)) {
01014 ast_copy_string(tmp, data, sizeof(tmp));
01015 grp = tmp;
01016 cat = strchr(tmp, '@');
01017 if (cat) {
01018 *cat = '\0';
01019 cat++;
01020 }
01021 }
01022
01023 if (!ast_strlen_zero(grp))
01024 ast_copy_string(group, grp, group_max);
01025 else
01026 res = -1;
01027
01028 if (!ast_strlen_zero(cat))
01029 ast_copy_string(category, cat, category_max);
01030
01031 return res;
01032 }
01033
01034 int ast_app_group_set_channel(struct ast_channel *chan, char *data)
01035 {
01036 int res = 0;
01037 char group[80] = "", category[80] = "";
01038 struct ast_group_info *gi = NULL;
01039 size_t len = 0;
01040
01041 if (ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category)))
01042 return -1;
01043
01044
01045 len = sizeof(*gi) + strlen(group) + 1;
01046 if (!ast_strlen_zero(category))
01047 len += strlen(category) + 1;
01048
01049 AST_LIST_LOCK(&groups);
01050 AST_LIST_TRAVERSE_SAFE_BEGIN(&groups, gi, list) {
01051 if ((gi->chan == chan) && ((ast_strlen_zero(category) && ast_strlen_zero(gi->category)) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
01052 AST_LIST_REMOVE_CURRENT(&groups, list);
01053 free(gi);
01054 break;
01055 }
01056 }
01057 AST_LIST_TRAVERSE_SAFE_END
01058
01059 if ((gi = calloc(1, len))) {
01060 gi->chan = chan;
01061 gi->group = (char *) gi + sizeof(*gi);
01062 strcpy(gi->group, group);
01063 if (!ast_strlen_zero(category)) {
01064 gi->category = (char *) gi + sizeof(*gi) + strlen(group) + 1;
01065 strcpy(gi->category, category);
01066 }
01067 AST_LIST_INSERT_TAIL(&groups, gi, list);
01068 } else {
01069 res = -1;
01070 }
01071
01072 AST_LIST_UNLOCK(&groups);
01073
01074 return res;
01075 }
01076
01077 int ast_app_group_get_count(