app.c 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * Convenient Application Routines
  5. *
  6. * Copyright (C) 1999-2004, Digium, Inc.
  7. *
  8. * Mark Spencer <markster@digium.com>
  9. *
  10. * This program is free software, distributed under the terms of
  11. * the GNU General Public License
  12. */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <sys/time.h>
  17. #include <signal.h>
  18. #include <errno.h>
  19. #include <unistd.h>
  20. #include <dirent.h>
  21. #include <asterisk/channel.h>
  22. #include <asterisk/pbx.h>
  23. #include <asterisk/file.h>
  24. #include <asterisk/app.h>
  25. #include <asterisk/dsp.h>
  26. #include <asterisk/logger.h>
  27. #include <asterisk/options.h>
  28. #include <asterisk/utils.h>
  29. #include <asterisk/lock.h>
  30. #include "asterisk.h"
  31. #include "astconf.h"
  32. #define MAX_OTHER_FORMATS 10
  33. /* set timeout to 0 for "standard" timeouts. Set timeout to -1 for
  34. "ludicrous time" (essentially never times out) */
  35. int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
  36. {
  37. int res,to,fto;
  38. /* XXX Merge with full version? XXX */
  39. if (maxlen)
  40. s[0] = '\0';
  41. if (prompt) {
  42. res = ast_streamfile(c, prompt, c->language);
  43. if (res < 0)
  44. return res;
  45. }
  46. fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000;
  47. to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
  48. if (timeout > 0) fto = to = timeout;
  49. if (timeout < 0) fto = to = 1000000000;
  50. res = ast_readstring(c, s, maxlen, to, fto, "#");
  51. return res;
  52. }
  53. int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
  54. {
  55. int res,to,fto;
  56. if (prompt) {
  57. res = ast_streamfile(c, prompt, c->language);
  58. if (res < 0)
  59. return res;
  60. }
  61. fto = 6000;
  62. to = 2000;
  63. if (timeout > 0) fto = to = timeout;
  64. if (timeout < 0) fto = to = 1000000000;
  65. res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
  66. return res;
  67. }
  68. int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
  69. {
  70. int res;
  71. struct ast_filestream *writer;
  72. int rfmt;
  73. int totalms=0, total;
  74. struct ast_frame *f;
  75. struct ast_dsp *sildet;
  76. /* Play prompt if requested */
  77. if (prompt) {
  78. res = ast_streamfile(c, prompt, c->language);
  79. if (res < 0)
  80. return res;
  81. res = ast_waitstream(c,"");
  82. if (res < 0)
  83. return res;
  84. }
  85. rfmt = c->readformat;
  86. res = ast_set_read_format(c, AST_FORMAT_SLINEAR);
  87. if (res < 0) {
  88. ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
  89. return -1;
  90. }
  91. sildet = ast_dsp_new();
  92. if (!sildet) {
  93. ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
  94. return -1;
  95. }
  96. writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
  97. if (!writer) {
  98. ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
  99. ast_dsp_free(sildet);
  100. return -1;
  101. }
  102. for(;;) {
  103. if ((res = ast_waitfor(c, 2000)) < 0) {
  104. ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
  105. break;
  106. }
  107. if (res) {
  108. f = ast_read(c);
  109. if (!f) {
  110. ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
  111. break;
  112. }
  113. if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
  114. /* Ended happily with DTMF */
  115. ast_frfree(f);
  116. break;
  117. } else if (f->frametype == AST_FRAME_VOICE) {
  118. ast_dsp_silence(sildet, f, &total);
  119. if (total > silence) {
  120. /* Ended happily with silence */
  121. ast_frfree(f);
  122. break;
  123. }
  124. totalms += f->samples / 8;
  125. if (totalms > maxsec * 1000) {
  126. /* Ended happily with too much stuff */
  127. ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
  128. ast_frfree(f);
  129. break;
  130. }
  131. res = ast_writestream(writer, f);
  132. if (res < 0) {
  133. ast_log(LOG_WARNING, "Failed to write to stream at %s!\n", dest);
  134. ast_frfree(f);
  135. break;
  136. }
  137. }
  138. ast_frfree(f);
  139. }
  140. }
  141. res = ast_set_read_format(c, rfmt);
  142. if (res)
  143. ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
  144. ast_dsp_free(sildet);
  145. ast_closestream(writer);
  146. return 0;
  147. }
  148. int ast_app_has_voicemail(const char *mailbox)
  149. {
  150. DIR *dir;
  151. struct dirent *de;
  152. char fn[256];
  153. char tmp[256]="";
  154. char *mb, *cur;
  155. char *context;
  156. int ret;
  157. /* If no mailbox, return immediately */
  158. if (ast_strlen_zero(mailbox))
  159. return 0;
  160. if (strchr(mailbox, ',')) {
  161. strncpy(tmp, mailbox, sizeof(tmp) - 1);
  162. mb = tmp;
  163. ret = 0;
  164. while((cur = strsep(&mb, ","))) {
  165. if (!ast_strlen_zero(cur)) {
  166. if (ast_app_has_voicemail(cur))
  167. return 1;
  168. }
  169. }
  170. return 0;
  171. }
  172. strncpy(tmp, mailbox, sizeof(tmp) - 1);
  173. context = strchr(tmp, '@');
  174. if (context) {
  175. *context = '\0';
  176. context++;
  177. } else
  178. context = "default";
  179. snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, context, tmp);
  180. dir = opendir(fn);
  181. if (!dir)
  182. return 0;
  183. while ((de = readdir(dir))) {
  184. if (!strncasecmp(de->d_name, "msg", 3))
  185. break;
  186. }
  187. closedir(dir);
  188. if (de)
  189. return 1;
  190. return 0;
  191. }
  192. int ast_app_messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
  193. {
  194. DIR *dir;
  195. struct dirent *de;
  196. char fn[256];
  197. char tmp[256]="";
  198. char *mb, *cur;
  199. char *context;
  200. int ret;
  201. if (newmsgs)
  202. *newmsgs = 0;
  203. if (oldmsgs)
  204. *oldmsgs = 0;
  205. /* If no mailbox, return immediately */
  206. if (ast_strlen_zero(mailbox))
  207. return 0;
  208. if (strchr(mailbox, ',')) {
  209. int tmpnew, tmpold;
  210. strncpy(tmp, mailbox, sizeof(tmp) - 1);
  211. mb = tmp;
  212. ret = 0;
  213. while((cur = strsep(&mb, ", "))) {
  214. if (!ast_strlen_zero(cur)) {
  215. if (ast_app_messagecount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
  216. return -1;
  217. else {
  218. if (newmsgs)
  219. *newmsgs += tmpnew;
  220. if (oldmsgs)
  221. *oldmsgs += tmpold;
  222. }
  223. }
  224. }
  225. return 0;
  226. }
  227. strncpy(tmp, mailbox, sizeof(tmp) - 1);
  228. context = strchr(tmp, '@');
  229. if (context) {
  230. *context = '\0';
  231. context++;
  232. } else
  233. context = "default";
  234. if (newmsgs) {
  235. snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, context, tmp);
  236. dir = opendir(fn);
  237. if (dir) {
  238. while ((de = readdir(dir))) {
  239. if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) &&
  240. !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt"))
  241. (*newmsgs)++;
  242. }
  243. closedir(dir);
  244. }
  245. }
  246. if (oldmsgs) {
  247. snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/Old", (char *)ast_config_AST_SPOOL_DIR, context, tmp);
  248. dir = opendir(fn);
  249. if (dir) {
  250. while ((de = readdir(dir))) {
  251. if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) &&
  252. !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt"))
  253. (*oldmsgs)++;
  254. }
  255. closedir(dir);
  256. }
  257. }
  258. return 0;
  259. }
  260. int ast_dtmf_stream(struct ast_channel *chan,struct ast_channel *peer,char *digits,int between)
  261. {
  262. char *ptr=NULL;
  263. int res=0;
  264. struct ast_frame f;
  265. if (!between)
  266. between = 100;
  267. if (peer)
  268. res = ast_autoservice_start(peer);
  269. if (!res) {
  270. res = ast_waitfor(chan,100);
  271. if (res > -1) {
  272. for (ptr=digits; *ptr; ptr++) {
  273. if (*ptr == 'w') {
  274. res = ast_safe_sleep(chan, 500);
  275. if (res)
  276. break;
  277. continue;
  278. }
  279. memset(&f, 0, sizeof(f));
  280. f.frametype = AST_FRAME_DTMF;
  281. f.subclass = *ptr;
  282. f.src = "ast_dtmf_stream";
  283. if (strchr("0123456789*#abcdABCD",*ptr)==NULL) {
  284. ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr);
  285. } else {
  286. res = ast_write(chan, &f);
  287. if (res)
  288. break;
  289. /* pause between digits */
  290. res = ast_safe_sleep(chan,between);
  291. if (res)
  292. break;
  293. }
  294. }
  295. }
  296. if (peer)
  297. res = ast_autoservice_stop(peer);
  298. }
  299. return res;
  300. }
  301. struct linear_state {
  302. int fd;
  303. int autoclose;
  304. int allowoverride;
  305. int origwfmt;
  306. };
  307. static void linear_release(struct ast_channel *chan, void *params)
  308. {
  309. struct linear_state *ls = params;
  310. if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
  311. ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt);
  312. }
  313. if (ls->autoclose)
  314. close(ls->fd);
  315. free(params);
  316. }
  317. static int linear_generator(struct ast_channel *chan, void *data, int len, int samples)
  318. {
  319. struct ast_frame f;
  320. short buf[2048 + AST_FRIENDLY_OFFSET / 2];
  321. struct linear_state *ls = data;
  322. int res;
  323. len = samples * 2;
  324. if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
  325. ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len);
  326. len = sizeof(buf) - AST_FRIENDLY_OFFSET;
  327. }
  328. memset(&f, 0, sizeof(f));
  329. res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len);
  330. if (res > 0) {
  331. f.frametype = AST_FRAME_VOICE;
  332. f.subclass = AST_FORMAT_SLINEAR;
  333. f.data = buf + AST_FRIENDLY_OFFSET/2;
  334. f.datalen = res;
  335. f.samples = res / 2;
  336. f.offset = AST_FRIENDLY_OFFSET;
  337. ast_write(chan, &f);
  338. if (res == len)
  339. return 0;
  340. }
  341. return -1;
  342. }
  343. static void *linear_alloc(struct ast_channel *chan, void *params)
  344. {
  345. struct linear_state *ls;
  346. /* In this case, params is already malloc'd */
  347. if (params) {
  348. ls = params;
  349. if (ls->allowoverride)
  350. chan->writeinterrupt = 1;
  351. else
  352. chan->writeinterrupt = 0;
  353. ls->origwfmt = chan->writeformat;
  354. if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
  355. ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
  356. free(ls);
  357. ls = params = NULL;
  358. }
  359. }
  360. return params;
  361. }
  362. static struct ast_generator linearstream =
  363. {
  364. alloc: linear_alloc,
  365. release: linear_release,
  366. generate: linear_generator,
  367. };
  368. int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride)
  369. {
  370. struct linear_state *lin;
  371. char tmpf[256] = "";
  372. int res = -1;
  373. int autoclose = 0;
  374. if (fd < 0) {
  375. if (!filename || ast_strlen_zero(filename))
  376. return -1;
  377. autoclose = 1;
  378. if (filename[0] == '/')
  379. strncpy(tmpf, filename, sizeof(tmpf) - 1);
  380. else
  381. snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", (char *)ast_config_AST_VAR_DIR, "sounds", filename);
  382. fd = open(tmpf, O_RDONLY);
  383. if (fd < 0){
  384. ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
  385. return -1;
  386. }
  387. }
  388. lin = malloc(sizeof(struct linear_state));
  389. if (lin) {
  390. memset(lin, 0, sizeof(lin));
  391. lin->fd = fd;
  392. lin->allowoverride = allowoverride;
  393. lin->autoclose = autoclose;
  394. res = ast_activate_generator(chan, &linearstream, lin);
  395. }
  396. return res;
  397. }
  398. int ast_control_streamfile(struct ast_channel *chan, char *file, char *fwd, char *rev, char *stop, char *pause, int skipms)
  399. {
  400. struct timeval started, ended;
  401. long elapsed = 0,last_elapsed =0;
  402. char *breaks=NULL;
  403. char *end=NULL;
  404. int blen=2;
  405. int res=0;
  406. if (stop)
  407. blen += strlen(stop);
  408. if (pause)
  409. blen += strlen(pause);
  410. if (blen > 2) {
  411. breaks = alloca(blen + 1);
  412. breaks[0] = '\0';
  413. strcat(breaks, stop);
  414. strcat(breaks, pause);
  415. }
  416. if (chan->_state != AST_STATE_UP)
  417. res = ast_answer(chan);
  418. if (chan)
  419. ast_stopstream(chan);
  420. if (file) {
  421. if ((end = strchr(file,':'))) {
  422. if (!strcasecmp(end, ":end")) {
  423. *end = '\0';
  424. end++;
  425. }
  426. }
  427. }
  428. for (;;) {
  429. gettimeofday(&started,NULL);
  430. if (chan)
  431. ast_stopstream(chan);
  432. res = ast_streamfile(chan, file, chan->language);
  433. if (!res) {
  434. if (end) {
  435. ast_seekstream(chan->stream, 0, SEEK_END);
  436. end=NULL;
  437. }
  438. res = 1;
  439. if (elapsed) {
  440. ast_stream_fastforward(chan->stream, elapsed);
  441. last_elapsed = elapsed - 200;
  442. }
  443. if (res)
  444. res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
  445. else
  446. break;
  447. }
  448. if (res < 1)
  449. break;
  450. if (pause != NULL && strchr(pause, res)) {
  451. gettimeofday(&ended, NULL);
  452. elapsed = (((ended.tv_sec * 1000) + ended.tv_usec / 1000) - ((started.tv_sec * 1000) + started.tv_usec / 1000) + last_elapsed);
  453. for(;;) {
  454. if (chan)
  455. ast_stopstream(chan);
  456. res = ast_waitfordigit(chan, 1000);
  457. if (res == 0)
  458. continue;
  459. else if (res == -1 || strchr(pause, res) || (stop && strchr(stop, res)))
  460. break;
  461. }
  462. if (res == *pause) {
  463. res = 0;
  464. continue;
  465. }
  466. }
  467. if (res == -1)
  468. break;
  469. /* if we get one of our stop chars, return it to the calling function */
  470. if (stop && strchr(stop, res)) {
  471. /* res = 0; */
  472. break;
  473. }
  474. }
  475. if (chan)
  476. ast_stopstream(chan);
  477. return res;
  478. }
  479. int ast_play_and_wait(struct ast_channel *chan, char *fn)
  480. {
  481. int d;
  482. d = ast_streamfile(chan, fn, chan->language);
  483. if (d)
  484. return d;
  485. d = ast_waitstream(chan, AST_DIGIT_ANY);
  486. ast_stopstream(chan);
  487. return d;
  488. }
  489. static int global_silence_threshold = 128;
  490. static int global_maxsilence = 0;
  491. 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)
  492. {
  493. int d;
  494. char *fmts;
  495. char comment[256];
  496. int x, fmtcnt=1, res=-1,outmsg=0;
  497. struct ast_frame *f;
  498. struct ast_filestream *others[MAX_OTHER_FORMATS];
  499. char *sfmt[MAX_OTHER_FORMATS];
  500. char *stringp=NULL;
  501. time_t start, end;
  502. struct ast_dsp *sildet=NULL; /* silence detector dsp */
  503. int totalsilence = 0;
  504. int dspsilence = 0;
  505. int gotsilence = 0; /* did we timeout for silence? */
  506. int rfmt=0;
  507. if (silencethreshold < 0)
  508. silencethreshold = global_silence_threshold;
  509. if (maxsilence < 0)
  510. maxsilence = global_maxsilence;
  511. /* barf if no pointer passed to store duration in */
  512. if (duration == NULL) {
  513. ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
  514. return -1;
  515. }
  516. ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
  517. snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
  518. if (playfile) {
  519. d = ast_play_and_wait(chan, playfile);
  520. if (d > -1)
  521. d = ast_streamfile(chan, "beep",chan->language);
  522. if (!d)
  523. d = ast_waitstream(chan,"");
  524. if (d < 0)
  525. return -1;
  526. }
  527. fmts = ast_strdupa(fmt);
  528. stringp=fmts;
  529. strsep(&stringp, "|");
  530. ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
  531. sfmt[0] = ast_strdupa(fmts);
  532. while((fmt = strsep(&stringp, "|"))) {
  533. if (fmtcnt > MAX_OTHER_FORMATS - 1) {
  534. ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
  535. break;
  536. }
  537. sfmt[fmtcnt++] = ast_strdupa(fmt);
  538. }
  539. time(&start);
  540. end=start; /* pre-initialize end to be same as start in case we never get into loop */
  541. for (x=0;x<fmtcnt;x++) {
  542. others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
  543. ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
  544. if (!others[x]) {
  545. break;
  546. }
  547. }
  548. if (path)
  549. ast_unlock_path(path);
  550. if (maxsilence > 0) {
  551. sildet = ast_dsp_new(); /* Create the silence detector */
  552. if (!sildet) {
  553. ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
  554. return -1;
  555. }
  556. ast_dsp_set_threshold(sildet, silencethreshold);
  557. rfmt = chan->readformat;
  558. res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
  559. if (res < 0) {
  560. ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
  561. ast_dsp_free(sildet);
  562. return -1;
  563. }
  564. }
  565. if (x == fmtcnt) {
  566. /* Loop forever, writing the packets we read to the writer(s), until
  567. we read a # or get a hangup */
  568. f = NULL;
  569. for(;;) {
  570. res = ast_waitfor(chan, 2000);
  571. if (!res) {
  572. ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
  573. /* Try one more time in case of masq */
  574. res = ast_waitfor(chan, 2000);
  575. if (!res) {
  576. ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
  577. res = -1;
  578. }
  579. }
  580. if (res < 0) {
  581. f = NULL;
  582. break;
  583. }
  584. f = ast_read(chan);
  585. if (!f)
  586. break;
  587. if (f->frametype == AST_FRAME_VOICE) {
  588. /* write each format */
  589. for (x=0;x<fmtcnt;x++) {
  590. res = ast_writestream(others[x], f);
  591. }
  592. /* Silence Detection */
  593. if (maxsilence > 0) {
  594. dspsilence = 0;
  595. ast_dsp_silence(sildet, f, &dspsilence);
  596. if (dspsilence)
  597. totalsilence = dspsilence;
  598. else
  599. totalsilence = 0;
  600. if (totalsilence > maxsilence) {
  601. /* Ended happily with silence */
  602. if (option_verbose > 2)
  603. ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
  604. ast_frfree(f);
  605. gotsilence = 1;
  606. outmsg=2;
  607. break;
  608. }
  609. }
  610. /* Exit on any error */
  611. if (res) {
  612. ast_log(LOG_WARNING, "Error writing frame\n");
  613. ast_frfree(f);
  614. break;
  615. }
  616. } else if (f->frametype == AST_FRAME_VIDEO) {
  617. /* Write only once */
  618. ast_writestream(others[0], f);
  619. } else if (f->frametype == AST_FRAME_DTMF) {
  620. if (f->subclass == '#') {
  621. if (option_verbose > 2)
  622. ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
  623. res = '#';
  624. outmsg = 2;
  625. ast_frfree(f);
  626. break;
  627. }
  628. }
  629. if (f->subclass == '0') {
  630. /* Check for a '0' during message recording also, in case caller wants operator */
  631. if (option_verbose > 2)
  632. ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
  633. res = '0';
  634. outmsg = 0;
  635. ast_frfree(f);
  636. break;
  637. }
  638. if (maxtime) {
  639. time(&end);
  640. if (maxtime < (end - start)) {
  641. if (option_verbose > 2)
  642. ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
  643. outmsg = 2;
  644. res = 't';
  645. ast_frfree(f);
  646. break;
  647. }
  648. }
  649. ast_frfree(f);
  650. }
  651. if (end == start) time(&end);
  652. if (!f) {
  653. if (option_verbose > 2)
  654. ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
  655. res = -1;
  656. outmsg=1;
  657. }
  658. } else {
  659. ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
  660. }
  661. *duration = end - start;
  662. for (x=0;x<fmtcnt;x++) {
  663. if (!others[x])
  664. break;
  665. if (res > 0) {
  666. if (totalsilence)
  667. ast_stream_rewind(others[x], totalsilence-200);
  668. else
  669. ast_stream_rewind(others[x], 200);
  670. }
  671. ast_truncstream(others[x]);
  672. ast_closestream(others[x]);
  673. }
  674. if (rfmt) {
  675. if (ast_set_read_format(chan, rfmt)) {
  676. ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
  677. }
  678. }
  679. if (outmsg > 1) {
  680. /* Let them know recording is stopped */
  681. if(!ast_streamfile(chan, "auth-thankyou", chan->language))
  682. ast_waitstream(chan, "");
  683. }
  684. if (sildet)
  685. ast_dsp_free(sildet);
  686. return res;
  687. }
  688. 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)
  689. {
  690. int d = 0;
  691. char *fmts;
  692. char comment[256];
  693. int x, fmtcnt=1, res=-1,outmsg=0;
  694. struct ast_frame *f;
  695. struct ast_filestream *others[MAX_OTHER_FORMATS];
  696. struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
  697. char *sfmt[MAX_OTHER_FORMATS];
  698. char *stringp=NULL;
  699. time_t start, end;
  700. struct ast_dsp *sildet; /* silence detector dsp */
  701. int totalsilence = 0;
  702. int dspsilence = 0;
  703. int gotsilence = 0; /* did we timeout for silence? */
  704. int rfmt=0;
  705. char prependfile[80];
  706. if (silencethreshold < 0)
  707. silencethreshold = global_silence_threshold;
  708. if (maxsilence < 0)
  709. maxsilence = global_maxsilence;
  710. /* barf if no pointer passed to store duration in */
  711. if (duration == NULL) {
  712. ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
  713. return -1;
  714. }
  715. ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
  716. snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
  717. if (playfile || beep) {
  718. if (!beep)
  719. d = ast_play_and_wait(chan, playfile);
  720. if (d > -1)
  721. d = ast_streamfile(chan, "beep",chan->language);
  722. if (!d)
  723. d = ast_waitstream(chan,"");
  724. if (d < 0)
  725. return -1;
  726. }
  727. strncpy(prependfile, recordfile, sizeof(prependfile) -1);
  728. strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
  729. fmts = ast_strdupa(fmt);
  730. stringp=fmts;
  731. strsep(&stringp, "|");
  732. ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
  733. sfmt[0] = ast_strdupa(fmts);
  734. while((fmt = strsep(&stringp, "|"))) {
  735. if (fmtcnt > MAX_OTHER_FORMATS - 1) {
  736. ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
  737. break;
  738. }
  739. sfmt[fmtcnt++] = ast_strdupa(fmt);
  740. }
  741. time(&start);
  742. end=start; /* pre-initialize end to be same as start in case we never get into loop */
  743. for (x=0;x<fmtcnt;x++) {
  744. others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
  745. ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
  746. if (!others[x]) {
  747. break;
  748. }
  749. }
  750. sildet = ast_dsp_new(); /* Create the silence detector */
  751. if (!sildet) {
  752. ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
  753. return -1;
  754. }
  755. ast_dsp_set_threshold(sildet, silencethreshold);
  756. if (maxsilence > 0) {
  757. rfmt = chan->readformat;
  758. res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
  759. if (res < 0) {
  760. ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
  761. return -1;
  762. }
  763. }
  764. if (x == fmtcnt) {
  765. /* Loop forever, writing the packets we read to the writer(s), until
  766. we read a # or get a hangup */
  767. f = NULL;
  768. for(;;) {
  769. res = ast_waitfor(chan, 2000);
  770. if (!res) {
  771. ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
  772. /* Try one more time in case of masq */
  773. res = ast_waitfor(chan, 2000);
  774. if (!res) {
  775. ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
  776. res = -1;
  777. }
  778. }
  779. if (res < 0) {
  780. f = NULL;
  781. break;
  782. }
  783. f = ast_read(chan);
  784. if (!f)
  785. break;
  786. if (f->frametype == AST_FRAME_VOICE) {
  787. /* write each format */
  788. for (x=0;x<fmtcnt;x++) {
  789. if (!others[x])
  790. break;
  791. res = ast_writestream(others[x], f);
  792. }
  793. /* Silence Detection */
  794. if (maxsilence > 0) {
  795. dspsilence = 0;
  796. ast_dsp_silence(sildet, f, &dspsilence);
  797. if (dspsilence)
  798. totalsilence = dspsilence;
  799. else
  800. totalsilence = 0;
  801. if (totalsilence > maxsilence) {
  802. /* Ended happily with silence */
  803. if (option_verbose > 2)
  804. ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
  805. ast_frfree(f);
  806. gotsilence = 1;
  807. outmsg=2;
  808. break;
  809. }
  810. }
  811. /* Exit on any error */
  812. if (res) {
  813. ast_log(LOG_WARNING, "Error writing frame\n");
  814. ast_frfree(f);
  815. break;
  816. }
  817. } else if (f->frametype == AST_FRAME_VIDEO) {
  818. /* Write only once */
  819. ast_writestream(others[0], f);
  820. } else if (f->frametype == AST_FRAME_DTMF) {
  821. /* stop recording with any digit */
  822. if (option_verbose > 2)
  823. ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
  824. res = 't';
  825. outmsg = 2;
  826. ast_frfree(f);
  827. break;
  828. }
  829. if (maxtime) {
  830. time(&end);
  831. if (maxtime < (end - start)) {
  832. if (option_verbose > 2)
  833. ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
  834. res = 't';
  835. outmsg=2;
  836. ast_frfree(f);
  837. break;
  838. }
  839. }
  840. ast_frfree(f);
  841. }
  842. if (end == start) time(&end);
  843. if (!f) {
  844. if (option_verbose > 2)
  845. ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
  846. res = -1;
  847. outmsg=1;
  848. #if 0
  849. /* delete all the prepend files */
  850. for (x=0;x<fmtcnt;x++) {
  851. if (!others[x])
  852. break;
  853. ast_closestream(others[x]);
  854. ast_filedelete(prependfile, sfmt[x]);
  855. }
  856. #endif
  857. }
  858. } else {
  859. ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
  860. }
  861. *duration = end - start;
  862. #if 0
  863. if (outmsg > 1) {
  864. #else
  865. if (outmsg) {
  866. #endif
  867. struct ast_frame *fr;
  868. for (x=0;x<fmtcnt;x++) {
  869. snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
  870. realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
  871. if (!others[x] || !realfiles[x])
  872. break;
  873. if (totalsilence)
  874. ast_stream_rewind(others[x], totalsilence-200);
  875. else
  876. ast_stream_rewind(others[x], 200);
  877. ast_truncstream(others[x]);
  878. /* add the original file too */
  879. while ((fr = ast_readframe(realfiles[x]))) {
  880. ast_writestream(others[x],fr);
  881. }
  882. ast_closestream(others[x]);
  883. ast_closestream(realfiles[x]);
  884. ast_filerename(prependfile, recordfile, sfmt[x]);
  885. #if 0
  886. ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
  887. #endif
  888. ast_filedelete(prependfile, sfmt[x]);
  889. }
  890. }
  891. if (rfmt) {
  892. if (ast_set_read_format(chan, rfmt)) {
  893. ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
  894. }
  895. }
  896. if (outmsg) {
  897. if (outmsg > 1) {
  898. /* Let them know it worked */
  899. ast_streamfile(chan, "auth-thankyou", chan->language);
  900. ast_waitstream(chan, "");
  901. }
  902. }
  903. return res;
  904. }
  905. int ast_lock_path(const char *path)
  906. {
  907. char *s;
  908. char *fs;
  909. int res;
  910. int fd;
  911. time_t start;
  912. s = alloca(strlen(path) + 10);
  913. fs = alloca(strlen(path) + 20);
  914. if (!fs || !s) {
  915. ast_log(LOG_WARNING, "Out of memory!\n");
  916. return -1;
  917. }
  918. snprintf(fs, strlen(path) + 19, "%s/%s-%08x", path, ".lock", rand());
  919. fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
  920. if (fd < 0) {
  921. fprintf(stderr, "Unable to create lock file: %s\n", strerror(errno));
  922. return -1;
  923. }
  924. close(fd);
  925. snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
  926. time(&start);
  927. while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
  928. usleep(1);
  929. if (res < 0) {
  930. ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
  931. }
  932. unlink(fs);
  933. ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
  934. return res;
  935. }
  936. int ast_unlock_path(const char *path)
  937. {
  938. char *s;
  939. s = alloca(strlen(path) + 10);
  940. if (!s)
  941. return -1;
  942. snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
  943. ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
  944. return unlink(s);
  945. }