00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "asterisk.h"
00032
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 122314 $")
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include <math.h>
00039
00040 #include "asterisk/indications.h"
00041 #include "asterisk/frame.h"
00042 #include "asterisk/options.h"
00043 #include "asterisk/channel.h"
00044 #include "asterisk/logger.h"
00045 #include "asterisk/lock.h"
00046 #include "asterisk/utils.h"
00047
00048 static int midi_tohz[128] = {
00049 8,8,9,9,10,10,11,12,12,13,14,
00050 15,16,17,18,19,20,21,23,24,25,
00051 27,29,30,32,34,36,38,41,43,46,
00052 48,51,55,58,61,65,69,73,77,82,
00053 87,92,97,103,110,116,123,130,138,146,
00054 155,164,174,184,195,207,220,233,246,261,
00055 277,293,311,329,349,369,391,415,440,466,
00056 493,523,554,587,622,659,698,739,783,830,
00057 880,932,987,1046,1108,1174,1244,1318,1396,1479,
00058 1567,1661,1760,1864,1975,2093,2217,2349,2489,2637,
00059 2793,2959,3135,3322,3520,3729,3951,4186,4434,4698,
00060 4978,5274,5587,5919,6271,6644,7040,7458,7902,8372,
00061 8869,9397,9956,10548,11175,11839,12543
00062 };
00063
00064 struct playtones_item {
00065 int fac1;
00066 int init_v2_1;
00067 int init_v3_1;
00068 int fac2;
00069 int init_v2_2;
00070 int init_v3_2;
00071 int modulate;
00072 int duration;
00073 };
00074
00075 struct playtones_def {
00076 int vol;
00077 int reppos;
00078 int nitems;
00079 int interruptible;
00080 struct playtones_item *items;
00081 };
00082
00083 struct playtones_state {
00084 int vol;
00085 int v1_1;
00086 int v2_1;
00087 int v3_1;
00088 int v1_2;
00089 int v2_2;
00090 int v3_2;
00091 int reppos;
00092 int nitems;
00093 struct playtones_item *items;
00094 int npos;
00095 int oldnpos;
00096 int pos;
00097 int origwfmt;
00098 struct ast_frame f;
00099 unsigned char offset[AST_FRIENDLY_OFFSET];
00100 short data[4000];
00101 };
00102
00103 static void playtones_release(struct ast_channel *chan, void *params)
00104 {
00105 struct playtones_state *ps = params;
00106 if (chan) {
00107 ast_set_write_format(chan, ps->origwfmt);
00108 }
00109 if (ps->items) free(ps->items);
00110 free(ps);
00111 }
00112
00113 static void * playtones_alloc(struct ast_channel *chan, void *params)
00114 {
00115 struct playtones_def *pd = params;
00116 struct playtones_state *ps;
00117 if (!(ps = ast_calloc(1, sizeof(*ps))))
00118 return NULL;
00119 ps->origwfmt = chan->writeformat;
00120 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00121 ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
00122 playtones_release(NULL, ps);
00123 ps = NULL;
00124 } else {
00125 ps->vol = pd->vol;
00126 ps->reppos = pd->reppos;
00127 ps->nitems = pd->nitems;
00128 ps->items = pd->items;
00129 ps->oldnpos = -1;
00130 }
00131
00132 if (pd->interruptible)
00133 ast_set_flag(chan, AST_FLAG_WRITE_INT);
00134 else
00135 ast_clear_flag(chan, AST_FLAG_WRITE_INT);
00136 return ps;
00137 }
00138
00139 static int playtones_generator(struct ast_channel *chan, void *data, int len, int samples)
00140 {
00141 struct playtones_state *ps = data;
00142 struct playtones_item *pi;
00143 int x;
00144
00145
00146
00147 len = samples * 2;
00148 if (len > sizeof(ps->data) / 2 - 1) {
00149 ast_log(LOG_WARNING, "Can't generate that much data!\n");
00150 return -1;
00151 }
00152 memset(&ps->f, 0, sizeof(ps->f));
00153
00154 pi = &ps->items[ps->npos];
00155 if (ps->oldnpos != ps->npos) {
00156
00157 ps->v1_1 = 0;
00158 ps->v2_1 = pi->init_v2_1;
00159 ps->v3_1 = pi->init_v3_1;
00160 ps->v1_2 = 0;
00161 ps->v2_2 = pi->init_v2_2;
00162 ps->v3_2 = pi->init_v3_2;
00163 ps->oldnpos = ps->npos;
00164 }
00165 for (x=0;x<len/2;x++) {
00166 ps->v1_1 = ps->v2_1;
00167 ps->v2_1 = ps->v3_1;
00168 ps->v3_1 = (pi->fac1 * ps->v2_1 >> 15) - ps->v1_1;
00169
00170 ps->v1_2 = ps->v2_2;
00171 ps->v2_2 = ps->v3_2;
00172 ps->v3_2 = (pi->fac2 * ps->v2_2 >> 15) - ps->v1_2;
00173 if (pi->modulate) {
00174 int p;
00175 p = ps->v3_2 - 32768;
00176 if (p < 0) p = -p;
00177 p = ((p * 9) / 10) + 1;
00178 ps->data[x] = (ps->v3_1 * p) >> 15;
00179 } else
00180 ps->data[x] = ps->v3_1 + ps->v3_2;
00181 }
00182
00183 ps->f.frametype = AST_FRAME_VOICE;
00184 ps->f.subclass = AST_FORMAT_SLINEAR;
00185 ps->f.datalen = len;
00186 ps->f.samples = samples;
00187 ps->f.offset = AST_FRIENDLY_OFFSET;
00188 ps->f.data = ps->data;
00189 ps->f.delivery.tv_sec = 0;
00190 ps->f.delivery.tv_usec = 0;
00191 ast_write(chan, &ps->f);
00192
00193 ps->pos += x;
00194 if (pi->duration && ps->pos >= pi->duration * 8) {
00195 ps->pos = 0;
00196 ps->npos++;
00197 if (ps->npos >= ps->nitems) {
00198 if (ps->reppos == -1)
00199 return -1;
00200 ps->npos = ps->reppos;
00201 }
00202 }
00203 return 0;
00204 }
00205
00206 static struct ast_generator playtones = {
00207 alloc: playtones_alloc,
00208 release: playtones_release,
00209 generate: playtones_generator,
00210 };
00211
00212 int ast_playtones_start(struct ast_channel *chan, int vol, const char *playlst, int interruptible)
00213 {
00214 char *s, *data = ast_strdupa(playlst);
00215 struct playtones_def d = { vol, -1, 0, 1, NULL};
00216 char *stringp;
00217 char *separator;
00218
00219 if (vol < 1)
00220 d.vol = 7219;
00221
00222 d.interruptible = interruptible;
00223
00224 stringp=data;
00225
00226
00227 if (strchr(stringp,'|'))
00228 separator = "|";
00229 else
00230 separator = ",";
00231 s = strsep(&stringp,separator);
00232 while (s && *s) {
00233 int freq1, freq2, time, modulate=0, midinote=0;
00234
00235 if (s[0]=='!')
00236 s++;
00237 else if (d.reppos == -1)
00238 d.reppos = d.nitems;
00239 if (sscanf(s, "%d+%d/%d", &freq1, &freq2, &time) == 3) {
00240
00241 } else if (sscanf(s, "%d+%d", &freq1, &freq2) == 2) {
00242
00243 time = 0;
00244 } else if (sscanf(s, "%d*%d/%d", &freq1, &freq2, &time) == 3) {
00245
00246 modulate = 1;
00247 } else if (sscanf(s, "%d*%d", &freq1, &freq2) == 2) {
00248
00249 time = 0;
00250 modulate = 1;
00251 } else if (sscanf(s, "%d/%d", &freq1, &time) == 2) {
00252
00253 freq2 = 0;
00254 } else if (sscanf(s, "%d", &freq1) == 1) {
00255
00256 freq2 = 0;
00257 time = 0;
00258 } else if (sscanf(s, "M%d+M%d/%d", &freq1, &freq2, &time) == 3) {
00259
00260 midinote = 1;
00261 } else if (sscanf(s, "M%d+M%d", &freq1, &freq2) == 2) {
00262
00263 time = 0;
00264 midinote = 1;
00265 } else if (sscanf(s, "M%d*M%d/%d", &freq1, &freq2, &time) == 3) {
00266
00267 modulate = 1;
00268 midinote = 1;
00269 } else if (sscanf(s, "M%d*M%d", &freq1, &freq2) == 2) {
00270
00271 time = 0;
00272 modulate = 1;
00273 midinote = 1;
00274 } else if (sscanf(s, "M%d/%d", &freq1, &time) == 2) {
00275
00276 freq2 = -1;
00277 midinote = 1;
00278 } else if (sscanf(s, "M%d", &freq1) == 1) {
00279
00280 freq2 = -1;
00281 time = 0;
00282 midinote = 1;
00283 } else {
00284 ast_log(LOG_WARNING,"%s: tone component '%s' of '%s' is no good\n",chan->name,s,playlst);
00285 return -1;
00286 }
00287
00288 if (midinote) {
00289
00290 if ((freq1 >= 0) && (freq1 <= 127))
00291 freq1 = midi_tohz[freq1];
00292 else
00293 freq1 = 0;
00294
00295 if ((freq2 >= 0) && (freq2 <= 127))
00296 freq2 = midi_tohz[freq2];
00297 else
00298 freq2 = 0;
00299 }
00300
00301 if (!(d.items = ast_realloc(d.items, (d.nitems + 1) * sizeof(*d.items)))) {
00302 return -1;
00303 }
00304 d.items[d.nitems].fac1 = 2.0 * cos(2.0 * M_PI * (freq1 / 8000.0)) * 32768.0;
00305 d.items[d.nitems].init_v2_1 = sin(-4.0 * M_PI * (freq1 / 8000.0)) * d.vol;
00306 d.items[d.nitems].init_v3_1 = sin(-2.0 * M_PI * (freq1 / 8000.0)) * d.vol;
00307
00308 d.items[d.nitems].fac2 = 2.0 * cos(2.0 * M_PI * (freq2 / 8000.0)) * 32768.0;
00309 d.items[d.nitems].init_v2_2 = sin(-4.0 * M_PI * (freq2 / 8000.0)) * d.vol;
00310 d.items[d.nitems].init_v3_2 = sin(-2.0 * M_PI * (freq2 / 8000.0)) * d.vol;
00311 d.items[d.nitems].duration = time;
00312 d.items[d.nitems].modulate = modulate;
00313 d.nitems++;
00314
00315 s = strsep(&stringp,separator);
00316 }
00317
00318 if (ast_activate_generator(chan, &playtones, &d)) {
00319 free(d.items);
00320 return -1;
00321 }
00322 return 0;
00323 }
00324
00325 void ast_playtones_stop(struct ast_channel *chan)
00326 {
00327 ast_deactivate_generator(chan);
00328 }
00329
00330
00331
00332 static struct ind_tone_zone *ind_tone_zones;
00333 static struct ind_tone_zone *current_tonezone;
00334
00335
00336
00337 AST_MUTEX_DEFINE_STATIC(tzlock);
00338
00339 struct ind_tone_zone *ast_walk_indications(const struct ind_tone_zone *cur)
00340 {
00341 struct ind_tone_zone *tz;
00342
00343 if (cur == NULL)
00344 return ind_tone_zones;
00345 ast_mutex_lock(&tzlock);
00346 for (tz = ind_tone_zones; tz; tz = tz->next)
00347 if (tz == cur)
00348 break;
00349 if (tz)
00350 tz = tz->next;
00351 ast_mutex_unlock(&tzlock);
00352 return tz;
00353 }
00354
00355
00356 int ast_set_indication_country(const char *country)
00357 {
00358 if (country) {
00359 struct ind_tone_zone *z = ast_get_indication_zone(country);
00360 if (z) {
00361 if (option_verbose > 2)
00362 ast_verbose(VERBOSE_PREFIX_3 "Setting default indication country to '%s'\n",country);
00363 current_tonezone = z;
00364 return 0;
00365 }
00366 }
00367 return 1;
00368 }
00369
00370
00371 struct ind_tone_zone *ast_get_indication_zone(const char *country)
00372 {
00373 struct ind_tone_zone *tz;
00374 int alias_loop = 0;
00375
00376
00377 if (country == NULL && current_tonezone)
00378 return current_tonezone;
00379 if (country == NULL && ind_tone_zones)
00380 return ind_tone_zones;
00381 if (country == NULL)
00382 return 0;
00383
00384 ast_mutex_lock(&tzlock);
00385 do {
00386 for (tz=ind_tone_zones; tz; tz=tz->next) {
00387 if (strcasecmp(country,tz->country)==0) {
00388
00389 if (tz->alias && tz->alias[0]) {
00390 country = tz->alias;
00391 break;
00392 }
00393 ast_mutex_unlock(&tzlock);
00394 return tz;
00395 }
00396 }
00397 } while (++alias_loop<20 && tz);
00398 ast_mutex_unlock(&tzlock);
00399 if (alias_loop==20)
00400 ast_log(LOG_NOTICE,"Alias loop for '%s' forcefull broken\n",country);
00401
00402 return 0;
00403 }
00404
00405
00406 struct ind_tone_zone_sound *ast_get_indication_tone(const struct ind_tone_zone *zone, const char *indication)
00407 {
00408 struct ind_tone_zone_sound *ts;
00409
00410
00411 if (zone == NULL && current_tonezone)
00412 zone = current_tonezone;
00413 if (zone == NULL && ind_tone_zones)
00414 zone = ind_tone_zones;
00415 if (zone == NULL)
00416 return 0;
00417
00418 ast_mutex_lock(&tzlock);
00419 for (ts=zone->tones; ts; ts=ts->next) {
00420 if (strcasecmp(indication,ts->name)==0) {
00421
00422 ast_mutex_unlock(&tzlock);
00423 return ts;
00424 }
00425 }
00426
00427 ast_mutex_unlock(&tzlock);
00428 return 0;
00429 }
00430
00431
00432 static inline void free_zone(struct ind_tone_zone* zone)
00433 {
00434 while (zone->tones) {
00435 struct ind_tone_zone_sound *tmp = zone->tones->next;
00436 free((void*)zone->tones->name);
00437 free((void*)zone->tones->data);
00438 free(zone->tones);
00439 zone->tones = tmp;
00440 }
00441 if (zone->ringcadence)
00442 free(zone->ringcadence);
00443 free(zone);
00444 }
00445
00446
00447
00448
00449 int ast_register_indication_country(struct ind_tone_zone *zone)
00450 {
00451 struct ind_tone_zone *tz,*pz;
00452
00453 ast_mutex_lock(&tzlock);
00454 for (pz=NULL,tz=ind_tone_zones; tz; pz=tz,tz=tz->next) {
00455 if (strcasecmp(zone->country,tz->country)==0) {
00456
00457 zone->next = tz->next;
00458 if (pz)
00459 pz->next = zone;
00460 else
00461 ind_tone_zones = zone;
00462
00463 if (tz == current_tonezone)
00464 current_tonezone = zone;
00465
00466 free_zone(tz);
00467 ast_mutex_unlock(&tzlock);
00468 return 0;
00469 }
00470 }
00471
00472 zone->next = NULL;
00473 if (pz)
00474 pz->next = zone;
00475 else
00476 ind_tone_zones = zone;
00477 ast_mutex_unlock(&tzlock);
00478
00479 if (option_verbose > 2)
00480 ast_verbose(VERBOSE_PREFIX_3 "Registered indication country '%s'\n",zone->country);
00481 return 0;
00482 }
00483
00484
00485
00486 int ast_unregister_indication_country(const char *country)
00487 {
00488 struct ind_tone_zone *tz, *pz = NULL, *tmp;
00489 int res = -1;
00490
00491 ast_mutex_lock(&tzlock);
00492 tz = ind_tone_zones;
00493 while (tz) {
00494 if (country==NULL ||
00495 (strcasecmp(country, tz->country)==0 ||
00496 strcasecmp(country, tz->alias)==0)) {
00497
00498 tmp = tz->next;
00499 if (pz)
00500 pz->next = tmp;
00501 else
00502 ind_tone_zones = tmp;
00503
00504 if (tz == current_tonezone) {
00505 ast_log(LOG_NOTICE,"Removed default indication country '%s'\n",tz->country);
00506 current_tonezone = NULL;
00507 }
00508 if (option_verbose > 2)
00509 ast_verbose(VERBOSE_PREFIX_3 "Unregistered indication country '%s'\n",tz->country);
00510 free_zone(tz);
00511 if (ind_tone_zones == tz)
00512 ind_tone_zones = tmp;
00513 tz = tmp;
00514 res = 0;
00515 }
00516 else {
00517
00518 pz = tz;
00519 tz = tz->next;
00520 }
00521 }
00522 ast_mutex_unlock(&tzlock);
00523 return res;
00524 }
00525
00526
00527
00528 int ast_register_indication(struct ind_tone_zone *zone, const char *indication, const char *tonelist)
00529 {
00530 struct ind_tone_zone_sound *ts,*ps;
00531
00532
00533 if (zone->alias[0])
00534 return -1;
00535
00536 ast_mutex_lock(&tzlock);
00537 for (ps=NULL,ts=zone->tones; ts; ps=ts,ts=ts->next) {
00538 if (strcasecmp(indication,ts->name)==0) {
00539
00540 free((void*)ts->name);
00541 free((void*)ts->data);
00542 break;
00543 }
00544 }
00545 if (!ts) {
00546
00547 if (!(ts = ast_malloc(sizeof(*ts)))) {
00548 ast_mutex_unlock(&tzlock);
00549 return -2;
00550 }
00551 ts->next = NULL;
00552 }
00553 if (!(ts->name = ast_strdup(indication)) || !(ts->data = ast_strdup(tonelist))) {
00554 ast_mutex_unlock(&tzlock);
00555 return -2;
00556 }
00557 if (ps)
00558 ps->next = ts;
00559 else
00560 zone->tones = ts;
00561 ast_mutex_unlock(&tzlock);
00562 return 0;
00563 }
00564
00565
00566 int ast_unregister_indication(struct ind_tone_zone *zone, const char *indication)
00567 {
00568 struct ind_tone_zone_sound *ts,*ps = NULL, *tmp;
00569 int res = -1;
00570
00571
00572 if (zone->alias[0])
00573 return -1;
00574
00575 ast_mutex_lock(&tzlock);
00576 ts = zone->tones;
00577 while (ts) {
00578 if (strcasecmp(indication,ts->name)==0) {
00579
00580 tmp = ts->next;
00581 if (ps)
00582 ps->next = tmp;
00583 else
00584 zone->tones = tmp;
00585 free((void*)ts->name);
00586 free((void*)ts->data);
00587 free(ts);
00588 ts = tmp;
00589 res = 0;
00590 }
00591 else {
00592
00593 ps = ts;
00594 ts = ts->next;
00595 }
00596 }
00597
00598 ast_mutex_unlock(&tzlock);
00599 return res;
00600 }