format_wav.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Work with WAV in the proprietary Microsoft format.
00022  * Microsoft WAV format (8000hz Signed Linear)
00023  * \arg File name extension: wav (lower case)
00024  * \ingroup formats
00025  */
00026  
00027 /*** MODULEINFO
00028    <support_level>core</support_level>
00029  ***/
00030 
00031 #include "asterisk.h"
00032 
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 433692 $")
00034 
00035 #include "asterisk/mod_format.h"
00036 #include "asterisk/module.h"
00037 #include "asterisk/endian.h"
00038 #include "asterisk/format_cache.h"
00039 #include "asterisk/format.h"
00040 #include "asterisk/codec.h"
00041 
00042 /* Some Ideas for this code came from makewave.c by Jeffrey Chilton */
00043 
00044 /* Portions of the conversion code are by guido@sienanet.it */
00045 
00046 #define  WAV_BUF_SIZE   320
00047 
00048 #define WAV_HEADER_SIZE 44
00049 
00050 struct wav_desc { /* format-specific parameters */
00051    int hz;
00052    int bytes;
00053    int lasttimeout;
00054    int maxlen;
00055    struct timeval last;
00056 };
00057 
00058 #define BLOCKSIZE 160
00059 
00060 #if __BYTE_ORDER == __LITTLE_ENDIAN
00061 #define htoll(b) (b)
00062 #define htols(b) (b)
00063 #define ltohl(b) (b)
00064 #define ltohs(b) (b)
00065 #else
00066 #if __BYTE_ORDER == __BIG_ENDIAN
00067 #define htoll(b) \
00068    (((((b)      ) & 0xFF) << 24) | \
00069    ((( (b) >>  8) & 0xFF) << 16) | \
00070    ((( (b) >> 16) & 0xFF) <<  8) | \
00071    ((( (b) >> 24) & 0xFF)      ))
00072 #define htols(b) \
00073    (((((b)      ) & 0xFF) <<  8) | \
00074    ((( (b) >>  8) & 0xFF)      ))
00075 #define ltohl(b) htoll(b)
00076 #define ltohs(b) htols(b)
00077 #else
00078 #error "Endianess not defined"
00079 #endif
00080 #endif
00081 
00082 
00083 static int check_header_fmt(FILE *f, int hsize, int hz)
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 }
00143 
00144 static int check_header(FILE *f, int hz)
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 }
00210 
00211 static int update_header(FILE *f)
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 }
00251 
00252 static int write_header(FILE *f, int writehz)
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 }
00322 
00323 static int wav_open(struct ast_filestream *s)
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 }
00333 
00334 static int wav_rewrite(struct ast_filestream *s, const char *comment)
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 }
00346 
00347 static void wav_close(struct ast_filestream *s)
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 }
00367 
00368 static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext)
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 }
00409 
00410 static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
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 }
00446 
00447 static int wav_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
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 }
00482 
00483 static int wav_trunc(struct ast_filestream *fs)
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 }
00502 
00503 static off_t wav_tell(struct ast_filestream *fs)
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 }
00510 
00511 static struct ast_format_def wav16_f = {
00512    .name = "wav16",
00513    .exts = "wav16",
00514    .open =  wav_open,
00515    .rewrite = wav_rewrite,
00516    .write = wav_write,
00517    .seek = wav_seek,
00518    .trunc = wav_trunc,
00519    .tell =  wav_tell,
00520    .read = wav_read,
00521    .close = wav_close,
00522    .buf_size = (WAV_BUF_SIZE * 2) + AST_FRIENDLY_OFFSET,
00523    .desc_size = sizeof(struct wav_desc),
00524 };
00525 
00526 static struct ast_format_def wav_f = {
00527    .name = "wav",
00528    .exts = "wav",
00529    .open =  wav_open,
00530    .rewrite = wav_rewrite,
00531    .write = wav_write,
00532    .seek = wav_seek,
00533    .trunc = wav_trunc,
00534    .tell =  wav_tell,
00535    .read = wav_read,
00536    .close = wav_close,
00537    .buf_size = WAV_BUF_SIZE + AST_FRIENDLY_OFFSET,
00538    .desc_size = sizeof(struct wav_desc),
00539 };
00540 
00541 static int load_module(void)
00542 {
00543    wav_f.format = ast_format_slin;
00544    wav16_f.format = ast_format_slin16;
00545    if (ast_format_def_register(&wav_f)
00546       || ast_format_def_register(&wav16_f))
00547       return AST_MODULE_LOAD_FAILURE;
00548    return AST_MODULE_LOAD_SUCCESS;
00549 }
00550 
00551 static int unload_module(void)
00552 {
00553    return ast_format_def_unregister(wav_f.name)
00554       || ast_format_def_unregister(wav16_f.name);
00555 }
00556 
00557 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Microsoft WAV/WAV16 format (8kHz/16kHz Signed Linear)",
00558    .support_level = AST_MODULE_SUPPORT_CORE,
00559    .load = load_module,
00560    .unload = unload_module,
00561    .load_pri = AST_MODPRI_APP_DEPEND
00562 );

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