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