Documentation / whitespace fix.
[asterisk/asterisk.git] / indications.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2002, Pauline Middelink
5  *
6  *
7  * See http://www.asterisk.org for more information about
8  * the Asterisk project. Please do not directly contact
9  * any of the maintainers of this project for assistance;
10  * the project provides a web site, mailing lists and IRC
11  * channels for your use.
12  *
13  * This program is free software, distributed under the terms of
14  * the GNU General Public License Version 2. See the LICENSE file
15  * at the top of the source tree.
16  */
17
18 /*! \file
19  *
20  * \brief Tone Management
21  * 
22  * \author Pauline Middelink <middelink@polyware.nl>
23  *
24  * This set of function allow us to play a list of tones on a channel.
25  * Each element has two frequencies, which are mixed together and a
26  * duration. For silence both frequencies can be set to 0.
27  * The playtones can be given as a comma separated string.
28  *
29  */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <math.h>                       /* For PI */
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
40 #include "asterisk/indications.h"
41 #include "asterisk/frame.h"
42 #include "asterisk/options.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/logger.h"
45 #include "asterisk/lock.h"
46 #include "asterisk/utils.h"
47
48 static int midi_tohz[128] = {
49                         8,8,9,9,10,10,11,12,12,13,14,
50                         15,16,17,18,19,20,21,23,24,25,
51                         27,29,30,32,34,36,38,41,43,46,
52                         48,51,55,58,61,65,69,73,77,82,
53                         87,92,97,103,110,116,123,130,138,146,
54                         155,164,174,184,195,207,220,233,246,261,
55                         277,293,311,329,349,369,391,415,440,466,
56                         493,523,554,587,622,659,698,739,783,830,
57                         880,932,987,1046,1108,1174,1244,1318,1396,1479,
58                         1567,1661,1760,1864,1975,2093,2217,2349,2489,2637,
59                         2793,2959,3135,3322,3520,3729,3951,4186,4434,4698,
60                         4978,5274,5587,5919,6271,6644,7040,7458,7902,8372,
61                         8869,9397,9956,10548,11175,11839,12543
62                         };
63
64 struct playtones_item {
65         int fac1;
66         int init_v2_1;
67         int init_v3_1;
68         int fac2;
69         int init_v2_2;
70         int init_v3_2;
71         int modulate;
72         int duration;
73 };
74
75 struct playtones_def {
76         int vol;
77         int reppos;
78         int nitems;
79         int interruptible;
80         struct playtones_item *items;
81 };
82
83 struct playtones_state {
84         int vol;
85         int v1_1;
86         int v2_1;
87         int v3_1;
88         int v1_2;
89         int v2_2;
90         int v3_2;
91         int reppos;
92         int nitems;
93         struct playtones_item *items;
94         int npos;
95         int oldnpos;
96         int pos;
97         int origwfmt;
98         struct ast_frame f;
99         unsigned char offset[AST_FRIENDLY_OFFSET];
100         short data[4000];
101 };
102
103 static void playtones_release(struct ast_channel *chan, void *params)
104 {
105         struct playtones_state *ps = params;
106         if (chan) {
107                 ast_set_write_format(chan, ps->origwfmt);
108         }
109         if (ps->items) free(ps->items);
110         free(ps);
111 }
112
113 static void * playtones_alloc(struct ast_channel *chan, void *params)
114 {
115         struct playtones_def *pd = params;
116         struct playtones_state *ps;
117         if (!(ps = ast_calloc(1, sizeof(*ps))))
118                 return NULL;
119         ps->origwfmt = chan->writeformat;
120         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
121                 ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
122                 playtones_release(NULL, ps);
123                 ps = NULL;
124         } else {
125                 ps->vol = pd->vol;
126                 ps->reppos = pd->reppos;
127                 ps->nitems = pd->nitems;
128                 ps->items = pd->items;
129                 ps->oldnpos = -1;
130         }
131         /* Let interrupts interrupt :) */
132         if (pd->interruptible)
133                 ast_set_flag(chan, AST_FLAG_WRITE_INT);
134         else
135                 ast_clear_flag(chan, AST_FLAG_WRITE_INT);
136         return ps;
137 }
138
139 static int playtones_generator(struct ast_channel *chan, void *data, int len, int samples)
140 {
141         struct playtones_state *ps = data;
142         struct playtones_item *pi;
143         int x;
144         /* we need to prepare a frame with 16 * timelen samples as we're 
145          * generating SLIN audio
146          */
147         len = samples * 2;
148         if (len > sizeof(ps->data) / 2 - 1) {
149                 ast_log(LOG_WARNING, "Can't generate that much data!\n");
150                 return -1;
151         }
152         memset(&ps->f, 0, sizeof(ps->f));
153
154         pi = &ps->items[ps->npos];
155         if (ps->oldnpos != ps->npos) {
156                 /* Load new parameters */
157                 ps->v1_1 = 0;
158                 ps->v2_1 = pi->init_v2_1;
159                 ps->v3_1 = pi->init_v3_1;
160                 ps->v1_2 = 0;
161                 ps->v2_2 = pi->init_v2_2;
162                 ps->v3_2 = pi->init_v3_2;
163                 ps->oldnpos = ps->npos;
164         }
165         for (x=0;x<len/2;x++) {
166                 ps->v1_1 = ps->v2_1;
167                 ps->v2_1 = ps->v3_1;
168                 ps->v3_1 = (pi->fac1 * ps->v2_1 >> 15) - ps->v1_1;
169                 
170                 ps->v1_2 = ps->v2_2;
171                 ps->v2_2 = ps->v3_2;
172                 ps->v3_2 = (pi->fac2 * ps->v2_2 >> 15) - ps->v1_2;
173                 if (pi->modulate) {
174                         int p;
175                         p = ps->v3_2 - 32768;
176                         if (p < 0) p = -p;
177                         p = ((p * 9) / 10) + 1;
178                         ps->data[x] = (ps->v3_1 * p) >> 15;
179                 } else
180                         ps->data[x] = ps->v3_1 + ps->v3_2; 
181         }
182         
183         ps->f.frametype = AST_FRAME_VOICE;
184         ps->f.subclass = AST_FORMAT_SLINEAR;
185         ps->f.datalen = len;
186         ps->f.samples = samples;
187         ps->f.offset = AST_FRIENDLY_OFFSET;
188         ps->f.data = ps->data;
189         ps->f.delivery.tv_sec = 0;
190         ps->f.delivery.tv_usec = 0;
191         ast_write(chan, &ps->f);
192
193         ps->pos += x;
194         if (pi->duration && ps->pos >= pi->duration * 8) {      /* item finished? */
195                 ps->pos = 0;                                    /* start new item */
196                 ps->npos++;
197                 if (ps->npos >= ps->nitems) {                   /* last item? */
198                         if (ps->reppos == -1)                   /* repeat set? */
199                                 return -1;
200                         ps->npos = ps->reppos;                  /* redo from top */
201                 }
202         }
203         return 0;
204 }
205
206 static struct ast_generator playtones = {
207         alloc: playtones_alloc,
208         release: playtones_release,
209         generate: playtones_generator,
210 };
211
212 int ast_playtones_start(struct ast_channel *chan, int vol, const char *playlst, int interruptible)
213 {
214         char *s, *data = ast_strdupa(playlst); /* cute */
215         struct playtones_def d = { vol, -1, 0, 1, NULL};
216         char *stringp=NULL;
217         char *separator;
218         if (!data)
219                 return -1;
220         if (vol < 1)
221                 d.vol = 7219; /* Default to -8db */
222
223         d.interruptible = interruptible;
224         
225         stringp=data;
226         /* the stringp/data is not null here */
227         /* check if the data is separated with '|' or with ',' by default */
228         if (strchr(stringp,'|'))
229                 separator = "|";
230         else
231                 separator = ",";
232         s = strsep(&stringp,separator);
233         while (s && *s) {
234                 int freq1, freq2, time, modulate=0, midinote=0;
235
236                 if (s[0]=='!')
237                         s++;
238                 else if (d.reppos == -1)
239                         d.reppos = d.nitems;
240                 if (sscanf(s, "%d+%d/%d", &freq1, &freq2, &time) == 3) {
241                         /* f1+f2/time format */
242                 } else if (sscanf(s, "%d+%d", &freq1, &freq2) == 2) {
243                         /* f1+f2 format */
244                         time = 0;
245                 } else if (sscanf(s, "%d*%d/%d", &freq1, &freq2, &time) == 3) {
246                         /* f1*f2/time format */
247                         modulate = 1;
248                 } else if (sscanf(s, "%d*%d", &freq1, &freq2) == 2) {
249                         /* f1*f2 format */
250                         time = 0;
251                         modulate = 1;
252                 } else if (sscanf(s, "%d/%d", &freq1, &time) == 2) {
253                         /* f1/time format */
254                         freq2 = 0;
255                 } else if (sscanf(s, "%d", &freq1) == 1) {
256                         /* f1 format */
257                         freq2 = 0;
258                         time = 0;
259                 } else if (sscanf(s, "M%d+M%d/%d", &freq1, &freq2, &time) == 3) {
260                         /* Mf1+Mf2/time format */
261                         midinote = 1;
262                 } else if (sscanf(s, "M%d+M%d", &freq1, &freq2) == 2) {
263                         /* Mf1+Mf2 format */
264                         time = 0;
265                         midinote = 1;
266                 } else if (sscanf(s, "M%d*M%d/%d", &freq1, &freq2, &time) == 3) {
267                         /* Mf1*Mf2/time format */
268                         modulate = 1;
269                         midinote = 1;
270                 } else if (sscanf(s, "M%d*M%d", &freq1, &freq2) == 2) {
271                         /* Mf1*Mf2 format */
272                         time = 0;
273                         modulate = 1;
274                         midinote = 1;
275                 } else if (sscanf(s, "M%d/%d", &freq1, &time) == 2) {
276                         /* Mf1/time format */
277                         freq2 = -1;
278                         midinote = 1;
279                 } else if (sscanf(s, "M%d", &freq1) == 1) {
280                         /* Mf1 format */
281                         freq2 = -1;
282                         time = 0;
283                         midinote = 1;
284                 } else {
285                         ast_log(LOG_WARNING,"%s: tone component '%s' of '%s' is no good\n",chan->name,s,playlst);
286                         return -1;
287                 }
288
289                 if (midinote) {
290                         /* midi notes must be between 0 and 127 */
291                         if ((freq1 >= 0) && (freq1 <= 127))
292                                 freq1 = midi_tohz[freq1];
293                         else
294                                 freq1 = 0;
295
296                         if ((freq2 >= 0) && (freq2 <= 127))
297                                 freq2 = midi_tohz[freq2];
298                         else
299                                 freq2 = 0;
300                 }
301
302                 if (!(d.items = ast_realloc(d.items, (d.nitems + 1) * sizeof(*d.items)))) {
303                         return -1;
304                 }
305                 d.items[d.nitems].fac1 = 2.0 * cos(2.0 * M_PI * (freq1 / 8000.0)) * 32768.0;
306                 d.items[d.nitems].init_v2_1 = sin(-4.0 * M_PI * (freq1 / 8000.0)) * d.vol;
307                 d.items[d.nitems].init_v3_1 = sin(-2.0 * M_PI * (freq1 / 8000.0)) * d.vol;
308
309                 d.items[d.nitems].fac2 = 2.0 * cos(2.0 * M_PI * (freq2 / 8000.0)) * 32768.0;
310                 d.items[d.nitems].init_v2_2 = sin(-4.0 * M_PI * (freq2 / 8000.0)) * d.vol;
311                 d.items[d.nitems].init_v3_2 = sin(-2.0 * M_PI * (freq2 / 8000.0)) * d.vol;
312                 d.items[d.nitems].duration = time;
313                 d.items[d.nitems].modulate = modulate;
314                 d.nitems++;
315
316                 s = strsep(&stringp,separator);
317         }
318
319         if (ast_activate_generator(chan, &playtones, &d)) {
320                 free(d.items);
321                 return -1;
322         }
323         return 0;
324 }
325
326 void ast_playtones_stop(struct ast_channel *chan)
327 {
328         ast_deactivate_generator(chan);
329 }
330
331 /*--------------------------------------------*/
332
333 static struct tone_zone *tone_zones;
334 static struct tone_zone *current_tonezone;
335
336 /* Protect the tone_zones list (highly unlikely that two things would change
337  * it at the same time, but still! */
338 AST_MUTEX_DEFINE_STATIC(tzlock);
339
340 struct tone_zone *ast_walk_indications(const struct tone_zone *cur)
341 {
342         struct tone_zone *tz;
343
344         if (cur == NULL)
345                 return tone_zones;
346         ast_mutex_lock(&tzlock);
347         for (tz = tone_zones; tz; tz = tz->next)
348                 if (tz == cur)
349                         break;
350         if (tz)
351                 tz = tz->next;
352         ast_mutex_unlock(&tzlock);
353         return tz;
354 }
355
356 /* Set global indication country */
357 int ast_set_indication_country(const char *country)
358 {
359         if (country) {
360                 struct tone_zone *z = ast_get_indication_zone(country);
361                 if (z) {
362                         if (option_verbose > 2)
363                                 ast_verbose(VERBOSE_PREFIX_3 "Setting default indication country to '%s'\n",country);
364                         current_tonezone = z;
365                         return 0;
366                 }
367         }
368         return 1; /* not found */
369 }
370
371 /* locate tone_zone, given the country. if country == NULL, use the default country */
372 struct tone_zone *ast_get_indication_zone(const char *country)
373 {
374         struct tone_zone *tz;
375         int alias_loop = 0;
376
377         /* we need some tonezone, pick the first */
378         if (country == NULL && current_tonezone)
379                 return current_tonezone;        /* default country? */
380         if (country == NULL && tone_zones)
381                 return tone_zones;              /* any country? */
382         if (country == NULL)
383                 return 0;       /* not a single country insight */
384
385         if (ast_mutex_lock(&tzlock)) {
386                 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
387                 return 0;
388         }
389         do {
390                 for (tz=tone_zones; tz; tz=tz->next) {
391                         if (strcasecmp(country,tz->country)==0) {
392                                 /* tone_zone found */
393                                 if (tz->alias && tz->alias[0]) {
394                                         country = tz->alias;
395                                         break;
396                                 }
397                                 ast_mutex_unlock(&tzlock);
398                                 return tz;
399                         }
400                 }
401         } while (++alias_loop<20 && tz);
402         ast_mutex_unlock(&tzlock);
403         if (alias_loop==20)
404                 ast_log(LOG_NOTICE,"Alias loop for '%s' forcefull broken\n",country);
405         /* nothing found, sorry */
406         return 0;
407 }
408
409 /* locate a tone_zone_sound, given the tone_zone. if tone_zone == NULL, use the default tone_zone */
410 struct tone_zone_sound *ast_get_indication_tone(const struct tone_zone *zone, const char *indication)
411 {
412         struct tone_zone_sound *ts;
413
414         /* we need some tonezone, pick the first */
415         if (zone == NULL && current_tonezone)
416                 zone = current_tonezone;        /* default country? */
417         if (zone == NULL && tone_zones)
418                 zone = tone_zones;              /* any country? */
419         if (zone == NULL)
420                 return 0;       /* not a single country insight */
421
422         if (ast_mutex_lock(&tzlock)) {
423                 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
424                 return 0;
425         }
426         for (ts=zone->tones; ts; ts=ts->next) {
427                 if (strcasecmp(indication,ts->name)==0) {
428                         /* found indication! */
429                         ast_mutex_unlock(&tzlock);
430                         return ts;
431                 }
432         }
433         /* nothing found, sorry */
434         ast_mutex_unlock(&tzlock);
435         return 0;
436 }
437
438 /* helper function to delete a tone_zone in its entirety */
439 static inline void free_zone(struct tone_zone* zone)
440 {
441         while (zone->tones) {
442                 struct tone_zone_sound *tmp = zone->tones->next;
443                 free((void*)zone->tones->name);
444                 free((void*)zone->tones->data);
445                 free(zone->tones);
446                 zone->tones = tmp;
447         }
448         if (zone->ringcadence)
449                 free(zone->ringcadence);
450         free(zone);
451 }
452
453 /*--------------------------------------------*/
454
455 /* add a new country, if country exists, it will be replaced. */
456 int ast_register_indication_country(struct tone_zone *zone)
457 {
458         struct tone_zone *tz,*pz;
459
460         if (ast_mutex_lock(&tzlock)) {
461                 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
462                 return -1;
463         }
464         for (pz=NULL,tz=tone_zones; tz; pz=tz,tz=tz->next) {
465                 if (strcasecmp(zone->country,tz->country)==0) {
466                         /* tone_zone already there, replace */
467                         zone->next = tz->next;
468                         if (pz)
469                                 pz->next = zone;
470                         else
471                                 tone_zones = zone;
472                         /* if we are replacing the default zone, re-point it */
473                         if (tz == current_tonezone)
474                                 current_tonezone = zone;
475                         /* now free the previous zone */
476                         free_zone(tz);
477                         ast_mutex_unlock(&tzlock);
478                         return 0;
479                 }
480         }
481         /* country not there, add */
482         zone->next = NULL;
483         if (pz)
484                 pz->next = zone;
485         else
486                 tone_zones = zone;
487         ast_mutex_unlock(&tzlock);
488
489         if (option_verbose > 2)
490                 ast_verbose(VERBOSE_PREFIX_3 "Registered indication country '%s'\n",zone->country);
491         return 0;
492 }
493
494 /* remove an existing country and all its indications, country must exist.
495  * Also, all countries which are an alias for the specified country are removed. */
496 int ast_unregister_indication_country(const char *country)
497 {
498         struct tone_zone *tz, *pz = NULL, *tmp;
499         int res = -1;
500
501         if (ast_mutex_lock(&tzlock)) {
502                 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
503                 return -1;
504         }
505         tz = tone_zones;
506         while (tz) {
507                 if (country==NULL ||
508                     (strcasecmp(country, tz->country)==0 ||
509                      strcasecmp(country, tz->alias)==0)) {
510                         /* tone_zone found, remove */
511                         tmp = tz->next;
512                         if (pz)
513                                 pz->next = tmp;
514                         else
515                                 tone_zones = tmp;
516                         /* if we are unregistering the default country, w'll notice */
517                         if (tz == current_tonezone) {
518                                 ast_log(LOG_NOTICE,"Removed default indication country '%s'\n",tz->country);
519                                 current_tonezone = NULL;
520                         }
521                         if (option_verbose > 2)
522                                 ast_verbose(VERBOSE_PREFIX_3 "Unregistered indication country '%s'\n",tz->country);
523                         free_zone(tz);
524                         if (tone_zones == tz)
525                                 tone_zones = tmp;
526                         tz = tmp;
527                         res = 0;
528                 }
529                 else {
530                         /* next zone please */
531                         pz = tz;
532                         tz = tz->next;
533                 }
534         }
535         ast_mutex_unlock(&tzlock);
536         return res;
537 }
538
539 /* add a new indication to a tone_zone. tone_zone must exist. if the indication already
540  * exists, it will be replaced. */
541 int ast_register_indication(struct tone_zone *zone, const char *indication, const char *tonelist)
542 {
543         struct tone_zone_sound *ts,*ps;
544
545         /* is it an alias? stop */
546         if (zone->alias[0])
547                 return -1;
548
549         if (ast_mutex_lock(&tzlock)) {
550                 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
551                 return -2;
552         }
553         for (ps=NULL,ts=zone->tones; ts; ps=ts,ts=ts->next) {
554                 if (strcasecmp(indication,ts->name)==0) {
555                         /* indication already there, replace */
556                         free((void*)ts->name);
557                         free((void*)ts->data);
558                         break;
559                 }
560         }
561         if (!ts) {
562                 /* not there, we have to add */
563                 if (!(ts = ast_malloc(sizeof(*ts)))) {
564                         ast_mutex_unlock(&tzlock);
565                         return -2;
566                 }
567                 ts->next = NULL;
568         }
569         if (!(ts->name = ast_strdup(indication)) || !(ts->data = ast_strdup(tonelist))) {
570                 ast_mutex_unlock(&tzlock);
571                 return -2;
572         }
573         if (ps)
574                 ps->next = ts;
575         else
576                 zone->tones = ts;
577         ast_mutex_unlock(&tzlock);
578         return 0;
579 }
580
581 /* remove an existing country's indication. Both country and indication must exist */
582 int ast_unregister_indication(struct tone_zone *zone, const char *indication)
583 {
584         struct tone_zone_sound *ts,*ps = NULL, *tmp;
585         int res = -1;
586
587         /* is it an alias? stop */
588         if (zone->alias[0])
589                 return -1;
590
591         if (ast_mutex_lock(&tzlock)) {
592                 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
593                 return -1;
594         }
595         ts = zone->tones;
596         while (ts) {
597                 if (strcasecmp(indication,ts->name)==0) {
598                         /* indication found */
599                         tmp = ts->next;
600                         if (ps)
601                                 ps->next = tmp;
602                         else
603                                 zone->tones = tmp;
604                         free((void*)ts->name);
605                         free((void*)ts->data);
606                         free(ts);
607                         ts = tmp;
608                         res = 0;
609                 }
610                 else {
611                         /* next zone please */
612                         ps = ts;
613                         ts = ts->next;
614                 }
615         }
616         /* indication not found, goodbye */
617         ast_mutex_unlock(&tzlock);
618         return res;
619 }