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 lang2[MAX_LANGUAGE];
00424 int res;
00425 ast_stopstream(chan);
00426
00427 if (chan->generator)
00428 ast_deactivate_generator(chan);
00429 if (preflang && strlen(preflang)) {
00430 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
00431 fmts = ast_fileexists(filename2, NULL, NULL);
00432 if (fmts < 1) {
00433 strncpy(lang2, preflang, sizeof(lang2)-1);
00434 snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
00435 fmts = ast_fileexists(filename2, NULL, NULL);
00436 }
00437 }
00438 if (fmts < 1) {
00439 strncpy(filename2, filename, sizeof(filename2)-1);
00440 fmts = ast_fileexists(filename2, NULL, NULL);
00441 }
00442 if (fmts < 1) {
00443 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
00444 return NULL;
00445 }
00446 chan->oldwriteformat = chan->writeformat;
00447
00448 res = ast_set_write_format(chan, fmts);
00449
00450 fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
00451 if(fd >= 0)
00452 return chan->stream;
00453 return NULL;
00454 }
00455
00456 struct ast_filestream *ast_openvstream(struct ast_channel *chan, char *filename, char *preflang)
00457 {
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470 int fd = -1;
00471 int fmts = -1;
00472 char filename2[256];
00473 char lang2[MAX_LANGUAGE];
00474
00475 char *fmt = "h263";
00476 if (preflang && strlen(preflang)) {
00477 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
00478 fmts = ast_fileexists(filename2, fmt, NULL);
00479 if (fmts < 1) {
00480 strncpy(lang2, preflang, sizeof(lang2)-1);
00481 snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
00482 fmts = ast_fileexists(filename2, fmt, NULL);
00483 }
00484 }
00485 if (fmts < 1) {
00486 strncpy(filename2, filename, sizeof(filename2)-1);
00487 fmts = ast_fileexists(filename2, fmt, NULL);
00488 }
00489 if (fmts < 1) {
00490 return NULL;
00491 }
00492 fd = ast_filehelper(filename2, (char *)chan, fmt, ACTION_OPEN);
00493 if(fd >= 0)
00494 return chan->vstream;
00495 ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
00496 return NULL;
00497 }
00498
00499 static int ast_readaudio_callback(void *data)
00500 {
00501 struct ast_filestream *s = data;
00502 struct ast_frame *fr;
00503 int whennext = 0;
00504
00505 while(!whennext) {
00506 fr = s->fmt->read(s, &whennext);
00507 if (fr) {
00508 if (ast_write(s->owner, fr)) {
00509 ast_log(LOG_WARNING, "Failed to write frame\n");
00510 s->owner->streamid = -1;
00511 #ifdef ZAPTEL_OPTIMIZATIONS
00512 ast_settimeout(s->owner, 0, NULL, NULL);
00513 #endif
00514 return 0;
00515 }
00516 } else {
00517
00518 s->owner->streamid = -1;
00519 #ifdef ZAPTEL_OPTIMIZATIONS
00520 ast_settimeout(s->owner, 0, NULL, NULL);
00521 #endif
00522 return 0;
00523 }
00524 }
00525 if (whennext != s->lasttimeout) {
00526 #ifdef ZAPTEL_OPTIMIZATIONS
00527 if (s->owner->timingfd > -1)
00528 ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
00529 else
00530 #endif
00531 s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
00532 s->lasttimeout = whennext;
00533 return 0;
00534 }
00535 return 1;
00536 }
00537
00538 static int ast_readvideo_callback(void *data)
00539 {
00540 struct ast_filestream *s = data;
00541 struct ast_frame *fr;
00542 int whennext = 0;
00543
00544 while(!whennext) {
00545 fr = s->fmt->read(s, &whennext);
00546 if (fr) {
00547 if (ast_write(s->owner, fr)) {
00548 ast_log(LOG_WARNING, "Failed to write frame\n");
00549 s->owner->vstreamid = -1;
00550 return 0;
00551 }
00552 } else {
00553
00554 s->owner->vstreamid = -1;
00555 return 0;
00556 }
00557 }
00558 if (whennext != s->lasttimeout) {
00559 s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
00560 s->lasttimeout = whennext;
00561 return 0;
00562 }
00563 return 1;
00564 }
00565
00566 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
00567 {
00568 s->owner = chan;
00569 return 0;
00570 }
00571
00572 int ast_playstream(struct ast_filestream *s)
00573 {
00574 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
00575 ast_readaudio_callback(s);
00576 else
00577 ast_readvideo_callback(s);
00578 return 0;
00579 }
00580
00581 int ast_seekstream(struct ast_filestream *fs, long sample_offset, int whence)
00582 {
00583 return fs->fmt->seek(fs, sample_offset, whence);
00584 }
00585
00586 int ast_truncstream(struct ast_filestream *fs)
00587 {
00588 return fs->fmt->trunc(fs);
00589 }
00590
00591 long ast_tellstream(struct ast_filestream *fs)
00592 {
00593 return fs->fmt->tell(fs);
00594 }
00595
00596 int ast_stream_fastforward(struct ast_filestream *fs, long ms)
00597 {
00598
00599
00600 long samples = ms * 8;
00601 return ast_seekstream(fs, samples, SEEK_CUR);
00602 }
00603
00604 int ast_stream_rewind(struct ast_filestream *fs, long ms)
00605 {
00606 long samples = ms * 8;
00607 samples = samples * -1;
00608 return ast_seekstream(fs, samples, SEEK_CUR);
00609 }
00610
00611 int ast_closestream(struct ast_filestream *f)
00612 {
00613
00614 if (f->owner) {
00615 if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
00616 f->owner->stream = NULL;
00617 if (f->owner->streamid > -1)
00618 ast_sched_del(f->owner->sched, f->owner->streamid);
00619 f->owner->streamid = -1;
00620 #ifdef ZAPTEL_OPTIMIZATIONS
00621 ast_settimeout(f->owner, 0, NULL, NULL);
00622 #endif
00623 } else {
00624 f->owner->vstream = NULL;
00625 if (f->owner->vstreamid > -1)
00626 ast_sched_del(f->owner->sched, f->owner->vstreamid);
00627 f->owner->vstreamid = -1;
00628 }
00629 }
00630
00631 if (f->trans) {
00632 ast_translator_free_path(f->trans);
00633 f->trans = NULL;
00634 }
00635 if (f->filename)
00636 free(f->filename);
00637 f->filename = NULL;
00638 f->fmt->close(f);
00639 return 0;
00640 }
00641
00642
00643 int ast_fileexists(char *filename, char *fmt, char *preflang)
00644 {
00645 char filename2[256];
00646 char tmp[256];
00647 char *postfix;
00648 char *prefix;
00649 char *c;
00650 char lang2[MAX_LANGUAGE];
00651 int res = -1;
00652 if (preflang && strlen(preflang)) {
00653
00654 strncpy(tmp, filename, sizeof(tmp) - 1);
00655 c = strrchr(tmp, '/');
00656 if (c) {
00657 *c = '\0';
00658 postfix = c+1;
00659 prefix = tmp;
00660 } else {
00661 postfix = tmp;
00662 prefix="";
00663 }
00664 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
00665 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
00666 if (res < 1) {
00667 char *stringp=NULL;
00668 strncpy(lang2, preflang, sizeof(lang2)-1);
00669 stringp=lang2;
00670 strsep(&stringp, "_");
00671 if (strcmp(lang2, preflang)) {
00672 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
00673 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
00674 }
00675 }
00676 }
00677 if (res < 1) {
00678 res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
00679 }
00680 return res;
00681 }
00682
00683 int ast_filedelete(char *filename, char *fmt)
00684 {
00685 return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
00686 }
00687
00688 int ast_filerename(char *filename, char *filename2, char *fmt)
00689 {
00690 return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
00691 }
00692
00693 int ast_filecopy(char *filename, char *filename2, char *fmt)
00694 {
00695 return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
00696 }
00697
00698 int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang)
00699 {
00700 struct ast_filestream *fs;
00701 struct ast_filestream *vfs;
00702
00703 fs = ast_openstream(chan, filename, preflang);
00704 vfs = ast_openvstream(chan, filename, preflang);
00705 if (vfs)
00706 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
00707 if(fs){
00708 if(ast_applystream(chan, fs))
00709 return -1;
00710 if(vfs && ast_applystream(chan, vfs))
00711 return -1;
00712 if(ast_playstream(fs))
00713 return -1;
00714 if(vfs && ast_playstream(vfs))
00715 return -1;
00716 #if 1
00717 if (option_verbose > 2)
00718 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s'\n", filename);
00719 #endif
00720 return 0;
00721 }
00722 ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname(chan->nativeformats), strerror(errno));
00723 return -1;
00724 }
00725
00726
00727 struct ast_filestream *ast_writefile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
00728 {
00729 int fd,myflags;
00730 struct ast_format *f;
00731 struct ast_filestream *fs=NULL;
00732 char *fn;
00733 char *ext;
00734 if (ast_mutex_lock(&formatlock)) {
00735 ast_log(LOG_WARNING, "Unable to lock format list\n");
00736 return NULL;
00737 }
00738 myflags = 0;
00739
00740 if (!(flags & O_APPEND)) myflags = O_TRUNC;
00741 f = formats;
00742 while(f) {
00743 if (!strcasecmp(f->name, type)) {
00744 char *stringp=NULL;
00745
00746 ext = strdup(f->exts);
00747 stringp=ext;
00748 ext = strsep(&stringp, "|");
00749 fn = build_filename(filename, ext);
00750 fd = open(fn, flags | myflags | O_WRONLY | O_CREAT, mode);
00751 if (fd >= 0) {
00752 errno = 0;
00753 if ((fs = f->rewrite(fd, comment))) {
00754 fs->trans = NULL;
00755 fs->fmt = f;
00756 fs->flags = flags;
00757 fs->mode = mode;
00758 fs->filename = strdup(filename);
00759 fs->vfs = NULL;
00760 } else {
00761 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
00762 close(fd);
00763 unlink(fn);
00764 }
00765 } else if (errno != EEXIST)
00766 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
00767 free(fn);
00768 free(ext);
00769 break;
00770 }
00771 f = f->next;
00772 }
00773 ast_mutex_unlock(&formatlock);
00774 if (!f)
00775 ast_log(LOG_WARNING, "No such format '%s'\n", type);
00776 return fs;
00777 }
00778
00779 char ast_waitstream(struct ast_channel *c, char *breakon)
00780 {
00781
00782 int res;
00783 struct ast_frame *fr;
00784 while(c->stream) {
00785 res = ast_sched_wait(c->sched);
00786 if ((res < 0) && !c->timingfunc) {
00787 ast_stopstream(c);
00788 break;
00789 }
00790 if (res < 0)
00791 res = 1000;
00792 res = ast_waitfor(c, res);
00793 if (res < 0) {
00794 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
00795 return res;
00796 } else if (res > 0) {
00797 fr = ast_read(c);
00798 if (!fr) {
00799 #if 0
00800 ast_log(LOG_DEBUG, "Got hung up\n");
00801 #endif
00802 return -1;
00803 }
00804
00805 switch(fr->frametype) {
00806 case AST_FRAME_DTMF:
00807 res = fr->subclass;
00808 if (strchr(breakon, res)) {
00809 ast_frfree(fr);
00810 return res;
00811 }
00812 break;
00813 case AST_FRAME_CONTROL:
00814 switch(fr->subclass) {
00815 case AST_CONTROL_HANGUP:
00816 ast_frfree(fr);
00817 return -1;
00818 case AST_CONTROL_RINGING:
00819 case AST_CONTROL_ANSWER:
00820
00821 break;
00822 default:
00823 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
00824 }
00825 }
00826
00827 ast_frfree(fr);
00828 }
00829 ast_sched_runq(c->sched);
00830 }
00831 return (c->_softhangup ? -1 : 0);
00832 }
00833
00834 char ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char *rewind, int ms)
00835 {
00836 int res;
00837 struct ast_frame *fr;
00838 while(c->stream) {
00839 res = ast_sched_wait(c->sched);
00840 if ((res < 0) && !c->timingfunc) {
00841 ast_stopstream(c);
00842 break;
00843 }
00844 if (res < 0)
00845 res = 1000;
00846 res = ast_waitfor(c, res);
00847 if (res < 0) {
00848 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
00849 return res;
00850 } else
00851 if (res > 0) {
00852 fr = ast_read(c);
00853 if (!fr) {
00854 #if 0
00855 ast_log(LOG_DEBUG, "Got hung up\n");
00856 #endif
00857 return -1;
00858 }
00859
00860 switch(fr->frametype) {
00861 case AST_FRAME_DTMF:
00862 res = fr->subclass;
00863 if (strchr(forward,res)) {
00864 ast_stream_fastforward(c->stream, ms);
00865 } else if (strchr(rewind,res)) {
00866 ast_stream_rewind(c->stream, ms);
00867 } else if (strchr(breakon, res)) {
00868 ast_frfree(fr);
00869 return res;
00870 }
00871 break;
00872 case AST_FRAME_CONTROL:
00873 switch(fr->subclass) {
00874 case AST_CONTROL_HANGUP:
00875 ast_frfree(fr);
00876 return -1;
00877 case AST_CONTROL_RINGING:
00878 case AST_CONTROL_ANSWER:
00879
00880 break;
00881 default:
00882 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
00883 }
00884 }
00885
00886 ast_frfree(fr);
00887 } else
00888 ast_sched_runq(c->sched);
00889
00890
00891 }
00892 return (c->_softhangup ? -1 : 0);
00893 }
00894
00895 char ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int cmdfd)
00896 {
00897 int res;
00898 int ms;
00899 int outfd;
00900 struct ast_frame *fr;
00901 struct ast_channel *rchan;
00902
00903 while(c->stream) {
00904 ms = ast_sched_wait(c->sched);
00905 if ((ms < 0) && !c->timingfunc) {
00906 ast_stopstream(c);
00907 break;
00908 }
00909 if (ms < 0)
00910 ms = 1000;
00911 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
00912 if (!rchan && (outfd < 0) && (ms)) {
00913 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
00914 return -1;
00915 } else if (outfd > -1) {
00916
00917 return 1;
00918 } else if (rchan) {
00919 fr = ast_read(c);
00920 if (!fr) {
00921 #if 0
00922 ast_log(LOG_DEBUG, "Got hung up\n");
00923 #endif
00924 return -1;
00925 }
00926
00927 switch(fr->frametype) {
00928 case AST_FRAME_DTMF:
00929 res = fr->subclass;
00930 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 case AST_FRAME_VOICE:
00948
00949 if (audiofd > -1)
00950 write(audiofd, fr->data, fr->datalen);
00951 }
00952
00953 ast_frfree(fr);
00954 }
00955 ast_sched_runq(c->sched);
00956
00957
00958 }
00959 return (c->_softhangup ? -1 : 0);
00960 }