BSD portability enhancements (bug #234)
[asterisk/asterisk.git] / formats / format_wav.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Work with WAV in the proprietary Microsoft format.
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13  
14 #include <asterisk/lock.h>
15 #include <asterisk/channel.h>
16 #include <asterisk/file.h>
17 #include <asterisk/logger.h>
18 #include <asterisk/sched.h>
19 #include <asterisk/module.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <stdlib.h>
23 #include <sys/time.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <pthread.h>
29 #ifdef __linux__
30 #include <endian.h>
31 #else
32 #include <machine/endian.h>
33 #endif
34
35 /* Some Ideas for this code came from makewave.c by Jeffery Chilton */
36
37 /* Portions of the conversion code are by guido@sienanet.it */
38
39 struct ast_filestream {
40         void *reserved[AST_RESERVED_POINTERS];
41         /* This is what a filestream means to us */
42         int fd; /* Descriptor */
43         int bytes;
44         int needsgain;
45         struct ast_frame fr;                            /* Frame information */
46         char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
47         char empty;                                                     /* Empty character */
48         short buf[160]; 
49         int foffset;
50         int lasttimeout;
51         int maxlen;
52         struct timeval last;
53 };
54
55
56 static ast_mutex_t wav_lock = AST_MUTEX_INITIALIZER;
57 static int glistcnt = 0;
58
59 static char *name = "wav";
60 static char *desc = "Microsoft WAV format (8000hz Signed Linear)";
61 static char *exts = "wav";
62
63 #define BLOCKSIZE 160
64
65 #define GAIN 2          /* 2^GAIN is the multiple to increase the volume by */
66
67 #if __BYTE_ORDER == __LITTLE_ENDIAN
68 #define htoll(b) (b)
69 #define htols(b) (b)
70 #define ltohl(b) (b)
71 #define ltohs(b) (b)
72 #else
73 #if __BYTE_ORDER == __BIG_ENDIAN
74 #define htoll(b)  \
75           (((((b)      ) & 0xFF) << 24) | \
76                ((((b) >>  8) & 0xFF) << 16) | \
77                    ((((b) >> 16) & 0xFF) <<  8) | \
78                    ((((b) >> 24) & 0xFF)      ))
79 #define htols(b) \
80           (((((b)      ) & 0xFF) << 8) | \
81                    ((((b) >> 8) & 0xFF)      ))
82 #define ltohl(b) htoll(b)
83 #define ltohs(b) htols(b)
84 #else
85 #error "Endianess not defined"
86 #endif
87 #endif
88
89
90 static int check_header(int fd)
91 {
92         int type, size, formtype;
93         int fmt, hsize;
94         short format, chans, bysam, bisam;
95         int bysec;
96         int freq;
97         int data;
98         if (read(fd, &type, 4) != 4) {
99                 ast_log(LOG_WARNING, "Read failed (type)\n");
100                 return -1;
101         }
102         if (read(fd, &size, 4) != 4) {
103                 ast_log(LOG_WARNING, "Read failed (size)\n");
104                 return -1;
105         }
106         size = ltohl(size);
107         if (read(fd, &formtype, 4) != 4) {
108                 ast_log(LOG_WARNING, "Read failed (formtype)\n");
109                 return -1;
110         }
111         if (memcmp(&type, "RIFF", 4)) {
112                 ast_log(LOG_WARNING, "Does not begin with RIFF\n");
113                 return -1;
114         }
115         if (memcmp(&formtype, "WAVE", 4)) {
116                 ast_log(LOG_WARNING, "Does not contain WAVE\n");
117                 return -1;
118         }
119         if (read(fd, &fmt, 4) != 4) {
120                 ast_log(LOG_WARNING, "Read failed (fmt)\n");
121                 return -1;
122         }
123         if (memcmp(&fmt, "fmt ", 4)) {
124                 ast_log(LOG_WARNING, "Does not say fmt\n");
125                 return -1;
126         }
127         if (read(fd, &hsize, 4) != 4) {
128                 ast_log(LOG_WARNING, "Read failed (formtype)\n");
129                 return -1;
130         }
131         if (ltohl(hsize) != 16) {
132                 ast_log(LOG_WARNING, "Unexpected header size %d\n", ltohl(hsize));
133                 return -1;
134         }
135         if (read(fd, &format, 2) != 2) {
136                 ast_log(LOG_WARNING, "Read failed (format)\n");
137                 return -1;
138         }
139         if (ltohs(format) != 1) {
140                 ast_log(LOG_WARNING, "Not a wav file %d\n", ltohs(format));
141                 return -1;
142         }
143         if (read(fd, &chans, 2) != 2) {
144                 ast_log(LOG_WARNING, "Read failed (format)\n");
145                 return -1;
146         }
147         if (ltohs(chans) != 1) {
148                 ast_log(LOG_WARNING, "Not in mono %d\n", ltohs(chans));
149                 return -1;
150         }
151         if (read(fd, &freq, 4) != 4) {
152                 ast_log(LOG_WARNING, "Read failed (freq)\n");
153                 return -1;
154         }
155         if (ltohl(freq) != 8000) {
156                 ast_log(LOG_WARNING, "Unexpected freqency %d\n", ltohl(freq));
157                 return -1;
158         }
159         /* Ignore the byte frequency */
160         if (read(fd, &bysec, 4) != 4) {
161                 ast_log(LOG_WARNING, "Read failed (BYTES_PER_SECOND)\n");
162                 return -1;
163         }
164         /* Check bytes per sample */
165         if (read(fd, &bysam, 2) != 2) {
166                 ast_log(LOG_WARNING, "Read failed (BYTES_PER_SAMPLE)\n");
167                 return -1;
168         }
169         if (ltohs(bysam) != 2) {
170                 ast_log(LOG_WARNING, "Can only handle 16bits per sample: %d\n", ltohs(bysam));
171                 return -1;
172         }
173         if (read(fd, &bisam, 2) != 2) {
174                 ast_log(LOG_WARNING, "Read failed (Bits Per Sample): %d\n", ltohs(bisam));
175                 return -1;
176         }
177         /* Begin data chunk */
178         if (read(fd, &data, 4) != 4) {
179                 ast_log(LOG_WARNING, "Read failed (data)\n");
180                 return -1;
181         }
182         if (memcmp(&data, "data", 4)) {
183                 ast_log(LOG_WARNING, "Does not say data\n");
184                 return -1;
185         }
186         /* Data has the actual length of data in it */
187         if (read(fd, &data, 4) != 4) {
188                 ast_log(LOG_WARNING, "Read failed (data)\n");
189                 return -1;
190         }
191 #if 0
192         curpos = lseek(fd, 0, SEEK_CUR);
193         truelength = lseek(fd, 0, SEEK_END);
194         lseek(fd, curpos, SEEK_SET);
195         truelength -= curpos;
196 #endif  
197         return ltohl(data);
198 }
199
200 static int update_header(int fd)
201 {
202         off_t cur,end;
203         int datalen,filelen,bytes;
204         
205         
206         cur = lseek(fd, 0, SEEK_CUR);
207         end = lseek(fd, 0, SEEK_END);
208         /* data starts 44 bytes in */
209         bytes = end - 44;
210         datalen = htoll(bytes);
211         /* chunk size is bytes of data plus 36 bytes of header */
212         filelen = htoll(36 + bytes);
213         
214         if (cur < 0) {
215                 ast_log(LOG_WARNING, "Unable to find our position\n");
216                 return -1;
217         }
218         if (lseek(fd, 4, SEEK_SET) != 4) {
219                 ast_log(LOG_WARNING, "Unable to set our position\n");
220                 return -1;
221         }
222         if (write(fd, &filelen, 4) != 4) {
223                 ast_log(LOG_WARNING, "Unable to set write file size\n");
224                 return -1;
225         }
226         if (lseek(fd, 40, SEEK_SET) != 40) {
227                 ast_log(LOG_WARNING, "Unable to set our position\n");
228                 return -1;
229         }
230         if (write(fd, &datalen, 4) != 4) {
231                 ast_log(LOG_WARNING, "Unable to set write datalen\n");
232                 return -1;
233         }
234         if (lseek(fd, cur, SEEK_SET) != cur) {
235                 ast_log(LOG_WARNING, "Unable to return to position\n");
236                 return -1;
237         }
238         return 0;
239 }
240
241 static int write_header(int fd)
242 {
243         unsigned int hz=htoll(8000);
244         unsigned int bhz = htoll(16000);
245         unsigned int hs = htoll(16);
246         unsigned short fmt = htols(1);
247         unsigned short chans = htols(1);
248         unsigned short bysam = htols(2);
249         unsigned short bisam = htols(16);
250         unsigned int size = htoll(0);
251         /* Write a wav header, ignoring sizes which will be filled in later */
252         lseek(fd,0,SEEK_SET);
253         if (write(fd, "RIFF", 4) != 4) {
254                 ast_log(LOG_WARNING, "Unable to write header\n");
255                 return -1;
256         }
257         if (write(fd, &size, 4) != 4) {
258                 ast_log(LOG_WARNING, "Unable to write header\n");
259                 return -1;
260         }
261         if (write(fd, "WAVEfmt ", 8) != 8) {
262                 ast_log(LOG_WARNING, "Unable to write header\n");
263                 return -1;
264         }
265         if (write(fd, &hs, 4) != 4) {
266                 ast_log(LOG_WARNING, "Unable to write header\n");
267                 return -1;
268         }
269         if (write(fd, &fmt, 2) != 2) {
270                 ast_log(LOG_WARNING, "Unable to write header\n");
271                 return -1;
272         }
273         if (write(fd, &chans, 2) != 2) {
274                 ast_log(LOG_WARNING, "Unable to write header\n");
275                 return -1;
276         }
277         if (write(fd, &hz, 4) != 4) {
278                 ast_log(LOG_WARNING, "Unable to write header\n");
279                 return -1;
280         }
281         if (write(fd, &bhz, 4) != 4) {
282                 ast_log(LOG_WARNING, "Unable to write header\n");
283                 return -1;
284         }
285         if (write(fd, &bysam, 2) != 2) {
286                 ast_log(LOG_WARNING, "Unable to write header\n");
287                 return -1;
288         }
289         if (write(fd, &bisam, 2) != 2) {
290                 ast_log(LOG_WARNING, "Unable to write header\n");
291                 return -1;
292         }
293         if (write(fd, "data", 4) != 4) {
294                 ast_log(LOG_WARNING, "Unable to write header\n");
295                 return -1;
296         }
297         if (write(fd, &size, 4) != 4) {
298                 ast_log(LOG_WARNING, "Unable to write header\n");
299                 return -1;
300         }
301         return 0;
302 }
303
304 static struct ast_filestream *wav_open(int fd)
305 {
306         /* We don't have any header to read or anything really, but
307            if we did, it would go here.  We also might want to check
308            and be sure it's a valid file.  */
309         struct ast_filestream *tmp;
310         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
311                 memset(tmp, 0, sizeof(struct ast_filestream));
312                 if ((tmp->maxlen = check_header(fd)) < 0) {
313                         free(tmp);
314                         return NULL;
315                 }
316                 if (ast_mutex_lock(&wav_lock)) {
317                         ast_log(LOG_WARNING, "Unable to lock wav list\n");
318                         free(tmp);
319                         return NULL;
320                 }
321                 tmp->fd = fd;
322                 tmp->needsgain = 1;
323                 tmp->fr.data = tmp->buf;
324                 tmp->fr.frametype = AST_FRAME_VOICE;
325                 tmp->fr.subclass = AST_FORMAT_SLINEAR;
326                 /* datalen will vary for each frame */
327                 tmp->fr.src = name;
328                 tmp->fr.mallocd = 0;
329                 tmp->bytes = 0;
330                 glistcnt++;
331                 ast_mutex_unlock(&wav_lock);
332                 ast_update_use_count();
333         }
334         return tmp;
335 }
336
337 static struct ast_filestream *wav_rewrite(int fd, char *comment)
338 {
339         /* We don't have any header to read or anything really, but
340            if we did, it would go here.  We also might want to check
341            and be sure it's a valid file.  */
342         struct ast_filestream *tmp;
343         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
344                 memset(tmp, 0, sizeof(struct ast_filestream));
345                 if (write_header(fd)) {
346                         free(tmp);
347                         return NULL;
348                 }
349                 if (ast_mutex_lock(&wav_lock)) {
350                         ast_log(LOG_WARNING, "Unable to lock wav list\n");
351                         free(tmp);
352                         return NULL;
353                 }
354                 tmp->fd = fd;
355                 glistcnt++;
356                 ast_mutex_unlock(&wav_lock);
357                 ast_update_use_count();
358         } else
359                 ast_log(LOG_WARNING, "Out of memory\n");
360         return tmp;
361 }
362
363 static void wav_close(struct ast_filestream *s)
364 {
365         char zero = 0;
366         if (ast_mutex_lock(&wav_lock)) {
367                 ast_log(LOG_WARNING, "Unable to lock wav list\n");
368                 return;
369         }
370         glistcnt--;
371         ast_mutex_unlock(&wav_lock);
372         ast_update_use_count();
373         /* Pad to even length */
374         if (s->bytes & 0x1)
375                 write(s->fd, &zero, 1);
376         close(s->fd);
377         free(s);
378         s = NULL;
379 }
380
381 static struct ast_frame *wav_read(struct ast_filestream *s, int *whennext)
382 {
383         int res;
384         int delay;
385         int x;
386         short tmp[sizeof(s->buf) / 2];
387         int bytes = sizeof(tmp);
388         off_t here;
389         /* Send a frame from the file to the appropriate channel */
390         here = lseek(s->fd, 0, SEEK_CUR);
391         if ((s->maxlen - here) < bytes)
392                 bytes = s->maxlen - here;
393         if (bytes < 0)
394                 bytes = 0;
395 /*      ast_log(LOG_DEBUG, "here: %d, maxlen: %d, bytes: %d\n", here, s->maxlen, bytes); */
396         
397         if ( (res = read(s->fd, tmp, bytes)) <= 0 ) {
398                 if (res) {
399                         ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
400                 }
401                 return NULL;
402         }
403
404 #if __BYTE_ORDER == __BIG_ENDIAN
405         for( x = 0; x < sizeof(tmp)/2; x++) tmp[x] = (tmp[x] << 8) | ((tmp[x] & 0xff00) >> 8);
406 #endif
407
408         if (s->needsgain) {
409                 for (x=0;x<sizeof(tmp)/2;x++)
410                         if (tmp[x] & ((1 << GAIN) - 1)) {
411                                 /* If it has data down low, then it's not something we've artificially increased gain
412                                    on, so we don't need to gain adjust it */
413                                 s->needsgain = 0;
414                         }
415         }
416         if (s->needsgain) {
417                 for (x=0;x<sizeof(tmp)/2;x++) {
418                         s->buf[x] = tmp[x] >> GAIN;
419                 }
420         } else {
421                 memcpy(s->buf, tmp, sizeof(s->buf));
422         }
423                         
424         delay = res / 2;
425         s->fr.frametype = AST_FRAME_VOICE;
426         s->fr.subclass = AST_FORMAT_SLINEAR;
427         s->fr.offset = AST_FRIENDLY_OFFSET;
428         s->fr.datalen = res;
429         s->fr.data = s->buf;
430         s->fr.mallocd = 0;
431         s->fr.samples = delay;
432         *whennext = delay;
433         return &s->fr;
434 }
435
436 static int wav_write(struct ast_filestream *fs, struct ast_frame *f)
437 {
438         int res = 0;
439         int x;
440         short tmp[8000], *tmpi;
441         float tmpf;
442         if (f->frametype != AST_FRAME_VOICE) {
443                 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
444                 return -1;
445         }
446         if (f->subclass != AST_FORMAT_SLINEAR) {
447                 ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%d)!\n", f->subclass);
448                 return -1;
449         }
450         if (f->datalen > sizeof(tmp)) {
451                 ast_log(LOG_WARNING, "Data length is too long\n");
452                 return -1;
453         }
454         if (!f->datalen)
455                 return -1;
456
457 #if 0
458         printf("Data Length: %d\n", f->datalen);
459 #endif  
460
461         if (fs->buf) {
462                 tmpi = f->data;
463                 /* Volume adjust here to accomodate */
464                 for (x=0;x<f->datalen/2;x++) {
465                         tmpf = ((float)tmpi[x]) * ((float)(1 << GAIN));
466                         if (tmpf > 32767.0)
467                                 tmpf = 32767.0;
468                         if (tmpf < -32768.0)
469                                 tmpf = -32768.0;
470                         tmp[x] = tmpf;
471                         tmp[x] &= ~((1 << GAIN) - 1);
472
473 #if __BYTE_ORDER == __BIG_ENDIAN
474                         tmp[x] = (tmp[x] << 8) | ((tmp[x] & 0xff00) >> 8);
475 #endif
476
477                 }
478                 if ((write (fs->fd, tmp, f->datalen) != f->datalen) ) {
479                         ast_log(LOG_WARNING, "Bad write (%d): %s\n", res, strerror(errno));
480                         return -1;
481                 }
482         } else {
483                 ast_log(LOG_WARNING, "Cannot write data to file.\n");
484                 return -1;
485         }
486         
487         fs->bytes += f->datalen;
488         update_header(fs->fd);
489                 
490         return 0;
491
492 }
493
494 static int wav_seek(struct ast_filestream *fs, long sample_offset, int whence)
495 {
496         off_t min,max,cur;
497         long offset=0,samples;
498         
499         samples = sample_offset * 2; /* SLINEAR is 16 bits mono, so sample_offset * 2 = bytes */
500         min = 44; /* wav header is 44 bytes */
501         cur = lseek(fs->fd, 0, SEEK_CUR);
502         max = lseek(fs->fd, 0, SEEK_END);
503         if (whence == SEEK_SET)
504                 offset = samples + min;
505         else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
506                 offset = samples + cur;
507         else if (whence == SEEK_END)
508                 offset = max - samples;
509         if (whence != SEEK_FORCECUR) {
510                 offset = (offset > max)?max:offset;
511                 offset = (offset < min)?min:offset;
512         }
513         return lseek(fs->fd,offset,SEEK_SET);
514 }
515
516 static int wav_trunc(struct ast_filestream *fs)
517 {
518         if(ftruncate(fs->fd, lseek(fs->fd,0,SEEK_CUR)))
519                 return -1;
520         return update_header(fs->fd);
521 }
522
523 static long wav_tell(struct ast_filestream *fs)
524 {
525         off_t offset;
526         offset = lseek(fs->fd, 0, SEEK_CUR);
527         /* subtract header size to get samples, then divide by 2 for 16 bit samples */
528         return (offset - 44)/2;
529 }
530
531 static char *wav_getcomment(struct ast_filestream *s)
532 {
533         return NULL;
534 }
535
536 int load_module()
537 {
538         return ast_format_register(name, exts, AST_FORMAT_SLINEAR,
539                                                                 wav_open,
540                                                                 wav_rewrite,
541                                                                 wav_write,
542                                                                 wav_seek,
543                                                                 wav_trunc,
544                                                                 wav_tell,
545                                                                 wav_read,
546                                                                 wav_close,
547                                                                 wav_getcomment);
548                                                                 
549                                                                 
550 }
551
552 int unload_module()
553 {
554         return ast_format_unregister(name);
555 }       
556
557 int usecount()
558 {
559         int res;
560         if (ast_mutex_lock(&wav_lock)) {
561                 ast_log(LOG_WARNING, "Unable to lock wav list\n");
562                 return -1;
563         }
564         res = glistcnt;
565         ast_mutex_unlock(&wav_lock);
566         return res;
567 }
568
569 char *description()
570 {
571         return desc;
572 }
573
574
575 char *key()
576 {
577         return ASTERISK_GPL_KEY;
578 }