Largely simplify format handlers (for file copy etc.)
authorLuigi Rizzo <rizzo@icir.org>
Tue, 4 Apr 2006 12:59:25 +0000 (12:59 +0000)
committerLuigi Rizzo <rizzo@icir.org>
Tue, 4 Apr 2006 12:59:25 +0000 (12:59 +0000)
collecting common functions in a single place and removing
them from the individual handlers.
The full description is on mantis,
http://bugs.digium.com/view.php?id=6375
and only the ogg_vorbis handler needs to be converted to
the new structure.

As a result of this change, format_au.c and format_pcm_alaw.c
should go away (in a separate commit) as their functionality
(trivial) has been merged in another file.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@17243 65c4cc65-6c06-0410-ace0-fbb531ad65f3

18 files changed:
file.c
formats/Makefile
formats/format_au.c
formats/format_g723.c
formats/format_g726.c
formats/format_g729.c
formats/format_gsm.c
formats/format_h263.c
formats/format_h264.c
formats/format_ilbc.c
formats/format_ogg_vorbis.c
formats/format_pcm.c
formats/format_pcm_alaw.c
formats/format_sln.c
formats/format_vox.c
formats/format_wav.c
formats/format_wav_gsm.c
include/asterisk/file.h

diff --git a/file.c b/file.c
index 9e3db7b..6dbd81f 100644 (file)
--- a/file.c
+++ b/file.c
@@ -51,100 +51,65 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/app.h"
 #include "asterisk/pbx.h"
 #include "asterisk/linkedlists.h"
+#include "asterisk/module.h"   /* ast_update_use_count() */
 
-struct ast_format {
-       /*! Name of format */
-       char name[80];
-       /*! Extensions (separated by | if more than one) 
-           this format can read.  First is assumed for writing (e.g. .mp3) */
-       char exts[80];
-       /*! Format of frames it uses/provides (one only) */
-       int format;
-       /*! Open an input stream, and start playback */
-       struct ast_filestream * (*open)(FILE * f);
-       /*! Open an output stream, of a given file descriptor and comment it appropriately if applicable */
-       struct ast_filestream * (*rewrite)(FILE *f, const char *comment);
-       /*! Write a frame to a channel */
-       int (*write)(struct ast_filestream *, struct ast_frame *);
-       /*! seek num samples into file, whence(think normal seek) */
-       int (*seek)(struct ast_filestream *, off_t offset, int whence);
-       /*! trunc file to current position */
-       int (*trunc)(struct ast_filestream *fs);
-       /*! tell current position */
-       off_t (*tell)(struct ast_filestream *fs);
-       /*! Read the next frame from the filestream (if available) and report when to get next one
-               (in samples) */
-       struct ast_frame * (*read)(struct ast_filestream *, int *whennext);
-       /*! Close file, and destroy filestream structure */
-       void (*close)(struct ast_filestream *);
-       /*! Retrieve file comment */
-       char * (*getcomment)(struct ast_filestream *);
-       /*! Link */
-       AST_LIST_ENTRY(ast_format) list;
-};
-
-struct ast_filestream {
-       /*! Everybody reserves a block of AST_RESERVED_POINTERS pointers for us */
-       struct ast_format *fmt;
-       int flags;
-       mode_t mode;
-       char *filename;
-       char *realfilename;
-       /*! Video file stream */
-       struct ast_filestream *vfs;
-       /*! Transparently translate from another format -- just once */
-       struct ast_trans_pvt *trans;
-       struct ast_tranlator_pvt *tr;
-       int lastwriteformat;
-       int lasttimeout;
-       struct ast_channel *owner;
-};
+/*
+ * The following variable controls the layout of localized sound files.
+ * If 0, use the historical layout with prefix just before the filename
+ * (i.e. digits/en/1.gsm , digits/it/1.gsm or default to digits/1.gsm),
+ * if 1 put the prefix at the beginning of the filename
+ * (i.e. en/digits/1.gsm, it/digits/1.gsm or default to digits/1.gsm).
+ * The latter permits a language to be entirely in one directory.
+ */
+int ast_language_is_prefix;
 
 static AST_LIST_HEAD_STATIC(formats, ast_format);
 
-int ast_format_register(const char *name, const char *exts, int format,
-                                               struct ast_filestream * (*open)(FILE *f),
-                                               struct ast_filestream * (*rewrite)(FILE *f, const char *comment),
-                                               int (*write)(struct ast_filestream *, struct ast_frame *),
-                                               int (*seek)(struct ast_filestream *, off_t sample_offset, int whence),
-                                               int (*trunc)(struct ast_filestream *),
-                                               off_t (*tell)(struct ast_filestream *),
-                                               struct ast_frame * (*read)(struct ast_filestream *, int *whennext),
-                                               void (*close)(struct ast_filestream *),
-                                               char * (*getcomment)(struct ast_filestream *))
+int ast_format_register(const struct ast_format *f)
 {
        struct ast_format *tmp;
+
+       if (f->lockp == NULL) {
+               ast_log(LOG_WARNING, "Missing lock pointer, you need to supply one\n");
+               return -1;
+       }
        if (AST_LIST_LOCK(&formats)) {
                ast_log(LOG_WARNING, "Unable to lock format list\n");
                return -1;
        }
        AST_LIST_TRAVERSE(&formats, tmp, list) {
-               if (!strcasecmp(name, tmp->name)) {
+               if (!strcasecmp(f->name, tmp->name)) {
                        AST_LIST_UNLOCK(&formats);
-                       ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", name);
+                       ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", f->name);
                        return -1;
                }
-       }       
-       if (!(tmp = ast_malloc(sizeof(*tmp)))) {
+       }
+       tmp = ast_calloc(1, sizeof(struct ast_format));
+       if (!tmp) {
                AST_LIST_UNLOCK(&formats);
                return -1;
        }
-       ast_copy_string(tmp->name, name, sizeof(tmp->name));
-       ast_copy_string(tmp->exts, exts, sizeof(tmp->exts));
-       tmp->open = open;
-       tmp->rewrite = rewrite;
-       tmp->read = read;
-       tmp->write = write;
-       tmp->seek = seek;
-       tmp->trunc = trunc;
-       tmp->tell = tell;
-       tmp->close = close;
-       tmp->format = format;
-       tmp->getcomment = getcomment;
+       *tmp = *f;
+       if (tmp->buf_size) {
+               /*
+                * Align buf_size properly, rounding up to the machine-specific
+                * alignment for pointers.
+                */
+               struct _test_align { void *a, *b; } p;
+               int align = (char *)&p.b - (char *)&p.a;
+               tmp->buf_size = ((f->buf_size + align - 1)/align)*align;
+       }
+       
+       memset(&tmp->list, 0, sizeof(tmp->list));
+       if (tmp->lockp->usecnt < 0) {
+               ast_mutex_init(&tmp->lockp->lock);
+               tmp->lockp->usecnt = 0;
+       }
+
        AST_LIST_INSERT_HEAD(&formats, tmp, list);
        AST_LIST_UNLOCK(&formats);
        if (option_verbose > 1)
-               ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", name, exts);
+               ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", f->name, f->exts);
        return 0;
 }
 
@@ -169,7 +134,7 @@ int ast_format_unregister(const char *name)
 
        if (tmp) {
                if (option_verbose > 1)
-                               ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
+                       ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
        } else
                ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
 
@@ -189,9 +154,8 @@ int ast_stopstream(struct ast_channel *tmp)
 
 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
 {
-       struct ast_frame *trf;
        int res = -1;
-       int alt=0;
+       int alt = 0;
        if (f->frametype == AST_FRAME_VIDEO) {
                if (fs->fmt->format < AST_FORMAT_MAX_AUDIO) {
                        /* This is the audio portion.  Call the video one... */
@@ -202,7 +166,7 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
                        }
                        if (fs->vfs)
                                return ast_writestream(fs->vfs, f);
-                       /* Ignore */
+                       /* else ignore */
                        return 0;                               
                } else {
                        /* Might / might not have mark set */
@@ -216,23 +180,23 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
                res =  fs->fmt->write(fs, f);
                if (res < 0) 
                        ast_log(LOG_WARNING, "Natural write failed\n");
-               if (res > 0)
+               else if (res > 0)
                        ast_log(LOG_WARNING, "Huh??\n");
-               return res;
        } else {
                /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
                       the one we've setup a translator for, we do the "wrong thing" XXX */
-               if (fs->trans && (f->subclass != fs->lastwriteformat)) {
+               if (fs->trans && f->subclass != fs->lastwriteformat) {
                        ast_translator_free_path(fs->trans);
                        fs->trans = NULL;
                }
                if (!fs->trans) 
                        fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass);
                if (!fs->trans)
-                       ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n", fs->fmt->name, ast_getformatname(f->subclass));
+                       ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n",
+                               fs->fmt->name, ast_getformatname(f->subclass));
                else {
+                       struct ast_frame *trf;
                        fs->lastwriteformat = f->subclass;
-                       res = 0;
                        /* Get the translated frame but don't consume the original in case they're using it on another stream */
                        trf = ast_translate(fs->trans, f, 0);
                        if (trf) {
@@ -242,17 +206,14 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
                        } else
                                res = 0;
                }
-               return res;
        }
+       return res;
 }
 
 static int copy(const char *infile, const char *outfile)
 {
-       int ifd;
-       int ofd;
-       int res;
-       int len;
-       char buf[4096];
+       int ifd, ofd, len;
+       char buf[4096]; /* XXX make it lerger. */
 
        if ((ifd = open(infile, O_RDONLY)) < 0) {
                ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
@@ -263,187 +224,312 @@ static int copy(const char *infile, const char *outfile)
                close(ifd);
                return -1;
        }
-       do {
-               len = read(ifd, buf, sizeof(buf));
+       while ( (len = read(ifd, buf, sizeof(buf)) ) ) {
+               int res;
                if (len < 0) {
                        ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
-                       close(ifd);
-                       close(ofd);
-                       unlink(outfile);
+                       break;
                }
-               if (len) {
-                       res = write(ofd, buf, len);
-                       if (res != len) {
-                               ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
-                               close(ifd);
-                               close(ofd);
-                               unlink(outfile);
-                       }
+               /* XXX handle partial writes */
+               res = write(ofd, buf, len);
+               if (res != len) {
+                       ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
+                       len = -1; /* error marker */
+                       break;
                }
-       } while(len);
+       }
        close(ifd);
        close(ofd);
-       return 0;
+       if (len < 0) {
+               unlink(outfile);
+               return -1; /* error */
+       }
+       return 0;       /* success */
 }
 
+/*!
+ * \brief construct a filename. Absolute pathnames are preserved,
+ * relative names are prefixed by the sounds/ directory.
+ * The wav49 suffix is replaced by 'WAV'.
+ * Returns a malloc'ed string to be freed by the caller.
+ */
 static char *build_filename(const char *filename, const char *ext)
 {
-       char *fn, type[16];
-       int fnsize = 0;
+       char *fn = NULL;
 
-       if (!strcmp(ext, "wav49")) {
-               ast_copy_string(type, "WAV", sizeof(type));
-       } else {
-               ast_copy_string(type, ext, sizeof(type));
-       }
-
-       if (filename[0] == '/') {
-               fnsize = strlen(filename) + strlen(type) + 2;
-               if ((fn = ast_malloc(fnsize)))
-                       snprintf(fn, fnsize, "%s.%s", filename, type);
-       } else {
-               char tmp[AST_CONFIG_MAX_PATH] = "";
-
-               snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_VAR_DIR, "sounds");
-               fnsize = strlen(tmp) + strlen(filename) + strlen(type) + 3;
-               if ((fn = ast_malloc(fnsize)))
-                       snprintf(fn, fnsize, "%s/%s.%s", tmp, filename, type);
-       }
+       if (!strcmp(ext, "wav49"))
+               ext = "WAV";
 
+       if (filename[0] == '/')
+               asprintf(&fn, "%s.%s", filename, ext);
+       else
+               asprintf(&fn, "%s/sounds/%s.%s",
+                       ast_config_AST_VAR_DIR, filename, ext);
        return fn;
 }
 
+/* compare type against the list 'exts' */
+/* XXX need a better algorithm */
 static int exts_compare(const char *exts, const char *type)
 {
-       char *stringp = NULL, *ext;
        char tmp[256];
+       char *stringp = tmp, *ext;
 
        ast_copy_string(tmp, exts, sizeof(tmp));
-       stringp = tmp;
        while ((ext = strsep(&stringp, "|"))) {
-               if (!strcmp(ext, type)) {
+               if (!strcmp(ext, type))
                        return 1;
-               }
        }
 
        return 0;
 }
 
+static struct ast_filestream *get_filestream(struct ast_format *fmt, FILE *bfile)
+{
+       struct ast_filestream *s;
+
+       int l = sizeof(*s) + fmt->buf_size + fmt->desc_size;    /* total allocation size */
+       if ( (s = ast_calloc(1, l)) == NULL)
+               return NULL;
+       s->fmt = fmt;
+       s->f = bfile;
+
+       if (fmt->desc_size)
+               s->private = ((char *)(s+1)) + fmt->buf_size;
+       if (fmt->buf_size)
+               s->buf = (char *)(s+1);
+       s->fr.src = fmt->name;
+       return s;
+}
+
+/*
+ * Default implementations of open and rewrite.
+ * Only use them if you don't have expensive stuff to do.
+ */
+enum wrap_fn { WRAP_OPEN, WRAP_REWRITE };
+
+static int fn_wrapper(struct ast_filestream *s, const char *comment, enum wrap_fn mode)
+{
+       struct ast_format *f = s->fmt;
+       int ret = -1;
+
+       if (mode == WRAP_OPEN && f->open && f->open(s))
+                ast_log(LOG_WARNING, "Unable to open format %s\n", f->name);
+       else if (mode == WRAP_REWRITE && f->rewrite && f->rewrite(s, comment))
+                ast_log(LOG_WARNING, "Unable to rewrite format %s\n", f->name);
+       else {
+               /* preliminary checks succeed. update usecount */
+               if (ast_mutex_lock(&f->lockp->lock)) {
+                       ast_log(LOG_WARNING, "Unable to lock format %s\n", f->name);
+                       return -1;
+               }
+               f->lockp->usecnt++;
+               ast_mutex_unlock(&f->lockp->lock);
+               ret = 0;
+               ast_update_use_count();
+       }
+        return ret;
+}
+
+static int rewrite_wrapper(struct ast_filestream *s, const char *comment)
+{
+       return fn_wrapper(s, comment, WRAP_REWRITE);
+}
+                
+static int open_wrapper(struct ast_filestream *s)
+{
+       return fn_wrapper(s, NULL, WRAP_OPEN);
+}
+
 enum file_action {
-       ACTION_EXISTS = 1,
-       ACTION_DELETE,
-       ACTION_RENAME,
+       ACTION_EXISTS = 1, /* return matching format if file exists, 0 otherwise */
+       ACTION_DELETE,  /* delete file, return 0 on success, -1 on error */
+       ACTION_RENAME,  /* rename file. return 0 on success, -1 on error */
        ACTION_OPEN,
-       ACTION_COPY
+       ACTION_COPY     /* copy file. return 0 on success, -1 on error */
 };
 
-static int ast_filehelper(const char *filename, const char *filename2, const char *fmt, const enum file_action action)
+/*!
+ * \brief perform various actions on a file. Second argument
+ * arg2 depends on the command:
+ *     unused for EXISTS and DELETE
+ *     destination file name (const char *) for COPY and RENAME
+ *     struct ast_channel * for OPEN
+ */
+static int ast_filehelper(const char *filename, const void *arg2, const char *fmt, const enum file_action action)
 {
-       struct stat st;
        struct ast_format *f;
-       struct ast_filestream *s;
-       int res=0, ret = 0;
-       char *ext=NULL, *exts, *fn, *nfn;
-       FILE *bfile;
-       struct ast_channel *chan = (struct ast_channel *)filename2;
-       
-       /* Start with negative response */
-       if (action == ACTION_EXISTS)
-               res = 0;
-       else
-               res = -1;
-       if (action == ACTION_OPEN)
-               ret = -1;
-       /* Check for a specific format */
+       char *ext = NULL, *fn = NULL;
+       int res = (action == ACTION_EXISTS) ? 0 : -1;
+
        if (AST_LIST_LOCK(&formats)) {
                ast_log(LOG_WARNING, "Unable to lock format list\n");
                return res;
        }
+       /* Check for a specific format */
        AST_LIST_TRAVERSE(&formats, f, list) {
-               if (!fmt || exts_compare(f->exts, fmt)) {
-                       char *stringp=NULL;
-                       exts = ast_strdupa(f->exts);
-                       /* Try each kind of extension */
-                       stringp=exts;
-                       ext = strsep(&stringp, "|");
-                       do {
-                               fn = build_filename(filename, ext);
-                               if (fn) {
-                                       res = stat(fn, &st);
-                                       if (!res) {
-                                               switch(action) {
-                                               case ACTION_EXISTS:
-                                                       ret |= f->format;
-                                                       break;
-                                               case ACTION_DELETE:
-                                                       res = unlink(fn);
-                                                       if (res)
-                                                               ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
-                                                       break;
-                                               case ACTION_RENAME:
-                                                       nfn = build_filename(filename2, ext);
-                                                       if (nfn) {
-                                                               res = rename(fn, nfn);
-                                                               if (res)
-                                                                       ast_log(LOG_WARNING, "rename(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
-                                                               free(nfn);
-                                                       }
-                                                       break;
-                                               case ACTION_COPY:
-                                                       nfn = build_filename(filename2, ext);
-                                                       if (nfn) {
-                                                               res = copy(fn, nfn);
-                                                               if (res)
-                                                                       ast_log(LOG_WARNING, "copy(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
-                                                               free(nfn);
-                                                       }
-                                                       break;
-                                               case ACTION_OPEN:
-                                                       if ((ret < 0) && ((chan->writeformat & f->format) ||
-                                                                               ((f->format >= AST_FORMAT_MAX_AUDIO) && fmt))) {
-                                                               bfile = fopen(fn, "r");
-                                                               if (bfile) {
-                                                                       ret = 1;
-                                                                       s = f->open(bfile);
-                                                                       if (s) {
-                                                                               s->lasttimeout = -1;
-                                                                               s->fmt = f;
-                                                                               s->trans = NULL;
-                                                                               s->filename = NULL;
-                                                                               if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
-                                                                                       chan->stream = s;
-                                                                               else
-                                                                                       chan->vstream = s;
-                                                                       } else {
-                                                                               fclose(bfile);
-                                                                               ast_log(LOG_WARNING, "Unable to open file on %s\n", fn);
-                                                                               ret = -1;
-                                                                       }
-                                                               } else{
-                                                                       ast_log(LOG_WARNING, "Couldn't open file %s\n", fn);
-                                                                       ret = -1;
-                                                               }
-                                                       }
-                                                       break;
-                                               default:
-                                                       ast_log(LOG_WARNING, "Unknown helper %d\n", action);
-                                               }
-                                               /* Conveniently this logic is the same for all */
-                                               if (res)
-                                                       break;
-                                       }
+               char *stringp;
+
+               if (fmt && !exts_compare(f->exts, fmt))
+                       continue;
+
+               /* Look for a file matching the supported extensions.
+                * The file must exist, and for OPEN, must match
+                * one of the formats supported by the channel.
+                */
+               stringp = ast_strdupa(f->exts);
+               while ( (ext = strsep(&stringp, "|")) ) {
+                       struct stat st;
+                       fn = build_filename(filename, ext);
+                       if (fn == NULL)
+                               continue;
+
+                       if ( stat(fn, &st) ) { /* file not existent */
+                               free(fn);
+                               continue;
+                       }
+                       /* for 'OPEN' we need to be sure that the format matches
+                        * what the channel can process
+                        */
+                       if (action == ACTION_OPEN) {
+                               struct ast_channel *chan = (struct ast_channel *)arg2;
+                               FILE *bfile;
+                               struct ast_filestream *s;
+
+                               if ( !(chan->writeformat & f->format) &&
+                                    !(f->format >= AST_FORMAT_MAX_AUDIO && fmt)) {
                                        free(fn);
+                                       continue;       /* not a supported format */
+                               }
+                               if ( (bfile = fopen(fn, "r")) == NULL) {
+                                       free(fn);
+                                       continue;       /* cannot open file */
+                               }
+                               s = get_filestream(f, bfile);
+                               if (!s) {
+                                       fclose(bfile);
+                                       free(fn);       /* cannot allocate descriptor */
+                                       continue;
                                }
-                               ext = strsep(&stringp, "|");
-                       } while(ext);
-                       
+                               if (open_wrapper(s)) {
+                                       fclose(bfile);
+                                       free(fn);
+                                       free(s);
+                                       continue;       /* cannot run open on file */
+                               }
+                               /* ok this is good for OPEN */
+                               res = 1;        /* found */
+                               s->lasttimeout = -1;
+                               s->fmt = f;
+                               s->trans = NULL;
+                               s->filename = NULL;
+                               if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
+                                       chan->stream = s;
+                               else
+                                       chan->vstream = s;
+                       }
+                       break;  /* found the file */
                }
+               if (ext)
+                       break;
+       }
+       if (ext) {      /* break out on a valid 'ext', so fn is also valid */
+               char *nfn;
+
+               switch (action) {
+               case ACTION_EXISTS:     /* return the matching format */
+                       res |= f->format;
+                       break;
+
+               case ACTION_DELETE:
+                       if ( (res = unlink(fn)) )
+                               ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
+                       break;
+               case ACTION_RENAME:
+               case ACTION_COPY:
+                       nfn = build_filename((const char *)arg2, ext);
+                       if (!nfn)
+                               ast_log(LOG_WARNING, "Out of memory\n");
+                       else {
+                               res = action == ACTION_COPY ? copy(fn, nfn) : rename(fn, nfn);
+                               if (res)
+                                       ast_log(LOG_WARNING, "%s(%s,%s) failed: %s\n",
+                                               action == ACTION_COPY ? "copy" : "rename",
+                                                fn, nfn, strerror(errno));
+                               free(nfn);
+                       }
+                       break;
+               case ACTION_OPEN:       /* all done already! */
+                       break;
+               default:
+                       ast_log(LOG_WARNING, "Unknown helper %d\n", action);
+               }
+               free(fn);
        }
        AST_LIST_UNLOCK(&formats);
-       if ((action == ACTION_EXISTS) || (action == ACTION_OPEN))
-               res = ret ? ret : -1;
        return res;
 }
+
+/*!
+ * \brief helper routine to locate a file with a given format
+ * and language preference.
+ * Try preflang, preflang with stripped '_' suffix, or NULL.
+ * In the standard asterisk, language goes just before the last component.
+ * In an alternative configuration, the language should be a prefix
+ * to the actual filename.
+ *
+ * The last parameter(s) point to a buffer of sufficient size,
+ * which on success is filled with the matching filename.
+ */
+static int fileexists_core(const char *filename, const char *fmt, const char *preflang,
+               char *buf, int buflen)
+{
+       int res = -1;
+       int langlen;    /* length of language string */
+       const char *c = strrchr(filename, '/');
+       int offset = c ? c - filename + 1 : 0;  /* points right after the last '/' */
+
+       if (preflang == NULL)
+               preflang = "";
+       langlen = strlen(preflang);
+       
+       if (buflen < langlen + strlen(filename) + 2) {
+               ast_log(LOG_WARNING, "buffer too small\n");
+               buf[0] = '\0'; /* set to empty */
+               buf = alloca(langlen + strlen(filename) + 2);   /* room for everything */
+       }
+       if (buf == NULL)
+               return 0;
+       buf[0] = '\0';
+       for (;;) {
+               if (ast_language_is_prefix) { /* new layout */
+                       if (langlen) {
+                               strcpy(buf, preflang);
+                               buf[langlen] = '/';
+                               strcpy(buf + langlen + 1, filename);
+                       } else
+                               strcpy(buf, filename);  /* first copy the full string */
+               } else { /* old layout */
+                       strcpy(buf, filename);  /* first copy the full string */
+                       if (langlen) {
+                               /* insert the language and suffix if needed */
+                               strcpy(buf + offset, preflang);
+                               sprintf(buf + offset + langlen, "/%s", filename + offset);
+                       }
+               }
+               res = ast_filehelper(buf, NULL, fmt, ACTION_EXISTS);
+               if (res > 0)            /* found format */
+                       break;
+               if (langlen == 0)       /* no more formats */
+                       break;
+               if (preflang[langlen] == '_') /* we are on the local suffix */
+                       langlen = 0;    /* try again with no language */
+               else
+                       langlen = (c = strchr(preflang, '_')) ? c - preflang : 0;
+       }
+       return res;
+}
+
 struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
 {
        return ast_openstream_full(chan, filename, preflang, 0);
@@ -451,23 +537,13 @@ struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *file
 
 struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis)
 {
-       /* This is a fairly complex routine.  Essentially we should do 
-          the following:
-          
-          1) Find which file handlers produce our type of format.
-          2) Look for a filename which it can handle.
-          3) If we find one, then great.  
-          4) If not, see what files are there
-          5) See what we can actually support
-          6) Choose the one with the least costly translator path and
-              set it up.
-                  
-       */
-       int fmts = -1;
-       char filename2[256]="";
-       char filename3[256];
-       char *endpart;
-       int res;
+       /* 
+        * Use fileexists_core() to find a file in a compatible
+        * language and format, set up a suitable translator,
+        * and open the stream.
+        */
+       int fmts, res, buflen;
+       char *buf;
 
        if (!asis) {
                /* do this first, otherwise we detect the wrong writeformat */
@@ -475,25 +551,15 @@ struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char
                if (chan->generator)
                        ast_deactivate_generator(chan);
        }
-       if (!ast_strlen_zero(preflang)) {
-               ast_copy_string(filename3, filename, sizeof(filename3));
-               endpart = strrchr(filename3, '/');
-               if (endpart) {
-                       *endpart = '\0';
-                       endpart++;
-                       snprintf(filename2, sizeof(filename2), "%s/%s/%s", filename3, preflang, endpart);
-               } else
-                       snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
-               fmts = ast_fileexists(filename2, NULL, NULL);
-               if (fmts > 0) 
-                       fmts &= AST_FORMAT_AUDIO_MASK;
-       }
-       if (fmts < 1) {
-               ast_copy_string(filename2, filename, sizeof(filename2));
-               fmts = ast_fileexists(filename2, NULL, NULL);
-               if (fmts > 0)
-                       fmts &= AST_FORMAT_AUDIO_MASK;
-       }
+       if (preflang == NULL)
+               preflang = "";
+       buflen = strlen(preflang) + strlen(filename) + 2;
+       buf = alloca(buflen);
+       if (buf == NULL)
+               return NULL;
+       fmts = fileexists_core(filename, NULL, preflang, buf, buflen);
+       if (fmts > 0)
+               fmts &= AST_FORMAT_AUDIO_MASK;
        if (fmts < 1) {
                ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
                return NULL;
@@ -501,8 +567,7 @@ struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char
        chan->oldwriteformat = chan->writeformat;
        /* Set the channel to a format we can work with */
        res = ast_set_write_format(chan, fmts);
-       
-       res = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
+       res = ast_filehelper(buf, chan, NULL, ACTION_OPEN);
        if (res >= 0)
                return chan->stream;
        return NULL;
@@ -510,45 +575,30 @@ struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char
 
 struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
 {
-       /* This is a fairly complex routine.  Essentially we should do 
-          the following:
-          
-          1) Find which file handlers produce our type of format.
-          2) Look for a filename which it can handle.
-          3) If we find one, then great.  
-          4) If not, see what files are there
-          5) See what we can actually support
-          6) Choose the one with the least costly translator path and
-              set it up.
-                  
-       */
-       int fd = -1;
-       int fmts = -1;
+       /* As above, but for video. But here we don't have translators
+        * so we must enforce a format.
+        */
        unsigned int format;
-       char filename2[256];
-       char lang2[MAX_LANGUAGE];
-       const char *fmt;
+       char *buf;
+       int buflen;
+
+       if (preflang == NULL)
+               preflang = "";
+       buflen = strlen(preflang) + strlen(filename) + 2;
+       buf = alloca(buflen);
+       if (buf == NULL)
+               return NULL;
+
        for (format = AST_FORMAT_MAX_AUDIO << 1; format <= AST_FORMAT_MAX_VIDEO; format = format << 1) {
+               int fd;
+               const char *fmt;
+
                if (!(chan->nativeformats & format))
                        continue;
                fmt = ast_getformatname(format);
-               if (!ast_strlen_zero(preflang)) {
-                       snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
-                       fmts = ast_fileexists(filename2, fmt, NULL);
-                       if (fmts < 1) {
-                               ast_copy_string(lang2, preflang, sizeof(lang2));
-                               snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
-                               fmts = ast_fileexists(filename2, fmt, NULL);
-                       }
-               }
-               if (fmts < 1) {
-                       ast_copy_string(filename2, filename, sizeof(filename2));
-                       fmts = ast_fileexists(filename2, fmt, NULL);
-               }
-               if (fmts < 1) {
+               if ( fileexists_core(filename, fmt, preflang, buf, buflen) < 1) /* no valid format */
                        continue;
-               }
-               fd = ast_filehelper(filename2, (char *)chan, fmt, ACTION_OPEN);
+               fd = ast_filehelper(buf, chan, fmt, ACTION_OPEN);
                if (fd >= 0)
                        return chan->vstream;
                ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
@@ -568,22 +618,13 @@ struct ast_frame *ast_readframe(struct ast_filestream *s)
 static int ast_readaudio_callback(void *data)
 {
        struct ast_filestream *s = data;
-       struct ast_frame *fr;
        int whennext = 0;
 
        while(!whennext) {
-               fr = s->fmt->read(s, &whennext);
-               if (fr) {
-                       if (ast_write(s->owner, fr)) {
+               struct ast_frame *fr = s->fmt->read(s, &whennext);
+               if (!fr /* stream complete */ || ast_write(s->owner, fr) /* error writing */) {
+                       if (fr)
                                ast_log(LOG_WARNING, "Failed to write frame\n");
-                               s->owner->streamid = -1;
-#ifdef ZAPTEL_OPTIMIZATIONS
-                               ast_settimeout(s->owner, 0, NULL, NULL);
-#endif                 
-                               return 0;
-                       }
-               } else {
-                       /* Stream has finished */
                        s->owner->streamid = -1;
 #ifdef ZAPTEL_OPTIMIZATIONS
                        ast_settimeout(s->owner, 0, NULL, NULL);
@@ -607,19 +648,13 @@ static int ast_readaudio_callback(void *data)
 static int ast_readvideo_callback(void *data)
 {
        struct ast_filestream *s = data;
-       struct ast_frame *fr;
        int whennext = 0;
 
-       while(!whennext) {
-               fr = s->fmt->read(s, &whennext);
-               if (fr) {
-                       if (ast_write(s->owner, fr)) {
+       while (!whennext) {
+               struct ast_frame *fr = s->fmt->read(s, &whennext);
+               if (!fr || ast_write(s->owner, fr)) { /* no stream or error, as above */
+                       if (fr)
                                ast_log(LOG_WARNING, "Failed to write frame\n");
-                               s->owner->vstreamid = -1;
-                               return 0;
-                       }
-               } else {
-                       /* Stream has finished */
                        s->owner->vstreamid = -1;
                        return 0;
                }
@@ -664,17 +699,12 @@ off_t ast_tellstream(struct ast_filestream *fs)
 
 int ast_stream_fastforward(struct ast_filestream *fs, off_t ms)
 {
-       /* I think this is right, 8000 samples per second, 1000 ms a second so 8
-        * samples per ms  */
-       off_t samples = ms * 8;
-       return ast_seekstream(fs, samples, SEEK_CUR);
+       return ast_seekstream(fs, ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
 }
 
 int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
 {
-       off_t samples = ms * 8;
-       samples = samples * -1;
-       return ast_seekstream(fs, samples, SEEK_CUR);
+       return ast_seekstream(fs, -ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
 }
 
 int ast_closestream(struct ast_filestream *f)
@@ -699,10 +729,8 @@ int ast_closestream(struct ast_filestream *f)
                }
        }
        /* destroy the translator on exit */
-       if (f->trans) {
+       if (f->trans)
                ast_translator_free_path(f->trans);
-               f->trans = NULL;
-       }
 
        if (f->realfilename && f->filename) {
                        size = strlen(f->filename) + strlen(f->realfilename) + 15;
@@ -712,69 +740,42 @@ int ast_closestream(struct ast_filestream *f)
                        ast_safe_system(cmd);
        }
 
-       if (f->filename) {
+       if (f->filename)
                free(f->filename);
-               f->filename = NULL;
-       }
-       if (f->realfilename) {
+       if (f->realfilename)
                free(f->realfilename);
-               f->realfilename = NULL;
-       }
-       if (f->vfs) {
+       if (f->fmt->close)
+               f->fmt->close(f);
+       fclose(f->f);
+       if (f->vfs)
                ast_closestream(f->vfs);
-               f->vfs = NULL;
+       if (ast_mutex_lock(&f->fmt->lockp->lock)) {
+               ast_log(LOG_WARNING, "Unable to lock format %s\n", f->fmt->name);
+       } else {
+               f->fmt->lockp->usecnt--;
+               ast_mutex_unlock(&f->fmt->lockp->lock);
+               ast_update_use_count();
        }
-       f->fmt->close(f);
+       free(f);
        return 0;
 }
 
 
+/*
+ * Look the various language-specific places where a file could exist.
+ */
 int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
 {
-       char filename2[256];
-       char tmp[256];
-       char *postfix;
-       char *prefix;
-       char *c;
-       char lang2[MAX_LANGUAGE];
-       int res = -1;
-       if (!ast_strlen_zero(preflang)) {
-               /* Insert the language between the last two parts of the path */
-               ast_copy_string(tmp, filename, sizeof(tmp));
-               c = strrchr(tmp, '/');
-               if (c) {
-                       *c = '\0';
-                       postfix = c+1;
-                       prefix = tmp;
-                       snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
-               } else {
-                       postfix = tmp;
-                       prefix="";
-                       snprintf(filename2, sizeof(filename2), "%s/%s", preflang, postfix);
-               }
-               res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
-               if (res < 1) {
-                       char *stringp=NULL;
-                       ast_copy_string(lang2, preflang, sizeof(lang2));
-                       stringp=lang2;
-                       strsep(&stringp, "_");
-                       /* If language is a specific locality of a language (like es_MX), strip the locality and try again */
-                       if (strcmp(lang2, preflang)) {
-                               if (ast_strlen_zero(prefix)) {
-                                       snprintf(filename2, sizeof(filename2), "%s/%s", lang2, postfix);
-                               } else {
-                                       snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
-                               }
-                               res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
-                       }
-               }
-       }
-
-       /* Fallback to no language (usually winds up being American English) */
-       if (res < 1) {
-               res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
-       }
-       return res;
+       char *buf;
+       int buflen;
+
+       if (preflang == NULL)
+               preflang = "";
+       buflen = strlen(preflang) + strlen(filename) + 2;       /* room for everything */
+       buf = alloca(buflen);
+       if (buf == NULL)
+               return 0;
+       return fileexists_core(filename, fmt, preflang, buf, buflen);
 }
 
 int ast_filedelete(const char *filename, const char *fmt)
@@ -835,33 +836,30 @@ struct ast_filestream *ast_readfile(const char *filename, const char *type, cons
        }
 
        AST_LIST_TRAVERSE(&formats, f, list) {
-               if (fs)
-                       break;
-
+               fs = NULL;
                if (!exts_compare(f->exts, type))
                        continue;
 
                fn = build_filename(filename, type);
+               errno = 0;
                bfile = fopen(fn, "r");
-               if (bfile) {
-                       errno = 0;
-
-                       if (!(fs = f->open(bfile))) {
-                               ast_log(LOG_WARNING, "Unable to open %s\n", fn);
-                               fclose(bfile);
-                               free(fn);
-                               continue;
-                       }
-
-                       fs->trans = NULL;
-                       fs->fmt = f;
-                       fs->flags = flags;
-                       fs->mode = mode;
-                       fs->filename = strdup(filename);
-                       fs->vfs = NULL;
-               } else if (errno != EEXIST)
-                       ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
-               free(fn);
+               if (!bfile || (fs = get_filestream(f, bfile)) == NULL ||
+                       open_wrapper(fs) ) {
+                       ast_log(LOG_WARNING, "Unable to open %s\n", fn);
+                       fclose(bfile);
+                       free(fn);
+                       if (fs)
+                               free(fs);
+                       continue;
+               }
+               /* found it */
+               fs->trans = NULL;
+               fs->fmt = f;
+               fs->flags = flags;
+               fs->mode = mode;
+               fs->filename = strdup(filename);
+               fs->vfs = NULL;
+               break;
        }
 
        AST_LIST_UNLOCK(&formats);
@@ -878,7 +876,6 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
        FILE *bfile = NULL;
        struct ast_format *f;
        struct ast_filestream *fs = NULL;
-       char *fn, *orig_fn = NULL;
        char *buf = NULL;
        size_t size = 0;
 
@@ -888,8 +885,8 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
        }
 
        /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
+       /* We really can't use O_APPEND as it will break WAV header updates */
        if (flags & O_APPEND) { 
-               /* We really can't use O_APPEND as it will break WAV header updates */
                flags &= ~O_APPEND;
        } else {
                myflags = O_TRUNC;
@@ -897,7 +894,11 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
        
        myflags |= O_WRONLY | O_CREAT;
 
+       /* XXX need to fix this - we should just do the fopen,
+        * not open followed by fdopen()
+        */
        AST_LIST_TRAVERSE(&formats, f, list) {
+               char *fn, *orig_fn = NULL;
                if (fs)
                        break;
 
@@ -919,7 +920,7 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
                if (ast_opt_cache_record_files && (fd > -1)) {
                        char *c;
 
-                       fclose(bfile);
+                       fclose(bfile);  /* this also closes fd */
                        /*
                          We touch orig_fn just as a place-holder so other things (like vmail) see the file is there.
                          What we are really doing is writing to record_cache_dir until we are done then we will mv the file into place.
@@ -949,29 +950,31 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
                }
                if (fd > -1) {
                        errno = 0;
-                       if ((fs = f->rewrite(bfile, comment))) {
-                               fs->trans = NULL;
-                               fs->fmt = f;
-                               fs->flags = flags;
-                               fs->mode = mode;
-                               if (orig_fn) {
-                                       fs->realfilename = strdup(orig_fn);
-                                       fs->filename = strdup(fn);
-                               } else {
-                                       fs->realfilename = NULL;
-                                       fs->filename = strdup(filename);
-                               }
-                               fs->vfs = NULL;
-                               /* If truncated, we'll be at the beginning; if not truncated, then append */
-                               f->seek(fs, 0, SEEK_END);
-                       } else {
+                       fs = get_filestream(f, bfile);
+                       if (!fs || rewrite_wrapper(fs, comment)) {
                                ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
                                close(fd);
                                if (orig_fn) {
                                        unlink(fn);
                                        unlink(orig_fn);
                                }
+                               if (fs)
+                                       free(fs);
+                       }
+                       fs->trans = NULL;
+                       fs->fmt = f;
+                       fs->flags = flags;
+                       fs->mode = mode;
+                       if (orig_fn) {
+                               fs->realfilename = strdup(orig_fn);
+                               fs->filename = strdup(fn);
+                       } else {
+                               fs->realfilename = NULL;
+                               fs->filename = strdup(filename);
                        }
+                       fs->vfs = NULL;
+                       /* If truncated, we'll be at the beginning; if not truncated, then append */
+                       f->seek(fs, 0, SEEK_END);
                } else if (errno != EEXIST) {
                        ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
                        if (orig_fn)
@@ -989,176 +992,73 @@ struct ast_filestream *ast_writefile(const char *filename, const char *type, con
        return fs;
 }
 
-int ast_waitstream(struct ast_channel *c, const char *breakon)
-{
-       /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
-       int res;
-       struct ast_frame *fr;
-       if (!breakon) breakon = "";
-       while(c->stream) {
-               res = ast_sched_wait(c->sched);
-               if ((res < 0) && !c->timingfunc) {
-                       ast_stopstream(c);
-                       break;
-               }
-               if (res < 0)
-                       res = 1000;
-               res = ast_waitfor(c, res);
-               if (res < 0) {
-                       ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
-                       return res;
-               } else if (res > 0) {
-                       fr = ast_read(c);
-                       if (!fr) {
-#if 0
-                               ast_log(LOG_DEBUG, "Got hung up\n");
-#endif
-                               return -1;
-                       }
-                       
-                       switch(fr->frametype) {
-                       case AST_FRAME_DTMF:
-                               res = fr->subclass;
-                               if (strchr(breakon, res)) {
-                                       ast_frfree(fr);
-                                       return res;
-                               }
-                               break;
-                       case AST_FRAME_CONTROL:
-                               switch(fr->subclass) {
-                               case AST_CONTROL_HANGUP:
-                                       ast_frfree(fr);
-                                       return -1;
-                               case AST_CONTROL_RINGING:
-                               case AST_CONTROL_ANSWER:
-                               case AST_CONTROL_VIDUPDATE:
-                                       /* Unimportant */
-                                       break;
-                               default:
-                                       ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
-                               }
-                       }
-                       /* Ignore */
-                       ast_frfree(fr);
-               }
-               ast_sched_runq(c->sched);
-       }
-       return (c->_softhangup ? -1 : 0);
-}
-
-int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
+/*!
+ * \brief the core of all waitstream() functions
+ */
+static int waitstream_core(struct ast_channel *c, const char *breakon,
+       const char *forward, const char *rewind, int skip_ms,
+       int audiofd, int cmdfd,  const char *context)
 {
-       int res;
-       struct ast_frame *fr;
-
        if (!breakon)
-                       breakon = "";
+               breakon = "";
        if (!forward)
-                       forward = "";
+               forward = "";
        if (!rewind)
-                       rewind = "";
-       
-       while(c->stream) {
-               res = ast_sched_wait(c->sched);
-               if ((res < 0) && !c->timingfunc) {
-                       ast_stopstream(c);
-                       break;
-               }
-               if (res < 0)
-                       res = 1000;
-               res = ast_waitfor(c, res);
-               if (res < 0) {
-                       ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
-                       return res;
-               } else
-               if (res > 0) {
-                       fr = ast_read(c);
-                       if (!fr) {
-#if 0
-                               ast_log(LOG_DEBUG, "Got hung up\n");
-#endif
-                               return -1;
-                       }
-                       
-                       switch(fr->frametype) {
-                       case AST_FRAME_DTMF:
-                               res = fr->subclass;
-                               if (strchr(forward,res)) {
-                                       ast_stream_fastforward(c->stream, ms);
-                               } else if (strchr(rewind,res)) {
-                                       ast_stream_rewind(c->stream, ms);
-                               } else if (strchr(breakon, res)) {
-                                       ast_frfree(fr);
-                                       return res;
-                               }                                       
-                               break;
-                       case AST_FRAME_CONTROL:
-                               switch(fr->subclass) {
-                               case AST_CONTROL_HANGUP:
-                                       ast_frfree(fr);
-                                       return -1;
-                               case AST_CONTROL_RINGING:
-                               case AST_CONTROL_ANSWER:
-                                       /* Unimportant */
-                                       break;
-                               default:
-                                       ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
-                               }
-                       }
-                       /* Ignore */
-                       ast_frfree(fr);
-               } else
-                       ast_sched_runq(c->sched);
-       
-               
-       }
-       return (c->_softhangup ? -1 : 0);
-}
-
-int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
-{
-       int res;
-       int ms;
-       int outfd;
-       struct ast_frame *fr;
-       struct ast_channel *rchan;
-
-       if (!breakon)
-               breakon = "";
+               rewind = "";
        
-       while(c->stream) {
-               ms = ast_sched_wait(c->sched);
-               if ((ms < 0) && !c->timingfunc) {
+       while (c->stream) {
+               int res;
+               int ms = ast_sched_wait(c->sched);
+               if (ms < 0 && !c->timingfunc) {
                        ast_stopstream(c);
                        break;
                }
                if (ms < 0)
                        ms = 1000;
-               rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
-               if (!rchan && (outfd < 0) && (ms)) {
-                       /* Continue */
-                       if (errno == EINTR)
-                               continue;
-                       ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
-                       return -1;
-               } else if (outfd > -1) {
-                       /* The FD we were watching has something waiting */
-                       return 1;
-               } else if (rchan) {
-                       fr = ast_read(c);
-                       if (!fr) {
-#if 0
-                               ast_log(LOG_DEBUG, "Got hung up\n");
-#endif
+               if (!cmdfd) {
+                       res = ast_waitfor(c, ms);
+                       if (res < 0) {
+                               ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
+                               return res;
+                       }
+               } else {
+                       int outfd;
+                       struct ast_channel *rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
+                       if (!rchan && (outfd < 0) && (ms)) {
+                               /* Continue */
+                               if (errno == EINTR)
+                                       continue;
+                               ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
                                return -1;
+                       } else if (outfd > -1) { /* this requires cmdfd set */
+                               /* The FD we were watching has something waiting */
+                               return 1;
                        }
-                       
+                       /* if rchan is set, it is 'c' */
+                       res = rchan ? 1 : 0; /* map into 'res' values */
+               }
+               if (res > 0) {
+                       struct ast_frame *fr = ast_read(c);
+                       if (!fr)
+                               return -1;
                        switch(fr->frametype) {
                        case AST_FRAME_DTMF:
-                               res = fr->subclass;
-                               if (strchr(breakon, res)) {
-                                       ast_frfree(fr);
-                                       return res;
+                               if (context) {
+                                       const char exten[2] = { fr->subclass, '\0' };
+                                       if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
+                                               ast_frfree(fr);
+                                               return res;
+                                       }
+                               } else {
+                                       res = fr->subclass;
+                                       if (strchr(forward,res)) {
+                                               ast_stream_fastforward(c->stream, skip_ms);
+                                       } else if (strchr(rewind,res)) {
+                                               ast_stream_rewind(c->stream, skip_ms);
+                                       } else if (strchr(breakon, res)) {
+                                               ast_frfree(fr);
+                                               return res;
+                                       }                                       
                                }
                                break;
                        case AST_FRAME_CONTROL:
@@ -1178,7 +1078,7 @@ int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd,
                                if (audiofd > -1)
                                        write(audiofd, fr->data, fr->datalen);
                        }
-                       /* Ignore */
+                       /* Ignore all others */
                        ast_frfree(fr);
                }
                ast_sched_runq(c->sched);
@@ -1186,65 +1086,32 @@ int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd,
        return (c->_softhangup ? -1 : 0);
 }
 
+int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
+{
+       return waitstream_core(c, breakon, forward, rewind, ms,
+               -1 /* no audiofd */, -1 /* no cmdfd */, NULL /* no context */);
+}
+
+int ast_waitstream(struct ast_channel *c, const char *breakon)
+{
+       return waitstream_core(c, breakon, NULL, NULL, 0, -1, -1, NULL);
+}
+
+int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
+{
+       return waitstream_core(c, breakon, NULL, NULL, 0,
+               audiofd, cmdfd, NULL /* no context */);
+}
+
 int ast_waitstream_exten(struct ast_channel *c, const char *context)
 {
        /* Waitstream, with return in the case of a valid 1 digit extension */
        /* in the current or specified context being pressed */
-       /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
-       int res;
-       struct ast_frame *fr;
-       char exten[AST_MAX_EXTENSION];
-
-       if (!context) context = c->context;
-       while(c->stream) {
-               res = ast_sched_wait(c->sched);
-               if ((res < 0) && !c->timingfunc) {
-                       ast_stopstream(c);
-                       break;
-               }
-               if (res < 0)
-                       res = 1000;
-               res = ast_waitfor(c, res);
-               if (res < 0) {
-                       ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
-                       return res;
-               } else if (res > 0) {
-                       fr = ast_read(c);
-                       if (!fr) {
-#if 0
-                               ast_log(LOG_DEBUG, "Got hung up\n");
-#endif
-                               return -1;
-                       }
-                       
-                       switch(fr->frametype) {
-                       case AST_FRAME_DTMF:
-                               res = fr->subclass;
-                               snprintf(exten, sizeof(exten), "%c", res);
-                               if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
-                                       ast_frfree(fr);
-                                       return res;
-                               }
-                               break;
-                       case AST_FRAME_CONTROL:
-                               switch(fr->subclass) {
-                               case AST_CONTROL_HANGUP:
-                                       ast_frfree(fr);
-                                       return -1;
-                               case AST_CONTROL_RINGING:
-                               case AST_CONTROL_ANSWER:
-                                       /* Unimportant */
-                                       break;
-                               default:
-                                       ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
-                               }
-                       }
-                       /* Ignore */
-                       ast_frfree(fr);
-               }
-               ast_sched_runq(c->sched);
-       }
-       return (c->_softhangup ? -1 : 0);
+
+       if (!context)
+               context = c->context;
+       return waitstream_core(c, NULL, NULL, NULL, 0,
+               -1, -1, context);
 }
 
 static int show_file_formats(int fd, int argc, char *argv[])
@@ -1272,7 +1139,6 @@ static int show_file_formats(int fd, int argc, char *argv[])
        return RESULT_SUCCESS;
 #undef FORMAT
 #undef FORMAT2
-       
 }
 
 struct ast_cli_entry show_file =
index 80143e5..8b47f8d 100644 (file)
 
 MODS:=$(patsubst %.c,%.so,$(wildcard format_*.c))
 
+MODS:=$(filter-out format_pcm_alaw.so,$(MODS))
+MODS:=$(filter-out format_au.so,$(MODS))
+
+# merged.      format_pcm_alaw.so
+# merged.      format_au.so
 #
 # OGG/Vorbis format
 #
index e8be324..06626a0 100644 (file)
@@ -44,7 +44,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
 
-#define BUF_SIZE               160
+#define BUF_SIZE               160     /* samples and 1 byte per sample */
 
 #define AU_HEADER_SIZE         24
 #define AU_HEADER(var)         u_int32_t var[6]
@@ -58,26 +58,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #define AU_ENC_8BIT_ULAW       1
 
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
-       /* This is what a filestream means to us */
-       FILE *f;                                /* Descriptor */
-       struct ast_channel *owner;
-       struct ast_frame fr;                    /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                             /* Empty character */
-       short buf[BUF_SIZE];
-};
-
-
-AST_MUTEX_DEFINE_STATIC(au_lock);
-static int localusecnt = 0;
-
-static char *name = "au";
-static char *desc = "Sun Microsystems AU format (signed linear)";
-static char *exts = "au";
-
-
 #define AU_MAGIC 0x2e736e64
 #if __BYTE_ORDER == __BIG_ENDIAN
 #define htoll(b) (b)
@@ -130,7 +110,7 @@ static int check_header(FILE *f)
                return -1;
        }
        sample_rate = ltohl(header[AU_HDR_SAMPLE_RATE_OFF]);
-       if (sample_rate != 8000) {
+       if (sample_rate != DEFAULT_SAMPLE_RATE) {
                ast_log(LOG_WARNING, "Sample rate can only be 8000 not %d\n", sample_rate);
                return -1;
        }
@@ -189,7 +169,7 @@ static int write_header(FILE *f)
        header[AU_HDR_HDR_SIZE_OFF] = htoll(AU_HEADER_SIZE);
        header[AU_HDR_DATA_SIZE_OFF] = 0;
        header[AU_HDR_ENCODING_OFF] = htoll(AU_ENC_8BIT_ULAW);
-       header[AU_HDR_SAMPLE_RATE_OFF] = htoll(8000);
+       header[AU_HDR_SAMPLE_RATE_OFF] = htoll(DEFAULT_SAMPLE_RATE);
        header[AU_HDR_CHANNELS_OFF] = htoll(1);
 
        /* Write an au header, ignoring sizes which will be filled in later */
@@ -201,97 +181,36 @@ static int write_header(FILE *f)
        return 0;
 }
 
-static struct ast_filestream *au_open(FILE *f)
-{
-       struct ast_filestream *tmp;
-
-       if (!(tmp = malloc(sizeof(struct ast_filestream)))) {
-               ast_log(LOG_ERROR, "Out of memory\n");
-               return NULL;
-       }
-
-       memset(tmp, 0, sizeof(struct ast_filestream));
-       if (check_header(f) < 0) {
-               free(tmp);
-               return NULL;
-       }
-       if (ast_mutex_lock(&au_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock au count\n");
-               free(tmp);
-               return NULL;
-       }
-       tmp->f = f;
-       tmp->fr.data = tmp->buf;
-       tmp->fr.frametype = AST_FRAME_VOICE;
-       tmp->fr.subclass = AST_FORMAT_ULAW;
-       /* datalen will vary for each frame */
-       tmp->fr.src = name;
-       tmp->fr.mallocd = 0;
-       localusecnt++;
-       ast_mutex_unlock(&au_lock);
-       ast_update_use_count();
-       return tmp;
-}
-
-static struct ast_filestream *au_rewrite(FILE *f, const char *comment)
+static int au_open(struct ast_filestream *s)
 {
-       struct ast_filestream *tmp;
-
-       if ((tmp = malloc(sizeof(struct ast_filestream))) == NULL) {
-               ast_log(LOG_ERROR, "Out of memory\n");
-               return NULL;
-       }
-
-       memset(tmp, 0, sizeof(struct ast_filestream));
-       if (write_header(f)) {
-               free(tmp);
-               return NULL;
-       }
-       if (ast_mutex_lock(&au_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock au count\n");
-               free(tmp);
-               return NULL;
-       }
-       tmp->f = f;
-       localusecnt++;
-       ast_mutex_unlock(&au_lock);
-       ast_update_use_count();
-       return tmp;
+       if (check_header(s->f) < 0)
+               return -1;
+       return 0;
 }
 
-static void au_close(struct ast_filestream *s)
+static int au_rewrite(struct ast_filestream *s, const char *comment)
 {
-       if (ast_mutex_lock(&au_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock au count\n");
-               return;
-       }
-       localusecnt--;
-       ast_mutex_unlock(&au_lock);
-       ast_update_use_count();
-       fclose(s->f);
-       free(s);
+       if (write_header(s->f))
+               return -1;
+       return 0;
 }
 
 static struct ast_frame *au_read(struct ast_filestream *s, int *whennext)
 {
        int res;
-       int delay;
        /* Send a frame from the file to the appropriate channel */
 
        s->fr.frametype = AST_FRAME_VOICE;
        s->fr.subclass = AST_FORMAT_ULAW;
-       s->fr.offset = AST_FRIENDLY_OFFSET;
        s->fr.mallocd = 0;
-       s->fr.data = s->buf;
-       if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) {
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
+       if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) < 1) {
                if (res)
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
                return NULL;
        }
-       s->fr.samples = res;
+       *whennext = s->fr.samples = res;
        s->fr.datalen = res;
-       delay = s->fr.samples;
-       *whennext = delay;
        return &s->fr;
 }
 
@@ -308,8 +227,8 @@ static int au_write(struct ast_filestream *fs, struct ast_frame *f)
                return -1;
        }
        if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
-                       ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
-                       return -1;
+               ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
+               return -1;
        }
        update_header(fs->f);
        return 0;
@@ -348,44 +267,45 @@ static int au_trunc(struct ast_filestream *fs)
 
 static off_t au_tell(struct ast_filestream *fs)
 {
-       off_t offset;
-
-       offset = ftello(fs->f);
+       off_t offset = ftello(fs->f);
        return offset - AU_HEADER_SIZE;
 }
 
-static char *au_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format au_f = {
+       .name = "au",
+       .exts = "au",
+       .format = AST_FORMAT_ULAW,
+       .open = au_open,
+       .rewrite = au_rewrite,
+       .write = au_write,
+       .seek = au_seek,
+       .trunc = au_trunc,
+       .tell = au_tell,
+       .read = au_read,
+       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,     /* this many shorts */
+       .lockp = &me,
+};
 
 int load_module()
 {
-       return ast_format_register(name, exts, AST_FORMAT_ULAW,
-                                  au_open,
-                                  au_rewrite,
-                                  au_write,
-                                  au_seek,
-                                  au_trunc,
-                                  au_tell,
-                                  au_read,
-                                  au_close,
-                                  au_getcomment);
+       return ast_format_register(&au_f);
 }
 
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(au_f.name);
 }
 
 int usecount()
 {
-       return localusecnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Sun Microsystems AU format (signed linear)";
 }
 
 char *key()
index 5eff15d..7ddc79b 100644 (file)
@@ -47,81 +47,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #define G723_MAX_SIZE 1024
 
-struct ast_filestream {
-       /* First entry MUST be reserved for the channel type */
-       void *reserved[AST_RESERVED_POINTERS];
-       /* This is what a filestream means to us */
-       FILE *f; /* Descriptor */
-       struct ast_filestream *next;
-       struct ast_frame *fr;   /* Frame representation of buf */
-       struct timeval orig;    /* Original frame time */
-       char buf[G723_MAX_SIZE + AST_FRIENDLY_OFFSET];  /* Buffer for sending frames, etc */
-};
-
-
-AST_MUTEX_DEFINE_STATIC(g723_lock);
-static int glistcnt = 0;
-
-static char *name = "g723sf";
-static char *desc = "G.723.1 Simple Timestamp File Format";
-static char *exts = "g723|g723sf";
-
-static struct ast_filestream *g723_open(FILE *f)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&g723_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock g723 list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->fr = (struct ast_frame *)tmp->buf;
-               tmp->fr->data = tmp->buf + sizeof(struct ast_frame);
-               tmp->fr->frametype = AST_FRAME_VOICE;
-               tmp->fr->subclass = AST_FORMAT_G723_1;
-               /* datalen will vary for each frame */
-               tmp->fr->src = name;
-               tmp->fr->mallocd = 0;
-               glistcnt++;
-               ast_mutex_unlock(&g723_lock);
-               ast_update_use_count();
-       }
-       return tmp;
-}
-
-static struct ast_filestream *g723_rewrite(FILE *f, const char *comment)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&g723_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock g723 list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               glistcnt++;
-               ast_mutex_unlock(&g723_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
-}
-
 static struct ast_frame *g723_read(struct ast_filestream *s, int *whennext)
 {
        unsigned short size;
        int res;
        int delay;
        /* Read the delay for the next packet, and schedule again if necessary */
+       /* XXX is this ignored ? */
        if (fread(&delay, 1, 4, s->f) == 4) 
                delay = ntohl(delay);
        else
@@ -133,7 +65,7 @@ static struct ast_frame *g723_read(struct ast_filestream *s, int *whennext)
        }
        /* Looks like we have a frame to read from here */
        size = ntohs(size);
-       if (size > G723_MAX_SIZE - sizeof(struct ast_frame)) {
+       if (size > G723_MAX_SIZE) {
                ast_log(LOG_WARNING, "Size %d is invalid\n", size);
                /* The file is apparently no longer any good, as we
                   shouldn't ever get frames even close to this 
@@ -141,50 +73,24 @@ static struct ast_frame *g723_read(struct ast_filestream *s, int *whennext)
                return NULL;
        }
        /* Read the data into the buffer */
-       s->fr->offset = AST_FRIENDLY_OFFSET;
-       s->fr->datalen = size;
-       s->fr->data = s->buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET;
-       if ((res = fread(s->fr->data, 1, size, s->f)) != size) {
+       s->fr.frametype = AST_FRAME_VOICE;
+       s->fr.subclass = AST_FORMAT_G723_1;
+       s->fr.mallocd = 0;
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, size);
+       if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) != size) {
                ast_log(LOG_WARNING, "Short read (%d of %d bytes) (%s)!\n", res, size, strerror(errno));
                return NULL;
        }
-#if 0
-               /* Average out frames <= 50 ms */
-               if (delay < 50)
-                       s->fr->timelen = 30;
-               else
-                       s->fr->timelen = delay;
-#else
-               s->fr->samples = 240;
-#endif
-       *whennext = s->fr->samples;
-       return s->fr;
+       *whennext = s->fr.samples = 240;
+       return &s->fr;
 }
 
-static void g723_close(struct ast_filestream *s)
-{
-       if (ast_mutex_lock(&g723_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock g723 list\n");
-               return;
-       }
-       glistcnt--;
-       ast_mutex_unlock(&g723_lock);
-       ast_update_use_count();
-       fclose(s->f);
-       free(s);
-       s = NULL;
-}
-
-
-static int g723_write(struct ast_filestream *fs, struct ast_frame *f)
+static int g723_write(struct ast_filestream *s, struct ast_frame *f)
 {
        u_int32_t delay;
        u_int16_t size;
        int res;
-       if (fs->fr) {
-               ast_log(LOG_WARNING, "Asked to write on a read stream??\n");
-               return -1;
-       }
+       /* XXX there used to be a check s->fr means a read stream */
        if (f->frametype != AST_FRAME_VOICE) {
                ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
                return -1;
@@ -198,16 +104,16 @@ static int g723_write(struct ast_filestream *fs, struct ast_frame *f)
                ast_log(LOG_WARNING, "Short frame ignored (%d bytes long?)\n", f->datalen);
                return 0;
        }
-       if ((res = fwrite(&delay, 1, 4, fs->f)) != 4) {
+       if ((res = fwrite(&delay, 1, 4, s->f)) != 4) {
                ast_log(LOG_WARNING, "Unable to write delay: res=%d (%s)\n", res, strerror(errno));
                return -1;
        }
        size = htons(f->datalen);
-       if ((res = fwrite(&size, 1, 2, fs->f)) != 2) {
+       if ((res = fwrite(&size, 1, 2, s->f)) != 2) {
                ast_log(LOG_WARNING, "Unable to write size: res=%d (%s)\n", res, strerror(errno));
                return -1;
        }
-       if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
+       if ((res = fwrite(f->data, 1, f->datalen, s->f)) != f->datalen) {
                ast_log(LOG_WARNING, "Unable to write frame: res=%d (%s)\n", res, strerror(errno));
                return -1;
        }       
@@ -232,43 +138,41 @@ static off_t g723_tell(struct ast_filestream *fs)
        return -1;
 }
 
-static char *g723_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format g723_1_f = {
+       .name = "g723sf",
+       .exts = "g723|g723sf",
+       .format = AST_FORMAT_G723_1,
+       .write = g723_write,
+       .seek = g723_seek,
+       .trunc = g723_trunc,
+       .tell = g723_tell,
+       .read = g723_read,
+       .buf_size = G723_MAX_SIZE + AST_FRIENDLY_OFFSET,
+       .lockp = &me,
+};
 
 int load_module()
 {
-       return ast_format_register(name, exts, AST_FORMAT_G723_1,
-                                                               g723_open,
-                                                               g723_rewrite,
-                                                               g723_write,
-                                                               g723_seek,
-                                                               g723_trunc,
-                                                               g723_tell,
-                                                               g723_read,
-                                                               g723_close,
-                                                               g723_getcomment);
-                                                               
-                                                               
+       return ast_format_register(&g723_1_f);
 }
 
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(g723_1_f.name);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "G.723.1 Simple Timestamp File Format";
 }
 
-
 char *key()
 {
        return ASTERISK_GPL_KEY;
index 70c6ac8..01b94c0 100644 (file)
@@ -58,6 +58,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 /* We can only read/write chunks of FRAME_TIME ms G.726 data */
 #define        FRAME_TIME      10      /* 10 ms size */
 
+#define        BUF_SIZE        (5*FRAME_TIME)  /* max frame size in bytes ? */
 /* Frame sizes in bytes */
 static int frame_size[4] = { 
                FRAME_TIME * 5,
@@ -66,293 +67,79 @@ static int frame_size[4] = {
                FRAME_TIME * 2
 };
 
-struct ast_filestream {
-       /* Do not place anything before "reserved" */
-       void *reserved[AST_RESERVED_POINTERS];
-       /* This is what a filestream means to us */
-       FILE *f;                                                        /* Open file descriptor */
-       int rate;                                                       /* RATE_* defines */
-       struct ast_frame fr;                            /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                                                     /* Empty character */
-       unsigned char g726[FRAME_TIME * 5];     /* G.726 encoded voice */
+struct g726_desc  {
+       int rate;       /* RATE_* defines */
 };
 
-AST_MUTEX_DEFINE_STATIC(g726_lock);
-static int glistcnt = 0;
-
-static char *desc = "Raw G.726 (16/24/32/40kbps) data";
-static char *name40 = "g726-40";
-static char *name32 = "g726-32";
-static char *name24 = "g726-24";
-static char *name16 = "g726-16";
-static char *exts40 = "g726-40";
-static char *exts32 = "g726-32";
-static char *exts24 = "g726-24";
-static char *exts16 = "g726-16";
-
 /*
  * Rate dependant format functions (open, rewrite)
  */
-static struct ast_filestream *g726_40_open(FILE *f)
+static int g726_open(struct ast_filestream *tmp, int rate)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&g726_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->rate = RATE_40;
-               tmp->fr.data = tmp->g726;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_G726;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name40;
-               tmp->fr.mallocd = 0;
-               glistcnt++;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
-                                                                       40 - tmp->rate * 8);
-               ast_mutex_unlock(&g726_lock);
-               ast_update_use_count();
-       }
-       return tmp;
+       struct g726_desc *s = (struct g726_desc *)tmp->private;
+       s->rate = rate;
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
+                               40 - s->rate * 8);
+       return 0;
 }
 
-static struct ast_filestream *g726_32_open(FILE *f)
+static int g726_40_open(struct ast_filestream *s)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&g726_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->rate = RATE_32;
-               tmp->fr.data = tmp->g726;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_G726;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name32;
-               tmp->fr.mallocd = 0;
-               glistcnt++;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
-                                                                       40 - tmp->rate * 8);
-               ast_mutex_unlock(&g726_lock);
-               ast_update_use_count();
-       }
-       return tmp;
+       return g726_open(s, RATE_40);
 }
 
-static struct ast_filestream *g726_24_open(FILE *f)
+static int g726_32_open(struct ast_filestream *s)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&g726_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->rate = RATE_24;
-               tmp->fr.data = tmp->g726;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_G726;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name24;
-               tmp->fr.mallocd = 0;
-               glistcnt++;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
-                                                                       40 - tmp->rate * 8);
-               ast_mutex_unlock(&g726_lock);
-               ast_update_use_count();
-       }
-       return tmp;
+       return g726_open(s, RATE_32);
 }
 
-static struct ast_filestream *g726_16_open(FILE *f)
+static int g726_24_open(struct ast_filestream *s)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&g726_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->rate = RATE_16;
-               tmp->fr.data = tmp->g726;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_G726;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name16;
-               tmp->fr.mallocd = 0;
-               glistcnt++;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
-                                                                       40 - tmp->rate * 8);
-               ast_mutex_unlock(&g726_lock);
-               ast_update_use_count();
-       }
-       return tmp;
+       return g726_open(s, RATE_24);
 }
 
-static struct ast_filestream *g726_40_rewrite(FILE *f, const char *comment)
+static int g726_16_open(struct ast_filestream *s)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&g726_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->rate = RATE_40;
-               glistcnt++;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
-                                                                       40 - tmp->rate * 8);
-               ast_mutex_unlock(&g726_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
+       return g726_open(s, RATE_16);
 }
 
-static struct ast_filestream *g726_32_rewrite(FILE *f, const char *comment)
+static int g726_40_rewrite(struct ast_filestream *s, const char *comment)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&g726_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->rate = RATE_32;
-               glistcnt++;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
-                                                                       40 - tmp->rate * 8);
-               ast_mutex_unlock(&g726_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
+       return g726_open(s, RATE_40);
 }
 
-static struct ast_filestream *g726_24_rewrite(FILE *f, const char *comment)
+static int g726_32_rewrite(struct ast_filestream *s, const char *comment)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&g726_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->rate = RATE_24;
-               glistcnt++;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
-                                                                       40 - tmp->rate * 8);
-               ast_mutex_unlock(&g726_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
+       return g726_open(s, RATE_32);
 }
 
-static struct ast_filestream *g726_16_rewrite(FILE *f, const char *comment)
+static int g726_24_rewrite(struct ast_filestream *s, const char *comment)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&g726_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->rate = RATE_16;
-               glistcnt++;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
-                                                                       40 - tmp->rate * 8);
-               ast_mutex_unlock(&g726_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
+       return g726_open(s, RATE_24);
 }
 
-/*
- * Rate independent format functions (close, read, write)
- */
-static void g726_close(struct ast_filestream *s)
+static int g726_16_rewrite(struct ast_filestream *s, const char *comment)
 {
-       if (ast_mutex_lock(&g726_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
-               return;
-       }
-       glistcnt--;
-       if (option_debug)
-               ast_log(LOG_DEBUG, "Closed filestream G.726-%dk.\n", 40 - s->rate * 8);
-       ast_mutex_unlock(&g726_lock);
-       ast_update_use_count();
-       fclose(s->f);
-       free(s);
-       s = NULL;
+       return g726_open(s, RATE_16);
 }
 
+/*
+ * Rate independent format functions (read, write)
+ */
+
 static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext)
 {
        int res;
+       struct g726_desc *fs = (struct g726_desc *)s->private;
+
        /* Send a frame from the file to the appropriate channel */
        s->fr.frametype = AST_FRAME_VOICE;
        s->fr.subclass = AST_FORMAT_G726;
-       s->fr.offset = AST_FRIENDLY_OFFSET;
-       s->fr.samples = 8 * FRAME_TIME;
-       s->fr.datalen = frame_size[s->rate];
        s->fr.mallocd = 0;
-       s->fr.data = s->g726;
-       if ((res = fread(s->g726, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, frame_size[fs->rate]);
+       s->fr.samples = 8 * FRAME_TIME;
+       if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
                if (res)
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
                return NULL;
@@ -361,9 +148,11 @@ static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext)
        return &s->fr;
 }
 
-static int g726_write(struct ast_filestream *fs, struct ast_frame *f)
+static int g726_write(struct ast_filestream *s, struct ast_frame *f)
 {
        int res;
+       struct g726_desc *fs = (struct g726_desc *)s->private;
+
        if (f->frametype != AST_FRAME_VOICE) {
                ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
                return -1;
@@ -378,19 +167,14 @@ static int g726_write(struct ast_filestream *fs, struct ast_frame *f)
                                                f->datalen, frame_size[fs->rate]);
                return -1;
        }
-       if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
-                       ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", 
-                                                       res, frame_size[fs->rate], strerror(errno));
+       if ((res = fwrite(f->data, 1, f->datalen, s->f)) != f->datalen) {
+               ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", 
+                               res, frame_size[fs->rate], strerror(errno));
                        return -1;
        }
        return 0;
 }
 
-static char *g726_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
-
 static int g726_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
 {
        return -1;
@@ -406,107 +190,107 @@ static off_t g726_tell(struct ast_filestream *fs)
        return -1;
 }
 
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format f[] = {
+       {
+               .name = "g726-40",
+               .exts = "g726-40",
+               .format = AST_FORMAT_G726,
+               .open = g726_40_open,
+               .rewrite = g726_40_rewrite,
+               .write = g726_write,
+               .seek = g726_seek,
+               .trunc = g726_trunc,
+               .tell = g726_tell,
+               .read = g726_read,
+               .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+               .desc_size = sizeof(struct g726_desc),
+               .lockp = &me,
+       },
+       {
+               .name = "g726-32",
+               .exts = "g726-32",
+               .format = AST_FORMAT_G726,
+               .open = g726_32_open,
+               .rewrite = g726_32_rewrite,
+               .write = g726_write,
+               .seek = g726_seek,
+               .trunc = g726_trunc,
+               .tell = g726_tell,
+               .read = g726_read,
+               .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+               .desc_size = sizeof(struct g726_desc),
+               .lockp = &me,
+       },
+       {
+               .name = "g726-24",
+               .exts = "g726-24",
+               .format = AST_FORMAT_G726,
+               .open = g726_24_open,
+               .rewrite = g726_24_rewrite,
+               .write = g726_write,
+               .seek = g726_seek,
+               .trunc = g726_trunc,
+               .tell = g726_tell,
+               .read = g726_read,
+               .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+               .desc_size = sizeof(struct g726_desc),
+               .lockp = &me,
+       },
+       {
+               .name = "g726-16",
+               .exts = "g726-16",
+               .format = AST_FORMAT_G726,
+               .open = g726_16_open,
+               .rewrite = g726_16_rewrite,
+               .write = g726_write,
+               .seek = g726_seek,
+               .trunc = g726_trunc,
+               .tell = g726_tell,
+               .read = g726_read,
+               .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+               .desc_size = sizeof(struct g726_desc),
+               .lockp = &me,
+       },
+       {       .format = 0 }   /* terminator */
+};
+
 /*
  * Module interface (load_module, unload_module, usecount, description, key)
  */
 int load_module()
 {
-       int res;
+       int i;
 
-       res = ast_format_register(name40, exts40, AST_FORMAT_G726,
-                                                               g726_40_open,
-                                                               g726_40_rewrite,
-                                                               g726_write,
-                                                               g726_seek,
-                                                               g726_trunc,
-                                                               g726_tell,
-                                                               g726_read,
-                                                               g726_close,
-                                                               g726_getcomment);
-       if (res) {
-               ast_log(LOG_WARNING, "Failed to register format %s.\n", name40);
-               return(-1);
-       }
-       res = ast_format_register(name32, exts32, AST_FORMAT_G726,
-                                                               g726_32_open,
-                                                               g726_32_rewrite,
-                                                               g726_write,
-                                                               g726_seek,
-                                                               g726_trunc,
-                                                               g726_tell,
-                                                               g726_read,
-                                                               g726_close,
-                                                               g726_getcomment);
-       if (res) {
-               ast_log(LOG_WARNING, "Failed to register format %s.\n", name32);
-               return(-1);
-       }
-       res = ast_format_register(name24, exts24, AST_FORMAT_G726,
-                                                               g726_24_open,
-                                                               g726_24_rewrite,
-                                                               g726_write,
-                                                               g726_seek,
-                                                               g726_trunc,
-                                                               g726_tell,
-                                                               g726_read,
-                                                               g726_close,
-                                                               g726_getcomment);
-       if (res) {
-               ast_log(LOG_WARNING, "Failed to register format %s.\n", name24);
-               return(-1);
-       }
-       res = ast_format_register(name16, exts16, AST_FORMAT_G726,
-                                                               g726_16_open,
-                                                               g726_16_rewrite,
-                                                               g726_write,
-                                                               g726_seek,
-                                                               g726_trunc,
-                                                               g726_tell,
-                                                               g726_read,
-                                                               g726_close,
-                                                               g726_getcomment);
-       if (res) {
-               ast_log(LOG_WARNING, "Failed to register format %s.\n", name16);
-               return(-1);
+       for (i = 0; f[i].format ; i++) {
+               if (ast_format_register(&f[i])) {       /* errors are fatal */
+                       ast_log(LOG_WARNING, "Failed to register format %s.\n", f[i].name);
+                       return -1;
+               }
        }
-       return(0);
+       return 0;
 }
 
 int unload_module()
 {
-       int res;
+       int i;
 
-       res = ast_format_unregister(name16);
-       if (res) {
-               ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name16);
-               return(-1);
-       }
-       res = ast_format_unregister(name24);
-       if (res) {
-               ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name24);
-               return(-1);
-       }
-       res = ast_format_unregister(name32);
-       if (res) {
-               ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name32);
-               return(-1);
-       }
-       res = ast_format_unregister(name40);
-       if (res) {
-               ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name40);
-               return(-1);
+       for (i = 0; f[i].format ; i++) {
+               if (ast_format_unregister(f[i].name))
+                       ast_log(LOG_WARNING, "Failed to unregister format %s.\n", f[i].name);
        }
        return(0);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Raw G.726 (16/24/32/40kbps) data";
 }
 
 char *key()
index 5194cea..fc1e3e3 100644 (file)
@@ -51,88 +51,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 /* Portions of the conversion code are by guido@sienanet.it */
 
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
-       /* Believe it or not, we must decode/recode to account for the
-          weird MS format */
-       /* This is what a filestream means to us */
-       FILE *f; /* Descriptor */
-       struct ast_frame fr;                            /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                                                     /* Empty character */
-       unsigned char g729[20];                         /* Two Real G729 Frames */
-};
-
-
-AST_MUTEX_DEFINE_STATIC(g729_lock);
-static int glistcnt = 0;
-
-static char *name = "g729";
-static char *desc = "Raw G729 data";
-static char *exts = "g729";
-
-static struct ast_filestream *g729_open(FILE *f)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&g729_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock g729 list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->fr.data = tmp->g729;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_G729A;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name;
-               tmp->fr.mallocd = 0;
-               glistcnt++;
-               ast_mutex_unlock(&g729_lock);
-               ast_update_use_count();
-       }
-       return tmp;
-}
-
-static struct ast_filestream *g729_rewrite(FILE *f, const char *comment)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&g729_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock g729 list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               glistcnt++;
-               ast_mutex_unlock(&g729_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
-}
-
-static void g729_close(struct ast_filestream *s)
-{
-       if (ast_mutex_lock(&g729_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock g729 list\n");
-               return;
-       }
-       glistcnt--;
-       ast_mutex_unlock(&g729_lock);
-       ast_update_use_count();
-       fclose(s->f);
-       free(s);
-       s = NULL;
-}
+#define        BUF_SIZE        20      /* two G729 frames */
+#define        G729A_SAMPLES   160
 
 static struct ast_frame *g729_read(struct ast_filestream *s, int *whennext)
 {
@@ -140,13 +60,11 @@ static struct ast_frame *g729_read(struct ast_filestream *s, int *whennext)
        /* Send a frame from the file to the appropriate channel */
        s->fr.frametype = AST_FRAME_VOICE;
        s->fr.subclass = AST_FORMAT_G729A;
-       s->fr.offset = AST_FRIENDLY_OFFSET;
-       s->fr.samples = 160;
-       s->fr.datalen = 20;
        s->fr.mallocd = 0;
-       s->fr.data = s->g729;
-       if ((res = fread(s->g729, 1, 20, s->f)) != 20) {
-               if (res && (res != 10))
+       s->fr.samples = G729A_SAMPLES;
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
+       if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
+               if (res && (res != 10)) /* XXX what for ? */
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
                return NULL;
        }
@@ -176,11 +94,6 @@ static int g729_write(struct ast_filestream *fs, struct ast_frame *f)
        return 0;
 }
 
-static char *g729_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
-
 static int g729_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
 {
        long bytes;
@@ -190,7 +103,7 @@ static int g729_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
        fseeko(fs->f, 0, SEEK_END);
        max = ftello(fs->f);
        
-       bytes = 20 * (sample_offset / 160);
+       bytes = BUF_SIZE * (sample_offset / G729A_SAMPLES);
        if (whence == SEEK_SET)
                offset = bytes;
        else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
@@ -217,43 +130,45 @@ static int g729_trunc(struct ast_filestream *fs)
 
 static off_t g729_tell(struct ast_filestream *fs)
 {
-       off_t offset;
-       offset = ftello(fs->f);
-       return (offset/20)*160;
+       off_t offset = ftello(fs->f);
+       return (offset/BUF_SIZE)*G729A_SAMPLES;
 }
 
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format g729_f = {
+       .name = "g729",
+       .exts = "g729",
+       .format = AST_FORMAT_G729A,
+       .write = g729_write,
+       .seek = g729_seek,
+       .trunc = g729_trunc,
+       .tell = g729_tell,
+       .read = g729_read,
+       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+       .lockp = &me,
+};
+
 int load_module()
 {
-       return ast_format_register(name, exts, AST_FORMAT_G729A,
-                                                               g729_open,
-                                                               g729_rewrite,
-                                                               g729_write,
-                                                               g729_seek,
-                                                               g729_trunc,
-                                                               g729_tell,
-                                                               g729_read,
-                                                               g729_close,
-                                                               g729_getcomment);
-                                                               
-                                                               
+       return ast_format_register(&g729_f);
 }
 
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(g729_f.name);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Raw G729 data";
 }
 
-
 char *key()
 {
        return ASTERISK_GPL_KEY;
index c6ef31f..3a27a11 100644 (file)
@@ -50,6 +50,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 /* Portions of the conversion code are by guido@sienanet.it */
 
+#define        GSM_FRAME_SIZE  33
+#define        GSM_SAMPLES     160
+
 /* silent gsm frame */
 /* begin binary data: */
 char gsm_silence[] = /* 33 */
@@ -58,111 +61,28 @@ char gsm_silence[] = /* 33 */
 ,0x92,0x49,0x24};
 /* end binary data. size = 33 bytes */
 
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
-       /* Believe it or not, we must decode/recode to account for the
-          weird MS format */
-       /* This is what a filestream means to us */
-       FILE *f; /* Descriptor */
-       struct ast_frame fr;                            /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                                                     /* Empty character */
-       unsigned char gsm[66];                          /* Two Real GSM Frames */
-};
-
-
-AST_MUTEX_DEFINE_STATIC(gsm_lock);
-static int glistcnt = 0;
-
-static char *name = "gsm";
-static char *desc = "Raw GSM data";
-static char *exts = "gsm";
-
-static struct ast_filestream *gsm_open(FILE *f)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&gsm_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock gsm list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->fr.data = tmp->gsm;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_GSM;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name;
-               tmp->fr.mallocd = 0;
-               glistcnt++;
-               ast_mutex_unlock(&gsm_lock);
-               ast_update_use_count();
-       }
-       return tmp;
-}
-
-static struct ast_filestream *gsm_rewrite(FILE *f, const char *comment)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&gsm_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock gsm list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               glistcnt++;
-               ast_mutex_unlock(&gsm_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
-}
-
-static void gsm_close(struct ast_filestream *s)
-{
-       if (ast_mutex_lock(&gsm_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock gsm list\n");
-               return;
-       }
-       glistcnt--;
-       ast_mutex_unlock(&gsm_lock);
-       ast_update_use_count();
-       fclose(s->f);
-       free(s);
-}
-
 static struct ast_frame *gsm_read(struct ast_filestream *s, int *whennext)
 {
        int res;
+
        s->fr.frametype = AST_FRAME_VOICE;
        s->fr.subclass = AST_FORMAT_GSM;
-       s->fr.offset = AST_FRIENDLY_OFFSET;
-       s->fr.samples = 160;
-       s->fr.datalen = 33;
+       FR_SET_BUF(&(s->fr), s->buf, AST_FRIENDLY_OFFSET, GSM_FRAME_SIZE)
        s->fr.mallocd = 0;
-       s->fr.data = s->gsm;
-       if ((res = fread(s->gsm, 1, 33, s->f)) != 33) {
+       if ((res = fread(s->fr.data, 1, GSM_FRAME_SIZE, s->f)) != GSM_FRAME_SIZE) {
                if (res)
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
                return NULL;
        }
-       *whennext = 160;
+       *whennext = s->fr.samples = GSM_SAMPLES;
        return &s->fr;
 }
 
 static int gsm_write(struct ast_filestream *fs, struct ast_frame *f)
 {
        int res;
-       unsigned char gsm[66];
+       unsigned char gsm[2*GSM_FRAME_SIZE];
+
        if (f->frametype != AST_FRAME_VOICE) {
                ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
                return -1;
@@ -176,14 +96,14 @@ static int gsm_write(struct ast_filestream *fs, struct ast_frame *f)
                int len=0;
                while(len < f->datalen) {
                        conv65(f->data + len, gsm);
-                       if ((res = fwrite(gsm, 1, 66, fs->f)) != 66) {
+                       if ((res = fwrite(gsm, 1, 2*GSM_FRAME_SIZE, fs->f)) != 2*GSM_FRAME_SIZE) {
                                ast_log(LOG_WARNING, "Bad write (%d/66): %s\n", res, strerror(errno));
                                return -1;
                        }
                        len += 65;
                }
        } else {
-               if (f->datalen % 33) {
+               if (f->datalen % GSM_FRAME_SIZE) {
                        ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 33\n", f->datalen);
                        return -1;
                }
@@ -204,7 +124,7 @@ static int gsm_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
        fseeko(fs->f, 0, SEEK_END);
        max = ftello(fs->f);
        /* have to fudge to frame here, so not fully to sample */
-       distance = (sample_offset/160) * 33;
+       distance = (sample_offset/GSM_SAMPLES) * GSM_FRAME_SIZE;
        if(whence == SEEK_SET)
                offset = distance;
        else if(whence == SEEK_CUR || whence == SEEK_FORCECUR)
@@ -218,8 +138,8 @@ static int gsm_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
        } else if (offset > max) {
                int i;
                fseeko(fs->f, 0, SEEK_END);
-               for (i=0; i< (offset - max) / 33; i++) {
-                       fwrite(gsm_silence, 1, 33, fs->f);
+               for (i=0; i< (offset - max) / GSM_FRAME_SIZE; i++) {
+                       fwrite(gsm_silence, 1, GSM_FRAME_SIZE, fs->f);
                }
        }
        return fseeko(fs->f, offset, SEEK_SET);
@@ -232,48 +152,45 @@ static int gsm_trunc(struct ast_filestream *fs)
 
 static off_t gsm_tell(struct ast_filestream *fs)
 {
-       off_t offset;
-       offset = ftello(fs->f);
-       return (offset/33)*160;
+       off_t offset = ftello(fs->f);
+       return (offset/GSM_FRAME_SIZE)*GSM_SAMPLES;
 }
 
-static char *gsm_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format gsm_f = {
+       .name = "gsm",
+       .exts = "gsm",
+       .format = AST_FORMAT_GSM,
+       .write = gsm_write,
+       .seek = gsm_seek,
+       .trunc = gsm_trunc,
+       .tell = gsm_tell,
+       .read = gsm_read,
+       .buf_size = 2*GSM_FRAME_SIZE + AST_FRIENDLY_OFFSET,     /* 2 gsm frames */
+       .lockp = &me,
+};
 
 int load_module()
 {
-       return ast_format_register(name, exts, AST_FORMAT_GSM,
-                                                               gsm_open,
-                                                               gsm_rewrite,
-                                                               gsm_write,
-                                                               gsm_seek,
-                                                               gsm_trunc,
-                                                               gsm_tell,
-                                                               gsm_read,
-                                                               gsm_close,
-                                                               gsm_getcomment);
-                                                               
-                                                               
+       return ast_format_register(&gsm_f);
 }
 
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(gsm_f.name);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Raw GSM data";
 }
 
-
 char *key()
 {
        return ASTERISK_GPL_KEY;
index 45692a3..fa5b5c6 100644 (file)
@@ -48,133 +48,60 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 /* Portions of the conversion code are by guido@sienanet.it */
 
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
-       /* Believe it or not, we must decode/recode to account for the
-          weird MS format */
-       /* This is what a filestream means to us */
-       FILE *f; /* Descriptor */
+#define        BUF_SIZE        4096    /* Two Real h263 Frames */
+
+struct h263_desc {
        unsigned int lastts;
-       struct ast_frame fr;                            /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                                                     /* Empty character */
-       unsigned char h263[4096];                               /* Two Real h263 Frames */
 };
 
 
-AST_MUTEX_DEFINE_STATIC(h263_lock);
-static int glistcnt = 0;
-
-static char *name = "h263";
-static char *desc = "Raw h263 data";
-static char *exts = "h263";
-
-static struct ast_filestream *h263_open(FILE *f)
+static int h263_open(struct ast_filestream *s)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
        unsigned int ts;
        int res;
-       if ((res = fread(&ts, 1, sizeof(ts), f)) < sizeof(ts)) {
-               ast_log(LOG_WARNING, "Empty file!\n");
-               return NULL;
-       }
-               
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&h263_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock h263 list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->fr.data = tmp->h263;
-               tmp->fr.frametype = AST_FRAME_VIDEO;
-               tmp->fr.subclass = AST_FORMAT_H263;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name;
-               tmp->fr.mallocd = 0;
-               glistcnt++;
-               ast_mutex_unlock(&h263_lock);
-               ast_update_use_count();
-       }
-       return tmp;
-}
 
-static struct ast_filestream *h263_rewrite(FILE *f, const char *comment)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&h263_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock h263 list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               glistcnt++;
-               ast_mutex_unlock(&h263_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
-}
-
-static void h263_close(struct ast_filestream *s)
-{
-       if (ast_mutex_lock(&h263_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock h263 list\n");
-               return;
+       if ((res = fread(&ts, 1, sizeof(ts), s->f)) < sizeof(ts)) {
+               ast_log(LOG_WARNING, "Empty file!\n");
+               return -1;
        }
-       glistcnt--;
-       ast_mutex_unlock(&h263_lock);
-       ast_update_use_count();
-       fclose(s->f);
-       free(s);
-       s = NULL;
+       return 0;
 }
 
 static struct ast_frame *h263_read(struct ast_filestream *s, int *whennext)
 {
        int res;
-       int mark=0;
+       int mark;
        unsigned short len;
        unsigned int ts;
+       struct h263_desc *fs = (struct h263_desc *)s->private;
+
        /* Send a frame from the file to the appropriate channel */
-       s->fr.frametype = AST_FRAME_VIDEO;
-       s->fr.subclass = AST_FORMAT_H263;
-       s->fr.offset = AST_FRIENDLY_OFFSET;
-       s->fr.mallocd = 0;
-       s->fr.data = s->h263;
-       if ((res = fread(&len, 1, sizeof(len), s->f)) < 1) {
+       if ((res = fread(&len, 1, sizeof(len), s->f)) < 1)
                return NULL;
-       }
        len = ntohs(len);
-       if (len & 0x8000) {
-               mark = 1;
-       }
+       mark = (len & 0x8000) ? 1 : 0;
        len &= 0x7fff;
-       if (len > sizeof(s->h263)) {
+       if (len > BUF_SIZE) {
                ast_log(LOG_WARNING, "Length %d is too long\n", len);
+               len = BUF_SIZE; /* XXX truncate ? */
        }
-       if ((res = fread(s->h263, 1, len, s->f)) != len) {
+       s->fr.frametype = AST_FRAME_VIDEO;
+       s->fr.subclass = AST_FORMAT_H263;
+       s->fr.mallocd = 0;
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, len);
+       if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
                if (res)
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
                return NULL;
        }
-       s->fr.samples = s->lastts;
+       s->fr.samples = fs->lastts;     /* XXX what ? */
        s->fr.datalen = len;
        s->fr.subclass |= mark;
        s->fr.delivery.tv_sec = 0;
        s->fr.delivery.tv_usec = 0;
        if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) {
-               s->lastts = ntohl(ts);
-               *whennext = s->lastts * 4/45;
+               fs->lastts = ntohl(ts);
+               *whennext = fs->lastts * 4/45;
        } else
                *whennext = 0;
        return &s->fr;
@@ -216,11 +143,6 @@ static int h263_write(struct ast_filestream *fs, struct ast_frame *f)
        return 0;
 }
 
-static char *h263_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
-
 static int h263_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
 {
        /* No way Jose */
@@ -237,44 +159,47 @@ static int h263_trunc(struct ast_filestream *fs)
 
 static off_t h263_tell(struct ast_filestream *fs)
 {
-       /* XXX This is totally bogus XXX */
-       off_t offset;
-       offset = ftello(fs->f);
-       return (offset/20)*160;
+       off_t offset = ftello(fs->f);
+       return offset;  /* XXX totally bogus, needs fixing */
 }
 
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format h263_f = {
+       .name = "h263",
+       .exts = "h264",
+       .format = AST_FORMAT_H263,
+       .open = h263_open,
+       .write = h263_write,
+       .seek = h263_seek,
+       .trunc = h263_trunc,
+       .tell = h263_tell,
+       .read = h263_read,
+       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+       .desc_size = sizeof(struct h263_desc),
+       .lockp = &me,
+};
+
 int load_module()
 {
-       return ast_format_register(name, exts, AST_FORMAT_H263,
-                                                               h263_open,
-                                                               h263_rewrite,
-                                                               h263_write,
-                                                               h263_seek,
-                                                               h263_trunc,
-                                                               h263_tell,
-                                                               h263_read,
-                                                               h263_close,
-                                                               h263_getcomment);
-                                                               
-                                                               
+       return ast_format_register(&h263_f);
 }
 
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(h263_f.name);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Raw h263 data";
 }
 
-
 char *key()
 {
        return ASTERISK_GPL_KEY;
index 185b268..5beb826 100644 (file)
@@ -47,96 +47,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 /* Some Ideas for this code came from makeh264e.c by Jeffrey Chilton */
 
 /* Portions of the conversion code are by guido@sienanet.it */
-
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
-       /* Believe it or not, we must decode/recode to account for the
-          weird MS format */
-       /* This is what a filestream means to us */
-       FILE *f; /* Descriptor */
+#define BUF_SIZE       4096    /* Two Real h264 Frames */
+struct h264_desc {
        unsigned int lastts;
-       struct ast_frame fr;                            /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                                                     /* Empty character */
-       unsigned char h264[4096];                               /* Two Real h264 Frames */
 };
 
-
-AST_MUTEX_DEFINE_STATIC(h264_lock);
-static int glistcnt = 0;
-
-static char *name = "h264";
-static char *desc = "Raw h264 data";
-static char *exts = "h264";
-
-static struct ast_filestream *h264_open(FILE *f)
+static int h264_open(struct ast_filestream *s)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
        unsigned int ts;
        int res;
-       if ((res = fread(&ts, 1, sizeof(ts), f)) < sizeof(ts)) {
+       if ((res = fread(&ts, 1, sizeof(ts), s->f)) < sizeof(ts)) {
                ast_log(LOG_WARNING, "Empty file!\n");
-               return NULL;
-       }
-               
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&h264_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock h264 list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->fr.data = tmp->h264;
-               tmp->fr.frametype = AST_FRAME_VIDEO;
-               tmp->fr.subclass = AST_FORMAT_H264;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name;
-               tmp->fr.mallocd = 0;
-               glistcnt++;
-               ast_mutex_unlock(&h264_lock);
-               ast_update_use_count();
-       }
-       return tmp;
-}
-
-static struct ast_filestream *h264_rewrite(FILE *f, const char *comment)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&h264_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock h264 list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               glistcnt++;
-               ast_mutex_unlock(&h264_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
-}
-
-static void h264_close(struct ast_filestream *s)
-{
-       if (ast_mutex_lock(&h264_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock h264 list\n");
-               return;
+               return -1;
        }
-       glistcnt--;
-       ast_mutex_unlock(&h264_lock);
-       ast_update_use_count();
-       fclose(s->f);
-       free(s);
-       s = NULL;
+       return 0;
 }
 
 static struct ast_frame *h264_read(struct ast_filestream *s, int *whennext)
@@ -145,82 +69,73 @@ static struct ast_frame *h264_read(struct ast_filestream *s, int *whennext)
        int mark=0;
        unsigned short len;
        unsigned int ts;
+       struct h264_desc *fs = (struct h264_desc *)s->private;
+
        /* Send a frame from the file to the appropriate channel */
-       s->fr.frametype = AST_FRAME_VIDEO;
-       s->fr.subclass = AST_FORMAT_H264;
-       s->fr.offset = AST_FRIENDLY_OFFSET;
-       s->fr.mallocd = 0;
-       s->fr.data = s->h264;
-       if ((res = fread(&len, 1, sizeof(len), s->f)) < 1) {
+       if ((res = fread(&len, 1, sizeof(len), s->f)) < 1)
                return NULL;
-       }
        len = ntohs(len);
-       if (len & 0x8000) {
-               mark = 1;
-       }
+       mark = (len & 0x8000) ? 1 : 0;
        len &= 0x7fff;
-       if (len > sizeof(s->h264)) {
+       if (len > BUF_SIZE) {
                ast_log(LOG_WARNING, "Length %d is too long\n", len);
+               len = BUF_SIZE; /* XXX truncate */
        }
-       if ((res = fread(s->h264, 1, len, s->f)) != len) {
+       s->fr.frametype = AST_FRAME_VIDEO;
+       s->fr.subclass = AST_FORMAT_H264;
+       s->fr.mallocd = 0;
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, len);
+       if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
                if (res)
                        ast_log(LOG_WARNING, "Short read (%d of %d) (%s)!\n", res, len, strerror(errno));
                return NULL;
        }
-       s->fr.samples = s->lastts;
+       s->fr.samples = fs->lastts;
        s->fr.datalen = len;
        s->fr.subclass |= mark;
        s->fr.delivery.tv_sec = 0;
        s->fr.delivery.tv_usec = 0;
        if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) {
-               s->lastts = ntohl(ts);
-               *whennext = s->lastts * 4/45;
+               fs->lastts = ntohl(ts);
+               *whennext = fs->lastts * 4/45;
        } else
                *whennext = 0;
        return &s->fr;
 }
 
-static int h264_write(struct ast_filestream *fs, struct ast_frame *f)
+static int h264_write(struct ast_filestream *s, struct ast_frame *f)
 {
        int res;
        unsigned int ts;
        unsigned short len;
-       int subclass;
-       int mark=0;
+       int mark;
+
        if (f->frametype != AST_FRAME_VIDEO) {
                ast_log(LOG_WARNING, "Asked to write non-video frame!\n");
                return -1;
        }
-       subclass = f->subclass;
-       if (subclass & 0x1)
-               mark=0x8000;
-       subclass &= ~0x1;
-       if (subclass != AST_FORMAT_H264) {
+       mark = (f->subclass & 0x1) ? 0x8000 : 0;
+       if ((f->subclass & ~0x1) != AST_FORMAT_H264) {
                ast_log(LOG_WARNING, "Asked to write non-h264 frame (%d)!\n", f->subclass);
                return -1;
        }
        ts = htonl(f->samples);
-       if ((res = fwrite(&ts, 1, sizeof(ts), fs->f)) != sizeof(ts)) {
-                       ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno));
-                       return -1;
+       if ((res = fwrite(&ts, 1, sizeof(ts), s->f)) != sizeof(ts)) {
+               ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno));
+               return -1;
        }
        len = htons(f->datalen | mark);
-       if ((res = fwrite(&len, 1, sizeof(len), fs->f)) != sizeof(len)) {
-                       ast_log(LOG_WARNING, "Bad write (%d/2): %s\n", res, strerror(errno));
-                       return -1;
+       if ((res = fwrite(&len, 1, sizeof(len), s->f)) != sizeof(len)) {
+               ast_log(LOG_WARNING, "Bad write (%d/2): %s\n", res, strerror(errno));
+               return -1;
        }
-       if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
-                       ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
-                       return -1;
+       if ((res = fwrite(f->data, 1, f->datalen, s->f)) != f->datalen) {
+               ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
+               return -1;
        }
        return 0;
 }
 
-static char *h264_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
-
 static int h264_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
 {
        /* No way Jose */
@@ -237,44 +152,47 @@ static int h264_trunc(struct ast_filestream *fs)
 
 static off_t h264_tell(struct ast_filestream *fs)
 {
-       /* XXX This is totally bogus XXX */
-       off_t offset;
-       offset = ftell(fs->f);
-       return (offset/20)*160;
+       off_t offset = ftell(fs->f);
+       return offset; /* XXX totally bogus, needs fixing */
 }
 
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format h264_f = {
+       .name = "h264",
+       .exts = "h264",
+       .format = AST_FORMAT_H264,
+       .open = h264_open,
+       .write = h264_write,
+       .seek = h264_seek,
+       .trunc = h264_trunc,
+       .tell = h264_tell,
+       .read = h264_read,
+       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+       .desc_size = sizeof(struct h264_desc),
+       .lockp = &me,
+};
+
 int load_module()
 {
-       return ast_format_register(name, exts, AST_FORMAT_H264,
-                                                               h264_open,
-                                                               h264_rewrite,
-                                                               h264_write,
-                                                               h264_seek,
-                                                               h264_trunc,
-                                                               h264_tell,
-                                                               h264_read,
-                                                               h264_close,
-                                                               h264_getcomment);
-                                                               
-                                                               
+       return ast_format_register(&h264_f);
 }
 
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(h264_f.name);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Raw h264 data";
 }
 
-
 char *key()
 {
        return ASTERISK_GPL_KEY;
index f0bcfbf..daaab39 100644 (file)
@@ -50,88 +50,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 /* Portions of the conversion code are by guido@sienanet.it */
 
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
-       /* Believe it or not, we must decode/recode to account for the
-          weird MS format */
-       /* This is what a filestream means to us */
-       FILE *f; /* Descriptor */
-       struct ast_frame fr;                            /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                                                     /* Empty character */
-       unsigned char ilbc[50];                         /* One Real iLBC Frame */
-};
-
-
-AST_MUTEX_DEFINE_STATIC(ilbc_lock);
-static int glistcnt = 0;
-
-static char *name = "iLBC";
-static char *desc = "Raw iLBC data";
-static char *exts = "ilbc";
-
-static struct ast_filestream *ilbc_open(FILE *f)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&ilbc_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock ilbc list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->fr.data = tmp->ilbc;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_ILBC;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name;
-               tmp->fr.mallocd = 0;
-               glistcnt++;
-               ast_mutex_unlock(&ilbc_lock);
-               ast_update_use_count();
-       }
-       return tmp;
-}
-
-static struct ast_filestream *ilbc_rewrite(FILE *f, const char *comment)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&ilbc_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock ilbc list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               glistcnt++;
-               ast_mutex_unlock(&ilbc_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
-}
-
-static void ilbc_close(struct ast_filestream *s)
-{
-       if (ast_mutex_lock(&ilbc_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock ilbc list\n");
-               return;
-       }
-       glistcnt--;
-       ast_mutex_unlock(&ilbc_lock);
-       ast_update_use_count();
-       fclose(s->f);
-       free(s);
-       s = NULL;
-}
+#define        ILBC_BUF_SIZE   50      /* One Real iLBC Frame */
+#define        ILBC_SAMPLES    240
 
 static struct ast_frame *ilbc_read(struct ast_filestream *s, int *whennext)
 {
@@ -139,17 +59,14 @@ static struct ast_frame *ilbc_read(struct ast_filestream *s, int *whennext)
        /* Send a frame from the file to the appropriate channel */
        s->fr.frametype = AST_FRAME_VOICE;
        s->fr.subclass = AST_FORMAT_ILBC;
-       s->fr.offset = AST_FRIENDLY_OFFSET;
-       s->fr.samples = 240;
-       s->fr.datalen = 50;
        s->fr.mallocd = 0;
-       s->fr.data = s->ilbc;
-       if ((res = fread(s->ilbc, 1, 50, s->f)) != 50) {
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, ILBC_BUF_SIZE);
+       if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
                if (res)
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
                return NULL;
        }
-       *whennext = s->fr.samples;
+       *whennext = s->fr.samples = ILBC_SAMPLES;
        return &s->fr;
 }
 
@@ -175,11 +92,6 @@ static int ilbc_write(struct ast_filestream *fs, struct ast_frame *f)
        return 0;
 }
 
-static char *ilbc_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
-
 static int ilbc_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
 {
        long bytes;
@@ -189,7 +101,7 @@ static int ilbc_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
        fseeko(fs->f, 0, SEEK_END);
        max = ftello(fs->f);
        
-       bytes = 50 * (sample_offset / 240);
+       bytes = ILBC_BUF_SIZE * (sample_offset / ILBC_SAMPLES);
        if (whence == SEEK_SET)
                offset = bytes;
        else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
@@ -216,43 +128,46 @@ static int ilbc_trunc(struct ast_filestream *fs)
 
 static off_t ilbc_tell(struct ast_filestream *fs)
 {
-       off_t offset;
-       offset = ftello(fs->f);
-       return (offset/50)*240;
+       off_t offset = ftello(fs->f);
+       return (offset/ILBC_BUF_SIZE)*ILBC_SAMPLES;
 }
 
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format ilbc_f = {
+       .name = "iLBC",
+       .exts = "ilbc",
+       .format = AST_FORMAT_ILBC,
+       .write = ilbc_write,
+       .seek = ilbc_seek,
+       .trunc = ilbc_trunc,
+       .tell = ilbc_tell,
+       .read = ilbc_read,
+       .buf_size = ILBC_BUF_SIZE + AST_FRIENDLY_OFFSET,
+       .lockp = &me,
+};
+
 int load_module()
 {
-       return ast_format_register(name, exts, AST_FORMAT_ILBC,
-                                                               ilbc_open,
-                                                               ilbc_rewrite,
-                                                               ilbc_write,
-                                                               ilbc_seek,
-                                                               ilbc_trunc,
-                                                               ilbc_tell,
-                                                               ilbc_read,
-                                                               ilbc_close,
-                                                               ilbc_getcomment);
-                                                               
-                                                               
+       return ast_format_register(&ilbc_f);
 }
 
+
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(ilbc_f.name);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Raw iLBC data";
 }
 
-
 char *key()
 {
        return ASTERISK_GPL_KEY;
index 0437a38..061684f 100644 (file)
@@ -51,11 +51,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #define SAMPLES_MAX 160
 #define BLOCK_SIZE 4096
 
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
-       
-       FILE *f;
-       
+struct vorbis_desc {
        /* structures for handling the Ogg container */
        ogg_sync_state oy;
        ogg_stream_state os;
@@ -73,14 +69,6 @@ struct ast_filestream {
        
        /*! \brief Indicates whether an End of Stream condition has been detected. */
        int eos;
-       
-       /*! \brief Buffer to hold audio data. */
-       short buffer[SAMPLES_MAX];
-       
-       /*! \brief Asterisk frame object. */
-       struct ast_frame fr;
-       char waste[AST_FRIENDLY_OFFSET];
-       char empty;
 };
 
 AST_MUTEX_DEFINE_STATIC(ogg_vorbis_lock);
@@ -96,176 +84,123 @@ static char *exts = "ogg";
  * \param f File that points to on disk storage of the OGG/Vorbis data.
  * \return The new filestream.
  */
-static struct ast_filestream *ogg_vorbis_open(FILE * f)
+static int ogg_vorbis_open(struct ast_filestream *s)
 {
        int i;
        int bytes;
        int result;
        char **ptr;
        char *buffer;
+       struct vorbis_desc *tmp = (struct vorbis_desc *)s->private;
 
-       struct ast_filestream *tmp;
-
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-
-               tmp->writing = 0;
-               tmp->f = f;
-
-               ogg_sync_init(&tmp->oy);
+       tmp->writing = 0;
+       tmp->f = f;
 
-               buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
-               bytes = fread(buffer, 1, BLOCK_SIZE, f);
-               ogg_sync_wrote(&tmp->oy, bytes);
-
-               result = ogg_sync_pageout(&tmp->oy, &tmp->og);
-               if (result != 1) {
-                       if (bytes < BLOCK_SIZE) {
-                               ast_log(LOG_ERROR, "Run out of data...\n");
-                       } else {
-                               ast_log(LOG_ERROR,
-                                               "Input does not appear to be an Ogg bitstream.\n");
-                       }
-                       fclose(f);
-                       ogg_sync_clear(&tmp->oy);
-                       free(tmp);
-                       return NULL;
-               }
-
-               ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og));
-               vorbis_info_init(&tmp->vi);
-               vorbis_comment_init(&tmp->vc);
-
-               if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) {
-                       ast_log(LOG_ERROR,
-                                       "Error reading first page of Ogg bitstream data.\n");
-                       fclose(f);
-                       ogg_stream_clear(&tmp->os);
-                       vorbis_comment_clear(&tmp->vc);
-                       vorbis_info_clear(&tmp->vi);
-                       ogg_sync_clear(&tmp->oy);
-                       free(tmp);
-                       return NULL;
-               }
+       ogg_sync_init(&tmp->oy);
 
-               if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) {
-                       ast_log(LOG_ERROR, "Error reading initial header packet.\n");
-                       fclose(f);
-                       ogg_stream_clear(&tmp->os);
-                       vorbis_comment_clear(&tmp->vc);
-                       vorbis_info_clear(&tmp->vi);
-                       ogg_sync_clear(&tmp->oy);
-                       free(tmp);
-                       return NULL;
-               }
+       buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
+       bytes = fread(buffer, 1, BLOCK_SIZE, f);
+       ogg_sync_wrote(&tmp->oy, bytes);
 
-               if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) {
-                       ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n");
-                       fclose(f);
-                       ogg_stream_clear(&tmp->os);
-                       vorbis_comment_clear(&tmp->vc);
-                       vorbis_info_clear(&tmp->vi);
-                       ogg_sync_clear(&tmp->oy);
-                       free(tmp);
-                       return NULL;
+       result = ogg_sync_pageout(&tmp->oy, &tmp->og);
+       if (result != 1) {
+               if(bytes < BLOCK_SIZE) {
+                       ast_log(LOG_ERROR, "Run out of data...\n");
+               } else {
+                       ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n");
                }
-
-               i = 0;
+               ogg_sync_clear(&tmp->oy);
+               return -1;
+       }
+       
+       ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og));
+       vorbis_info_init(&tmp->vi);
+       vorbis_comment_init(&tmp->vc);
+
+       if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) { 
+               ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n");
+error:
+               ogg_stream_clear(&tmp->os);
+               vorbis_comment_clear(&tmp->vc);
+               vorbis_info_clear(&tmp->vi);
+               ogg_sync_clear(&tmp->oy);
+               return -1;
+       }
+       
+       if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) { 
+               ast_log(LOG_ERROR, "Error reading initial header packet.\n");
+               goto error;
+       }
+       
+       if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) { 
+               ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n");
+               goto error;
+       }
+       
+       for (i = 0; i < 2 ; ) {
                while (i < 2) {
-                       while (i < 2) {
-                               result = ogg_sync_pageout(&tmp->oy, &tmp->og);
-                               if (result == 0)
-                                       break;
-                               if (result == 1) {
-                                       ogg_stream_pagein(&tmp->os, &tmp->og);
-                                       while (i < 2) {
-                                               result = ogg_stream_packetout(&tmp->os, &tmp->op);
-                                               if (result == 0)
-                                                       break;
-                                               if (result < 0) {
-                                                       ast_log(LOG_ERROR, "Corrupt secondary header.  Exiting.\n");
-                                                       fclose(f);
-                                                       ogg_stream_clear(&tmp->os);
-                                                       vorbis_comment_clear(&tmp->vc);
-                                                       vorbis_info_clear(&tmp->vi);
-                                                       ogg_sync_clear(&tmp->oy);
-                                                       free(tmp);
-                                                       return NULL;
-                                               }
-                                               vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op);
-                                               i++;
+                       result = ogg_sync_pageout(&tmp->oy, &tmp->og);
+                       if (result == 0)
+                               break;
+                       if (result == 1) {
+                               ogg_stream_pagein(&tmp->os, &tmp->og);
+                               while(i < 2) {
+                                       result = ogg_stream_packetout(&tmp->os,&tmp->op);
+                                       if(result == 0)
+                                               break;
+                                       if(result < 0) {
+                                               ast_log(LOG_ERROR, "Corrupt secondary header.  Exiting.\n");
+                                               goto error;
                                        }
+                                       vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op);
+                                       i++;
                                }
                        }
-
-                       buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
-                       bytes = fread(buffer, 1, BLOCK_SIZE, f);
-                       if (bytes == 0 && i < 2) {
-                               ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n");
-                               fclose(f);
-                               ogg_stream_clear(&tmp->os);
-                               vorbis_comment_clear(&tmp->vc);
-                               vorbis_info_clear(&tmp->vi);
-                               ogg_sync_clear(&tmp->oy);
-                               free(tmp);
-                               return NULL;
-                       }
-                       ogg_sync_wrote(&tmp->oy, bytes);
-               }
-
-               ptr = tmp->vc.user_comments;
-               while (*ptr) {
-                       ast_log(LOG_DEBUG, "OGG/Vorbis comment: %s\n", *ptr);
-                       ++ptr;
                }
-               ast_log(LOG_DEBUG, "OGG/Vorbis bitstream is %d channel, %ldHz\n",
-                       tmp->vi.channels, tmp->vi.rate);
-               ast_log(LOG_DEBUG, "OGG/Vorbis file encoded by: %s\n",
-                       tmp->vc.vendor);
 
-               if (tmp->vi.channels != 1) {
-                       ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n");
-                       ogg_stream_clear(&tmp->os);
-                       vorbis_comment_clear(&tmp->vc);
-                       vorbis_info_clear(&tmp->vi);
-                       ogg_sync_clear(&tmp->oy);
-                       free(tmp);
-                       return NULL;
+               buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
+               bytes = fread(buffer, 1, BLOCK_SIZE, f);
+               if(bytes == 0 && i < 2) {
+                       ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n");
+                       goto error;
                }
+               ogg_sync_wrote(&tmp->oy, bytes);
+       }
+       
+       ptr = tmp->vc.user_comments;
+       while(*ptr){
+               ast_log(LOG_DEBUG, "OGG/Vorbis comment: %s\n", *ptr);
+               ++ptr;
+       }
+       ast_log(LOG_DEBUG, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate);
+       ast_log(LOG_DEBUG, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor);
 
-               if (tmp->vi.rate != 8000) {
-                       ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n");
-                       fclose(f);
-                       ogg_stream_clear(&tmp->os);
-                       vorbis_block_clear(&tmp->vb);
-                       vorbis_dsp_clear(&tmp->vd);
-                       vorbis_comment_clear(&tmp->vc);
-                       vorbis_info_clear(&tmp->vi);
-                       ogg_sync_clear(&tmp->oy);
-                       free(tmp);
-                       return NULL;
-               }
+       if(tmp->vi.channels != 1) {
+               ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n");
+               goto error;
+       }
+       
 
-               vorbis_synthesis_init(&tmp->vd, &tmp->vi);
-               vorbis_block_init(&tmp->vd, &tmp->vb);
+       if(tmp->vi.rate != DEFAULT_SAMPLE_RATE) {
+               ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n");
+               vorbis_block_clear(&tmp->vb);
+               vorbis_dsp_clear(&tmp->vd);
+               goto error;
+       }
+       
+       vorbis_synthesis_init(&tmp->vd, &tmp->vi);
+       vorbis_block_init(&tmp->vd, &tmp->vb);
 
-               if (ast_mutex_lock(&ogg_vorbis_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock ogg_vorbis list\n");
-                       fclose(f);
-                       ogg_stream_clear(&tmp->os);
-                       vorbis_block_clear(&tmp->vb);
-                       vorbis_dsp_clear(&tmp->vd);
-                       vorbis_comment_clear(&tmp->vc);
-                       vorbis_info_clear(&tmp->vi);
-                       ogg_sync_clear(&tmp->oy);
-                       free(tmp);
-                       return NULL;
-               }
-               glistcnt++;
-               ast_mutex_unlock(&ogg_vorbis_lock);
-               ast_update_use_count();
+       if(ast_mutex_lock(&ogg_vorbis_lock)) {
+               ast_log(LOG_WARNING, "Unable to lock ogg_vorbis list\n");
+               vorbis_block_clear(&tmp->vb);
+               vorbis_dsp_clear(&tmp->vd);
+               goto error;
        }
-       return tmp;
+       glistcnt++;
+       ast_mutex_unlock(&ogg_vorbis_lock);
+       ast_update_use_count();
+return 0;
 }
 
 /*!
@@ -291,7 +226,7 @@ static struct ast_filestream *ogg_vorbis_rewrite(FILE * f,
 
                vorbis_info_init(&tmp->vi);
 
-               if (vorbis_encode_init_vbr(&tmp->vi, 1, 8000, 0.4)) {
+               if (vorbis_encode_init_vbr(&tmp->vi, 1, DEFAULT_SAMPLE_RATE, 0.4)) {
                        ast_log(LOG_ERROR, "Unable to initialize Vorbis encoder!\n");
                        free(tmp);
                        return NULL;
@@ -440,9 +375,6 @@ static void ogg_vorbis_close(struct ast_filestream *s)
        if (s->writing) {
                ogg_sync_clear(&s->oy);
        }
-
-       fclose(s->f);
-       free(s);
 }
 
 /*!
@@ -643,18 +575,28 @@ static char *ogg_vorbis_getcomment(struct ast_filestream *s)
        return NULL;
 }
 
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format vorbis_f = {
+       .name =
+       .ext =
+       .format = AST_FORMAT_SLINEAR,
+       .open = ogg_vorbis_open,
+       .rewrite = ogg_vorbis_rewrite,
+       .write = ogg_vorbis_write,
+       .seek = ogg_vorbis_seek,
+       .trunc = ogg_vorbis_trunc,
+       .tell = ogg_vorbis_tell,
+       .read = ogg_vorbis_read,
+       .close = ogg_vorbis_close,
+       .buf_sie = BUF_SIZE + AST_FRIENDLY_OFFSET,
+       .desc_size = sizeof(struct vorbis_desc),
+       .lockp = &me,
+};
+
 int load_module()
 {
-       return ast_format_register(name, exts, AST_FORMAT_SLINEAR,
-                                  ogg_vorbis_open,
-                                  ogg_vorbis_rewrite,
-                                  ogg_vorbis_write,
-                                  ogg_vorbis_seek,
-                                  ogg_vorbis_trunc,
-                                  ogg_vorbis_tell,
-                                  ogg_vorbis_read,
-                                  ogg_vorbis_close,
-                                  ogg_vorbis_getcomment);
+       return ast_format_register(&vorbis_f);
 }
 
 int unload_module()
@@ -664,7 +606,7 @@ int unload_module()
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
index d3f73e3..4624de5 100644 (file)
@@ -45,135 +45,67 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
 #include "asterisk/ulaw.h"
+#include "asterisk/alaw.h"
 
-#define BUF_SIZE 160           /* 160 samples */
-
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
-       /* This is what a filestream means to us */
-       FILE *f; /* Descriptor */
-       struct ast_channel *owner;
-       struct ast_frame fr;                            /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                                                     /* Empty character */
-       unsigned char buf[BUF_SIZE];                            /* Output Buffer */
-       struct timeval last;
-};
-
+#define BUF_SIZE 160           /* 160 bytes, and same number of samples */
 
-AST_MUTEX_DEFINE_STATIC(pcm_lock);
-static int glistcnt = 0;
+static char ulaw_silence[BUF_SIZE];
+static char alaw_silence[BUF_SIZE];
 
-static char *name = "pcm";
-static char *desc = "Raw uLaw 8khz Audio support (PCM)";
-static char *exts = "pcm|ulaw|ul|mu";
+/* #define REALTIME_WRITE */   /* XXX does it work at all ? */
 
-static char ulaw_silence[BUF_SIZE];
+#ifdef REALTIME_WRITE
+struct pcm_desc {
+       unsigned long start_time;
+};
 
-static struct ast_filestream *pcm_open(FILE *f)
+/* Returns time in msec since system boot. */
+static unsigned long get_time(void)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&pcm_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock pcm list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->fr.data = tmp->buf;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_ULAW;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name;
-               tmp->fr.mallocd = 0;
-               glistcnt++;
-               ast_mutex_unlock(&pcm_lock);
-               ast_update_use_count();
+       struct tms buf;
+       clock_t cur;
+
+       cur = times( &buf );
+       if( cur < 0 ) {
+               ast_log( LOG_WARNING, "Cannot get current time\n" );
+               return 0;
        }
-       return tmp;
+       return cur * 1000 / sysconf( _SC_CLK_TCK );
 }
 
-static struct ast_filestream *pcm_rewrite(FILE *f, const char *comment)
+static int pcma_open(struct ast_filestream *s)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&pcm_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock pcm list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               glistcnt++;
-               ast_mutex_unlock(&pcm_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
+       if (s->fmt->format == AST_FORMAT_ALAW)
+               pd->starttime = get_time();
+       return 0;
 }
 
-static void pcm_close(struct ast_filestream *s)
+static int pcma_rewrite(struct ast_filestream *s, const char *comment)
 {
-       if (ast_mutex_lock(&pcm_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock pcm list\n");
-               return;
-       }
-       glistcnt--;
-       ast_mutex_unlock(&pcm_lock);
-       ast_update_use_count();
-       fclose(s->f);
-       free(s);
-       s = NULL;
+       return pcma_open(s);
 }
+#endif
 
 static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext)
 {
        int res;
-       int delay;
+       
        /* Send a frame from the file to the appropriate channel */
 
        s->fr.frametype = AST_FRAME_VOICE;
-       s->fr.subclass = AST_FORMAT_ULAW;
-       s->fr.offset = AST_FRIENDLY_OFFSET;
+       s->fr.subclass = s->fmt->format;
        s->fr.mallocd = 0;
-       s->fr.data = s->buf;
-       if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) {
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
+       if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) < 1) {
                if (res)
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
                return NULL;
        }
-       s->fr.samples = res;
        s->fr.datalen = res;
-       delay = s->fr.samples;
-       *whennext = delay;
+       *whennext = s->fr.samples = res;
        return &s->fr;
 }
 
-static int pcm_write(struct ast_filestream *fs, struct ast_frame *f)
-{
-       int res;
-       if (f->frametype != AST_FRAME_VOICE) {
-               ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
-               return -1;
-       }
-       if (f->subclass != AST_FORMAT_ULAW) {
-               ast_log(LOG_WARNING, "Asked to write non-ulaw frame (%d)!\n", f->subclass);
-               return -1;
-       }
-       if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
-                       ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
-                       return -1;
-       }
-       return 0;
-}
-
 static int pcm_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
 {
        off_t cur, max, offset = 0;
@@ -204,13 +136,13 @@ static int pcm_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
        }
        if (whence == SEEK_FORCECUR && offset > max) { /* extend the file */
                size_t left = offset - max;
+               const char *src = (fs->fmt->format == AST_FORMAT_ALAW) ? alaw_silence : ulaw_silence;
 
                while (left) {
-                       size_t written = fwrite(ulaw_silence, sizeof(ulaw_silence[0]),
-                                    (left > BUF_SIZE) ? BUF_SIZE : left, fs->f);
+                       size_t written = fwrite(src, 1, (left > BUF_SIZE) ? BUF_SIZE : left, fs->f);
                        if (written == -1)
                                break;  /* error */
-                       left -= written * sizeof(ulaw_silence[0]);
+                       left -= written;
                }
                ret = 0; /* successful */
        } else {
@@ -230,51 +162,336 @@ static int pcm_trunc(struct ast_filestream *fs)
 
 static off_t pcm_tell(struct ast_filestream *fs)
 {
-       off_t offset;
-       offset = ftello(fs->f);
-       return offset;
+       return ftello(fs->f);
 }
 
-static char *pcm_getcomment(struct ast_filestream *s)
+static int pcm_write(struct ast_filestream *fs, struct ast_frame *f)
 {
-       return NULL;
+       int res;
+
+       if (f->frametype != AST_FRAME_VOICE) {
+               ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+               return -1;
+       }
+       if (f->subclass != fs->fmt->format) {
+               ast_log(LOG_WARNING, "Asked to write incompatible format frame (%d)!\n", f->subclass);
+               return -1;
+       }
+
+#ifdef REALTIME_WRITE
+       if (s->fmt->format == AST_FORMAT_ALAW) {
+               struct pcm_desc *pd = (struct pcm_desc *)fs->private;
+               struct stat stat_buf;
+               unsigned long cur_time = get_time();
+               unsigned long fpos = ( cur_time - pd->start_time ) * 8; /* 8 bytes per msec */
+               /* Check if we have written to this position yet. If we have, then increment pos by one frame
+               *  for some degree of protection against receiving packets in the same clock tick.
+               */
+               
+               fstat(fileno(fs->f), &stat_buf );
+               if (stat_buf.st_size > fpos )
+                       fpos += f->datalen;     /* Incrementing with the size of this current frame */
+
+               if (stat_buf.st_size < fpos) {
+                       /* fill the gap with 0x55 rather than 0. */
+                       char buf[1024];
+                       unsigned long cur, to_write;
+
+                       cur = stat_buf.st_size;
+                       if (fseek(fs->f, cur, SEEK_SET) < 0) {
+                               ast_log( LOG_WARNING, "Cannot seek in file: %s\n", strerror(errno) );
+                               return -1;
+                       }
+                       memset(buf, 0x55, 512);
+                       while (cur < fpos) {
+                               to_write = fpos - cur;
+                               if (to_write > sizeof(buf))
+                                       to_write = sizeof(buf);
+                               fwrite(buf, 1, to_write, fs->f);
+                               cur += to_write;
+                       }
+               }
+
+               if (fseek(s->f, fpos, SEEK_SET) < 0) {
+                       ast_log( LOG_WARNING, "Cannot seek in file: %s\n", strerror(errno) );
+                       return -1;
+               }
+       }
+#endif /* REALTIME_WRITE */
+       
+       if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
+               ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
+               return -1;
+       }
+       return 0;
 }
 
+/* SUN .au support routines */
+
+#define AU_HEADER_SIZE         24
+#define AU_HEADER(var)         u_int32_t var[6]
+
+#define AU_HDR_MAGIC_OFF       0
+#define AU_HDR_HDR_SIZE_OFF    1
+#define AU_HDR_DATA_SIZE_OFF   2
+#define AU_HDR_ENCODING_OFF    3
+#define AU_HDR_SAMPLE_RATE_OFF 4
+#define AU_HDR_CHANNELS_OFF    5
+
+#define AU_ENC_8BIT_ULAW       1
+
+#define AU_MAGIC 0x2e736e64
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define htoll(b) (b)
+#define htols(b) (b)
+#define ltohl(b) (b)
+#define ltohs(b) (b)
+#else
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define htoll(b)  \
+          (((((b)      ) & 0xFF) << 24) | \
+              ((((b) >>  8) & 0xFF) << 16) | \
+                  ((((b) >> 16) & 0xFF) <<  8) | \
+                  ((((b) >> 24) & 0xFF)      ))
+#define htols(b) \
+          (((((b)      ) & 0xFF) << 8) | \
+                  ((((b) >> 8) & 0xFF)      ))
+#define ltohl(b) htoll(b)
+#define ltohs(b) htols(b)
+#else
+#error "Endianess not defined"
+#endif
+#endif
+
+static int check_header(FILE *f)
+{
+       AU_HEADER(header);
+       u_int32_t magic;
+       u_int32_t hdr_size;
+       u_int32_t data_size;
+       u_int32_t encoding;
+       u_int32_t sample_rate;
+       u_int32_t channels;
+
+       if (fread(header, 1, AU_HEADER_SIZE, f) != AU_HEADER_SIZE) {
+               ast_log(LOG_WARNING, "Read failed (header)\n");
+               return -1;
+       }
+       magic = ltohl(header[AU_HDR_MAGIC_OFF]);
+       if (magic != (u_int32_t) AU_MAGIC) {
+               ast_log(LOG_WARNING, "Bad magic: 0x%x\n", magic);
+       }
+/*     hdr_size = ltohl(header[AU_HDR_HDR_SIZE_OFF]);
+       if (hdr_size < AU_HEADER_SIZE)*/
+       hdr_size = AU_HEADER_SIZE;
+/*     data_size = ltohl(header[AU_HDR_DATA_SIZE_OFF]); */
+       encoding = ltohl(header[AU_HDR_ENCODING_OFF]);
+       if (encoding != AU_ENC_8BIT_ULAW) {
+               ast_log(LOG_WARNING, "Unexpected format: %d. Only 8bit ULAW allowed (%d)\n", encoding, AU_ENC_8BIT_ULAW);
+               return -1;
+       }
+       sample_rate = ltohl(header[AU_HDR_SAMPLE_RATE_OFF]);
+       if (sample_rate != DEFAULT_SAMPLE_RATE) {
+               ast_log(LOG_WARNING, "Sample rate can only be 8000 not %d\n", sample_rate);
+               return -1;
+       }
+       channels = ltohl(header[AU_HDR_CHANNELS_OFF]);
+       if (channels != 1) {
+               ast_log(LOG_WARNING, "Not in mono: channels=%d\n", channels);
+               return -1;
+       }
+       /* Skip to data */
+       fseek(f, 0, SEEK_END);
+       data_size = ftell(f) - hdr_size;
+       if (fseek(f, hdr_size, SEEK_SET) == -1 ) {
+               ast_log(LOG_WARNING, "Failed to skip to data: %d\n", hdr_size);
+               return -1;
+       }
+       return data_size;
+}
+
+static int update_header(FILE *f)
+{
+       off_t cur, end;
+       u_int32_t datalen;
+       int bytes;
+
+       cur = ftell(f);
+       fseek(f, 0, SEEK_END);
+       end = ftell(f);
+       /* data starts 24 bytes in */
+       bytes = end - AU_HEADER_SIZE;
+       datalen = htoll(bytes);
+
+       if (cur < 0) {
+               ast_log(LOG_WARNING, "Unable to find our position\n");
+               return -1;
+       }
+       if (fseek(f, AU_HDR_DATA_SIZE_OFF * sizeof(u_int32_t), SEEK_SET)) {
+               ast_log(LOG_WARNING, "Unable to set our position\n");
+               return -1;
+       }
+       if (fwrite(&datalen, 1, sizeof(datalen), f) != sizeof(datalen)) {
+               ast_log(LOG_WARNING, "Unable to set write file size\n");
+               return -1;
+       }
+       if (fseek(f, cur, SEEK_SET)) {
+               ast_log(LOG_WARNING, "Unable to return to position\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int write_header(FILE *f)
+{
+       AU_HEADER(header);
+
+       header[AU_HDR_MAGIC_OFF] = htoll((u_int32_t) AU_MAGIC);
+       header[AU_HDR_HDR_SIZE_OFF] = htoll(AU_HEADER_SIZE);
+       header[AU_HDR_DATA_SIZE_OFF] = 0;
+       header[AU_HDR_ENCODING_OFF] = htoll(AU_ENC_8BIT_ULAW);
+       header[AU_HDR_SAMPLE_RATE_OFF] = htoll(DEFAULT_SAMPLE_RATE);
+       header[AU_HDR_CHANNELS_OFF] = htoll(1);
+
+       /* Write an au header, ignoring sizes which will be filled in later */
+       fseek(f, 0, SEEK_SET);
+       if (fwrite(header, 1, AU_HEADER_SIZE, f) != AU_HEADER_SIZE) {
+               ast_log(LOG_WARNING, "Unable to write header\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int au_open(struct ast_filestream *s)
+{
+       if (check_header(s->f) < 0)
+               return -1;
+       return 0;
+}
+
+static int au_rewrite(struct ast_filestream *s, const char *comment)
+{
+       if (write_header(s->f))
+               return -1;
+       return 0;
+}
+
+/* XXX check this, probably incorrect */
+static int au_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
+{
+       off_t min, max, cur;
+       long offset = 0, samples;
+       
+       samples = sample_offset;
+       min = AU_HEADER_SIZE;
+       cur = ftello(fs->f);
+       fseek(fs->f, 0, SEEK_END);
+       max = ftello(fs->f);
+       if (whence == SEEK_SET)
+               offset = samples + min;
+       else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
+               offset = samples + cur;
+       else if (whence == SEEK_END)
+               offset = max - samples;
+        if (whence != SEEK_FORCECUR) {
+               offset = (offset > max) ? max : offset;
+       }
+       /* always protect the header space. */
+       offset = (offset < min) ? min : offset;
+       return fseeko(fs->f, offset, SEEK_SET);
+}
+
+static int au_trunc(struct ast_filestream *fs)
+{
+       if (ftruncate(fileno(fs->f), ftell(fs->f)))
+               return -1;
+       return update_header(fs->f);
+}
+
+static off_t au_tell(struct ast_filestream *fs)
+{
+       off_t offset = ftello(fs->f);
+       return offset - AU_HEADER_SIZE;
+}
+
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format alaw_f = {
+       .name = "alaw",
+       .exts = "alaw|al",
+       .format = AST_FORMAT_ALAW,
+       .write = pcm_write,
+       .seek = pcm_seek,
+       .trunc = pcm_trunc,
+       .tell = pcm_tell,
+       .read = pcm_read,
+       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+       .lockp = &me,
+#ifdef REALTIME_WRITE
+       .open = pcma_open,
+       .rewrite = pcma_rewrite,
+       .desc_size = sizeof(struct pcm_desc),
+#endif
+};
+
+static const struct ast_format pcm_f = {
+       .name = "pcm",
+       .exts = "pcm|ulaw|ul|mu",
+       .format = AST_FORMAT_ULAW,
+       .write = pcm_write,
+       .seek = pcm_seek,
+       .trunc = pcm_trunc,
+       .tell = pcm_tell,
+       .read = pcm_read,
+       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+       .lockp = &me,
+};
+
+static const struct ast_format au_f = {
+       .name = "au",
+       .exts = "au",
+       .format = AST_FORMAT_ULAW,
+       .open = au_open,
+       .rewrite = au_rewrite,
+       .write = pcm_write,
+       .seek = au_seek,
+       .trunc = au_trunc,
+       .tell = au_tell,
+       .read = pcm_read,
+       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,     /* this many shorts */
+       .lockp = &me,
+};
+
 int load_module()
 {
        int index;
 
+       /* XXX better init ? */
        for (index = 0; index < (sizeof(ulaw_silence) / sizeof(ulaw_silence[0])); index++)
                ulaw_silence[index] = AST_LIN2MU(0);
+       for (index = 0; index < (sizeof(alaw_silence) / sizeof(alaw_silence[0])); index++)
+               alaw_silence[index] = AST_LIN2A(0);
 
-       return ast_format_register(name, exts, AST_FORMAT_ULAW,
-                                  pcm_open,
-                                  pcm_rewrite,
-                                  pcm_write,
-                                  pcm_seek,
-                                  pcm_trunc,
-                                  pcm_tell,
-                                  pcm_read,
-                                  pcm_close,
-                                  pcm_getcomment);
+       return ast_format_register(&pcm_f) || ast_format_register(&alaw_f)
+               || ast_format_register(&au_f);
 }
 
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(pcm_f.name) || ast_format_unregister(alaw_f.name)
+               || ast_format_unregister(au_f.name);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Raw/Sun uLaw/ALaw 8khz Audio support (PCM,PCMA,AU)";
 }
 
-
 char *key()
 {
        return ASTERISK_GPL_KEY;
index af1705f..dcca10a 100644 (file)
@@ -47,42 +47,25 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/endian.h"
 #include "asterisk/alaw.h"
 
-#define BUF_SIZE 160           /* 160 samples */
-
-/* #define REALTIME_WRITE */
-
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
-       /* Believe it or not, we must decode/recode to account for the
-          weird MS format */
-       /* This is what a filestream means to us */
-       FILE *f; /* Descriptor */
-       struct ast_frame fr;                            /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                                                     /* Empty character */
-       unsigned char buf[BUF_SIZE];                            /* Output Buffer */
+#define BUF_SIZE 160           /* 160 bytes, and same number of samples */
+
+/* #define REALTIME_WRITE */   /* XXX does it work at all ? */
+
+struct pcma_desc {
 #ifdef REALTIME_WRITE
        unsigned long start_time;
 #endif
 };
 
-
-AST_MUTEX_DEFINE_STATIC(pcm_lock);
-static int glistcnt = 0;
-
-static char *name = "alaw";
-static char *desc = "Raw aLaw 8khz PCM Audio support";
-static char *exts = "alaw|al";
-
 static char alaw_silence[BUF_SIZE];
 
-
 #if 0
 /* Returns time in msec since system boot. */
-static unsigned long get_time(void)
+static unsigned long get_time(struct ast_filestream *s)
 {
        struct tms buf;
        clock_t cur;
+       unsigned long *res;
 
        cur = times( &buf );
        if( cur < 0 )
@@ -90,77 +73,26 @@ static unsigned long get_time(void)
                ast_log( LOG_WARNING, "Cannot get current time\n" );
                return 0;
        }
-       return cur * 1000 / sysconf( _SC_CLK_TCK );
-}
-#endif
-
-static struct ast_filestream *pcm_open(FILE *f)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&pcm_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock pcm list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->fr.data = tmp->buf;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_ALAW;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name;
-               tmp->fr.mallocd = 0;
-#ifdef REALTIME_WRITE
-               tmp->start_time = get_time();
-#endif
-               glistcnt++;
-               ast_mutex_unlock(&pcm_lock);
-               ast_update_use_count();
+       res = cur * 1000 / sysconf( _SC_CLK_TCK );
+       if (s) {
+               struct pcma_desc *d = (struct pcma_filestream *)s->private;
+               d->start_time = res;
        }
-       return tmp;
+       return res;
 }
+#endif
 
-static struct ast_filestream *pcm_rewrite(FILE *f, const char *comment)
+static int pcm_open(struct ast_filestream *s)
 {
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&pcm_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock pcm list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
 #ifdef REALTIME_WRITE
-               tmp->start_time = get_time();
+       get_time(s);
 #endif
-               glistcnt++;
-               ast_mutex_unlock(&pcm_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
+       return 0;
 }
 
-static void pcm_close(struct ast_filestream *s)
+static int pcm_rewrite(struct ast_filestream *s, const char *comment)
 {
-       if (ast_mutex_lock(&pcm_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock pcm list\n");
-               return;
-       }
-       glistcnt--;
-       ast_mutex_unlock(&pcm_lock);
-       ast_update_use_count();
-       fclose(s->f);
-       free(s);
-       s = NULL;
+       return pcm_open(s);
 }
 
 static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext)
@@ -170,17 +102,15 @@ static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext)
 
        s->fr.frametype = AST_FRAME_VOICE;
        s->fr.subclass = AST_FORMAT_ALAW;
-       s->fr.offset = AST_FRIENDLY_OFFSET;
        s->fr.mallocd = 0;
-       s->fr.data = s->buf;
-       if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) {
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
+       if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) < 1) {
                if (res)
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
                return NULL;
        }
-       s->fr.samples = res;
        s->fr.datalen = res;
-       *whennext = s->fr.samples;
+       *whennext = s->fr.samples = res;
        return &s->fr;
 }
 
@@ -191,6 +121,7 @@ static int pcm_write(struct ast_filestream *fs, struct ast_frame *f)
        unsigned long cur_time;
        unsigned long fpos;
        struct stat stat_buf;
+       struct pcma_filestream *s = (struct pcma_filestream *)fs->private;
 #endif
 
        if (f->frametype != AST_FRAME_VOICE) {
@@ -204,7 +135,7 @@ static int pcm_write(struct ast_filestream *fs, struct ast_frame *f)
 
 #ifdef REALTIME_WRITE
        cur_time = get_time();
-       fpos = ( cur_time - fs->start_time ) * 8;       /* 8 bytes per msec */
+       fpos = ( cur_time - s->start_time ) * 8;        /* 8 bytes per msec */
        /* Check if we have written to this position yet. If we have, then increment pos by one frame
        *  for some degree of protection against receiving packets in the same clock tick.
        */
@@ -306,16 +237,28 @@ static int pcm_trunc(struct ast_filestream *fs)
 
 static off_t pcm_tell(struct ast_filestream *fs)
 {
-       off_t offset;
-       offset = ftello(fs->f);
-       return offset;
+       return ftello(fs->f);
 }
 
-
-static char *pcm_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format alaw_f = {
+       .name = "alaw",
+       .exts = "alaw|al",
+       .format = AST_FORMAT_ALAW,
+       .open = pcm_open,
+       .rewrite = pcm_rewrite,
+       .write = pcm_write,
+       .seek = pcm_seek,
+       .trunc = pcm_trunc,
+       .tell = pcm_tell,
+       .read = pcm_read,
+       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+       .lockp = &me,
+#ifdef REALTIME_WRITE
+       .desc_size = sizeof(struct pcma_desc),
+#endif
+};
 
 int load_module()
 {
@@ -324,34 +267,24 @@ int load_module()
        for (index = 0; index < (sizeof(alaw_silence) / sizeof(alaw_silence[0])); index++)
                alaw_silence[index] = AST_LIN2A(0);
 
-       return ast_format_register(name, exts, AST_FORMAT_ALAW,
-                                  pcm_open,
-                                  pcm_rewrite,
-                                  pcm_write,
-                                  pcm_seek,
-                                  pcm_trunc,
-                                  pcm_tell,
-                                  pcm_read,
-                                  pcm_close,
-                                  pcm_getcomment);
+       return ast_format_register(&alaw_f);
 }
 
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(alaw_f.name);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Raw aLaw 8khz PCM Audio support";
 }
 
-
 char *key()
 {
        return ASTERISK_GPL_KEY;
index 74792c6..d3a7591 100644 (file)
@@ -43,111 +43,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
 
-#define BUF_SIZE 320           /* 320 samples */
-
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
-       /* This is what a filestream means to us */
-       FILE *f; /* Descriptor */
-       struct ast_channel *owner;
-       struct ast_frame fr;                            /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                                                     /* Empty character */
-       unsigned char buf[BUF_SIZE];                            /* Output Buffer */
-       struct timeval last;
-};
-
-
-AST_MUTEX_DEFINE_STATIC(slinear_lock);
-static int glistcnt = 0;
-
-static char *name = "sln";
-static char *desc = "Raw Signed Linear Audio support (SLN)";
-static char *exts = "sln|raw";
-
-static struct ast_filestream *slinear_open(FILE *f)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&slinear_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock slinear list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->fr.data = tmp->buf;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_SLINEAR;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name;
-               tmp->fr.mallocd = 0;
-               glistcnt++;
-               ast_mutex_unlock(&slinear_lock);
-               ast_update_use_count();
-       }
-       return tmp;
-}
-
-static struct ast_filestream *slinear_rewrite(FILE *f, const char *comment)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&slinear_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock slinear list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               glistcnt++;
-               ast_mutex_unlock(&slinear_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
-}
-
-static void slinear_close(struct ast_filestream *s)
-{
-       if (ast_mutex_lock(&slinear_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock slinear list\n");
-               return;
-       }
-       glistcnt--;
-       ast_mutex_unlock(&slinear_lock);
-       ast_update_use_count();
-       fclose(s->f);
-       free(s);
-       s = NULL;
-}
+#define BUF_SIZE       320             /* 320 bytes, 160 samples */
+#define        SLIN_SAMPLES    160
 
 static struct ast_frame *slinear_read(struct ast_filestream *s, int *whennext)
 {
        int res;
-       int delay;
        /* Send a frame from the file to the appropriate channel */
 
        s->fr.frametype = AST_FRAME_VOICE;
        s->fr.subclass = AST_FORMAT_SLINEAR;
        s->fr.offset = AST_FRIENDLY_OFFSET;
        s->fr.mallocd = 0;
-       s->fr.data = s->buf;
-       if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) {
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
+       if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) < 1) {
                if (res)
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
                return NULL;
        }
-       s->fr.samples = res/2;
+       *whennext = s->fr.samples = res/2;
        s->fr.datalen = res;
-       delay = s->fr.samples;
-       *whennext = delay;
        return &s->fr;
 }
 
@@ -199,48 +114,44 @@ static int slinear_trunc(struct ast_filestream *fs)
 
 static off_t slinear_tell(struct ast_filestream *fs)
 {
-       off_t offset;
-       offset = ftello(fs->f);
-       return offset / 2;
+       return ftello(fs->f) / 2;
 }
 
-static char *slinear_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format slin_f = {
+       .name = "sln",
+       .exts = "sln|raw",
+       .format = AST_FORMAT_SLINEAR,
+       .write = slinear_write,
+       .seek = slinear_seek,
+       .trunc = slinear_trunc,
+       .tell = slinear_tell,
+       .read = slinear_read,
+       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+       .lockp = &me,
+};
 
 int load_module()
 {
-       return ast_format_register(name, exts, AST_FORMAT_SLINEAR,
-                                                               slinear_open,
-                                                               slinear_rewrite,
-                                                               slinear_write,
-                                                               slinear_seek,
-                                                               slinear_trunc,
-                                                               slinear_tell,
-                                                               slinear_read,
-                                                               slinear_close,
-                                                               slinear_getcomment);
-                                                               
-                                                               
+       return ast_format_register(&slin_f);
 }
 
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(slin_f.name);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Raw Signed Linear Audio support (SLN)";
 }
 
-
 char *key()
 {
        return ASTERISK_GPL_KEY;
index 8cc1431..2bd8b36 100644 (file)
@@ -45,117 +45,29 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/module.h"
 #include "asterisk/endian.h"
 
-#define BUF_SIZE 80            /* 160 samples */
-
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
-       /* This is what a filestream means to us */
-       FILE *f; /* Descriptor */
-       struct ast_frame fr;                            /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                                                     /* Empty character */
-       unsigned char buf[BUF_SIZE];    /* Output Buffer */
-       int lasttimeout;
-       struct timeval last;
-       short signal;                                           /* Signal level (file side) */
-       short ssindex;                                          /* Signal ssindex (file side) */
-       unsigned char zero_count;                               /* counter of consecutive zero samples */
-       unsigned char next_flag;
-};
-
-
-AST_MUTEX_DEFINE_STATIC(vox_lock);
-static int glistcnt = 0;
-
-static char *name = "vox";
-static char *desc = "Dialogic VOX (ADPCM) File Format";
-static char *exts = "vox";
-
-static struct ast_filestream *vox_open(FILE *f)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&vox_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock vox list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->fr.data = tmp->buf;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_ADPCM;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name;
-               tmp->fr.mallocd = 0;
-               tmp->lasttimeout = -1;
-               glistcnt++;
-               ast_mutex_unlock(&vox_lock);
-               ast_update_use_count();
-       }
-       return tmp;
-}
-
-static struct ast_filestream *vox_rewrite(FILE *f, const char *comment)
-{
-       /* We don't have any header to read or anything really, but
-          if we did, it would go here.  We also might want to check
-          and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (ast_mutex_lock(&vox_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock vox list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               glistcnt++;
-               ast_mutex_unlock(&vox_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
-}
-
-static void vox_close(struct ast_filestream *s)
-{
-       if (ast_mutex_lock(&vox_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock vox list\n");
-               return;
-       }
-       glistcnt--;
-       ast_mutex_unlock(&vox_lock);
-       ast_update_use_count();
-       fclose(s->f);
-       free(s);
-       s = NULL;
-}
+#define BUF_SIZE       80              /* 80 bytes, 160 samples */
+#define VOX_SAMPLES    160
 
 static struct ast_frame *vox_read(struct ast_filestream *s, int *whennext)
 {
        int res;
+
        /* Send a frame from the file to the appropriate channel */
        s->fr.frametype = AST_FRAME_VOICE;
        s->fr.subclass = AST_FORMAT_ADPCM;
-       s->fr.offset = AST_FRIENDLY_OFFSET;
        s->fr.mallocd = 0;
-       s->fr.data = s->buf;
-       if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) {
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
+       if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) < 1) {
                if (res)
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
                return NULL;
        }
-       s->fr.samples = res * 2;
+       *whennext = s->fr.samples = res * 2;
        s->fr.datalen = res;
-       *whennext = s->fr.samples;
        return &s->fr;
 }
 
-static int vox_write(struct ast_filestream *fs, struct ast_frame *f)
+static int vox_write(struct ast_filestream *s, struct ast_frame *f)
 {
        int res;
        if (f->frametype != AST_FRAME_VOICE) {
@@ -166,18 +78,13 @@ static int vox_write(struct ast_filestream *fs, struct ast_frame *f)
                ast_log(LOG_WARNING, "Asked to write non-ADPCM frame (%d)!\n", f->subclass);
                return -1;
        }
-       if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
+       if ((res = fwrite(f->data, 1, f->datalen, s->f)) != f->datalen) {
                        ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
                        return -1;
        }
        return 0;
 }
 
-static char *vox_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
-
 static int vox_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
 {
      off_t offset=0,min,cur,max,distance;
@@ -199,8 +106,7 @@ static int vox_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
          offset = (offset > max)?max:offset;
          offset = (offset < min)?min:offset;
      }
-     fseeko(fs->f, offset, SEEK_SET);
-        return ftello(fs->f);
+     return fseeko(fs->f, offset, SEEK_SET);
 }
 
 static int vox_trunc(struct ast_filestream *fs)
@@ -215,38 +121,41 @@ static off_t vox_tell(struct ast_filestream *fs)
      return offset; 
 }
 
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format vox_f = {
+       .name = "vox",
+       .exts = "vox",
+       .format = AST_FORMAT_ADPCM,
+       .write = vox_write,
+       .seek = vox_seek,
+       .trunc = vox_trunc,
+       .tell = vox_tell,
+       .read = vox_read,
+       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+       .lockp = &me,
+};
+
 int load_module()
 {
-       return ast_format_register(name, exts, AST_FORMAT_ADPCM,
-                                                               vox_open,
-                                                               vox_rewrite,
-                                                               vox_write,
-                                                               vox_seek,
-                                                               vox_trunc,
-                                                               vox_tell,
-                                                               vox_read,
-                                                               vox_close,
-                                                               vox_getcomment);
-                                                               
-                                                               
+       return ast_format_register(&vox_f);
 }
 
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(vox_f.name);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Dialogic VOX (ADPCM) File Format";
 }
 
-
 char *key()
 {
        return ASTERISK_GPL_KEY;
index 67df416..f46d75b 100644 (file)
@@ -49,30 +49,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 /* Portions of the conversion code are by guido@sienanet.it */
 
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
-       /* This is what a filestream means to us */
-       FILE *f; /* Descriptor */
+#define        WAV_BUF_SIZE    320
+
+struct wav_desc {      /* format-specific parameters */
        int bytes;
        int needsgain;
-       struct ast_frame fr;                            /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                                                     /* Empty character */
-       short buf[160]; 
-       int foffset;
        int lasttimeout;
        int maxlen;
        struct timeval last;
 };
 
-
-AST_MUTEX_DEFINE_STATIC(wav_lock);
-static int glistcnt = 0;
-
-static char *name = "wav";
-static char *desc = "Microsoft WAV format (8000hz Signed Linear)";
-static char *exts = "wav";
-
 #define BLOCKSIZE 160
 
 #define GAIN 2         /* 2^GAIN is the multiple to increase the volume by */
@@ -165,7 +151,7 @@ static int check_header(FILE *f)
                ast_log(LOG_WARNING, "Read failed (freq)\n");
                return -1;
        }
-       if (ltohl(freq) != 8000) {
+       if (ltohl(freq) != DEFAULT_SAMPLE_RATE) {
                ast_log(LOG_WARNING, "Unexpected freqency %d\n", ltohl(freq));
                return -1;
        }
@@ -233,7 +219,6 @@ static int update_header(FILE *f)
        off_t cur,end;
        int datalen,filelen,bytes;
        
-       
        cur = ftello(f);
        fseek(f, 0, SEEK_END);
        end = ftello(f);
@@ -333,135 +318,90 @@ static int write_header(FILE *f)
        return 0;
 }
 
-static struct ast_filestream *wav_open(FILE *f)
+static int wav_open(struct ast_filestream *s)
 {
        /* We don't have any header to read or anything really, but
           if we did, it would go here.  We also might want to check
           and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if ((tmp->maxlen = check_header(f)) < 0) {
-                       free(tmp);
-                       return NULL;
-               }
-               if (ast_mutex_lock(&wav_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock wav list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->needsgain = 1;
-               tmp->fr.data = tmp->buf;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_SLINEAR;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name;
-               tmp->fr.mallocd = 0;
-               tmp->bytes = 0;
-               glistcnt++;
-               ast_mutex_unlock(&wav_lock);
-               ast_update_use_count();
-       }
-       return tmp;
+       struct wav_desc *tmp = (struct wav_desc *)s->private;
+       if ((tmp->maxlen = check_header(s->f)) < 0)
+               return -1;
+       return 0;
 }
 
-static struct ast_filestream *wav_rewrite(FILE *f, const char *comment)
+static int wav_rewrite(struct ast_filestream *s, const char *comment)
 {
        /* We don't have any header to read or anything really, but
           if we did, it would go here.  We also might want to check
           and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (write_header(f)) {
-                       free(tmp);
-                       return NULL;
-               }
-               if (ast_mutex_lock(&wav_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock wav list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               glistcnt++;
-               ast_mutex_unlock(&wav_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
+
+       if (write_header(s->f))
+               return -1;
+       return 0;
 }
 
 static void wav_close(struct ast_filestream *s)
 {
        char zero = 0;
-       if (ast_mutex_lock(&wav_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock wav list\n");
-               return;
-       }
-       glistcnt--;
-       ast_mutex_unlock(&wav_lock);
-       ast_update_use_count();
+       struct wav_desc *fs = (struct wav_desc *)s->private;
        /* Pad to even length */
-       if (s->bytes & 0x1)
+       if (fs->bytes & 0x1)
                fwrite(&zero, 1, 1, s->f);
-       fclose(s->f);
-       free(s);
-       s = NULL;
 }
 
 static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext)
 {
        int res;
-       int delay;
+       int samples;    /* actual samples read */
        int x;
-       short tmp[sizeof(s->buf) / 2];
-       int bytes = sizeof(tmp);
+       short *tmp;
+       int bytes = WAV_BUF_SIZE;       /* in bytes */
        off_t here;
        /* Send a frame from the file to the appropriate channel */
+       struct wav_desc *fs = (struct wav_desc *)s->private;
+
        here = ftello(s->f);
-       if ((s->maxlen - here) < bytes)
-               bytes = s->maxlen - here;
+       if (fs->maxlen - here < bytes)          /* truncate if necessary */
+               bytes = fs->maxlen - here;
        if (bytes < 0)
                bytes = 0;
 /*     ast_log(LOG_DEBUG, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */
+       s->fr.frametype = AST_FRAME_VOICE;
+       s->fr.subclass = AST_FORMAT_SLINEAR;
+       s->fr.mallocd = 0;
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, bytes);
        
-       if ( (res = fread(tmp, 1, bytes, s->f)) <= 0 ) {
-               if (res) {
+       if ( (res = fread(s->fr.data, 1, s->fr.datalen, s->f)) <= 0 ) {
+               if (res)
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
-               }
                return NULL;
        }
+       s->fr.datalen = res;
+       s->fr.samples = samples = res / 2;
 
+       tmp = (short *)(s->fr.data);
 #if __BYTE_ORDER == __BIG_ENDIAN
-       for( x = 0; x < sizeof(tmp)/2; x++) tmp[x] = (tmp[x] << 8) | ((tmp[x] & 0xff00) >> 8);
+       /* file format is little endian so we need to swap */
+       for( x = 0; x < samples; x++)
+               tmp[x] = (tmp[x] << 8) | ((tmp[x] & 0xff00) >> 8);
 #endif
 
-       if (s->needsgain) {
-               for (x=0;x<sizeof(tmp)/2;x++)
+       if (fs->needsgain) {
+               for (x=0; x < samples; x++) {
                        if (tmp[x] & ((1 << GAIN) - 1)) {
                                /* If it has data down low, then it's not something we've artificially increased gain
                                   on, so we don't need to gain adjust it */
-                               s->needsgain = 0;
+                               fs->needsgain = 0;
+                               break;
                        }
-       }
-       if (s->needsgain) {
-               for (x=0;x<sizeof(tmp)/2;x++) {
-                       s->buf[x] = tmp[x] >> GAIN;
                }
-       } else {
-               memcpy(s->buf, tmp, sizeof(s->buf));
+               if (fs->needsgain) {
+                       for (x=0; x < samples; x++)
+                               tmp[x] = tmp[x] >> GAIN;
+               }
        }
                        
-       delay = res / 2;
-       s->fr.frametype = AST_FRAME_VOICE;
-       s->fr.subclass = AST_FORMAT_SLINEAR;
-       s->fr.offset = AST_FRIENDLY_OFFSET;
-       s->fr.datalen = res;
-       s->fr.data = s->buf;
-       s->fr.mallocd = 0;
-       s->fr.samples = delay;
-       *whennext = delay;
+       *whennext = samples;
        return &s->fr;
 }
 
@@ -470,6 +410,9 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
        int x;
        short tmp[8000], *tmpi;
        float tmpf;
+       struct wav_desc *s = (struct wav_desc *)fs->private;
+       int res;
+
        if (f->frametype != AST_FRAME_VOICE) {
                ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
                return -1;
@@ -489,33 +432,28 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
        printf("Data Length: %d\n", f->datalen);
 #endif 
 
-       if (fs->buf) {
-               tmpi = f->data;
-               /* Volume adjust here to accomodate */
-               for (x=0;x<f->datalen/2;x++) {
-                       tmpf = ((float)tmpi[x]) * ((float)(1 << GAIN));
-                       if (tmpf > 32767.0)
-                               tmpf = 32767.0;
-                       if (tmpf < -32768.0)
-                               tmpf = -32768.0;
-                       tmp[x] = tmpf;
-                       tmp[x] &= ~((1 << GAIN) - 1);
+       tmpi = f->data;
+       /* Volume adjust here to accomodate */
+       for (x=0;x<f->datalen/2;x++) {
+               tmpf = ((float)tmpi[x]) * ((float)(1 << GAIN));
+               if (tmpf > 32767.0)
+                       tmpf = 32767.0;
+               if (tmpf < -32768.0)
+                       tmpf = -32768.0;
+               tmp[x] = tmpf;
+               tmp[x] &= ~((1 << GAIN) - 1);
 
 #if __BYTE_ORDER == __BIG_ENDIAN
-                       tmp[x] = (tmp[x] << 8) | ((tmp[x] & 0xff00) >> 8);
+               tmp[x] = (tmp[x] << 8) | ((tmp[x] & 0xff00) >> 8);
 #endif
 
-               }
-               if ((fwrite(tmp, 1, f->datalen, fs->f) != f->datalen) ) {
-                       ast_log(LOG_WARNING, "Bad write (%d): %s\n", errno, strerror(errno));
-                       return -1;
-               }
-       } else {
-               ast_log(LOG_WARNING, "Cannot write data to file.\n");
+       }
+       if ((res = fwrite(tmp, 1, f->datalen, fs->f)) != f->datalen ) {
+               ast_log(LOG_WARNING, "Bad write (%d): %s\n", res, strerror(errno));
                return -1;
        }
-       
-       fs->bytes += f->datalen;
+
+       s->bytes += f->datalen;
        update_header(fs->f);
                
        return 0;
@@ -560,43 +498,45 @@ static off_t wav_tell(struct ast_filestream *fs)
        return (offset - 44)/2;
 }
 
-static char *wav_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format wav_f = {
+       .name = "wav",
+       .exts = "wav",
+       .format = AST_FORMAT_SLINEAR,
+       .open = wav_open,
+       .rewrite = wav_rewrite,
+       .write = wav_write,
+       .seek = wav_seek,
+       .trunc = wav_trunc,
+       .tell = wav_tell,
+       .read = wav_read,
+       .close = wav_close,
+       .buf_size = WAV_BUF_SIZE + AST_FRIENDLY_OFFSET,
+       .desc_size = sizeof(struct wav_desc),
+       .lockp = &me,
+};
 
 int load_module()
 {
-       return ast_format_register(name, exts, AST_FORMAT_SLINEAR,
-                                                               wav_open,
-                                                               wav_rewrite,
-                                                               wav_write,
-                                                               wav_seek,
-                                                               wav_trunc,
-                                                               wav_tell,
-                                                               wav_read,
-                                                               wav_close,
-                                                               wav_getcomment);
-                                                               
-                                                               
+       return ast_format_register(&wav_f);
 }
 
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(wav_f.name);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Microsoft WAV format (8000hz Signed Linear)";
 }
 
-
 char *key()
 {
        return ASTERISK_GPL_KEY;
index 0875e77..888a960 100644 (file)
@@ -54,6 +54,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 /* Portions of the conversion code are by guido@sienanet.it */
 
+#define        GSM_FRAME_SIZE  33
+#define        MSGSM_FRAME_SIZE        65
+#define        MSGSM_DATA_OFS          60      /* offset of data bytes */
+#define        GSM_SAMPLES             160     /* samples in a GSM block */
+#define        MSGSM_SAMPLES           (2*GSM_SAMPLES) /* samples in an MSGSM block */
+
 /* begin binary data: */
 char msgsm_silence[] = /* 65 */
 {0x48,0x17,0xD6,0x84,0x02,0x80,0x24,0x49,0x92,0x24,0x89,0x02,0x80,0x24,0x49
@@ -63,29 +69,12 @@ char msgsm_silence[] = /* 65 */
 ,0x92,0x24,0x49,0x92,0x00};
 /* end binary data. size = 65 bytes */
 
-struct ast_filestream {
-       void *reserved[AST_RESERVED_POINTERS];
+struct wavg_desc {
        /* Believe it or not, we must decode/recode to account for the
           weird MS format */
-       /* This is what a filestream means to us */
-       FILE *f; /* Descriptor */
-       struct ast_frame fr;                            /* Frame information */
-       char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
-       char empty;                                                     /* Empty character */
-       unsigned char gsm[66];                          /* Two Real GSM Frames */
-       int foffset;
        int secondhalf;                                         /* Are we on the second half */
-       struct timeval last;
 };
 
-
-AST_MUTEX_DEFINE_STATIC(wav_lock);
-static int glistcnt = 0;
-
-static char *name = "wav49";
-static char *desc = "Microsoft WAV format (Proprietary GSM)";
-static char *exts = "WAV|wav49";
-
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 #define htoll(b) (b)
 #define htols(b) (b)
@@ -173,7 +162,7 @@ static int check_header(FILE *f)
                ast_log(LOG_WARNING, "Read failed (freq)\n");
                return -1;
        }
-       if (ltohl(freq) != 8000) {
+       if (ltohl(freq) != DEFAULT_SAMPLE_RATE) {
                ast_log(LOG_WARNING, "Unexpected freqency %d\n", ltohl(freq));
                return -1;
        }
@@ -236,7 +225,7 @@ static int update_header(FILE *f)
        fseek(f, 0, SEEK_END);
        end = ftello(f);
        /* in a gsm WAV, data starts 60 bytes in */
-       bytes = end - 60;
+       bytes = end - MSGSM_DATA_OFS;
        datalen = htoll((bytes + 1) & ~0x1);
        filelen = htoll(52 + ((bytes + 1) & ~0x1));
        if (cur < 0) {
@@ -268,7 +257,7 @@ static int update_header(FILE *f)
 
 static int write_header(FILE *f)
 {
-       unsigned int hz=htoll(8000);
+       unsigned int hz=htoll(DEFAULT_SAMPLE_RATE);     /* XXX the following are relate to DEFAULT_SAMPLE_RATE ? */
        unsigned int bhz = htoll(1625);
        unsigned int hs = htoll(20);
        unsigned short fmt = htols(49);
@@ -347,119 +336,78 @@ static int write_header(FILE *f)
        return 0;
 }
 
-static struct ast_filestream *wav_open(FILE *f)
+static int wav_open(struct ast_filestream *s)
 {
        /* We don't have any header to read or anything really, but
           if we did, it would go here.  We also might want to check
           and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (check_header(f)) {
-                       free(tmp);
-                       return NULL;
-               }
-               if (ast_mutex_lock(&wav_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock wav list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               tmp->fr.data = tmp->gsm;
-               tmp->fr.frametype = AST_FRAME_VOICE;
-               tmp->fr.subclass = AST_FORMAT_GSM;
-               /* datalen will vary for each frame */
-               tmp->fr.src = name;
-               tmp->fr.mallocd = 0;
-               tmp->secondhalf = 0;
-               glistcnt++;
-               ast_mutex_unlock(&wav_lock);
-               ast_update_use_count();
-       }
-       return tmp;
+       struct wavg_desc *fs = (struct wavg_desc *)s->private;
+
+       if (check_header(s->f))
+               return -1;
+       fs->secondhalf = 0;     /* not strictly necessary */
+       return 0;
 }
 
-static struct ast_filestream *wav_rewrite(FILE *f, const char *comment)
+static int wav_rewrite(struct ast_filestream *s, const char *comment)
 {
        /* We don't have any header to read or anything really, but
           if we did, it would go here.  We also might want to check
           and be sure it's a valid file.  */
-       struct ast_filestream *tmp;
-       if ((tmp = malloc(sizeof(struct ast_filestream)))) {
-               memset(tmp, 0, sizeof(struct ast_filestream));
-               if (write_header(f)) {
-                       free(tmp);
-                       return NULL;
-               }
-               if (ast_mutex_lock(&wav_lock)) {
-                       ast_log(LOG_WARNING, "Unable to lock wav list\n");
-                       free(tmp);
-                       return NULL;
-               }
-               tmp->f = f;
-               glistcnt++;
-               ast_mutex_unlock(&wav_lock);
-               ast_update_use_count();
-       } else
-               ast_log(LOG_WARNING, "Out of memory\n");
-       return tmp;
+
+       if (write_header(s->f))
+               return -1;
+       return 0;
 }
 
 static void wav_close(struct ast_filestream *s)
 {
        char zero = 0;
-       if (ast_mutex_lock(&wav_lock)) {
-               ast_log(LOG_WARNING, "Unable to lock wav list\n");
-               return;
-       }
-       glistcnt--;
-       ast_mutex_unlock(&wav_lock);
-       ast_update_use_count();
        /* Pad to even length */
        fseek(s->f, 0, SEEK_END);
        if (ftello(s->f) & 0x1)
                fwrite(&zero, 1, 1, s->f);
-       fclose(s->f);
-       free(s);
-       s = NULL;
 }
 
 static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext)
 {
-       int res;
-       char msdata[66];
        /* Send a frame from the file to the appropriate channel */
+       struct wavg_desc *fs = (struct wavg_desc *)s->private;
 
        s->fr.frametype = AST_FRAME_VOICE;
        s->fr.subclass = AST_FORMAT_GSM;
        s->fr.offset = AST_FRIENDLY_OFFSET;
-       s->fr.samples = 160;
-       s->fr.datalen = 33;
+       s->fr.samples = GSM_SAMPLES;
        s->fr.mallocd = 0;
-       if (s->secondhalf) {
+       FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, GSM_FRAME_SIZE);
+       if (fs->secondhalf) {
                /* Just return a frame based on the second GSM frame */
-               s->fr.data = s->gsm + 33;
+               s->fr.data = (char *)s->fr.data + GSM_FRAME_SIZE;
+               s->fr.offset += GSM_FRAME_SIZE;
        } else {
-               if ((res = fread(msdata, 1, 65, s->f)) != 65) {
+               /* read and convert */
+               char msdata[MSGSM_FRAME_SIZE];
+               int res;
+               
+               if ((res = fread(msdata, 1, MSGSM_FRAME_SIZE, s->f)) != MSGSM_FRAME_SIZE) {
                        if (res && (res != 1))
                                ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
                        return NULL;
                }
                /* Convert from MS format to two real GSM frames */
-               conv65(msdata, s->gsm);
-               s->fr.data = s->gsm;
+               conv65(msdata, s->fr.data);
        }
-       s->secondhalf = !s->secondhalf;
-       *whennext = 160;
+       fs->secondhalf = !fs->secondhalf;
+       *whennext = GSM_SAMPLES;
        return &s->fr;
 }
 
-static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
+static int wav_write(struct ast_filestream *s, struct ast_frame *f)
 {
-       int res;
-       char msdata[66];
-       int len =0;
-       int alreadyms=0;
+       int len;
+       int size;
+       struct wavg_desc *fs = (struct wavg_desc *)s->private;
+
        if (f->frametype != AST_FRAME_VOICE) {
                ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
                return -1;
@@ -468,65 +416,70 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
                ast_log(LOG_WARNING, "Asked to write non-GSM frame (%d)!\n", f->subclass);
                return -1;
        }
-       if (!(f->datalen % 65)) 
-               alreadyms = 1;
-       while(len < f->datalen) {
-               if (alreadyms) {
+       /* XXX this might fail... if the input is a multiple of MSGSM_FRAME_SIZE
+        * we assume it is already in the correct format.
+        */
+       if (!(f->datalen % MSGSM_FRAME_SIZE)) {
+               size = MSGSM_FRAME_SIZE;
+               fs->secondhalf = 0;
+       } else {
+               size = GSM_FRAME_SIZE;
+       }
+       for (len = 0; len < f->datalen ; len += size) {
+               int res;
+               char *src, msdata[MSGSM_FRAME_SIZE];
+               if (fs->secondhalf) {   /* second half of raw gsm to be converted */
+                       memcpy(s->buf + GSM_FRAME_SIZE, f->data + len, GSM_FRAME_SIZE);
+                       conv66(s->buf, msdata);
+                       src = msdata;
                        fs->secondhalf = 0;
-                       if ((res = fwrite(f->data + len, 1, 65, fs->f)) != 65) {
-                               ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno));
-                               return -1;
-                       }
-                       update_header(fs->f);
-                       len += 65;
-               } else {
-                       if (fs->secondhalf) {
-                               memcpy(fs->gsm + 33, f->data + len, 33);
-                               conv66(fs->gsm, msdata);
-                               if ((res = fwrite(msdata, 1, 65, fs->f)) != 65) {
-                                       ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno));
-                                       return -1;
-                               }
-                               update_header(fs->f);
-                       } else {
-                               /* Copy the data and do nothing */
-                               memcpy(fs->gsm, f->data + len, 33);
-                       }
-                       fs->secondhalf = !fs->secondhalf;
-                       len += 33;
+               } else if (size == GSM_FRAME_SIZE) {    /* first half of raw gsm */
+                       memcpy(s->buf, f->data + len, GSM_FRAME_SIZE);
+                       src = NULL;     /* nothing to write */
+                       fs->secondhalf = 1;
+               } else {        /* raw msgsm data */
+                       src = f->data + len;
                }
+               if (src && (res = fwrite(src, 1, size, s->f)) != size) {
+                       ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno));
+                       return -1;
+               }
+               update_header(s->f); /* XXX inefficient! */
        }
        return 0;
 }
 
 static int wav_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
 {
-       off_t offset=0,distance,cur,min,max;
-       min = 60;
-       cur = ftello(fs->f);
+       off_t offset=0, distance, max;
+       struct wavg_desc *s = (struct wavg_desc *)fs->private;
+
+       off_t min = MSGSM_DATA_OFS;
+       off_t cur = ftello(fs->f);
        fseek(fs->f, 0, SEEK_END);
-       max = ftello(fs->f);
-       /* I'm getting sloppy here, I'm only going to go to even splits of the 2
-        * frames, if you want tighter cuts use format_gsm, format_pcm, or format_wav */
-       distance = (sample_offset/320) * 65;
-       if(whence == SEEK_SET)
+       max = ftello(fs->f);    /* XXX ideally, should round correctly */
+       /* Compute the distance in bytes, rounded to the block size */
+       distance = (sample_offset/MSGSM_SAMPLES) * MSGSM_FRAME_SIZE;
+       if (whence == SEEK_SET)
                offset = distance + min;
-       else if(whence == SEEK_CUR || whence == SEEK_FORCECUR)
+       else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
                offset = distance + cur;
-       else if(whence == SEEK_END)
+       else if (whence == SEEK_END)
                offset = max - distance;
        /* always protect against seeking past end of header */
-       offset = (offset < min)?min:offset;
+       if (offset < min)
+               offset = min;
        if (whence != SEEK_FORCECUR) {
-               offset = (offset > max)?max:offset;
+               if (offset > max)
+                       offset = max;
        } else if (offset > max) {
                int i;
                fseek(fs->f, 0, SEEK_END);
-               for (i=0; i< (offset - max) / 65; i++) {
-                       fwrite(msgsm_silence, 1, 65, fs->f);
+               for (i=0; i< (offset - max) / MSGSM_FRAME_SIZE; i++) {
+                       fwrite(msgsm_silence, 1, MSGSM_FRAME_SIZE, fs->f);
                }
        }
-       fs->secondhalf = 0;
+       s->secondhalf = 0;
        return fseeko(fs->f, offset, SEEK_SET);
 }
 
@@ -543,46 +496,49 @@ static off_t wav_tell(struct ast_filestream *fs)
        offset = ftello(fs->f);
        /* since this will most likely be used later in play or record, lets stick
         * to that level of resolution, just even frames boundaries */
-       return (offset - 52)/65*320;
+       /* XXX why 52 ? */
+       return (offset - 52)/MSGSM_FRAME_SIZE*MSGSM_SAMPLES;
 }
 
-static char *wav_getcomment(struct ast_filestream *s)
-{
-       return NULL;
-}
+static struct ast_format_lock me = { .usecnt = -1 };
+
+static const struct ast_format wav49_f = {
+       .name = "wav49",
+       .exts = "WAV|wav49",
+       .format = AST_FORMAT_GSM,
+       .open = wav_open,
+       .rewrite = wav_rewrite,
+       .write = wav_write,
+       .seek = wav_seek,
+       .trunc = wav_trunc,
+       .tell = wav_tell,
+       .read = wav_read,
+       .close = wav_close,
+       .buf_size = 2*GSM_FRAME_SIZE + AST_FRIENDLY_OFFSET,
+       .desc_size = sizeof(struct wavg_desc),
+       .lockp = &me,
+};
 
 int load_module()
 {
-       return ast_format_register(name, exts, AST_FORMAT_GSM,
-                                                               wav_open,
-                                                               wav_rewrite,
-                                                               wav_write,
-                                                               wav_seek,
-                                                               wav_trunc,
-                                                               wav_tell,
-                                                               wav_read,
-                                                               wav_close,
-                                                               wav_getcomment);
-                                                               
-                                                               
+       return ast_format_register(&wav49_f);
 }
 
 int unload_module()
 {
-       return ast_format_unregister(name);
+       return ast_format_unregister(wav49_f.name);
 }      
 
 int usecount()
 {
-       return glistcnt;
+       return me.usecnt;
 }
 
 char *description()
 {
-       return desc;
+       return "Microsoft WAV format (Proprietary GSM)";
 }
 
-
 char *key()
 {
        return ASTERISK_GPL_KEY;
index 67150cf..905ea0a 100644 (file)
@@ -40,28 +40,109 @@ extern "C" {
 #define AST_DIGIT_ANY "0123456789#*ABCD"
 #define AST_DIGIT_ANYNUM "0123456789"
 
+/*! structure used for lock and refcount of format handlers.
+ * Should not be here, but this is a temporary workaround
+ * until we implement a more general mechanism.
+ * The format handler should include a pointer to
+ * this structure.
+ * As a trick, if usecnt is initialized with -1,
+ * ast_format_register will init the mutex for you.
+ */
+struct ast_format_lock {
+       ast_mutex_t lock;
+       int usecnt;     /* number of active clients */
+};
+
+/*!
+ * Each supported file format is described by the following fields.
+ * Not all are necessary, the support routine implement default
+ * values for some of them.
+ * A handler typically fills a structure initializing the desired
+ * fields, and then calls ast_format_register() with the (readonly)
+ * structure as an argument.
+ */
+struct ast_format {
+       char name[80];          /*! Name of format */
+       char exts[80];          /*! Extensions (separated by | if more than one) 
+                               this format can read.  First is assumed for writing (e.g. .mp3) */
+       int format;             /*! Format of frames it uses/provides (one only) */
+       /*! Prepare an input stream for playback. Return 0 on success, -1 on error.
+        * The FILE is already open (in s->f) so this function only needs to perform
+        * any applicable validity checks on the file. If none is required, the
+        * function can be omitted.
+        */
+       int (*open)(struct ast_filestream *s);
+       /*! Prepare a stream for output, and comment it appropriately if applicable.
+        *  Return 0 on success, -1 on error. Same as the open, the FILE is already
+        * open so the function just needs to prepare any header and other fields,
+        * if any. The function can be omitted if nothing is needed.
+        */
+       int (*rewrite)(struct ast_filestream *s, const char *comment);
+       /*! Write a frame to a channel */
+       int (*write)(struct ast_filestream *, struct ast_frame *);
+       /*! seek num samples into file, whence - like a normal seek but with offset in samples */
+       int (*seek)(struct ast_filestream *, off_t, int);
+       int (*trunc)(struct ast_filestream *fs);        /*! trunc file to current position */
+       off_t (*tell)(struct ast_filestream *fs);       /*! tell current position */
+       /*! Read the next frame from the filestream (if available) and report
+        * when to get next frame (in samples)
+        */
+       struct ast_frame * (*read)(struct ast_filestream *, int *whennext);
+       /*! Do any closing actions, if any. The descriptor and structure are closed
+        * and destroyed by the generic routines, so they must not be done here. */
+       void (*close)(struct ast_filestream *);
+       char * (*getcomment)(struct ast_filestream *);          /*! Retrieve file comment */
+
+       AST_LIST_ENTRY(ast_format) list;                        /*! Link */
+
+       /*!
+        * If the handler needs a buffer (for read, typically)
+        * and/or a private descriptor, put here the
+        * required size (in bytes) and the support routine will allocate them
+        * for you, pointed by s->buf and s->private, respectively.
+        * When allocating a buffer, remember to leave AST_FRIENDLY_OFFSET
+        * spare bytes at the bginning.
+        */
+       int buf_size;                   /*! size of frame buffer, if any, aligned to 8 bytes. */
+       int desc_size;                  /*! size of private descriptor, if any */
+
+       struct ast_format_lock *lockp;
+};
+
+/*
+ * This structure is allocated by file.c in one chunk,
+ * together with buf_size and desc_size bytes of memory
+ * to be used for private purposes (e.g. buffers etc.)
+ */
+struct ast_filestream {
+       /*! Everybody reserves a block of AST_RESERVED_POINTERS pointers for us */
+       struct ast_format *fmt; /* need to write to the lock and usecnt */
+       int flags;
+       mode_t mode;
+       char *filename;
+       char *realfilename;
+       /*! Video file stream */
+       struct ast_filestream *vfs;
+       /*! Transparently translate from another format -- just once */
+       struct ast_trans_pvt *trans;
+       struct ast_tranlator_pvt *tr;
+       int lastwriteformat;
+       int lasttimeout;
+       struct ast_channel *owner;
+       FILE *f;
+       struct ast_frame fr;    /* frame produced by read, typically */
+       char *buf;              /* buffer pointed to by ast_frame; */
+       void *private;  /* pointer to private buffer */
+};
+
 #define SEEK_FORCECUR  10
        
-/* Defined by individual formats.  First item MUST be a
-   pointer for use by the stream manager */
-struct ast_filestream;
-
-/*! Registers a new file format */
 /*! Register a new file format capability
- * Adds a format to asterisk's format abilities.  Fill in the fields, and it will work. For examples, look at some of the various format code.
+ * Adds a format to asterisk's format abilities.
  * returns 0 on success, -1 on failure
  */
-int ast_format_register(const char *name, const char *exts, int format,
-                                               struct ast_filestream * (*open)(FILE *f),
-                                               struct ast_filestream * (*rewrite)(FILE *f, const char *comment),
-                                               int (*write)(struct ast_filestream *, struct ast_frame *),
-                                               int (*seek)(struct ast_filestream *, off_t offset, int whence),
-                                               int (*trunc)(struct ast_filestream *),
-                                               off_t (*tell)(struct ast_filestream *),
-                                               struct ast_frame * (*read)(struct ast_filestream *, int *timetonext),
-                                               void (*close)(struct ast_filestream *),
-                                               char * (*getcomment)(struct ast_filestream *));
-       
+int ast_format_register(const struct ast_format *f);
+
 /*! Unregisters a file format */
 /*!
  * \param name the name of the format you wish to unregister