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: https://origsvn.digium.com/svn/asterisk/trunk@17243 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Luigi Rizzo 2006-04-04 12:59:25 +00:00
parent ec67c650ad
commit 4beb6deeaa
18 changed files with 1748 additions and 2790 deletions

1018
file.c

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,11 @@
MODS:=$(patsubst %.c,%.so,$(wildcard format_*.c)) 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 # OGG/Vorbis format
# #

View File

@ -44,7 +44,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h" #include "asterisk/module.h"
#include "asterisk/endian.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_SIZE 24
#define AU_HEADER(var) u_int32_t var[6] #define AU_HEADER(var) u_int32_t var[6]
@ -58,26 +58,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define AU_ENC_8BIT_ULAW 1 #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 #define AU_MAGIC 0x2e736e64
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
#define htoll(b) (b) #define htoll(b) (b)
@ -130,7 +110,7 @@ static int check_header(FILE *f)
return -1; return -1;
} }
sample_rate = ltohl(header[AU_HDR_SAMPLE_RATE_OFF]); 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); ast_log(LOG_WARNING, "Sample rate can only be 8000 not %d\n", sample_rate);
return -1; 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_HDR_SIZE_OFF] = htoll(AU_HEADER_SIZE);
header[AU_HDR_DATA_SIZE_OFF] = 0; header[AU_HDR_DATA_SIZE_OFF] = 0;
header[AU_HDR_ENCODING_OFF] = htoll(AU_ENC_8BIT_ULAW); 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); header[AU_HDR_CHANNELS_OFF] = htoll(1);
/* Write an au header, ignoring sizes which will be filled in later */ /* Write an au header, ignoring sizes which will be filled in later */
@ -201,97 +181,36 @@ static int write_header(FILE *f)
return 0; return 0;
} }
static struct ast_filestream *au_open(FILE *f) static int au_open(struct ast_filestream *s)
{ {
struct ast_filestream *tmp; if (check_header(s->f) < 0)
return -1;
if (!(tmp = malloc(sizeof(struct ast_filestream)))) { return 0;
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_rewrite(struct ast_filestream *s, const char *comment)
{ {
struct ast_filestream *tmp; if (write_header(s->f))
return -1;
if ((tmp = malloc(sizeof(struct ast_filestream))) == NULL) { return 0;
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;
}
static void au_close(struct ast_filestream *s)
{
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);
} }
static struct ast_frame *au_read(struct ast_filestream *s, int *whennext) static struct ast_frame *au_read(struct ast_filestream *s, int *whennext)
{ {
int res; int res;
int delay;
/* Send a frame from the file to the appropriate channel */ /* Send a frame from the file to the appropriate channel */
s->fr.frametype = AST_FRAME_VOICE; s->fr.frametype = AST_FRAME_VOICE;
s->fr.subclass = AST_FORMAT_ULAW; s->fr.subclass = AST_FORMAT_ULAW;
s->fr.offset = AST_FRIENDLY_OFFSET;
s->fr.mallocd = 0; s->fr.mallocd = 0;
s->fr.data = s->buf; FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) { if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) < 1) {
if (res) if (res)
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL; return NULL;
} }
s->fr.samples = res; *whennext = s->fr.samples = res;
s->fr.datalen = res; s->fr.datalen = res;
delay = s->fr.samples;
*whennext = delay;
return &s->fr; return &s->fr;
} }
@ -348,44 +267,45 @@ static int au_trunc(struct ast_filestream *fs)
static off_t au_tell(struct ast_filestream *fs) static off_t au_tell(struct ast_filestream *fs)
{ {
off_t offset; off_t offset = ftello(fs->f);
offset = ftello(fs->f);
return offset - AU_HEADER_SIZE; return offset - AU_HEADER_SIZE;
} }
static char *au_getcomment(struct ast_filestream *s) static struct ast_format_lock me = { .usecnt = -1 };
{
return NULL; 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() int load_module()
{ {
return ast_format_register(name, exts, AST_FORMAT_ULAW, return ast_format_register(&au_f);
au_open,
au_rewrite,
au_write,
au_seek,
au_trunc,
au_tell,
au_read,
au_close,
au_getcomment);
} }
int unload_module() int unload_module()
{ {
return ast_format_unregister(name); return ast_format_unregister(au_f.name);
} }
int usecount() int usecount()
{ {
return localusecnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Sun Microsystems AU format (signed linear)";
} }
char *key() char *key()

View File

@ -47,81 +47,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define G723_MAX_SIZE 1024 #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) static struct ast_frame *g723_read(struct ast_filestream *s, int *whennext)
{ {
unsigned short size; unsigned short size;
int res; int res;
int delay; int delay;
/* Read the delay for the next packet, and schedule again if necessary */ /* Read the delay for the next packet, and schedule again if necessary */
/* XXX is this ignored ? */
if (fread(&delay, 1, 4, s->f) == 4) if (fread(&delay, 1, 4, s->f) == 4)
delay = ntohl(delay); delay = ntohl(delay);
else 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 */ /* Looks like we have a frame to read from here */
size = ntohs(size); 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); ast_log(LOG_WARNING, "Size %d is invalid\n", size);
/* The file is apparently no longer any good, as we /* The file is apparently no longer any good, as we
shouldn't ever get frames even close to this 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; return NULL;
} }
/* Read the data into the buffer */ /* Read the data into the buffer */
s->fr->offset = AST_FRIENDLY_OFFSET; s->fr.frametype = AST_FRAME_VOICE;
s->fr->datalen = size; s->fr.subclass = AST_FORMAT_G723_1;
s->fr->data = s->buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET; s->fr.mallocd = 0;
if ((res = fread(s->fr->data, 1, size, s->f)) != size) { 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)); ast_log(LOG_WARNING, "Short read (%d of %d bytes) (%s)!\n", res, size, strerror(errno));
return NULL; return NULL;
} }
#if 0 *whennext = s->fr.samples = 240;
/* Average out frames <= 50 ms */ return &s->fr;
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;
} }
static void g723_close(struct ast_filestream *s) static int g723_write(struct ast_filestream *s, struct ast_frame *f)
{
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)
{ {
u_int32_t delay; u_int32_t delay;
u_int16_t size; u_int16_t size;
int res; int res;
if (fs->fr) { /* XXX there used to be a check s->fr means a read stream */
ast_log(LOG_WARNING, "Asked to write on a read stream??\n");
return -1;
}
if (f->frametype != AST_FRAME_VOICE) { if (f->frametype != AST_FRAME_VOICE) {
ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
return -1; 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); ast_log(LOG_WARNING, "Short frame ignored (%d bytes long?)\n", f->datalen);
return 0; 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)); ast_log(LOG_WARNING, "Unable to write delay: res=%d (%s)\n", res, strerror(errno));
return -1; return -1;
} }
size = htons(f->datalen); 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)); ast_log(LOG_WARNING, "Unable to write size: res=%d (%s)\n", res, strerror(errno));
return -1; 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)); ast_log(LOG_WARNING, "Unable to write frame: res=%d (%s)\n", res, strerror(errno));
return -1; return -1;
} }
@ -232,43 +138,41 @@ static off_t g723_tell(struct ast_filestream *fs)
return -1; return -1;
} }
static char *g723_getcomment(struct ast_filestream *s) static struct ast_format_lock me = { .usecnt = -1 };
{
return NULL; 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() int load_module()
{ {
return ast_format_register(name, exts, AST_FORMAT_G723_1, return ast_format_register(&g723_1_f);
g723_open,
g723_rewrite,
g723_write,
g723_seek,
g723_trunc,
g723_tell,
g723_read,
g723_close,
g723_getcomment);
} }
int unload_module() int unload_module()
{ {
return ast_format_unregister(name); return ast_format_unregister(g723_1_f.name);
} }
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "G.723.1 Simple Timestamp File Format";
} }
char *key() char *key()
{ {
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;

View File

@ -58,6 +58,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/* We can only read/write chunks of FRAME_TIME ms G.726 data */ /* We can only read/write chunks of FRAME_TIME ms G.726 data */
#define FRAME_TIME 10 /* 10 ms size */ #define FRAME_TIME 10 /* 10 ms size */
#define BUF_SIZE (5*FRAME_TIME) /* max frame size in bytes ? */
/* Frame sizes in bytes */ /* Frame sizes in bytes */
static int frame_size[4] = { static int frame_size[4] = {
FRAME_TIME * 5, FRAME_TIME * 5,
@ -66,293 +67,79 @@ static int frame_size[4] = {
FRAME_TIME * 2 FRAME_TIME * 2
}; };
struct ast_filestream { struct g726_desc {
/* 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 */ 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 */
}; };
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) * 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 struct g726_desc *s = (struct g726_desc *)tmp->private;
if we did, it would go here. We also might want to check s->rate = rate;
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) if (option_debug)
ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n",
40 - tmp->rate * 8); 40 - s->rate * 8);
ast_mutex_unlock(&g726_lock); return 0;
ast_update_use_count();
}
return tmp;
} }
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 return g726_open(s, RATE_40);
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;
} }
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 return g726_open(s, RATE_32);
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;
} }
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 return g726_open(s, RATE_24);
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;
} }
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 return g726_open(s, RATE_16);
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;
} }
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 return g726_open(s, RATE_40);
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;
} }
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 return g726_open(s, RATE_32);
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;
} }
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 return g726_open(s, RATE_24);
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; static int g726_16_rewrite(struct ast_filestream *s, const char *comment)
if ((tmp = malloc(sizeof(struct ast_filestream)))) { {
memset(tmp, 0, sizeof(struct ast_filestream)); return g726_open(s, RATE_16);
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;
} }
/* /*
* Rate independent format functions (close, read, write) * Rate independent format functions (read, write)
*/ */
static void g726_close(struct ast_filestream *s)
{
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;
}
static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext) static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext)
{ {
int res; int res;
struct g726_desc *fs = (struct g726_desc *)s->private;
/* Send a frame from the file to the appropriate channel */ /* Send a frame from the file to the appropriate channel */
s->fr.frametype = AST_FRAME_VOICE; s->fr.frametype = AST_FRAME_VOICE;
s->fr.subclass = AST_FORMAT_G726; 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.mallocd = 0;
s->fr.data = s->g726; FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, frame_size[fs->rate]);
if ((res = fread(s->g726, 1, s->fr.datalen, s->f)) != s->fr.datalen) { s->fr.samples = 8 * FRAME_TIME;
if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
if (res) if (res)
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL; return NULL;
@ -361,9 +148,11 @@ static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext)
return &s->fr; 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; int res;
struct g726_desc *fs = (struct g726_desc *)s->private;
if (f->frametype != AST_FRAME_VOICE) { if (f->frametype != AST_FRAME_VOICE) {
ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
return -1; return -1;
@ -378,7 +167,7 @@ static int g726_write(struct ast_filestream *fs, struct ast_frame *f)
f->datalen, frame_size[fs->rate]); f->datalen, frame_size[fs->rate]);
return -1; 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", ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n",
res, frame_size[fs->rate], strerror(errno)); res, frame_size[fs->rate], strerror(errno));
return -1; return -1;
@ -386,11 +175,6 @@ static int g726_write(struct ast_filestream *fs, struct ast_frame *f)
return 0; 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) static int g726_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
{ {
return -1; return -1;
@ -406,107 +190,107 @@ static off_t g726_tell(struct ast_filestream *fs)
return -1; 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) * Module interface (load_module, unload_module, usecount, description, key)
*/ */
int load_module() int load_module()
{ {
int res; int i;
res = ast_format_register(name40, exts40, AST_FORMAT_G726, for (i = 0; f[i].format ; i++) {
g726_40_open, if (ast_format_register(&f[i])) { /* errors are fatal */
g726_40_rewrite, ast_log(LOG_WARNING, "Failed to register format %s.\n", f[i].name);
g726_write, return -1;
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, return 0;
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);
}
return(0);
} }
int unload_module() int unload_module()
{ {
int res; int i;
res = ast_format_unregister(name16); for (i = 0; f[i].format ; i++) {
if (res) { if (ast_format_unregister(f[i].name))
ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name16); ast_log(LOG_WARNING, "Failed to unregister format %s.\n", f[i].name);
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);
} }
return(0); return(0);
} }
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Raw G.726 (16/24/32/40kbps) data";
} }
char *key() char *key()

View File

@ -51,88 +51,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/* Portions of the conversion code are by guido@sienanet.it */ /* Portions of the conversion code are by guido@sienanet.it */
struct ast_filestream { #define BUF_SIZE 20 /* two G729 frames */
void *reserved[AST_RESERVED_POINTERS]; #define G729A_SAMPLES 160
/* 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;
}
static struct ast_frame *g729_read(struct ast_filestream *s, int *whennext) 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 */ /* Send a frame from the file to the appropriate channel */
s->fr.frametype = AST_FRAME_VOICE; s->fr.frametype = AST_FRAME_VOICE;
s->fr.subclass = AST_FORMAT_G729A; 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.mallocd = 0;
s->fr.data = s->g729; s->fr.samples = G729A_SAMPLES;
if ((res = fread(s->g729, 1, 20, s->f)) != 20) { FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
if (res && (res != 10)) 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)); ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL; return NULL;
} }
@ -176,11 +94,6 @@ static int g729_write(struct ast_filestream *fs, struct ast_frame *f)
return 0; 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) static int g729_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
{ {
long bytes; 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); fseeko(fs->f, 0, SEEK_END);
max = ftello(fs->f); max = ftello(fs->f);
bytes = 20 * (sample_offset / 160); bytes = BUF_SIZE * (sample_offset / G729A_SAMPLES);
if (whence == SEEK_SET) if (whence == SEEK_SET)
offset = bytes; offset = bytes;
else if (whence == SEEK_CUR || whence == SEEK_FORCECUR) 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) static off_t g729_tell(struct ast_filestream *fs)
{ {
off_t offset; off_t offset = ftello(fs->f);
offset = ftello(fs->f); return (offset/BUF_SIZE)*G729A_SAMPLES;
return (offset/20)*160;
} }
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() int load_module()
{ {
return ast_format_register(name, exts, AST_FORMAT_G729A, return ast_format_register(&g729_f);
g729_open,
g729_rewrite,
g729_write,
g729_seek,
g729_trunc,
g729_tell,
g729_read,
g729_close,
g729_getcomment);
} }
int unload_module() int unload_module()
{ {
return ast_format_unregister(name); return ast_format_unregister(g729_f.name);
} }
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Raw G729 data";
} }
char *key() char *key()
{ {
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;

View File

@ -50,6 +50,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/* Portions of the conversion code are by guido@sienanet.it */ /* Portions of the conversion code are by guido@sienanet.it */
#define GSM_FRAME_SIZE 33
#define GSM_SAMPLES 160
/* silent gsm frame */ /* silent gsm frame */
/* begin binary data: */ /* begin binary data: */
char gsm_silence[] = /* 33 */ char gsm_silence[] = /* 33 */
@ -58,111 +61,28 @@ char gsm_silence[] = /* 33 */
,0x92,0x49,0x24}; ,0x92,0x49,0x24};
/* end binary data. size = 33 bytes */ /* 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) static struct ast_frame *gsm_read(struct ast_filestream *s, int *whennext)
{ {
int res; int res;
s->fr.frametype = AST_FRAME_VOICE; s->fr.frametype = AST_FRAME_VOICE;
s->fr.subclass = AST_FORMAT_GSM; s->fr.subclass = AST_FORMAT_GSM;
s->fr.offset = AST_FRIENDLY_OFFSET; FR_SET_BUF(&(s->fr), s->buf, AST_FRIENDLY_OFFSET, GSM_FRAME_SIZE)
s->fr.samples = 160;
s->fr.datalen = 33;
s->fr.mallocd = 0; s->fr.mallocd = 0;
s->fr.data = s->gsm; if ((res = fread(s->fr.data, 1, GSM_FRAME_SIZE, s->f)) != GSM_FRAME_SIZE) {
if ((res = fread(s->gsm, 1, 33, s->f)) != 33) {
if (res) if (res)
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL; return NULL;
} }
*whennext = 160; *whennext = s->fr.samples = GSM_SAMPLES;
return &s->fr; return &s->fr;
} }
static int gsm_write(struct ast_filestream *fs, struct ast_frame *f) static int gsm_write(struct ast_filestream *fs, struct ast_frame *f)
{ {
int res; int res;
unsigned char gsm[66]; unsigned char gsm[2*GSM_FRAME_SIZE];
if (f->frametype != AST_FRAME_VOICE) { if (f->frametype != AST_FRAME_VOICE) {
ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
return -1; return -1;
@ -176,14 +96,14 @@ static int gsm_write(struct ast_filestream *fs, struct ast_frame *f)
int len=0; int len=0;
while(len < f->datalen) { while(len < f->datalen) {
conv65(f->data + len, gsm); 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)); ast_log(LOG_WARNING, "Bad write (%d/66): %s\n", res, strerror(errno));
return -1; return -1;
} }
len += 65; len += 65;
} }
} else { } 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); ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 33\n", f->datalen);
return -1; 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); fseeko(fs->f, 0, SEEK_END);
max = ftello(fs->f); max = ftello(fs->f);
/* have to fudge to frame here, so not fully to sample */ /* 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) if(whence == SEEK_SET)
offset = distance; offset = distance;
else if(whence == SEEK_CUR || whence == SEEK_FORCECUR) 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) { } else if (offset > max) {
int i; int i;
fseeko(fs->f, 0, SEEK_END); fseeko(fs->f, 0, SEEK_END);
for (i=0; i< (offset - max) / 33; i++) { for (i=0; i< (offset - max) / GSM_FRAME_SIZE; i++) {
fwrite(gsm_silence, 1, 33, fs->f); fwrite(gsm_silence, 1, GSM_FRAME_SIZE, fs->f);
} }
} }
return fseeko(fs->f, offset, SEEK_SET); 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) static off_t gsm_tell(struct ast_filestream *fs)
{ {
off_t offset; off_t offset = ftello(fs->f);
offset = ftello(fs->f); return (offset/GSM_FRAME_SIZE)*GSM_SAMPLES;
return (offset/33)*160;
} }
static char *gsm_getcomment(struct ast_filestream *s) static struct ast_format_lock me = { .usecnt = -1 };
{
return NULL; 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() int load_module()
{ {
return ast_format_register(name, exts, AST_FORMAT_GSM, return ast_format_register(&gsm_f);
gsm_open,
gsm_rewrite,
gsm_write,
gsm_seek,
gsm_trunc,
gsm_tell,
gsm_read,
gsm_close,
gsm_getcomment);
} }
int unload_module() int unload_module()
{ {
return ast_format_unregister(name); return ast_format_unregister(gsm_f.name);
} }
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Raw GSM data";
} }
char *key() char *key()
{ {
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;

View File

@ -48,133 +48,60 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/* Portions of the conversion code are by guido@sienanet.it */ /* Portions of the conversion code are by guido@sienanet.it */
struct ast_filestream { #define BUF_SIZE 4096 /* Two Real h263 Frames */
void *reserved[AST_RESERVED_POINTERS];
/* Believe it or not, we must decode/recode to account for the struct h263_desc {
weird MS format */
/* This is what a filestream means to us */
FILE *f; /* Descriptor */
unsigned int lastts; 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 h263_open(struct ast_filestream *s)
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)
{ {
/* 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; unsigned int ts;
int res; 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"); ast_log(LOG_WARNING, "Empty file!\n");
return NULL; return -1;
} }
return 0;
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;
}
glistcnt--;
ast_mutex_unlock(&h263_lock);
ast_update_use_count();
fclose(s->f);
free(s);
s = NULL;
} }
static struct ast_frame *h263_read(struct ast_filestream *s, int *whennext) static struct ast_frame *h263_read(struct ast_filestream *s, int *whennext)
{ {
int res; int res;
int mark=0; int mark;
unsigned short len; unsigned short len;
unsigned int ts; unsigned int ts;
struct h263_desc *fs = (struct h263_desc *)s->private;
/* Send a frame from the file to the appropriate channel */ /* Send a frame from the file to the appropriate channel */
if ((res = fread(&len, 1, sizeof(len), s->f)) < 1)
return NULL;
len = ntohs(len);
mark = (len & 0x8000) ? 1 : 0;
len &= 0x7fff;
if (len > BUF_SIZE) {
ast_log(LOG_WARNING, "Length %d is too long\n", len);
len = BUF_SIZE; /* XXX truncate ? */
}
s->fr.frametype = AST_FRAME_VIDEO; s->fr.frametype = AST_FRAME_VIDEO;
s->fr.subclass = AST_FORMAT_H263; s->fr.subclass = AST_FORMAT_H263;
s->fr.offset = AST_FRIENDLY_OFFSET;
s->fr.mallocd = 0; s->fr.mallocd = 0;
s->fr.data = s->h263; FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, len);
if ((res = fread(&len, 1, sizeof(len), s->f)) < 1) { if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
return NULL;
}
len = ntohs(len);
if (len & 0x8000) {
mark = 1;
}
len &= 0x7fff;
if (len > sizeof(s->h263)) {
ast_log(LOG_WARNING, "Length %d is too long\n", len);
}
if ((res = fread(s->h263, 1, len, s->f)) != len) {
if (res) if (res)
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL; return NULL;
} }
s->fr.samples = s->lastts; s->fr.samples = fs->lastts; /* XXX what ? */
s->fr.datalen = len; s->fr.datalen = len;
s->fr.subclass |= mark; s->fr.subclass |= mark;
s->fr.delivery.tv_sec = 0; s->fr.delivery.tv_sec = 0;
s->fr.delivery.tv_usec = 0; s->fr.delivery.tv_usec = 0;
if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) { if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) {
s->lastts = ntohl(ts); fs->lastts = ntohl(ts);
*whennext = s->lastts * 4/45; *whennext = fs->lastts * 4/45;
} else } else
*whennext = 0; *whennext = 0;
return &s->fr; return &s->fr;
@ -216,11 +143,6 @@ static int h263_write(struct ast_filestream *fs, struct ast_frame *f)
return 0; 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) static int h263_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
{ {
/* No way Jose */ /* No way Jose */
@ -237,44 +159,47 @@ static int h263_trunc(struct ast_filestream *fs)
static off_t h263_tell(struct ast_filestream *fs) static off_t h263_tell(struct ast_filestream *fs)
{ {
/* XXX This is totally bogus XXX */ off_t offset = ftello(fs->f);
off_t offset; return offset; /* XXX totally bogus, needs fixing */
offset = ftello(fs->f);
return (offset/20)*160;
} }
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() int load_module()
{ {
return ast_format_register(name, exts, AST_FORMAT_H263, return ast_format_register(&h263_f);
h263_open,
h263_rewrite,
h263_write,
h263_seek,
h263_trunc,
h263_tell,
h263_read,
h263_close,
h263_getcomment);
} }
int unload_module() int unload_module()
{ {
return ast_format_unregister(name); return ast_format_unregister(h263_f.name);
} }
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Raw h263 data";
} }
char *key() char *key()
{ {
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;

View File

@ -47,96 +47,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/* Some Ideas for this code came from makeh264e.c by Jeffrey Chilton */ /* Some Ideas for this code came from makeh264e.c by Jeffrey Chilton */
/* Portions of the conversion code are by guido@sienanet.it */ /* Portions of the conversion code are by guido@sienanet.it */
#define BUF_SIZE 4096 /* Two Real h264 Frames */
struct ast_filestream { struct h264_desc {
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 */
unsigned int lastts; 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 */
}; };
static int h264_open(struct ast_filestream *s)
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)
{ {
/* 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; unsigned int ts;
int res; 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"); ast_log(LOG_WARNING, "Empty file!\n");
return NULL; return -1;
} }
return 0;
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;
}
glistcnt--;
ast_mutex_unlock(&h264_lock);
ast_update_use_count();
fclose(s->f);
free(s);
s = NULL;
} }
static struct ast_frame *h264_read(struct ast_filestream *s, int *whennext) 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; int mark=0;
unsigned short len; unsigned short len;
unsigned int ts; unsigned int ts;
struct h264_desc *fs = (struct h264_desc *)s->private;
/* Send a frame from the file to the appropriate channel */ /* Send a frame from the file to the appropriate channel */
if ((res = fread(&len, 1, sizeof(len), s->f)) < 1)
return NULL;
len = ntohs(len);
mark = (len & 0x8000) ? 1 : 0;
len &= 0x7fff;
if (len > BUF_SIZE) {
ast_log(LOG_WARNING, "Length %d is too long\n", len);
len = BUF_SIZE; /* XXX truncate */
}
s->fr.frametype = AST_FRAME_VIDEO; s->fr.frametype = AST_FRAME_VIDEO;
s->fr.subclass = AST_FORMAT_H264; s->fr.subclass = AST_FORMAT_H264;
s->fr.offset = AST_FRIENDLY_OFFSET;
s->fr.mallocd = 0; s->fr.mallocd = 0;
s->fr.data = s->h264; FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, len);
if ((res = fread(&len, 1, sizeof(len), s->f)) < 1) { if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
return NULL;
}
len = ntohs(len);
if (len & 0x8000) {
mark = 1;
}
len &= 0x7fff;
if (len > sizeof(s->h264)) {
ast_log(LOG_WARNING, "Length %d is too long\n", len);
}
if ((res = fread(s->h264, 1, len, s->f)) != len) {
if (res) if (res)
ast_log(LOG_WARNING, "Short read (%d of %d) (%s)!\n", res, len, strerror(errno)); ast_log(LOG_WARNING, "Short read (%d of %d) (%s)!\n", res, len, strerror(errno));
return NULL; return NULL;
} }
s->fr.samples = s->lastts; s->fr.samples = fs->lastts;
s->fr.datalen = len; s->fr.datalen = len;
s->fr.subclass |= mark; s->fr.subclass |= mark;
s->fr.delivery.tv_sec = 0; s->fr.delivery.tv_sec = 0;
s->fr.delivery.tv_usec = 0; s->fr.delivery.tv_usec = 0;
if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) { if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) {
s->lastts = ntohl(ts); fs->lastts = ntohl(ts);
*whennext = s->lastts * 4/45; *whennext = fs->lastts * 4/45;
} else } else
*whennext = 0; *whennext = 0;
return &s->fr; 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; int res;
unsigned int ts; unsigned int ts;
unsigned short len; unsigned short len;
int subclass; int mark;
int mark=0;
if (f->frametype != AST_FRAME_VIDEO) { if (f->frametype != AST_FRAME_VIDEO) {
ast_log(LOG_WARNING, "Asked to write non-video frame!\n"); ast_log(LOG_WARNING, "Asked to write non-video frame!\n");
return -1; return -1;
} }
subclass = f->subclass; mark = (f->subclass & 0x1) ? 0x8000 : 0;
if (subclass & 0x1) if ((f->subclass & ~0x1) != AST_FORMAT_H264) {
mark=0x8000;
subclass &= ~0x1;
if (subclass != AST_FORMAT_H264) {
ast_log(LOG_WARNING, "Asked to write non-h264 frame (%d)!\n", f->subclass); ast_log(LOG_WARNING, "Asked to write non-h264 frame (%d)!\n", f->subclass);
return -1; return -1;
} }
ts = htonl(f->samples); ts = htonl(f->samples);
if ((res = fwrite(&ts, 1, sizeof(ts), fs->f)) != sizeof(ts)) { if ((res = fwrite(&ts, 1, sizeof(ts), s->f)) != sizeof(ts)) {
ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno)); ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno));
return -1; return -1;
} }
len = htons(f->datalen | mark); len = htons(f->datalen | mark);
if ((res = fwrite(&len, 1, sizeof(len), fs->f)) != sizeof(len)) { if ((res = fwrite(&len, 1, sizeof(len), s->f)) != sizeof(len)) {
ast_log(LOG_WARNING, "Bad write (%d/2): %s\n", res, strerror(errno)); ast_log(LOG_WARNING, "Bad write (%d/2): %s\n", res, strerror(errno));
return -1; 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)); ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
return -1; return -1;
} }
return 0; 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) static int h264_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
{ {
/* No way Jose */ /* No way Jose */
@ -237,44 +152,47 @@ static int h264_trunc(struct ast_filestream *fs)
static off_t h264_tell(struct ast_filestream *fs) static off_t h264_tell(struct ast_filestream *fs)
{ {
/* XXX This is totally bogus XXX */ off_t offset = ftell(fs->f);
off_t offset; return offset; /* XXX totally bogus, needs fixing */
offset = ftell(fs->f);
return (offset/20)*160;
} }
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() int load_module()
{ {
return ast_format_register(name, exts, AST_FORMAT_H264, return ast_format_register(&h264_f);
h264_open,
h264_rewrite,
h264_write,
h264_seek,
h264_trunc,
h264_tell,
h264_read,
h264_close,
h264_getcomment);
} }
int unload_module() int unload_module()
{ {
return ast_format_unregister(name); return ast_format_unregister(h264_f.name);
} }
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Raw h264 data";
} }
char *key() char *key()
{ {
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;

View File

@ -50,88 +50,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/* Portions of the conversion code are by guido@sienanet.it */ /* Portions of the conversion code are by guido@sienanet.it */
struct ast_filestream { #define ILBC_BUF_SIZE 50 /* One Real iLBC Frame */
void *reserved[AST_RESERVED_POINTERS]; #define ILBC_SAMPLES 240
/* 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;
}
static struct ast_frame *ilbc_read(struct ast_filestream *s, int *whennext) 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 */ /* Send a frame from the file to the appropriate channel */
s->fr.frametype = AST_FRAME_VOICE; s->fr.frametype = AST_FRAME_VOICE;
s->fr.subclass = AST_FORMAT_ILBC; 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.mallocd = 0;
s->fr.data = s->ilbc; FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, ILBC_BUF_SIZE);
if ((res = fread(s->ilbc, 1, 50, s->f)) != 50) { if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
if (res) if (res)
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL; return NULL;
} }
*whennext = s->fr.samples; *whennext = s->fr.samples = ILBC_SAMPLES;
return &s->fr; return &s->fr;
} }
@ -175,11 +92,6 @@ static int ilbc_write(struct ast_filestream *fs, struct ast_frame *f)
return 0; 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) static int ilbc_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
{ {
long bytes; 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); fseeko(fs->f, 0, SEEK_END);
max = ftello(fs->f); max = ftello(fs->f);
bytes = 50 * (sample_offset / 240); bytes = ILBC_BUF_SIZE * (sample_offset / ILBC_SAMPLES);
if (whence == SEEK_SET) if (whence == SEEK_SET)
offset = bytes; offset = bytes;
else if (whence == SEEK_CUR || whence == SEEK_FORCECUR) 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) static off_t ilbc_tell(struct ast_filestream *fs)
{ {
off_t offset; off_t offset = ftello(fs->f);
offset = ftello(fs->f); return (offset/ILBC_BUF_SIZE)*ILBC_SAMPLES;
return (offset/50)*240;
} }
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() int load_module()
{ {
return ast_format_register(name, exts, AST_FORMAT_ILBC, return ast_format_register(&ilbc_f);
ilbc_open,
ilbc_rewrite,
ilbc_write,
ilbc_seek,
ilbc_trunc,
ilbc_tell,
ilbc_read,
ilbc_close,
ilbc_getcomment);
} }
int unload_module() int unload_module()
{ {
return ast_format_unregister(name); return ast_format_unregister(ilbc_f.name);
} }
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Raw iLBC data";
} }
char *key() char *key()
{ {
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;

View File

@ -51,11 +51,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define SAMPLES_MAX 160 #define SAMPLES_MAX 160
#define BLOCK_SIZE 4096 #define BLOCK_SIZE 4096
struct ast_filestream { struct vorbis_desc {
void *reserved[AST_RESERVED_POINTERS];
FILE *f;
/* structures for handling the Ogg container */ /* structures for handling the Ogg container */
ogg_sync_state oy; ogg_sync_state oy;
ogg_stream_state os; ogg_stream_state os;
@ -73,14 +69,6 @@ struct ast_filestream {
/*! \brief Indicates whether an End of Stream condition has been detected. */ /*! \brief Indicates whether an End of Stream condition has been detected. */
int eos; 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); AST_MUTEX_DEFINE_STATIC(ogg_vorbis_lock);
@ -96,18 +84,14 @@ static char *exts = "ogg";
* \param f File that points to on disk storage of the OGG/Vorbis data. * \param f File that points to on disk storage of the OGG/Vorbis data.
* \return The new filestream. * \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 i;
int bytes; int bytes;
int result; int result;
char **ptr; char **ptr;
char *buffer; 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->writing = 0;
tmp->f = f; tmp->f = f;
@ -120,16 +104,13 @@ static struct ast_filestream *ogg_vorbis_open(FILE * f)
result = ogg_sync_pageout(&tmp->oy, &tmp->og); result = ogg_sync_pageout(&tmp->oy, &tmp->og);
if (result != 1) { if (result != 1) {
if (bytes < BLOCK_SIZE) { if(bytes < BLOCK_SIZE) {
ast_log(LOG_ERROR, "Run out of data...\n"); ast_log(LOG_ERROR, "Run out of data...\n");
} else { } else {
ast_log(LOG_ERROR, ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n");
"Input does not appear to be an Ogg bitstream.\n");
} }
fclose(f);
ogg_sync_clear(&tmp->oy); ogg_sync_clear(&tmp->oy);
free(tmp); return -1;
return NULL;
} }
ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og)); ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og));
@ -137,60 +118,39 @@ static struct ast_filestream *ogg_vorbis_open(FILE * f)
vorbis_comment_init(&tmp->vc); vorbis_comment_init(&tmp->vc);
if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) { if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) {
ast_log(LOG_ERROR, ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n");
"Error reading first page of Ogg bitstream data.\n"); error:
fclose(f);
ogg_stream_clear(&tmp->os); ogg_stream_clear(&tmp->os);
vorbis_comment_clear(&tmp->vc); vorbis_comment_clear(&tmp->vc);
vorbis_info_clear(&tmp->vi); vorbis_info_clear(&tmp->vi);
ogg_sync_clear(&tmp->oy); ogg_sync_clear(&tmp->oy);
free(tmp); return -1;
return NULL;
} }
if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) { if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) {
ast_log(LOG_ERROR, "Error reading initial header packet.\n"); ast_log(LOG_ERROR, "Error reading initial header packet.\n");
fclose(f); goto error;
ogg_stream_clear(&tmp->os);
vorbis_comment_clear(&tmp->vc);
vorbis_info_clear(&tmp->vi);
ogg_sync_clear(&tmp->oy);
free(tmp);
return NULL;
} }
if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) { 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"); ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n");
fclose(f); goto error;
ogg_stream_clear(&tmp->os);
vorbis_comment_clear(&tmp->vc);
vorbis_info_clear(&tmp->vi);
ogg_sync_clear(&tmp->oy);
free(tmp);
return NULL;
} }
i = 0; for (i = 0; i < 2 ; ) {
while (i < 2) {
while (i < 2) { while (i < 2) {
result = ogg_sync_pageout(&tmp->oy, &tmp->og); result = ogg_sync_pageout(&tmp->oy, &tmp->og);
if (result == 0) if (result == 0)
break; break;
if (result == 1) { if (result == 1) {
ogg_stream_pagein(&tmp->os, &tmp->og); ogg_stream_pagein(&tmp->os, &tmp->og);
while (i < 2) { while(i < 2) {
result = ogg_stream_packetout(&tmp->os, &tmp->op); result = ogg_stream_packetout(&tmp->os,&tmp->op);
if (result == 0) if(result == 0)
break; break;
if (result < 0) { if(result < 0) {
ast_log(LOG_ERROR, "Corrupt secondary header. Exiting.\n"); ast_log(LOG_ERROR, "Corrupt secondary header. Exiting.\n");
fclose(f); goto error;
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); vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op);
i++; i++;
@ -200,72 +160,47 @@ static struct ast_filestream *ogg_vorbis_open(FILE * f)
buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE); buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
bytes = fread(buffer, 1, BLOCK_SIZE, f); bytes = fread(buffer, 1, BLOCK_SIZE, f);
if (bytes == 0 && i < 2) { if(bytes == 0 && i < 2) {
ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n"); ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n");
fclose(f); goto error;
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); ogg_sync_wrote(&tmp->oy, bytes);
} }
ptr = tmp->vc.user_comments; ptr = tmp->vc.user_comments;
while (*ptr) { while(*ptr){
ast_log(LOG_DEBUG, "OGG/Vorbis comment: %s\n", *ptr); ast_log(LOG_DEBUG, "OGG/Vorbis comment: %s\n", *ptr);
++ptr; ++ptr;
} }
ast_log(LOG_DEBUG, "OGG/Vorbis bitstream is %d channel, %ldHz\n", ast_log(LOG_DEBUG, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate);
tmp->vi.channels, tmp->vi.rate); ast_log(LOG_DEBUG, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor);
ast_log(LOG_DEBUG, "OGG/Vorbis file encoded by: %s\n",
tmp->vc.vendor);
if (tmp->vi.channels != 1) { if(tmp->vi.channels != 1) {
ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n"); ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n");
ogg_stream_clear(&tmp->os); goto error;
vorbis_comment_clear(&tmp->vc);
vorbis_info_clear(&tmp->vi);
ogg_sync_clear(&tmp->oy);
free(tmp);
return NULL;
} }
if (tmp->vi.rate != 8000) {
if(tmp->vi.rate != DEFAULT_SAMPLE_RATE) {
ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n"); 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_block_clear(&tmp->vb);
vorbis_dsp_clear(&tmp->vd); vorbis_dsp_clear(&tmp->vd);
vorbis_comment_clear(&tmp->vc); goto error;
vorbis_info_clear(&tmp->vi);
ogg_sync_clear(&tmp->oy);
free(tmp);
return NULL;
} }
vorbis_synthesis_init(&tmp->vd, &tmp->vi); vorbis_synthesis_init(&tmp->vd, &tmp->vi);
vorbis_block_init(&tmp->vd, &tmp->vb); vorbis_block_init(&tmp->vd, &tmp->vb);
if (ast_mutex_lock(&ogg_vorbis_lock)) { if(ast_mutex_lock(&ogg_vorbis_lock)) {
ast_log(LOG_WARNING, "Unable to lock ogg_vorbis list\n"); ast_log(LOG_WARNING, "Unable to lock ogg_vorbis list\n");
fclose(f);
ogg_stream_clear(&tmp->os);
vorbis_block_clear(&tmp->vb); vorbis_block_clear(&tmp->vb);
vorbis_dsp_clear(&tmp->vd); vorbis_dsp_clear(&tmp->vd);
vorbis_comment_clear(&tmp->vc); goto error;
vorbis_info_clear(&tmp->vi);
ogg_sync_clear(&tmp->oy);
free(tmp);
return NULL;
} }
glistcnt++; glistcnt++;
ast_mutex_unlock(&ogg_vorbis_lock); ast_mutex_unlock(&ogg_vorbis_lock);
ast_update_use_count(); ast_update_use_count();
} return 0;
return tmp;
} }
/*! /*!
@ -291,7 +226,7 @@ static struct ast_filestream *ogg_vorbis_rewrite(FILE * f,
vorbis_info_init(&tmp->vi); 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"); ast_log(LOG_ERROR, "Unable to initialize Vorbis encoder!\n");
free(tmp); free(tmp);
return NULL; return NULL;
@ -440,9 +375,6 @@ static void ogg_vorbis_close(struct ast_filestream *s)
if (s->writing) { if (s->writing) {
ogg_sync_clear(&s->oy); 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; 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() int load_module()
{ {
return ast_format_register(name, exts, AST_FORMAT_SLINEAR, return ast_format_register(&vorbis_f);
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);
} }
int unload_module() int unload_module()
@ -664,7 +606,7 @@ int unload_module()
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()

View File

@ -45,135 +45,67 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h" #include "asterisk/module.h"
#include "asterisk/endian.h" #include "asterisk/endian.h"
#include "asterisk/ulaw.h" #include "asterisk/ulaw.h"
#include "asterisk/alaw.h"
#define BUF_SIZE 160 /* 160 samples */ #define BUF_SIZE 160 /* 160 bytes, and same number of 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(pcm_lock);
static int glistcnt = 0;
static char *name = "pcm";
static char *desc = "Raw uLaw 8khz Audio support (PCM)";
static char *exts = "pcm|ulaw|ul|mu";
static char ulaw_silence[BUF_SIZE]; static char ulaw_silence[BUF_SIZE];
static char alaw_silence[BUF_SIZE];
static struct ast_filestream *pcm_open(FILE *f) /* #define REALTIME_WRITE */ /* XXX does it work at all ? */
#ifdef REALTIME_WRITE
struct pcm_desc {
unsigned long start_time;
};
/* 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 struct tms buf;
if we did, it would go here. We also might want to check clock_t cur;
and be sure it's a valid file. */
struct ast_filestream *tmp; cur = times( &buf );
if ((tmp = malloc(sizeof(struct ast_filestream)))) { if( cur < 0 ) {
memset(tmp, 0, sizeof(struct ast_filestream)); ast_log( LOG_WARNING, "Cannot get current time\n" );
if (ast_mutex_lock(&pcm_lock)) { return 0;
ast_log(LOG_WARNING, "Unable to lock pcm list\n");
free(tmp);
return NULL;
} }
tmp->f = f; return cur * 1000 / sysconf( _SC_CLK_TCK );
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();
}
return tmp;
} }
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 (s->fmt->format == AST_FORMAT_ALAW)
if we did, it would go here. We also might want to check pd->starttime = get_time();
and be sure it's a valid file. */ return 0;
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;
} }
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)) { return pcma_open(s);
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;
} }
#endif
static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext) static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext)
{ {
int res; int res;
int delay;
/* Send a frame from the file to the appropriate channel */ /* Send a frame from the file to the appropriate channel */
s->fr.frametype = AST_FRAME_VOICE; s->fr.frametype = AST_FRAME_VOICE;
s->fr.subclass = AST_FORMAT_ULAW; s->fr.subclass = s->fmt->format;
s->fr.offset = AST_FRIENDLY_OFFSET;
s->fr.mallocd = 0; s->fr.mallocd = 0;
s->fr.data = s->buf; FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) { if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) < 1) {
if (res) if (res)
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL; return NULL;
} }
s->fr.samples = res;
s->fr.datalen = res; s->fr.datalen = res;
delay = s->fr.samples; *whennext = s->fr.samples = res;
*whennext = delay;
return &s->fr; 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) static int pcm_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
{ {
off_t cur, max, offset = 0; 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 */ if (whence == SEEK_FORCECUR && offset > max) { /* extend the file */
size_t left = offset - max; size_t left = offset - max;
const char *src = (fs->fmt->format == AST_FORMAT_ALAW) ? alaw_silence : ulaw_silence;
while (left) { while (left) {
size_t written = fwrite(ulaw_silence, sizeof(ulaw_silence[0]), size_t written = fwrite(src, 1, (left > BUF_SIZE) ? BUF_SIZE : left, fs->f);
(left > BUF_SIZE) ? BUF_SIZE : left, fs->f);
if (written == -1) if (written == -1)
break; /* error */ break; /* error */
left -= written * sizeof(ulaw_silence[0]); left -= written;
} }
ret = 0; /* successful */ ret = 0; /* successful */
} else { } else {
@ -230,51 +162,336 @@ static int pcm_trunc(struct ast_filestream *fs)
static off_t pcm_tell(struct ast_filestream *fs) static off_t pcm_tell(struct ast_filestream *fs)
{ {
off_t offset; return ftello(fs->f);
offset = ftello(fs->f);
return offset;
} }
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 load_module()
{ {
int index; int index;
/* XXX better init ? */
for (index = 0; index < (sizeof(ulaw_silence) / sizeof(ulaw_silence[0])); index++) for (index = 0; index < (sizeof(ulaw_silence) / sizeof(ulaw_silence[0])); index++)
ulaw_silence[index] = AST_LIN2MU(0); 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, return ast_format_register(&pcm_f) || ast_format_register(&alaw_f)
pcm_open, || ast_format_register(&au_f);
pcm_rewrite,
pcm_write,
pcm_seek,
pcm_trunc,
pcm_tell,
pcm_read,
pcm_close,
pcm_getcomment);
} }
int unload_module() 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() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Raw/Sun uLaw/ALaw 8khz Audio support (PCM,PCMA,AU)";
} }
char *key() char *key()
{ {
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;

View File

@ -47,42 +47,25 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/endian.h" #include "asterisk/endian.h"
#include "asterisk/alaw.h" #include "asterisk/alaw.h"
#define BUF_SIZE 160 /* 160 samples */ #define BUF_SIZE 160 /* 160 bytes, and same number of samples */
/* #define REALTIME_WRITE */ /* #define REALTIME_WRITE */ /* XXX does it work at all ? */
struct ast_filestream { struct pcma_desc {
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 */
#ifdef REALTIME_WRITE #ifdef REALTIME_WRITE
unsigned long start_time; unsigned long start_time;
#endif #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]; static char alaw_silence[BUF_SIZE];
#if 0 #if 0
/* Returns time in msec since system boot. */ /* 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; struct tms buf;
clock_t cur; clock_t cur;
unsigned long *res;
cur = times( &buf ); cur = times( &buf );
if( cur < 0 ) if( cur < 0 )
@ -90,77 +73,26 @@ static unsigned long get_time(void)
ast_log( LOG_WARNING, "Cannot get current time\n" ); ast_log( LOG_WARNING, "Cannot get current time\n" );
return 0; return 0;
} }
return cur * 1000 / sysconf( _SC_CLK_TCK ); res = cur * 1000 / sysconf( _SC_CLK_TCK );
if (s) {
struct pcma_desc *d = (struct pcma_filestream *)s->private;
d->start_time = res;
}
return res;
} }
#endif #endif
static struct ast_filestream *pcm_open(FILE *f) 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;
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 #ifdef REALTIME_WRITE
tmp->start_time = get_time(); get_time(s);
#endif #endif
glistcnt++; return 0;
ast_mutex_unlock(&pcm_lock);
ast_update_use_count();
}
return tmp;
} }
static struct ast_filestream *pcm_rewrite(FILE *f, const char *comment) static int pcm_rewrite(struct ast_filestream *s, const char *comment)
{ {
/* We don't have any header to read or anything really, but return pcm_open(s);
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();
#endif
glistcnt++;
ast_mutex_unlock(&pcm_lock);
ast_update_use_count();
} else
ast_log(LOG_WARNING, "Out of memory\n");
return tmp;
}
static void pcm_close(struct ast_filestream *s)
{
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;
} }
static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext) 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.frametype = AST_FRAME_VOICE;
s->fr.subclass = AST_FORMAT_ALAW; s->fr.subclass = AST_FORMAT_ALAW;
s->fr.offset = AST_FRIENDLY_OFFSET;
s->fr.mallocd = 0; s->fr.mallocd = 0;
s->fr.data = s->buf; FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) { if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) < 1) {
if (res) if (res)
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL; return NULL;
} }
s->fr.samples = res;
s->fr.datalen = res; s->fr.datalen = res;
*whennext = s->fr.samples; *whennext = s->fr.samples = res;
return &s->fr; 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 cur_time;
unsigned long fpos; unsigned long fpos;
struct stat stat_buf; struct stat stat_buf;
struct pcma_filestream *s = (struct pcma_filestream *)fs->private;
#endif #endif
if (f->frametype != AST_FRAME_VOICE) { 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 #ifdef REALTIME_WRITE
cur_time = get_time(); 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 /* 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. * 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) static off_t pcm_tell(struct ast_filestream *fs)
{ {
off_t offset; return ftello(fs->f);
offset = ftello(fs->f);
return offset;
} }
static struct ast_format_lock me = { .usecnt = -1 };
static char *pcm_getcomment(struct ast_filestream *s) static const struct ast_format alaw_f = {
{ .name = "alaw",
return NULL; .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() int load_module()
{ {
@ -324,34 +267,24 @@ int load_module()
for (index = 0; index < (sizeof(alaw_silence) / sizeof(alaw_silence[0])); index++) for (index = 0; index < (sizeof(alaw_silence) / sizeof(alaw_silence[0])); index++)
alaw_silence[index] = AST_LIN2A(0); alaw_silence[index] = AST_LIN2A(0);
return ast_format_register(name, exts, AST_FORMAT_ALAW, return ast_format_register(&alaw_f);
pcm_open,
pcm_rewrite,
pcm_write,
pcm_seek,
pcm_trunc,
pcm_tell,
pcm_read,
pcm_close,
pcm_getcomment);
} }
int unload_module() int unload_module()
{ {
return ast_format_unregister(name); return ast_format_unregister(alaw_f.name);
} }
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Raw aLaw 8khz PCM Audio support";
} }
char *key() char *key()
{ {
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;

View File

@ -43,111 +43,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h" #include "asterisk/module.h"
#include "asterisk/endian.h" #include "asterisk/endian.h"
#define BUF_SIZE 320 /* 320 samples */ #define BUF_SIZE 320 /* 320 bytes, 160 samples */
#define SLIN_SAMPLES 160
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;
}
static struct ast_frame *slinear_read(struct ast_filestream *s, int *whennext) static struct ast_frame *slinear_read(struct ast_filestream *s, int *whennext)
{ {
int res; int res;
int delay;
/* Send a frame from the file to the appropriate channel */ /* Send a frame from the file to the appropriate channel */
s->fr.frametype = AST_FRAME_VOICE; s->fr.frametype = AST_FRAME_VOICE;
s->fr.subclass = AST_FORMAT_SLINEAR; s->fr.subclass = AST_FORMAT_SLINEAR;
s->fr.offset = AST_FRIENDLY_OFFSET; s->fr.offset = AST_FRIENDLY_OFFSET;
s->fr.mallocd = 0; s->fr.mallocd = 0;
s->fr.data = s->buf; FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) { if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) < 1) {
if (res) if (res)
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL; return NULL;
} }
s->fr.samples = res/2; *whennext = s->fr.samples = res/2;
s->fr.datalen = res; s->fr.datalen = res;
delay = s->fr.samples;
*whennext = delay;
return &s->fr; return &s->fr;
} }
@ -199,48 +114,44 @@ static int slinear_trunc(struct ast_filestream *fs)
static off_t slinear_tell(struct ast_filestream *fs) static off_t slinear_tell(struct ast_filestream *fs)
{ {
off_t offset; return ftello(fs->f) / 2;
offset = ftello(fs->f);
return offset / 2;
} }
static char *slinear_getcomment(struct ast_filestream *s) static struct ast_format_lock me = { .usecnt = -1 };
{
return NULL; 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() int load_module()
{ {
return ast_format_register(name, exts, AST_FORMAT_SLINEAR, return ast_format_register(&slin_f);
slinear_open,
slinear_rewrite,
slinear_write,
slinear_seek,
slinear_trunc,
slinear_tell,
slinear_read,
slinear_close,
slinear_getcomment);
} }
int unload_module() int unload_module()
{ {
return ast_format_unregister(name); return ast_format_unregister(slin_f.name);
} }
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Raw Signed Linear Audio support (SLN)";
} }
char *key() char *key()
{ {
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;

View File

@ -45,117 +45,29 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h" #include "asterisk/module.h"
#include "asterisk/endian.h" #include "asterisk/endian.h"
#define BUF_SIZE 80 /* 160 samples */ #define BUF_SIZE 80 /* 80 bytes, 160 samples */
#define VOX_SAMPLES 160
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;
}
static struct ast_frame *vox_read(struct ast_filestream *s, int *whennext) static struct ast_frame *vox_read(struct ast_filestream *s, int *whennext)
{ {
int res; int res;
/* Send a frame from the file to the appropriate channel */ /* Send a frame from the file to the appropriate channel */
s->fr.frametype = AST_FRAME_VOICE; s->fr.frametype = AST_FRAME_VOICE;
s->fr.subclass = AST_FORMAT_ADPCM; s->fr.subclass = AST_FORMAT_ADPCM;
s->fr.offset = AST_FRIENDLY_OFFSET;
s->fr.mallocd = 0; s->fr.mallocd = 0;
s->fr.data = s->buf; FR_SET_BUF(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) { if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) < 1) {
if (res) if (res)
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL; return NULL;
} }
s->fr.samples = res * 2; *whennext = s->fr.samples = res * 2;
s->fr.datalen = res; s->fr.datalen = res;
*whennext = s->fr.samples;
return &s->fr; 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; int res;
if (f->frametype != AST_FRAME_VOICE) { 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); ast_log(LOG_WARNING, "Asked to write non-ADPCM frame (%d)!\n", f->subclass);
return -1; 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)); ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
return -1; return -1;
} }
return 0; 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) static int vox_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
{ {
off_t offset=0,min,cur,max,distance; 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 > max)?max:offset;
offset = (offset < min)?min:offset; offset = (offset < min)?min:offset;
} }
fseeko(fs->f, offset, SEEK_SET); return fseeko(fs->f, offset, SEEK_SET);
return ftello(fs->f);
} }
static int vox_trunc(struct ast_filestream *fs) static int vox_trunc(struct ast_filestream *fs)
@ -215,38 +121,41 @@ static off_t vox_tell(struct ast_filestream *fs)
return offset; 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() int load_module()
{ {
return ast_format_register(name, exts, AST_FORMAT_ADPCM, return ast_format_register(&vox_f);
vox_open,
vox_rewrite,
vox_write,
vox_seek,
vox_trunc,
vox_tell,
vox_read,
vox_close,
vox_getcomment);
} }
int unload_module() int unload_module()
{ {
return ast_format_unregister(name); return ast_format_unregister(vox_f.name);
} }
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Dialogic VOX (ADPCM) File Format";
} }
char *key() char *key()
{ {
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;

View File

@ -49,30 +49,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/* Portions of the conversion code are by guido@sienanet.it */ /* Portions of the conversion code are by guido@sienanet.it */
struct ast_filestream { #define WAV_BUF_SIZE 320
void *reserved[AST_RESERVED_POINTERS];
/* This is what a filestream means to us */ struct wav_desc { /* format-specific parameters */
FILE *f; /* Descriptor */
int bytes; int bytes;
int needsgain; 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 lasttimeout;
int maxlen; int maxlen;
struct timeval last; 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 BLOCKSIZE 160
#define GAIN 2 /* 2^GAIN is the multiple to increase the volume by */ #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"); ast_log(LOG_WARNING, "Read failed (freq)\n");
return -1; return -1;
} }
if (ltohl(freq) != 8000) { if (ltohl(freq) != DEFAULT_SAMPLE_RATE) {
ast_log(LOG_WARNING, "Unexpected freqency %d\n", ltohl(freq)); ast_log(LOG_WARNING, "Unexpected freqency %d\n", ltohl(freq));
return -1; return -1;
} }
@ -233,7 +219,6 @@ static int update_header(FILE *f)
off_t cur,end; off_t cur,end;
int datalen,filelen,bytes; int datalen,filelen,bytes;
cur = ftello(f); cur = ftello(f);
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
end = ftello(f); end = ftello(f);
@ -333,135 +318,90 @@ static int write_header(FILE *f)
return 0; 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 /* 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 if we did, it would go here. We also might want to check
and be sure it's a valid file. */ and be sure it's a valid file. */
struct ast_filestream *tmp; struct wav_desc *tmp = (struct wav_desc *)s->private;
if ((tmp = malloc(sizeof(struct ast_filestream)))) { if ((tmp->maxlen = check_header(s->f)) < 0)
memset(tmp, 0, sizeof(struct ast_filestream)); return -1;
if ((tmp->maxlen = check_header(f)) < 0) { return 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;
} }
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 /* 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 if we did, it would go here. We also might want to check
and be sure it's a valid file. */ and be sure it's a valid file. */
struct ast_filestream *tmp;
if ((tmp = malloc(sizeof(struct ast_filestream)))) { if (write_header(s->f))
memset(tmp, 0, sizeof(struct ast_filestream)); return -1;
if (write_header(f)) { return 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;
glistcnt++;
ast_mutex_unlock(&wav_lock);
ast_update_use_count();
} else
ast_log(LOG_WARNING, "Out of memory\n");
return tmp;
} }
static void wav_close(struct ast_filestream *s) static void wav_close(struct ast_filestream *s)
{ {
char zero = 0; char zero = 0;
if (ast_mutex_lock(&wav_lock)) { struct wav_desc *fs = (struct wav_desc *)s->private;
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 */ /* Pad to even length */
if (s->bytes & 0x1) if (fs->bytes & 0x1)
fwrite(&zero, 1, 1, s->f); 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) static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext)
{ {
int res; int res;
int delay; int samples; /* actual samples read */
int x; int x;
short tmp[sizeof(s->buf) / 2]; short *tmp;
int bytes = sizeof(tmp); int bytes = WAV_BUF_SIZE; /* in bytes */
off_t here; off_t here;
/* Send a frame from the file to the appropriate channel */ /* Send a frame from the file to the appropriate channel */
struct wav_desc *fs = (struct wav_desc *)s->private;
here = ftello(s->f); here = ftello(s->f);
if ((s->maxlen - here) < bytes) if (fs->maxlen - here < bytes) /* truncate if necessary */
bytes = s->maxlen - here; bytes = fs->maxlen - here;
if (bytes < 0) if (bytes < 0)
bytes = 0; bytes = 0;
/* ast_log(LOG_DEBUG, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */ /* 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 = fread(s->fr.data, 1, s->fr.datalen, s->f)) <= 0 ) {
if (res) { if (res)
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
}
return NULL; return NULL;
} }
s->fr.datalen = res;
s->fr.samples = samples = res / 2;
tmp = (short *)(s->fr.data);
#if __BYTE_ORDER == __BIG_ENDIAN #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 #endif
if (s->needsgain) { if (fs->needsgain) {
for (x=0;x<sizeof(tmp)/2;x++) for (x=0; x < samples; x++) {
if (tmp[x] & ((1 << GAIN) - 1)) { if (tmp[x] & ((1 << GAIN) - 1)) {
/* If it has data down low, then it's not something we've artificially increased gain /* 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 */ on, so we don't need to gain adjust it */
s->needsgain = 0; fs->needsgain = 0;
break;
} }
} }
if (s->needsgain) { if (fs->needsgain) {
for (x=0;x<sizeof(tmp)/2;x++) { for (x=0; x < samples; x++)
s->buf[x] = tmp[x] >> GAIN; tmp[x] = tmp[x] >> GAIN;
} }
} else {
memcpy(s->buf, tmp, sizeof(s->buf));
} }
delay = res / 2; *whennext = samples;
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;
return &s->fr; return &s->fr;
} }
@ -470,6 +410,9 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
int x; int x;
short tmp[8000], *tmpi; short tmp[8000], *tmpi;
float tmpf; float tmpf;
struct wav_desc *s = (struct wav_desc *)fs->private;
int res;
if (f->frametype != AST_FRAME_VOICE) { if (f->frametype != AST_FRAME_VOICE) {
ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
return -1; return -1;
@ -489,7 +432,6 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
printf("Data Length: %d\n", f->datalen); printf("Data Length: %d\n", f->datalen);
#endif #endif
if (fs->buf) {
tmpi = f->data; tmpi = f->data;
/* Volume adjust here to accomodate */ /* Volume adjust here to accomodate */
for (x=0;x<f->datalen/2;x++) { for (x=0;x<f->datalen/2;x++) {
@ -506,16 +448,12 @@ static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
#endif #endif
} }
if ((fwrite(tmp, 1, f->datalen, fs->f) != f->datalen) ) { if ((res = fwrite(tmp, 1, f->datalen, fs->f)) != f->datalen ) {
ast_log(LOG_WARNING, "Bad write (%d): %s\n", errno, strerror(errno)); ast_log(LOG_WARNING, "Bad write (%d): %s\n", res, strerror(errno));
return -1;
}
} else {
ast_log(LOG_WARNING, "Cannot write data to file.\n");
return -1; return -1;
} }
fs->bytes += f->datalen; s->bytes += f->datalen;
update_header(fs->f); update_header(fs->f);
return 0; return 0;
@ -560,43 +498,45 @@ static off_t wav_tell(struct ast_filestream *fs)
return (offset - 44)/2; return (offset - 44)/2;
} }
static char *wav_getcomment(struct ast_filestream *s) static struct ast_format_lock me = { .usecnt = -1 };
{
return NULL; 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() int load_module()
{ {
return ast_format_register(name, exts, AST_FORMAT_SLINEAR, return ast_format_register(&wav_f);
wav_open,
wav_rewrite,
wav_write,
wav_seek,
wav_trunc,
wav_tell,
wav_read,
wav_close,
wav_getcomment);
} }
int unload_module() int unload_module()
{ {
return ast_format_unregister(name); return ast_format_unregister(wav_f.name);
} }
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Microsoft WAV format (8000hz Signed Linear)";
} }
char *key() char *key()
{ {
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;

View File

@ -54,6 +54,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/* Portions of the conversion code are by guido@sienanet.it */ /* 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: */ /* begin binary data: */
char msgsm_silence[] = /* 65 */ char msgsm_silence[] = /* 65 */
{0x48,0x17,0xD6,0x84,0x02,0x80,0x24,0x49,0x92,0x24,0x89,0x02,0x80,0x24,0x49 {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}; ,0x92,0x24,0x49,0x92,0x00};
/* end binary data. size = 65 bytes */ /* end binary data. size = 65 bytes */
struct ast_filestream { struct wavg_desc {
void *reserved[AST_RESERVED_POINTERS];
/* Believe it or not, we must decode/recode to account for the /* Believe it or not, we must decode/recode to account for the
weird MS format */ 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 */ 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 #if __BYTE_ORDER == __LITTLE_ENDIAN
#define htoll(b) (b) #define htoll(b) (b)
#define htols(b) (b) #define htols(b) (b)
@ -173,7 +162,7 @@ static int check_header(FILE *f)
ast_log(LOG_WARNING, "Read failed (freq)\n"); ast_log(LOG_WARNING, "Read failed (freq)\n");
return -1; return -1;
} }
if (ltohl(freq) != 8000) { if (ltohl(freq) != DEFAULT_SAMPLE_RATE) {
ast_log(LOG_WARNING, "Unexpected freqency %d\n", ltohl(freq)); ast_log(LOG_WARNING, "Unexpected freqency %d\n", ltohl(freq));
return -1; return -1;
} }
@ -236,7 +225,7 @@ static int update_header(FILE *f)
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
end = ftello(f); end = ftello(f);
/* in a gsm WAV, data starts 60 bytes in */ /* in a gsm WAV, data starts 60 bytes in */
bytes = end - 60; bytes = end - MSGSM_DATA_OFS;
datalen = htoll((bytes + 1) & ~0x1); datalen = htoll((bytes + 1) & ~0x1);
filelen = htoll(52 + ((bytes + 1) & ~0x1)); filelen = htoll(52 + ((bytes + 1) & ~0x1));
if (cur < 0) { if (cur < 0) {
@ -268,7 +257,7 @@ static int update_header(FILE *f)
static int write_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 bhz = htoll(1625);
unsigned int hs = htoll(20); unsigned int hs = htoll(20);
unsigned short fmt = htols(49); unsigned short fmt = htols(49);
@ -347,119 +336,78 @@ static int write_header(FILE *f)
return 0; 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 /* 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 if we did, it would go here. We also might want to check
and be sure it's a valid file. */ and be sure it's a valid file. */
struct ast_filestream *tmp; struct wavg_desc *fs = (struct wavg_desc *)s->private;
if ((tmp = malloc(sizeof(struct ast_filestream)))) {
memset(tmp, 0, sizeof(struct ast_filestream)); if (check_header(s->f))
if (check_header(f)) { return -1;
free(tmp); fs->secondhalf = 0; /* not strictly necessary */
return NULL; return 0;
}
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;
} }
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 /* 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 if we did, it would go here. We also might want to check
and be sure it's a valid file. */ and be sure it's a valid file. */
struct ast_filestream *tmp;
if ((tmp = malloc(sizeof(struct ast_filestream)))) { if (write_header(s->f))
memset(tmp, 0, sizeof(struct ast_filestream)); return -1;
if (write_header(f)) { return 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;
glistcnt++;
ast_mutex_unlock(&wav_lock);
ast_update_use_count();
} else
ast_log(LOG_WARNING, "Out of memory\n");
return tmp;
} }
static void wav_close(struct ast_filestream *s) static void wav_close(struct ast_filestream *s)
{ {
char zero = 0; 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 */ /* Pad to even length */
fseek(s->f, 0, SEEK_END); fseek(s->f, 0, SEEK_END);
if (ftello(s->f) & 0x1) if (ftello(s->f) & 0x1)
fwrite(&zero, 1, 1, s->f); 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) 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 */ /* 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.frametype = AST_FRAME_VOICE;
s->fr.subclass = AST_FORMAT_GSM; s->fr.subclass = AST_FORMAT_GSM;
s->fr.offset = AST_FRIENDLY_OFFSET; s->fr.offset = AST_FRIENDLY_OFFSET;
s->fr.samples = 160; s->fr.samples = GSM_SAMPLES;
s->fr.datalen = 33;
s->fr.mallocd = 0; 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 */ /* 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 { } 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)) if (res && (res != 1))
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL; return NULL;
} }
/* Convert from MS format to two real GSM frames */ /* Convert from MS format to two real GSM frames */
conv65(msdata, s->gsm); conv65(msdata, s->fr.data);
s->fr.data = s->gsm;
} }
s->secondhalf = !s->secondhalf; fs->secondhalf = !fs->secondhalf;
*whennext = 160; *whennext = GSM_SAMPLES;
return &s->fr; 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; int len;
char msdata[66]; int size;
int len =0; struct wavg_desc *fs = (struct wavg_desc *)s->private;
int alreadyms=0;
if (f->frametype != AST_FRAME_VOICE) { if (f->frametype != AST_FRAME_VOICE) {
ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
return -1; 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); ast_log(LOG_WARNING, "Asked to write non-GSM frame (%d)!\n", f->subclass);
return -1; return -1;
} }
if (!(f->datalen % 65)) /* XXX this might fail... if the input is a multiple of MSGSM_FRAME_SIZE
alreadyms = 1; * we assume it is already in the correct format.
while(len < f->datalen) { */
if (alreadyms) { if (!(f->datalen % MSGSM_FRAME_SIZE)) {
size = MSGSM_FRAME_SIZE;
fs->secondhalf = 0; fs->secondhalf = 0;
if ((res = fwrite(f->data + len, 1, 65, fs->f)) != 65) { } 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;
} 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)); ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno));
return -1; return -1;
} }
update_header(fs->f); update_header(s->f); /* XXX inefficient! */
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;
}
} }
return 0; return 0;
} }
static int wav_seek(struct ast_filestream *fs, off_t sample_offset, int whence) static int wav_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
{ {
off_t offset=0,distance,cur,min,max; off_t offset=0, distance, max;
min = 60; struct wavg_desc *s = (struct wavg_desc *)fs->private;
cur = ftello(fs->f);
off_t min = MSGSM_DATA_OFS;
off_t cur = ftello(fs->f);
fseek(fs->f, 0, SEEK_END); fseek(fs->f, 0, SEEK_END);
max = ftello(fs->f); max = ftello(fs->f); /* XXX ideally, should round correctly */
/* I'm getting sloppy here, I'm only going to go to even splits of the 2 /* Compute the distance in bytes, rounded to the block size */
* frames, if you want tighter cuts use format_gsm, format_pcm, or format_wav */ distance = (sample_offset/MSGSM_SAMPLES) * MSGSM_FRAME_SIZE;
distance = (sample_offset/320) * 65; if (whence == SEEK_SET)
if(whence == SEEK_SET)
offset = distance + min; offset = distance + min;
else if(whence == SEEK_CUR || whence == SEEK_FORCECUR) else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
offset = distance + cur; offset = distance + cur;
else if(whence == SEEK_END) else if (whence == SEEK_END)
offset = max - distance; offset = max - distance;
/* always protect against seeking past end of header */ /* always protect against seeking past end of header */
offset = (offset < min)?min:offset; if (offset < min)
offset = min;
if (whence != SEEK_FORCECUR) { if (whence != SEEK_FORCECUR) {
offset = (offset > max)?max:offset; if (offset > max)
offset = max;
} else if (offset > max) { } else if (offset > max) {
int i; int i;
fseek(fs->f, 0, SEEK_END); fseek(fs->f, 0, SEEK_END);
for (i=0; i< (offset - max) / 65; i++) { for (i=0; i< (offset - max) / MSGSM_FRAME_SIZE; i++) {
fwrite(msgsm_silence, 1, 65, fs->f); fwrite(msgsm_silence, 1, MSGSM_FRAME_SIZE, fs->f);
} }
} }
fs->secondhalf = 0; s->secondhalf = 0;
return fseeko(fs->f, offset, SEEK_SET); return fseeko(fs->f, offset, SEEK_SET);
} }
@ -543,46 +496,49 @@ static off_t wav_tell(struct ast_filestream *fs)
offset = ftello(fs->f); offset = ftello(fs->f);
/* since this will most likely be used later in play or record, lets stick /* since this will most likely be used later in play or record, lets stick
* to that level of resolution, just even frames boundaries */ * 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) static struct ast_format_lock me = { .usecnt = -1 };
{
return NULL; 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() int load_module()
{ {
return ast_format_register(name, exts, AST_FORMAT_GSM, return ast_format_register(&wav49_f);
wav_open,
wav_rewrite,
wav_write,
wav_seek,
wav_trunc,
wav_tell,
wav_read,
wav_close,
wav_getcomment);
} }
int unload_module() int unload_module()
{ {
return ast_format_unregister(name); return ast_format_unregister(wav49_f.name);
} }
int usecount() int usecount()
{ {
return glistcnt; return me.usecnt;
} }
char *description() char *description()
{ {
return desc; return "Microsoft WAV format (Proprietary GSM)";
} }
char *key() char *key()
{ {
return ASTERISK_GPL_KEY; return ASTERISK_GPL_KEY;

View File

@ -40,27 +40,108 @@ extern "C" {
#define AST_DIGIT_ANY "0123456789#*ABCD" #define AST_DIGIT_ANY "0123456789#*ABCD"
#define AST_DIGIT_ANYNUM "0123456789" #define AST_DIGIT_ANYNUM "0123456789"
/*! structure used for lock and refcount of format handlers.
* Should not be here, but this is a temporary workaround
* until we implement a more general mechanism.
* The format handler should include a pointer to
* this structure.
* As a trick, if usecnt is initialized with -1,
* ast_format_register will init the mutex for you.
*/
struct ast_format_lock {
ast_mutex_t lock;
int usecnt; /* number of active clients */
};
/*!
* Each supported file format is described by the following fields.
* Not all are necessary, the support routine implement default
* values for some of them.
* A handler typically fills a structure initializing the desired
* fields, and then calls ast_format_register() with the (readonly)
* structure as an argument.
*/
struct ast_format {
char name[80]; /*! Name of format */
char exts[80]; /*! Extensions (separated by | if more than one)
this format can read. First is assumed for writing (e.g. .mp3) */
int format; /*! Format of frames it uses/provides (one only) */
/*! Prepare an input stream for playback. Return 0 on success, -1 on error.
* The FILE is already open (in s->f) so this function only needs to perform
* any applicable validity checks on the file. If none is required, the
* function can be omitted.
*/
int (*open)(struct ast_filestream *s);
/*! Prepare a stream for output, and comment it appropriately if applicable.
* Return 0 on success, -1 on error. Same as the open, the FILE is already
* open so the function just needs to prepare any header and other fields,
* if any. The function can be omitted if nothing is needed.
*/
int (*rewrite)(struct ast_filestream *s, const char *comment);
/*! Write a frame to a channel */
int (*write)(struct ast_filestream *, struct ast_frame *);
/*! seek num samples into file, whence - like a normal seek but with offset in samples */
int (*seek)(struct ast_filestream *, off_t, int);
int (*trunc)(struct ast_filestream *fs); /*! trunc file to current position */
off_t (*tell)(struct ast_filestream *fs); /*! tell current position */
/*! Read the next frame from the filestream (if available) and report
* when to get next frame (in samples)
*/
struct ast_frame * (*read)(struct ast_filestream *, int *whennext);
/*! Do any closing actions, if any. The descriptor and structure are closed
* and destroyed by the generic routines, so they must not be done here. */
void (*close)(struct ast_filestream *);
char * (*getcomment)(struct ast_filestream *); /*! Retrieve file comment */
AST_LIST_ENTRY(ast_format) list; /*! Link */
/*!
* If the handler needs a buffer (for read, typically)
* and/or a private descriptor, put here the
* required size (in bytes) and the support routine will allocate them
* for you, pointed by s->buf and s->private, respectively.
* When allocating a buffer, remember to leave AST_FRIENDLY_OFFSET
* spare bytes at the bginning.
*/
int buf_size; /*! size of frame buffer, if any, aligned to 8 bytes. */
int desc_size; /*! size of private descriptor, if any */
struct ast_format_lock *lockp;
};
/*
* This structure is allocated by file.c in one chunk,
* together with buf_size and desc_size bytes of memory
* to be used for private purposes (e.g. buffers etc.)
*/
struct ast_filestream {
/*! Everybody reserves a block of AST_RESERVED_POINTERS pointers for us */
struct ast_format *fmt; /* need to write to the lock and usecnt */
int flags;
mode_t mode;
char *filename;
char *realfilename;
/*! Video file stream */
struct ast_filestream *vfs;
/*! Transparently translate from another format -- just once */
struct ast_trans_pvt *trans;
struct ast_tranlator_pvt *tr;
int lastwriteformat;
int lasttimeout;
struct ast_channel *owner;
FILE *f;
struct ast_frame fr; /* frame produced by read, typically */
char *buf; /* buffer pointed to by ast_frame; */
void *private; /* pointer to private buffer */
};
#define SEEK_FORCECUR 10 #define SEEK_FORCECUR 10
/* Defined by individual formats. First item MUST be a
pointer for use by the stream manager */
struct ast_filestream;
/*! Registers a new file format */
/*! Register a new file format capability /*! Register a new file format capability
* Adds a format to asterisk's format abilities. Fill in the fields, and it will work. For examples, look at some of the various format code. * Adds a format to asterisk's format abilities.
* returns 0 on success, -1 on failure * returns 0 on success, -1 on failure
*/ */
int ast_format_register(const char *name, const char *exts, int format, int ast_format_register(const struct ast_format *f);
struct ast_filestream * (*open)(FILE *f),
struct ast_filestream * (*rewrite)(FILE *f, const char *comment),
int (*write)(struct ast_filestream *, struct ast_frame *),
int (*seek)(struct ast_filestream *, off_t offset, int whence),
int (*trunc)(struct ast_filestream *),
off_t (*tell)(struct ast_filestream *),
struct ast_frame * (*read)(struct ast_filestream *, int *timetonext),
void (*close)(struct ast_filestream *),
char * (*getcomment)(struct ast_filestream *));
/*! Unregisters a file format */ /*! Unregisters a file format */
/*! /*!