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