00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <sys/types.h>
00015 #include <asterisk/frame.h>
00016 #include <asterisk/file.h>
00017 #include <asterisk/cli.h>
00018 #include <asterisk/logger.h>
00019 #include <asterisk/channel.h>
00020 #include <asterisk/sched.h>
00021 #include <asterisk/options.h>
00022 #include <asterisk/translate.h>
00023 #include <asterisk/utils.h>
00024 #include <asterisk/lock.h>
00025 #include <asterisk/app.h>
00026 #include <errno.h>
00027 #include <unistd.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <stdio.h>
00031 #include <fcntl.h>
00032 #include <dirent.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include "asterisk.h"
00036 #include "astconf.h"
00037
00038 struct ast_format {
00039
00040 char name[80];
00041
00042
00043 char exts[80];
00044
00045 int format;
00046
00047 struct ast_filestream * (*open)(int fd);
00048
00049 struct ast_filestream * (*rewrite)(int fd, char *comment);
00050
00051 int (*write)(struct ast_filestream *, struct ast_frame *);
00052
00053 int (*seek)(struct ast_filestream *, long offset, int whence);
00054
00055 int (*trunc)(struct ast_filestream *fs);
00056
00057 long (*tell)(struct ast_filestream *fs);
00058
00059
00060 struct ast_frame * (*read)(struct ast_filestream *, int *whennext);
00061
00062 void (*close)(struct ast_filestream *);
00063
00064 char * (*getcomment)(struct ast_filestream *);
00065
00066 struct ast_format *next;
00067 };
00068
00069 struct ast_filestream {
00070
00071 struct ast_format *fmt;
00072 int flags;
00073 mode_t mode;
00074 char *filename;
00075 char *realfilename;
00076
00077 struct ast_filestream *vfs;
00078
00079 struct ast_trans_pvt *trans;
00080 struct ast_tranlator_pvt *tr;
00081 int lastwriteformat;
00082 int lasttimeout;
00083 struct ast_channel *owner;
00084 };
00085
00086 AST_MUTEX_DEFINE_STATIC(formatlock);
00087
00088 static struct ast_format *formats = NULL;
00089
00090 int ast_format_register(char *name, char *exts, int format,
00091 struct ast_filestream * (*open)(int fd),
00092 struct ast_filestream * (*rewrite)(int fd, char *comment),
00093 int (*write)(struct ast_filestream *, struct ast_frame *),
00094 int (*seek)(struct ast_filestream *, long sample_offset, int whence),
00095 int (*trunc)(struct ast_filestream *),
00096 long (*tell)(struct ast_filestream *),
00097 struct ast_frame * (*read)(struct ast_filestream *, int *whennext),
00098 void (*close)(struct ast_filestream *),
00099 char * (*getcomment)(struct ast_filestream *))
00100 {
00101 struct ast_format *tmp;
00102 if (ast_mutex_lock(&formatlock)) {
00103 ast_log(LOG_WARNING, "Unable to lock format list\n");
00104 return -1;
00105 }
00106 tmp = formats;
00107 while(tmp) {
00108 if (!strcasecmp(name, tmp->name)) {
00109 ast_mutex_unlock(&formatlock);
00110 ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", name);
00111 return -1;
00112 }
00113 tmp = tmp->next;
00114 }
00115 tmp = malloc(sizeof(struct ast_format));
00116 if (!tmp) {
00117 ast_log(LOG_WARNING, "Out of memory\n");
00118 ast_mutex_unlock(&formatlock);
00119 return -1;
00120 }
00121 strncpy(tmp->name, name, sizeof(tmp->name)-1);
00122 strncpy(tmp->exts, exts, sizeof(tmp->exts)-1);
00123 tmp->open = open;
00124 tmp->rewrite = rewrite;
00125 tmp->read = read;
00126 tmp->write = write;
00127 tmp->seek = seek;
00128 tmp->trunc = trunc;
00129 tmp->tell = tell;
00130 tmp->close = close;
00131 tmp->format = format;
00132 tmp->getcomment = getcomment;
00133 tmp->next = formats;
00134 formats = tmp;
00135 ast_mutex_unlock(&formatlock);
00136 if (option_verbose > 1)
00137 ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", name, exts);
00138 return 0;
00139 }
00140
00141 int ast_format_unregister(char *name)
00142 {
00143 struct ast_format *tmp, *tmpl = NULL;
00144 if (ast_mutex_lock(&formatlock)) {
00145 ast_log(LOG_WARNING, "Unable to lock format list\n");
00146 return -1;
00147 }
00148 tmp = formats;
00149 while(tmp) {
00150 if (!strcasecmp(name, tmp->name)) {
00151 if (tmpl)
00152 tmpl->next = tmp->next;
00153 else
00154 formats = tmp->next;
00155 free(tmp);
00156 ast_mutex_unlock(&formatlock);
00157 if (option_verbose > 1)
00158 ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
00159 return 0;
00160 }
00161 tmpl = tmp;
00162 tmp = tmp->next;
00163 }
00164 ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
00165 return -1;
00166 }
00167
00168 int ast_stopstream(struct ast_channel *tmp)
00169 {
00170
00171 if (tmp->vstream)
00172 ast_closestream(tmp->vstream);
00173 if (tmp->stream) {
00174 ast_closestream(tmp->stream);
00175 if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
00176 ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat);
00177 }
00178 return 0;
00179 }
00180
00181 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
00182 {
00183 struct ast_frame *trf;
00184 int res = -1;
00185 int alt=0;
00186 if (f->frametype == AST_FRAME_VIDEO) {
00187 if (fs->fmt->format < AST_FORMAT_MAX_AUDIO) {
00188
00189 if (!fs->vfs && fs->filename) {
00190
00191 char *type = "h263";
00192 fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
00193 ast_log(LOG_DEBUG, "Opened video output file\n");
00194 }
00195 if (fs->vfs)
00196 return ast_writestream(fs->vfs, f);
00197
00198 return 0;
00199 } else {
00200
00201 alt = 1;
00202 }
00203 } else if (f->frametype != AST_FRAME_VOICE) {
00204 ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
00205 return -1;
00206 }
00207 if (((fs->fmt->format | alt) & f->subclass) == f->subclass) {
00208 res = fs->fmt->write(fs, f);
00209 if (res < 0)
00210 ast_log(LOG_WARNING, "Natural write failed\n");
00211 if (res > 0)
00212 ast_log(LOG_WARNING, "Huh??\n");
00213 return res;
00214 } else {
00215
00216
00217 if (fs->trans && (f->subclass != fs->lastwriteformat)) {
00218 ast_translator_free_path(fs->trans);
00219 fs->trans = NULL;
00220 }
00221 if (!fs->trans)
00222 fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass);
00223 if (!fs->trans)
00224 ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n", fs->fmt->name, ast_getformatname(f->subclass));
00225 else {
00226 fs->lastwriteformat = f->subclass;
00227 res = 0;
00228
00229 trf = ast_translate(fs->trans, f, 0);
00230 if (trf) {
00231 res = fs->fmt->write(fs, trf);
00232 if (res)
00233 ast_log(LOG_WARNING, "Translated frame write failed\n");
00234 } else
00235 res = 0;
00236 }
00237 return res;
00238 }
00239 }
00240
00241 static int copy(char *infile, char *outfile)
00242 {
00243 int ifd;
00244 int ofd;
00245 int res;
00246 int len;
00247 char buf[4096];
00248
00249 if ((ifd = open(infile, O_RDONLY)) < 0) {
00250 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
00251 return -1;
00252 }
00253 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
00254 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
00255 close(ifd);
00256 return -1;
00257 }
00258 do {
00259 len = read(ifd, buf, sizeof(buf));
00260 if (len < 0) {
00261 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
00262 close(ifd);
00263 close(ofd);
00264 unlink(outfile);
00265 }
00266 if (len) {
00267 res = write(ofd, buf, len);
00268 if (res != len) {
00269 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
00270 close(ifd);
00271 close(ofd);
00272 unlink(outfile);
00273 }
00274 }
00275 } while(len);
00276 close(ifd);
00277 close(ofd);
00278 return 0;
00279 }
00280
00281 static char *build_filename(char *filename, char *ext)
00282 {
00283 char *fn;
00284 int fnsize = 0;
00285 char tmp[AST_CONFIG_MAX_PATH]="";
00286
00287 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_DATA_DIR, "sounds");
00288 fnsize = strlen(tmp) + strlen(filename) + strlen(ext) + 10;
00289 fn = malloc(fnsize);
00290 if (fn) {
00291 if (filename[0] == '/')
00292 snprintf(fn, fnsize, "%s.%s", filename, ext);
00293 else
00294 snprintf(fn, fnsize, "%s/%s.%s", tmp, filename, ext);
00295 }
00296 return fn;
00297
00298 }
00299
00300 static int exts_compare(char *exts, char *type)
00301 {
00302 char *stringp = NULL, *ext;
00303 char tmp[256];
00304
00305 strncpy(tmp, exts, sizeof(tmp) - 1);
00306 stringp = tmp;
00307 while ((ext = strsep(&stringp, "|"))) {
00308 if (!strcmp(ext, type)) {
00309 return 1;
00310 }
00311 }
00312
00313 return 0;
00314 }
00315
00316 #define ACTION_EXISTS 1
00317 #define ACTION_DELETE 2
00318 #define ACTION_RENAME 3
00319 #define ACTION_OPEN 4
00320 #define ACTION_COPY 5
00321
00322 static int ast_filehelper(char *filename, char *filename2, char *fmt, int action)
00323 {
00324 struct stat st;
00325 struct ast_format *f;
00326 struct ast_filestream *s;
00327 int res=0, ret = 0;
00328 char *ext=NULL, *exts, *fn, *nfn;
00329 struct ast_channel *chan = (struct ast_channel *)filename2;
00330
00331
00332 if (action == ACTION_EXISTS)
00333 res = 0;
00334 else
00335 res = -1;
00336 if (action == ACTION_OPEN)
00337 ret = -1;
00338
00339 if (ast_mutex_lock(&formatlock)) {
00340 ast_log(LOG_WARNING, "Unable to lock format list\n");
00341 if (action == ACTION_EXISTS)
00342 return 0;
00343 else
00344 return -1;
00345 }
00346 f = formats;
00347 while(f) {
00348 if (!fmt || exts_compare(f->exts, fmt)) {
00349 char *stringp=NULL;
00350 exts = strdup(f->exts);
00351
00352 stringp=exts;
00353 ext = strsep(&stringp, "|");
00354 if (!strcmp(ext,"wav49")) {
00355 ext = "WAV";
00356 }
00357 do {
00358 fn = build_filename(filename, ext);
00359 if (fn) {
00360 res = stat(fn, &st);
00361 if (!res) {
00362 switch(action) {
00363 case ACTION_EXISTS:
00364 ret |= f->format;
00365 break;
00366 case ACTION_DELETE:
00367 res = unlink(fn);
00368 if (res)
00369 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
00370 break;
00371 case ACTION_RENAME:
00372 nfn = build_filename(filename2, ext);
00373 if (nfn) {
00374 res = rename(fn, nfn);
00375 if (res)
00376 ast_log(LOG_WARNING, "rename(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
00377 free(nfn);
00378 } else
00379 ast_log(LOG_WARNING, "Out of memory\n");
00380 break;
00381 case ACTION_COPY:
00382 nfn = build_filename(filename2, ext);
00383 if (nfn) {
00384 res = copy(fn, nfn);
00385 if (res)
00386 ast_log(LOG_WARNING, "copy(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
00387 free(nfn);
00388 } else
00389 ast_log(LOG_WARNING, "Out of memory\n");
00390 break;
00391 case ACTION_OPEN:
00392 if ((ret < 0) && ((chan->writeformat & f->format) ||
00393 ((f->format >= AST_FORMAT_MAX_AUDIO) && fmt))) {
00394 ret = open(fn, O_RDONLY);
00395 if (ret >= 0) {
00396 s = f->open(ret);
00397 if (s) {
00398 s->lasttimeout = -1;
00399 s->fmt = f;
00400 s->trans = NULL;
00401 s->filename = NULL;
00402 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
00403 chan->stream = s;
00404 else
00405 chan->vstream = s;
00406 } else {
00407 close(ret);
00408 ast_log(LOG_WARNING, "Unable to open fd on %s\n", fn);
00409 }
00410 } else
00411 ast_log(LOG_WARNING, "Couldn't open file %s\n", fn);
00412 }
00413 break;
00414 default:
00415 ast_log(LOG_WARNING, "Unknown helper %d\n", action);
00416 }
00417
00418 if (res)
00419 break;
00420 }
00421 free(fn);
00422 }
00423 ext = strsep(&stringp, "|");
00424 } while(ext);
00425 free(exts);
00426 }
00427 f = f->next;
00428 }
00429 ast_mutex_unlock(&formatlock);
00430 if ((action == ACTION_EXISTS) || (action == ACTION_OPEN))
00431 res = ret ? ret : -1;
00432 return res;
00433 }
00434
00435 struct ast_filestream *ast_openstream(struct ast_channel *chan, char *filename, char *preflang)
00436 {
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449 int fd = -1;
00450 int fmts = -1;
00451 char filename2[256]="";
00452 char filename3[256]="";
00453 char *endpart;
00454 int res;
00455 ast_stopstream(chan);
00456
00457 if (chan->generator)
00458 ast_deactivate_generator(chan);
00459 if (preflang && !ast_strlen_zero(preflang)) {
00460 strncpy(filename3, filename, sizeof(filename3) - 1);
00461 endpart = strrchr(filename3, '/');
00462 if (endpart) {
00463 *endpart = '\0';
00464 endpart++;
00465 snprintf(filename2, sizeof(filename2), "%s/%s/%s", filename3, preflang, endpart);
00466 } else
00467 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
00468 fmts = ast_fileexists(filename2, NULL, NULL);
00469 }
00470 if (fmts < 1) {
00471 strncpy(filename2, filename, sizeof(filename2)-1);
00472 fmts = ast_fileexists(filename2, NULL, NULL);
00473 }
00474 if (fmts < 1) {
00475 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
00476 return NULL;
00477 }
00478 chan->oldwriteformat = chan->writeformat;
00479
00480 res = ast_set_write_format(chan, fmts);
00481
00482 fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
00483 if (fd >= 0)
00484 return chan->stream;
00485 return NULL;
00486 }
00487
00488 struct ast_filestream *ast_openvstream(struct ast_channel *chan, char *filename, char *preflang)
00489 {
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502 int fd = -1;
00503 int fmts = -1;
00504 char filename2[256];
00505 char lang2[MAX_LANGUAGE];
00506
00507 char *fmt = "h263";
00508 if (preflang && !ast_strlen_zero(preflang)) {
00509 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
00510 fmts = ast_fileexists(filename2, fmt, NULL);
00511 if (fmts < 1) {
00512 strncpy(lang2, preflang, sizeof(lang2)-1);
00513 snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
00514 fmts = ast_fileexists(filename2, fmt, NULL);
00515 }
00516 }
00517 if (fmts < 1) {
00518 strncpy(filename2, filename, sizeof(filename2)-1);
00519 fmts = ast_fileexists(filename2, fmt, NULL);
00520 }
00521 if (fmts < 1) {
00522 return NULL;
00523 }
00524 fd = ast_filehelper(filename2, (char *)chan, fmt, ACTION_OPEN);
00525 if (fd >= 0)
00526 return chan->vstream;
00527 ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
00528 return NULL;
00529 }
00530
00531 struct ast_frame *ast_readframe(struct ast_filestream *s)
00532 {
00533 struct ast_frame *f = NULL;
00534 int whennext = 0;
00535 if (s && s->fmt)
00536 f = s->fmt->read(s, &whennext);
00537 return f;
00538 }
00539
00540 static int ast_readaudio_callback(void *data)
00541 {
00542 struct ast_filestream *s = data;
00543 struct ast_frame *fr;
00544 int whennext = 0;
00545
00546 while(!whennext) {
00547 fr = s->fmt->read(s, &whennext);
00548 if (fr) {
00549 if (ast_write(s->owner, fr)) {
00550 ast_log(LOG_WARNING, "Failed to write frame\n");
00551 s->owner->streamid = -1;
00552 #ifdef ZAPTEL_OPTIMIZATIONS
00553 ast_settimeout(s->owner, 0, NULL, NULL);
00554 #endif
00555 return 0;
00556 }
00557 } else {
00558
00559 s->owner->streamid = -1;
00560 #ifdef ZAPTEL_OPTIMIZATIONS
00561 ast_settimeout(s->owner, 0, NULL, NULL);
00562 #endif
00563 return 0;
00564 }
00565 }
00566 if (whennext != s->lasttimeout) {
00567 #ifdef ZAPTEL_OPTIMIZATIONS
00568 if (s->owner->timingfd > -1)
00569 ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
00570 else
00571 #endif
00572 s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
00573 s->lasttimeout = whennext;
00574 return 0;
00575 }
00576 return 1;
00577 }
00578
00579 static int ast_readvideo_callback(void *data)
00580 {
00581 struct ast_filestream *s = data;
00582 struct ast_frame *fr;
00583 int whennext = 0;
00584
00585 while(!whennext) {
00586 fr = s->fmt->read(s, &whennext);
00587 if (fr) {
00588 if (ast_write(s->owner, fr)) {
00589 ast_log(LOG_WARNING, "Failed to write frame\n");
00590 s->owner->vstreamid = -1;
00591 return 0;
00592 }
00593 } else {
00594
00595 s->owner->vstreamid = -1;
00596 return 0;
00597 }
00598 }
00599 if (whennext != s->lasttimeout) {
00600 s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
00601 s->lasttimeout = whennext;
00602 return 0;
00603 }
00604 return 1;
00605 }
00606
00607 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
00608 {
00609 s->owner = chan;
00610 return 0;
00611 }
00612
00613 int ast_playstream(struct ast_filestream *s)
00614 {
00615 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
00616 ast_readaudio_callback(s);
00617 else
00618 ast_readvideo_callback(s);
00619 return 0;
00620 }
00621
00622 int ast_seekstream(struct ast_filestream *fs, long sample_offset, int whence)
00623 {
00624 return fs->fmt->seek(fs, sample_offset, whence);
00625 }
00626
00627 int ast_truncstream(struct ast_filestream *fs)
00628 {
00629 return fs->fmt->trunc(fs);
00630 }
00631
00632 long ast_tellstream(struct ast_filestream *fs)
00633 {
00634 return fs->fmt->tell(fs);
00635 }
00636
00637 int ast_stream_fastforward(struct ast_filestream *fs, long ms)
00638 {
00639
00640
00641 long samples = ms * 8;
00642 return ast_seekstream(fs, samples, SEEK_CUR);
00643 }
00644
00645 int ast_stream_rewind(struct ast_filestream *fs, long ms)
00646 {
00647 long samples = ms * 8;
00648 samples = samples * -1;
00649 return ast_seekstream(fs, samples, SEEK_CUR);
00650 }
00651
00652 int ast_closestream(struct ast_filestream *f)
00653 {
00654 char *cmd = NULL;
00655 size_t size = 0;
00656
00657 if (f->owner) {
00658 if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
00659 f->owner->stream = NULL;
00660 if (f->owner->streamid > -1)
00661 ast_sched_del(f->owner->sched, f->owner->streamid);
00662 f->owner->streamid = -1;
00663 #ifdef ZAPTEL_OPTIMIZATIONS
00664 ast_settimeout(f->owner, 0, NULL, NULL);
00665 #endif
00666 } else {
00667 f->owner->vstream = NULL;
00668 if (f->owner->vstreamid > -1)
00669 ast_sched_del(f->owner->sched, f->owner->vstreamid);
00670 f->owner->vstreamid = -1;
00671 }
00672 }
00673
00674 if (f->trans) {
00675 ast_translator_free_path(f->trans);
00676 f->trans = NULL;
00677 }
00678
00679 if (f->realfilename && f->filename) {
00680 size = strlen(f->filename) + strlen(f->realfilename) + 15;
00681 cmd = alloca(size);
00682 memset(cmd,0,size);
00683 snprintf(cmd,size,"/bin/mv -f %s %s",f->filename,f->realfilename);
00684 ast_safe_system(cmd);
00685 }
00686
00687 if (f->filename) {
00688 free(f->filename);
00689 f->filename = NULL;
00690 }
00691 if (f->realfilename) {
00692 free(f->realfilename);
00693 f->realfilename = NULL;
00694 }
00695 f->fmt->close(f);
00696 return 0;
00697 }
00698
00699
00700 int ast_fileexists(char *filename, char *fmt, char *preflang)
00701 {
00702 char filename2[256];
00703 char tmp[256];
00704 char *postfix;
00705 char *prefix;
00706 char *c;
00707 char lang2[MAX_LANGUAGE];
00708 int res = -1;
00709 if (preflang && !ast_strlen_zero(preflang)) {
00710
00711 strncpy(tmp, filename, sizeof(tmp) - 1);
00712 c = strrchr(tmp, '/');
00713 if (c) {
00714 *c = '\0';
00715 postfix = c+1;
00716 prefix = tmp;
00717 } else {
00718 postfix = tmp;
00719 prefix="";
00720 }
00721 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
00722 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
00723 if (res < 1) {
00724 char *stringp=NULL;
00725 strncpy(lang2, preflang, sizeof(lang2)-1);
00726 stringp=lang2;
00727 strsep(&stringp, "_");
00728 if (strcmp(lang2, preflang)) {
00729 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
00730 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
00731 }
00732 }
00733 }
00734 if (res < 1) {
00735 res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
00736 }
00737 return res;
00738 }
00739
00740 int ast_filedelete(char *filename, char *fmt)
00741 {
00742 return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
00743 }
00744
00745 int ast_filerename(char *filename, char *filename2, char *fmt)
00746 {
00747 return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
00748 }
00749
00750 int ast_filecopy(char *filename, char *filename2, char *fmt)
00751 {
00752 return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
00753 }
00754
00755 int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang)
00756 {
00757 struct ast_filestream *fs;
00758 struct ast_filestream *vfs;
00759
00760 fs = ast_openstream(chan, filename, preflang);
00761 vfs = ast_openvstream(chan, filename, preflang);
00762 if (vfs)
00763 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
00764 if (fs){
00765 if (ast_applystream(chan, fs))
00766 return -1;
00767 if (vfs && ast_applystream(chan, vfs))
00768 return -1;
00769 if (ast_playstream(fs))
00770 return -1;
00771 if (vfs && ast_playstream(vfs))
00772 return -1;
00773 #if 1
00774 if (option_verbose > 2)
00775 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (language '%s')\n", filename, preflang ? preflang : "default");
00776 #endif
00777 return 0;
00778 }
00779 ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname(chan->nativeformats), strerror(errno));
00780 return -1;
00781 }
00782
00783 struct ast_filestream *ast_readfile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
00784 {
00785 int fd,myflags = 0;
00786 struct ast_format *f;
00787 struct ast_filestream *fs=NULL;
00788 char *fn;
00789 char *ext;
00790 if (ast_mutex_lock(&formatlock)) {
00791 ast_log(LOG_WARNING, "Unable to lock format list\n");
00792 return NULL;
00793 }
00794 f = formats;
00795 while(f) {
00796 if (exts_compare(f->exts, type)) {
00797 char *stringp=NULL;
00798
00799 ext = strdup(f->exts);
00800 stringp=ext;
00801 ext = strsep(&stringp, "|");
00802 fn = build_filename(filename, ext);
00803 fd = open(fn, flags | myflags);
00804 if (fd >= 0) {
00805 errno = 0;
00806 if ((fs = f->open(fd))) {
00807 fs->trans = NULL;
00808 fs->fmt = f;
00809 fs->flags = flags;
00810 fs->mode = mode;
00811 fs->filename = strdup(filename);
00812 fs->vfs = NULL;
00813 } else {
00814 ast_log(LOG_WARNING, "Unable to open %s\n", fn);
00815 close(fd);
00816 unlink(fn);
00817 }
00818 } else if (errno != EEXIST)
00819 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
00820 free(fn);
00821 free(ext);
00822 break;
00823 }
00824 f = f->next;
00825 }
00826 ast_mutex_unlock(&formatlock);
00827 if (!f)
00828 ast_log(LOG_WARNING, "No such format '%s'\n", type);
00829 return fs;
00830 }
00831
00832 struct ast_filestream *ast_writefile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
00833 {
00834 int fd,myflags = 0;
00835 struct ast_format *f;
00836 struct ast_filestream *fs=NULL;
00837 char *fn,*orig_fn=NULL;
00838 char *ext;
00839 char *buf=NULL;
00840 size_t size = 0;
00841
00842 if (ast_mutex_lock(&formatlock)) {
00843 ast_log(LOG_WARNING, "Unable to lock format list\n");
00844 return NULL;
00845 }
00846
00847 if (flags & O_APPEND){
00848
00849 flags &= ~O_APPEND;
00850 }else{
00851 myflags = O_TRUNC;
00852 }
00853
00854 myflags |= O_WRONLY | O_CREAT;
00855
00856 f = formats;
00857 while(f) {
00858 if (exts_compare(f->exts, type)) {
00859 char *stringp=NULL;
00860
00861 ext = ast_strdupa(f->exts);
00862 stringp=ext;
00863 ext = strsep(&stringp, "|");
00864 fn = build_filename(filename, ext);
00865 fd = open(fn, flags | myflags, mode);
00866
00867 if (option_cache_record_files && fd >= 0) {
00868 close(fd);
00869
00870
00871
00872
00873 orig_fn = ast_strdupa(fn);
00874 for (size=0;size<strlen(fn);size++) {
00875 if (fn[size] == '/')
00876 fn[size] = '_';
00877 }
00878
00879 size += (strlen(record_cache_dir) + 10);
00880 buf = alloca(size);
00881 memset(buf, 0, size);
00882 snprintf(buf, size, "%s/%s", record_cache_dir, fn);
00883 free(fn);
00884 fn=buf;
00885 fd = open(fn, flags | myflags, mode);
00886 }
00887 if (fd >= 0) {
00888 errno = 0;
00889 if ((fs = f->rewrite(fd, comment))) {
00890 fs->trans = NULL;
00891 fs->fmt = f;
00892 fs->flags = flags;
00893 fs->mode = mode;
00894 if (option_cache_record_files) {
00895 fs->realfilename = build_filename(filename, ext);
00896 fs->filename = strdup(fn);
00897 } else {
00898 fs->realfilename = NULL;
00899 fs->filename = strdup(filename);
00900 }
00901 fs->vfs = NULL;
00902 } else {
00903 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
00904 close(fd);
00905 unlink(fn);
00906 if (orig_fn)
00907 unlink(orig_fn);
00908 }
00909 } else if (errno != EEXIST) {
00910 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
00911 if (orig_fn)
00912 unlink(orig_fn);
00913 }
00914 if (!buf)
00915 free(fn);
00916
00917 break;
00918 }
00919 f = f->next;
00920 }
00921 ast_mutex_unlock(&formatlock);
00922 if (!f)
00923 ast_log(LOG_WARNING, "No such format '%s'\n", type);
00924 return fs;
00925 }
00926
00927 char ast_waitstream(struct ast_channel *c, char *breakon)
00928 {
00929
00930 int res;
00931 struct ast_frame *fr;
00932 if (!breakon) breakon = "";
00933 while(c->stream) {
00934 res = ast_sched_wait(c->sched);
00935 if ((res < 0) && !c->timingfunc) {
00936 ast_stopstream(c);
00937 break;
00938 }
00939 if (res < 0)
00940 res = 1000;
00941 res = ast_waitfor(c, res);
00942 if (res < 0) {
00943 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
00944 return res;
00945 } else if (res > 0) {
00946 fr = ast_read(c);
00947 if (!fr) {
00948 #if 0
00949 ast_log(LOG_DEBUG, "Got hung up\n");
00950 #endif
00951 return -1;
00952 }
00953
00954 switch(fr->frametype) {
00955 case AST_FRAME_DTMF:
00956 res = fr->subclass;
00957 if (strchr(breakon, res)) {
00958 ast_frfree(fr);
00959 return res;
00960 }
00961 break;
00962 case AST_FRAME_CONTROL:
00963 switch(fr->subclass) {
00964 case AST_CONTROL_HANGUP:
00965 ast_frfree(fr);
00966 return -1;
00967 case AST_CONTROL_RINGING:
00968 case AST_CONTROL_ANSWER:
00969
00970 break;
00971 default:
00972 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
00973 }
00974 }
00975
00976 ast_frfree(fr);
00977 }
00978 ast_sched_runq(c->sched);
00979 }
00980 return (c->_softhangup ? -1 : 0);
00981 }
00982
00983 char ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char *rewind, int ms)
00984 {
00985 int res;
00986 struct ast_frame *fr;
00987
00988 if (!breakon)
00989 breakon = "";
00990 if (!forward)
00991 forward = "";
00992 if (!rewind)
00993 rewind = "";
00994
00995 while(c->stream) {
00996 res = ast_sched_wait(c->sched);
00997 if ((res < 0) && !c->timingfunc) {
00998 ast_stopstream(c);
00999 break;
01000 }
01001 if (res < 0)
01002 res = 1000;
01003 res = ast_waitfor(c, res);
01004 if (res < 0) {
01005 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
01006 return res;
01007 } else
01008 if (res > 0) {
01009 fr = ast_read(c);
01010 if (!fr) {
01011 #if 0
01012 ast_log(LOG_DEBUG, "Got hung up\n");
01013 #endif
01014 return -1;
01015 }
01016
01017 switch(fr->frametype) {
01018 case AST_FRAME_DTMF:
01019 res = fr->subclass;
01020 if (strchr(forward,res)) {
01021 ast_stream_fastforward(c->stream, ms);
01022 } else if (strchr(rewind,res)) {
01023 ast_stream_rewind(c->stream, ms);
01024 } else if (strchr(breakon, res)) {
01025 ast_frfree(fr);
01026 return res;
01027 }
01028 break;
01029 case AST_FRAME_CONTROL:
01030 switch(fr->subclass) {
01031 case AST_CONTROL_HANGUP:
01032 ast_frfree(fr);
01033 return -1;
01034 case AST_CONTROL_RINGING:
01035 case AST_CONTROL_ANSWER:
01036
01037 break;
01038 default:
01039 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01040 }
01041 }
01042
01043 ast_frfree(fr);
01044 } else
01045 ast_sched_runq(c->sched);
01046
01047
01048 }
01049 return (c->_softhangup ? -1 : 0);
01050 }
01051
01052 char ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int cmdfd)
01053 {
01054 int res;
01055 int ms;
01056 int outfd;
01057 struct ast_frame *fr;
01058 struct ast_channel *rchan;
01059
01060 if (!breakon)
01061 breakon = "";
01062
01063 while(c->stream) {
01064 ms = ast_sched_wait(c->sched);
01065 if ((ms < 0) && !c->timingfunc) {
01066 ast_stopstream(c);
01067 break;
01068 }
01069 if (ms < 0)
01070 ms = 1000;
01071 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
01072 if (!rchan && (outfd < 0) && (ms)) {
01073 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
01074 return -1;
01075 } else if (outfd > -1) {
01076
01077 return 1;
01078 } else if (rchan) {
01079 fr = ast_read(c);
01080 if (!fr) {
01081 #if 0
01082 ast_log(LOG_DEBUG, "Got hung up\n");
01083 #endif
01084 return -1;
01085 }
01086
01087 switch(fr->frametype) {
01088 case AST_FRAME_DTMF:
01089 res = fr->subclass;
01090 if (strchr(breakon, res)) {
01091 ast_frfree(fr);
01092 return res;
01093 }
01094 break;
01095 case AST_FRAME_CONTROL:
01096 switch(fr->subclass) {
01097 case AST_CONTROL_HANGUP:
01098 ast_frfree(fr);
01099 return -1;
01100 case AST_CONTROL_RINGING:
01101 case AST_CONTROL_ANSWER:
01102
01103 break;
01104 default:
01105 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01106 }
01107 case AST_FRAME_VOICE:
01108
01109 if (audiofd > -1)
01110 write(audiofd, fr->data, fr->datalen);
01111 }
01112
01113 ast_frfree(fr);
01114 }
01115 ast_sched_runq(c->sched);
01116
01117
01118 }
01119 return (c->_softhangup ? -1 : 0);
01120 }
01121
01122 static int show_file_formats(int fd, int argc, char *argv[])
01123 {
01124 #define FORMAT "%-10s %-10s %-20s\n"
01125 #define FORMAT2 "%-10s %-10s %-20s\n"
01126 struct ast_format *f;
01127 if (argc != 3)
01128 return RESULT_SHOWUSAGE;
01129 ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
01130
01131 if (ast_mutex_lock(&formatlock)) {
01132 ast_log(LOG_WARNING, "Unable to lock format list\n");
01133 return -1;
01134 }
01135
01136 f = formats;
01137 while(f) {
01138 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
01139 f = f->next;
01140 };
01141 ast_mutex_unlock(&formatlock);
01142 return RESULT_SUCCESS;
01143 }
01144
01145 struct ast_cli_entry show_file =
01146 {
01147 { "show", "file", "formats" },
01148 show_file_formats,
01149 "Displays file formats",
01150 "Usage: show file formats\n"
01151 " displays currently registered file formats (if any)\n"
01152 };
01153
01154 int ast_file_init(void)
01155 {
01156 ast_cli_register(&show_file);
01157 return 0;
01158 }