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

Generated on Fri Sep 24 21:03:47 2004 for Asterisk by doxygen 1.3.8