Sat Mar 24 23:26:04 2007

Asterisk developer's documentation


format_wav_gsm.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 Save GSM in the proprietary Microsoft format.
00022  * 
00023  * Microsoft WAV format (Proprietary GSM)
00024  * \arg File name extension: WAV,wav49  (Upper case WAV, lower case is another format)
00025  * This format can be played on Windows systems, used for
00026  * e-mail attachments mainly.
00027  * \ingroup formats
00028  */
00029  
00030 #include <unistd.h>
00031 #include <netinet/in.h>
00032 #include <arpa/inet.h>
00033 #include <stdlib.h>
00034 #include <sys/time.h>
00035 #include <stdio.h>
00036 #include <errno.h>
00037 #include <string.h>
00038 
00039 #include "asterisk.h"
00040 
00041 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
00042 
00043 #include "asterisk/lock.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/logger.h"
00047 #include "asterisk/sched.h"
00048 #include "asterisk/module.h"
00049 #include "asterisk/endian.h"
00050 
00051 #include "msgsm.h"
00052 
00053 /* Some Ideas for this code came from makewave.c by Jeffrey Chilton */
00054 
00055 /* Portions of the conversion code are by guido@sienanet.it */
00056 
00057 /* begin binary data: */
00058 char msgsm_silence[] = /* 65 */
00059 {0x48,0x17,0xD6,0x84,0x02,0x80,0x24,0x49,0x92,0x24,0x89,0x02,0x80,0x24,0x49
00060 ,0x92,0x24,0x89,0x02,0x80,0x24,0x49,0x92,0x24,0x89,0x02,0x80,0x24,0x49,0x92
00061 ,0x24,0x09,0x82,0x74,0x61,0x4D,0x28,0x00,0x48,0x92,0x24,0x49,0x92,0x28,0x00
00062 ,0x48,0x92,0x24,0x49,0x92,0x28,0x00,0x48,0x92,0x24,0x49,0x92,0x28,0x00,0x48
00063 ,0x92,0x24,0x49,0x92,0x00};
00064 /* end binary data. size = 65 bytes */
00065 
00066 struct ast_filestream {
00067    void *reserved[AST_RESERVED_POINTERS];
00068    /* Believe it or not, we must decode/recode to account for the
00069       weird MS format */
00070    /* This is what a filestream means to us */
00071    FILE *f; /* Descriptor */
00072    struct ast_frame fr;          /* Frame information */
00073    char waste[AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */
00074    char empty;                   /* Empty character */
00075    unsigned char gsm[66];           /* Two Real GSM Frames */
00076    int foffset;
00077    int secondhalf;                  /* Are we on the second half */
00078    struct timeval last;
00079 };
00080 
00081 
00082 AST_MUTEX_DEFINE_STATIC(wav_lock);
00083 static int glistcnt = 0;
00084 
00085 static char *name = "wav49";
00086 static char *desc = "Microsoft WAV format (Proprietary GSM)";
00087 static char *exts = "WAV|wav49";
00088 
00089 #if __BYTE_ORDER == __LITTLE_ENDIAN
00090 #define htoll(b) (b)
00091 #define htols(b) (b)
00092 #define ltohl(b) (b)
00093 #define ltohs(b) (b)
00094 #else
00095 #if __BYTE_ORDER == __BIG_ENDIAN
00096 #define htoll(b)  \
00097           (((((b)      ) & 0xFF) << 24) | \
00098           ((((b) >>  8) & 0xFF) << 16) | \
00099          ((((b) >> 16) & 0xFF) <<  8) | \
00100          ((((b) >> 24) & 0xFF)      ))
00101 #define htols(b) \
00102           (((((b)      ) & 0xFF) << 8) | \
00103          ((((b) >> 8) & 0xFF)      ))
00104 #define ltohl(b) htoll(b)
00105 #define ltohs(b) htols(b)
00106 #else
00107 #error "Endianess not defined"
00108 #endif
00109 #endif
00110 
00111 
00112 static int check_header(FILE *f)
00113 {
00114    int type, size, formtype;
00115    int fmt, hsize, fact;
00116    short format, chans;
00117    int freq;
00118    int data;
00119    if (fread(&type, 1, 4, f) != 4) {
00120       ast_log(LOG_WARNING, "Read failed (type)\n");
00121       return -1;
00122    }
00123    if (fread(&size, 1, 4, f) != 4) {
00124       ast_log(LOG_WARNING, "Read failed (size)\n");
00125       return -1;
00126    }
00127    size = ltohl(size);
00128    if (fread(&formtype, 1, 4, f) != 4) {
00129       ast_log(LOG_WARNING, "Read failed (formtype)\n");
00130       return -1;
00131    }
00132    if (memcmp(&type, "RIFF", 4)) {
00133       ast_log(LOG_WARNING, "Does not begin with RIFF\n");
00134       return -1;
00135    }
00136    if (memcmp(&formtype, "WAVE", 4)) {
00137       ast_log(LOG_WARNING, "Does not contain WAVE\n");
00138       return -1;
00139    }
00140    if (fread(&fmt, 1, 4, f) != 4) {
00141       ast_log(LOG_WARNING, "Read failed (fmt)\n");
00142       return -1;
00143    }
00144    if (memcmp(&fmt, "fmt ", 4)) {
00145       ast_log(LOG_WARNING, "Does not say fmt\n");
00146       return -1;
00147    }
00148    if (fread(&hsize, 1, 4, f) != 4) {
00149       ast_log(LOG_WARNING, "Read failed (formtype)\n");
00150       return -1;
00151    }
00152    if (ltohl(hsize) != 20) {
00153       ast_log(LOG_WARNING, "Unexpected header size %d\n", ltohl(hsize));
00154       return -1;
00155    }
00156    if (fread(&format, 1, 2, f) != 2) {
00157       ast_log(LOG_WARNING, "Read failed (format)\n");
00158       return -1;
00159    }
00160    if (ltohs(format) != 49) {
00161       ast_log(LOG_WARNING, "Not a GSM file %d\n", ltohs(format));
00162       return -1;
00163    }
00164    if (fread(&chans, 1, 2, f) != 2) {
00165       ast_log(LOG_WARNING, "Read failed (format)\n");
00166       return -1;
00167    }
00168    if (ltohs(chans) != 1) {
00169       ast_log(LOG_WARNING, "Not in mono %d\n", ltohs(chans));
00170       return -1;
00171    }
00172    if (fread(&freq, 1, 4, f) != 4) {
00173       ast_log(LOG_WARNING, "Read failed (freq)\n");
00174       return -1;
00175    }
00176    if (ltohl(freq) != 8000) {
00177       ast_log(LOG_WARNING, "Unexpected freqency %d\n", ltohl(freq));
00178       return -1;
00179    }
00180    /* Ignore the byte frequency */
00181    if (fread(&freq, 1, 4, f) != 4) {
00182       ast_log(LOG_WARNING, "Read failed (X_1)\n");
00183       return -1;
00184    }
00185    /* Ignore the two weird fields */
00186    if (fread(&freq, 1, 4, f) != 4) {
00187       ast_log(LOG_WARNING, "Read failed (X_2/X_3)\n");
00188       return -1;
00189    }
00190    /* Ignore the byte frequency */
00191    if (fread(&freq, 1, 4, f) != 4) {
00192       ast_log(LOG_WARNING, "Read failed (Y_1)\n");
00193       return -1;
00194    }
00195    /* Check for the word fact */
00196    if (fread(&fact, 1, 4, f) != 4) {
00197       ast_log(LOG_WARNING, "Read failed (fact)\n");
00198       return -1;
00199    }
00200    if (memcmp(&fact, "fact", 4)) {
00201       ast_log(LOG_WARNING, "Does not say fact\n");
00202       return -1;
00203    }
00204    /* Ignore the "fact value" */
00205    if (fread(&fact, 1, 4, f) != 4) {
00206       ast_log(LOG_WARNING, "Read failed (fact header)\n");
00207       return -1;
00208    }
00209    if (fread(&fact, 1, 4, f) != 4) {
00210       ast_log(LOG_WARNING, "Read failed (fact value)\n");
00211       return -1;
00212    }
00213    /* Check for the word data */
00214    if (fread(&data, 1, 4, f) != 4) {
00215       ast_log(LOG_WARNING, "Read failed (data)\n");
00216       return -1;
00217    }
00218    if (memcmp(&data, "data", 4)) {
00219       ast_log(LOG_WARNING, "Does not say data\n");
00220       return -1;
00221    }
00222    /* Ignore the data length */
00223    if (fread(&data, 1, 4, f) != 4) {
00224       ast_log(LOG_WARNING, "Read failed (data)\n");
00225       return -1;
00226    }
00227    return 0;
00228 }
00229 
00230 static int update_header(FILE *f)
00231 {
00232    off_t cur,end,bytes;
00233    int datalen,filelen;
00234    
00235    cur = ftell(f);
00236    fseek(f, 0, SEEK_END);
00237    end = ftell(f);
00238    /* in a gsm WAV, data starts 60 bytes in */
00239    bytes = end - 60;
00240    datalen = htoll((bytes + 1) & ~0x1);
00241    filelen = htoll(52 + ((bytes + 1) & ~0x1));
00242    if (cur < 0) {
00243       ast_log(LOG_WARNING, "Unable to find our position\n");
00244       return -1;
00245    }
00246    if (fseek(f, 4, SEEK_SET)) {
00247       ast_log(LOG_WARNING, "Unable to set our position\n");
00248       return -1;
00249    }
00250    if (fwrite(&filelen, 1, 4, f) != 4) {
00251       ast_log(LOG_WARNING, "Unable to set write file size\n");
00252       return -1;
00253    }
00254    if (fseek(f, 56, SEEK_SET)) {
00255       ast_log(LOG_WARNING, "Unable to set our position\n");
00256       return -1;
00257    }
00258    if (fwrite(&datalen, 1, 4, f) != 4) {
00259       ast_log(LOG_WARNING, "Unable to set write datalen\n");
00260       return -1;
00261    }
00262    if (fseek(f, cur, SEEK_SET)) {
00263       ast_log(LOG_WARNING, "Unable to return to position\n");
00264       return -1;
00265    }
00266    return 0;
00267 }
00268 
00269 static int write_header(FILE *f)
00270 {
00271    unsigned int hz=htoll(8000);
00272    unsigned int bhz = htoll(1625);
00273    unsigned int hs = htoll(20);
00274    unsigned short fmt = htols(49);
00275    unsigned short chans = htols(1);
00276    unsigned int fhs = htoll(4);
00277    unsigned int x_1 = htoll(65);
00278    unsigned short x_2 = htols(2);
00279    unsigned short x_3 = htols(320);
00280    unsigned int y_1 = htoll(20160);
00281    unsigned int size = htoll(0);
00282    /* Write a GSM header, ignoring sizes which will be filled in later */
00283    if (fwrite("RIFF", 1, 4, f) != 4) {
00284       ast_log(LOG_WARNING, "Unable to write header\n");
00285       return -1;
00286    }
00287    if (fwrite(&size, 1, 4, f) != 4) {
00288       ast_log(LOG_WARNING, "Unable to write header\n");
00289       return -1;
00290    }
00291    if (fwrite("WAVEfmt ", 1, 8, f) != 8) {
00292       ast_log(LOG_WARNING, "Unable to write header\n");
00293       return -1;
00294    }
00295    if (fwrite(&hs, 1, 4, f) != 4) {
00296       ast_log(LOG_WARNING, "Unable to write header\n");
00297       return -1;
00298    }
00299    if (fwrite(&fmt, 1, 2, f) != 2) {
00300       ast_log(LOG_WARNING, "Unable to write header\n");
00301       return -1;
00302    }
00303    if (fwrite(&chans, 1, 2, f) != 2) {
00304       ast_log(LOG_WARNING, "Unable to write header\n");
00305       return -1;
00306    }
00307    if (fwrite(&hz, 1, 4, f) != 4) {
00308       ast_log(LOG_WARNING, "Unable to write header\n");
00309       return -1;
00310    }
00311    if (fwrite(&bhz, 1, 4, f) != 4) {
00312       ast_log(LOG_WARNING, "Unable to write header\n");
00313       return -1;
00314    }
00315    if (fwrite(&x_1, 1, 4, f) != 4) {
00316       ast_log(LOG_WARNING, "Unable to write header\n");
00317       return -1;
00318    }
00319    if (fwrite(&x_2, 1, 2, f) != 2) {
00320       ast_log(LOG_WARNING, "Unable to write header\n");
00321       return -1;
00322    }
00323    if (fwrite(&x_3, 1, 2, f) != 2) {
00324       ast_log(LOG_WARNING, "Unable to write header\n");
00325       return -1;
00326    }
00327    if (fwrite("fact", 1, 4, f) != 4) {
00328       ast_log(LOG_WARNING, "Unable to write header\n");
00329       return -1;
00330    }
00331    if (fwrite(&fhs, 1, 4, f) != 4) {
00332       ast_log(LOG_WARNING, "Unable to write header\n");
00333       return -1;
00334    }
00335    if (fwrite(&y_1, 1, 4, f) != 4) {
00336       ast_log(LOG_WARNING, "Unable to write header\n");
00337       return -1;
00338    }
00339    if (fwrite("data", 1, 4, f) != 4) {
00340       ast_log(LOG_WARNING, "Unable to write header\n");
00341       return -1;
00342    }
00343    if (fwrite(&size, 1, 4, f) != 4) {
00344       ast_log(LOG_WARNING, "Unable to write header\n");
00345       return -1;
00346    }
00347    return 0;
00348 }
00349 
00350 static struct ast_filestream *wav_open(FILE *f)
00351 {
00352    /* We don't have any header to read or anything really, but
00353       if we did, it would go here.  We also might want to check
00354       and be sure it's a valid file.  */
00355    struct ast_filestream *tmp;
00356    if ((tmp = malloc(sizeof(struct ast_filestream)))) {
00357       memset(tmp, 0, sizeof(struct ast_filestream));
00358       if (check_header(f)) {
00359          free(tmp);
00360          return NULL;
00361       }
00362       if (ast_mutex_lock(&wav_lock)) {
00363          ast_log(LOG_WARNING, "Unable to lock wav list\n");
00364          free(tmp);
00365          return NULL;
00366       }
00367       tmp->f = f;
00368       tmp->fr.data = tmp->gsm;
00369       tmp->fr.frametype = AST_FRAME_VOICE;
00370       tmp->fr.subclass = AST_FORMAT_GSM;
00371       /* datalen will vary for each frame */
00372       tmp->fr.src = name;
00373       tmp->fr.mallocd = 0;
00374       tmp->secondhalf = 0;
00375       glistcnt++;
00376       ast_mutex_unlock(&wav_lock);
00377       ast_update_use_count();
00378    }
00379    return tmp;
00380 }
00381 
00382 static struct ast_filestream *wav_rewrite(FILE *f, const char *comment)
00383 {
00384    /* We don't have any header to read or anything really, but
00385       if we did, it would go here.  We also might want to check
00386       and be sure it's a valid file.  */
00387    struct ast_filestream *tmp;
00388    if ((tmp = malloc(sizeof(struct ast_filestream)))) {
00389       memset(tmp, 0, sizeof(struct ast_filestream));
00390       if (write_header(f)) {
00391          free(tmp);
00392          return NULL;
00393       }
00394       if (ast_mutex_lock(&wav_lock)) {
00395          ast_log(LOG_WARNING, "Unable to lock wav list\n");
00396          free(tmp);
00397          return NULL;
00398       }
00399       tmp->f = f;
00400       glistcnt++;
00401       ast_mutex_unlock(&wav_lock);
00402       ast_update_use_count();
00403    } else
00404       ast_log(LOG_WARNING, "Out of memory\n");
00405    return tmp;
00406 }
00407 
00408 static void wav_close(struct ast_filestream *s)
00409 {
00410    char zero = 0;
00411    if (ast_mutex_lock(&wav_lock)) {
00412       ast_log(LOG_WARNING, "Unable to lock wav list\n");
00413       return;
00414    }
00415    glistcnt--;
00416    ast_mutex_unlock(&wav_lock);
00417    ast_update_use_count();
00418    /* Pad to even length */
00419    fseek(s->f, 0, SEEK_END);
00420    if (ftell(s->f) & 0x1)
00421       fwrite(&zero, 1, 1, s->f);
00422    fclose(s->f);
00423    free(s);
00424    s = NULL;
00425 }
00426 
00427 static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext)
00428 {
00429    int res;
00430    char msdata[66];
00431    /* Send a frame from the file to the appropriate channel */
00432 
00433    s->fr.frametype = AST_FRAME_VOICE;
00434    s->fr.subclass = AST_FORMAT_GSM;
00435    s->fr.offset = AST_FRIENDLY_OFFSET;
00436    s->fr.samples = 160;
00437    s->fr.datalen = 33;
00438    s->fr.mallocd = 0;
00439    if (s->secondhalf) {
00440       /* Just return a frame based on the second GSM frame */
00441       s->fr.data = s->gsm + 33;
00442    } else {
00443       if ((res = fread(msdata, 1, 65, s->f)) != 65) {
00444          if (res && (res != 1))
00445             ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
00446          return NULL;
00447       }
00448       /* Convert from MS format to two real GSM frames */
00449       conv65(msdata, s->gsm);
00450       s->fr.data = s->gsm;
00451    }
00452    s->secondhalf = !s->secondhalf;
00453    *whennext = 160;
00454    return &s->fr;
00455 }
00456 
00457 static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
00458 {
00459    int res;
00460    char msdata[66];
00461    int len =0;
00462    int alreadyms=0;
00463    if (f->frametype != AST_FRAME_VOICE) {
00464       ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00465       return -1;
00466    }
00467    if (f->subclass != AST_FORMAT_GSM) {
00468       ast_log(LOG_WARNING, "Asked to write non-GSM frame (%d)!\n", f->subclass);
00469       return -1;
00470    }
00471    if (!(f->datalen % 65)) 
00472       alreadyms = 1;
00473    while(len < f->datalen) {
00474       if (alreadyms) {
00475          fs->secondhalf = 0;
00476          if ((res = fwrite(f->data + len, 1, 65, fs->f)) != 65) {
00477             ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno));
00478             return -1;
00479          }
00480          update_header(fs->f);
00481          len += 65;
00482       } else {
00483          if (fs->secondhalf) {
00484             memcpy(fs->gsm + 33, f->data + len, 33);
00485             conv66(fs->gsm, msdata);
00486             if ((res = fwrite(msdata, 1, 65, fs->f)) != 65) {
00487                ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno));
00488                return -1;
00489             }
00490             update_header(fs->f);
00491          } else {
00492             /* Copy the data and do nothing */
00493             memcpy(fs->gsm, f->data + len, 33);
00494          }
00495          fs->secondhalf = !fs->secondhalf;
00496          len += 33;
00497       }
00498    }
00499    return 0;
00500 }
00501 
00502 static int wav_seek(struct ast_filestream *fs, long sample_offset, int whence)
00503 {
00504    off_t offset=0,distance,cur,min,max;
00505    min = 60;
00506    cur = ftell(fs->f);
00507    fseek(fs->f, 0, SEEK_END);
00508    max = ftell(fs->f);
00509    /* I'm getting sloppy here, I'm only going to go to even splits of the 2
00510     * frames, if you want tighter cuts use format_gsm, format_pcm, or format_wav */
00511    distance = (sample_offset/320) * 65;
00512    if(whence == SEEK_SET)
00513       offset = distance + min;
00514    else if(whence == SEEK_CUR || whence == SEEK_FORCECUR)
00515       offset = distance + cur;
00516    else if(whence == SEEK_END)
00517       offset = max - distance;
00518    /* always protect against seeking past end of header */
00519    offset = (offset < min)?min:offset;
00520    if (whence != SEEK_FORCECUR) {
00521       offset = (offset > max)?max:offset;
00522    } else if (offset > max) {
00523       int i;
00524       fseek(fs->f, 0, SEEK_END);
00525       for (i=0; i< (offset - max) / 65; i++) {
00526          fwrite(msgsm_silence, 1, 65, fs->f);
00527       }
00528    }
00529    fs->secondhalf = 0;
00530    return fseek(fs->f, offset, SEEK_SET);
00531 }
00532 
00533 static int wav_trunc(struct ast_filestream *fs)
00534 {
00535    if (ftruncate(fileno(fs->f), ftell(fs->f)))
00536       return -1;
00537    return update_header(fs->f);
00538 }
00539 
00540 static long wav_tell(struct ast_filestream *fs)
00541 {
00542    off_t offset;
00543    offset = ftell(fs->f);
00544    /* since this will most likely be used later in play or record, lets stick
00545     * to that level of resolution, just even frames boundaries */
00546    return (offset - 52)/65*320;
00547 }
00548 
00549 static char *wav_getcomment(struct ast_filestream *s)
00550 {
00551    return NULL;
00552 }
00553 
00554 int load_module()
00555 {
00556    return ast_format_register(name, exts, AST_FORMAT_GSM,
00557                         wav_open,
00558                         wav_rewrite,
00559                         wav_write,
00560                         wav_seek,
00561                         wav_trunc,
00562                         wav_tell,
00563                         wav_read,
00564                         wav_close,
00565                         wav_getcomment);
00566                         
00567                         
00568 }
00569 
00570 int unload_module()
00571 {
00572    return ast_format_unregister(name);
00573 }  
00574 
00575 int usecount()
00576 {
00577    return glistcnt;
00578 }
00579 
00580 char *description()
00581 {
00582    return desc;
00583 }
00584 
00585 
00586 char *key()
00587 {
00588    return ASTERISK_GPL_KEY;
00589 }

Generated on Sat Mar 24 23:26:04 2007 for Asterisk - the Open Source PBX by  doxygen 1.4.6