format_wav.c File Reference

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"
#include "asterisk/format_cache.h"
#include "asterisk/format.h"
#include "asterisk/codec.h"

Include dependency graph for format_wav.c:

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_framewav_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, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND }
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_format_def wav16_f
static struct ast_format_def wav_f


Detailed Description

Work with WAV in the proprietary Microsoft format. Microsoft WAV format (8000hz Signed Linear).

Definition in file format_wav.c.


Define Documentation

#define BLOCKSIZE   160

Definition at line 58 of file format_wav.c.

#define WAV_BUF_SIZE   320

Definition at line 46 of file format_wav.c.

Referenced by wav_read().

#define WAV_HEADER_SIZE   44

Definition at line 48 of file format_wav.c.

Referenced by wav_seek().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 562 of file format_wav.c.

static void __unreg_module ( void   )  [static]

Definition at line 562 of file format_wav.c.

static int check_header ( FILE *  f,
int  hz 
) [static]

Definition at line 144 of file format_wav.c.

References ast_log, buf, check_header_fmt(), LOG_DEBUG, LOG_WARNING, and type.

00145 {
00146    int type, size, formtype;
00147    int data;
00148    if (fread(&type, 1, 4, f) != 4) {
00149       ast_log(LOG_WARNING, "Read failed (type)\n");
00150       return -1;
00151    }
00152    if (fread(&size, 1, 4, f) != 4) {
00153       ast_log(LOG_WARNING, "Read failed (size)\n");
00154       return -1;
00155    }
00156 #if __BYTE_ORDER == __BIG_ENDIAN
00157    size = ltohl(size);
00158 #endif
00159    if (fread(&formtype, 1, 4, f) != 4) {
00160       ast_log(LOG_WARNING, "Read failed (formtype)\n");
00161       return -1;
00162    }
00163    if (memcmp(&type, "RIFF", 4)) {
00164       ast_log(LOG_WARNING, "Does not begin with RIFF\n");
00165       return -1;
00166    }
00167    if (memcmp(&formtype, "WAVE", 4)) {
00168       ast_log(LOG_WARNING, "Does not contain WAVE\n");
00169       return -1;
00170    }
00171    /* Skip any facts and get the first data block */
00172    for(;;)
00173    { 
00174       char buf[4];
00175       
00176       /* Begin data chunk */
00177       if (fread(&buf, 1, 4, f) != 4) {
00178          ast_log(LOG_WARNING, "Read failed (block header format)\n");
00179          return -1;
00180       }
00181       /* Data has the actual length of data in it */
00182       if (fread(&data, 1, 4, f) != 4) {
00183          ast_log(LOG_WARNING, "Read failed (block '%.4s' header length)\n", buf);
00184          return -1;
00185       }
00186 #if __BYTE_ORDER == __BIG_ENDIAN
00187       data = ltohl(data);
00188 #endif
00189       if (memcmp(&buf, "fmt ", 4) == 0) {
00190          if (check_header_fmt(f, data, hz))
00191             return -1;
00192          continue;
00193       }
00194       if(memcmp(buf, "data", 4) == 0 ) 
00195          break;
00196       ast_log(LOG_DEBUG, "Skipping unknown block '%.4s'\n", buf);
00197       if (fseek(f,data,SEEK_CUR) == -1 ) {
00198          ast_log(LOG_WARNING, "Failed to skip '%.4s' block: %d\n", buf, data);
00199          return -1;
00200       }
00201    }
00202 #if 0
00203    curpos = lseek(fd, 0, SEEK_CUR);
00204    truelength = lseek(fd, 0, SEEK_END);
00205    lseek(fd, curpos, SEEK_SET);
00206    truelength -= curpos;
00207 #endif   
00208    return data;
00209 }

static int check_header_fmt ( FILE *  f,
int  hsize,
int  hz 
) [static]

Definition at line 83 of file format_wav.c.

References ast_log, format, and LOG_WARNING.

Referenced by check_header().

00084 {
00085    short format, chans, bysam, bisam;
00086    int bysec;
00087    int freq;
00088    if (hsize < 16) {
00089       ast_log(LOG_WARNING, "Unexpected header size %d\n", hsize);
00090       return -1;
00091    }
00092    if (fread(&format, 1, 2, f) != 2) {
00093       ast_log(LOG_WARNING, "Read failed (format)\n");
00094       return -1;
00095    }
00096    if (ltohs(format) != 1) {
00097       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));
00098       return -1;
00099    }
00100    if (fread(&chans, 1, 2, f) != 2) {
00101       ast_log(LOG_WARNING, "Read failed (format)\n");
00102       return -1;
00103    }
00104    if (ltohs(chans) != 1) {
00105       ast_log(LOG_WARNING, "Not in mono %d\n", ltohs(chans));
00106       return -1;
00107    }
00108    if (fread(&freq, 1, 4, f) != 4) {
00109       ast_log(LOG_WARNING, "Read failed (freq)\n");
00110       return -1;
00111    }
00112    if (((ltohl(freq) != 8000) && (ltohl(freq) != 16000)) ||
00113       ((ltohl(freq) == 8000) && (hz != 8000)) ||
00114       ((ltohl(freq) == 16000) && (hz != 16000))) {
00115       ast_log(LOG_WARNING, "Unexpected frequency mismatch %d (expecting %d)\n", ltohl(freq),hz);
00116       return -1;
00117    }
00118    /* Ignore the byte frequency */
00119    if (fread(&bysec, 1, 4, f) != 4) {
00120       ast_log(LOG_WARNING, "Read failed (BYTES_PER_SECOND)\n");
00121       return -1;
00122    }
00123    /* Check bytes per sample */
00124    if (fread(&bysam, 1, 2, f) != 2) {
00125       ast_log(LOG_WARNING, "Read failed (BYTES_PER_SAMPLE)\n");
00126       return -1;
00127    }
00128    if (ltohs(bysam) != 2) {
00129       ast_log(LOG_WARNING, "Can only handle 16bits per sample: %d\n", ltohs(bysam));
00130       return -1;
00131    }
00132    if (fread(&bisam, 1, 2, f) != 2) {
00133       ast_log(LOG_WARNING, "Read failed (Bits Per Sample): %d\n", ltohs(bisam));
00134       return -1;
00135    }
00136    /* Skip any additional header */
00137    if (fseek(f,hsize-16,SEEK_CUR) == -1 ) {
00138       ast_log(LOG_WARNING, "Failed to skip remaining header bytes: %d\n", hsize-16 );
00139       return -1;
00140    }
00141    return 0;
00142 }

static int load_module ( void   )  [static]

static int unload_module ( void   )  [static]

Definition at line 551 of file format_wav.c.

References ast_format_def_unregister(), and ast_format_def::name.

00552 {
00553    return ast_format_def_unregister(wav_f.name)
00554       || ast_format_def_unregister(wav16_f.name);
00555 }

static int update_header ( FILE *  f  )  [static]

Definition at line 211 of file format_wav.c.

References ast_log, end, and LOG_WARNING.

00212 {
00213    off_t cur,end;
00214    int datalen,filelen,bytes;
00215    
00216    cur = ftello(f);
00217    fseek(f, 0, SEEK_END);
00218    end = ftello(f);
00219    /* data starts 44 bytes in */
00220    bytes = end - 44;
00221    datalen = htoll(bytes);
00222    /* chunk size is bytes of data plus 36 bytes of header */
00223    filelen = htoll(36 + bytes);
00224    
00225    if (cur < 0) {
00226       ast_log(LOG_WARNING, "Unable to find our position\n");
00227       return -1;
00228    }
00229    if (fseek(f, 4, SEEK_SET)) {
00230       ast_log(LOG_WARNING, "Unable to set our position\n");
00231       return -1;
00232    }
00233    if (fwrite(&filelen, 1, 4, f) != 4) {
00234       ast_log(LOG_WARNING, "Unable to set write file size\n");
00235       return -1;
00236    }
00237    if (fseek(f, 40, SEEK_SET)) {
00238       ast_log(LOG_WARNING, "Unable to set our position\n");
00239       return -1;
00240    }
00241    if (fwrite(&datalen, 1, 4, f) != 4) {
00242       ast_log(LOG_WARNING, "Unable to set write datalen\n");
00243       return -1;
00244    }
00245    if (fseeko(f, cur, SEEK_SET)) {
00246       ast_log(LOG_WARNING, "Unable to return to position\n");
00247       return -1;
00248    }
00249    return 0;
00250 }

static void wav_close ( struct ast_filestream s  )  [static]

Definition at line 347 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().

00348 {
00349    char zero = 0;
00350    struct wav_desc *fs = (struct wav_desc *)s->_private;
00351 
00352    if (s->mode == O_RDONLY) {
00353       return;
00354    }
00355 
00356    if (s->filename) {
00357       update_header(s->f);
00358    }
00359 
00360    /* Pad to even length */
00361    if (fs->bytes & 0x1) {
00362       if (!fwrite(&zero, 1, 1, s->f)) {
00363          ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00364       }
00365    }
00366 }

static int wav_open ( struct ast_filestream s  )  [static]

Definition at line 323 of file format_wav.c.

References ast_filestream::_private, ast_format_get_sample_rate(), check_header(), ast_filestream::f, ast_filestream::fmt, ast_format_def::format, wav_desc::maxlen, and tmp().

00324 {
00325    /* We don't have any header to read or anything really, but
00326       if we did, it would go here.  We also might want to check
00327       and be sure it's a valid file.  */
00328    struct wav_desc *tmp = (struct wav_desc *)s->_private;
00329    if ((tmp->maxlen = check_header(s->f, ast_format_get_sample_rate(s->fmt->format))) < 0)
00330       return -1;
00331    return 0;
00332 }

static struct ast_frame* wav_read ( struct ast_filestream s,
int *  whennext 
) [static, read]

Definition at line 368 of file format_wav.c.

References ast_filestream::_private, AST_FRAME_SET_BUFFER, AST_FRIENDLY_OFFSET, ast_log, ast_filestream::buf, ast_frame::data, ast_frame::datalen, errno, ast_filestream::f, ast_filestream::fr, wav_desc::hz, LOG_WARNING, wav_desc::maxlen, NULL, ast_frame::ptr, ast_frame::samples, tmp(), and WAV_BUF_SIZE.

00369 {
00370    int res;
00371    int samples;   /* actual samples read */
00372 #if __BYTE_ORDER == __BIG_ENDIAN
00373    int x;
00374    short *tmp;
00375 #endif
00376    int bytes;
00377    off_t here;
00378    /* Send a frame from the file to the appropriate channel */
00379    struct wav_desc *fs = (struct wav_desc *)s->_private;
00380 
00381    bytes = (fs->hz == 16000 ? (WAV_BUF_SIZE * 2) : WAV_BUF_SIZE);
00382 
00383    here = ftello(s->f);
00384    if (fs->maxlen - here < bytes)      /* truncate if necessary */
00385       bytes = fs->maxlen - here;
00386    if (bytes < 0)
00387       bytes = 0;
00388 /*    ast_debug(1, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */
00389    AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, bytes);
00390    
00391    if ( (res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) <= 0 ) {
00392       if (res)
00393          ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
00394       return NULL;
00395    }
00396    s->fr.datalen = res;
00397    s->fr.samples = samples = res / 2;
00398 
00399 #if __BYTE_ORDER == __BIG_ENDIAN
00400    tmp = (short *)(s->fr.data.ptr);
00401    /* file format is little endian so we need to swap */
00402    for( x = 0; x < samples; x++)
00403       tmp[x] = (tmp[x] << 8) | ((tmp[x] & 0xff00) >> 8);
00404 #endif
00405 
00406    *whennext = samples;
00407    return &s->fr;
00408 }

static int wav_rewrite ( struct ast_filestream s,
const char *  comment 
) [static]

Definition at line 334 of file format_wav.c.

References ast_filestream::_private, ast_format_get_sample_rate(), ast_filestream::f, ast_filestream::fmt, ast_format_def::format, wav_desc::hz, tmp(), and write_header().

00335 {
00336    /* We don't have any header to read or anything really, but
00337       if we did, it would go here.  We also might want to check
00338       and be sure it's a valid file.  */
00339 
00340    struct wav_desc *tmp = (struct wav_desc *)s->_private;
00341    tmp->hz = ast_format_get_sample_rate(s->fmt->format);
00342    if (write_header(s->f,tmp->hz))
00343       return -1;
00344    return 0;
00345 }

static int wav_seek ( struct ast_filestream fs,
off_t  sample_offset,
int  whence 
) [static]

Definition at line 447 of file format_wav.c.

References ast_log, AST_LOG_WARNING, errno, ast_filestream::f, max, min, SEEK_FORCECUR, and WAV_HEADER_SIZE.

00448 {
00449    off_t min = WAV_HEADER_SIZE, max, cur, offset = 0, samples;
00450 
00451    samples = sample_offset * 2; /* SLINEAR is 16 bits mono, so sample_offset * 2 = bytes */
00452 
00453    if ((cur = ftello(fs->f)) < 0) {
00454       ast_log(AST_LOG_WARNING, "Unable to determine current position in wav filestream %p: %s\n", fs, strerror(errno));
00455       return -1;
00456    }
00457 
00458    if (fseeko(fs->f, 0, SEEK_END) < 0) {
00459       ast_log(AST_LOG_WARNING, "Unable to seek to end of wav filestream %p: %s\n", fs, strerror(errno));
00460       return -1;
00461    }
00462 
00463    if ((max = ftello(fs->f)) < 0) {
00464       ast_log(AST_LOG_WARNING, "Unable to determine max position in wav filestream %p: %s\n", fs, strerror(errno));
00465       return -1;
00466    }
00467 
00468    if (whence == SEEK_SET) {
00469       offset = samples + min;
00470    } else if (whence == SEEK_CUR || whence == SEEK_FORCECUR) {
00471       offset = samples + cur;
00472    } else if (whence == SEEK_END) {
00473       offset = max - samples;
00474    }
00475    if (whence != SEEK_FORCECUR) {
00476       offset = (offset > max)?max:offset;
00477    }
00478    /* always protect the header space. */
00479    offset = (offset < min)?min:offset;
00480    return fseeko(fs->f, offset, SEEK_SET);
00481 }

static off_t wav_tell ( struct ast_filestream fs  )  [static]

Definition at line 503 of file format_wav.c.

References ast_filestream::f.

00504 {
00505    off_t offset;
00506    offset = ftello(fs->f);
00507    /* subtract header size to get samples, then divide by 2 for 16 bit samples */
00508    return (offset - 44)/2;
00509 }

static int wav_trunc ( struct ast_filestream fs  )  [static]

Definition at line 483 of file format_wav.c.

References ast_log, AST_LOG_WARNING, errno, ast_filestream::f, and update_header().

00484 {
00485    int fd;
00486    off_t cur;
00487 
00488    if ((fd = fileno(fs->f)) < 0) {
00489       ast_log(AST_LOG_WARNING, "Unable to determine file descriptor for wav filestream %p: %s\n", fs, strerror(errno));
00490       return -1;
00491    }
00492    if ((cur = ftello(fs->f)) < 0) {
00493       ast_log(AST_LOG_WARNING, "Unable to determine current position in wav filestream %p: %s\n", fs, strerror(errno));
00494       return -1;
00495    }
00496    /* Truncate file to current length */
00497    if (ftruncate(fd, cur)) {
00498       return -1;
00499    }
00500    return update_header(fs->f);
00501 }

static int wav_write ( struct ast_filestream fs,
struct ast_frame f 
) [static]

Definition at line 410 of file format_wav.c.

References ast_filestream::_private, ast_log, wav_desc::bytes, ast_frame::data, ast_frame::datalen, errno, ast_filestream::f, LOG_WARNING, ast_frame::ptr, and tmp().

00411 {
00412 #if __BYTE_ORDER == __BIG_ENDIAN
00413    int x;
00414    short tmp[16000], *tmpi;
00415 #endif
00416    struct wav_desc *s = (struct wav_desc *)fs->_private;
00417    int res;
00418 
00419    if (!f->datalen)
00420       return -1;
00421 
00422 #if __BYTE_ORDER == __BIG_ENDIAN
00423    /* swap and write */
00424    if (f->datalen > sizeof(tmp)) {
00425       ast_log(LOG_WARNING, "Data length is too long\n");
00426       return -1;
00427    }
00428    tmpi = f->data.ptr;
00429    for (x=0; x < f->datalen/2; x++) 
00430       tmp[x] = (tmpi[x] << 8) | ((tmpi[x] & 0xff00) >> 8);
00431 
00432    if ((res = fwrite(tmp, 1, f->datalen, fs->f)) != f->datalen ) {
00433 #else
00434    /* just write */
00435    if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen ) {
00436 #endif
00437       ast_log(LOG_WARNING, "Bad write (%d): %s\n", res, strerror(errno));
00438       return -1;
00439    }
00440 
00441    s->bytes += f->datalen;
00442       
00443    return 0;
00444 
00445 }

static int write_header ( FILE *  f,
int  writehz 
) [static]

Definition at line 252 of file format_wav.c.

References ast_log, and LOG_WARNING.

00253 {
00254    unsigned int hz;
00255    unsigned int bhz;
00256    unsigned int hs = htoll(16);
00257    unsigned short fmt = htols(1);
00258    unsigned short chans = htols(1);
00259    unsigned short bysam = htols(2);
00260    unsigned short bisam = htols(16);
00261    unsigned int size = htoll(0);
00262 
00263    if (writehz == 16000) {
00264       hz = htoll(16000);
00265       bhz = htoll(32000);
00266    } else {
00267       hz = htoll(8000);
00268       bhz = htoll(16000);
00269    }
00270    /* Write a wav header, ignoring sizes which will be filled in later */
00271    fseek(f,0,SEEK_SET);
00272    if (fwrite("RIFF", 1, 4, f) != 4) {
00273       ast_log(LOG_WARNING, "Unable to write header\n");
00274       return -1;
00275    }
00276    if (fwrite(&size, 1, 4, f) != 4) {
00277       ast_log(LOG_WARNING, "Unable to write header\n");
00278       return -1;
00279    }
00280    if (fwrite("WAVEfmt ", 1, 8, f) != 8) {
00281       ast_log(LOG_WARNING, "Unable to write header\n");
00282       return -1;
00283    }
00284    if (fwrite(&hs, 1, 4, f) != 4) {
00285       ast_log(LOG_WARNING, "Unable to write header\n");
00286       return -1;
00287    }
00288    if (fwrite(&fmt, 1, 2, f) != 2) {
00289       ast_log(LOG_WARNING, "Unable to write header\n");
00290       return -1;
00291    }
00292    if (fwrite(&chans, 1, 2, f) != 2) {
00293       ast_log(LOG_WARNING, "Unable to write header\n");
00294       return -1;
00295    }
00296    if (fwrite(&hz, 1, 4, f) != 4) {
00297       ast_log(LOG_WARNING, "Unable to write header\n");
00298       return -1;
00299    }
00300    if (fwrite(&bhz, 1, 4, f) != 4) {
00301       ast_log(LOG_WARNING, "Unable to write header\n");
00302       return -1;
00303    }
00304    if (fwrite(&bysam, 1, 2, f) != 2) {
00305       ast_log(LOG_WARNING, "Unable to write header\n");
00306       return -1;
00307    }
00308    if (fwrite(&bisam, 1, 2, f) != 2) {
00309       ast_log(LOG_WARNING, "Unable to write header\n");
00310       return -1;
00311    }
00312    if (fwrite("data", 1, 4, f) != 4) {
00313       ast_log(LOG_WARNING, "Unable to write header\n");
00314       return -1;
00315    }
00316    if (fwrite(&size, 1, 4, f) != 4) {
00317       ast_log(LOG_WARNING, "Unable to write header\n");
00318       return -1;
00319    }
00320    return 0;
00321 }


Variable Documentation

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, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND } [static]

Definition at line 562 of file format_wav.c.

Definition at line 562 of file format_wav.c.

struct ast_format_def wav16_f [static]

Definition at line 511 of file format_wav.c.

struct ast_format_def wav_f [static]

Definition at line 526 of file format_wav.c.


Generated on Thu Apr 16 06:31:08 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6