diff options
author | rizzo <rizzo@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-04-04 12:59:25 +0000 |
---|---|---|
committer | rizzo <rizzo@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-04-04 12:59:25 +0000 |
commit | 217ea2f1ea680d457c19aac1b563077f1f9ae67c (patch) | |
tree | c2ca953ad9722e235aa0205ca61e6b6a59c5e9e5 /formats | |
parent | 577bc5cf68911578b9a529d3919a923f5a5b3436 (diff) |
Largely simplify format handlers (for file copy etc.)
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: http://svn.digium.com/svn/asterisk/trunk@17243 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'formats')
-rw-r--r-- | formats/Makefile | 5 | ||||
-rw-r--r-- | formats/format_au.c | 154 | ||||
-rw-r--r-- | formats/format_g723.c | 160 | ||||
-rw-r--r-- | formats/format_g726.c | 456 | ||||
-rw-r--r-- | formats/format_g729.c | 141 | ||||
-rw-r--r-- | formats/format_gsm.c | 151 | ||||
-rw-r--r-- | formats/format_h263.c | 167 | ||||
-rw-r--r-- | formats/format_h264.c | 196 | ||||
-rw-r--r-- | formats/format_ilbc.c | 141 | ||||
-rw-r--r-- | formats/format_ogg_vorbis.c | 294 | ||||
-rw-r--r-- | formats/format_pcm.c | 459 | ||||
-rw-r--r-- | formats/format_pcm_alaw.c | 161 | ||||
-rw-r--r-- | formats/format_sln.c | 137 | ||||
-rw-r--r-- | formats/format_vox.c | 147 | ||||
-rw-r--r-- | formats/format_wav.c | 230 | ||||
-rw-r--r-- | formats/format_wav_gsm.c | 264 |
16 files changed, 1137 insertions, 2126 deletions
diff --git a/formats/Makefile b/formats/Makefile index 80143e58f..8b47f8d2d 100644 --- a/formats/Makefile +++ b/formats/Makefile @@ -13,6 +13,11 @@ 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 # diff --git a/formats/format_au.c b/formats/format_au.c index e8be324ae..06626a052 100644 --- a/formats/format_au.c +++ b/formats/format_au.c @@ -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() diff --git a/formats/format_g723.c b/formats/format_g723.c index 5eff15df3..7ddc79b04 100644 --- a/formats/format_g723.c +++ b/formats/format_g723.c @@ -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; diff --git a/formats/format_g726.c b/formats/format_g726.c index 70c6ac88f..01b94c07f 100644 --- a/formats/format_g726.c +++ b/formats/format_g726.c @@ -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() diff --git a/formats/format_g729.c b/formats/format_g729.c index 5194cea05..fc1e3e334 100644 --- a/formats/format_g729.c +++ b/formats/format_g729.c @@ -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; diff --git a/formats/format_gsm.c b/formats/format_gsm.c index c6ef31f7e..3a27a11fb 100644 --- a/formats/format_gsm.c +++ b/formats/format_gsm.c @@ -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; diff --git a/formats/format_h263.c b/formats/format_h263.c index 45692a354..fa5b5c60b 100644 --- a/formats/format_h263.c +++ b/formats/format_h263.c @@ -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; diff --git a/formats/format_h264.c b/formats/format_h264.c index 185b2680c..5beb826ec 100644 --- a/formats/format_h264.c +++ b/formats/format_h264.c @@ -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; diff --git a/formats/format_ilbc.c b/formats/format_ilbc.c index f0bcfbf4e..daaab3937 100644 --- a/formats/format_ilbc.c +++ b/formats/format_ilbc.c @@ -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; diff --git a/formats/format_ogg_vorbis.c b/formats/format_ogg_vorbis.c index 0437a38ef..061684f74 100644 --- a/formats/format_ogg_vorbis.c +++ b/formats/format_ogg_vorbis.c @@ -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() diff --git a/formats/format_pcm.c b/formats/format_pcm.c index d3f73e3b3..4624de518 100644 --- a/formats/format_pcm.c +++ b/formats/format_pcm.c @@ -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; diff --git a/formats/format_pcm_alaw.c b/formats/format_pcm_alaw.c index af1705f79..dcca10a9d 100644 --- a/formats/format_pcm_alaw.c +++ b/formats/format_pcm_alaw.c @@ -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; diff --git a/formats/format_sln.c b/formats/format_sln.c index 74792c605..d3a759131 100644 --- a/formats/format_sln.c +++ b/formats/format_sln.c @@ -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; diff --git a/formats/format_vox.c b/formats/format_vox.c index 8cc143178..2bd8b3650 100644 --- a/formats/format_vox.c +++ b/formats/format_vox.c @@ -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; diff --git a/formats/format_wav.c b/formats/format_wav.c index 67df4163b..f46d75b1b 100644 --- a/formats/format_wav.c +++ b/formats/format_wav.c @@ -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; diff --git a/formats/format_wav_gsm.c b/formats/format_wav_gsm.c index 0875e77fe..888a96020 100644 --- a/formats/format_wav_gsm.c +++ b/formats/format_wav_gsm.c @@ -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; |