00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <pthread.h>
00022 #include <string.h>
00023 #include <math.h>
00024 #include <asterisk/indications.h>
00025 #include <asterisk/frame.h>
00026 #include <asterisk/options.h>
00027 #include <asterisk/channel.h>
00028 #include <asterisk/logger.h>
00029
00030 struct playtones_item {
00031 int freq1;
00032 int freq2;
00033 int duration;
00034 };
00035
00036 struct playtones_def {
00037 int vol;
00038 int reppos;
00039 int nitems;
00040 int interruptible;
00041 struct playtones_item *items;
00042 };
00043
00044 struct playtones_state {
00045 int vol;
00046 int reppos;
00047 int nitems;
00048 struct playtones_item *items;
00049 int npos;
00050 int pos;
00051 int origwfmt;
00052 struct ast_frame f;
00053 short data[4000];
00054 };
00055
00056 static void playtones_release(struct ast_channel *chan, void *params)
00057 {
00058 struct playtones_state *ps = params;
00059 if (chan) {
00060 ast_set_write_format(chan, ps->origwfmt);
00061 }
00062 if (ps->items) free(ps->items);
00063 free(ps);
00064 }
00065
00066 static void * playtones_alloc(struct ast_channel *chan, void *params)
00067 {
00068 struct playtones_def *pd = params;
00069 struct playtones_state *ps = malloc(sizeof(struct playtones_state));
00070 if (!ps)
00071 return NULL;
00072 memset(ps, 0, sizeof(struct playtones_state));
00073 ps->origwfmt = chan->writeformat;
00074 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00075 ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
00076 playtones_release(NULL, ps);
00077 ps = NULL;
00078 } else {
00079 ps->vol = pd->vol;
00080 ps->reppos = pd->reppos;
00081 ps->nitems = pd->nitems;
00082 ps->items = pd->items;
00083 }
00084
00085 chan->writeinterrupt = pd->interruptible;
00086 return ps;
00087 }
00088
00089 static int playtones_generator(struct ast_channel *chan, void *data, int len, int samples)
00090 {
00091 struct playtones_state *ps = data;
00092 struct playtones_item *pi;
00093 int x;
00094
00095
00096
00097 len = samples * 2;
00098 if (len > sizeof(ps->data) / 2 - 1) {
00099 ast_log(LOG_WARNING, "Can't generate that much data!\n");
00100 return -1;
00101 }
00102 memset(&ps->f, 0, sizeof(ps->f));
00103
00104 pi = &ps->items[ps->npos];
00105 for (x=0;x<len/2;x++) {
00106 ps->data[x] = ps->vol * (
00107 sin((pi->freq1 * 2.0 * M_PI / 8000.0) * (ps->pos + x)) +
00108 sin((pi->freq2 * 2.0 * M_PI / 8000.0) * (ps->pos + x))
00109 );
00110 }
00111 ps->f.frametype = AST_FRAME_VOICE;
00112 ps->f.subclass = AST_FORMAT_SLINEAR;
00113 ps->f.datalen = len;
00114 ps->f.samples = samples;
00115 ps->f.offset = AST_FRIENDLY_OFFSET;
00116 ps->f.data = ps->data;
00117 ast_write(chan, &ps->f);
00118
00119 ps->pos += x;
00120 if (pi->duration && ps->pos >= pi->duration * 8) {
00121 ps->pos = 0;
00122 ps->npos++;
00123 if (ps->npos >= ps->nitems) {
00124 if (ps->reppos == -1)
00125 return -1;
00126 ps->npos = ps->reppos;
00127 }
00128 }
00129 return 0;
00130 }
00131
00132 static struct ast_generator playtones = {
00133 alloc: playtones_alloc,
00134 release: playtones_release,
00135 generate: playtones_generator,
00136 };
00137
00138 int ast_playtones_start(struct ast_channel *chan, int vol, const char *playlst, int interruptible)
00139 {
00140 char *s, *data = ast_strdupa(playlst);
00141 struct playtones_def d = { vol, -1, 0, 1, NULL};
00142 char *stringp=NULL;
00143 char *separator;
00144 if (!data)
00145 return -1;
00146 if (vol < 1)
00147 d.vol = 8192;
00148
00149 d.interruptible = interruptible;
00150
00151 stringp=data;
00152
00153
00154 if (strchr(stringp,'|'))
00155 separator = "|";
00156 else
00157 separator = ",";
00158 s = strsep(&stringp,separator);
00159 while(s && *s) {
00160 int freq1, freq2, time;
00161
00162 if (s[0]=='!')
00163 s++;
00164 else if (d.reppos == -1)
00165 d.reppos = d.nitems;
00166 if (sscanf(s, "%d+%d/%d", &freq1, &freq2, &time) == 3) {
00167
00168 } else if (sscanf(s, "%d+%d", &freq1, &freq2) == 2) {
00169
00170 time = 0;
00171 } else if (sscanf(s, "%d/%d", &freq1, &time) == 2) {
00172
00173 freq2 = 0;
00174 } else if (sscanf(s, "%d", &freq1) == 1) {
00175
00176 freq2 = 0;
00177 time = 0;
00178 } else {
00179 ast_log(LOG_WARNING,"%s: tone component '%s' of '%s' is no good\n",chan->name,s,playlst);
00180 return -1;
00181 }
00182
00183 d.items = realloc(d.items,(d.nitems+1)*sizeof(struct playtones_item));
00184 if (d.items == NULL)
00185 return -1;
00186 d.items[d.nitems].freq1 = freq1;
00187 d.items[d.nitems].freq2 = freq2;
00188 d.items[d.nitems].duration = time;
00189 d.nitems++;
00190
00191 s = strsep(&stringp,separator);
00192 }
00193
00194 if (ast_activate_generator(chan, &playtones, &d)) {
00195 free(d.items);
00196 return -1;
00197 }
00198 return 0;
00199 }
00200
00201 void ast_playtones_stop(struct ast_channel *chan)
00202 {
00203 ast_deactivate_generator(chan);
00204 }
00205
00206
00207
00208 struct tone_zone *tone_zones;
00209 static struct tone_zone *current_tonezone;
00210
00211
00212
00213 ast_mutex_t tzlock = AST_MUTEX_INITIALIZER;
00214
00215
00216 int ast_set_indication_country(const char *country)
00217 {
00218 if (country) {
00219 struct tone_zone *z = ast_get_indication_zone(country);
00220 if (z) {
00221 ast_verbose(VERBOSE_PREFIX_3 "Setting default indication country to '%s'\n",country);
00222 current_tonezone = z;
00223 return 0;
00224 }
00225 }
00226 return 1;
00227 }
00228
00229
00230 struct tone_zone *ast_get_indication_zone(const char *country)
00231 {
00232 struct tone_zone *tz;
00233 int alias_loop = 0;
00234
00235
00236 if (country == NULL && current_tonezone)
00237 return current_tonezone;
00238 if (country == NULL && tone_zones)
00239 return tone_zones;
00240 if (country == NULL)
00241 return 0;
00242
00243 if (ast_mutex_lock(&tzlock)) {
00244 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
00245 return 0;
00246 }
00247 do {
00248 for (tz=tone_zones; tz; tz=tz->next) {
00249 if (strcasecmp(country,tz->country)==0) {
00250
00251 if (tz->alias && tz->alias[0]) {
00252 country = tz->alias;
00253 break;
00254 }
00255 ast_mutex_unlock(&tzlock);
00256 return tz;
00257 }
00258 }
00259 } while (++alias_loop<20 && tz);
00260 ast_mutex_unlock(&tzlock);
00261 if (alias_loop==20)
00262 ast_log(LOG_NOTICE,"Alias loop for '%s' forcefull broken\n",country);
00263
00264 return 0;
00265 }
00266
00267
00268 struct tone_zone_sound *ast_get_indication_tone(const struct tone_zone *zone, const char *indication)
00269 {
00270 struct tone_zone_sound *ts;
00271
00272
00273 if (zone == NULL && current_tonezone)
00274 zone = current_tonezone;
00275 if (zone == NULL && tone_zones)
00276 zone = tone_zones;
00277 if (zone == NULL)
00278 return 0;
00279
00280 if (ast_mutex_lock(&tzlock)) {
00281 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
00282 return 0;
00283 }
00284 for (ts=zone->tones; ts; ts=ts->next) {
00285 if (strcasecmp(indication,ts->name)==0) {
00286
00287 ast_mutex_unlock(&tzlock);
00288 return ts;
00289 }
00290 }
00291
00292 ast_mutex_unlock(&tzlock);
00293 return 0;
00294 }
00295
00296
00297 static inline void free_zone(struct tone_zone* zone)
00298 {
00299 while (zone->tones) {
00300 struct tone_zone_sound *tmp = zone->tones->next;
00301 free((void*)zone->tones->name);
00302 free((void*)zone->tones->data);
00303 free(zone->tones);
00304 zone->tones = tmp;
00305 }
00306 free(zone);
00307 }
00308
00309
00310
00311
00312 int ast_register_indication_country(struct tone_zone *zone)
00313 {
00314 struct tone_zone *tz,*pz;
00315
00316 if (ast_mutex_lock(&tzlock)) {
00317 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
00318 return -1;
00319 }
00320 for (pz=NULL,tz=tone_zones; tz; pz=tz,tz=tz->next) {
00321 if (strcasecmp(zone->country,tz->country)==0) {
00322
00323 zone->next = tz->next;
00324 if (pz)
00325 pz->next = zone;
00326 else
00327 tone_zones = zone;
00328
00329 if (tz == current_tonezone)
00330 current_tonezone = zone;
00331
00332 free_zone(tz);
00333 ast_mutex_unlock(&tzlock);
00334 return 0;
00335 }
00336 }
00337
00338 zone->next = NULL;
00339 if (pz)
00340 pz->next = zone;
00341 else
00342 tone_zones = zone;
00343 ast_mutex_unlock(&tzlock);
00344
00345 ast_verbose(VERBOSE_PREFIX_3 "Registered indication country '%s'\n",zone->country);
00346 return 0;
00347 }
00348
00349
00350
00351 int ast_unregister_indication_country(const char *country)
00352 {
00353 struct tone_zone *tz, *pz = NULL, *tmp;
00354 int res = -1;
00355
00356 if (ast_mutex_lock(&tzlock)) {
00357 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
00358 return -1;
00359 }
00360 tz = tone_zones;
00361 while (tz) {
00362 if (country==NULL ||
00363 (strcasecmp(country, tz->country)==0 ||
00364 strcasecmp(country, tz->alias)==0)) {
00365
00366 tmp = tz->next;
00367 if (pz)
00368 pz->next = tmp;
00369 else
00370 tone_zones = tmp;
00371
00372 if (tz == current_tonezone) {
00373 ast_log(LOG_NOTICE,"Removed default indication country '%s'\n",tz->country);
00374 current_tonezone = NULL;
00375 }
00376 ast_verbose(VERBOSE_PREFIX_3 "Unregistered indication country '%s'\n",tz->country);
00377 free_zone(tz);
00378 tz = tmp;
00379 res = 0;
00380 }
00381 else {
00382
00383 pz = tz;
00384 tz = tz->next;
00385 }
00386 }
00387 ast_mutex_unlock(&tzlock);
00388 return res;
00389 }
00390
00391
00392
00393 int ast_register_indication(struct tone_zone *zone, const char *indication, const char *tonelist)
00394 {
00395 struct tone_zone_sound *ts,*ps;
00396
00397
00398 if (zone->alias[0])
00399 return -1;
00400
00401 if (ast_mutex_lock(&tzlock)) {
00402 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
00403 return -2;
00404 }
00405 for (ps=NULL,ts=zone->tones; ts; ps=ts,ts=ts->next) {
00406 if (strcasecmp(indication,ts->name)==0) {
00407
00408 free((void*)ts->name);
00409 free((void*)ts->data);
00410 break;
00411 }
00412 }
00413 if (!ts) {
00414
00415 ts = malloc(sizeof(struct tone_zone_sound));
00416 if (!ts) {
00417 ast_log(LOG_WARNING, "Out of memory\n");
00418 ast_mutex_unlock(&tzlock);
00419 return -2;
00420 }
00421 ts->next = NULL;
00422 }
00423 ts->name = strdup(indication);
00424 ts->data = strdup(tonelist);
00425 if (ts->name==NULL || ts->data==NULL) {
00426 ast_log(LOG_WARNING, "Out of memory\n");
00427 ast_mutex_unlock(&tzlock);
00428 return -2;
00429 }
00430 if (ps)
00431 ps->next = ts;
00432 else
00433 zone->tones = ts;
00434 ast_mutex_unlock(&tzlock);
00435 return 0;
00436 }
00437
00438
00439 int ast_unregister_indication(struct tone_zone *zone, const char *indication)
00440 {
00441 struct tone_zone_sound *ts,*ps = NULL, *tmp;
00442 int res = -1;
00443
00444
00445 if (zone->alias[0])
00446 return -1;
00447
00448 if (ast_mutex_lock(&tzlock)) {
00449 ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
00450 return -1;
00451 }
00452 ts = zone->tones;
00453 while (ts) {
00454 if (strcasecmp(indication,ts->name)==0) {
00455
00456 tmp = ts->next;
00457 if (ps)
00458 ps->next = tmp;
00459 else
00460 zone->tones = tmp;
00461 free((void*)ts->name);
00462 free((void*)ts->data);
00463 free(ts);
00464 ts = tmp;
00465 res = 0;
00466 }
00467 else {
00468
00469 ps = ts;
00470 ts = ts->next;
00471 }
00472 }
00473
00474 ast_mutex_unlock(&tzlock);
00475 return res;
00476 }