74c14f21c8af8bd32523f8c37d5c23d76cbdd19c
[asterisk/asterisk.git] / formats / format_wav.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
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.
13  *
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.
17  */
18
19 /*! \file
20  *
21  * \brief Work with WAV in the proprietary Microsoft format.
22  * Microsoft WAV format (8000hz Signed Linear)
23  * \arg File name extension: wav (lower case)
24  * \ingroup formats
25  */
26  
27 #include "asterisk.h"
28
29 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30
31 #include "asterisk/mod_format.h"
32 #include "asterisk/module.h"
33 #include "asterisk/endian.h"
34
35 /* Some Ideas for this code came from makewave.c by Jeffrey Chilton */
36
37 /* Portions of the conversion code are by guido@sienanet.it */
38
39 #define WAV_BUF_SIZE    320
40
41 struct wav_desc {       /* format-specific parameters */
42         int hz;
43         int bytes;
44         int lasttimeout;
45         int maxlen;
46         struct timeval last;
47 };
48
49 #define BLOCKSIZE 160
50
51 #if __BYTE_ORDER == __LITTLE_ENDIAN
52 #define htoll(b) (b)
53 #define htols(b) (b)
54 #define ltohl(b) (b)
55 #define ltohs(b) (b)
56 #else
57 #if __BYTE_ORDER == __BIG_ENDIAN
58 #define htoll(b)  \
59           (((((b)      ) & 0xFF) << 24) | \
60                ((((b) >>  8) & 0xFF) << 16) | \
61                    ((((b) >> 16) & 0xFF) <<  8) | \
62                    ((((b) >> 24) & 0xFF)      ))
63 #define htols(b) \
64           (((((b)      ) & 0xFF) << 8) | \
65                    ((((b) >> 8) & 0xFF)      ))
66 #define ltohl(b) htoll(b)
67 #define ltohs(b) htols(b)
68 #else
69 #error "Endianess not defined"
70 #endif
71 #endif
72
73
74 static int check_header(FILE *f, int hz)
75 {
76         int type, size, formtype;
77         int fmt, hsize;
78         short format, chans, bysam, bisam;
79         int bysec;
80         int freq;
81         int data;
82         if (fread(&type, 1, 4, f) != 4) {
83                 ast_log(LOG_WARNING, "Read failed (type)\n");
84                 return -1;
85         }
86         if (fread(&size, 1, 4, f) != 4) {
87                 ast_log(LOG_WARNING, "Read failed (size)\n");
88                 return -1;
89         }
90         size = ltohl(size);
91         if (fread(&formtype, 1, 4, f) != 4) {
92                 ast_log(LOG_WARNING, "Read failed (formtype)\n");
93                 return -1;
94         }
95         if (memcmp(&type, "RIFF", 4)) {
96                 ast_log(LOG_WARNING, "Does not begin with RIFF\n");
97                 return -1;
98         }
99         if (memcmp(&formtype, "WAVE", 4)) {
100                 ast_log(LOG_WARNING, "Does not contain WAVE\n");
101                 return -1;
102         }
103         if (fread(&fmt, 1, 4, f) != 4) {
104                 ast_log(LOG_WARNING, "Read failed (fmt)\n");
105                 return -1;
106         }
107         if (memcmp(&fmt, "fmt ", 4)) {
108                 ast_log(LOG_WARNING, "Does not say fmt\n");
109                 return -1;
110         }
111         if (fread(&hsize, 1, 4, f) != 4) {
112                 ast_log(LOG_WARNING, "Read failed (formtype)\n");
113                 return -1;
114         }
115         if (ltohl(hsize) < 16) {
116                 ast_log(LOG_WARNING, "Unexpected header size %d\n", ltohl(hsize));
117                 return -1;
118         }
119         if (fread(&format, 1, 2, f) != 2) {
120                 ast_log(LOG_WARNING, "Read failed (format)\n");
121                 return -1;
122         }
123         if (ltohs(format) != 1) {
124                 ast_log(LOG_WARNING, "Not a wav file %d\n", ltohs(format));
125                 return -1;
126         }
127         if (fread(&chans, 1, 2, f) != 2) {
128                 ast_log(LOG_WARNING, "Read failed (format)\n");
129                 return -1;
130         }
131         if (ltohs(chans) != 1) {
132                 ast_log(LOG_WARNING, "Not in mono %d\n", ltohs(chans));
133                 return -1;
134         }
135         if (fread(&freq, 1, 4, f) != 4) {
136                 ast_log(LOG_WARNING, "Read failed (freq)\n");
137                 return -1;
138         }
139         if (((ltohl(freq) != 8000) && (ltohl(freq) != 16000)) ||
140             ((ltohl(freq) == 8000) && (hz != 8000)) ||
141             ((ltohl(freq) == 16000) && (hz != 16000))) {
142                 ast_log(LOG_WARNING, "Unexpected frequency mismatch %d (expecting %d)\n", ltohl(freq),hz);
143                 return -1;
144         }
145         /* Ignore the byte frequency */
146         if (fread(&bysec, 1, 4, f) != 4) {
147                 ast_log(LOG_WARNING, "Read failed (BYTES_PER_SECOND)\n");
148                 return -1;
149         }
150         /* Check bytes per sample */
151         if (fread(&bysam, 1, 2, f) != 2) {
152                 ast_log(LOG_WARNING, "Read failed (BYTES_PER_SAMPLE)\n");
153                 return -1;
154         }
155         if (ltohs(bysam) != 2) {
156                 ast_log(LOG_WARNING, "Can only handle 16bits per sample: %d\n", ltohs(bysam));
157                 return -1;
158         }
159         if (fread(&bisam, 1, 2, f) != 2) {
160                 ast_log(LOG_WARNING, "Read failed (Bits Per Sample): %d\n", ltohs(bisam));
161                 return -1;
162         }
163         /* Skip any additional header */
164         if (fseek(f,ltohl(hsize)-16,SEEK_CUR) == -1 ) {
165                 ast_log(LOG_WARNING, "Failed to skip remaining header bytes: %d\n", ltohl(hsize)-16 );
166                 return -1;
167         }
168         /* Skip any facts and get the first data block */
169         for(;;)
170         { 
171                 char buf[4];
172             
173             /* Begin data chunk */
174             if (fread(&buf, 1, 4, f) != 4) {
175                         ast_log(LOG_WARNING, "Read failed (data)\n");
176                         return -1;
177             }
178             /* Data has the actual length of data in it */
179             if (fread(&data, 1, 4, f) != 4) {
180                         ast_log(LOG_WARNING, "Read failed (data)\n");
181                         return -1;
182             }
183             data = ltohl(data);
184             if(memcmp(buf, "data", 4) == 0 ) 
185                         break;
186             if(memcmp(buf, "fact", 4) != 0 ) {
187                         ast_log(LOG_WARNING, "Unknown block - not fact or data\n");
188                         return -1;
189             }
190             if (fseek(f,data,SEEK_CUR) == -1 ) {
191                         ast_log(LOG_WARNING, "Failed to skip fact block: %d\n", data );
192                         return -1;
193             }
194         }
195 #if 0
196         curpos = lseek(fd, 0, SEEK_CUR);
197         truelength = lseek(fd, 0, SEEK_END);
198         lseek(fd, curpos, SEEK_SET);
199         truelength -= curpos;
200 #endif  
201         return data;
202 }
203
204 static int update_header(FILE *f)
205 {
206         off_t cur,end;
207         int datalen,filelen,bytes;
208         
209         cur = ftello(f);
210         fseek(f, 0, SEEK_END);
211         end = ftello(f);
212         /* data starts 44 bytes in */
213         bytes = end - 44;
214         datalen = htoll(bytes);
215         /* chunk size is bytes of data plus 36 bytes of header */
216         filelen = htoll(36 + bytes);
217         
218         if (cur < 0) {
219                 ast_log(LOG_WARNING, "Unable to find our position\n");
220                 return -1;
221         }
222         if (fseek(f, 4, SEEK_SET)) {
223                 ast_log(LOG_WARNING, "Unable to set our position\n");
224                 return -1;
225         }
226         if (fwrite(&filelen, 1, 4, f) != 4) {
227                 ast_log(LOG_WARNING, "Unable to set write file size\n");
228                 return -1;
229         }
230         if (fseek(f, 40, SEEK_SET)) {
231                 ast_log(LOG_WARNING, "Unable to set our position\n");
232                 return -1;
233         }
234         if (fwrite(&datalen, 1, 4, f) != 4) {
235                 ast_log(LOG_WARNING, "Unable to set write datalen\n");
236                 return -1;
237         }
238         if (fseeko(f, cur, SEEK_SET)) {
239                 ast_log(LOG_WARNING, "Unable to return to position\n");
240                 return -1;
241         }
242         return 0;
243 }
244
245 static int write_header(FILE *f, int writehz)
246 {
247         unsigned int hz;
248         unsigned int bhz;
249         unsigned int hs = htoll(16);
250         unsigned short fmt = htols(1);
251         unsigned short chans = htols(1);
252         unsigned short bysam = htols(2);
253         unsigned short bisam = htols(16);
254         unsigned int size = htoll(0);
255
256         if (writehz == 16000) {
257                 hz = htoll(16000);
258                 bhz = htoll(32000);
259         } else {
260                 hz = htoll(8000);
261                 bhz = htoll(16000);
262         }
263         /* Write a wav header, ignoring sizes which will be filled in later */
264         fseek(f,0,SEEK_SET);
265         if (fwrite("RIFF", 1, 4, f) != 4) {
266                 ast_log(LOG_WARNING, "Unable to write header\n");
267                 return -1;
268         }
269         if (fwrite(&size, 1, 4, f) != 4) {
270                 ast_log(LOG_WARNING, "Unable to write header\n");
271                 return -1;
272         }
273         if (fwrite("WAVEfmt ", 1, 8, f) != 8) {
274                 ast_log(LOG_WARNING, "Unable to write header\n");
275                 return -1;
276         }
277         if (fwrite(&hs, 1, 4, f) != 4) {
278                 ast_log(LOG_WARNING, "Unable to write header\n");
279                 return -1;
280         }
281         if (fwrite(&fmt, 1, 2, f) != 2) {
282                 ast_log(LOG_WARNING, "Unable to write header\n");
283                 return -1;
284         }
285         if (fwrite(&chans, 1, 2, f) != 2) {
286                 ast_log(LOG_WARNING, "Unable to write header\n");
287                 return -1;
288         }
289         if (fwrite(&hz, 1, 4, f) != 4) {
290                 ast_log(LOG_WARNING, "Unable to write header\n");
291                 return -1;
292         }
293         if (fwrite(&bhz, 1, 4, f) != 4) {
294                 ast_log(LOG_WARNING, "Unable to write header\n");
295                 return -1;
296         }
297         if (fwrite(&bysam, 1, 2, f) != 2) {
298                 ast_log(LOG_WARNING, "Unable to write header\n");
299                 return -1;
300         }
301         if (fwrite(&bisam, 1, 2, f) != 2) {
302                 ast_log(LOG_WARNING, "Unable to write header\n");
303                 return -1;
304         }
305         if (fwrite("data", 1, 4, f) != 4) {
306                 ast_log(LOG_WARNING, "Unable to write header\n");
307                 return -1;
308         }
309         if (fwrite(&size, 1, 4, f) != 4) {
310                 ast_log(LOG_WARNING, "Unable to write header\n");
311                 return -1;
312         }
313         return 0;
314 }
315
316 static int wav_open(struct ast_filestream *s)
317 {
318         /* We don't have any header to read or anything really, but
319            if we did, it would go here.  We also might want to check
320            and be sure it's a valid file.  */
321         struct wav_desc *tmp = (struct wav_desc *)s->_private;
322         if ((tmp->maxlen = check_header(s->f, (s->fmt->format.id == AST_FORMAT_SLINEAR16 ? 16000 : 8000))) < 0)
323                 return -1;
324         return 0;
325 }
326
327 static int wav_rewrite(struct ast_filestream *s, const char *comment)
328 {
329         /* We don't have any header to read or anything really, but
330            if we did, it would go here.  We also might want to check
331            and be sure it's a valid file.  */
332
333         struct wav_desc *tmp = (struct wav_desc *)s->_private;
334         tmp->hz = (s->fmt->format.id == AST_FORMAT_SLINEAR16 ? 16000 : 8000);
335         if (write_header(s->f,tmp->hz))
336                 return -1;
337         return 0;
338 }
339
340 static void wav_close(struct ast_filestream *s)
341 {
342         char zero = 0;
343         struct wav_desc *fs = (struct wav_desc *)s->_private;
344
345         if (s->filename) {
346                 update_header(s->f);
347         }
348
349         /* Pad to even length */
350         if (fs->bytes & 0x1) {
351                 if (!fwrite(&zero, 1, 1, s->f)) {
352                         ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
353                 }
354         }
355 }
356
357 static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext)
358 {
359         int res;
360         int samples;    /* actual samples read */
361 #if __BYTE_ORDER == __BIG_ENDIAN
362         int x;
363 #endif
364         short *tmp;
365         int bytes;
366         off_t here;
367         /* Send a frame from the file to the appropriate channel */
368         struct wav_desc *fs = (struct wav_desc *)s->_private;
369
370         bytes = (fs->hz == 16000 ? (WAV_BUF_SIZE * 2) : WAV_BUF_SIZE);
371
372         here = ftello(s->f);
373         if (fs->maxlen - here < bytes)          /* truncate if necessary */
374                 bytes = fs->maxlen - here;
375         if (bytes < 0)
376                 bytes = 0;
377 /*      ast_debug(1, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */
378         s->fr.frametype = AST_FRAME_VOICE;
379         ast_format_set(&s->fr.subclass.format, (fs->hz == 16000 ? AST_FORMAT_SLINEAR16 : AST_FORMAT_SLINEAR), 0);
380         s->fr.mallocd = 0;
381         AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, bytes);
382         
383         if ( (res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) <= 0 ) {
384                 if (res)
385                         ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
386                 return NULL;
387         }
388         s->fr.datalen = res;
389         s->fr.samples = samples = res / 2;
390
391         tmp = (short *)(s->fr.data.ptr);
392 #if __BYTE_ORDER == __BIG_ENDIAN
393         /* file format is little endian so we need to swap */
394         for( x = 0; x < samples; x++)
395                 tmp[x] = (tmp[x] << 8) | ((tmp[x] & 0xff00) >> 8);
396 #endif
397
398         *whennext = samples;
399         return &s->fr;
400 }
401
402 static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
403 {
404 #if __BYTE_ORDER == __BIG_ENDIAN
405         int x;
406         short tmp[16000], *tmpi;
407 #endif
408         struct wav_desc *s = (struct wav_desc *)fs->_private;
409         int res;
410
411         if (f->frametype != AST_FRAME_VOICE) {
412                 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
413                 return -1;
414         }
415         if ((f->subclass.format.id != AST_FORMAT_SLINEAR) && (f->subclass.format.id != AST_FORMAT_SLINEAR16)) {
416                 ast_log(LOG_WARNING, "Asked to write non-SLINEAR%s frame (%s)!\n", s->hz == 16000 ? "16" : "", ast_getformatname(&f->subclass.format));
417                 return -1;
418         }
419         if (ast_format_cmp(&f->subclass.format, &fs->fmt->format) == AST_FORMAT_CMP_NOT_EQUAL) {
420                 ast_log(LOG_WARNING, "Can't change SLINEAR frequency during write\n");
421                 return -1;
422         }
423         if (!f->datalen)
424                 return -1;
425
426 #if __BYTE_ORDER == __BIG_ENDIAN
427         /* swap and write */
428         if (f->datalen > sizeof(tmp)) {
429                 ast_log(LOG_WARNING, "Data length is too long\n");
430                 return -1;
431         }
432         tmpi = f->data.ptr;
433         for (x=0; x < f->datalen/2; x++) 
434                 tmp[x] = (tmpi[x] << 8) | ((tmpi[x] & 0xff00) >> 8);
435
436         if ((res = fwrite(tmp, 1, f->datalen, fs->f)) != f->datalen ) {
437 #else
438         /* just write */
439         if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen ) {
440 #endif
441                 ast_log(LOG_WARNING, "Bad write (%d): %s\n", res, strerror(errno));
442                 return -1;
443         }
444
445         s->bytes += f->datalen;
446                 
447         return 0;
448
449 }
450
451 static int wav_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
452 {
453         off_t min, max, cur, offset = 0, samples;
454
455         samples = sample_offset * 2; /* SLINEAR is 16 bits mono, so sample_offset * 2 = bytes */
456         min = 44; /* wav header is 44 bytes */
457         cur = ftello(fs->f);
458         fseeko(fs->f, 0, SEEK_END);
459         max = ftello(fs->f);
460         if (whence == SEEK_SET)
461                 offset = samples + min;
462         else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
463                 offset = samples + cur;
464         else if (whence == SEEK_END)
465                 offset = max - samples;
466         if (whence != SEEK_FORCECUR) {
467                 offset = (offset > max)?max:offset;
468         }
469         /* always protect the header space. */
470         offset = (offset < min)?min:offset;
471         return fseeko(fs->f, offset, SEEK_SET);
472 }
473
474 static int wav_trunc(struct ast_filestream *fs)
475 {
476         if (ftruncate(fileno(fs->f), ftello(fs->f)))
477                 return -1;
478         return update_header(fs->f);
479 }
480
481 static off_t wav_tell(struct ast_filestream *fs)
482 {
483         off_t offset;
484         offset = ftello(fs->f);
485         /* subtract header size to get samples, then divide by 2 for 16 bit samples */
486         return (offset - 44)/2;
487 }
488
489 static struct ast_format_def wav16_f = {
490         .name = "wav16",
491         .exts = "wav16",
492         .open = wav_open,
493         .rewrite = wav_rewrite,
494         .write = wav_write,
495         .seek = wav_seek,
496         .trunc = wav_trunc,
497         .tell = wav_tell,
498         .read = wav_read,
499         .close = wav_close,
500         .buf_size = (WAV_BUF_SIZE * 2) + AST_FRIENDLY_OFFSET,
501         .desc_size = sizeof(struct wav_desc),
502 };
503
504 static struct ast_format_def wav_f = {
505         .name = "wav",
506         .exts = "wav",
507         .open = wav_open,
508         .rewrite = wav_rewrite,
509         .write = wav_write,
510         .seek = wav_seek,
511         .trunc = wav_trunc,
512         .tell = wav_tell,
513         .read = wav_read,
514         .close = wav_close,
515         .buf_size = WAV_BUF_SIZE + AST_FRIENDLY_OFFSET,
516         .desc_size = sizeof(struct wav_desc),
517 };
518
519 static int load_module(void)
520 {
521         ast_format_set(&wav_f.format, AST_FORMAT_SLINEAR, 0);
522         ast_format_set(&wav16_f.format, AST_FORMAT_SLINEAR16, 0);
523         if (ast_format_def_register(&wav_f)
524                 || ast_format_def_register(&wav16_f))
525                 return AST_MODULE_LOAD_FAILURE;
526         return AST_MODULE_LOAD_SUCCESS;
527 }
528
529 static int unload_module(void)
530 {
531         return ast_format_def_unregister(wav_f.name)
532                 || ast_format_def_unregister(wav16_f.name);
533 }
534
535 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Microsoft WAV/WAV16 format (8kHz/16kHz Signed Linear)",
536         .load = load_module,
537         .unload = unload_module,
538         .load_pri = AST_MODPRI_APP_DEPEND
539 );