make compile with gcc 4.* without warnings. (hopefully with all versions)
[lcr.git] / tones.c
1 /*****************************************************************************\
2 **                                                                           **
3 ** PBX4Linux                                                                 **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** opening and reading tone                                                  **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include "main.h"
13
14 /* 
15 notes about codecs:
16
17 CODEC_OFF is a none accepted value
18 CODEC_LAW is 8 bit (1 byte) data 8khz
19 other codecs are 16 bit (2 bytes) data 8khz
20 the read_tone() will return law or 16bit mono. the read_tone will convert all other formats to 16bit mono.
21
22 */ 
23
24
25 /*
26  * open the tone (don't increase fhuse, since it is done after calling this function)
27  * NOTE: length and left will be set to the number of samples, NOT bytes
28  */
29 struct fmt {
30         unsigned short  stereo; /* 1 = pcm, 2 = adpcm */
31         unsigned short  channels; /* number of channels */
32         unsigned int   sample_rate; /* sample rate */
33         unsigned int   data_rate; /* data rate */
34         unsigned short  bytes_sample; /* bytes per sample (all channels) */
35         unsigned short  bits_sample; /* bits per sample (one channel) */
36 };
37 int open_tone(char *file, int *codec, signed int *length, signed int *left)
38 {
39         int fh;
40         char filename[256];        
41         char linkname[256];        
42         unsigned char buffer[256];
43         struct fmt *fmt;
44         int channels, bytes;
45         unsigned int size, chunk;
46         int gotfmt = 0;
47         struct stat _stat;
48         int linksize;
49         int l;
50         char *p;
51
52
53         /* try to open the law file */
54         SPRINT(filename, "%s.isdn", file);
55         if ((fh = open(filename, O_RDONLY)) >= 0)
56         {
57                 /* stat tone */
58                 l = 0;
59                 while(42)
60                 {
61                         if (l >= 10)
62                         {
63                                 close(fh);
64                                 PERROR("Link chain too deep: '%s'\n", filename);
65                                 return(-1);
66                         }
67                         if (lstat(filename, &_stat) == -1)
68                         {
69                                 close(fh);
70                                 PERROR("Cannot stat file: '%s'\n", filename);
71                                 return(-1);
72                         }
73                         if (!S_ISLNK(_stat.st_mode))
74                         {
75                                 break;
76                         }
77                         if ((linksize=readlink(filename, linkname, sizeof(linkname))) > 0)
78                         {
79                                 linkname[linksize] = '\0';
80                         } else
81                         {
82                                 close(fh);
83                                 PERROR("Cannot read link information: '%s'\n", filename);
84                                 return(-1);
85                         }
86                         if (linkname[0] == '/') /* absolute link */
87                         {
88                                 SCPY(filename, linkname);
89                         } else /* relative link */
90                         {
91                                 /* remove filename */
92                                 p = filename;
93                                 while(strchr(p, '/'))
94                                 {
95                                         p = strchr(p, '/')+1;
96                                 }
97                                 *p = 0;
98                                 /* concat the link */
99                                 SCAT(filename, linkname);
100                         }
101 //printf("follow link: %s\n", filename);
102                         l++;
103                 }
104                 if (length)
105                         *length = _stat.st_size;
106                 if (left)
107                         *left = _stat.st_size;
108                 if (codec)
109                         *codec = CODEC_LAW;
110                 return(fh);
111         }
112
113         /* try to open the wave file */
114         SPRINT(filename, "%s.wav", file);
115         if ((fh = open(filename, O_RDONLY)) >= 0)
116         {
117                 /* get wave header */
118                 read(fh, buffer, 8);
119                 size=(buffer[4]) + (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24);
120                 if (!!strncmp((char *)buffer, "RIFF", 4))
121                 {
122                         close(fh);
123                         errno = 0;
124                         PERROR("%s is no riff file!\n", filename);
125                         return(-1);
126                 }
127 //              printf("%c%c%c%c size=%ld\n",buffer[0],buffer[1],buffer[2],buffer[3],size);
128                 read(fh, buffer, 4);
129                 size -= 4;
130                 if (!!strncmp((char *)buffer, "WAVE", 4))
131                 {
132                         close(fh);
133                         errno = 0;
134                         PERROR("%s is no wave file!\n", filename);
135                         return(-1);
136                 }
137                 while(size)
138                 {
139                         if (size>0 && size<8)
140                         {
141                                 close(fh);
142                                 errno = 0;
143                                 PERROR("Remaining file size %ld not large enough for next chunk.\n",size);
144                                 return(-1);
145                         }
146                         read(fh, buffer, 8);
147                         chunk=(buffer[4]) + (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24);
148                         size -= (8+chunk);
149 //                      printf("%c%c%c%c length=%d\n",buffer[0],buffer[1],buffer[2],buffer[3],chunk);
150                         if (size < 0)
151                         {
152                                 close(fh);
153                                 errno = 0;
154                                 PERROR("Chunk '%c%c%c%c' is larger than remainig file size (length=%ld)\n",buffer[0],buffer[1],buffer[2],buffer[3], chunk);
155                                 return(-1);
156                         }
157                         if (!strncmp((char *)buffer, "fmt ", 4))
158                         {
159                                 if (chunk < 16)
160                                 {
161                                         close(fh);
162                                         errno = 0;
163                                         PERROR("File %s Fmt chunk illegal size.\n", filename);
164                                         return(-1);
165                                 }
166                                 read(fh, buffer, chunk);
167                                 fmt = (struct fmt *)buffer;
168                                 if (fmt->channels<1 || fmt->channels>2)
169                                 {
170                                         close(fh);
171                                         errno = 0;
172                                         PERROR("File %s Only support one or two channels file.\n", filename);
173                                         return(-1);
174                                 }
175                                 channels = fmt->channels;
176 //                              printf("Channels: %d\n", channels);
177                                 if (fmt->sample_rate != 8000)
178                                 {
179                                         PERROR("Warning: File %s has sample rate of %ld.\n", filename, fmt->sample_rate);
180                                 }
181 //                              printf("Sample Rate: %ld\n", fmt->sample_rate);
182                                 if (fmt->bits_sample!=8 && fmt->bits_sample!=16)
183                                 {
184                                         close(fh);
185                                         errno = 0;
186                                         PERROR("File %s has neigher 8 nor 16 bit samples.\n", filename);
187                                         return(-1);
188                                 }
189                                 bytes = (fmt->bits_sample==16)?2:1;
190 //                              printf("Bit-Resolution: %d\n", bytes*16-16);
191                                 gotfmt = 1;
192                         } else
193                         if (!strncmp((char *)buffer, "data", 4))
194                         {
195                                 if (!gotfmt)
196                                 {
197                                         close(fh);
198                                         errno = 0;
199                                         PERROR("File %s No fmt chunk found before data chunk.\n", filename);
200                                         return(-1);
201                                 }
202 //                              printf("Length: %ld samples (%ld.%03ld seconds)\n", chunk/bytes/channels, chunk/bytes/channels/8000, ((chunk/bytes/channels)%8000)*1000/8000);
203                                 if (bytes==2 && channels==1)
204                                 {
205                                         if (codec)
206                                                 *codec = CODEC_MONO;
207                                         if (length)
208                                                 *length = ((signed int)chunk)>>1;
209                                         if (left)
210                                                 *left = ((signed int)chunk)>>1;
211 //                                      printf("left=%d\n",*left);
212                                 } else
213                                 if (bytes==2 && channels==2)
214                                 {
215                                         if (codec)
216                                                 *codec = CODEC_STEREO;
217                                         if (length)
218                                                 *length = ((signed int)chunk)>>2;
219                                         if (left)
220                                                 *left = ((signed int)chunk)>>2;
221                                 } else
222                                 if (bytes==1 && channels==1)
223                                 {
224                                         if (codec)
225                                                 *codec = CODEC_8BIT;
226                                         if (length)
227                                                 *length = (signed int)chunk;
228                                         if (left)
229                                                 *left = (signed int)chunk;
230                                 } else
231                                 {
232                                         close(fh);
233                                         errno = 0;
234                                         PERROR("File %s Is not MONO8, MONO16 nor STEREO16.\n", filename);
235                                         return(-1);
236                                 }
237                                 return(fh);
238                         } else
239                         {
240 //                              PDEBUG(DEBUG_PORT, "Unknown chunk '%c%c%c%c'\n",buffer[0],buffer[1],buffer[2],buffer[3]);
241                                 while(chunk > sizeof(buffer))
242                                 {
243                                         read(fh, buffer, sizeof(buffer));
244                                         chunk -=  sizeof(buffer);
245                                 }
246                                 if (chunk)
247                                         read(fh, buffer, chunk);
248                         }
249                         
250                 }
251                 if (!gotfmt)
252                 {
253                         close(fh);
254                         errno = 0;
255                         PERROR("File %s No fmt chunk found in file.\n", filename);
256                         return(-1);
257                 }
258                 close(fh);
259                 errno = 0;
260                 PERROR("File %s No data chunk found in file.\n", filename);
261                 return(-1);
262         }
263
264         return(-1);
265 }
266
267
268 /*
269  * read from tone, check size
270  * the len must be the number of samples, NOT for the bytes to read!!
271  * the data returned is law-code
272  */
273 int read_tone(int fh, unsigned char *buffer, int codec, int len, signed int size, signed int *left, int speed)
274 {
275         int l;
276         int offset;
277         signed short buffer16[len], *buf16 = buffer16;
278         signed short buffer32[len<<1], *buf32 = buffer32;
279         unsigned char buffer8[len], *buf8 = buffer8;
280         signed int sample;
281         int i = 0;
282 //printf("left=%ld\n",*left);
283
284         /* if no *left is given (law has unknown length) */
285         if (!left)
286                 goto unknown_length;
287
288         if (speed!=1)
289         {
290                 offset = ((len&(~4)) * (speed-1));
291                 lseek(fh, offset, SEEK_CUR); /* step fowards, backwards (len must be round to 4 bytes, to be sure, that 16bit stereo will not drift out of sync)*/
292                 *left -= offset; /* correct the current bytes left */
293                 if (*left < 0)
294                 {
295                         /* eof */
296                         *left = 0;
297                         return(0);
298                 }
299                 if (*left >= size)
300                 {
301                         /* eof */
302                         *left = size;
303                         return(0);
304                 }
305         }
306
307         if (*left == 0)
308                 return(0);
309
310         if (*left < len)
311                 len = *left;
312         unknown_length:
313         switch(codec)
314         {
315                 case CODEC_LAW:
316                 l = read(fh, buffer, len); /* as is */
317                 break;
318
319                 case CODEC_MONO:
320                         l = read(fh, buf16, len<<1);
321                         if (l>0)
322                         {
323                                 l = l>>1;
324                                 while(i < l)
325                                 {
326                                         sample = *buf16++;
327                                         if (sample < -32767)
328                                                 sample = -32767;
329                                         if (sample > 32767)
330                                                 sample = 32767;
331                                         *buffer++ = audio_s16_to_law[sample & 0xffff];
332                                         i++;
333                                 }
334                         }
335                 break;
336
337                 case CODEC_STEREO:
338                 {
339                         l = read(fh, buf32, len<<2);
340                         if (l>0)
341                         {
342                                 l = l>>2;
343                                 while(i < l)
344                                 {
345                                         sample = (*buf32++);
346                                         sample += (*buf32++);
347                                         if (sample < -32767)
348                                                 sample = -32767;
349                                         if (sample > 32767)
350                                                 sample = 32767;
351                                         *buffer++ = audio_s16_to_law[sample & 0xffff];
352                                         i++;
353                                 }
354                         }
355                 }
356                 break;
357
358                 case CODEC_8BIT:
359                 {
360                         l = read(fh, buf8, len);
361                         if (l>0)
362                         {
363                                 while(i < l)
364                                 {
365                                         *buffer++ = audio_s16_to_law[(((*buf8++)<<8)-0x8000) & 0xffff];
366                                         i++;
367                                 }
368                         }
369                 }
370                 break;
371
372                 default:
373                 FATAL("codec %d is not supported.\n", codec);
374         }
375
376         if (l>0 && left)
377                 *left -= l;
378         return(l);
379 }
380
381
382 struct toneset *toneset_first = NULL;
383
384 /*
385  * free fetched tones
386  */
387 void free_tones(void)
388 {
389         struct toneset *toneset_temp;
390         struct tonesettone *tonesettone_temp;
391         void *temp;
392
393         toneset_temp = toneset_first;
394         while(toneset_temp)
395         {
396                 tonesettone_temp = toneset_temp->first;
397                 while(tonesettone_temp)
398                 {
399                         temp = tonesettone_temp;
400                         tonesettone_temp = tonesettone_temp->next;
401                         FREE(temp, sizeof(struct tonesettone));
402                         memuse--;
403                 }
404                 temp = toneset_temp;
405                 toneset_temp = toneset_temp->next;
406                 FREE(temp, sizeof(struct toneset));
407                 memuse--;
408         }
409         toneset_first = NULL;
410 }
411
412 /*
413  * fetch tones as specified in options.conf
414  */
415 int fetch_tones(void)
416 {
417         DIR *dir;
418         struct dirent *dirent;
419         struct toneset **toneset_nextpointer;
420         struct tonesettone **tonesettone_nextpointer;
421         char *p, *p_next;
422         char path[256];
423         char filename[256], name[256];
424         int fh;
425         int tone_codec;
426         signed int tone_size, tone_left;
427         unsigned int memory = 0;
428         int samples = 0;
429
430         /* if disabled */
431         if (!options.fetch_tones)
432                 return(1);
433
434         toneset_nextpointer = &toneset_first;
435         p = options.fetch_tones;
436         if (*p == '\0')
437                 return(1);
438
439         while (*p)
440         {
441                 p_next = p;
442                 while(*p_next)
443                 {
444                         if (*p_next == ',')
445                         {
446                                 *p_next = '\0';
447                                 p_next++;
448                                 break;
449                         }
450                         p_next++;
451                 }
452
453                 /* remove trailing / */
454                 if (*p) if (p[strlen(p)-1] == '/')
455                         p[strlen(p)-1] = '\0';
456
457                 printf("PBX: Fetching tones '%s'\n", p);
458                 PDEBUG(DEBUG_PORT, "fetching tones directory '%s'\n", p);
459
460                 *toneset_nextpointer = (struct toneset *)MALLOC(sizeof(struct toneset));
461                 memuse++;
462                 memory += sizeof(struct toneset);
463                 SCPY((*toneset_nextpointer)->directory, p);
464                 tonesettone_nextpointer = &(*toneset_nextpointer)->first;
465
466                 SPRINT(path, "%s/%s", INSTALL_DATA, p);
467                 dir = opendir(path);
468                 if (dir == NULL)
469                 {
470                         PERROR("Tone set not found: '%s'\n", path);
471                         return(0);
472                 }
473
474                 while((dirent=readdir(dir)))
475                 {
476                         SPRINT(name, "%s", dirent->d_name);
477
478                         /* remove .isdn and .wave */
479                         if (strlen(name) >= 4)
480                         {
481                                 if (!strcmp(name+strlen(name)-4, ".wav"))
482                                         name[strlen(name)-4] = '\0';
483                         }
484                         if (strlen(name) >= 5)
485                         {
486                                 if (!strcmp(name+strlen(name)-5, ".isdn"))
487                                         name[strlen(name)-5] = '\0';
488                         }
489
490                         SPRINT(filename, "%s/%s", path, name);
491
492                         /* skip . / .. */
493                         if (!strcmp(dirent->d_name, "."))
494                                 continue;
495                         if (!strcmp(dirent->d_name, ".."))
496                                 continue;
497
498                         /* open file */
499                         fh = open_tone(filename, &tone_codec, &tone_size, &tone_left);
500                         if (fh < 0)
501                         {
502                                 PERROR("Cannot open file: '%s'\n", filename);
503                                 continue;
504                         }
505                         fduse++;
506
507                         if (tone_size < 0)
508                         {
509                                 PERROR("File has 0-length: '%s'\n", filename);
510                                 close(fh);
511                                 fduse--;
512                                 continue;
513                         }
514
515                         /* Allocate tone */
516                         *tonesettone_nextpointer = (struct tonesettone *)MALLOC(sizeof(struct tonesettone)+tone_size);
517                         memuse++;
518 //printf("tone:%s, %ld bytes\n", name, tone_size);
519                         memory += sizeof(struct tonesettone)+tone_size;
520                         samples ++;
521
522                         /* load tone */
523                         read_tone(fh, (*tonesettone_nextpointer)->data, tone_codec, tone_size, tone_size, &tone_left, 1);
524                         (*tonesettone_nextpointer)->size = tone_size;
525                         (*tonesettone_nextpointer)->codec = (tone_codec==CODEC_LAW)?CODEC_LAW:CODEC_MONO;
526                         SCPY((*tonesettone_nextpointer)->name, name);
527
528                         close(fh);
529                         fduse--;
530                                  
531                         tonesettone_nextpointer = &((*tonesettone_nextpointer)->next);
532                 }
533
534                 toneset_nextpointer = &((*toneset_nextpointer)->next);
535                 p = p_next;
536         }
537
538         printf("PBX: Memory used for tones: %d bytes (%d samples)\n", memory, samples);
539         PDEBUG(DEBUG_PORT, "Memory used for tones: %ld bytes (%d samples)\n", memory, samples);
540
541         return(1);
542
543
544
545 /*
546  * opens the fetched tone (if available)
547  */
548 void *open_tone_fetched(char *dir, char *file, int *codec, signed int *length, signed int *left)
549 {
550         struct toneset *toneset;
551         struct tonesettone *tonesettone;
552
553         /* if anything fetched */
554         if (!toneset_first)
555                 return(NULL);
556
557         /* find set */
558         toneset = toneset_first;
559         while(toneset)
560         {
561 //printf("1. comparing '%s' with '%s'\n", toneset->directory, dir);
562                 if (!strcmp(toneset->directory, dir))
563                         break;
564                 toneset = toneset->next;
565         }
566         if (!toneset)
567                 return(NULL);
568
569         /* find tone */
570         tonesettone = toneset->first;
571         while(tonesettone)
572         {
573 //printf("2. comparing '%s' with '%s'\n", tonesettone->name, file);
574                 if (!strcmp(tonesettone->name, file))
575                         break;
576                 tonesettone = tonesettone->next;
577         }
578         if (!tonesettone)
579                 return(NULL);
580
581         /* return information */
582         if (length)
583                 *length = tonesettone->size;
584         if (left)
585                 *left = tonesettone->size;
586         if (codec)
587                 *codec = tonesettone->codec;
588 //printf("size=%ld, data=%08x\n", tonesettone->size, tonesettone->data);
589         return(tonesettone->data);
590 }
591
592
593 /*
594  * read from fetched tone, check size
595  * the len must be the number of samples, NOT for the bytes to read!!
596  */
597 int read_tone_fetched(void **fetched, void *buffer, int len, signed int size, signed int *left, int speed)
598 {
599         int l;
600 //printf("left=%ld\n",*left);
601
602         /* if no *left is given (law has unknown length) */
603         if (!left)
604                 return(0);
605
606         if (*left == 0)
607                 return(0);
608
609         if (*left < len)
610                 len = *left;
611
612         memcpy(buffer, *fetched, len);
613         *((char **)fetched) += len;
614         l = len;
615
616         if (l>0 && left)
617                 *left -= l;
618         return(l);
619 }
620