Work with WAV in the proprietary Microsoft format. Microsoft WAV format (8000hz Signed Linear) More...
#include "asterisk.h"#include "asterisk/mod_format.h"#include "asterisk/module.h"#include "asterisk/endian.h"
Go to the source code of this file.
Data Structures | |
| struct | wav_desc |
Defines | |
| #define | BLOCKSIZE 160 |
| #define | WAV_BUF_SIZE 320 |
| #define | WAV_HEADER_SIZE 44 |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | check_header (FILE *f, int hz) |
| static int | check_header_fmt (FILE *f, int hsize, int hz) |
| static int | load_module (void) |
| static int | unload_module (void) |
| static int | update_header (FILE *f) |
| static void | wav_close (struct ast_filestream *s) |
| static int | wav_open (struct ast_filestream *s) |
| static struct ast_frame * | wav_read (struct ast_filestream *s, int *whennext) |
| static int | wav_rewrite (struct ast_filestream *s, const char *comment) |
| static int | wav_seek (struct ast_filestream *fs, off_t sample_offset, int whence) |
| static off_t | wav_tell (struct ast_filestream *fs) |
| static int | wav_trunc (struct ast_filestream *fs) |
| static int | wav_write (struct ast_filestream *fs, struct ast_frame *f) |
| static int | write_header (FILE *f, int writehz) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Microsoft WAV/WAV16 format (8kHz/16kHz Signed Linear)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_format_def | wav16_f |
| static struct ast_format_def | wav_f |
Work with WAV in the proprietary Microsoft format. Microsoft WAV format (8000hz Signed Linear)
Definition in file format_wav.c.
| #define BLOCKSIZE 160 |
Definition at line 55 of file format_wav.c.
| #define WAV_BUF_SIZE 320 |
Definition at line 43 of file format_wav.c.
Referenced by wav_read().
| #define WAV_HEADER_SIZE 44 |
Definition at line 45 of file format_wav.c.
Referenced by wav_seek().
| static void __reg_module | ( | void | ) | [static] |
Definition at line 568 of file format_wav.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 568 of file format_wav.c.
| static int check_header | ( | FILE * | f, |
| int | hz | ||
| ) | [static] |
Definition at line 141 of file format_wav.c.
References ast_log(), check_header_fmt(), LOG_DEBUG, LOG_WARNING, and type.
Referenced by wav_open().
{
int type, size, formtype;
int data;
if (fread(&type, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Read failed (type)\n");
return -1;
}
if (fread(&size, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Read failed (size)\n");
return -1;
}
size = ltohl(size);
if (fread(&formtype, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Read failed (formtype)\n");
return -1;
}
if (memcmp(&type, "RIFF", 4)) {
ast_log(LOG_WARNING, "Does not begin with RIFF\n");
return -1;
}
if (memcmp(&formtype, "WAVE", 4)) {
ast_log(LOG_WARNING, "Does not contain WAVE\n");
return -1;
}
/* Skip any facts and get the first data block */
for(;;)
{
char buf[4];
/* Begin data chunk */
if (fread(&buf, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Read failed (block header format)\n");
return -1;
}
/* Data has the actual length of data in it */
if (fread(&data, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Read failed (block '%.4s' header length)\n", buf);
return -1;
}
data = ltohl(data);
if (memcmp(&buf, "fmt ", 4) == 0) {
if (check_header_fmt(f, data, hz))
return -1;
continue;
}
if(memcmp(buf, "data", 4) == 0 )
break;
ast_log(LOG_DEBUG, "Skipping unknown block '%.4s'\n", buf);
if (fseek(f,data,SEEK_CUR) == -1 ) {
ast_log(LOG_WARNING, "Failed to skip '%.4s' block: %d\n", buf, data);
return -1;
}
}
#if 0
curpos = lseek(fd, 0, SEEK_CUR);
truelength = lseek(fd, 0, SEEK_END);
lseek(fd, curpos, SEEK_SET);
truelength -= curpos;
#endif
return data;
}
| static int check_header_fmt | ( | FILE * | f, |
| int | hsize, | ||
| int | hz | ||
| ) | [static] |
Definition at line 80 of file format_wav.c.
References ast_log(), format, and LOG_WARNING.
Referenced by check_header().
{
short format, chans, bysam, bisam;
int bysec;
int freq;
if (hsize < 16) {
ast_log(LOG_WARNING, "Unexpected header size %d\n", hsize);
return -1;
}
if (fread(&format, 1, 2, f) != 2) {
ast_log(LOG_WARNING, "Read failed (format)\n");
return -1;
}
if (ltohs(format) != 1) {
ast_log(LOG_WARNING, "Not a supported wav file format (%d). Only PCM encoded, 16 bit, mono, 8kHz files are supported with a lowercase '.wav' extension.\n", ltohs(format));
return -1;
}
if (fread(&chans, 1, 2, f) != 2) {
ast_log(LOG_WARNING, "Read failed (format)\n");
return -1;
}
if (ltohs(chans) != 1) {
ast_log(LOG_WARNING, "Not in mono %d\n", ltohs(chans));
return -1;
}
if (fread(&freq, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Read failed (freq)\n");
return -1;
}
if (((ltohl(freq) != 8000) && (ltohl(freq) != 16000)) ||
((ltohl(freq) == 8000) && (hz != 8000)) ||
((ltohl(freq) == 16000) && (hz != 16000))) {
ast_log(LOG_WARNING, "Unexpected frequency mismatch %d (expecting %d)\n", ltohl(freq),hz);
return -1;
}
/* Ignore the byte frequency */
if (fread(&bysec, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Read failed (BYTES_PER_SECOND)\n");
return -1;
}
/* Check bytes per sample */
if (fread(&bysam, 1, 2, f) != 2) {
ast_log(LOG_WARNING, "Read failed (BYTES_PER_SAMPLE)\n");
return -1;
}
if (ltohs(bysam) != 2) {
ast_log(LOG_WARNING, "Can only handle 16bits per sample: %d\n", ltohs(bysam));
return -1;
}
if (fread(&bisam, 1, 2, f) != 2) {
ast_log(LOG_WARNING, "Read failed (Bits Per Sample): %d\n", ltohs(bisam));
return -1;
}
/* Skip any additional header */
if (fseek(f,hsize-16,SEEK_CUR) == -1 ) {
ast_log(LOG_WARNING, "Failed to skip remaining header bytes: %d\n", hsize-16 );
return -1;
}
return 0;
}
| static int load_module | ( | void | ) | [static] |
Definition at line 548 of file format_wav.c.
References ast_format_def_register, ast_format_set(), AST_FORMAT_SLINEAR, AST_FORMAT_SLINEAR16, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, and ast_format_def::format.
{
ast_format_set(&wav_f.format, AST_FORMAT_SLINEAR, 0);
ast_format_set(&wav16_f.format, AST_FORMAT_SLINEAR16, 0);
if (ast_format_def_register(&wav_f)
|| ast_format_def_register(&wav16_f))
return AST_MODULE_LOAD_FAILURE;
return AST_MODULE_LOAD_SUCCESS;
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 558 of file format_wav.c.
References ast_format_def_unregister(), and ast_format_def::name.
{
return ast_format_def_unregister(wav_f.name)
|| ast_format_def_unregister(wav16_f.name);
}
| static int update_header | ( | FILE * | f | ) | [static] |
Definition at line 204 of file format_wav.c.
References ast_log(), and LOG_WARNING.
Referenced by wav_close(), and wav_trunc().
{
off_t cur,end;
int datalen,filelen,bytes;
cur = ftello(f);
fseek(f, 0, SEEK_END);
end = ftello(f);
/* data starts 44 bytes in */
bytes = end - 44;
datalen = htoll(bytes);
/* chunk size is bytes of data plus 36 bytes of header */
filelen = htoll(36 + bytes);
if (cur < 0) {
ast_log(LOG_WARNING, "Unable to find our position\n");
return -1;
}
if (fseek(f, 4, SEEK_SET)) {
ast_log(LOG_WARNING, "Unable to set our position\n");
return -1;
}
if (fwrite(&filelen, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Unable to set write file size\n");
return -1;
}
if (fseek(f, 40, SEEK_SET)) {
ast_log(LOG_WARNING, "Unable to set our position\n");
return -1;
}
if (fwrite(&datalen, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Unable to set write datalen\n");
return -1;
}
if (fseeko(f, cur, SEEK_SET)) {
ast_log(LOG_WARNING, "Unable to return to position\n");
return -1;
}
return 0;
}
| static void wav_close | ( | struct ast_filestream * | s | ) | [static] |
Definition at line 340 of file format_wav.c.
References ast_filestream::_private, ast_log(), wav_desc::bytes, errno, ast_filestream::f, ast_filestream::filename, LOG_WARNING, ast_filestream::mode, and update_header().
{
char zero = 0;
struct wav_desc *fs = (struct wav_desc *)s->_private;
if (s->mode == O_RDONLY) {
return;
}
if (s->filename) {
update_header(s->f);
}
/* Pad to even length */
if (fs->bytes & 0x1) {
if (!fwrite(&zero, 1, 1, s->f)) {
ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
}
}
}
| static int wav_open | ( | struct ast_filestream * | s | ) | [static] |
Definition at line 316 of file format_wav.c.
References ast_filestream::_private, AST_FORMAT_SLINEAR16, check_header(), ast_filestream::f, ast_filestream::fmt, ast_format_def::format, ast_format::id, and wav_desc::maxlen.
{
/* 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 wav_desc *tmp = (struct wav_desc *)s->_private;
if ((tmp->maxlen = check_header(s->f, (s->fmt->format.id == AST_FORMAT_SLINEAR16 ? 16000 : 8000))) < 0)
return -1;
return 0;
}
| static struct ast_frame* wav_read | ( | struct ast_filestream * | s, |
| int * | whennext | ||
| ) | [static, read] |
Definition at line 361 of file format_wav.c.
References ast_filestream::_private, ast_format_set(), AST_FORMAT_SLINEAR, AST_FORMAT_SLINEAR16, AST_FRAME_SET_BUFFER, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_filestream::buf, ast_frame::data, ast_frame::datalen, errno, ast_filestream::f, ast_frame_subclass::format, ast_filestream::fr, ast_frame::frametype, wav_desc::hz, LOG_WARNING, ast_frame::mallocd, wav_desc::maxlen, ast_frame::ptr, ast_frame::samples, ast_frame::subclass, and WAV_BUF_SIZE.
{
int res;
int samples; /* actual samples read */
#if __BYTE_ORDER == __BIG_ENDIAN
int x;
short *tmp;
#endif
int bytes;
off_t here;
/* Send a frame from the file to the appropriate channel */
struct wav_desc *fs = (struct wav_desc *)s->_private;
bytes = (fs->hz == 16000 ? (WAV_BUF_SIZE * 2) : WAV_BUF_SIZE);
here = ftello(s->f);
if (fs->maxlen - here < bytes) /* truncate if necessary */
bytes = fs->maxlen - here;
if (bytes < 0)
bytes = 0;
/* ast_debug(1, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */
s->fr.frametype = AST_FRAME_VOICE;
ast_format_set(&s->fr.subclass.format, (fs->hz == 16000 ? AST_FORMAT_SLINEAR16 : AST_FORMAT_SLINEAR), 0);
s->fr.mallocd = 0;
AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, bytes);
if ( (res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) <= 0 ) {
if (res)
ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
return NULL;
}
s->fr.datalen = res;
s->fr.samples = samples = res / 2;
#if __BYTE_ORDER == __BIG_ENDIAN
tmp = (short *)(s->fr.data.ptr);
/* 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
*whennext = samples;
return &s->fr;
}
| static int wav_rewrite | ( | struct ast_filestream * | s, |
| const char * | comment | ||
| ) | [static] |
Definition at line 327 of file format_wav.c.
References ast_filestream::_private, AST_FORMAT_SLINEAR16, ast_filestream::f, ast_filestream::fmt, ast_format_def::format, wav_desc::hz, ast_format::id, and write_header().
{
/* 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 wav_desc *tmp = (struct wav_desc *)s->_private;
tmp->hz = (s->fmt->format.id == AST_FORMAT_SLINEAR16 ? 16000 : 8000);
if (write_header(s->f,tmp->hz))
return -1;
return 0;
}
| static int wav_seek | ( | struct ast_filestream * | fs, |
| off_t | sample_offset, | ||
| int | whence | ||
| ) | [static] |
Definition at line 455 of file format_wav.c.
References ast_log(), AST_LOG_WARNING, errno, ast_filestream::f, SEEK_FORCECUR, and WAV_HEADER_SIZE.
{
off_t min = WAV_HEADER_SIZE, max, cur, offset = 0, samples;
samples = sample_offset * 2; /* SLINEAR is 16 bits mono, so sample_offset * 2 = bytes */
if ((cur = ftello(fs->f)) < 0) {
ast_log(AST_LOG_WARNING, "Unable to determine current position in wav filestream %p: %s\n", fs, strerror(errno));
return -1;
}
if (fseeko(fs->f, 0, SEEK_END) < 0) {
ast_log(AST_LOG_WARNING, "Unable to seek to end of wav filestream %p: %s\n", fs, strerror(errno));
return -1;
}
if ((max = ftello(fs->f)) < 0) {
ast_log(AST_LOG_WARNING, "Unable to determine max position in wav filestream %p: %s\n", fs, strerror(errno));
return -1;
}
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 off_t wav_tell | ( | struct ast_filestream * | fs | ) | [static] |
Definition at line 510 of file format_wav.c.
References ast_filestream::f.
{
off_t offset;
offset = ftello(fs->f);
/* subtract header size to get samples, then divide by 2 for 16 bit samples */
return (offset - 44)/2;
}
| static int wav_trunc | ( | struct ast_filestream * | fs | ) | [static] |
Definition at line 490 of file format_wav.c.
References ast_log(), AST_LOG_WARNING, errno, ast_filestream::f, and update_header().
{
int fd;
off_t cur;
if ((fd = fileno(fs->f)) < 0) {
ast_log(AST_LOG_WARNING, "Unable to determine file descriptor for wav filestream %p: %s\n", fs, strerror(errno));
return -1;
}
if ((cur = ftello(fs->f)) < 0) {
ast_log(AST_LOG_WARNING, "Unable to determine current position in wav filestream %p: %s\n", fs, strerror(errno));
return -1;
}
/* Truncate file to current length */
if (ftruncate(fd, cur)) {
return -1;
}
return update_header(fs->f);
}
| static int wav_write | ( | struct ast_filestream * | fs, |
| struct ast_frame * | f | ||
| ) | [static] |
Definition at line 406 of file format_wav.c.
References ast_filestream::_private, ast_format_cmp(), AST_FORMAT_CMP_NOT_EQUAL, AST_FORMAT_SLINEAR, AST_FORMAT_SLINEAR16, AST_FRAME_VOICE, ast_getformatname(), ast_log(), wav_desc::bytes, ast_frame::data, ast_frame::datalen, errno, ast_filestream::f, ast_filestream::fmt, ast_format_def::format, ast_frame_subclass::format, ast_frame::frametype, wav_desc::hz, ast_format::id, LOG_WARNING, ast_frame::ptr, and ast_frame::subclass.
{
#if __BYTE_ORDER == __BIG_ENDIAN
int x;
short tmp[16000], *tmpi;
#endif
struct wav_desc *s = (struct wav_desc *)fs->_private;
int res;
if (f->frametype != AST_FRAME_VOICE) {
ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
return -1;
}
if ((f->subclass.format.id != AST_FORMAT_SLINEAR) && (f->subclass.format.id != AST_FORMAT_SLINEAR16)) {
ast_log(LOG_WARNING, "Asked to write non-SLINEAR%s frame (%s)!\n", s->hz == 16000 ? "16" : "", ast_getformatname(&f->subclass.format));
return -1;
}
if (ast_format_cmp(&f->subclass.format, &fs->fmt->format) == AST_FORMAT_CMP_NOT_EQUAL) {
ast_log(LOG_WARNING, "Can't change SLINEAR frequency during write\n");
return -1;
}
if (!f->datalen)
return -1;
#if __BYTE_ORDER == __BIG_ENDIAN
/* swap and write */
if (f->datalen > sizeof(tmp)) {
ast_log(LOG_WARNING, "Data length is too long\n");
return -1;
}
tmpi = f->data.ptr;
for (x=0; x < f->datalen/2; x++)
tmp[x] = (tmpi[x] << 8) | ((tmpi[x] & 0xff00) >> 8);
if ((res = fwrite(tmp, 1, f->datalen, fs->f)) != f->datalen ) {
#else
/* just write */
if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen ) {
#endif
ast_log(LOG_WARNING, "Bad write (%d): %s\n", res, strerror(errno));
return -1;
}
s->bytes += f->datalen;
return 0;
}
| static int write_header | ( | FILE * | f, |
| int | writehz | ||
| ) | [static] |
Definition at line 245 of file format_wav.c.
References ast_log(), and LOG_WARNING.
Referenced by wav_rewrite().
{
unsigned int hz;
unsigned int bhz;
unsigned int hs = htoll(16);
unsigned short fmt = htols(1);
unsigned short chans = htols(1);
unsigned short bysam = htols(2);
unsigned short bisam = htols(16);
unsigned int size = htoll(0);
if (writehz == 16000) {
hz = htoll(16000);
bhz = htoll(32000);
} else {
hz = htoll(8000);
bhz = htoll(16000);
}
/* Write a wav header, ignoring sizes which will be filled in later */
fseek(f,0,SEEK_SET);
if (fwrite("RIFF", 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Unable to write header\n");
return -1;
}
if (fwrite(&size, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Unable to write header\n");
return -1;
}
if (fwrite("WAVEfmt ", 1, 8, f) != 8) {
ast_log(LOG_WARNING, "Unable to write header\n");
return -1;
}
if (fwrite(&hs, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Unable to write header\n");
return -1;
}
if (fwrite(&fmt, 1, 2, f) != 2) {
ast_log(LOG_WARNING, "Unable to write header\n");
return -1;
}
if (fwrite(&chans, 1, 2, f) != 2) {
ast_log(LOG_WARNING, "Unable to write header\n");
return -1;
}
if (fwrite(&hz, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Unable to write header\n");
return -1;
}
if (fwrite(&bhz, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Unable to write header\n");
return -1;
}
if (fwrite(&bysam, 1, 2, f) != 2) {
ast_log(LOG_WARNING, "Unable to write header\n");
return -1;
}
if (fwrite(&bisam, 1, 2, f) != 2) {
ast_log(LOG_WARNING, "Unable to write header\n");
return -1;
}
if (fwrite("data", 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Unable to write header\n");
return -1;
}
if (fwrite(&size, 1, 4, f) != 4) {
ast_log(LOG_WARNING, "Unable to write header\n");
return -1;
}
return 0;
}
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Microsoft WAV/WAV16 format (8kHz/16kHz Signed Linear)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND } [static] |
Definition at line 568 of file format_wav.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 568 of file format_wav.c.
struct ast_format_def wav16_f [static] |
Definition at line 518 of file format_wav.c.
struct ast_format_def wav_f [static] |
Definition at line 533 of file format_wav.c.