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