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

Generated on Tue Aug 17 16:13:53 2004 for Asterisk by doxygen 1.3.8