Mon Mar 12 2012 21:39:41

Asterisk developer's documentation


format_wav_gsm.c File Reference

Save GSM in the proprietary Microsoft format. More...

#include "asterisk.h"
#include "asterisk/mod_format.h"
#include "asterisk/module.h"
#include "asterisk/endian.h"
#include "msgsm.h"
Include dependency graph for format_wav_gsm.c:

Go to the source code of this file.

Data Structures

struct  wavg_desc

Defines

#define GSM_FRAME_SIZE   33
#define GSM_SAMPLES   160
#define MSGSM_DATA_OFFSET   60
#define MSGSM_FRAME_SIZE   65
#define MSGSM_SAMPLES   (2*GSM_SAMPLES)

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 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 *s, struct ast_frame *f)
static int write_header (FILE *f)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Microsoft WAV format (Proprietary GSM)" , .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, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND }
static struct ast_module_infoast_module_info = &__mod_info
static char msgsm_silence []
static struct ast_format wav49_f

Detailed Description

Save GSM in the proprietary Microsoft format.

Microsoft WAV format (Proprietary GSM)

  • File name extension: WAV,wav49 (Upper case WAV, lower case is another format) This format can be played on Windows systems, used for e-mail attachments mainly.

Definition in file format_wav_gsm.c.


Define Documentation

#define GSM_FRAME_SIZE   33

Definition at line 48 of file format_wav_gsm.c.

Referenced by wav_read(), and wav_write().

#define GSM_SAMPLES   160

Definition at line 51 of file format_wav_gsm.c.

Referenced by wav_read().

#define MSGSM_DATA_OFFSET   60

Definition at line 50 of file format_wav_gsm.c.

Referenced by update_header(), wav_seek(), and wav_tell().

#define MSGSM_FRAME_SIZE   65

Definition at line 49 of file format_wav_gsm.c.

Referenced by update_header(), wav_read(), wav_seek(), wav_tell(), wav_write(), and write_header().

#define MSGSM_SAMPLES   (2*GSM_SAMPLES)

Definition at line 52 of file format_wav_gsm.c.

Referenced by update_header(), wav_seek(), wav_tell(), and write_header().


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 559 of file format_wav_gsm.c.

static void __unreg_module ( void  ) [static]

Definition at line 559 of file format_wav_gsm.c.

static int check_header ( FILE *  f) [static]

Definition at line 92 of file format_wav_gsm.c.

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

Referenced by wav_open().

{
   int type, size, formtype;
   int fmt, hsize, fact;
   short format, chans;
   int freq;
   int data;
   if (fread(&type, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (type)\n");
      return -1;
   }
   if (fread(&size, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (size)\n");
      return -1;
   }
   size = ltohl(size);
   if (fread(&formtype, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (formtype)\n");
      return -1;
   }
   if (memcmp(&type, "RIFF", 4)) {
      ast_log(LOG_WARNING, "Does not begin with RIFF\n");
      return -1;
   }
   if (memcmp(&formtype, "WAVE", 4)) {
      ast_log(LOG_WARNING, "Does not contain WAVE\n");
      return -1;
   }
   if (fread(&fmt, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (fmt)\n");
      return -1;
   }
   if (memcmp(&fmt, "fmt ", 4)) {
      ast_log(LOG_WARNING, "Does not say fmt\n");
      return -1;
   }
   if (fread(&hsize, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (formtype)\n");
      return -1;
   }
   if (ltohl(hsize) != 20) {
      ast_log(LOG_WARNING, "Unexpected header size %d\n", ltohl(hsize));
      return -1;
   }
   if (fread(&format, 1, 2, f) != 2) {
      ast_log(LOG_WARNING, "Read failed (format)\n");
      return -1;
   }
   if (ltohs(format) != 49) {
      ast_log(LOG_WARNING, "Not a GSM file %d\n", ltohs(format));
      return -1;
   }
   if (fread(&chans, 1, 2, f) != 2) {
      ast_log(LOG_WARNING, "Read failed (format)\n");
      return -1;
   }
   if (ltohs(chans) != 1) {
      ast_log(LOG_WARNING, "Not in mono %d\n", ltohs(chans));
      return -1;
   }
   if (fread(&freq, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (freq)\n");
      return -1;
   }
   if (ltohl(freq) != DEFAULT_SAMPLE_RATE) {
      ast_log(LOG_WARNING, "Unexpected frequency %d\n", ltohl(freq));
      return -1;
   }
   /* Ignore the byte frequency */
   if (fread(&freq, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (X_1)\n");
      return -1;
   }
   /* Ignore the two weird fields */
   if (fread(&freq, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (X_2/X_3)\n");
      return -1;
   }
   /* Ignore the byte frequency */
   if (fread(&freq, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (Y_1)\n");
      return -1;
   }
   /* Check for the word fact */
   if (fread(&fact, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (fact)\n");
      return -1;
   }
   if (memcmp(&fact, "fact", 4)) {
      ast_log(LOG_WARNING, "Does not say fact\n");
      return -1;
   }
   /* Ignore the "fact value" */
   if (fread(&fact, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (fact header)\n");
      return -1;
   }
   if (fread(&fact, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (fact value)\n");
      return -1;
   }
   /* Check for the word data */
   if (fread(&data, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (data)\n");
      return -1;
   }
   if (memcmp(&data, "data", 4)) {
      ast_log(LOG_WARNING, "Does not say data\n");
      return -1;
   }
   /* Ignore the data length */
   if (fread(&data, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Read failed (data)\n");
      return -1;
   }
   return 0;
}
static int load_module ( void  ) [static]
static int unload_module ( void  ) [static]

Definition at line 550 of file format_wav_gsm.c.

References ast_format_unregister(), and ast_format::name.

static int update_header ( FILE *  f) [static]

Definition at line 210 of file format_wav_gsm.c.

References ast_log(), LOG_WARNING, MSGSM_DATA_OFFSET, MSGSM_FRAME_SIZE, and MSGSM_SAMPLES.

Referenced by wav_trunc(), and wav_write().

{
   off_t cur,end,bytes;
   int datalen, filelen, samples;

   cur = ftello(f);
   fseek(f, 0, SEEK_END);
   end = ftello(f);
   /* in a gsm WAV, data starts 60 bytes in */
   bytes = end - MSGSM_DATA_OFFSET;
   samples = htoll(bytes / MSGSM_FRAME_SIZE * MSGSM_SAMPLES);
   datalen = htoll(bytes);
   filelen = htoll(MSGSM_DATA_OFFSET - 8 + bytes);
   if (cur < 0) {
      ast_log(LOG_WARNING, "Unable to find our position\n");
      return -1;
   }
   if (fseek(f, 4, SEEK_SET)) {
      ast_log(LOG_WARNING, "Unable to set our position\n");
      return -1;
   }
   if (fwrite(&filelen, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write file size\n");
      return -1;
   }
   if (fseek(f, 48, SEEK_SET)) {
      ast_log(LOG_WARNING, "Unable to set our position\n");
      return -1;
   }
   if (fwrite(&samples, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write samples\n");
      return -1;
   }
   if (fseek(f, 56, SEEK_SET)) {
      ast_log(LOG_WARNING, "Unable to set our position\n");
      return -1;
   }
   if (fwrite(&datalen, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write datalen\n");
      return -1;
   }
   if (fseeko(f, cur, SEEK_SET)) {
      ast_log(LOG_WARNING, "Unable to return to position\n");
      return -1;
   }
   return 0;
}
static int wav_open ( struct ast_filestream s) [static]

Definition at line 372 of file format_wav_gsm.c.

References ast_filestream::_private, check_header(), ast_filestream::f, and wavg_desc::secondhalf.

{
   /* We don't have any header to read or anything really, but
      if we did, it would go here.  We also might want to check
      and be sure it's a valid file.  */
   struct wavg_desc *fs = (struct wavg_desc *)s->_private;

   if (check_header(s->f))
      return -1;
   fs->secondhalf = 0;  /* not strictly necessary */
   return 0;
}
static struct ast_frame* wav_read ( struct ast_filestream s,
int *  whennext 
) [static, read]

Definition at line 396 of file format_wav_gsm.c.

References ast_filestream::_private, AST_FORMAT_GSM, AST_FRAME_SET_BUFFER, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_filestream::buf, ast_frame_subclass::codec, conv65(), ast_frame::data, errno, ast_filestream::f, ast_filestream::fr, ast_frame::frametype, GSM_FRAME_SIZE, GSM_SAMPLES, LOG_WARNING, ast_frame::mallocd, MSGSM_FRAME_SIZE, ast_frame::offset, ast_frame::ptr, ast_frame::samples, wavg_desc::secondhalf, and ast_frame::subclass.

{
   /* Send a frame from the file to the appropriate channel */
   struct wavg_desc *fs = (struct wavg_desc *)s->_private;

   s->fr.frametype = AST_FRAME_VOICE;
   s->fr.subclass.codec = AST_FORMAT_GSM;
   s->fr.offset = AST_FRIENDLY_OFFSET;
   s->fr.samples = GSM_SAMPLES;
   s->fr.mallocd = 0;
   AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, GSM_FRAME_SIZE);
   if (fs->secondhalf) {
      /* Just return a frame based on the second GSM frame */
      s->fr.data.ptr = (char *)s->fr.data.ptr + GSM_FRAME_SIZE;
      s->fr.offset += GSM_FRAME_SIZE;
   } else {
      /* read and convert */
      unsigned char msdata[MSGSM_FRAME_SIZE];
      int res;
      
      if ((res = fread(msdata, 1, MSGSM_FRAME_SIZE, s->f)) != MSGSM_FRAME_SIZE) {
         if (res && (res != 1))
            ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
         return NULL;
      }
      /* Convert from MS format to two real GSM frames */
      conv65(msdata, s->fr.data.ptr);
   }
   fs->secondhalf = !fs->secondhalf;
   *whennext = GSM_SAMPLES;
   return &s->fr;
}
static int wav_rewrite ( struct ast_filestream s,
const char *  comment 
) [static]

Definition at line 385 of file format_wav_gsm.c.

References ast_filestream::f, and write_header().

{
   /* We don't have any header to read or anything really, but
      if we did, it would go here.  We also might want to check
      and be sure it's a valid file.  */

   if (write_header(s->f))
      return -1;
   return 0;
}
static int wav_seek ( struct ast_filestream fs,
off_t  sample_offset,
int  whence 
) [static]

Definition at line 476 of file format_wav_gsm.c.

References ast_filestream::_private, ast_log(), errno, ast_filestream::f, LOG_WARNING, MSGSM_DATA_OFFSET, MSGSM_FRAME_SIZE, MSGSM_SAMPLES, wavg_desc::secondhalf, and SEEK_FORCECUR.

{
   off_t offset=0, distance, max;
   struct wavg_desc *s = (struct wavg_desc *)fs->_private;

   off_t min = MSGSM_DATA_OFFSET;
   off_t cur = ftello(fs->f);
   fseek(fs->f, 0, SEEK_END);
   max = ftello(fs->f); /* XXX ideally, should round correctly */
   /* Compute the distance in bytes, rounded to the block size */
   distance = (sample_offset/MSGSM_SAMPLES) * MSGSM_FRAME_SIZE;
   if (whence == SEEK_SET)
      offset = distance + min;
   else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
      offset = distance + cur;
   else if (whence == SEEK_END)
      offset = max - distance;
   /* always protect against seeking past end of header */
   if (offset < min)
      offset = min;
   if (whence != SEEK_FORCECUR) {
      if (offset > max)
         offset = max;
   } else if (offset > max) {
      int i;
      fseek(fs->f, 0, SEEK_END);
      for (i=0; i< (offset - max) / MSGSM_FRAME_SIZE; i++) {
         if (!fwrite(msgsm_silence, 1, MSGSM_FRAME_SIZE, fs->f)) {
            ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
         }
      }
   }
   s->secondhalf = 0;
   return fseeko(fs->f, offset, SEEK_SET);
}
static off_t wav_tell ( struct ast_filestream fs) [static]

Definition at line 519 of file format_wav_gsm.c.

References ast_filestream::f, MSGSM_DATA_OFFSET, MSGSM_FRAME_SIZE, and MSGSM_SAMPLES.

{
   off_t offset;
   offset = ftello(fs->f);
   /* since this will most likely be used later in play or record, lets stick
    * to that level of resolution, just even frames boundaries */
   return (offset - MSGSM_DATA_OFFSET)/MSGSM_FRAME_SIZE*MSGSM_SAMPLES;
}
static int wav_trunc ( struct ast_filestream fs) [static]

Definition at line 512 of file format_wav_gsm.c.

References ast_filestream::f, and update_header().

{
   if (ftruncate(fileno(fs->f), ftello(fs->f)))
      return -1;
   return update_header(fs->f);
}
static int wav_write ( struct ast_filestream s,
struct ast_frame f 
) [static]

Definition at line 429 of file format_wav_gsm.c.

References ast_filestream::_private, AST_FORMAT_GSM, AST_FRAME_VOICE, ast_getformatname(), ast_log(), ast_filestream::buf, ast_frame_subclass::codec, conv66(), ast_frame::data, ast_frame::datalen, errno, ast_filestream::f, ast_frame::frametype, GSM_FRAME_SIZE, len(), LOG_WARNING, MSGSM_FRAME_SIZE, ast_frame::ptr, wavg_desc::secondhalf, ast_frame::subclass, and update_header().

{
   int len;
   int size;
   struct wavg_desc *fs = (struct wavg_desc *)s->_private;

   if (f->frametype != AST_FRAME_VOICE) {
      ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
      return -1;
   }
   if (f->subclass.codec != AST_FORMAT_GSM) {
      ast_log(LOG_WARNING, "Asked to write non-GSM frame (%s)!\n", ast_getformatname(f->subclass.codec));
      return -1;
   }
   /* XXX this might fail... if the input is a multiple of MSGSM_FRAME_SIZE
    * we assume it is already in the correct format.
    */
   if (!(f->datalen % MSGSM_FRAME_SIZE)) {
      size = MSGSM_FRAME_SIZE;
      fs->secondhalf = 0;
   } else {
      size = GSM_FRAME_SIZE;
   }
   for (len = 0; len < f->datalen ; len += size) {
      int res;
      unsigned char *src, msdata[MSGSM_FRAME_SIZE];
      if (fs->secondhalf) {   /* second half of raw gsm to be converted */
         memcpy(s->buf + GSM_FRAME_SIZE, f->data.ptr + len, GSM_FRAME_SIZE);
         conv66((unsigned char *) s->buf, msdata);
         src = msdata;
         fs->secondhalf = 0;
      } else if (size == GSM_FRAME_SIZE) {   /* first half of raw gsm */
         memcpy(s->buf, f->data.ptr + len, GSM_FRAME_SIZE);
         src = NULL; /* nothing to write */
         fs->secondhalf = 1;
      } else { /* raw msgsm data */
         src = f->data.ptr + len;
      }
      if (src && (res = fwrite(src, 1, MSGSM_FRAME_SIZE, s->f)) != MSGSM_FRAME_SIZE) {
         ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno));
         return -1;
      }
      update_header(s->f); /* XXX inefficient! */
   }
   return 0;
}
static int write_header ( FILE *  f) [static]

Definition at line 258 of file format_wav_gsm.c.

References ast_log(), LOG_WARNING, MSGSM_FRAME_SIZE, and MSGSM_SAMPLES.

Referenced by wav_rewrite().

{
   /* Samples per second (always 8000 for this format). */
   unsigned int sample_rate = htoll(8000);
   /* Bytes per second (always 1625 for this format). */
   unsigned int byte_sample_rate = htoll(1625);
   /* This is the size of the "fmt " subchunk */
   unsigned int fmtsize = htoll(20);
   /* WAV #49 */
   unsigned short fmt = htols(49);
   /* Mono = 1 channel */
   unsigned short chans = htols(1);
   /* Each block of data is exactly 65 bytes in size. */
   unsigned int block_align = htoll(MSGSM_FRAME_SIZE);
   /* Not actually 2, but rounded up to the nearest bit */
   unsigned short bits_per_sample = htols(2);
   /* Needed for compressed formats */
   unsigned short extra_format = htols(MSGSM_SAMPLES);
   /* This is the size of the "fact" subchunk */
   unsigned int factsize = htoll(4);
   /* Number of samples in the data chunk */
   unsigned int num_samples = htoll(0);
   /* Number of bytes in the data chunk */
   unsigned int size = htoll(0);
   /* Write a GSM header, ignoring sizes which will be filled in later */

   /*  0: Chunk ID */
   if (fwrite("RIFF", 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /*  4: Chunk Size */
   if (fwrite(&size, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /*  8: Chunk Format */
   if (fwrite("WAVE", 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 12: Subchunk 1: ID */
   if (fwrite("fmt ", 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 16: Subchunk 1: Size (minus 8) */
   if (fwrite(&fmtsize, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 20: Subchunk 1: Audio format (49) */
   if (fwrite(&fmt, 1, 2, f) != 2) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 22: Subchunk 1: Number of channels */
   if (fwrite(&chans, 1, 2, f) != 2) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 24: Subchunk 1: Sample rate */
   if (fwrite(&sample_rate, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 28: Subchunk 1: Byte rate */
   if (fwrite(&byte_sample_rate, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 32: Subchunk 1: Block align */
   if (fwrite(&block_align, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 36: Subchunk 1: Bits per sample */
   if (fwrite(&bits_per_sample, 1, 2, f) != 2) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 38: Subchunk 1: Extra format bytes */
   if (fwrite(&extra_format, 1, 2, f) != 2) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 40: Subchunk 2: ID */
   if (fwrite("fact", 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 44: Subchunk 2: Size (minus 8) */
   if (fwrite(&factsize, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 48: Subchunk 2: Number of samples */
   if (fwrite(&num_samples, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 52: Subchunk 3: ID */
   if (fwrite("data", 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   /* 56: Subchunk 3: Size */
   if (fwrite(&size, 1, 4, f) != 4) {
      ast_log(LOG_WARNING, "Unable to write header\n");
      return -1;
   }
   return 0;
}

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Microsoft WAV format (Proprietary GSM)" , .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, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND } [static]

Definition at line 559 of file format_wav_gsm.c.

Definition at line 559 of file format_wav_gsm.c.

char msgsm_silence[] [static]

Definition at line 55 of file format_wav_gsm.c.

struct ast_format wav49_f [static]

Definition at line 528 of file format_wav_gsm.c.