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