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