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 #define ACTION_EXISTS 1
00291 #define ACTION_DELETE 2
00292 #define ACTION_RENAME 3
00293 #define ACTION_OPEN 4
00294 #define ACTION_COPY 5
00295
00296 static int ast_filehelper(char *filename, char *filename2, char *fmt, int action)
00297 {
00298 struct stat st;
00299 struct ast_format *f;
00300 struct ast_filestream *s;
00301 int res=0, ret = 0;
00302 char *ext=NULL, *exts, *fn, *nfn;
00303 struct ast_channel *chan = (struct ast_channel *)filename2;
00304
00305
00306 if (action == ACTION_EXISTS)
00307 res = 0;
00308 else
00309 res = -1;
00310 if (action == ACTION_OPEN)
00311 ret = -1;
00312
00313 if (ast_mutex_lock(&formatlock)) {
00314 ast_log(LOG_WARNING, "Unable to lock format list\n");
00315 if (action == ACTION_EXISTS)
00316 return 0;
00317 else
00318 return -1;
00319 }
00320 f = formats;
00321 while(f) {
00322 if (!fmt || !strcasecmp(f->name, fmt)) {
00323 char *stringp=NULL;
00324 exts = strdup(f->exts);
00325
00326 stringp=exts;
00327 ext = strsep(&stringp, "|");
00328 do {
00329 fn = build_filename(filename, ext);
00330 if (fn) {
00331 res = stat(fn, &st);
00332 if (!res) {
00333 switch(action) {
00334 case ACTION_EXISTS:
00335 ret |= f->format;
00336 break;
00337 case ACTION_DELETE:
00338 res = unlink(fn);
00339 if (res)
00340 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
00341 break;
00342 case ACTION_RENAME:
00343 nfn = build_filename(filename2, ext);
00344 if (nfn) {
00345 res = rename(fn, nfn);
00346 if (res)
00347 ast_log(LOG_WARNING, "rename(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
00348 free(nfn);
00349 } else
00350 ast_log(LOG_WARNING, "Out of memory\n");
00351 break;
00352 case ACTION_COPY:
00353 nfn = build_filename(filename2, ext);
00354 if (nfn) {
00355 res = copy(fn, nfn);
00356 if (res)
00357 ast_log(LOG_WARNING, "copy(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
00358 free(nfn);
00359 } else
00360 ast_log(LOG_WARNING, "Out of memory\n");
00361 break;
00362 case ACTION_OPEN:
00363 if ((ret < 0) && ((chan->writeformat & f->format) ||
00364 ((f->format >= AST_FORMAT_MAX_AUDIO) && fmt))) {
00365 ret = open(fn, O_RDONLY);
00366 if (ret >= 0) {
00367 s = f->open(ret);
00368 if (s) {
00369 s->lasttimeout = -1;
00370 s->fmt = f;
00371 s->trans = NULL;
00372 s->filename = NULL;
00373 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
00374 chan->stream = s;
00375 else
00376 chan->vstream = s;
00377 } else {
00378 close(ret);
00379 ast_log(LOG_WARNING, "Unable to open fd on %s\n", filename);
00380 }
00381 } else
00382 ast_log(LOG_WARNING, "Couldn't open file %s\n", fn);
00383 }
00384 break;
00385 default:
00386 ast_log(LOG_WARNING, "Unknown helper %d\n", action);
00387 }
00388
00389 if (res)
00390 break;
00391 }
00392 free(fn);
00393 }
00394 ext = strsep(&stringp, "|");
00395 } while(ext);
00396 free(exts);
00397 }
00398 f = f->next;
00399 }
00400 ast_mutex_unlock(&formatlock);
00401 if ((action == ACTION_EXISTS) || (action == ACTION_OPEN))
00402 res = ret ? ret : -1;
00403 return res;
00404 }
00405
00406 struct ast_filestream *ast_openstream(struct ast_channel *chan, char *filename, char *preflang)
00407 {
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420 int fd = -1;
00421 int fmts = -1;
00422 char filename2[256]="";
00423 char filename3[256]="";
00424 char *endpart;
00425 int res;
00426 ast_stopstream(chan);
00427
00428 if (chan->generator)
00429 ast_deactivate_generator(chan);
00430 if (preflang && strlen(preflang)) {
00431 strncpy(filename3, filename, sizeof(filename3) - 1);
00432 endpart = strrchr(filename3, '/');
00433 if (endpart) {
00434 *endpart = '\0';
00435 endpart++;
00436 snprintf(filename2, sizeof(filename2), "%s/%s/%s", filename3, preflang, endpart);
00437 } else
00438 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
00439 fmts = ast_fileexists(filename2, NULL, NULL);
00440 }
00441 if (fmts < 1) {
00442 strncpy(filename2, filename, sizeof(filename2)-1);
00443 fmts = ast_fileexists(filename2, NULL, NULL);
00444 }
00445 if (fmts < 1) {
00446 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
00447 return NULL;
00448 }
00449 chan->oldwriteformat = chan->writeformat;
00450
00451 res = ast_set_write_format(chan, fmts);
00452
00453 fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
00454 if(fd >= 0)
00455 return chan->stream;
00456 return NULL;
00457 }
00458
00459 struct ast_filestream *ast_openvstream(struct ast_channel *chan, char *filename, char *preflang)
00460 {
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473 int fd = -1;
00474 int fmts = -1;
00475 char filename2[256];
00476 char lang2[MAX_LANGUAGE];
00477
00478 char *fmt = "h263";
00479 if (preflang && strlen(preflang)) {
00480 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
00481 fmts = ast_fileexists(filename2, fmt, NULL);
00482 if (fmts < 1) {
00483 strncpy(lang2, preflang, sizeof(lang2)-1);
00484 snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
00485 fmts = ast_fileexists(filename2, fmt, NULL);
00486 }
00487 }
00488 if (fmts < 1) {
00489 strncpy(filename2, filename, sizeof(filename2)-1);
00490 fmts = ast_fileexists(filename2, fmt, NULL);
00491 }
00492 if (fmts < 1) {
00493 return NULL;
00494 }
00495 fd = ast_filehelper(filename2, (char *)chan, fmt, ACTION_OPEN);
00496 if(fd >= 0)
00497 return chan->vstream;
00498 ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
00499 return NULL;
00500 }
00501
00502 struct ast_frame *ast_readframe(struct ast_filestream *s)
00503 {
00504 struct ast_frame *f = NULL;
00505 int whennext = 0;
00506 if (s && s->fmt)
00507 f = s->fmt->read(s, &whennext);
00508 return f;
00509 }
00510
00511 static int ast_readaudio_callback(void *data)
00512 {
00513 struct ast_filestream *s = data;
00514 struct ast_frame *fr;
00515 int whennext = 0;
00516
00517 while(!whennext) {
00518 fr = s->fmt->read(s, &whennext);
00519 if (fr) {
00520 if (ast_write(s->owner, fr)) {
00521 ast_log(LOG_WARNING, "Failed to write frame\n");
00522 s->owner->streamid = -1;
00523 #ifdef ZAPTEL_OPTIMIZATIONS
00524 ast_settimeout(s->owner, 0, NULL, NULL);
00525 #endif
00526 return 0;
00527 }
00528 } else {
00529
00530 s->owner->streamid = -1;
00531 #ifdef ZAPTEL_OPTIMIZATIONS
00532 ast_settimeout(s->owner, 0, NULL, NULL);
00533 #endif
00534 return 0;
00535 }
00536 }
00537 if (whennext != s->lasttimeout) {
00538 #ifdef ZAPTEL_OPTIMIZATIONS
00539 if (s->owner->timingfd > -1)
00540 ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
00541 else
00542 #endif
00543 s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
00544 s->lasttimeout = whennext;
00545 return 0;
00546 }
00547 return 1;
00548 }
00549
00550 static int ast_readvideo_callback(void *data)
00551 {
00552 struct ast_filestream *s = data;
00553 struct ast_frame *fr;
00554 int whennext = 0;
00555
00556 while(!whennext) {
00557 fr = s->fmt->read(s, &whennext);
00558 if (fr) {
00559 if (ast_write(s->owner, fr)) {
00560 ast_log(LOG_WARNING, "Failed to write frame\n");
00561 s->owner->vstreamid = -1;
00562 return 0;
00563 }
00564 } else {
00565
00566 s->owner->vstreamid = -1;
00567 return 0;
00568 }
00569 }
00570 if (whennext != s->lasttimeout) {
00571 s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
00572 s->lasttimeout = whennext;
00573 return 0;
00574 }
00575 return 1;
00576 }
00577
00578 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
00579 {
00580 s->owner = chan;
00581 return 0;
00582 }
00583
00584 int ast_playstream(struct ast_filestream *s)
00585 {
00586 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
00587 ast_readaudio_callback(s);
00588 else
00589 ast_readvideo_callback(s);
00590 return 0;
00591 }
00592
00593 int ast_seekstream(struct ast_filestream *fs, long sample_offset, int whence)
00594 {
00595 return fs->fmt->seek(fs, sample_offset, whence);
00596 }
00597
00598 int ast_truncstream(struct ast_filestream *fs)
00599 {
00600 return fs->fmt->trunc(fs);
00601 }
00602
00603 long ast_tellstream(struct ast_filestream *fs)
00604 {
00605 return fs->fmt->tell(fs);
00606 }
00607
00608 int ast_stream_fastforward(struct ast_filestream *fs, long ms)
00609 {
00610
00611
00612 long samples = ms * 8;
00613 return ast_seekstream(fs, samples, SEEK_CUR);
00614 }
00615
00616 int ast_stream_rewind(struct ast_filestream *fs, long ms)
00617 {
00618 long samples = ms * 8;
00619 samples = samples * -1;
00620 return ast_seekstream(fs, samples, SEEK_CUR);
00621 }
00622
00623 int ast_closestream(struct ast_filestream *f)
00624 {
00625
00626 if (f->owner) {
00627 if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
00628 f->owner->stream = NULL;
00629 if (f->owner->streamid > -1)
00630 ast_sched_del(f->owner->sched, f->owner->streamid);
00631 f->owner->streamid = -1;
00632 #ifdef ZAPTEL_OPTIMIZATIONS
00633 ast_settimeout(f->owner, 0, NULL, NULL);
00634 #endif
00635 } else {
00636 f->owner->vstream = NULL;
00637 if (f->owner->vstreamid > -1)
00638 ast_sched_del(f->owner->sched, f->owner->vstreamid);
00639 f->owner->vstreamid = -1;
00640 }
00641 }
00642
00643 if (f->trans) {
00644 ast_translator_free_path(f->trans);
00645 f->trans = NULL;
00646 }
00647 if (f->filename)
00648 free(f->filename);
00649 f->filename = NULL;
00650 f->fmt->close(f);
00651 return 0;
00652 }
00653
00654
00655 int ast_fileexists(char *filename, char *fmt, char *preflang)
00656 {
00657 char filename2[256];
00658 char tmp[256];
00659 char *postfix;
00660 char *prefix;
00661 char *c;
00662 char lang2[MAX_LANGUAGE];
00663 int res = -1;
00664 if (preflang && strlen(preflang)) {
00665
00666 strncpy(tmp, filename, sizeof(tmp) - 1);
00667 c = strrchr(tmp, '/');
00668 if (c) {
00669 *c = '\0';
00670 postfix = c+1;
00671 prefix = tmp;
00672 } else {
00673 postfix = tmp;
00674 prefix="";
00675 }
00676 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
00677 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
00678 if (res < 1) {
00679 char *stringp=NULL;
00680 strncpy(lang2, preflang, sizeof(lang2)-1);
00681 stringp=lang2;
00682 strsep(&stringp, "_");
00683 if (strcmp(lang2, preflang)) {
00684 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
00685 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
00686 }
00687 }
00688 }
00689 if (res < 1) {
00690 res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
00691 }
00692 return res;
00693 }
00694
00695 int ast_filedelete(char *filename, char *fmt)
00696 {
00697 return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
00698 }
00699
00700 int ast_filerename(char *filename, char *filename2, char *fmt)
00701 {
00702 return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
00703 }
00704
00705 int ast_filecopy(char *filename, char *filename2, char *fmt)
00706 {
00707 return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
00708 }
00709
00710 int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang)
00711 {
00712 struct ast_filestream *fs;
00713 struct ast_filestream *vfs;
00714
00715 fs = ast_openstream(chan, filename, preflang);
00716 vfs = ast_openvstream(chan, filename, preflang);
00717 if (vfs)
00718 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
00719 if(fs){
00720 if(ast_applystream(chan, fs))
00721 return -1;
00722 if(vfs && ast_applystream(chan, vfs))
00723 return -1;
00724 if(ast_playstream(fs))
00725 return -1;
00726 if(vfs && ast_playstream(vfs))
00727 return -1;
00728 #if 1
00729 if (option_verbose > 2)
00730 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (language '%s')\n", filename, preflang ? preflang : "default");
00731 #endif
00732 return 0;
00733 }
00734 ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname(chan->nativeformats), strerror(errno));
00735 return -1;
00736 }
00737
00738 struct ast_filestream *ast_readfile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
00739 {
00740 int fd,myflags = 0;
00741 struct ast_format *f;
00742 struct ast_filestream *fs=NULL;
00743 char *fn;
00744 char *ext;
00745 if (ast_mutex_lock(&formatlock)) {
00746 ast_log(LOG_WARNING, "Unable to lock format list\n");
00747 return NULL;
00748 }
00749 f = formats;
00750 while(f) {
00751 if (!strcasecmp(f->name, type)) {
00752 char *stringp=NULL;
00753
00754 ext = strdup(f->exts);
00755 stringp=ext;
00756 ext = strsep(&stringp, "|");
00757 fn = build_filename(filename, ext);
00758 fd = open(fn, flags | myflags);
00759 if (fd >= 0) {
00760 errno = 0;
00761 if ((fs = f->open(fd))) {
00762 fs->trans = NULL;
00763 fs->fmt = f;
00764 fs->flags = flags;
00765 fs->mode = mode;
00766 fs->filename = strdup(filename);
00767 fs->vfs = NULL;
00768 } else {
00769 ast_log(LOG_WARNING, "Unable to open %s\n", fn);
00770 close(fd);
00771 unlink(fn);
00772 }
00773 } else if (errno != EEXIST)
00774 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
00775 free(fn);
00776 free(ext);
00777 break;
00778 }
00779 f = f->next;
00780 }
00781 ast_mutex_unlock(&formatlock);
00782 if (!f)
00783 ast_log(LOG_WARNING, "No such format '%s'\n", type);
00784 return fs;
00785 }
00786
00787 struct ast_filestream *ast_writefile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
00788 {
00789 int fd,myflags = 0;
00790 struct ast_format *f;
00791 struct ast_filestream *fs=NULL;
00792 char *fn;
00793 char *ext;
00794 if (ast_mutex_lock(&formatlock)) {
00795 ast_log(LOG_WARNING, "Unable to lock format list\n");
00796 return NULL;
00797 }
00798
00799 if (!(flags & O_APPEND))
00800 myflags = O_TRUNC;
00801
00802 myflags |= O_WRONLY | O_CREAT;
00803
00804 f = formats;
00805 while(f) {
00806 if (!strcasecmp(f->name, type)) {
00807 char *stringp=NULL;
00808
00809 ext = strdup(f->exts);
00810 stringp=ext;
00811 ext = strsep(&stringp, "|");
00812 fn = build_filename(filename, ext);
00813 fd = open(fn, flags | myflags, mode);
00814 if (fd >= 0) {
00815 errno = 0;
00816 if ((fs = f->rewrite(fd, comment))) {
00817 fs->trans = NULL;
00818 fs->fmt = f;
00819 fs->flags = flags;
00820 fs->mode = mode;
00821 fs->filename = strdup(filename);
00822 fs->vfs = NULL;
00823 } else {
00824 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
00825 close(fd);
00826 unlink(fn);
00827 }
00828 } else if (errno != EEXIST)
00829 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
00830 free(fn);
00831 free(ext);
00832 break;
00833 }
00834 f = f->next;
00835 }
00836 ast_mutex_unlock(&formatlock);
00837 if (!f)
00838 ast_log(LOG_WARNING, "No such format '%s'\n", type);
00839 return fs;
00840 }
00841
00842 char ast_waitstream(struct ast_channel *c, char *breakon)
00843 {
00844
00845 int res;
00846 struct ast_frame *fr;
00847 while(c->stream) {
00848 res = ast_sched_wait(c->sched);
00849 if ((res < 0) && !c->timingfunc) {
00850 ast_stopstream(c);
00851 break;
00852 }
00853 if (res < 0)
00854 res = 1000;
00855 res = ast_waitfor(c, res);
00856 if (res < 0) {
00857 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
00858 return res;
00859 } else if (res > 0) {
00860 fr = ast_read(c);
00861 if (!fr) {
00862 #if 0
00863 ast_log(LOG_DEBUG, "Got hung up\n");
00864 #endif
00865 return -1;
00866 }
00867
00868 switch(fr->frametype) {
00869 case AST_FRAME_DTMF:
00870 res = fr->subclass;
00871 if (strchr(breakon, res)) {
00872 ast_frfree(fr);
00873 return res;
00874 }
00875 break;
00876 case AST_FRAME_CONTROL:
00877 switch(fr->subclass) {
00878 case AST_CONTROL_HANGUP:
00879 ast_frfree(fr);
00880 return -1;
00881 case AST_CONTROL_RINGING:
00882 case AST_CONTROL_ANSWER:
00883
00884 break;
00885 default:
00886 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
00887 }
00888 }
00889
00890 ast_frfree(fr);
00891 }
00892 ast_sched_runq(c->sched);
00893 }
00894 return (c->_softhangup ? -1 : 0);
00895 }
00896
00897 char ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char *rewind, int ms)
00898 {
00899 int res;
00900 struct ast_frame *fr;
00901 while(c->stream) {
00902 res = ast_sched_wait(c->sched);
00903 if ((res < 0) && !c->timingfunc) {
00904 ast_stopstream(c);
00905 break;
00906 }
00907 if (res < 0)
00908 res = 1000;
00909 res = ast_waitfor(c, res);
00910 if (res < 0) {
00911 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
00912 return res;
00913 } else
00914 if (res > 0) {
00915 fr = ast_read(c);
00916 if (!fr) {
00917 #if 0
00918 ast_log(LOG_DEBUG, "Got hung up\n");
00919 #endif
00920 return -1;
00921 }
00922
00923 switch(fr->frametype) {
00924 case AST_FRAME_DTMF:
00925 res = fr->subclass;
00926 if (strchr(forward,res)) {
00927 ast_stream_fastforward(c->stream, ms);
00928 } else if (strchr(rewind,res)) {
00929 ast_stream_rewind(c->stream, ms);
00930 } else if (strchr(breakon, res)) {
00931 ast_frfree(fr);
00932 return res;
00933 }
00934 break;
00935 case AST_FRAME_CONTROL:
00936 switch(fr->subclass) {
00937 case AST_CONTROL_HANGUP:
00938 ast_frfree(fr);
00939 return -1;
00940 case AST_CONTROL_RINGING:
00941 case AST_CONTROL_ANSWER:
00942
00943 break;
00944 default:
00945 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
00946 }
00947 }
00948
00949 ast_frfree(fr);
00950 } else
00951 ast_sched_runq(c->sched);
00952
00953
00954 }
00955 return (c->_softhangup ? -1 : 0);
00956 }
00957
00958 char ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int cmdfd)
00959 {
00960 int res;
00961 int ms;
00962 int outfd;
00963 struct ast_frame *fr;
00964 struct ast_channel *rchan;
00965
00966 while(c->stream) {
00967 ms = ast_sched_wait(c->sched);
00968 if ((ms < 0) && !c->timingfunc) {
00969 ast_stopstream(c);
00970 break;
00971 }
00972 if (ms < 0)
00973 ms = 1000;
00974 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
00975 if (!rchan && (outfd < 0) && (ms)) {
00976 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
00977 return -1;
00978 } else if (outfd > -1) {
00979
00980 return 1;
00981 } else if (rchan) {
00982 fr = ast_read(c);
00983 if (!fr) {
00984 #if 0
00985 ast_log(LOG_DEBUG, "Got hung up\n");
00986 #endif
00987 return -1;
00988 }
00989
00990 switch(fr->frametype) {
00991 case AST_FRAME_DTMF:
00992 res = fr->subclass;
00993 if (strchr(breakon, res)) {
00994 ast_frfree(fr);
00995 return res;
00996 }
00997 break;
00998 case AST_FRAME_CONTROL:
00999 switch(fr->subclass) {
01000 case AST_CONTROL_HANGUP:
01001 ast_frfree(fr);
01002 return -1;
01003 case AST_CONTROL_RINGING:
01004 case AST_CONTROL_ANSWER:
01005
01006 break;
01007 default:
01008 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01009 }
01010 case AST_FRAME_VOICE:
01011
01012 if (audiofd > -1)
01013 write(audiofd, fr->data, fr->datalen);
01014 }
01015
01016 ast_frfree(fr);
01017 }
01018 ast_sched_runq(c->sched);
01019
01020
01021 }
01022 return (c->_softhangup ? -1 : 0);
01023 }