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