1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** opening and reading tone **
10 \*****************************************************************************/
15 #include <sys/types.h>
26 CODEC_OFF is a none accepted value
27 CODEC_LAW is 8 bit (1 byte) data 8khz
28 other codecs are 16 bit (2 bytes) data 8khz
29 the read_tone() will return law or 16bit mono. the read_tone will convert all other formats to 16bit mono.
35 * open the tone (don't increase fhuse, since it is done after calling this function)
36 * NOTE: length and left will be set to the number of samples, NOT bytes
39 unsigned short stereo; /* 1 = pcm, 2 = adpcm */
40 unsigned short channels; /* number of channels */
41 unsigned long sample_rate; /* sample rate */
42 unsigned long data_rate; /* data rate */
43 unsigned short bytes_sample; /* bytes per sample (all channels) */
44 unsigned short bits_sample; /* bits per sample (one channel) */
46 int open_tone(char *file, int *codec, signed long *length, signed long *left)
51 unsigned char buffer[256];
54 unsigned long size, chunk;
62 /* try to open the law file */
63 SPRINT(filename, "%s.isdn", file);
64 if ((fh = open(filename, O_RDONLY)) >= 0)
73 PERROR("Link chain too deep: '%s'\n", filename);
76 if (lstat(filename, &_stat) == -1)
79 PERROR("Cannot stat file: '%s'\n", filename);
82 if (!S_ISLNK(_stat.st_mode))
86 if ((linksize=readlink(filename, linkname, sizeof(linkname))) > 0)
88 linkname[linksize] = '\0';
92 PERROR("Cannot read link information: '%s'\n", filename);
95 if (linkname[0] == '/') /* absolute link */
97 SCPY(filename, linkname);
98 } else /* relative link */
100 /* remove filename */
102 while(strchr(p, '/'))
104 p = strchr(p, '/')+1;
107 /* concat the link */
108 SCAT(filename, linkname);
110 //printf("follow link: %s\n", filename);
114 *length = _stat.st_size;
116 *left = _stat.st_size;
122 /* try to open the wave file */
123 SPRINT(filename, "%s.wav", file);
124 if ((fh = open(filename, O_RDONLY)) >= 0)
126 /* get wave header */
128 size=(buffer[4]) + (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24);
129 if (!!strncmp((char *)buffer, "RIFF", 4))
133 PERROR("%s is no riff file!\n", filename);
136 // printf("%c%c%c%c size=%ld\n",buffer[0],buffer[1],buffer[2],buffer[3],size);
139 if (!!strncmp((char *)buffer, "WAVE", 4))
143 PERROR("%s is no wave file!\n", filename);
148 if (size>0 && size<8)
152 PERROR("Remaining file size %ld not large enough for next chunk.\n",size);
156 chunk=(buffer[4]) + (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24);
158 // printf("%c%c%c%c lenght=%d\n",buffer[0],buffer[1],buffer[2],buffer[3],chunk);
163 PERROR("Chunk '%c%c%c%c' is larger than remainig file size (length=%ld)\n",buffer[0],buffer[1],buffer[2],buffer[3], chunk);
166 if (!strncmp((char *)buffer, "fmt ", 4))
172 PERROR("File %s Fmt chunk illegal size.\n", filename);
175 read(fh, buffer, chunk);
176 fmt = (struct fmt *)buffer;
177 if (fmt->channels<1 || fmt->channels>2)
181 PERROR("File %s Only support one or two channels file.\n", filename);
184 channels = fmt->channels;
185 // printf("Channels: %d\n", channels);
186 if (fmt->sample_rate != 8000)
188 PERROR("Warning: File %s has sample rate of %ld.\n", filename, fmt->sample_rate);
190 // printf("Sample Rate: %ld\n", fmt->sample_rate);
191 if (fmt->bits_sample!=8 && fmt->bits_sample!=16)
195 PERROR("File %s has neigher 8 nor 16 bit samples.\n", filename);
198 bytes = (fmt->bits_sample==16)?2:1;
199 // printf("Bit-Resolution: %d\n", bytes*16-16);
202 if (!strncmp((char *)buffer, "data", 4))
208 PERROR("File %s No fmt chunk found before data chunk.\n", filename);
211 // printf("Length: %ld samples (%ld.%03ld seconds)\n", chunk/bytes/channels, chunk/bytes/channels/8000, ((chunk/bytes/channels)%8000)*1000/8000);
212 if (bytes==2 && channels==1)
217 *length = ((signed long)chunk)>>1;
219 *left = ((signed long)chunk)>>1;
221 if (bytes==2 && channels==2)
224 *codec = CODEC_STEREO;
226 *length = ((signed long)chunk)>>2;
228 *left = ((signed long)chunk)>>2;
230 if (bytes==1 && channels==1)
235 *length = (signed long)chunk;
237 *left = (signed long)chunk;
242 PERROR("File %s Is not MONO8, MONO16 nor STEREO16.\n", filename);
248 // PDEBUG(DEBUG_PORT, "Unknown chunk '%c%c%c%c'\n",buffer[0],buffer[1],buffer[2],buffer[3]);
249 while(chunk > sizeof(buffer))
251 read(fh, buffer, sizeof(buffer));
252 chunk -= sizeof(buffer);
255 read(fh, buffer, chunk);
263 PERROR("File %s No fmt chunk found in file.\n", filename);
268 PERROR("File %s No data chunk found in file.\n", filename);
277 * read from tone, check size
278 * the len must be the number of samples, NOT for the bytes to read!!
280 int read_tone(int fh, void *buffer, int codec, int len, signed long size, signed long *left, int speed)
284 //printf("left=%ld\n",*left);
286 /* if no *left is given (law has unknown length) */
292 offset = ((len&(~4)) * (speed-1));
293 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)*/
294 *left -= offset; /* correct the current bytes left */
318 l = read(fh, buffer, len); /* as is */
322 l = read(fh, buffer, len<<1); /* as is */
329 signed short buffer32[len<<1], *buf32 = buffer32;
330 signed short *buf16 = (signed short *)buffer;
333 l = read(fh, buf32, len<<2);
339 sample = (*buf32++) + (*buf32++);
353 unsigned char buffer8[len], *buf8 = buffer8;
354 signed short *buf16 = (signed short *)buffer;
356 l = read(fh, buf8, len);
361 *buf16++ = (((*buf8++) << 8) - 0x8000) & 0xffff;
369 PERROR("codec %d is not specified or supported, exitting...\n", codec);
379 struct toneset *toneset_first = NULL;
384 void free_tones(void)
386 struct toneset *toneset_temp;
387 struct tonesettone *tonesettone_temp;
390 toneset_temp = toneset_first;
393 tonesettone_temp = toneset_temp->first;
394 while(tonesettone_temp)
396 temp = tonesettone_temp;
397 tonesettone_temp = tonesettone_temp->next;
402 toneset_temp = toneset_temp->next;
406 toneset_first = NULL;
410 * fetch tones as specified in options.conf
412 int fetch_tones(void)
415 struct dirent *dirent;
416 struct toneset **toneset_nextpointer;
417 struct tonesettone **tonesettone_nextpointer;
420 char filename[256], name[256];
423 signed long tone_size, tone_left, real_size;
424 unsigned long memory = 0;
428 if (!options.fetch_tones)
431 toneset_nextpointer = &toneset_first;
432 p = options.fetch_tones;
450 /* remove trailing / */
451 if (*p) if (p[strlen(p)-1] == '/')
452 p[strlen(p)-1] = '\0';
454 printf("PBX: Fetching tones '%s'\n", p);
455 PDEBUG(DEBUG_PORT, "fetching tones directory '%s'\n", p);
457 *toneset_nextpointer = (struct toneset *)calloc(1, sizeof(struct toneset));
458 if (*toneset_nextpointer == NULL)
460 PERROR("No memory for tone set: '%s'\n",p);
464 memory += sizeof(struct toneset);
465 memset(*toneset_nextpointer, 0 , sizeof(struct toneset));
466 SCPY((*toneset_nextpointer)->directory, p);
467 tonesettone_nextpointer = &(*toneset_nextpointer)->first;
469 SPRINT(path, "%s/%s", INSTALL_DATA, p);
473 PERROR("Tone set not found: '%s'\n", path);
477 while((dirent=readdir(dir)))
479 SPRINT(name, "%s", dirent->d_name);
481 /* remove .isdn and .wave */
482 if (strlen(name) >= 4)
484 if (!strcmp(name+strlen(name)-4, ".wav"))
485 name[strlen(name)-4] = '\0';
487 if (strlen(name) >= 5)
489 if (!strcmp(name+strlen(name)-5, ".isdn"))
490 name[strlen(name)-5] = '\0';
493 SPRINT(filename, "%s/%s", path, name);
496 if (!strcmp(dirent->d_name, "."))
498 if (!strcmp(dirent->d_name, ".."))
502 fh = open_tone(filename, &tone_codec, &tone_size, &tone_left);
505 PERROR("Cannot open file: '%s'\n", filename);
512 PERROR("File has 0-length: '%s'\n", filename);
522 real_size = tone_size;
526 real_size = tone_size << 1;
530 real_size = tone_size << 1;
534 real_size = tone_size << 1;
538 PERROR("codec %d is not specified or supported, exitting...\n", tone_codec);
543 *tonesettone_nextpointer = (struct tonesettone *)calloc(1, sizeof(struct tonesettone)+real_size);
544 if (*toneset_nextpointer == NULL)
546 PERROR("No memory for tone set: '%s'\n",p);
552 //printf("tone:%s, %ld bytes\n", name, tone_size);
553 memset(*tonesettone_nextpointer, 0 , sizeof(struct tonesettone)+real_size);
554 memory += sizeof(struct tonesettone)+real_size;
558 read_tone(fh, (*tonesettone_nextpointer)->data, tone_codec, tone_size, tone_size, &tone_left, 1);
559 (*tonesettone_nextpointer)->size = tone_size;
560 (*tonesettone_nextpointer)->codec = (tone_codec==CODEC_LAW)?CODEC_LAW:CODEC_MONO;
561 SCPY((*tonesettone_nextpointer)->name, name);
566 tonesettone_nextpointer = &((*tonesettone_nextpointer)->next);
569 toneset_nextpointer = &((*toneset_nextpointer)->next);
573 printf("PBX: Memory used for tones: %ld bytes (%d samples)\n", memory, samples);
574 PDEBUG(DEBUG_PORT, "Memory used for tones: %ld bytes (%d samples)\n", memory, samples);
581 * opens the fetched tone (if available)
583 void *open_tone_fetched(char *dir, char *file, int *codec, signed long *length, signed long *left)
585 struct toneset *toneset;
586 struct tonesettone *tonesettone;
588 /* if anything fetched */
593 toneset = toneset_first;
596 //printf("1. comparing '%s' with '%s'\n", toneset->directory, dir);
597 if (!strcmp(toneset->directory, dir))
599 toneset = toneset->next;
605 tonesettone = toneset->first;
608 //printf("2. comparing '%s' with '%s'\n", tonesettone->name, file);
609 if (!strcmp(tonesettone->name, file))
611 tonesettone = tonesettone->next;
616 /* return information */
618 *length = tonesettone->size;
620 *left = tonesettone->size;
622 *codec = tonesettone->codec;
623 //printf("size=%ld, data=%08x\n", tonesettone->size, tonesettone->data);
624 return(tonesettone->data);
629 * read from fetched tone, check size
630 * the len must be the number of samples, NOT for the bytes to read!!
632 int read_tone_fetched(void **fetched, void *buffer, int codec, int len, signed long size, signed long *left, int speed)
635 //printf("left=%ld\n",*left);
637 /* if no *left is given (law has unknown length) */
649 memcpy(buffer, *fetched, len);
650 *((char **)fetched) += len;
655 memcpy(buffer, *fetched, len<<1);
656 *((char **)fetched) += len<<1;
661 PERROR("codec %d is not specified or supported, exitting...\n", codec);