indications.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * Tone Management
  5. *
  6. * Copyright (C) 2002, Pauline Middelink
  7. *
  8. * Pauline Middelink <middelink@polyware.nl>
  9. *
  10. * This program is free software, distributed under the terms of
  11. * the GNU General Public License
  12. *
  13. * This set of function allow us to play a list of tones on a channel.
  14. * Each element has two frequencies, which are mixed together and a
  15. * duration. For silence both frequencies can be set to 0.
  16. * The playtones can be given as a comma separated string.
  17. */
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <math.h> /* For PI */
  22. #include <asterisk/indications.h>
  23. #include <asterisk/frame.h>
  24. #include <asterisk/options.h>
  25. #include <asterisk/channel.h>
  26. #include <asterisk/logger.h>
  27. #include <asterisk/lock.h>
  28. struct playtones_item {
  29. int freq1;
  30. int freq2;
  31. int duration;
  32. int modulate;
  33. };
  34. struct playtones_def {
  35. int vol;
  36. int reppos;
  37. int nitems;
  38. int interruptible;
  39. struct playtones_item *items;
  40. };
  41. struct playtones_state {
  42. int vol;
  43. int reppos;
  44. int nitems;
  45. struct playtones_item *items;
  46. int npos;
  47. int pos;
  48. int origwfmt;
  49. struct ast_frame f;
  50. unsigned char offset[AST_FRIENDLY_OFFSET];
  51. short data[4000];
  52. };
  53. static void playtones_release(struct ast_channel *chan, void *params)
  54. {
  55. struct playtones_state *ps = params;
  56. if (chan) {
  57. ast_set_write_format(chan, ps->origwfmt);
  58. }
  59. if (ps->items) free(ps->items);
  60. free(ps);
  61. }
  62. static void * playtones_alloc(struct ast_channel *chan, void *params)
  63. {
  64. struct playtones_def *pd = params;
  65. struct playtones_state *ps = malloc(sizeof(struct playtones_state));
  66. if (!ps)
  67. return NULL;
  68. memset(ps, 0, sizeof(struct playtones_state));
  69. ps->origwfmt = chan->writeformat;
  70. if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
  71. ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
  72. playtones_release(NULL, ps);
  73. ps = NULL;
  74. } else {
  75. ps->vol = pd->vol;
  76. ps->reppos = pd->reppos;
  77. ps->nitems = pd->nitems;
  78. ps->items = pd->items;
  79. }
  80. /* Let interrupts interrupt :) */
  81. chan->writeinterrupt = pd->interruptible;
  82. return ps;
  83. }
  84. static int playtones_generator(struct ast_channel *chan, void *data, int len, int samples)
  85. {
  86. struct playtones_state *ps = data;
  87. struct playtones_item *pi;
  88. int x;
  89. /* we need to prepare a frame with 16 * timelen samples as we're
  90. * generating SLIN audio
  91. */
  92. len = samples * 2;
  93. if (len > sizeof(ps->data) / 2 - 1) {
  94. ast_log(LOG_WARNING, "Can't generate that much data!\n");
  95. return -1;
  96. }
  97. memset(&ps->f, 0, sizeof(ps->f));
  98. pi = &ps->items[ps->npos];
  99. for (x=0;x<len/2;x++) {
  100. if (pi->modulate)
  101. /* Modulate 1st tone with 2nd, to 90% modulation depth */
  102. ps->data[x] = ps->vol * 2 * (
  103. sin((pi->freq1 * 2.0 * M_PI / 8000.0) * (ps->pos + x)) *
  104. (0.9 * fabs(sin((pi->freq2 * 2.0 * M_PI / 8000.0) * (ps->pos + x))) + 0.1)
  105. );
  106. else
  107. /* Add 2 tones together */
  108. ps->data[x] = ps->vol * (
  109. sin((pi->freq1 * 2.0 * M_PI / 8000.0) * (ps->pos + x)) +
  110. sin((pi->freq2 * 2.0 * M_PI / 8000.0) * (ps->pos + x))
  111. );
  112. }
  113. ps->f.frametype = AST_FRAME_VOICE;
  114. ps->f.subclass = AST_FORMAT_SLINEAR;
  115. ps->f.datalen = len;
  116. ps->f.samples = samples;
  117. ps->f.offset = AST_FRIENDLY_OFFSET;
  118. ps->f.data = ps->data;
  119. ps->f.delivery.tv_sec = 0;
  120. ps->f.delivery.tv_usec = 0;
  121. ast_write(chan, &ps->f);
  122. ps->pos += x;
  123. if (pi->duration && ps->pos >= pi->duration * 8) { /* item finished? */
  124. ps->pos = 0; /* start new item */
  125. ps->npos++;
  126. if (ps->npos >= ps->nitems) { /* last item? */
  127. if (ps->reppos == -1) /* repeat set? */
  128. return -1;
  129. ps->npos = ps->reppos; /* redo from top */
  130. }
  131. }
  132. return 0;
  133. }
  134. static struct ast_generator playtones = {
  135. alloc: playtones_alloc,
  136. release: playtones_release,
  137. generate: playtones_generator,
  138. };
  139. int ast_playtones_start(struct ast_channel *chan, int vol, const char *playlst, int interruptible)
  140. {
  141. char *s, *data = ast_strdupa(playlst); /* cute */
  142. struct playtones_def d = { vol, -1, 0, 1, NULL};
  143. char *stringp=NULL;
  144. char *separator;
  145. if (!data)
  146. return -1;
  147. if (vol < 1)
  148. d.vol = 8192;
  149. d.interruptible = interruptible;
  150. stringp=data;
  151. /* the stringp/data is not null here */
  152. /* check if the data is separated with '|' or with ',' by default */
  153. if (strchr(stringp,'|'))
  154. separator = "|";
  155. else
  156. separator = ",";
  157. s = strsep(&stringp,separator);
  158. while (s && *s) {
  159. int freq1, freq2, time, modulate=0;
  160. if (s[0]=='!')
  161. s++;
  162. else if (d.reppos == -1)
  163. d.reppos = d.nitems;
  164. if (sscanf(s, "%d+%d/%d", &freq1, &freq2, &time) == 3) {
  165. /* f1+f2/time format */
  166. } else if (sscanf(s, "%d+%d", &freq1, &freq2) == 2) {
  167. /* f1+f2 format */
  168. time = 0;
  169. } else if (sscanf(s, "%d*%d/%d", &freq1, &freq2, &time) == 3) {
  170. /* f1*f2/time format */
  171. modulate = 1;
  172. } else if (sscanf(s, "%d*%d", &freq1, &freq2) == 2) {
  173. /* f1*f2 format */
  174. time = 0;
  175. modulate = 1;
  176. } else if (sscanf(s, "%d/%d", &freq1, &time) == 2) {
  177. /* f1/time format */
  178. freq2 = 0;
  179. } else if (sscanf(s, "%d", &freq1) == 1) {
  180. /* f1 format */
  181. freq2 = 0;
  182. time = 0;
  183. } else {
  184. ast_log(LOG_WARNING,"%s: tone component '%s' of '%s' is no good\n",chan->name,s,playlst);
  185. return -1;
  186. }
  187. d.items = realloc(d.items,(d.nitems+1)*sizeof(struct playtones_item));
  188. if (d.items == NULL)
  189. return -1;
  190. d.items[d.nitems].freq1 = freq1;
  191. d.items[d.nitems].freq2 = freq2;
  192. d.items[d.nitems].duration = time;
  193. d.items[d.nitems].modulate = modulate;
  194. d.nitems++;
  195. s = strsep(&stringp,separator);
  196. }
  197. if (ast_activate_generator(chan, &playtones, &d)) {
  198. free(d.items);
  199. return -1;
  200. }
  201. return 0;
  202. }
  203. void ast_playtones_stop(struct ast_channel *chan)
  204. {
  205. ast_deactivate_generator(chan);
  206. }
  207. /*--------------------------------------------*/
  208. struct tone_zone *tone_zones;
  209. static struct tone_zone *current_tonezone;
  210. /* Protect the tone_zones list (highly unlikely that two things would change
  211. * it at the same time, but still! */
  212. AST_MUTEX_DEFINE_EXPORTED(tzlock);
  213. /* Set global indication country */
  214. int ast_set_indication_country(const char *country)
  215. {
  216. if (country) {
  217. struct tone_zone *z = ast_get_indication_zone(country);
  218. if (z) {
  219. if (option_verbose > 2)
  220. ast_verbose(VERBOSE_PREFIX_3 "Setting default indication country to '%s'\n",country);
  221. current_tonezone = z;
  222. return 0;
  223. }
  224. }
  225. return 1; /* not found */
  226. }
  227. /* locate tone_zone, given the country. if country == NULL, use the default country */
  228. struct tone_zone *ast_get_indication_zone(const char *country)
  229. {
  230. struct tone_zone *tz;
  231. int alias_loop = 0;
  232. /* we need some tonezone, pick the first */
  233. if (country == NULL && current_tonezone)
  234. return current_tonezone; /* default country? */
  235. if (country == NULL && tone_zones)
  236. return tone_zones; /* any country? */
  237. if (country == NULL)
  238. return 0; /* not a single country insight */
  239. if (ast_mutex_lock(&tzlock)) {
  240. ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
  241. return 0;
  242. }
  243. do {
  244. for (tz=tone_zones; tz; tz=tz->next) {
  245. if (strcasecmp(country,tz->country)==0) {
  246. /* tone_zone found */
  247. if (tz->alias && tz->alias[0]) {
  248. country = tz->alias;
  249. break;
  250. }
  251. ast_mutex_unlock(&tzlock);
  252. return tz;
  253. }
  254. }
  255. } while (++alias_loop<20 && tz);
  256. ast_mutex_unlock(&tzlock);
  257. if (alias_loop==20)
  258. ast_log(LOG_NOTICE,"Alias loop for '%s' forcefull broken\n",country);
  259. /* nothing found, sorry */
  260. return 0;
  261. }
  262. /* locate a tone_zone_sound, given the tone_zone. if tone_zone == NULL, use the default tone_zone */
  263. struct tone_zone_sound *ast_get_indication_tone(const struct tone_zone *zone, const char *indication)
  264. {
  265. struct tone_zone_sound *ts;
  266. /* we need some tonezone, pick the first */
  267. if (zone == NULL && current_tonezone)
  268. zone = current_tonezone; /* default country? */
  269. if (zone == NULL && tone_zones)
  270. zone = tone_zones; /* any country? */
  271. if (zone == NULL)
  272. return 0; /* not a single country insight */
  273. if (ast_mutex_lock(&tzlock)) {
  274. ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
  275. return 0;
  276. }
  277. for (ts=zone->tones; ts; ts=ts->next) {
  278. if (strcasecmp(indication,ts->name)==0) {
  279. /* found indication! */
  280. ast_mutex_unlock(&tzlock);
  281. return ts;
  282. }
  283. }
  284. /* nothing found, sorry */
  285. ast_mutex_unlock(&tzlock);
  286. return 0;
  287. }
  288. /* helper function to delete a tone_zone in its entirety */
  289. static inline void free_zone(struct tone_zone* zone)
  290. {
  291. while (zone->tones) {
  292. struct tone_zone_sound *tmp = zone->tones->next;
  293. free((void*)zone->tones->name);
  294. free((void*)zone->tones->data);
  295. free(zone->tones);
  296. zone->tones = tmp;
  297. }
  298. if (zone->ringcadance)
  299. free((void*)zone->ringcadance);
  300. free(zone);
  301. }
  302. /*--------------------------------------------*/
  303. /* add a new country, if country exists, it will be replaced. */
  304. int ast_register_indication_country(struct tone_zone *zone)
  305. {
  306. struct tone_zone *tz,*pz;
  307. if (ast_mutex_lock(&tzlock)) {
  308. ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
  309. return -1;
  310. }
  311. for (pz=NULL,tz=tone_zones; tz; pz=tz,tz=tz->next) {
  312. if (strcasecmp(zone->country,tz->country)==0) {
  313. /* tone_zone already there, replace */
  314. zone->next = tz->next;
  315. if (pz)
  316. pz->next = zone;
  317. else
  318. tone_zones = zone;
  319. /* if we are replacing the default zone, re-point it */
  320. if (tz == current_tonezone)
  321. current_tonezone = zone;
  322. /* now free the previous zone */
  323. free_zone(tz);
  324. ast_mutex_unlock(&tzlock);
  325. return 0;
  326. }
  327. }
  328. /* country not there, add */
  329. zone->next = NULL;
  330. if (pz)
  331. pz->next = zone;
  332. else
  333. tone_zones = zone;
  334. ast_mutex_unlock(&tzlock);
  335. if (option_verbose > 2)
  336. ast_verbose(VERBOSE_PREFIX_3 "Registered indication country '%s'\n",zone->country);
  337. return 0;
  338. }
  339. /* remove an existing country and all its indications, country must exist.
  340. * Also, all countries which are an alias for the specified country are removed. */
  341. int ast_unregister_indication_country(const char *country)
  342. {
  343. struct tone_zone *tz, *pz = NULL, *tmp;
  344. int res = -1;
  345. if (ast_mutex_lock(&tzlock)) {
  346. ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
  347. return -1;
  348. }
  349. tz = tone_zones;
  350. while (tz) {
  351. if (country==NULL ||
  352. (strcasecmp(country, tz->country)==0 ||
  353. strcasecmp(country, tz->alias)==0)) {
  354. /* tone_zone found, remove */
  355. tmp = tz->next;
  356. if (pz)
  357. pz->next = tmp;
  358. else
  359. tone_zones = tmp;
  360. /* if we are unregistering the default country, w'll notice */
  361. if (tz == current_tonezone) {
  362. ast_log(LOG_NOTICE,"Removed default indication country '%s'\n",tz->country);
  363. current_tonezone = NULL;
  364. }
  365. if (option_verbose > 2)
  366. ast_verbose(VERBOSE_PREFIX_3 "Unregistered indication country '%s'\n",tz->country);
  367. free_zone(tz);
  368. if (tone_zones == tz)
  369. tone_zones = tmp;
  370. tz = tmp;
  371. res = 0;
  372. }
  373. else {
  374. /* next zone please */
  375. pz = tz;
  376. tz = tz->next;
  377. }
  378. }
  379. ast_mutex_unlock(&tzlock);
  380. return res;
  381. }
  382. /* add a new indication to a tone_zone. tone_zone must exist. if the indication already
  383. * exists, it will be replaced. */
  384. int ast_register_indication(struct tone_zone *zone, const char *indication, const char *tonelist)
  385. {
  386. struct tone_zone_sound *ts,*ps;
  387. /* is it an alias? stop */
  388. if (zone->alias[0])
  389. return -1;
  390. if (ast_mutex_lock(&tzlock)) {
  391. ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
  392. return -2;
  393. }
  394. for (ps=NULL,ts=zone->tones; ts; ps=ts,ts=ts->next) {
  395. if (strcasecmp(indication,ts->name)==0) {
  396. /* indication already there, replace */
  397. free((void*)ts->name);
  398. free((void*)ts->data);
  399. break;
  400. }
  401. }
  402. if (!ts) {
  403. /* not there, we have to add */
  404. ts = malloc(sizeof(struct tone_zone_sound));
  405. if (!ts) {
  406. ast_log(LOG_WARNING, "Out of memory\n");
  407. ast_mutex_unlock(&tzlock);
  408. return -2;
  409. }
  410. ts->next = NULL;
  411. }
  412. ts->name = strdup(indication);
  413. ts->data = strdup(tonelist);
  414. if (ts->name==NULL || ts->data==NULL) {
  415. ast_log(LOG_WARNING, "Out of memory\n");
  416. ast_mutex_unlock(&tzlock);
  417. return -2;
  418. }
  419. if (ps)
  420. ps->next = ts;
  421. else
  422. zone->tones = ts;
  423. ast_mutex_unlock(&tzlock);
  424. return 0;
  425. }
  426. /* remove an existing country's indication. Both country and indication must exist */
  427. int ast_unregister_indication(struct tone_zone *zone, const char *indication)
  428. {
  429. struct tone_zone_sound *ts,*ps = NULL, *tmp;
  430. int res = -1;
  431. /* is it an alias? stop */
  432. if (zone->alias[0])
  433. return -1;
  434. if (ast_mutex_lock(&tzlock)) {
  435. ast_log(LOG_WARNING, "Unable to lock tone_zones list\n");
  436. return -1;
  437. }
  438. ts = zone->tones;
  439. while (ts) {
  440. if (strcasecmp(indication,ts->name)==0) {
  441. /* indication found */
  442. tmp = ts->next;
  443. if (ps)
  444. ps->next = tmp;
  445. else
  446. zone->tones = tmp;
  447. free((void*)ts->name);
  448. free((void*)ts->data);
  449. free(ts);
  450. ts = tmp;
  451. res = 0;
  452. }
  453. else {
  454. /* next zone please */
  455. ps = ts;
  456. ts = ts->next;
  457. }
  458. }
  459. /* indication not found, goodbye */
  460. ast_mutex_unlock(&tzlock);
  461. return res;
  462. }