Main Page | Alphabetical List | Data Structures | Directories | 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          snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
00718       } else {
00719          postfix = tmp;
00720          prefix="";
00721          snprintf(filename2, sizeof(filename2), "%s/%s", preflang, postfix);
00722       }
00723       res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
00724       if (res < 1) {
00725          char *stringp=NULL;
00726          strncpy(lang2, preflang, sizeof(lang2)-1);
00727          stringp=lang2;
00728          strsep(&stringp, "_");
00729          /* If language is a specific locality of a language (like es_MX), strip the locality and try again */
00730          if (strcmp(lang2, preflang)) {
00731             if (ast_strlen_zero(prefix)) {
00732                snprintf(filename2, sizeof(filename2), "%s/%s", lang2, postfix);
00733             } else {
00734                snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
00735             }
00736             res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
00737          }
00738       }
00739    }
00740 
00741    /* Fallback to no language (usually winds up being American English) */
00742    if (res < 1) {
00743       res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
00744    }
00745    return res;
00746 }
00747 
00748 int ast_filedelete(char *filename, char *fmt)
00749 {
00750    return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
00751 }
00752 
00753 int ast_filerename(char *filename, char *filename2, char *fmt)
00754 {
00755    return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
00756 }
00757 
00758 int ast_filecopy(char *filename, char *filename2, char *fmt)
00759 {
00760    return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
00761 }
00762 
00763 int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang)
00764 {
00765    struct ast_filestream *fs;
00766    struct ast_filestream *vfs;
00767 
00768    fs = ast_openstream(chan, filename, preflang);
00769    vfs = ast_openvstream(chan, filename, preflang);
00770    if (vfs)
00771       ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
00772    if (fs){
00773       if (ast_applystream(chan, fs))
00774          return -1;
00775       if (vfs && ast_applystream(chan, vfs))
00776          return -1;
00777       if (ast_playstream(fs))
00778          return -1;
00779       if (vfs && ast_playstream(vfs))
00780          return -1;
00781 #if 1
00782       if (option_verbose > 2)
00783          ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (language '%s')\n", filename, preflang ? preflang : "default");
00784 #endif
00785       return 0;
00786    }
00787    ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname(chan->nativeformats), strerror(errno));
00788    return -1;
00789 }
00790 
00791 struct ast_filestream *ast_readfile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
00792 {
00793    int fd,myflags = 0;
00794    struct ast_format *f;
00795    struct ast_filestream *fs=NULL;
00796    char *fn;
00797    char *ext;
00798    if (ast_mutex_lock(&formatlock)) {
00799       ast_log(LOG_WARNING, "Unable to lock format list\n");
00800       return NULL;
00801    }
00802    f = formats;
00803    while(f) {
00804       if (exts_compare(f->exts, type)) {
00805          char *stringp=NULL;
00806          /* XXX Implement check XXX */
00807          ext = strdup(f->exts);
00808          stringp=ext;
00809          ext = strsep(&stringp, "|");
00810          fn = build_filename(filename, ext);
00811          fd = open(fn, flags | myflags);
00812          if (fd >= 0) {
00813             errno = 0;
00814             if ((fs = f->open(fd))) {
00815                fs->trans = NULL;
00816                fs->fmt = f;
00817                fs->flags = flags;
00818                fs->mode = mode;
00819                fs->filename = strdup(filename);
00820                fs->vfs = NULL;
00821             } else {
00822                ast_log(LOG_WARNING, "Unable to open %s\n", fn);
00823                close(fd);
00824                unlink(fn);
00825             }
00826          } else if (errno != EEXIST)
00827             ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
00828          free(fn);
00829          free(ext);
00830          break;
00831       }
00832       f = f->next;
00833    }
00834    ast_mutex_unlock(&formatlock);
00835    if (!f) 
00836       ast_log(LOG_WARNING, "No such format '%s'\n", type);
00837    return fs;
00838 }
00839 
00840 struct ast_filestream *ast_writefile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
00841 {
00842    int fd,myflags = 0;
00843    struct ast_format *f;
00844    struct ast_filestream *fs=NULL;
00845    char *fn,*orig_fn=NULL;
00846    char *ext;
00847    char *buf=NULL;
00848    size_t size = 0;
00849 
00850    if (ast_mutex_lock(&formatlock)) {
00851       ast_log(LOG_WARNING, "Unable to lock format list\n");
00852       return NULL;
00853    }
00854    /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
00855    if (flags & O_APPEND){ 
00856       /* We really can't use O_APPEND as it will break WAV header updates */
00857       flags &= ~O_APPEND;
00858    }else{
00859       myflags = O_TRUNC;
00860    }
00861    
00862    myflags |= O_WRONLY | O_CREAT;
00863 
00864    f = formats;
00865    while(f) {
00866       if (exts_compare(f->exts, type)) {
00867          char *stringp=NULL;
00868          /* XXX Implement check XXX */
00869          ext = ast_strdupa(f->exts);
00870          stringp=ext;
00871          ext = strsep(&stringp, "|");
00872          fn = build_filename(filename, ext);
00873          fd = open(fn, flags | myflags, mode);
00874 
00875          if (option_cache_record_files && fd >= 0) {
00876             close(fd);
00877             /*
00878                We touch orig_fn just as a place-holder so other things (like vmail) see the file is there.
00879                What we are really doing is writing to record_cache_dir until we are done then we will mv the file into place.
00880             */
00881             orig_fn = ast_strdupa(fn); 
00882             for (size=0;size<strlen(fn);size++) {
00883                if (fn[size] == '/')
00884                   fn[size] = '_';
00885             }
00886 
00887             size += (strlen(record_cache_dir) + 10);
00888             buf = alloca(size);
00889             memset(buf, 0, size);
00890             snprintf(buf, size, "%s/%s", record_cache_dir, fn);
00891             free(fn);
00892             fn=buf;
00893             fd = open(fn, flags | myflags, mode);
00894          }
00895          if (fd >= 0) {
00896             errno = 0;
00897             if ((fs = f->rewrite(fd, comment))) {
00898                fs->trans = NULL;
00899                fs->fmt = f;
00900                fs->flags = flags;
00901                fs->mode = mode;
00902                if (option_cache_record_files) {
00903                   fs->realfilename = build_filename(filename, ext);
00904                   fs->filename = strdup(fn);
00905                } else {
00906                   fs->realfilename = NULL;
00907                   fs->filename = strdup(filename);
00908                }
00909                fs->vfs = NULL;
00910             } else {
00911                ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
00912                close(fd);
00913                unlink(fn);
00914                if (orig_fn)
00915                   unlink(orig_fn);
00916             }
00917          } else if (errno != EEXIST) {
00918             ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
00919             if (orig_fn)
00920                unlink(orig_fn);
00921          }
00922          if (!buf) /* if buf != NULL then fn is already free and pointing to it */
00923             free(fn);
00924 
00925          break;
00926       }
00927       f = f->next;
00928    }
00929    ast_mutex_unlock(&formatlock);
00930    if (!f) 
00931       ast_log(LOG_WARNING, "No such format '%s'\n", type);
00932    return fs;
00933 }
00934 
00935 int ast_waitstream(struct ast_channel *c, char *breakon)
00936 {
00937    /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
00938    int res;
00939    struct ast_frame *fr;
00940    if (!breakon) breakon = "";
00941    while(c->stream) {
00942       res = ast_sched_wait(c->sched);
00943       if ((res < 0) && !c->timingfunc) {
00944          ast_stopstream(c);
00945          break;
00946       }
00947       if (res < 0)
00948          res = 1000;
00949       res = ast_waitfor(c, res);
00950       if (res < 0) {
00951          ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
00952          return res;
00953       } else if (res > 0) {
00954          fr = ast_read(c);
00955          if (!fr) {
00956 #if 0
00957             ast_log(LOG_DEBUG, "Got hung up\n");
00958 #endif
00959             return -1;
00960          }
00961          
00962          switch(fr->frametype) {
00963          case AST_FRAME_DTMF:
00964             res = fr->subclass;
00965             if (strchr(breakon, res)) {
00966                ast_frfree(fr);
00967                return res;
00968             }
00969             break;
00970          case AST_FRAME_CONTROL:
00971             switch(fr->subclass) {
00972             case AST_CONTROL_HANGUP:
00973                ast_frfree(fr);
00974                return -1;
00975             case AST_CONTROL_RINGING:
00976             case AST_CONTROL_ANSWER:
00977                /* Unimportant */
00978                break;
00979             default:
00980                ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
00981             }
00982          }
00983          /* Ignore */
00984          ast_frfree(fr);
00985       }
00986       ast_sched_runq(c->sched);
00987    }
00988    return (c->_softhangup ? -1 : 0);
00989 }
00990 
00991 int ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char *rewind, int ms)
00992 {
00993    int res;
00994    struct ast_frame *fr;
00995 
00996    if (!breakon)
00997          breakon = "";
00998    if (!forward)
00999          forward = "";
01000    if (!rewind)
01001          rewind = "";
01002    
01003    while(c->stream) {
01004       res = ast_sched_wait(c->sched);
01005       if ((res < 0) && !c->timingfunc) {
01006          ast_stopstream(c);
01007          break;
01008       }
01009       if (res < 0)
01010          res = 1000;
01011       res = ast_waitfor(c, res);
01012       if (res < 0) {
01013          ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
01014          return res;
01015       } else
01016       if (res > 0) {
01017          fr = ast_read(c);
01018          if (!fr) {
01019 #if 0
01020             ast_log(LOG_DEBUG, "Got hung up\n");
01021 #endif
01022             return -1;
01023          }
01024          
01025          switch(fr->frametype) {
01026          case AST_FRAME_DTMF:
01027             res = fr->subclass;
01028             if (strchr(forward,res)) {
01029                ast_stream_fastforward(c->stream, ms);
01030             } else if (strchr(rewind,res)) {
01031                ast_stream_rewind(c->stream, ms);
01032             } else if (strchr(breakon, res)) {
01033                ast_frfree(fr);
01034                return res;
01035             }              
01036             break;
01037          case AST_FRAME_CONTROL:
01038             switch(fr->subclass) {
01039             case AST_CONTROL_HANGUP:
01040                ast_frfree(fr);
01041                return -1;
01042             case AST_CONTROL_RINGING:
01043             case AST_CONTROL_ANSWER:
01044                /* Unimportant */
01045                break;
01046             default:
01047                ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01048             }
01049          }
01050          /* Ignore */
01051          ast_frfree(fr);
01052       } else
01053          ast_sched_runq(c->sched);
01054    
01055       
01056    }
01057    return (c->_softhangup ? -1 : 0);
01058 }
01059 
01060 int ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int cmdfd)
01061 {
01062    int res;
01063    int ms;
01064    int outfd;
01065    struct ast_frame *fr;
01066    struct ast_channel *rchan;
01067 
01068    if (!breakon)
01069       breakon = "";
01070    
01071    while(c->stream) {
01072       ms = ast_sched_wait(c->sched);
01073       if ((ms < 0) && !c->timingfunc) {
01074          ast_stopstream(c);
01075          break;
01076       }
01077       if (ms < 0)
01078          ms = 1000;
01079       rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
01080       if (!rchan && (outfd < 0) && (ms)) {
01081          /* Continue */
01082          if (errno == EINTR)
01083             continue;
01084          ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
01085          return -1;
01086       } else if (outfd > -1) {
01087          /* The FD we were watching has something waiting */
01088          return 1;
01089       } else if (rchan) {
01090          fr = ast_read(c);
01091          if (!fr) {
01092 #if 0
01093             ast_log(LOG_DEBUG, "Got hung up\n");
01094 #endif
01095             return -1;
01096          }
01097          
01098          switch(fr->frametype) {
01099          case AST_FRAME_DTMF:
01100             res = fr->subclass;
01101             if (strchr(breakon, res)) {
01102                ast_frfree(fr);
01103                return res;
01104             }
01105             break;
01106          case AST_FRAME_CONTROL:
01107             switch(fr->subclass) {
01108             case AST_CONTROL_HANGUP:
01109                ast_frfree(fr);
01110                return -1;
01111             case AST_CONTROL_RINGING:
01112             case AST_CONTROL_ANSWER:
01113                /* Unimportant */
01114                break;
01115             default:
01116                ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01117             }
01118          case AST_FRAME_VOICE:
01119             /* Write audio if appropriate */
01120             if (audiofd > -1)
01121                write(audiofd, fr->data, fr->datalen);
01122          }
01123          /* Ignore */
01124          ast_frfree(fr);
01125       }
01126       ast_sched_runq(c->sched);
01127    
01128       
01129    }
01130    return (c->_softhangup ? -1 : 0);
01131 }
01132 
01133 static int show_file_formats(int fd, int argc, char *argv[])
01134 {
01135 #define FORMAT "%-10s %-10s %-20s\n"
01136 #define FORMAT2 "%-10s %-10s %-20s\n"
01137    struct ast_format *f;
01138    if (argc != 3)
01139       return RESULT_SHOWUSAGE;
01140    ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
01141            
01142    if (ast_mutex_lock(&formatlock)) {
01143       ast_log(LOG_WARNING, "Unable to lock format list\n");
01144       return -1;
01145    }
01146 
01147    f = formats;
01148    while(f) {
01149       ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
01150       f = f->next;
01151    };
01152    ast_mutex_unlock(&formatlock);
01153    return RESULT_SUCCESS;
01154 }
01155 
01156 struct ast_cli_entry show_file =
01157 {
01158    { "show", "file", "formats" },
01159    show_file_formats,
01160    "Displays file formats",
01161    "Usage: show file formats\n"
01162    "       displays currently registered file formats (if any)\n"
01163 };
01164 
01165 int ast_file_init(void)
01166 {
01167    ast_cli_register(&show_file);
01168    return 0;
01169 }

Generated on Wed Aug 10 11:36:32 2005 for Asterisk by  doxygen 1.4.4