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

file.c

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

Generated on Fri Feb 27 12:19:42 2004 for Asterisk by doxygen 1.3.5