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 Thu Oct 28 11:32:53 2004 for Asterisk by doxygen1.2.15