Merge another change from team/russell/events ...
[asterisk-bristuff.git] / formats / format_wav_gsm.c
blob4c3694cda0006bf1a2d087c4dee8404462bf9951
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 /*! \file
21 * \brief Save GSM in the proprietary Microsoft format.
23 * Microsoft WAV format (Proprietary GSM)
24 * \arg File name extension: WAV,wav49 (Upper case WAV, lower case is another format)
25 * This format can be played on Windows systems, used for
26 * e-mail attachments mainly.
27 * \ingroup formats
30 #include "asterisk.h"
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34 #include "asterisk/mod_format.h"
35 #include "asterisk/module.h"
36 #include "asterisk/endian.h"
38 #include "msgsm.h"
40 /* Some Ideas for this code came from makewave.c by Jeffrey Chilton */
42 /* Portions of the conversion code are by guido@sienanet.it */
44 #define GSM_FRAME_SIZE 33
45 #define MSGSM_FRAME_SIZE 65
46 #define MSGSM_DATA_OFFSET 60 /* offset of data bytes */
47 #define GSM_SAMPLES 160 /* samples in a GSM block */
48 #define MSGSM_SAMPLES (2*GSM_SAMPLES) /* samples in an MSGSM block */
50 /* begin binary data: */
51 char msgsm_silence[] = /* 65 */
52 {0x48,0x17,0xD6,0x84,0x02,0x80,0x24,0x49,0x92,0x24,0x89,0x02,0x80,0x24,0x49
53 ,0x92,0x24,0x89,0x02,0x80,0x24,0x49,0x92,0x24,0x89,0x02,0x80,0x24,0x49,0x92
54 ,0x24,0x09,0x82,0x74,0x61,0x4D,0x28,0x00,0x48,0x92,0x24,0x49,0x92,0x28,0x00
55 ,0x48,0x92,0x24,0x49,0x92,0x28,0x00,0x48,0x92,0x24,0x49,0x92,0x28,0x00,0x48
56 ,0x92,0x24,0x49,0x92,0x00};
57 /* end binary data. size = 65 bytes */
59 struct wavg_desc {
60 /* Believe it or not, we must decode/recode to account for the
61 weird MS format */
62 int secondhalf; /* Are we on the second half */
65 #if __BYTE_ORDER == __LITTLE_ENDIAN
66 #define htoll(b) (b)
67 #define htols(b) (b)
68 #define ltohl(b) (b)
69 #define ltohs(b) (b)
70 #else
71 #if __BYTE_ORDER == __BIG_ENDIAN
72 #define htoll(b) \
73 (((((b) ) & 0xFF) << 24) | \
74 ((((b) >> 8) & 0xFF) << 16) | \
75 ((((b) >> 16) & 0xFF) << 8) | \
76 ((((b) >> 24) & 0xFF) ))
77 #define htols(b) \
78 (((((b) ) & 0xFF) << 8) | \
79 ((((b) >> 8) & 0xFF) ))
80 #define ltohl(b) htoll(b)
81 #define ltohs(b) htols(b)
82 #else
83 #error "Endianess not defined"
84 #endif
85 #endif
88 static int check_header(FILE *f)
90 int type, size, formtype;
91 int fmt, hsize, fact;
92 short format, chans;
93 int freq;
94 int data;
95 if (fread(&type, 1, 4, f) != 4) {
96 ast_log(LOG_WARNING, "Read failed (type)\n");
97 return -1;
99 if (fread(&size, 1, 4, f) != 4) {
100 ast_log(LOG_WARNING, "Read failed (size)\n");
101 return -1;
103 size = ltohl(size);
104 if (fread(&formtype, 1, 4, f) != 4) {
105 ast_log(LOG_WARNING, "Read failed (formtype)\n");
106 return -1;
108 if (memcmp(&type, "RIFF", 4)) {
109 ast_log(LOG_WARNING, "Does not begin with RIFF\n");
110 return -1;
112 if (memcmp(&formtype, "WAVE", 4)) {
113 ast_log(LOG_WARNING, "Does not contain WAVE\n");
114 return -1;
116 if (fread(&fmt, 1, 4, f) != 4) {
117 ast_log(LOG_WARNING, "Read failed (fmt)\n");
118 return -1;
120 if (memcmp(&fmt, "fmt ", 4)) {
121 ast_log(LOG_WARNING, "Does not say fmt\n");
122 return -1;
124 if (fread(&hsize, 1, 4, f) != 4) {
125 ast_log(LOG_WARNING, "Read failed (formtype)\n");
126 return -1;
128 if (ltohl(hsize) != 20) {
129 ast_log(LOG_WARNING, "Unexpected header size %d\n", ltohl(hsize));
130 return -1;
132 if (fread(&format, 1, 2, f) != 2) {
133 ast_log(LOG_WARNING, "Read failed (format)\n");
134 return -1;
136 if (ltohs(format) != 49) {
137 ast_log(LOG_WARNING, "Not a GSM file %d\n", ltohs(format));
138 return -1;
140 if (fread(&chans, 1, 2, f) != 2) {
141 ast_log(LOG_WARNING, "Read failed (format)\n");
142 return -1;
144 if (ltohs(chans) != 1) {
145 ast_log(LOG_WARNING, "Not in mono %d\n", ltohs(chans));
146 return -1;
148 if (fread(&freq, 1, 4, f) != 4) {
149 ast_log(LOG_WARNING, "Read failed (freq)\n");
150 return -1;
152 if (ltohl(freq) != DEFAULT_SAMPLE_RATE) {
153 ast_log(LOG_WARNING, "Unexpected freqency %d\n", ltohl(freq));
154 return -1;
156 /* Ignore the byte frequency */
157 if (fread(&freq, 1, 4, f) != 4) {
158 ast_log(LOG_WARNING, "Read failed (X_1)\n");
159 return -1;
161 /* Ignore the two weird fields */
162 if (fread(&freq, 1, 4, f) != 4) {
163 ast_log(LOG_WARNING, "Read failed (X_2/X_3)\n");
164 return -1;
166 /* Ignore the byte frequency */
167 if (fread(&freq, 1, 4, f) != 4) {
168 ast_log(LOG_WARNING, "Read failed (Y_1)\n");
169 return -1;
171 /* Check for the word fact */
172 if (fread(&fact, 1, 4, f) != 4) {
173 ast_log(LOG_WARNING, "Read failed (fact)\n");
174 return -1;
176 if (memcmp(&fact, "fact", 4)) {
177 ast_log(LOG_WARNING, "Does not say fact\n");
178 return -1;
180 /* Ignore the "fact value" */
181 if (fread(&fact, 1, 4, f) != 4) {
182 ast_log(LOG_WARNING, "Read failed (fact header)\n");
183 return -1;
185 if (fread(&fact, 1, 4, f) != 4) {
186 ast_log(LOG_WARNING, "Read failed (fact value)\n");
187 return -1;
189 /* Check for the word data */
190 if (fread(&data, 1, 4, f) != 4) {
191 ast_log(LOG_WARNING, "Read failed (data)\n");
192 return -1;
194 if (memcmp(&data, "data", 4)) {
195 ast_log(LOG_WARNING, "Does not say data\n");
196 return -1;
198 /* Ignore the data length */
199 if (fread(&data, 1, 4, f) != 4) {
200 ast_log(LOG_WARNING, "Read failed (data)\n");
201 return -1;
203 return 0;
206 static int update_header(FILE *f)
208 off_t cur,end,bytes;
209 int datalen, filelen, samples;
211 cur = ftello(f);
212 fseek(f, 0, SEEK_END);
213 end = ftello(f);
214 /* in a gsm WAV, data starts 60 bytes in */
215 bytes = end - MSGSM_DATA_OFFSET;
216 samples = htoll(bytes / MSGSM_FRAME_SIZE * MSGSM_SAMPLES);
217 datalen = htoll(bytes);
218 filelen = htoll(MSGSM_DATA_OFFSET - 8 + bytes);
219 if (cur < 0) {
220 ast_log(LOG_WARNING, "Unable to find our position\n");
221 return -1;
223 if (fseek(f, 4, SEEK_SET)) {
224 ast_log(LOG_WARNING, "Unable to set our position\n");
225 return -1;
227 if (fwrite(&filelen, 1, 4, f) != 4) {
228 ast_log(LOG_WARNING, "Unable to write file size\n");
229 return -1;
231 if (fseek(f, 48, SEEK_SET)) {
232 ast_log(LOG_WARNING, "Unable to set our position\n");
233 return -1;
235 if (fwrite(&samples, 1, 4, f) != 4) {
236 ast_log(LOG_WARNING, "Unable to write samples\n");
237 return -1;
239 if (fseek(f, 56, SEEK_SET)) {
240 ast_log(LOG_WARNING, "Unable to set our position\n");
241 return -1;
243 if (fwrite(&datalen, 1, 4, f) != 4) {
244 ast_log(LOG_WARNING, "Unable to write datalen\n");
245 return -1;
247 if (fseeko(f, cur, SEEK_SET)) {
248 ast_log(LOG_WARNING, "Unable to return to position\n");
249 return -1;
251 return 0;
254 static int write_header(FILE *f)
256 /* Samples per second (always 8000 for this format). */
257 unsigned int sample_rate = htoll(8000);
258 /* Bytes per second (always 1625 for this format). */
259 unsigned int byte_sample_rate = htoll(1625);
260 /* This is the size of the "fmt " subchunk */
261 unsigned int fmtsize = htoll(20);
262 /* WAV #49 */
263 unsigned short fmt = htols(49);
264 /* Mono = 1 channel */
265 unsigned short chans = htols(1);
266 /* Each block of data is exactly 65 bytes in size. */
267 unsigned int block_align = htoll(MSGSM_FRAME_SIZE);
268 /* Not actually 2, but rounded up to the nearest bit */
269 unsigned short bits_per_sample = htols(2);
270 /* Needed for compressed formats */
271 unsigned short extra_format = htols(MSGSM_SAMPLES);
272 /* This is the size of the "fact" subchunk */
273 unsigned int factsize = htoll(4);
274 /* Number of samples in the data chunk */
275 unsigned int num_samples = htoll(0);
276 /* Number of bytes in the data chunk */
277 unsigned int size = htoll(0);
278 /* Write a GSM header, ignoring sizes which will be filled in later */
280 /* 0: Chunk ID */
281 if (fwrite("RIFF", 1, 4, f) != 4) {
282 ast_log(LOG_WARNING, "Unable to write header\n");
283 return -1;
285 /* 4: Chunk Size */
286 if (fwrite(&size, 1, 4, f) != 4) {
287 ast_log(LOG_WARNING, "Unable to write header\n");
288 return -1;
290 /* 8: Chunk Format */
291 if (fwrite("WAVE", 1, 4, f) != 4) {
292 ast_log(LOG_WARNING, "Unable to write header\n");
293 return -1;
295 /* 12: Subchunk 1: ID */
296 if (fwrite("fmt ", 1, 4, f) != 4) {
297 ast_log(LOG_WARNING, "Unable to write header\n");
298 return -1;
300 /* 16: Subchunk 1: Size (minus 8) */
301 if (fwrite(&fmtsize, 1, 4, f) != 4) {
302 ast_log(LOG_WARNING, "Unable to write header\n");
303 return -1;
305 /* 20: Subchunk 1: Audio format (49) */
306 if (fwrite(&fmt, 1, 2, f) != 2) {
307 ast_log(LOG_WARNING, "Unable to write header\n");
308 return -1;
310 /* 22: Subchunk 1: Number of channels */
311 if (fwrite(&chans, 1, 2, f) != 2) {
312 ast_log(LOG_WARNING, "Unable to write header\n");
313 return -1;
315 /* 24: Subchunk 1: Sample rate */
316 if (fwrite(&sample_rate, 1, 4, f) != 4) {
317 ast_log(LOG_WARNING, "Unable to write header\n");
318 return -1;
320 /* 28: Subchunk 1: Byte rate */
321 if (fwrite(&byte_sample_rate, 1, 4, f) != 4) {
322 ast_log(LOG_WARNING, "Unable to write header\n");
323 return -1;
325 /* 32: Subchunk 1: Block align */
326 if (fwrite(&block_align, 1, 4, f) != 4) {
327 ast_log(LOG_WARNING, "Unable to write header\n");
328 return -1;
330 /* 36: Subchunk 1: Bits per sample */
331 if (fwrite(&bits_per_sample, 1, 2, f) != 2) {
332 ast_log(LOG_WARNING, "Unable to write header\n");
333 return -1;
335 /* 38: Subchunk 1: Extra format bytes */
336 if (fwrite(&extra_format, 1, 2, f) != 2) {
337 ast_log(LOG_WARNING, "Unable to write header\n");
338 return -1;
340 /* 40: Subchunk 2: ID */
341 if (fwrite("fact", 1, 4, f) != 4) {
342 ast_log(LOG_WARNING, "Unable to write header\n");
343 return -1;
345 /* 44: Subchunk 2: Size (minus 8) */
346 if (fwrite(&factsize, 1, 4, f) != 4) {
347 ast_log(LOG_WARNING, "Unable to write header\n");
348 return -1;
350 /* 48: Subchunk 2: Number of samples */
351 if (fwrite(&num_samples, 1, 4, f) != 4) {
352 ast_log(LOG_WARNING, "Unable to write header\n");
353 return -1;
355 /* 52: Subchunk 3: ID */
356 if (fwrite("data", 1, 4, f) != 4) {
357 ast_log(LOG_WARNING, "Unable to write header\n");
358 return -1;
360 /* 56: Subchunk 3: Size */
361 if (fwrite(&size, 1, 4, f) != 4) {
362 ast_log(LOG_WARNING, "Unable to write header\n");
363 return -1;
365 return 0;
368 static int wav_open(struct ast_filestream *s)
370 /* We don't have any header to read or anything really, but
371 if we did, it would go here. We also might want to check
372 and be sure it's a valid file. */
373 struct wavg_desc *fs = (struct wavg_desc *)s->_private;
375 if (check_header(s->f))
376 return -1;
377 fs->secondhalf = 0; /* not strictly necessary */
378 return 0;
381 static int wav_rewrite(struct ast_filestream *s, const char *comment)
383 /* We don't have any header to read or anything really, but
384 if we did, it would go here. We also might want to check
385 and be sure it's a valid file. */
387 if (write_header(s->f))
388 return -1;
389 return 0;
392 static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext)
394 /* Send a frame from the file to the appropriate channel */
395 struct wavg_desc *fs = (struct wavg_desc *)s->_private;
397 s->fr.frametype = AST_FRAME_VOICE;
398 s->fr.subclass = AST_FORMAT_GSM;
399 s->fr.offset = AST_FRIENDLY_OFFSET;
400 s->fr.samples = GSM_SAMPLES;
401 s->fr.mallocd = 0;
402 AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, GSM_FRAME_SIZE);
403 if (fs->secondhalf) {
404 /* Just return a frame based on the second GSM frame */
405 s->fr.data.ptr = (char *)s->fr.data.ptr + GSM_FRAME_SIZE;
406 s->fr.offset += GSM_FRAME_SIZE;
407 } else {
408 /* read and convert */
409 unsigned char msdata[MSGSM_FRAME_SIZE];
410 int res;
412 if ((res = fread(msdata, 1, MSGSM_FRAME_SIZE, s->f)) != MSGSM_FRAME_SIZE) {
413 if (res && (res != 1))
414 ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
415 return NULL;
417 /* Convert from MS format to two real GSM frames */
418 conv65(msdata, s->fr.data.ptr);
420 fs->secondhalf = !fs->secondhalf;
421 *whennext = GSM_SAMPLES;
422 return &s->fr;
425 static int wav_write(struct ast_filestream *s, struct ast_frame *f)
427 int len;
428 int size;
429 struct wavg_desc *fs = (struct wavg_desc *)s->_private;
431 if (f->frametype != AST_FRAME_VOICE) {
432 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
433 return -1;
435 if (f->subclass != AST_FORMAT_GSM) {
436 ast_log(LOG_WARNING, "Asked to write non-GSM frame (%d)!\n", f->subclass);
437 return -1;
439 /* XXX this might fail... if the input is a multiple of MSGSM_FRAME_SIZE
440 * we assume it is already in the correct format.
442 if (!(f->datalen % MSGSM_FRAME_SIZE)) {
443 size = MSGSM_FRAME_SIZE;
444 fs->secondhalf = 0;
445 } else {
446 size = GSM_FRAME_SIZE;
448 for (len = 0; len < f->datalen ; len += size) {
449 int res;
450 unsigned char *src, msdata[MSGSM_FRAME_SIZE];
451 if (fs->secondhalf) { /* second half of raw gsm to be converted */
452 memcpy(s->buf + GSM_FRAME_SIZE, f->data.ptr + len, GSM_FRAME_SIZE);
453 conv66((unsigned char *) s->buf, msdata);
454 src = msdata;
455 fs->secondhalf = 0;
456 } else if (size == GSM_FRAME_SIZE) { /* first half of raw gsm */
457 memcpy(s->buf, f->data.ptr + len, GSM_FRAME_SIZE);
458 src = NULL; /* nothing to write */
459 fs->secondhalf = 1;
460 } else { /* raw msgsm data */
461 src = f->data.ptr + len;
463 if (src && (res = fwrite(src, 1, MSGSM_FRAME_SIZE, s->f)) != MSGSM_FRAME_SIZE) {
464 ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno));
465 return -1;
467 update_header(s->f); /* XXX inefficient! */
469 return 0;
472 static int wav_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
474 off_t offset=0, distance, max;
475 struct wavg_desc *s = (struct wavg_desc *)fs->_private;
477 off_t min = MSGSM_DATA_OFFSET;
478 off_t cur = ftello(fs->f);
479 fseek(fs->f, 0, SEEK_END);
480 max = ftello(fs->f); /* XXX ideally, should round correctly */
481 /* Compute the distance in bytes, rounded to the block size */
482 distance = (sample_offset/MSGSM_SAMPLES) * MSGSM_FRAME_SIZE;
483 if (whence == SEEK_SET)
484 offset = distance + min;
485 else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
486 offset = distance + cur;
487 else if (whence == SEEK_END)
488 offset = max - distance;
489 /* always protect against seeking past end of header */
490 if (offset < min)
491 offset = min;
492 if (whence != SEEK_FORCECUR) {
493 if (offset > max)
494 offset = max;
495 } else if (offset > max) {
496 int i;
497 fseek(fs->f, 0, SEEK_END);
498 for (i=0; i< (offset - max) / MSGSM_FRAME_SIZE; i++) {
499 fwrite(msgsm_silence, 1, MSGSM_FRAME_SIZE, fs->f);
502 s->secondhalf = 0;
503 return fseeko(fs->f, offset, SEEK_SET);
506 static int wav_trunc(struct ast_filestream *fs)
508 if (ftruncate(fileno(fs->f), ftello(fs->f)))
509 return -1;
510 return update_header(fs->f);
513 static off_t wav_tell(struct ast_filestream *fs)
515 off_t offset;
516 offset = ftello(fs->f);
517 /* since this will most likely be used later in play or record, lets stick
518 * to that level of resolution, just even frames boundaries */
519 return (offset - MSGSM_DATA_OFFSET)/MSGSM_FRAME_SIZE*MSGSM_SAMPLES;
522 static const struct ast_format wav49_f = {
523 .name = "wav49",
524 .exts = "WAV|wav49",
525 .format = AST_FORMAT_GSM,
526 .open = wav_open,
527 .rewrite = wav_rewrite,
528 .write = wav_write,
529 .seek = wav_seek,
530 .trunc = wav_trunc,
531 .tell = wav_tell,
532 .read = wav_read,
533 .buf_size = 2*GSM_FRAME_SIZE + AST_FRIENDLY_OFFSET,
534 .desc_size = sizeof(struct wavg_desc),
537 static int load_module(void)
539 if (ast_format_register(&wav49_f))
540 return AST_MODULE_LOAD_FAILURE;
541 return AST_MODULE_LOAD_SUCCESS;
544 static int unload_module(void)
546 return ast_format_unregister(wav49_f.name);
549 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Microsoft WAV format (Proprietary GSM)");