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 static int exts_compare(char *exts, char *type)
00291 {
00292    char *stringp = NULL, *ext;
00293    char tmp[256];
00294 
00295    strncpy(tmp, exts, sizeof(tmp) - 1);
00296    stringp = tmp;
00297    while ((ext = strsep(&stringp, "|"))) {
00298       if (!strcmp(ext, type)) {
00299          return 1;
00300       }
00301    }
00302 
00303    return 0;
00304 }
00305 
00306 #define ACTION_EXISTS 1
00307 #define ACTION_DELETE 2
00308 #define ACTION_RENAME 3
00309 #define ACTION_OPEN   4
00310 #define ACTION_COPY   5
00311 
00312 static int ast_filehelper(char *filename, char *filename2, char *fmt, int action)
00313 {
00314    struct stat st;
00315    struct ast_format *f;
00316    struct ast_filestream *s;
00317    int res=0, ret = 0;
00318    char *ext=NULL, *exts, *fn, *nfn;
00319    struct ast_channel *chan = (struct ast_channel *)filename2;
00320    
00321    /* Start with negative response */
00322    if (action == ACTION_EXISTS)
00323       res = 0;
00324    else
00325       res = -1;
00326    if (action == ACTION_OPEN)
00327       ret = -1;
00328    /* Check for a specific format */
00329    if (ast_mutex_lock(&formatlock)) {
00330       ast_log(LOG_WARNING, "Unable to lock format list\n");
00331       if (action == ACTION_EXISTS)
00332          return 0;
00333       else
00334          return -1;
00335    }
00336    f = formats;
00337    while(f) {
00338       if (!fmt || exts_compare(f->exts, fmt)) {
00339          char *stringp=NULL;
00340          exts = strdup(f->exts);
00341          /* Try each kind of extension */
00342          stringp=exts;
00343          ext = strsep(&stringp, "|");
00344          do {
00345             fn = build_filename(filename, ext);
00346             if (fn) {
00347                res = stat(fn, &st);
00348                if (!res) {
00349                   switch(action) {
00350                   case ACTION_EXISTS:
00351                      ret |= f->format;
00352                      break;
00353                   case ACTION_DELETE:
00354                      res = unlink(fn);
00355                      if (res)
00356                         ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
00357                      break;
00358                   case ACTION_RENAME:
00359                      nfn = build_filename(filename2, ext);
00360                      if (nfn) {
00361                         res = rename(fn, nfn);
00362                         if (res)
00363                            ast_log(LOG_WARNING, "rename(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
00364                         free(nfn);
00365                      } else
00366                         ast_log(LOG_WARNING, "Out of memory\n");
00367                      break;
00368                   case ACTION_COPY:
00369                      nfn = build_filename(filename2, ext);
00370                      if (nfn) {
00371                         res = copy(fn, nfn);
00372                         if (res)
00373                            ast_log(LOG_WARNING, "copy(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
00374                         free(nfn);
00375                      } else
00376                         ast_log(LOG_WARNING, "Out of memory\n");
00377                      break;
00378                   case ACTION_OPEN:
00379                      if ((ret < 0) && ((chan->writeformat & f->format) ||
00380                               ((f->format >= AST_FORMAT_MAX_AUDIO) && fmt))) {
00381                         ret = open(fn, O_RDONLY);
00382                         if (ret >= 0) {
00383                            s = f->open(ret);
00384                            if (s) {
00385                               s->lasttimeout = -1;
00386                               s->fmt = f;
00387                               s->trans = NULL;
00388                               s->filename = NULL;
00389                               if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
00390                                  chan->stream = s;
00391                               else
00392                                  chan->vstream = s;
00393                            } else {
00394                               close(ret);
00395                               ast_log(LOG_WARNING, "Unable to open fd on %s\n", fn);
00396                            }
00397                         } else
00398                            ast_log(LOG_WARNING, "Couldn't open file %s\n", fn);
00399                      }
00400                      break;
00401                   default:
00402                      ast_log(LOG_WARNING, "Unknown helper %d\n", action);
00403                   }
00404                   /* Conveniently this logic is the same for all */
00405                   if (res)
00406                      break;
00407                }
00408                free(fn);
00409             }
00410             ext = strsep(&stringp, "|");
00411          } while(ext);
00412          free(exts);
00413       }
00414       f = f->next;
00415    }
00416    ast_mutex_unlock(&formatlock);
00417    if ((action == ACTION_EXISTS) || (action == ACTION_OPEN))
00418       res = ret ? ret : -1;
00419    return res;
00420 }
00421 
00422 struct ast_filestream *ast_openstream(struct ast_channel *chan, char *filename, char *preflang)
00423 {
00424    /* This is a fairly complex routine.  Essentially we should do 
00425       the following:
00426       
00427       1) Find which file handlers produce our type of format.
00428       2) Look for a filename which it can handle.
00429       3) If we find one, then great.  
00430       4) If not, see what files are there
00431       5) See what we can actually support
00432       6) Choose the one with the least costly translator path and
00433           set it up.
00434          
00435    */
00436    int fd = -1;
00437    int fmts = -1;
00438    char filename2[256]="";
00439    char filename3[256]="";
00440    char *endpart;
00441    int res;
00442    ast_stopstream(chan);
00443    /* do this first, otherwise we detect the wrong writeformat */
00444    if (chan->generator)
00445       ast_deactivate_generator(chan);
00446    if (preflang && strlen(preflang)) {
00447       strncpy(filename3, filename, sizeof(filename3) - 1);
00448       endpart = strrchr(filename3, '/');
00449       if (endpart) {
00450          *endpart = '\0';
00451          endpart++;
00452          snprintf(filename2, sizeof(filename2), "%s/%s/%s", filename3, preflang, endpart);
00453       } else
00454          snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
00455       fmts = ast_fileexists(filename2, NULL, NULL);
00456    }
00457    if (fmts < 1) {
00458       strncpy(filename2, filename, sizeof(filename2)-1);
00459       fmts = ast_fileexists(filename2, NULL, NULL);
00460    }
00461    if (fmts < 1) {
00462       ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
00463       return NULL;
00464    }
00465    chan->oldwriteformat = chan->writeformat;
00466    /* Set the channel to a format we can work with */
00467    res = ast_set_write_format(chan, fmts);
00468    
00469    fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
00470    if(fd >= 0)
00471       return chan->stream;
00472    return NULL;
00473 }
00474 
00475 struct ast_filestream *ast_openvstream(struct ast_channel *chan, char *filename, char *preflang)
00476 {
00477    /* This is a fairly complex routine.  Essentially we should do 
00478       the following:
00479       
00480       1) Find which file handlers produce our type of format.
00481       2) Look for a filename which it can handle.
00482       3) If we find one, then great.  
00483       4) If not, see what files are there
00484       5) See what we can actually support
00485       6) Choose the one with the least costly translator path and
00486           set it up.
00487          
00488    */
00489    int fd = -1;
00490    int fmts = -1;
00491    char filename2[256];
00492    char lang2[MAX_LANGUAGE];
00493    /* XXX H.263 only XXX */
00494    char *fmt = "h263";
00495    if (preflang && strlen(preflang)) {
00496       snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
00497       fmts = ast_fileexists(filename2, fmt, NULL);
00498       if (fmts < 1) {
00499          strncpy(lang2, preflang, sizeof(lang2)-1);
00500          snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
00501          fmts = ast_fileexists(filename2, fmt, NULL);
00502       }
00503    }
00504    if (fmts < 1) {
00505       strncpy(filename2, filename, sizeof(filename2)-1);
00506       fmts = ast_fileexists(filename2, fmt, NULL);
00507    }
00508    if (fmts < 1) {
00509       return NULL;
00510    }
00511    fd = ast_filehelper(filename2, (char *)chan, fmt, ACTION_OPEN);
00512    if(fd >= 0)
00513       return chan->vstream;
00514    ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
00515    return NULL;
00516 }
00517 
00518 struct ast_frame *ast_readframe(struct ast_filestream *s)
00519 {
00520    struct ast_frame *f = NULL;
00521    int whennext = 0; 
00522    if (s && s->fmt)
00523       f = s->fmt->read(s, &whennext);
00524    return f;
00525 }
00526 
00527 static int ast_readaudio_callback(void *data)
00528 {
00529    struct ast_filestream *s = data;
00530    struct ast_frame *fr;
00531    int whennext = 0;
00532 
00533    while(!whennext) {
00534       fr = s->fmt->read(s, &whennext);
00535       if (fr) {
00536          if (ast_write(s->owner, fr)) {
00537             ast_log(LOG_WARNING, "Failed to write frame\n");
00538             s->owner->streamid = -1;
00539 #ifdef ZAPTEL_OPTIMIZATIONS
00540             ast_settimeout(s->owner, 0, NULL, NULL);
00541 #endif         
00542             return 0;
00543          }
00544       } else {
00545          /* Stream has finished */
00546          s->owner->streamid = -1;
00547 #ifdef ZAPTEL_OPTIMIZATIONS
00548          ast_settimeout(s->owner, 0, NULL, NULL);
00549 #endif         
00550          return 0;
00551       }
00552    }
00553    if (whennext != s->lasttimeout) {
00554 #ifdef ZAPTEL_OPTIMIZATIONS
00555       if (s->owner->timingfd > -1)
00556          ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
00557       else
00558 #endif      
00559          s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
00560       s->lasttimeout = whennext;
00561       return 0;
00562    }
00563    return 1;
00564 }
00565 
00566 static int ast_readvideo_callback(void *data)
00567 {
00568    struct ast_filestream *s = data;
00569    struct ast_frame *fr;
00570    int whennext = 0;
00571 
00572    while(!whennext) {
00573       fr = s->fmt->read(s, &whennext);
00574       if (fr) {
00575          if (ast_write(s->owner, fr)) {
00576             ast_log(LOG_WARNING, "Failed to write frame\n");
00577             s->owner->vstreamid = -1;
00578             return 0;
00579          }
00580       } else {
00581          /* Stream has finished */
00582          s->owner->vstreamid = -1;
00583          return 0;
00584       }
00585    }
00586    if (whennext != s->lasttimeout) {
00587       s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
00588       s->lasttimeout = whennext;
00589       return 0;
00590    }
00591    return 1;
00592 }
00593 
00594 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
00595 {
00596    s->owner = chan;
00597    return 0;
00598 }
00599 
00600 int ast_playstream(struct ast_filestream *s)
00601 {
00602    if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
00603       ast_readaudio_callback(s);
00604    else
00605       ast_readvideo_callback(s);
00606    return 0;
00607 }
00608 
00609 int ast_seekstream(struct ast_filestream *fs, long sample_offset, int whence)
00610 {
00611    return fs->fmt->seek(fs, sample_offset, whence);
00612 }
00613 
00614 int ast_truncstream(struct ast_filestream *fs)
00615 {
00616    return fs->fmt->trunc(fs);
00617 }
00618 
00619 long ast_tellstream(struct ast_filestream *fs)
00620 {
00621    return fs->fmt->tell(fs);
00622 }
00623 
00624 int ast_stream_fastforward(struct ast_filestream *fs, long ms)
00625 {
00626    /* I think this is right, 8000 samples per second, 1000 ms a second so 8
00627     * samples per ms  */
00628    long samples = ms * 8;
00629    return ast_seekstream(fs, samples, SEEK_CUR);
00630 }
00631 
00632 int ast_stream_rewind(struct ast_filestream *fs, long ms)
00633 {
00634    long samples = ms * 8;
00635    samples = samples * -1;
00636    return ast_seekstream(fs, samples, SEEK_CUR);
00637 }
00638 
00639 int ast_closestream(struct ast_filestream *f)
00640 {
00641    /* Stop a running stream if there is one */
00642    if (f->owner) {
00643       if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
00644          f->owner->stream = NULL;
00645          if (f->owner->streamid > -1)
00646             ast_sched_del(f->owner->sched, f->owner->streamid);
00647          f->owner->streamid = -1;
00648 #ifdef ZAPTEL_OPTIMIZATIONS
00649          ast_settimeout(f->owner, 0, NULL, NULL);
00650 #endif         
00651       } else {
00652          f->owner->vstream = NULL;
00653          if (f->owner->vstreamid > -1)
00654             ast_sched_del(f->owner->sched, f->owner->vstreamid);
00655          f->owner->vstreamid = -1;
00656       }
00657    }
00658    /* destroy the translator on exit */
00659    if (f->trans) {
00660       ast_translator_free_path(f->trans);
00661       f->trans = NULL;
00662    }
00663    if (f->filename)
00664       free(f->filename);
00665    f->filename = NULL;
00666    f->fmt->close(f);
00667    return 0;
00668 }
00669 
00670 
00671 int ast_fileexists(char *filename, char *fmt, char *preflang)
00672 {
00673    char filename2[256];
00674    char tmp[256];
00675    char *postfix;
00676    char *prefix;
00677    char *c;
00678    char lang2[MAX_LANGUAGE];
00679    int res = -1;
00680    if (preflang && strlen(preflang)) {
00681       /* Insert the language between the last two parts of the path */
00682       strncpy(tmp, filename, sizeof(tmp) - 1);
00683       c = strrchr(tmp, '/');
00684       if (c) {
00685          *c = '\0';
00686          postfix = c+1;
00687          prefix = tmp;
00688       } else {
00689          postfix = tmp;
00690          prefix="";
00691       }
00692       snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
00693       res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
00694       if (res < 1) {
00695          char *stringp=NULL;
00696          strncpy(lang2, preflang, sizeof(lang2)-1);
00697          stringp=lang2;
00698          strsep(&stringp, "_");
00699          if (strcmp(lang2, preflang)) {
00700             snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
00701             res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
00702          }
00703       }
00704    }
00705    if (res < 1) {
00706       res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
00707    }
00708    return res;
00709 }
00710 
00711 int ast_filedelete(char *filename, char *fmt)
00712 {
00713    return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
00714 }
00715 
00716 int ast_filerename(char *filename, char *filename2, char *fmt)
00717 {
00718    return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
00719 }
00720 
00721 int ast_filecopy(char *filename, char *filename2, char *fmt)
00722 {
00723    return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
00724 }
00725 
00726 int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang)
00727 {
00728    struct ast_filestream *fs;
00729    struct ast_filestream *vfs;
00730 
00731    fs = ast_openstream(chan, filename, preflang);
00732    vfs = ast_openvstream(chan, filename, preflang);
00733    if (vfs)
00734       ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
00735    if(fs){
00736       if(ast_applystream(chan, fs))
00737          return -1;
00738       if(vfs && ast_applystream(chan, vfs))
00739          return -1;
00740       if(ast_playstream(fs))
00741          return -1;
00742       if(vfs && ast_playstream(vfs))
00743          return -1;
00744 #if 1
00745       if (option_verbose > 2)
00746          ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (language '%s')\n", filename, preflang ? preflang : "default");
00747 #endif
00748       return 0;
00749    }
00750    ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname(chan->nativeformats), strerror(errno));
00751    return -1;
00752 }
00753 
00754 struct ast_filestream *ast_readfile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
00755 {
00756    int fd,myflags = 0;
00757    struct ast_format *f;
00758    struct ast_filestream *fs=NULL;
00759    char *fn;
00760    char *ext;
00761    if (ast_mutex_lock(&formatlock)) {
00762       ast_log(LOG_WARNING, "Unable to lock format list\n");
00763       return NULL;
00764    }
00765    f = formats;
00766    while(f) {
00767       if (exts_compare(f->exts, type)) {
00768          char *stringp=NULL;
00769          /* XXX Implement check XXX */
00770          ext = strdup(f->exts);
00771          stringp=ext;
00772          ext = strsep(&stringp, "|");
00773          fn = build_filename(filename, ext);
00774          fd = open(fn, flags | myflags);
00775          if (fd >= 0) {
00776             errno = 0;
00777             if ((fs = f->open(fd))) {
00778                fs->trans = NULL;
00779                fs->fmt = f;
00780                fs->flags = flags;
00781                fs->mode = mode;
00782                fs->filename = strdup(filename);
00783                fs->vfs = NULL;
00784             } else {
00785                ast_log(LOG_WARNING, "Unable to open %s\n", fn);
00786                close(fd);
00787                unlink(fn);
00788             }
00789          } else if (errno != EEXIST)
00790             ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
00791          free(fn);
00792          free(ext);
00793          break;
00794       }
00795       f = f->next;
00796    }
00797    ast_mutex_unlock(&formatlock);
00798    if (!f) 
00799       ast_log(LOG_WARNING, "No such format '%s'\n", type);
00800    return fs;
00801 }
00802 
00803 struct ast_filestream *ast_writefile(char *filename, char *type, char *comment, int flags, int check, mode_t mode)
00804 {
00805    int fd,myflags = 0;
00806    struct ast_format *f;
00807    struct ast_filestream *fs=NULL;
00808    char *fn;
00809    char *ext;
00810    if (ast_mutex_lock(&formatlock)) {
00811       ast_log(LOG_WARNING, "Unable to lock format list\n");
00812       return NULL;
00813    }
00814    /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
00815    if (!(flags & O_APPEND)) 
00816       myflags = O_TRUNC;
00817    
00818    myflags |= O_WRONLY | O_CREAT;
00819 
00820    f = formats;
00821    while(f) {
00822       if (exts_compare(f->exts, type)) {
00823          char *stringp=NULL;
00824          /* XXX Implement check XXX */
00825          ext = strdup(f->exts);
00826          stringp=ext;
00827          ext = strsep(&stringp, "|");
00828          fn = build_filename(filename, ext);
00829          fd = open(fn, flags | myflags, mode);
00830          if (fd >= 0) {
00831             errno = 0;
00832             if ((fs = f->rewrite(fd, comment))) {
00833                fs->trans = NULL;
00834                fs->fmt = f;
00835                fs->flags = flags;
00836                fs->mode = mode;
00837                fs->filename = strdup(filename);
00838                fs->vfs = NULL;
00839             } else {
00840                ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
00841                close(fd);
00842                unlink(fn);
00843             }
00844          } else if (errno != EEXIST)
00845             ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
00846          free(fn);
00847          free(ext);
00848          break;
00849       }
00850       f = f->next;
00851    }
00852    ast_mutex_unlock(&formatlock);
00853    if (!f) 
00854       ast_log(LOG_WARNING, "No such format '%s'\n", type);
00855    return fs;
00856 }
00857 
00858 char ast_waitstream(struct ast_channel *c, char *breakon)
00859 {
00860    /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
00861    int res;
00862    struct ast_frame *fr;
00863    while(c->stream) {
00864       res = ast_sched_wait(c->sched);
00865       if ((res < 0) && !c->timingfunc) {
00866          ast_stopstream(c);
00867          break;
00868       }
00869       if (res < 0)
00870          res = 1000;
00871       res = ast_waitfor(c, res);
00872       if (res < 0) {
00873          ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
00874          return res;
00875       } else if (res > 0) {
00876          fr = ast_read(c);
00877          if (!fr) {
00878 #if 0
00879             ast_log(LOG_DEBUG, "Got hung up\n");
00880 #endif
00881             return -1;
00882          }
00883          
00884          switch(fr->frametype) {
00885          case AST_FRAME_DTMF:
00886             res = fr->subclass;
00887             if (strchr(breakon, res)) {
00888                ast_frfree(fr);
00889                return res;
00890             }
00891             break;
00892          case AST_FRAME_CONTROL:
00893             switch(fr->subclass) {
00894             case AST_CONTROL_HANGUP:
00895                ast_frfree(fr);
00896                return -1;
00897             case AST_CONTROL_RINGING:
00898             case AST_CONTROL_ANSWER:
00899                /* Unimportant */
00900                break;
00901             default:
00902                ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
00903             }
00904          }
00905          /* Ignore */
00906          ast_frfree(fr);
00907       }
00908       ast_sched_runq(c->sched);
00909    }
00910    return (c->_softhangup ? -1 : 0);
00911 }
00912 
00913 char ast_waitstream_fr(struct ast_channel *c, char *breakon, char *forward, char *rewind, int ms)
00914 {
00915    int res;
00916    struct ast_frame *fr;
00917    while(c->stream) {
00918       res = ast_sched_wait(c->sched);
00919       if ((res < 0) && !c->timingfunc) {
00920          ast_stopstream(c);
00921          break;
00922       }
00923       if (res < 0)
00924          res = 1000;
00925       res = ast_waitfor(c, res);
00926       if (res < 0) {
00927          ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
00928          return res;
00929       } else
00930       if (res > 0) {
00931          fr = ast_read(c);
00932          if (!fr) {
00933 #if 0
00934             ast_log(LOG_DEBUG, "Got hung up\n");
00935 #endif
00936             return -1;
00937          }
00938          
00939          switch(fr->frametype) {
00940          case AST_FRAME_DTMF:
00941             res = fr->subclass;
00942             if (strchr(forward,res)) {
00943                ast_stream_fastforward(c->stream, ms);
00944             } else if (strchr(rewind,res)) {
00945                ast_stream_rewind(c->stream, ms);
00946             } else if (strchr(breakon, res)) {
00947                ast_frfree(fr);
00948                return res;
00949             }              
00950             break;
00951          case AST_FRAME_CONTROL:
00952             switch(fr->subclass) {
00953             case AST_CONTROL_HANGUP:
00954                ast_frfree(fr);
00955                return -1;
00956             case AST_CONTROL_RINGING:
00957             case AST_CONTROL_ANSWER:
00958                /* Unimportant */
00959                break;
00960             default:
00961                ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
00962             }
00963          }
00964          /* Ignore */
00965          ast_frfree(fr);
00966       } else
00967          ast_sched_runq(c->sched);
00968    
00969       
00970    }
00971    return (c->_softhangup ? -1 : 0);
00972 }
00973 
00974 char ast_waitstream_full(struct ast_channel *c, char *breakon, int audiofd, int cmdfd)
00975 {
00976    int res;
00977    int ms;
00978    int outfd;
00979    struct ast_frame *fr;
00980    struct ast_channel *rchan;
00981    
00982    while(c->stream) {
00983       ms = ast_sched_wait(c->sched);
00984       if ((ms < 0) && !c->timingfunc) {
00985          ast_stopstream(c);
00986          break;
00987       }
00988       if (ms < 0)
00989          ms = 1000;
00990       rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
00991       if (!rchan && (outfd < 0) && (ms)) {
00992          ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
00993          return -1;
00994       } else if (outfd > -1) {
00995          /* The FD we were watching has something waiting */
00996          return 1;
00997       } else if (rchan) {
00998          fr = ast_read(c);
00999          if (!fr) {
01000 #if 0
01001             ast_log(LOG_DEBUG, "Got hung up\n");
01002 #endif
01003             return -1;
01004          }
01005          
01006          switch(fr->frametype) {
01007          case AST_FRAME_DTMF:
01008             res = fr->subclass;
01009             if (strchr(breakon, res)) {
01010                ast_frfree(fr);
01011                return res;
01012             }
01013             break;
01014          case AST_FRAME_CONTROL:
01015             switch(fr->subclass) {
01016             case AST_CONTROL_HANGUP:
01017                ast_frfree(fr);
01018                return -1;
01019             case AST_CONTROL_RINGING:
01020             case AST_CONTROL_ANSWER:
01021                /* Unimportant */
01022                break;
01023             default:
01024                ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01025             }
01026          case AST_FRAME_VOICE:
01027             /* Write audio if appropriate */
01028             if (audiofd > -1)
01029                write(audiofd, fr->data, fr->datalen);
01030          }
01031          /* Ignore */
01032          ast_frfree(fr);
01033       }
01034       ast_sched_runq(c->sched);
01035    
01036       
01037    }
01038    return (c->_softhangup ? -1 : 0);
01039 }

Generated on Sun Apr 18 23:33:51 2004 for Asterisk by doxygen 1.3.6-20040222