Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

file.c

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

Generated on Sat Jun 12 16:40:58 2004 for Asterisk by doxygen 1.3.7