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