Thu May 14 15:13:32 2009

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 <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/time.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/sched.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 GAIN   0
#define htoll(b)   (b)
#define htols(b)   (b)
#define ltohl(b)   (b)
#define ltohs(b)   (b)
#define WAV_BUF_SIZE   320

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int check_header (FILE *f)
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)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Microsoft WAV format (8000Hz 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 = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, }
static const struct ast_module_infoast_module_info = &__mod_info
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 62 of file format_wav.c.

#define GAIN   0

Definition at line 64 of file format_wav.c.

Referenced by wav_read(), and wav_write().

#define htoll (  )     (b)

Definition at line 68 of file format_wav.c.

#define htols (  )     (b)

Definition at line 69 of file format_wav.c.

#define ltohl (  )     (b)

Definition at line 70 of file format_wav.c.

#define ltohs (  )     (b)

Definition at line 71 of file format_wav.c.

#define WAV_BUF_SIZE   320

Definition at line 52 of file format_wav.c.

Referenced by wav_read().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 531 of file format_wav.c.

static void __unreg_module ( void   )  [static]

Definition at line 531 of file format_wav.c.

static int check_header ( FILE *  f  )  [static]

Definition at line 90 of file format_wav.c.

References ast_log(), DEFAULT_SAMPLE_RATE, format, LOG_WARNING, ltohl, ltohs, and type.

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

static int load_module ( void   )  [static]

Definition at line 521 of file format_wav.c.

References ast_format_register, and wav_f.

00522 {
00523    return ast_format_register(&wav_f);
00524 }

static int unload_module ( void   )  [static]

Definition at line 526 of file format_wav.c.

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

00527 {
00528    return ast_format_unregister(wav_f.name);
00529 }  

static int update_header ( FILE *  f  )  [static]

Definition at line 218 of file format_wav.c.

References ast_log(), errno, htoll, and LOG_WARNING.

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

static void wav_close ( struct ast_filestream s  )  [static]

Definition at line 344 of file format_wav.c.

References ast_log(), wav_desc::bytes, errno, LOG_WARNING, and s.

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

static int wav_open ( struct ast_filestream s  )  [static]

Definition at line 322 of file format_wav.c.

References check_header(), wav_desc::maxlen, and s.

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

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

Definition at line 356 of file format_wav.c.

References AST_FORMAT_SLINEAR, AST_FRAME_SET_BUFFER, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), errno, GAIN, LOG_WARNING, wav_desc::maxlen, wav_desc::needsgain, s, ast_frame::samples, and WAV_BUF_SIZE.

00357 {
00358    int res;
00359    int samples;   /* actual samples read */
00360    int x;
00361    short *tmp;
00362    int bytes = WAV_BUF_SIZE;  /* in bytes */
00363    off_t here;
00364    /* Send a frame from the file to the appropriate channel */
00365    struct wav_desc *fs = (struct wav_desc *)s->_private;
00366 
00367    here = ftello(s->f);
00368    if (fs->maxlen - here < bytes)      /* truncate if necessary */
00369       bytes = fs->maxlen - here;
00370    if (bytes < 0)
00371       bytes = 0;
00372 /*    ast_log(LOG_DEBUG, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */
00373    s->fr.frametype = AST_FRAME_VOICE;
00374    s->fr.subclass = AST_FORMAT_SLINEAR;
00375    s->fr.mallocd = 0;
00376    AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, bytes);
00377    
00378    if ( (res = fread(s->fr.data, 1, s->fr.datalen, s->f)) <= 0 ) {
00379       if (res)
00380          ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
00381       return NULL;
00382    }
00383    s->fr.datalen = res;
00384    s->fr.samples = samples = res / 2;
00385 
00386    tmp = (short *)(s->fr.data);
00387 #if __BYTE_ORDER == __BIG_ENDIAN
00388    /* file format is little endian so we need to swap */
00389    for( x = 0; x < samples; x++)
00390       tmp[x] = (tmp[x] << 8) | ((tmp[x] & 0xff00) >> 8);
00391 #endif
00392 
00393    if (fs->needsgain) {
00394       for (x=0; x < samples; x++) {
00395          if (tmp[x] & ((1 << GAIN) - 1)) {
00396             /* If it has data down low, then it's not something we've artificially increased gain
00397                on, so we don't need to gain adjust it */
00398             fs->needsgain = 0;
00399             break;
00400          }
00401       }
00402       if (fs->needsgain) {
00403          for (x=0; x < samples; x++)
00404             tmp[x] = tmp[x] >> GAIN;
00405       }
00406    }
00407          
00408    *whennext = samples;
00409    return &s->fr;
00410 }

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

Definition at line 333 of file format_wav.c.

References s, and write_header().

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

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

Definition at line 467 of file format_wav.c.

References ast_filestream::f, offset, and SEEK_FORCECUR.

00468 {
00469    off_t min, max, cur, offset = 0, samples;
00470 
00471    samples = sample_offset * 2; /* SLINEAR is 16 bits mono, so sample_offset * 2 = bytes */
00472    min = 44; /* wav header is 44 bytes */
00473    cur = ftello(fs->f);
00474    fseeko(fs->f, 0, SEEK_END);
00475    max = ftello(fs->f);
00476    if (whence == SEEK_SET)
00477       offset = samples + min;
00478    else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
00479       offset = samples + cur;
00480    else if (whence == SEEK_END)
00481       offset = max - samples;
00482         if (whence != SEEK_FORCECUR) {
00483       offset = (offset > max)?max:offset;
00484    }
00485    /* always protect the header space. */
00486    offset = (offset < min)?min:offset;
00487    return fseeko(fs->f, offset, SEEK_SET);
00488 }

static off_t wav_tell ( struct ast_filestream fs  )  [static]

Definition at line 497 of file format_wav.c.

References ast_filestream::f, and offset.

00498 {
00499    off_t offset;
00500    offset = ftello(fs->f);
00501    /* subtract header size to get samples, then divide by 2 for 16 bit samples */
00502    return (offset - 44)/2;
00503 }

static int wav_trunc ( struct ast_filestream fs  )  [static]

Definition at line 490 of file format_wav.c.

References ast_filestream::f, and update_header().

00491 {
00492    if (ftruncate(fileno(fs->f), ftello(fs->f)))
00493       return -1;
00494    return update_header(fs->f);
00495 }

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

Definition at line 412 of file format_wav.c.

References ast_filestream::_private, AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_log(), errno, ast_filestream::f, f, GAIN, LOG_WARNING, s, and update_header().

00413 {
00414    int x;
00415    short tmp[8000], *tmpi;
00416    float tmpf;
00417    struct wav_desc *s = (struct wav_desc *)fs->_private;
00418    int res;
00419 
00420    if (f->frametype != AST_FRAME_VOICE) {
00421       ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00422       return -1;
00423    }
00424    if (f->subclass != AST_FORMAT_SLINEAR) {
00425       ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%d)!\n", f->subclass);
00426       return -1;
00427    }
00428    if (f->datalen > sizeof(tmp)) {
00429       ast_log(LOG_WARNING, "Data length is too long\n");
00430       return -1;
00431    }
00432    if (!f->datalen)
00433       return -1;
00434 
00435 #if 0
00436    printf("Data Length: %d\n", f->datalen);
00437 #endif   
00438 
00439    tmpi = f->data;
00440    /* Volume adjust here to accomodate */
00441    for (x=0;x<f->datalen/2;x++) {
00442       tmpf = ((float)tmpi[x]) * ((float)(1 << GAIN));
00443       if (tmpf > 32767.0)
00444          tmpf = 32767.0;
00445       if (tmpf < -32768.0)
00446          tmpf = -32768.0;
00447       tmp[x] = tmpf;
00448       tmp[x] &= ~((1 << GAIN) - 1);
00449 
00450 #if __BYTE_ORDER == __BIG_ENDIAN
00451       tmp[x] = (tmp[x] << 8) | ((tmp[x] & 0xff00) >> 8);
00452 #endif
00453 
00454    }
00455    if ((res = fwrite(tmp, 1, f->datalen, fs->f)) != f->datalen ) {
00456       ast_log(LOG_WARNING, "Bad write (%d): %s\n", res, strerror(errno));
00457       return -1;
00458    }
00459 
00460    s->bytes += f->datalen;
00461    update_header(fs->f);
00462       
00463    return 0;
00464 
00465 }

static int write_header ( FILE *  f  )  [static]

Definition at line 259 of file format_wav.c.

References ast_log(), htoll, htols, and LOG_WARNING.

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


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Microsoft WAV format (8000Hz 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 = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, } [static]

Definition at line 531 of file format_wav.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 531 of file format_wav.c.

struct ast_format wav_f [static]

Definition at line 505 of file format_wav.c.

Referenced by load_module(), and unload_module().


Generated on Thu May 14 15:13:32 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7