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
00026
00027
00028
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 371590 $")
00033
00034 #include <dirent.h>
00035 #include <sys/stat.h>
00036 #include <sys/wait.h>
00037 #include <math.h>
00038
00039 #include "asterisk/_private.h"
00040 #include "asterisk/paths.h"
00041 #include "asterisk/mod_format.h"
00042 #include "asterisk/cli.h"
00043 #include "asterisk/channel.h"
00044 #include "asterisk/sched.h"
00045 #include "asterisk/translate.h"
00046 #include "asterisk/utils.h"
00047 #include "asterisk/lock.h"
00048 #include "asterisk/app.h"
00049 #include "asterisk/pbx.h"
00050 #include "asterisk/linkedlists.h"
00051 #include "asterisk/module.h"
00052 #include "asterisk/astobj2.h"
00053 #include "asterisk/test.h"
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 int ast_language_is_prefix = 1;
00064
00065 static AST_RWLIST_HEAD_STATIC(formats, ast_format);
00066
00067 int __ast_format_register(const struct ast_format *f, struct ast_module *mod)
00068 {
00069 struct ast_format *tmp;
00070
00071 AST_RWLIST_WRLOCK(&formats);
00072 AST_RWLIST_TRAVERSE(&formats, tmp, list) {
00073 if (!strcasecmp(f->name, tmp->name)) {
00074 AST_RWLIST_UNLOCK(&formats);
00075 ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", f->name);
00076 return -1;
00077 }
00078 }
00079 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
00080 AST_RWLIST_UNLOCK(&formats);
00081 return -1;
00082 }
00083 *tmp = *f;
00084 tmp->module = mod;
00085 if (tmp->buf_size) {
00086
00087
00088
00089
00090 struct _test_align { void *a, *b; } p;
00091 int align = (char *)&p.b - (char *)&p.a;
00092 tmp->buf_size = ((f->buf_size + align - 1) / align) * align;
00093 }
00094
00095 memset(&tmp->list, 0, sizeof(tmp->list));
00096
00097 AST_RWLIST_INSERT_HEAD(&formats, tmp, list);
00098 AST_RWLIST_UNLOCK(&formats);
00099 ast_verb(2, "Registered file format %s, extension(s) %s\n", f->name, f->exts);
00100
00101 return 0;
00102 }
00103
00104 int ast_format_unregister(const char *name)
00105 {
00106 struct ast_format *tmp;
00107 int res = -1;
00108
00109 AST_RWLIST_WRLOCK(&formats);
00110 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&formats, tmp, list) {
00111 if (!strcasecmp(name, tmp->name)) {
00112 AST_RWLIST_REMOVE_CURRENT(list);
00113 ast_free(tmp);
00114 res = 0;
00115 }
00116 }
00117 AST_RWLIST_TRAVERSE_SAFE_END;
00118 AST_RWLIST_UNLOCK(&formats);
00119
00120 if (!res)
00121 ast_verb(2, "Unregistered format %s\n", name);
00122 else
00123 ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
00124
00125 return res;
00126 }
00127
00128 int ast_stopstream(struct ast_channel *tmp)
00129 {
00130 ast_channel_lock(tmp);
00131
00132
00133 if (tmp->stream) {
00134 ast_closestream(tmp->stream);
00135 tmp->stream = NULL;
00136 if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
00137 ast_log(LOG_WARNING, "Unable to restore format back to %s\n", ast_getformatname(tmp->oldwriteformat));
00138 }
00139
00140 if (tmp->vstream != NULL) {
00141 ast_closestream(tmp->vstream);
00142 tmp->vstream = NULL;
00143 }
00144
00145 ast_channel_unlock(tmp);
00146
00147 return 0;
00148 }
00149
00150 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
00151 {
00152 int res = -1;
00153 int alt = 0;
00154 if (f->frametype == AST_FRAME_VIDEO) {
00155 if (fs->fmt->format & AST_FORMAT_AUDIO_MASK) {
00156
00157 if (!fs->vfs && fs->filename) {
00158 const char *type = ast_getformatname(f->subclass.codec & ~0x1);
00159 fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
00160 ast_debug(1, "Opened video output file\n");
00161 }
00162 if (fs->vfs)
00163 return ast_writestream(fs->vfs, f);
00164
00165 return 0;
00166 } else {
00167
00168 alt = 1;
00169 }
00170 } else if (f->frametype != AST_FRAME_VOICE) {
00171 ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
00172 return -1;
00173 }
00174 if (((fs->fmt->format | alt) & f->subclass.codec) == f->subclass.codec) {
00175 res = fs->fmt->write(fs, f);
00176 if (res < 0)
00177 ast_log(LOG_WARNING, "Natural write failed\n");
00178 else if (res > 0)
00179 ast_log(LOG_WARNING, "Huh??\n");
00180 } else {
00181
00182
00183 if (fs->trans && f->subclass.codec != fs->lastwriteformat) {
00184 ast_translator_free_path(fs->trans);
00185 fs->trans = NULL;
00186 }
00187 if (!fs->trans)
00188 fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass.codec);
00189 if (!fs->trans)
00190 ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n",
00191 fs->fmt->name, ast_getformatname(f->subclass.codec));
00192 else {
00193 struct ast_frame *trf;
00194 fs->lastwriteformat = f->subclass.codec;
00195
00196 if ((trf = ast_translate(fs->trans, f, 0))) {
00197 struct ast_frame *cur;
00198
00199
00200 for (cur = trf; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00201 if ((res = fs->fmt->write(fs, trf))) {
00202 ast_log(LOG_WARNING, "Translated frame write failed\n");
00203 break;
00204 }
00205 }
00206 ast_frfree(trf);
00207 } else {
00208 res = 0;
00209 }
00210 }
00211 }
00212 return res;
00213 }
00214
00215 static int copy(const char *infile, const char *outfile)
00216 {
00217 int ifd, ofd, len;
00218 char buf[4096];
00219
00220 if ((ifd = open(infile, O_RDONLY)) < 0) {
00221 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
00222 return -1;
00223 }
00224 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, AST_FILE_MODE)) < 0) {
00225 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
00226 close(ifd);
00227 return -1;
00228 }
00229 while ( (len = read(ifd, buf, sizeof(buf)) ) ) {
00230 int res;
00231 if (len < 0) {
00232 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
00233 break;
00234 }
00235
00236 res = write(ofd, buf, len);
00237 if (res != len) {
00238 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
00239 len = -1;
00240 break;
00241 }
00242 }
00243 close(ifd);
00244 close(ofd);
00245 if (len < 0) {
00246 unlink(outfile);
00247 return -1;
00248 }
00249 return 0;
00250 }
00251
00252
00253
00254
00255
00256
00257
00258 static char *build_filename(const char *filename, const char *ext)
00259 {
00260 char *fn = NULL;
00261
00262 if (!strcmp(ext, "wav49"))
00263 ext = "WAV";
00264
00265 if (filename[0] == '/') {
00266 if (ast_asprintf(&fn, "%s.%s", filename, ext) < 0) {
00267 fn = NULL;
00268 }
00269 } else {
00270 if (ast_asprintf(&fn, "%s/sounds/%s.%s",
00271 ast_config_AST_DATA_DIR, filename, ext) < 0) {
00272 fn = NULL;
00273 }
00274 }
00275 return fn;
00276 }
00277
00278
00279
00280 static int exts_compare(const char *exts, const char *type)
00281 {
00282 char tmp[256];
00283 char *stringp = tmp, *ext;
00284
00285 ast_copy_string(tmp, exts, sizeof(tmp));
00286 while ((ext = strsep(&stringp, "|"))) {
00287 if (!strcmp(ext, type))
00288 return 1;
00289 }
00290
00291 return 0;
00292 }
00293
00294
00295 static void filestream_close(struct ast_filestream *f)
00296 {
00297
00298 if (f->owner) {
00299 if (f->fmt->format & AST_FORMAT_AUDIO_MASK) {
00300 f->owner->stream = NULL;
00301 AST_SCHED_DEL(f->owner->sched, f->owner->streamid);
00302 ast_settimeout(f->owner, 0, NULL, NULL);
00303 } else if (f->fmt->format & AST_FORMAT_VIDEO_MASK) {
00304 f->owner->vstream = NULL;
00305 AST_SCHED_DEL(f->owner->sched, f->owner->vstreamid);
00306 } else {
00307 ast_log(AST_LOG_WARNING, "Unable to schedule deletion of filestream with unsupported type %s\n", f->fmt->name);
00308 }
00309 }
00310 }
00311
00312 static void filestream_destructor(void *arg)
00313 {
00314 struct ast_filestream *f = arg;
00315 int status;
00316 int pid = -1;
00317
00318
00319 filestream_close(f);
00320
00321
00322 if (f->trans)
00323 ast_translator_free_path(f->trans);
00324
00325 if (f->realfilename && f->filename) {
00326 pid = ast_safe_fork(0);
00327 if (!pid) {
00328 execl("/bin/mv", "mv", "-f", f->filename, f->realfilename, SENTINEL);
00329 _exit(1);
00330 }
00331 else if (pid > 0) {
00332
00333 waitpid(pid, &status, 0);
00334 }
00335 }
00336
00337 if (f->filename)
00338 free(f->filename);
00339 if (f->realfilename)
00340 free(f->realfilename);
00341 if (f->fmt->close) {
00342 void (*closefn)(struct ast_filestream *) = f->fmt->close;
00343 closefn(f);
00344 }
00345 if (f->f)
00346 fclose(f->f);
00347 if (f->vfs)
00348 ast_closestream(f->vfs);
00349 if (f->write_buffer) {
00350 ast_free(f->write_buffer);
00351 }
00352 if (f->orig_chan_name)
00353 free((void *) f->orig_chan_name);
00354 ast_module_unref(f->fmt->module);
00355 }
00356
00357 static struct ast_filestream *get_filestream(struct ast_format *fmt, FILE *bfile)
00358 {
00359 struct ast_filestream *s;
00360
00361 int l = sizeof(*s) + fmt->buf_size + fmt->desc_size;
00362 if ( (s = ao2_alloc(l, filestream_destructor)) == NULL)
00363 return NULL;
00364 s->fmt = fmt;
00365 s->f = bfile;
00366
00367 if (fmt->desc_size)
00368 s->_private = ((char *)(s + 1)) + fmt->buf_size;
00369 if (fmt->buf_size)
00370 s->buf = (char *)(s + 1);
00371 s->fr.src = fmt->name;
00372 return s;
00373 }
00374
00375
00376
00377
00378
00379 enum wrap_fn { WRAP_OPEN, WRAP_REWRITE };
00380
00381 static int fn_wrapper(struct ast_filestream *s, const char *comment, enum wrap_fn mode)
00382 {
00383 struct ast_format *f = s->fmt;
00384 int ret = -1;
00385 int (*openfn)(struct ast_filestream *s);
00386
00387 if (mode == WRAP_OPEN && (openfn = f->open) && openfn(s))
00388 ast_log(LOG_WARNING, "Unable to open format %s\n", f->name);
00389 else if (mode == WRAP_REWRITE && f->rewrite && f->rewrite(s, comment))
00390 ast_log(LOG_WARNING, "Unable to rewrite format %s\n", f->name);
00391 else {
00392
00393 ast_module_ref(f->module);
00394 ret = 0;
00395 }
00396 return ret;
00397 }
00398
00399 static int rewrite_wrapper(struct ast_filestream *s, const char *comment)
00400 {
00401 return fn_wrapper(s, comment, WRAP_REWRITE);
00402 }
00403
00404 static int open_wrapper(struct ast_filestream *s)
00405 {
00406 return fn_wrapper(s, NULL, WRAP_OPEN);
00407 }
00408
00409 enum file_action {
00410 ACTION_EXISTS = 1,
00411 ACTION_DELETE,
00412 ACTION_RENAME,
00413 ACTION_OPEN,
00414 ACTION_COPY
00415 };
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 static format_t ast_filehelper(const char *filename, const void *arg2, const char *fmt, const enum file_action action)
00427 {
00428 struct ast_format *f;
00429 format_t res = (action == ACTION_EXISTS) ? 0 : -1;
00430
00431 AST_RWLIST_RDLOCK(&formats);
00432
00433 AST_RWLIST_TRAVERSE(&formats, f, list) {
00434 char *stringp, *ext = NULL;
00435
00436 if (fmt && !exts_compare(f->exts, fmt))
00437 continue;
00438
00439
00440
00441
00442
00443 stringp = ast_strdupa(f->exts);
00444 while ( (ext = strsep(&stringp, "|")) ) {
00445 struct stat st;
00446 char *fn = build_filename(filename, ext);
00447
00448 if (fn == NULL)
00449 continue;
00450
00451 if ( stat(fn, &st) ) {
00452 ast_free(fn);
00453 continue;
00454 }
00455
00456
00457
00458 if (action == ACTION_OPEN) {
00459 struct ast_channel *chan = (struct ast_channel *)arg2;
00460 FILE *bfile;
00461 struct ast_filestream *s;
00462
00463 if ( !(chan->writeformat & f->format) &&
00464 !((f->format & AST_FORMAT_AUDIO_MASK && fmt) ||
00465 (f->format & AST_FORMAT_VIDEO_MASK && fmt))) {
00466 ast_free(fn);
00467 continue;
00468 }
00469 if ( (bfile = fopen(fn, "r")) == NULL) {
00470 ast_free(fn);
00471 continue;
00472 }
00473 s = get_filestream(f, bfile);
00474 if (!s) {
00475 fclose(bfile);
00476 ast_free(fn);
00477 continue;
00478 }
00479 if (open_wrapper(s)) {
00480 ast_free(fn);
00481 ast_closestream(s);
00482 continue;
00483 }
00484 if (st.st_size == 0) {
00485 ast_log(LOG_WARNING, "File %s detected to have zero size.\n", fn);
00486 }
00487
00488 res = 1;
00489 s->lasttimeout = -1;
00490 s->fmt = f;
00491 s->trans = NULL;
00492 s->filename = NULL;
00493 if (s->fmt->format & AST_FORMAT_AUDIO_MASK) {
00494 if (chan->stream)
00495 ast_closestream(chan->stream);
00496 chan->stream = s;
00497 } else {
00498 if (chan->vstream)
00499 ast_closestream(chan->vstream);
00500 chan->vstream = s;
00501 }
00502 ast_free(fn);
00503 break;
00504 }
00505 switch (action) {
00506 case ACTION_OPEN:
00507 break;
00508
00509 case ACTION_EXISTS:
00510 res |= f->format;
00511 break;
00512
00513 case ACTION_DELETE:
00514 if ( (res = unlink(fn)) )
00515 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
00516 break;
00517
00518 case ACTION_RENAME:
00519 case ACTION_COPY: {
00520 char *nfn = build_filename((const char *)arg2, ext);
00521 if (!nfn)
00522 ast_log(LOG_WARNING, "Out of memory\n");
00523 else {
00524 res = action == ACTION_COPY ? copy(fn, nfn) : rename(fn, nfn);
00525 if (res)
00526 ast_log(LOG_WARNING, "%s(%s,%s) failed: %s\n",
00527 action == ACTION_COPY ? "copy" : "rename",
00528 fn, nfn, strerror(errno));
00529 ast_free(nfn);
00530 }
00531 }
00532 break;
00533
00534 default:
00535 ast_log(LOG_WARNING, "Unknown helper %d\n", action);
00536 }
00537 ast_free(fn);
00538 }
00539 }
00540 AST_RWLIST_UNLOCK(&formats);
00541 return res;
00542 }
00543
00544 static int is_absolute_path(const char *filename)
00545 {
00546 return filename[0] == '/';
00547 }
00548
00549 static format_t fileexists_test(const char *filename, const char *fmt, const char *lang,
00550 char *buf, int buflen)
00551 {
00552 if (buf == NULL) {
00553 return -1;
00554 }
00555
00556 if (ast_language_is_prefix && !is_absolute_path(filename)) {
00557 if (lang) {
00558 snprintf(buf, buflen, "%s/%s", lang, filename);
00559 } else {
00560 snprintf(buf, buflen, "%s", filename);
00561 }
00562 } else {
00563 strcpy(buf, filename);
00564 if (lang) {
00565
00566 const char *c = strrchr(filename, '/');
00567 int offset = c ? c - filename + 1 : 0;
00568 snprintf(buf + offset, buflen - offset, "%s/%s", lang, filename + offset);
00569 }
00570 }
00571
00572 return ast_filehelper(buf, NULL, fmt, ACTION_EXISTS);
00573 }
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583 static format_t fileexists_core(const char *filename, const char *fmt, const char *preflang,
00584 char *buf, int buflen)
00585 {
00586 format_t res = -1;
00587 char *lang;
00588
00589 if (buf == NULL) {
00590 return -1;
00591 }
00592
00593
00594
00595
00596
00597
00598
00599
00600 lang = ast_strdupa(preflang);
00601
00602
00603 while (!ast_strlen_zero(lang)) {
00604 char *end;
00605
00606 if ((res = fileexists_test(filename, fmt, lang, buf, buflen)) > 0) {
00607 return res;
00608 }
00609
00610 if ((end = strrchr(lang, '_')) != NULL) {
00611 *end = '\0';
00612 continue;
00613 }
00614
00615 break;
00616 }
00617
00618
00619 if ((res = fileexists_test(filename, fmt, NULL, buf, buflen)) > 0) {
00620 return res;
00621 }
00622
00623
00624 if ((ast_strlen_zero(preflang) || strcmp(preflang, DEFAULT_LANGUAGE)) && (ast_strlen_zero(lang) || strcmp(lang, DEFAULT_LANGUAGE))) {
00625 if ((res = fileexists_test(filename, fmt, DEFAULT_LANGUAGE, buf, buflen)) > 0) {
00626 return res;
00627 }
00628 }
00629
00630 return 0;
00631 }
00632
00633 struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
00634 {
00635 return ast_openstream_full(chan, filename, preflang, 0);
00636 }
00637
00638 struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis)
00639 {
00640
00641
00642
00643
00644
00645 format_t fmts, res;
00646 int buflen;
00647 char *buf;
00648
00649 if (!asis) {
00650
00651 ast_stopstream(chan);
00652 if (chan->generator)
00653 ast_deactivate_generator(chan);
00654 }
00655 if (preflang == NULL)
00656 preflang = "";
00657 buflen = strlen(preflang) + strlen(filename) + 4;
00658 buf = ast_alloca(buflen);
00659 fmts = fileexists_core(filename, NULL, preflang, buf, buflen);
00660 if (fmts > 0)
00661 fmts &= AST_FORMAT_AUDIO_MASK;
00662 if (fmts < 1) {
00663 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
00664 return NULL;
00665 }
00666 chan->oldwriteformat = chan->writeformat;
00667
00668 res = ast_set_write_format(chan, fmts);
00669 if (res == -1) {
00670 return NULL;
00671 }
00672 res = ast_filehelper(buf, chan, NULL, ACTION_OPEN);
00673 if (res >= 0)
00674 return chan->stream;
00675 return NULL;
00676 }
00677
00678 struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
00679 {
00680
00681
00682
00683 format_t format;
00684 char *buf;
00685 int buflen;
00686
00687 if (preflang == NULL)
00688 preflang = "";
00689 buflen = strlen(preflang) + strlen(filename) + 4;
00690 buf = ast_alloca(buflen);
00691
00692 for (format = AST_FORMAT_FIRST_VIDEO_BIT; format <= AST_FORMAT_VIDEO_MASK; format = format << 1) {
00693 int fd;
00694 const char *fmt;
00695
00696 if (!(chan->nativeformats & format))
00697 continue;
00698 fmt = ast_getformatname(format);
00699 if ( fileexists_core(filename, fmt, preflang, buf, buflen) < 1)
00700 continue;
00701 fd = ast_filehelper(buf, chan, fmt, ACTION_OPEN);
00702 if (fd >= 0)
00703 return chan->vstream;
00704 ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
00705 }
00706 return NULL;
00707 }
00708
00709 static struct ast_frame *read_frame(struct ast_filestream *s, int *whennext)
00710 {
00711 struct ast_frame *fr, *new_fr;
00712
00713 if (!s || !s->fmt) {
00714 return NULL;
00715 }
00716
00717 if (!(fr = s->fmt->read(s, whennext))) {
00718 return NULL;
00719 }
00720
00721 if (!(new_fr = ast_frisolate(fr))) {
00722 ast_frfree(fr);
00723 return NULL;
00724 }
00725
00726 if (new_fr != fr) {
00727 ast_frfree(fr);
00728 fr = new_fr;
00729 }
00730
00731 return fr;
00732 }
00733
00734 struct ast_frame *ast_readframe(struct ast_filestream *s)
00735 {
00736 int whennext = 0;
00737
00738 return read_frame(s, &whennext);
00739 }
00740
00741 enum fsread_res {
00742 FSREAD_FAILURE,
00743 FSREAD_SUCCESS_SCHED,
00744 FSREAD_SUCCESS_NOSCHED,
00745 };
00746
00747 static int ast_fsread_audio(const void *data);
00748
00749 static enum fsread_res ast_readaudio_callback(struct ast_filestream *s)
00750 {
00751 int whennext = 0;
00752
00753 while (!whennext) {
00754 struct ast_frame *fr;
00755
00756 if (s->orig_chan_name && strcasecmp(s->owner->name, s->orig_chan_name)) {
00757 goto return_failure;
00758 }
00759
00760 fr = read_frame(s, &whennext);
00761
00762 if (!fr || ast_write(s->owner, fr) ) {
00763 if (fr) {
00764 ast_log(LOG_WARNING, "Failed to write frame\n");
00765 ast_frfree(fr);
00766 }
00767 goto return_failure;
00768 }
00769
00770 if (fr) {
00771 ast_frfree(fr);
00772 }
00773 }
00774
00775 if (whennext != s->lasttimeout) {
00776 if (s->owner->timingfd > -1) {
00777 float samp_rate = (float) ast_format_rate(s->fmt->format);
00778 unsigned int rate;
00779
00780 rate = (unsigned int) roundf(samp_rate / ((float) whennext));
00781
00782 ast_settimeout(s->owner, rate, ast_fsread_audio, s);
00783 } else {
00784 s->owner->streamid = ast_sched_add(s->owner->sched,
00785 whennext / (ast_format_rate(s->fmt->format) / 1000), ast_fsread_audio, s);
00786 }
00787 s->lasttimeout = whennext;
00788 return FSREAD_SUCCESS_NOSCHED;
00789 }
00790 return FSREAD_SUCCESS_SCHED;
00791
00792 return_failure:
00793 s->owner->streamid = -1;
00794 ast_settimeout(s->owner, 0, NULL, NULL);
00795 return FSREAD_FAILURE;
00796 }
00797
00798 static int ast_fsread_audio(const void *data)
00799 {
00800 struct ast_filestream *fs = (struct ast_filestream *)data;
00801 enum fsread_res res;
00802
00803 res = ast_readaudio_callback(fs);
00804
00805 if (res == FSREAD_SUCCESS_SCHED)
00806 return 1;
00807
00808 return 0;
00809 }
00810
00811 static int ast_fsread_video(const void *data);
00812
00813 static enum fsread_res ast_readvideo_callback(struct ast_filestream *s)
00814 {
00815 int whennext = 0;
00816
00817 while (!whennext) {
00818 struct ast_frame *fr = read_frame(s, &whennext);
00819
00820 if (!fr || ast_write(s->owner, fr) ) {
00821 if (fr) {
00822 ast_log(LOG_WARNING, "Failed to write frame\n");
00823 ast_frfree(fr);
00824 }
00825 s->owner->vstreamid = -1;
00826 return FSREAD_FAILURE;
00827 }
00828
00829 if (fr) {
00830 ast_frfree(fr);
00831 }
00832 }
00833
00834 if (whennext != s->lasttimeout) {
00835 s->owner->vstreamid = ast_sched_add(s->owner->sched,
00836 whennext / (ast_format_rate(s->fmt->format) / 1000),
00837 ast_fsread_video, s);
00838 s->lasttimeout = whennext;
00839 return FSREAD_SUCCESS_NOSCHED;
00840 }
00841
00842 return FSREAD_SUCCESS_SCHED;
00843 }
00844
00845 static int ast_fsread_video(const void *data)
00846 {
00847 struct ast_filestream *fs = (struct ast_filestream *)data;
00848 enum fsread_res res;
00849
00850 res = ast_readvideo_callback(fs);
00851
00852 if (res == FSREAD_SUCCESS_SCHED)
00853 return 1;
00854
00855 return 0;
00856 }
00857
00858 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
00859 {
00860 s->owner = chan;
00861 return 0;
00862 }
00863
00864 int ast_playstream(struct ast_filestream *s)
00865 {
00866 enum fsread_res res;
00867
00868 if (s->fmt->format & AST_FORMAT_AUDIO_MASK)
00869 res = ast_readaudio_callback(s);
00870 else
00871 res = ast_readvideo_callback(s);
00872
00873 return (res == FSREAD_FAILURE) ? -1 : 0;
00874 }
00875
00876 int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
00877 {
00878 return fs->fmt->seek(fs, sample_offset, whence);
00879 }
00880
00881 int ast_truncstream(struct ast_filestream *fs)
00882 {
00883 return fs->fmt->trunc(fs);
00884 }
00885
00886 off_t ast_tellstream(struct ast_filestream *fs)
00887 {
00888 return fs->fmt->tell(fs);
00889 }
00890
00891 int ast_stream_fastforward(struct ast_filestream *fs, off_t ms)
00892 {
00893 return ast_seekstream(fs, ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
00894 }
00895
00896 int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
00897 {
00898 return ast_seekstream(fs, -ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
00899 }
00900
00901 int ast_closestream(struct ast_filestream *f)
00902 {
00903
00904
00905
00906
00907 filestream_close(f);
00908 ao2_ref(f, -1);
00909 return 0;
00910 }
00911
00912
00913
00914
00915
00916 int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
00917 {
00918 char *buf;
00919 int buflen;
00920
00921 if (preflang == NULL)
00922 preflang = "";
00923 buflen = strlen(preflang) + strlen(filename) + 4;
00924 buf = ast_alloca(buflen);
00925 return fileexists_core(filename, fmt, preflang, buf, buflen);
00926 }
00927
00928 int ast_filedelete(const char *filename, const char *fmt)
00929 {
00930 return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
00931 }
00932
00933 int ast_filerename(const char *filename, const char *filename2, const char *fmt)
00934 {
00935 return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
00936 }
00937
00938 int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
00939 {
00940 return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
00941 }
00942
00943 int ast_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
00944 {
00945 struct ast_filestream *fs;
00946 struct ast_filestream *vfs=NULL;
00947 char fmt[256];
00948 off_t pos;
00949 int seekattempt;
00950 int res;
00951
00952 fs = ast_openstream(chan, filename, preflang);
00953 if (!fs) {
00954 ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname_multiple(fmt, sizeof(fmt), chan->nativeformats), strerror(errno));
00955 return -1;
00956 }
00957
00958
00959
00960
00961 pos = ftello(fs->f);
00962 seekattempt = fseeko(fs->f, -1, SEEK_END);
00963 if (seekattempt) {
00964 if (errno == EINVAL) {
00965
00966 return 0;
00967 } else {
00968 ast_seekstream(fs, 0, SEEK_SET);
00969 }
00970 } else {
00971 fseeko(fs->f, pos, SEEK_SET);
00972 }
00973
00974 vfs = ast_openvstream(chan, filename, preflang);
00975 if (vfs) {
00976 ast_debug(1, "Ooh, found a video stream, too, format %s\n", ast_getformatname(vfs->fmt->format));
00977 }
00978
00979 if (ast_test_flag(chan, AST_FLAG_MASQ_NOSTREAM))
00980 fs->orig_chan_name = ast_strdup(chan->name);
00981 if (ast_applystream(chan, fs))
00982 return -1;
00983 if (vfs && ast_applystream(chan, vfs))
00984 return -1;
00985 res = ast_playstream(fs);
00986 if (!res && vfs)
00987 res = ast_playstream(vfs);
00988 ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", chan->name, filename, ast_getformatname(chan->writeformat), preflang ? preflang : "default");
00989
00990 return res;
00991 }
00992
00993 struct ast_filestream *ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
00994 {
00995 FILE *bfile;
00996 struct ast_format *f;
00997 struct ast_filestream *fs = NULL;
00998 char *fn;
00999 int format_found = 0;
01000
01001 AST_RWLIST_RDLOCK(&formats);
01002
01003 AST_RWLIST_TRAVERSE(&formats, f, list) {
01004 fs = NULL;
01005 if (!exts_compare(f->exts, type))
01006 continue;
01007 else
01008 format_found = 1;
01009
01010 fn = build_filename(filename, type);
01011 if (!fn) {
01012 continue;
01013 }
01014 errno = 0;
01015 bfile = fopen(fn, "r");
01016
01017 if (!bfile || (fs = get_filestream(f, bfile)) == NULL || open_wrapper(fs) ) {
01018 ast_log(LOG_WARNING, "Unable to open %s\n", fn);
01019 if (fs) {
01020 ast_closestream(fs);
01021 }
01022 fs = NULL;
01023 bfile = NULL;
01024 ast_free(fn);
01025 break;
01026 }
01027
01028 fs->trans = NULL;
01029 fs->fmt = f;
01030 fs->flags = flags;
01031 fs->mode = mode;
01032 fs->filename = ast_strdup(filename);
01033 fs->vfs = NULL;
01034 ast_free(fn);
01035 break;
01036 }
01037
01038 AST_RWLIST_UNLOCK(&formats);
01039 if (!format_found)
01040 ast_log(LOG_WARNING, "No such format '%s'\n", type);
01041
01042 return fs;
01043 }
01044
01045 struct ast_filestream *ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
01046 {
01047 int fd, myflags = 0;
01048
01049 FILE *bfile = NULL;
01050 struct ast_format *f;
01051 struct ast_filestream *fs = NULL;
01052 char *buf = NULL;
01053 size_t size = 0;
01054 int format_found = 0;
01055
01056 AST_RWLIST_RDLOCK(&formats);
01057
01058
01059
01060 if (flags & O_APPEND) {
01061 flags &= ~O_APPEND;
01062 } else {
01063 myflags = O_TRUNC;
01064 }
01065
01066 myflags |= O_WRONLY | O_CREAT;
01067
01068
01069
01070
01071 AST_RWLIST_TRAVERSE(&formats, f, list) {
01072 char *fn, *orig_fn = NULL;
01073 if (fs)
01074 break;
01075
01076 if (!exts_compare(f->exts, type))
01077 continue;
01078 else
01079 format_found = 1;
01080
01081 fn = build_filename(filename, type);
01082 if (!fn) {
01083 continue;
01084 }
01085 fd = open(fn, flags | myflags, mode);
01086 if (fd > -1) {
01087
01088 bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
01089 if (!bfile) {
01090 ast_log(LOG_WARNING, "Whoa, fdopen failed: %s!\n", strerror(errno));
01091 close(fd);
01092 fd = -1;
01093 }
01094 }
01095
01096 if (ast_opt_cache_record_files && (fd > -1)) {
01097 char *c;
01098
01099 fclose(bfile);
01100
01101
01102
01103
01104 orig_fn = ast_strdupa(fn);
01105 for (c = fn; *c; c++)
01106 if (*c == '/')
01107 *c = '_';
01108
01109 size = strlen(fn) + strlen(record_cache_dir) + 2;
01110 buf = ast_alloca(size);
01111 strcpy(buf, record_cache_dir);
01112 strcat(buf, "/");
01113 strcat(buf, fn);
01114 ast_free(fn);
01115 fn = buf;
01116 fd = open(fn, flags | myflags, mode);
01117 if (fd > -1) {
01118
01119 bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
01120 if (!bfile) {
01121 ast_log(LOG_WARNING, "Whoa, fdopen failed: %s!\n", strerror(errno));
01122 close(fd);
01123 fd = -1;
01124 }
01125 }
01126 }
01127 if (fd > -1) {
01128 errno = 0;
01129 fs = get_filestream(f, bfile);
01130 if (fs) {
01131 if ((fs->write_buffer = ast_malloc(32768))) {
01132 setvbuf(fs->f, fs->write_buffer, _IOFBF, 32768);
01133 }
01134 }
01135 if (!fs || rewrite_wrapper(fs, comment)) {
01136 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
01137 close(fd);
01138 if (orig_fn) {
01139 unlink(fn);
01140 unlink(orig_fn);
01141 }
01142 if (fs) {
01143 ast_closestream(fs);
01144 fs = NULL;
01145 }
01146 if (!buf) {
01147 ast_free(fn);
01148 }
01149 continue;
01150 }
01151 fs->trans = NULL;
01152 fs->fmt = f;
01153 fs->flags = flags;
01154 fs->mode = mode;
01155 if (orig_fn) {
01156 fs->realfilename = ast_strdup(orig_fn);
01157 fs->filename = ast_strdup(fn);
01158 } else {
01159 fs->realfilename = NULL;
01160 fs->filename = ast_strdup(filename);
01161 }
01162 fs->vfs = NULL;
01163
01164 f->seek(fs, 0, SEEK_END);
01165 } else if (errno != EEXIST) {
01166 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
01167 if (orig_fn)
01168 unlink(orig_fn);
01169 }
01170
01171 if (!buf)
01172 ast_free(fn);
01173 }
01174
01175 AST_RWLIST_UNLOCK(&formats);
01176
01177 if (!format_found)
01178 ast_log(LOG_WARNING, "No such format '%s'\n", type);
01179
01180 return fs;
01181 }
01182
01183
01184
01185
01186 static int waitstream_core(struct ast_channel *c, const char *breakon,
01187 const char *forward, const char *reverse, int skip_ms,
01188 int audiofd, int cmdfd, const char *context)
01189 {
01190 const char *orig_chan_name = NULL;
01191 int err = 0;
01192
01193 if (!breakon)
01194 breakon = "";
01195 if (!forward)
01196 forward = "";
01197 if (!reverse)
01198 reverse = "";
01199
01200
01201 ast_set_flag(c, AST_FLAG_END_DTMF_ONLY);
01202
01203 if (ast_test_flag(c, AST_FLAG_MASQ_NOSTREAM))
01204 orig_chan_name = ast_strdupa(c->name);
01205
01206 while (c->stream) {
01207 int res;
01208 int ms;
01209
01210 if (orig_chan_name && strcasecmp(orig_chan_name, c->name)) {
01211 ast_stopstream(c);
01212 err = 1;
01213 break;
01214 }
01215
01216 ms = ast_sched_wait(c->sched);
01217
01218 if (ms < 0 && !c->timingfunc) {
01219 ast_stopstream(c);
01220 break;
01221 }
01222 if (ms < 0)
01223 ms = 1000;
01224 if (cmdfd < 0) {
01225 res = ast_waitfor(c, ms);
01226 if (res < 0) {
01227 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
01228 ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01229 return res;
01230 }
01231 } else {
01232 int outfd;
01233 struct ast_channel *rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
01234 if (!rchan && (outfd < 0) && (ms)) {
01235
01236 if (errno == EINTR)
01237 continue;
01238 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
01239 ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01240 return -1;
01241 } else if (outfd > -1) {
01242
01243 ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01244 return 1;
01245 }
01246
01247 res = rchan ? 1 : 0;
01248 }
01249 if (res > 0) {
01250 struct ast_frame *fr = ast_read(c);
01251 if (!fr) {
01252 ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01253 return -1;
01254 }
01255 switch (fr->frametype) {
01256 case AST_FRAME_DTMF_END:
01257 if (context) {
01258 const char exten[2] = { fr->subclass.integer, '\0' };
01259 if (ast_exists_extension(c, context, exten, 1,
01260 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
01261 res = fr->subclass.integer;
01262 ast_frfree(fr);
01263 ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01264 return res;
01265 }
01266 } else {
01267 res = fr->subclass.integer;
01268 if (strchr(forward, res)) {
01269 int eoftest;
01270 ast_stream_fastforward(c->stream, skip_ms);
01271 eoftest = fgetc(c->stream->f);
01272 if (feof(c->stream->f)) {
01273 ast_stream_rewind(c->stream, skip_ms);
01274 } else {
01275 ungetc(eoftest, c->stream->f);
01276 }
01277 } else if (strchr(reverse, res)) {
01278 ast_stream_rewind(c->stream, skip_ms);
01279 } else if (strchr(breakon, res)) {
01280 ast_frfree(fr);
01281 ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01282 return res;
01283 }
01284 }
01285 break;
01286 case AST_FRAME_CONTROL:
01287 switch (fr->subclass.integer) {
01288 case AST_CONTROL_HANGUP:
01289 case AST_CONTROL_BUSY:
01290 case AST_CONTROL_CONGESTION:
01291 ast_frfree(fr);
01292 ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01293 return -1;
01294 case AST_CONTROL_RINGING:
01295 case AST_CONTROL_ANSWER:
01296 case AST_CONTROL_VIDUPDATE:
01297 case AST_CONTROL_SRCUPDATE:
01298 case AST_CONTROL_SRCCHANGE:
01299 case AST_CONTROL_HOLD:
01300 case AST_CONTROL_UNHOLD:
01301 case AST_CONTROL_CONNECTED_LINE:
01302 case AST_CONTROL_REDIRECTING:
01303 case AST_CONTROL_AOC:
01304 case AST_CONTROL_UPDATE_RTP_PEER:
01305 case -1:
01306
01307 break;
01308 default:
01309 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass.integer);
01310 }
01311 break;
01312 case AST_FRAME_VOICE:
01313
01314 if (audiofd > -1) {
01315 if (write(audiofd, fr->data.ptr, fr->datalen) < 0) {
01316 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
01317 }
01318 }
01319 default:
01320
01321 break;
01322 }
01323 ast_frfree(fr);
01324 }
01325 ast_sched_runq(c->sched);
01326 }
01327
01328 ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
01329
01330 return (err || c->_softhangup) ? -1 : 0;
01331 }
01332
01333 int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *reverse, int ms)
01334 {
01335 return waitstream_core(c, breakon, forward, reverse, ms,
01336 -1 , -1 , NULL );
01337 }
01338
01339 int ast_waitstream(struct ast_channel *c, const char *breakon)
01340 {
01341 return waitstream_core(c, breakon, NULL, NULL, 0, -1, -1, NULL);
01342 }
01343
01344 int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
01345 {
01346 return waitstream_core(c, breakon, NULL, NULL, 0,
01347 audiofd, cmdfd, NULL );
01348 }
01349
01350 int ast_waitstream_exten(struct ast_channel *c, const char *context)
01351 {
01352
01353
01354
01355 if (!context)
01356 context = c->context;
01357 return waitstream_core(c, NULL, NULL, NULL, 0,
01358 -1, -1, context);
01359 }
01360
01361
01362
01363
01364
01365
01366 int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
01367 {
01368 int res = 0;
01369 if (!ast_strlen_zero(file)) {
01370 ast_test_suite_event_notify("PLAYBACK", "Message: %s", file);
01371 res = ast_streamfile(chan, file, chan->language);
01372 if (!res) {
01373 res = ast_waitstream(chan, digits);
01374 }
01375 }
01376 return res;
01377 }
01378
01379 char *ast_format_str_reduce(char *fmts)
01380 {
01381 struct ast_format *f;
01382 struct ast_format *fmts_ptr[AST_MAX_FORMATS];
01383 char *fmts_str[AST_MAX_FORMATS];
01384 char *stringp, *type;
01385 char *orig = fmts;
01386 int i, j, x, first, found = 0;
01387 int len = strlen(fmts) + 1;
01388 int res;
01389
01390 if (AST_RWLIST_RDLOCK(&formats)) {
01391 ast_log(LOG_WARNING, "Unable to lock format list\n");
01392 return NULL;
01393 }
01394
01395 stringp = ast_strdupa(fmts);
01396
01397 for (x = 0; (type = strsep(&stringp, "|")) && x < AST_MAX_FORMATS; x++) {
01398 AST_RWLIST_TRAVERSE(&formats, f, list) {
01399 if (exts_compare(f->exts, type)) {
01400 found = 1;
01401 break;
01402 }
01403 }
01404
01405 fmts_str[x] = type;
01406 if (found) {
01407 fmts_ptr[x] = f;
01408 } else {
01409 fmts_ptr[x] = NULL;
01410 }
01411 }
01412 AST_RWLIST_UNLOCK(&formats);
01413
01414 first = 1;
01415 for (i = 0; i < x; i++) {
01416
01417 if (!fmts_ptr[i]) {
01418 ast_log(LOG_WARNING, "ignoring unknown format '%s'\n", fmts_str[i]);
01419 continue;
01420 }
01421
01422
01423 if (first) {
01424 res = snprintf(fmts, len, "%s", fmts_str[i]);
01425 fmts += res;
01426 len -= res;
01427 first = 0;
01428 continue;
01429 }
01430
01431 found = 0;
01432 for (j = 0; j < i; j++) {
01433
01434 if (fmts_ptr[j] == fmts_ptr[i]) {
01435 found = 1;
01436 break;
01437 }
01438 }
01439
01440 if (!found) {
01441 res = snprintf(fmts, len, "|%s", fmts_str[i]);
01442 fmts += res;
01443 len -= res;
01444 }
01445 }
01446
01447 if (first) {
01448 ast_log(LOG_WARNING, "no known formats found in format list (%s)\n", orig);
01449 return NULL;
01450 }
01451
01452 return orig;
01453 }
01454
01455 static char *handle_cli_core_show_file_formats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01456 {
01457 #define FORMAT "%-10s %-10s %-20s\n"
01458 #define FORMAT2 "%-10s %-10s %-20s\n"
01459 struct ast_format *f;
01460 int count_fmt = 0;
01461
01462 switch (cmd) {
01463 case CLI_INIT:
01464 e->command = "core show file formats";
01465 e->usage =
01466 "Usage: core show file formats\n"
01467 " Displays currently registered file formats (if any).\n";
01468 return NULL;
01469 case CLI_GENERATE:
01470 return NULL;
01471 }
01472
01473 if (a->argc != 4)
01474 return CLI_SHOWUSAGE;
01475
01476 ast_cli(a->fd, FORMAT, "Format", "Name", "Extensions");
01477 ast_cli(a->fd, FORMAT, "------", "----", "----------");
01478
01479 AST_RWLIST_RDLOCK(&formats);
01480 AST_RWLIST_TRAVERSE(&formats, f, list) {
01481 ast_cli(a->fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
01482 count_fmt++;
01483 }
01484 AST_RWLIST_UNLOCK(&formats);
01485 ast_cli(a->fd, "%d file formats registered.\n", count_fmt);
01486 return CLI_SUCCESS;
01487 #undef FORMAT
01488 #undef FORMAT2
01489 }
01490
01491 static struct ast_cli_entry cli_file[] = {
01492 AST_CLI_DEFINE(handle_cli_core_show_file_formats, "Displays file formats")
01493 };
01494
01495 int ast_file_init(void)
01496 {
01497 ast_cli_register_multiple(cli_file, ARRAY_LEN(cli_file));
01498 return 0;
01499 }