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 myflags = O_TRUNC;
00849
00850 myflags |= O_WRONLY | O_CREAT;
00851
00852 f = formats;
00853 while(f) {
00854 if (exts_compare(f->exts, type)) {
00855 char *stringp=NULL;
00856
00857 ext = ast_strdupa(f->exts);
00858 stringp=ext;
00859 ext = strsep(&stringp, "|");
00860 fn = build_filename(filename, ext);
00861 fd = open(fn, flags | myflags, mode);
00862
00863 if (option_cache_record_files && fd >= 0) {
00864 close(fd);
00865
00866
00867
00868
00869 orig_fn = ast_strdupa(fn);
00870 for (size=0;size<strlen(fn);size++) {
00871 if (fn[size] == '/')
00872 fn[size] = '_';
00873 }
00874
00875 size += (strlen(record_cache_dir) + 10);
00876 buf = alloca(size);
00877 memset(buf, 0, size);
00878 snprintf(buf, size, "%s/%s", record_cache_dir, fn);
00879 free(fn);
00880 fn=buf;
00881 fd = open(fn, flags | myflags, mode);
00882 }
00883 if (fd >= 0) {
00884 errno = 0;
00885 if ((fs = f->rewrite(fd, comment))) {
00886 fs->trans = NULL;
00887 fs->fmt = f;
00888 fs->flags = flags;
00889 fs->mode = mode;
00890 if (option_cache_record_files) {
00891 fs->realfilename = build_filename(filename, ext);
00892 fs->filename = strdup(fn);
00893 } else {
00894 fs->realfilename = NULL;
00895 fs->filename = strdup(filename);
00896 }
00897 fs->vfs = NULL;
00898 } else {
00899 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
00900 close(fd);
00901 unlink(fn);
00902 if (orig_fn)
00903 unlink(orig_fn);
00904 }
00905 } else if (errno != EEXIST) {
00906 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
00907 if (orig_fn)
00908 unlink(orig_fn);
00909 }
00910 if (!buf)
00911 free(fn);
00912
00913 break;
00914 }
00915 f = f->next;
00916 }
00917 ast_mutex_unlock(&formatlock);
00918 if (!f)
00919 ast_log(LOG_WARNING, "No such format '%s'\n", type);
00920 return fs;
00921 }
00922
00923 char ast_waitstream(struct ast_channel *c, char *breakon)
00924 {
00925
00926 int res;
00927 struct ast_frame *fr;
00928 if (!breakon) breakon = "";
00929 while(c->stream) {
00930 res = ast_sched_wait(c->sched);
00931 if ((res < 0) && !c->timingfunc) {
00932 ast_stopstream(c);
00933 break;
00934 }
00935 if (res < 0)
00936 res = 1000;
00937 res = ast_waitfor(c, res);
00938 if (res < 0) {
00939 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
00940 return res;
00941 } else if (res > 0) {
00942 fr = ast_read(c);
00943 if (!fr) {
00944 #if 0
00945 ast_log(LOG_DEBUG, "Got hung up\n");
00946 #endif
00947 return -1;
00948 }
00949
00950 switch(fr->frametype) {
00951 case AST_FRAME_DTMF:
00952 res = fr->subclass;
00953 if (strchr(breakon, res)) {
00954 ast_frfree(fr);
00955 return res;
00956 }
00957 break;
00958 case AST_FRAME_CONTROL:
00959 switch(fr->subclass) {
00960 case AST_CONTROL_HANGUP:
00961 ast_frfree(fr);
00962 return -1;
00963 case AST_CONTROL_RINGING:
00964 case AST_CONTROL_ANSWER:
00965
00966 break;
00967 default:
00968 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
00969 }
00970 }
00971
00972 ast_frfree(fr);
00973 }
00974 ast_sched_runq(c->sched);
00975 }
00976 return (c->_softhangup ? -1 : 0);
00977 }
00978
00979 char ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char *rewind, int ms)
00980 {
00981 int res;
00982 struct ast_frame *fr;
00983 while(c->stream) {
00984 res = ast_sched_wait(c->sched);
00985 if ((res < 0) && !c->timingfunc) {
00986 ast_stopstream(c);
00987 break;
00988 }
00989 if (res < 0)
00990 res = 1000;
00991 res = ast_waitfor(c, res);
00992 if (res < 0) {
00993 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
00994 return res;
00995 } else
00996 if (res > 0) {
00997 fr = ast_read(c);
00998 if (!fr) {
00999 #if 0
01000 ast_log(LOG_DEBUG, "Got hung up\n");
01001 #endif
01002 return -1;
01003 }
01004
01005 switch(fr->frametype) {
01006 case AST_FRAME_DTMF:
01007 res = fr->subclass;
01008 if (strchr(forward,res)) {
01009 ast_stream_fastforward(c->stream, ms);
01010 } else if (strchr(rewind,res)) {
01011 ast_stream_rewind(c->stream, ms);
01012 } else if (strchr(breakon, res)) {
01013 ast_frfree(fr);
01014 return res;
01015 }
01016 break;
01017 case AST_FRAME_CONTROL:
01018 switch(fr->subclass) {
01019 case AST_CONTROL_HANGUP:
01020 ast_frfree(fr);
01021 return -1;
01022 case AST_CONTROL_RINGING:
01023 case AST_CONTROL_ANSWER:
01024
01025 break;
01026 default:
01027 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01028 }
01029 }
01030
01031 ast_frfree(fr);
01032 } else
01033 ast_sched_runq(c->sched);
01034
01035
01036 }
01037 return (c->_softhangup ? -1 : 0);
01038 }
01039
01040 char ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int cmdfd)
01041 {
01042 int res;
01043 int ms;
01044 int outfd;
01045 struct ast_frame *fr;
01046 struct ast_channel *rchan;
01047
01048 while(c->stream) {
01049 ms = ast_sched_wait(c->sched);
01050 if ((ms < 0) && !c->timingfunc) {
01051 ast_stopstream(c);
01052 break;
01053 }
01054 if (ms < 0)
01055 ms = 1000;
01056 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
01057 if (!rchan && (outfd < 0) && (ms)) {
01058 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
01059 return -1;
01060 } else if (outfd > -1) {
01061
01062 return 1;
01063 } else if (rchan) {
01064 fr = ast_read(c);
01065 if (!fr) {
01066 #if 0
01067 ast_log(LOG_DEBUG, "Got hung up\n");
01068 #endif
01069 return -1;
01070 }
01071
01072 switch(fr->frametype) {
01073 case AST_FRAME_DTMF:
01074 res = fr->subclass;
01075 if (strchr(breakon, res)) {
01076 ast_frfree(fr);
01077 return res;
01078 }
01079 break;
01080 case AST_FRAME_CONTROL:
01081 switch(fr->subclass) {
01082 case AST_CONTROL_HANGUP:
01083 ast_frfree(fr);
01084 return -1;
01085 case AST_CONTROL_RINGING:
01086 case AST_CONTROL_ANSWER:
01087
01088 break;
01089 default:
01090 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01091 }
01092 case AST_FRAME_VOICE:
01093
01094 if (audiofd > -1)
01095 write(audiofd, fr->data, fr->datalen);
01096 }
01097
01098 ast_frfree(fr);
01099 }
01100 ast_sched_runq(c->sched);
01101
01102
01103 }
01104 return (c->_softhangup ? -1 : 0);
01105 }
01106
01107 static int show_file_formats(int fd, int argc, char *argv[])
01108 {
01109 #define FORMAT "%-10s %-10s %-20s\n"
01110 #define FORMAT2 "%-10s %-10s %-20s\n"
01111 struct ast_format *f;
01112 if (argc != 3)
01113 return RESULT_SHOWUSAGE;
01114 ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
01115
01116 if (ast_mutex_lock(&formatlock)) {
01117 ast_log(LOG_WARNING, "Unable to lock format list\n");
01118 return -1;
01119 }
01120
01121 f = formats;
01122 while(f) {
01123 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
01124 f = f->next;
01125 };
01126 ast_mutex_unlock(&formatlock);
01127 return RESULT_SUCCESS;
01128 }
01129
01130 struct ast_cli_entry show_file =
01131 {
01132 { "show", "file", "formats" },
01133 show_file_formats,
01134 "Displays file formats",
01135 "Usage: show file formats\n"
01136 " displays currently registered file formats (if any)\n"
01137 };
01138
01139 int ast_file_init(void)
01140 {
01141 ast_cli_register(&show_file);
01142 return 0;
01143 }