Wed Apr 6 11:30:04 2011

Asterisk developer's documentation


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"

Go to the source code of this file.

Data Structures

struct  wav_desc

Defines

#define BLOCKSIZE   160
#define WAV_BUF_SIZE   320

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int check_header (FILE *f, 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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 wav16_f
static struct ast_format 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 49 of file format_wav.c.

#define WAV_BUF_SIZE   320

Definition at line 39 of file format_wav.c.

Referenced by wav_read().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 539 of file format_wav.c.

static void __unreg_module ( void   )  [static]

Definition at line 539 of file format_wav.c.

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

Definition at line 74 of file format_wav.c.

References ast_log(), format, LOG_WARNING, and type.

00075 {
00076    int type, size, formtype;
00077    int fmt, hsize;
00078    short format, chans, bysam, bisam;
00079    int bysec;
00080    int freq;
00081    int data;
00082    if (fread(&type, 1, 4, f) != 4) {
00083       ast_log(LOG_WARNING, "Read failed (type)\n");
00084       return -1;
00085    }
00086    if (fread(&size, 1, 4, f) != 4) {
00087       ast_log(LOG_WARNING, "Read failed (size)\n");
00088       return -1;
00089    }
00090    size = ltohl(size);
00091    if (fread(&formtype, 1, 4, f) != 4) {
00092       ast_log(LOG_WARNING, "Read failed (formtype)\n");
00093       return -1;
00094    }
00095    if (memcmp(&type, "RIFF", 4)) {
00096       ast_log(LOG_WARNING, "Does not begin with RIFF\n");
00097       return -1;
00098    }
00099    if (memcmp(&formtype, "WAVE", 4)) {
00100       ast_log(LOG_WARNING, "Does not contain WAVE\n");
00101       return -1;
00102    }
00103    if (fread(&fmt, 1, 4, f) != 4) {
00104       ast_log(LOG_WARNING, "Read failed (fmt)\n");
00105       return -1;
00106    }
00107    if (memcmp(&fmt, "fmt ", 4)) {
00108       ast_log(LOG_WARNING, "Does not say fmt\n");
00109       return -1;
00110    }
00111    if (fread(&hsize, 1, 4, f) != 4) {
00112       ast_log(LOG_WARNING, "Read failed (formtype)\n");
00113       return -1;
00114    }
00115    if (ltohl(hsize) < 16) {
00116       ast_log(LOG_WARNING, "Unexpected header size %d\n", ltohl(hsize));
00117       return -1;
00118    }
00119    if (fread(&format, 1, 2, f) != 2) {
00120       ast_log(LOG_WARNING, "Read failed (format)\n");
00121       return -1;
00122    }
00123    if (ltohs(format) != 1) {
00124       ast_log(LOG_WARNING, "Not a wav file %d\n", ltohs(format));
00125       return -1;
00126    }
00127    if (fread(&chans, 1, 2, f) != 2) {
00128       ast_log(LOG_WARNING, "Read failed (format)\n");
00129       return -1;
00130    }
00131    if (ltohs(chans) != 1) {
00132       ast_log(LOG_WARNING, "Not in mono %d\n", ltohs(chans));
00133       return -1;
00134    }
00135    if (fread(&freq, 1, 4, f) != 4) {
00136       ast_log(LOG_WARNING, "Read failed (freq)\n");
00137       return -1;
00138    }
00139    if (((ltohl(freq) != 8000) && (ltohl(freq) != 16000)) ||
00140        ((ltohl(freq) == 8000) && (hz != 8000)) ||
00141        ((ltohl(freq) == 16000) && (hz != 16000))) {
00142       ast_log(LOG_WARNING, "Unexpected frequency mismatch %d (expecting %d)\n", ltohl(freq),hz);
00143       return -1;
00144    }
00145    /* Ignore the byte frequency */
00146    if (fread(&bysec, 1, 4, f) != 4) {
00147       ast_log(LOG_WARNING, "Read failed (BYTES_PER_SECOND)\n");
00148       return -1;
00149    }
00150    /* Check bytes per sample */
00151    if (fread(&bysam, 1, 2, f) != 2) {
00152       ast_log(LOG_WARNING, "Read failed (BYTES_PER_SAMPLE)\n");
00153       return -1;
00154    }
00155    if (ltohs(bysam) != 2) {
00156       ast_log(LOG_WARNING, "Can only handle 16bits per sample: %d\n", ltohs(bysam));
00157       return -1;
00158    }
00159    if (fread(&bisam, 1, 2, f) != 2) {
00160       ast_log(LOG_WARNING, "Read failed (Bits Per Sample): %d\n", ltohs(bisam));
00161       return -1;
00162    }
00163    /* Skip any additional header */
00164    if (fseek(f,ltohl(hsize)-16,SEEK_CUR) == -1 ) {
00165       ast_log(LOG_WARNING, "Failed to skip remaining header bytes: %d\n", ltohl(hsize)-16 );
00166       return -1;
00167    }
00168    /* Skip any facts and get the first data block */
00169    for(;;)
00170    { 
00171       char buf[4];
00172        
00173        /* Begin data chunk */
00174        if (fread(&buf, 1, 4, f) != 4) {
00175          ast_log(LOG_WARNING, "Read failed (data)\n");
00176          return -1;
00177        }
00178        /* Data has the actual length of data in it */
00179        if (fread(&data, 1, 4, f) != 4) {
00180          ast_log(LOG_WARNING, "Read failed (data)\n");
00181          return -1;
00182        }
00183        data = ltohl(data);
00184        if(memcmp(buf, "data", 4) == 0 ) 
00185          break;
00186        if(memcmp(buf, "fact", 4) != 0 ) {
00187          ast_log(LOG_WARNING, "Unknown block - not fact or data\n");
00188          return -1;
00189        }
00190        if (fseek(f,data,SEEK_CUR) == -1 ) {
00191          ast_log(LOG_WARNING, "Failed to skip fact block: %d\n", data );
00192          return -1;
00193        }
00194    }
00195 #if 0
00196    curpos = lseek(fd, 0, SEEK_CUR);
00197    truelength = lseek(fd, 0, SEEK_END);
00198    lseek(fd, curpos, SEEK_SET);
00199    truelength -= curpos;
00200 #endif   
00201    return data;
00202 }

static int load_module ( void   )  [static]

Definition at line 521 of file format_wav.c.

References ast_format_register, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, wav16_f, and wav_f.

00522 {
00523    if (ast_format_register(&wav_f)
00524       || ast_format_register(&wav16_f))
00525       return AST_MODULE_LOAD_FAILURE;
00526    return AST_MODULE_LOAD_SUCCESS;
00527 }

static int unload_module ( void   )  [static]

Definition at line 529 of file format_wav.c.

References ast_format_unregister(), ast_format::name, wav16_f, and wav_f.

00530 {
00531    return ast_format_unregister(wav_f.name)
00532       || ast_format_unregister(wav16_f.name);
00533 }

static int update_header ( FILE *  f  )  [static]

Definition at line 204 of file format_wav.c.

References ast_log(), fwrite, and LOG_WARNING.

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

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, fwrite, LOG_WARNING, and update_header().

00341 {
00342    char zero = 0;
00343    struct wav_desc *fs = (struct wav_desc *)s->_private;
00344 
00345    if (s->filename) {
00346       update_header(s->f);
00347    }
00348 
00349    /* Pad to even length */
00350    if (fs->bytes & 0x1) {
00351       if (!fwrite(&zero, 1, 1, s->f)) {
00352          ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00353       }
00354    }
00355 }

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::format, and wav_desc::maxlen.

00317 {
00318    /* We don't have any header to read or anything really, but
00319       if we did, it would go here.  We also might want to check
00320       and be sure it's a valid file.  */
00321    struct wav_desc *tmp = (struct wav_desc *)s->_private;
00322    if ((tmp->maxlen = check_header(s->f, (s->fmt->format == AST_FORMAT_SLINEAR16 ? 16000 : 8000))) < 0)
00323       return -1;
00324    return 0;
00325 }

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

Definition at line 357 of file format_wav.c.

References ast_filestream::_private, AST_FORMAT_SLINEAR, AST_FORMAT_SLINEAR16, AST_FRAME_SET_BUFFER, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_filestream::buf, ast_frame_subclass::codec, ast_frame::data, ast_frame::datalen, errno, ast_filestream::f, 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.

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

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::format, wav_desc::hz, and write_header().

00328 {
00329    /* We don't have any header to read or anything really, but
00330       if we did, it would go here.  We also might want to check
00331       and be sure it's a valid file.  */
00332 
00333    struct wav_desc *tmp = (struct wav_desc *)s->_private;
00334    tmp->hz = (s->fmt->format == AST_FORMAT_SLINEAR16 ? 16000 : 8000);
00335    if (write_header(s->f,tmp->hz))
00336       return -1;
00337    return 0;
00338 }

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

Definition at line 451 of file format_wav.c.

References ast_filestream::f, and SEEK_FORCECUR.

00452 {
00453    off_t min, max, cur, offset = 0, samples;
00454 
00455    samples = sample_offset * 2; /* SLINEAR is 16 bits mono, so sample_offset * 2 = bytes */
00456    min = 44; /* wav header is 44 bytes */
00457    cur = ftello(fs->f);
00458    fseeko(fs->f, 0, SEEK_END);
00459    max = ftello(fs->f);
00460    if (whence == SEEK_SET)
00461       offset = samples + min;
00462    else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
00463       offset = samples + cur;
00464    else if (whence == SEEK_END)
00465       offset = max - samples;
00466         if (whence != SEEK_FORCECUR) {
00467       offset = (offset > max)?max:offset;
00468    }
00469    /* always protect the header space. */
00470    offset = (offset < min)?min:offset;
00471    return fseeko(fs->f, offset, SEEK_SET);
00472 }

static off_t wav_tell ( struct ast_filestream fs  )  [static]

Definition at line 481 of file format_wav.c.

References ast_filestream::f.

00482 {
00483    off_t offset;
00484    offset = ftello(fs->f);
00485    /* subtract header size to get samples, then divide by 2 for 16 bit samples */
00486    return (offset - 44)/2;
00487 }

static int wav_trunc ( struct ast_filestream fs  )  [static]

Definition at line 474 of file format_wav.c.

References ast_filestream::f, and update_header().

00475 {
00476    if (ftruncate(fileno(fs->f), ftello(fs->f)))
00477       return -1;
00478    return update_header(fs->f);
00479 }

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

Definition at line 402 of file format_wav.c.

References ast_filestream::_private, AST_FORMAT_SLINEAR, AST_FORMAT_SLINEAR16, AST_FRAME_VOICE, ast_getformatname(), ast_log(), errno, ast_filestream::f, f, ast_filestream::fmt, ast_format::format, fwrite, wav_desc::hz, and LOG_WARNING.

00403 {
00404 #if __BYTE_ORDER == __BIG_ENDIAN
00405    int x;
00406    short tmp[16000], *tmpi;
00407 #endif
00408    struct wav_desc *s = (struct wav_desc *)fs->_private;
00409    int res;
00410 
00411    if (f->frametype != AST_FRAME_VOICE) {
00412       ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00413       return -1;
00414    }
00415    if ((f->subclass.codec != AST_FORMAT_SLINEAR) && (f->subclass.codec != AST_FORMAT_SLINEAR16)) {
00416       ast_log(LOG_WARNING, "Asked to write non-SLINEAR%s frame (%s)!\n", s->hz == 16000 ? "16" : "", ast_getformatname(f->subclass.codec));
00417       return -1;
00418    }
00419    if (f->subclass.codec != fs->fmt->format) {
00420       ast_log(LOG_WARNING, "Can't change SLINEAR frequency during write\n");
00421       return -1;
00422    }
00423    if (!f->datalen)
00424       return -1;
00425 
00426 #if __BYTE_ORDER == __BIG_ENDIAN
00427    /* swap and write */
00428    if (f->datalen > sizeof(tmp)) {
00429       ast_log(LOG_WARNING, "Data length is too long\n");
00430       return -1;
00431    }
00432    tmpi = f->data.ptr;
00433    for (x=0; x < f->datalen/2; x++) 
00434       tmp[x] = (tmpi[x] << 8) | ((tmpi[x] & 0xff00) >> 8);
00435 
00436    if ((res = fwrite(tmp, 1, f->datalen, fs->f)) != f->datalen ) {
00437 #else
00438    /* just write */
00439    if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen ) {
00440 #endif
00441       ast_log(LOG_WARNING, "Bad write (%d): %s\n", res, strerror(errno));
00442       return -1;
00443    }
00444 
00445    s->bytes += f->datalen;
00446       
00447    return 0;
00448 
00449 }

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

Definition at line 245 of file format_wav.c.

References ast_log(), fwrite, and LOG_WARNING.

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


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

Definition at line 539 of file format_wav.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 539 of file format_wav.c.

struct ast_format wav16_f [static]

Definition at line 489 of file format_wav.c.

Referenced by load_module(), and unload_module().

struct ast_format wav_f [static]

Definition at line 505 of file format_wav.c.

Referenced by load_module(), and unload_module().


Generated on Wed Apr 6 11:30:04 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7