Thu Apr 28 2011 17:13:56

Asterisk developer's documentation


indications.c File Reference

Indication Tone Handling. More...

#include "asterisk.h"
#include <math.h>
#include "asterisk/lock.h"
#include "asterisk/linkedlists.h"
#include "asterisk/indications.h"
#include "asterisk/frame.h"
#include "asterisk/channel.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/module.h"
#include "asterisk/astobj2.h"
#include "asterisk/_private.h"
Include dependency graph for indications.c:

Go to the source code of this file.

Data Structures

struct  playtones_def
struct  playtones_item
struct  playtones_state

Defines

#define NUM_TONE_ZONE_BUCKETS   53

Functions

struct ast_tone_zone_soundast_get_indication_tone (const struct ast_tone_zone *_zone, const char *indication)
 Locate a tone zone sound.
struct ast_tone_zoneast_get_indication_zone (const char *country)
 locate ast_tone_zone
int ast_indications_init (void)
 Load indications module.
int ast_indications_reload (void)
 Reload indications module.
int ast_playtones_start (struct ast_channel *chan, int vol, const char *playlst, int interruptible)
 Start playing a list of tones on a channel.
void ast_playtones_stop (struct ast_channel *chan)
 Stop playing tones on a channel.
static int ast_register_indication (struct ast_tone_zone *zone, const char *indication, const char *tonelist)
static int ast_register_indication_country (struct ast_tone_zone *zone)
static int ast_set_indication_country (const char *country)
static struct ast_tone_zoneast_tone_zone_alloc (void)
static int ast_tone_zone_cmp (void *obj, void *arg, int flags)
int ast_tone_zone_count (void)
 Get the number of registered tone zones.
static void ast_tone_zone_destructor (void *obj)
 deallocate the passed tone zone
static int ast_tone_zone_hash (const void *obj, const int flags)
struct ao2_iterator ast_tone_zone_iterator_init (void)
 Get an iterator for the available tone zones.
int ast_tone_zone_part_parse (const char *s, struct ast_tone_zone_part *tone_data)
 Parse a tone part.
static void ast_tone_zone_sound_destructor (void *obj)
static int ast_unregister_indication (struct ast_tone_zone *zone, const char *indication)
static int ast_unregister_indication_country (const char *country)
static char * complete_country (struct ast_cli_args *a)
static char * complete_indications (struct ast_cli_args *a)
static char * handle_cli_indication_add (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_indication_remove (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_indication_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int is_valid_tone_zone (struct ast_tone_zone *zone)
static int load_indications (int reload)
 load indications module
static int parse_tone_zone (struct ast_config *cfg, const char *country)
static void * playtones_alloc (struct ast_channel *chan, void *params)
static int playtones_generator (struct ast_channel *chan, void *data, int len, int samples)
static void playtones_release (struct ast_channel *chan, void *params)
static int prune_tone_zone (void *obj, void *arg, int flags)
static void reset_tone_zone (struct ast_tone_zone *zone)
static void store_config_tone_zone (struct ast_tone_zone *zone, const char *var, const char *value)
static void store_tone_zone_ring_cadence (struct ast_tone_zone *zone, const char *val)
static int tone_zone_mark (void *obj, void *arg, int flags)

Variables

static struct ao2_containerast_tone_zones
static struct ast_cli_entry cli_indications []
 CLI entries for commands provided by this module.
static const char config [] = "indications.conf"
static struct ast_tone_zonedefault_tone_zone
static const int midi_tohz [128]
static struct ast_generator playtones

Detailed Description

Indication Tone Handling.

Author:
Pauline Middelink <middelink@polyware.nl>
Russell Bryant <russell@digium.com>

Definition in file indications.c.


Define Documentation

#define NUM_TONE_ZONE_BUCKETS   53

Definition at line 65 of file indications.c.

Referenced by ast_indications_init().


Function Documentation

struct ast_tone_zone_sound* ast_get_indication_tone ( const struct ast_tone_zone zone,
const char *  indication 
) [read]

Locate a tone zone sound.

Parameters:
zoneZone to look in for a sound, if NULL, the default will be used
indicationSound to look for, such as "busy"
Returns:
a reference to the specified sound if it exists, NULL if not

Definition at line 452 of file indications.c.

References ao2_lock(), ao2_unlock(), AST_LIST_TRAVERSE, ast_tone_zone_lock, ast_tone_zone_ref(), ast_tone_zone_sound_ref(), ast_tone_zone_unlock, ast_tone_zone_sound::name, and ast_tone_zone::tones.

Referenced by ast_app_dtget(), ast_indicate_data(), dialtone_indicate(), handle_playtones(), in_band_indication(), pbx_builtin_waitexten(), play_dialtone(), read_exec(), readexten_exec(), and skinny_transfer().

{
   struct ast_tone_zone_sound *ts = NULL;
   /* _zone is const to the users of the API */
   struct ast_tone_zone *zone = (struct ast_tone_zone *) _zone;

   /* If no zone is specified, use the default */
   if (!zone) {
      ao2_lock(ast_tone_zones);
      if (default_tone_zone) {
         zone = ast_tone_zone_ref(default_tone_zone);
      }
      ao2_unlock(ast_tone_zones);

      if (!zone) {
         return NULL;
      }
   }

   ast_tone_zone_lock(zone);

   /* Look through list of tones in the zone searching for the right one */
   AST_LIST_TRAVERSE(&zone->tones, ts, entry) {
      if (!strcasecmp(ts->name, indication)) {
         /* Increase ref count for the reference we will return */
         ts = ast_tone_zone_sound_ref(ts);
         break;
      }
   }

   ast_tone_zone_unlock(zone);

   return ts;
}
struct ast_tone_zone* ast_get_indication_zone ( const char *  country) [read]

locate ast_tone_zone

Parameters:
countrycountry to find. If NULL is provided, get the default.
Returns:
a reference to the specified country if found or NULL if not found

Definition at line 430 of file indications.c.

References ao2_find, ao2_lock(), ao2_unlock(), ast_copy_string(), ast_strlen_zero(), ast_tone_zone_ref(), ast_tone_zone::country, ast_tone_zone::nrringcadence, and OBJ_POINTER.

Referenced by ast_set_indication_country(), ast_var_indications(), build_device(), func_channel_write_real(), handle_cli_indication_add(), and handle_cli_indication_remove().

{
   struct ast_tone_zone *tz = NULL;
   struct ast_tone_zone zone_arg = {
      .nrringcadence = 0,
   };

   if (ast_strlen_zero(country)) {
      ao2_lock(ast_tone_zones);
      if (default_tone_zone) {
         tz = ast_tone_zone_ref(default_tone_zone);
      }
      ao2_unlock(ast_tone_zones);

      return tz;
   }

   ast_copy_string(zone_arg.country, country, sizeof(zone_arg.country));

   return ao2_find(ast_tone_zones, &zone_arg, OBJ_POINTER);
}
int ast_indications_init ( void  )
int ast_indications_reload ( void  )

Reload indications module.

Provided by indications.c

Definition at line 1123 of file indications.c.

References load_indications().

{
   return load_indications(1);
}
int ast_playtones_start ( struct ast_channel chan,
int  vol,
const char *  tonelist,
int  interruptible 
)

Start playing a list of tones on a channel.

Parameters:
chanthe channel to play tones on
volvolume
tonelistthe list of tones to play, comma separated
interruptiblewhether or not this tone can be interrupted
Return values:
0success
non-zerofailure

Definition at line 301 of file indications.c.

References ast_activate_generator(), ast_free, ast_log(), ast_realloc, ast_strdupa, ast_strip(), ast_strlen_zero(), ast_tone_zone_part_parse(), cos, playtones_item::duration, playtones_item::fac1, playtones_item::fac2, ast_tone_zone_part::freq1, ast_tone_zone_part::freq2, playtones_item::init_v2_1, playtones_item::init_v2_2, playtones_item::init_v3_1, playtones_item::init_v3_2, playtones_def::interruptible, playtones_def::items, LOG_ERROR, ast_tone_zone_part::midinote, ast_tone_zone_part::modulate, playtones_item::modulate, playtones_def::nitems, playtones_def::reppos, s, strsep(), ast_tone_zone_part::time, and playtones_def::vol.

Referenced by ast_app_dtget(), ast_indicate_data(), ast_senddigit_begin(), dialtone_indicate(), do_dtmf_local(), handle_playtones(), in_band_indication(), milliwatt_exec(), pbx_builtin_waitexten(), play_dialtone(), playtone(), read_exec(), readexten_exec(), send_digit_to_chan(), and skinny_transfer().

{
   char *s, *data = ast_strdupa(playlst);
   struct playtones_def d = { vol, -1, 0, 1, NULL };
   char *stringp;
   char *separator;
   static const float sample_rate = 8000.0;
   static const float max_sample_val = 32768.0;

   if (vol < 1) {
      d.vol = 7219; /* Default to -8db */
   }

   d.interruptible = interruptible;

   stringp = data;

   /* check if the data is separated with '|' or with ',' by default */
   if (strchr(stringp,'|')) {
      separator = "|";
   } else {
      separator = ",";
   }

   while ((s = strsep(&stringp, separator)) && !ast_strlen_zero(s)) {
      struct ast_tone_zone_part tone_data = {
         .time = 0,
      };

      s = ast_strip(s);

      if (s[0]=='!') {
         s++;
      } else if (d.reppos == -1) {
         d.reppos = d.nitems;
      }

      if (ast_tone_zone_part_parse(s, &tone_data)) {
         ast_log(LOG_ERROR, "Failed to parse tone part '%s'\n", s);
         continue;
      }

      if (tone_data.midinote) {
         /* midi notes must be between 0 and 127 */

         if (tone_data.freq1 >= 0 && tone_data.freq1 <= 127) {
            tone_data.freq1 = midi_tohz[tone_data.freq1];
         } else {
            tone_data.freq1 = 0;
         }

         if (tone_data.freq2 >= 0 && tone_data.freq2 <= 127) {
            tone_data.freq2 = midi_tohz[tone_data.freq2];
         } else {
            tone_data.freq2 = 0;
         }
      }

      if (!(d.items = ast_realloc(d.items, (d.nitems + 1) * sizeof(*d.items)))) {
         return -1;
      }

      d.items[d.nitems].fac1 = 2.0 * cos(2.0 * M_PI * (tone_data.freq1 / sample_rate)) * max_sample_val;
      d.items[d.nitems].init_v2_1 = sin(-4.0 * M_PI * (tone_data.freq1 / sample_rate)) * d.vol;
      d.items[d.nitems].init_v3_1 = sin(-2.0 * M_PI * (tone_data.freq1 / sample_rate)) * d.vol;

      d.items[d.nitems].fac2 = 2.0 * cos(2.0 * M_PI * (tone_data.freq2 / sample_rate)) * max_sample_val;
      d.items[d.nitems].init_v2_2 = sin(-4.0 * M_PI * (tone_data.freq2 / sample_rate)) * d.vol;
      d.items[d.nitems].init_v3_2 = sin(-2.0 * M_PI * (tone_data.freq2 / sample_rate)) * d.vol;

      d.items[d.nitems].duration = tone_data.time;
      d.items[d.nitems].modulate = tone_data.modulate;

      d.nitems++;
   }

   if (!d.nitems) {
      ast_log(LOG_ERROR, "No valid tone parts\n");
      return -1;
   }

   if (ast_activate_generator(chan, &playtones, &d)) {
      ast_free(d.items);
      return -1;
   }

   return 0;
}
void ast_playtones_stop ( struct ast_channel chan)
static int ast_register_indication ( struct ast_tone_zone zone,
const char *  indication,
const char *  tonelist 
) [static]
Note:
called with the tone zone locked

Definition at line 567 of file indications.c.

References ao2_alloc, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_strdup, ast_strlen_zero(), ast_tone_zone_sound_destructor(), ast_tone_zone_sound_unref(), ast_tone_zone_sound::data, ast_tone_zone_sound::entry, ast_tone_zone_sound::name, and ast_tone_zone::tones.

Referenced by handle_cli_indication_add(), and store_config_tone_zone().

{
   struct ast_tone_zone_sound *ts;

   if (ast_strlen_zero(indication) || ast_strlen_zero(tonelist)) {
      return -1;
   }

   AST_LIST_TRAVERSE_SAFE_BEGIN(&zone->tones, ts, entry) {
      if (!strcasecmp(indication, ts->name)) {
         AST_LIST_REMOVE_CURRENT(entry);
         ts = ast_tone_zone_sound_unref(ts);
         break;
      }
   }
   AST_LIST_TRAVERSE_SAFE_END;

   if (!(ts = ao2_alloc(sizeof(*ts), ast_tone_zone_sound_destructor))) {
      return -1;
   }

   if (!(ts->name = ast_strdup(indication)) || !(ts->data = ast_strdup(tonelist))) {
      ts = ast_tone_zone_sound_unref(ts);
      return -1;
   }

   AST_LIST_INSERT_TAIL(&zone->tones, ts, entry); /* Inherit reference */

   return 0;
}
static int ast_register_indication_country ( struct ast_tone_zone zone) [static]

Definition at line 520 of file indications.c.

References ao2_link, ao2_lock(), ao2_unlock(), ast_tone_zone_ref(), ast_verb, and ast_tone_zone::country.

Referenced by handle_cli_indication_add(), and parse_tone_zone().

{
   ao2_lock(ast_tone_zones);
   if (!default_tone_zone) {
      default_tone_zone = ast_tone_zone_ref(zone);
   }
   ao2_unlock(ast_tone_zones);

   ao2_link(ast_tone_zones, zone);

   ast_verb(3, "Registered indication country '%s'\n", zone->country);

   return 0;
}
static int ast_set_indication_country ( const char *  country) [static]

Definition at line 406 of file indications.c.

References ao2_lock(), ao2_unlock(), ast_get_indication_zone(), ast_strlen_zero(), ast_tone_zone_ref(), ast_tone_zone_unref(), and ast_verb.

Referenced by load_indications().

{
   struct ast_tone_zone *zone = NULL;

   /* If no country is specified or we are unable to find the zone, then return not found */
   if (ast_strlen_zero(country) || !(zone = ast_get_indication_zone(country))) {
      return -1;
   }

   ast_verb(3, "Setting default indication country to '%s'\n", country);

   ao2_lock(ast_tone_zones);
   if (default_tone_zone) {
      default_tone_zone = ast_tone_zone_unref(default_tone_zone);
   }
   default_tone_zone = ast_tone_zone_ref(zone);
   ao2_unlock(ast_tone_zones);

   zone = ast_tone_zone_unref(zone);

   return 0;
}
static struct ast_tone_zone* ast_tone_zone_alloc ( void  ) [static, read]

Definition at line 622 of file indications.c.

References ao2_alloc, and ast_tone_zone_destructor().

Referenced by handle_cli_indication_add(), and parse_tone_zone().

{
   return ao2_alloc(sizeof(struct ast_tone_zone), ast_tone_zone_destructor);
}
static int ast_tone_zone_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1096 of file indications.c.

References CMP_MATCH, CMP_STOP, and ast_tone_zone::country.

Referenced by ast_indications_init().

{
   struct ast_tone_zone *zone = obj;
   struct ast_tone_zone *zone_arg = arg;

   return (!strcasecmp(zone->country, zone_arg->country)) ?
         CMP_MATCH | CMP_STOP : 0;
}
int ast_tone_zone_count ( void  )

Get the number of registered tone zones.

Returns:
the total number of registered tone zones

Definition at line 395 of file indications.c.

References ao2_container_count().

static void ast_tone_zone_destructor ( void *  obj) [static]

deallocate the passed tone zone

Definition at line 504 of file indications.c.

References ast_free, AST_LIST_REMOVE_HEAD, ast_tone_zone_sound_unref(), ast_tone_zone_sound::entry, ast_tone_zone::ringcadence, and ast_tone_zone::tones.

Referenced by ast_tone_zone_alloc().

{
   struct ast_tone_zone *zone = obj;
   struct ast_tone_zone_sound *current;

   while ((current = AST_LIST_REMOVE_HEAD(&zone->tones, entry))) {
      current = ast_tone_zone_sound_unref(current);
   }

   if (zone->ringcadence) {
      ast_free(zone->ringcadence);
      zone->ringcadence = NULL;
   }
}
static int ast_tone_zone_hash ( const void *  obj,
const int  flags 
) [static]

Definition at line 1089 of file indications.c.

References ast_str_case_hash(), and ast_tone_zone::country.

Referenced by ast_indications_init().

{
   const struct ast_tone_zone *zone = obj;

   return ast_str_case_hash(zone->country);
}
struct ao2_iterator ast_tone_zone_iterator_init ( void  ) [read]

Get an iterator for the available tone zones.

Use ao2_iterator_next() to iterate the tone zones.

Returns:
an initialized iterator

Definition at line 400 of file indications.c.

References ao2_iterator_init().

Referenced by ast_var_indications(), ast_var_indications_table(), and handle_cli_indication_show().

int ast_tone_zone_part_parse ( const char *  s,
struct ast_tone_zone_part tone_data 
)

Parse a tone part.

Parameters:
sThe part of a tone to parse. This should be in the form described for the data part of ast_tone_zone_sound. '!' should be removed if present.
tone_dataAn output parameter that contains the result of the parsing.
Return values:
0success
-1failure, and the contents of tone_data are undefined

Definition at line 244 of file indications.c.

References ast_tone_zone_part::freq1, ast_tone_zone_part::freq2, ast_tone_zone_part::midinote, ast_tone_zone_part::modulate, and ast_tone_zone_part::time.

Referenced by ast_playtones_start().

{
   if (sscanf(s, "%30u+%30u/%30u", &tone_data->freq1, &tone_data->freq2, 
         &tone_data->time) == 3) {
      /* f1+f2/time format */
   } else if (sscanf(s, "%30u+%30u", &tone_data->freq1, &tone_data->freq2) == 2) {
      /* f1+f2 format */
      tone_data->time = 0;
   } else if (sscanf(s, "%30u*%30u/%30u", &tone_data->freq1, &tone_data->freq2, 
         &tone_data->time) == 3) {
      /* f1*f2/time format */
      tone_data->modulate = 1;
   } else if (sscanf(s, "%30u*%30u", &tone_data->freq1, &tone_data->freq2) == 2) {
      /* f1*f2 format */
      tone_data->time = 0;
      tone_data->modulate = 1;
   } else if (sscanf(s, "%30u/%30u", &tone_data->freq1, &tone_data->time) == 2) {
      /* f1/time format */
      tone_data->freq2 = 0;
   } else if (sscanf(s, "%30u", &tone_data->freq1) == 1) {
      /* f1 format */
      tone_data->freq2 = 0;
      tone_data->time = 0;
   } else if (sscanf(s, "M%30u+M%30u/%30u", &tone_data->freq1, &tone_data->freq2, 
         &tone_data->time) == 3) {
      /* Mf1+Mf2/time format */
      tone_data->midinote = 1;
   } else if (sscanf(s, "M%30u+M%30u", &tone_data->freq1, &tone_data->freq2) == 2) {
      /* Mf1+Mf2 format */
      tone_data->time = 0;
      tone_data->midinote = 1;
   } else if (sscanf(s, "M%30u*M%30u/%30u", &tone_data->freq1, &tone_data->freq2, 
         &tone_data->time) == 3) {
      /* Mf1*Mf2/time format */
      tone_data->modulate = 1;
      tone_data->midinote = 1;
   } else if (sscanf(s, "M%30u*M%30u", &tone_data->freq1, &tone_data->freq2) == 2) {
      /* Mf1*Mf2 format */
      tone_data->time = 0;
      tone_data->modulate = 1;
      tone_data->midinote = 1;
   } else if (sscanf(s, "M%30u/%30u", &tone_data->freq1, &tone_data->time) == 2) {
      /* Mf1/time format */
      tone_data->freq2 = -1;
      tone_data->midinote = 1;
   } else if (sscanf(s, "M%30u", &tone_data->freq1) == 1) {
      /* Mf1 format */
      tone_data->freq2 = -1;
      tone_data->time = 0;
      tone_data->midinote = 1;
   } else {
      return -1;
   }

   return 0;
}
static void ast_tone_zone_sound_destructor ( void *  obj) [static]

Definition at line 487 of file indications.c.

References ast_free, ast_tone_zone_sound::data, and ast_tone_zone_sound::name.

Referenced by ast_register_indication().

{
   struct ast_tone_zone_sound *ts = obj;

   /* Deconstify the 'const char *'s so the compiler doesn't complain. (but it's safe) */
   if (ts->name) {
      ast_free((char *) ts->name);
      ts->name = NULL;
   }

   if (ts->data) {
      ast_free((char *) ts->data);
      ts->data = NULL;
   }
}
static int ast_unregister_indication ( struct ast_tone_zone zone,
const char *  indication 
) [static]
static int ast_unregister_indication_country ( const char *  country) [static]

Definition at line 536 of file indications.c.

References ao2_callback, ao2_find, ao2_lock(), ao2_unlink, ao2_unlock(), ast_copy_string(), ast_tone_zone_unref(), ast_tone_zone::country, ast_tone_zone::nrringcadence, and OBJ_POINTER.

Referenced by handle_cli_indication_add(), and handle_cli_indication_remove().

{
   struct ast_tone_zone *tz = NULL;
   struct ast_tone_zone zone_arg = {
      .nrringcadence = 0,
   };

   ast_copy_string(zone_arg.country, country, sizeof(zone_arg.country));

   if (!(tz = ao2_find(ast_tone_zones, &zone_arg, OBJ_POINTER))) {
      return -1;
   }

   ao2_lock(ast_tone_zones);
   if (default_tone_zone == tz) {
      ast_tone_zone_unref(default_tone_zone);
      /* Get a new default, punt to the first one we find */
      default_tone_zone = ao2_callback(ast_tone_zones, 0, NULL, NULL);
   }
   ao2_unlock(ast_tone_zones);

   ao2_unlink(ast_tone_zones, tz);

   tz = ast_tone_zone_unref(tz);

   return 0;
}
static char* complete_country ( struct ast_cli_args a) [static]

Definition at line 627 of file indications.c.

References ao2_iterator_init(), ao2_iterator_next, ast_strdup, ast_tone_zone_unref(), ast_tone_zone::country, ast_cli_args::n, and ast_cli_args::word.

Referenced by handle_cli_indication_add(), handle_cli_indication_remove(), and handle_cli_indication_show().

{
   char *res = NULL;
   struct ao2_iterator i;
   int which = 0;
   size_t wordlen;
   struct ast_tone_zone *tz;

   wordlen = strlen(a->word);

   i = ao2_iterator_init(ast_tone_zones, 0);
   while ((tz = ao2_iterator_next(&i))) {
      if (!strncasecmp(a->word, tz->country, wordlen) && ++which > a->n) {
         res = ast_strdup(tz->country);
      }
      tz = ast_tone_zone_unref(tz);
      if (res) {
         break;
      }
   }

   return res;
}
static char* complete_indications ( struct ast_cli_args a) [static]

Definition at line 712 of file indications.c.

References ao2_find, ast_cli_args::argv, ast_copy_string(), AST_LIST_TRAVERSE, ast_strdup, ast_tone_zone_lock, ast_tone_zone_unlock, ast_tone_zone_unref(), ast_tone_zone::country, ast_cli_args::n, ast_tone_zone_sound::name, ast_tone_zone::nrringcadence, OBJ_POINTER, ast_cli_args::pos, ast_tone_zone::tones, and ast_cli_args::word.

Referenced by handle_cli_indication_remove().

{
   char *res = NULL;
   int which = 0;
   size_t wordlen;
   struct ast_tone_zone_sound *ts;
   struct ast_tone_zone *tz, tmp_tz = {
      .nrringcadence = 0,
   };

   ast_copy_string(tmp_tz.country, a->argv[a->pos - 1], sizeof(tmp_tz.country));

   if (!(tz = ao2_find(ast_tone_zones, &tmp_tz, OBJ_POINTER))) {
      return NULL;
   }

   wordlen = strlen(a->word);

   ast_tone_zone_lock(tz);
   AST_LIST_TRAVERSE(&tz->tones, ts, entry) {
      if (!strncasecmp(a->word, ts->name, wordlen) && ++which > a->n) {
         res = ast_strdup(ts->name);
         break;
      }
   }
   ast_tone_zone_unlock(tz);

   tz = ast_tone_zone_unref(tz);

   return res;
}
static char* handle_cli_indication_add ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 651 of file indications.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_copy_string(), ast_get_indication_zone(), ast_log(), ast_register_indication(), ast_register_indication_country(), ast_tone_zone_alloc(), ast_tone_zone_lock, ast_tone_zone_unlock, ast_tone_zone_unref(), ast_unregister_indication_country(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_country(), ast_tone_zone::country, LOG_NOTICE, LOG_WARNING, ast_cli_args::pos, and ast_cli_entry::usage.

{
   struct ast_tone_zone *tz;
   int created_country = 0;
   char *res = CLI_SUCCESS;

   switch (cmd) {
   case CLI_INIT:
      e->command = "indication add";
      e->usage =
         "Usage: indication add <country> <indication> \"<tonelist>\"\n"
         "       Add the given indication to the country.\n";
      return NULL;
   case CLI_GENERATE:
      if (a->pos == 2) {
         return complete_country(a);
      } else {
         return NULL;
      }
   }

   if (a->argc != 5) {
      return CLI_SHOWUSAGE;
   }

   if (!(tz = ast_get_indication_zone(a->argv[2]))) {
      /* country does not exist, create it */
      ast_log(LOG_NOTICE, "Country '%s' does not exist, creating it.\n", a->argv[2]);

      if (!(tz = ast_tone_zone_alloc())) {
         return CLI_FAILURE;
      }

      ast_copy_string(tz->country, a->argv[2], sizeof(tz->country));

      if (ast_register_indication_country(tz)) {
         ast_log(LOG_WARNING, "Unable to register new country\n");
         tz = ast_tone_zone_unref(tz);
         return CLI_FAILURE;
      }

      created_country = 1;
   }

   ast_tone_zone_lock(tz);

   if (ast_register_indication(tz, a->argv[3], a->argv[4])) {
      ast_log(LOG_WARNING, "Unable to register indication %s/%s\n", a->argv[2], a->argv[3]);
      if (created_country) {
         ast_unregister_indication_country(a->argv[2]);
      }
      res = CLI_FAILURE;
   }

   ast_tone_zone_unlock(tz);

   tz = ast_tone_zone_unref(tz);

   return res;
}
static char* handle_cli_indication_remove ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 744 of file indications.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_get_indication_zone(), ast_log(), ast_tone_zone_unref(), ast_unregister_indication(), ast_unregister_indication_country(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_country(), complete_indications(), LOG_WARNING, ast_cli_args::pos, and ast_cli_entry::usage.

{
   struct ast_tone_zone *tz;
   char *res = CLI_SUCCESS;

   switch (cmd) {
   case CLI_INIT:
      e->command = "indication remove";
      e->usage =
         "Usage: indication remove <country> [indication]\n"
         "       Remove the given indication from the country.\n";
      return NULL;
   case CLI_GENERATE:
      if (a->pos == 2) {
         return complete_country(a);
      } else if (a->pos == 3) {
         return complete_indications(a);
      }
   }

   if (a->argc != 3 && a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   if (a->argc == 3) {
      /* remove entire country */
      if (ast_unregister_indication_country(a->argv[2])) {
         ast_log(LOG_WARNING, "Unable to unregister indication country %s\n", a->argv[2]);
         return CLI_FAILURE;
      }

      return CLI_SUCCESS;
   }

   if (!(tz = ast_get_indication_zone(a->argv[2]))) {
      ast_log(LOG_WARNING, "Unable to unregister indication %s/%s, country does not exists\n", a->argv[2], a->argv[3]);
      return CLI_FAILURE;
   }

   if (ast_unregister_indication(tz, a->argv[3])) {
      ast_log(LOG_WARNING, "Unable to unregister indication %s/%s\n", a->argv[2], a->argv[3]);
      res = CLI_FAILURE;
   }

   tz = ast_tone_zone_unref(tz);

   return res;
}
static char* handle_cli_indication_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 793 of file indications.c.

References ao2_find, ao2_iterator_next, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), AST_LIST_TRAVERSE, ast_str_alloca, ast_str_append(), ast_str_set(), ast_tone_zone_iterator_init(), ast_tone_zone_lock, ast_tone_zone_unlock, ast_tone_zone_unref(), buf, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, complete_country(), ast_tone_zone::country, ast_tone_zone_sound::data, ast_tone_zone::description, ast_tone_zone_sound::entry, ast_cli_args::fd, ast_tone_zone_sound::name, ast_tone_zone::nrringcadence, OBJ_POINTER, ast_tone_zone::ringcadence, ast_tone_zone::tones, and ast_cli_entry::usage.

{
   struct ast_tone_zone *tz = NULL;
   struct ast_str *buf;
   int found_country = 0;
   int i;

   switch (cmd) {
   case CLI_INIT:
      e->command = "indication show";
      e->usage =
         "Usage: indication show [<country> ...]\n"
         "       Display either a condensed summary of all countries and indications, or a\n"
         "       more verbose list of indications for the specified countries.\n";
      return NULL;
   case CLI_GENERATE:
      return complete_country(a);
   }

   if (a->argc == 2) {
      struct ao2_iterator iter;
      /* no arguments, show a list of countries */
      ast_cli(a->fd, "Country   Description\n");
      ast_cli(a->fd, "===========================\n");
      iter = ast_tone_zone_iterator_init();
      while ((tz = ao2_iterator_next(&iter))) {
         ast_tone_zone_lock(tz);
         ast_cli(a->fd, "%-7.7s  %s\n", tz->country, tz->description);
         ast_tone_zone_unlock(tz);
         tz = ast_tone_zone_unref(tz);
      }
      return CLI_SUCCESS;
   }

   buf = ast_str_alloca(256);

   for (i = 2; i < a->argc; i++) {
      struct ast_tone_zone zone_arg = {
         .nrringcadence = 0,
      };
      struct ast_tone_zone_sound *ts;
      int j;

      ast_copy_string(zone_arg.country, a->argv[i], sizeof(zone_arg.country));

      if (!(tz = ao2_find(ast_tone_zones, &zone_arg, OBJ_POINTER))) {
         continue;
      }

      if (!found_country) {
         found_country = 1;
         ast_cli(a->fd, "Country Indication      PlayList\n");
         ast_cli(a->fd, "=====================================\n");
      }

      ast_tone_zone_lock(tz);

      ast_str_set(&buf, 0, "%-7.7s %-15.15s ", tz->country, "<ringcadence>");
      for (j = 0; j < tz->nrringcadence; j++) {
         ast_str_append(&buf, 0, "%d%s", tz->ringcadence[j],
               (j == tz->nrringcadence - 1) ? "" : ",");
      }
      ast_str_append(&buf, 0, "\n");
      ast_cli(a->fd, "%s", buf->str);

      AST_LIST_TRAVERSE(&tz->tones, ts, entry) {
         ast_cli(a->fd, "%-7.7s %-15.15s %s\n", tz->country, ts->name, ts->data);
      }

      ast_tone_zone_unlock(tz);
      tz = ast_tone_zone_unref(tz);
   }

   if (!found_country) {
      ast_cli(a->fd, "No countries matched your criteria.\n");
   }

   return CLI_SUCCESS;
}
static int is_valid_tone_zone ( struct ast_tone_zone zone) [static]
static int load_indications ( int  reload) [static]

load indications module

Definition at line 1030 of file indications.c.

References ao2_callback, ao2_lock(), ao2_unlock(), ast_category_browse(), ast_config_destroy(), ast_config_load2(), ast_log(), ast_set_indication_country(), ast_strlen_zero(), ast_variable_retrieve(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, country, LOG_WARNING, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, parse_tone_zone(), prune_tone_zone(), and tone_zone_mark().

Referenced by ast_indications_init(), and ast_indications_reload().

{
   struct ast_config *cfg;
   const char *cxt = NULL;
   const char *country = NULL;
   struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
   int res = -1;

   cfg = ast_config_load2(config, "indications", config_flags);

   if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_WARNING, "Can't find indications config file %s.\n", config);
      return 0;
   } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
      return 0;
   }

   /* Lock the container to prevent multiple simultaneous reloads */
   ao2_lock(ast_tone_zones);

   ao2_callback(ast_tone_zones, OBJ_NODATA, tone_zone_mark, NULL);

   /* Use existing config to populate the Indication table */
   while ((cxt = ast_category_browse(cfg, cxt))) {
      /* All categories but "general" are considered countries */
      if (!strcasecmp(cxt, "general")) {
         continue;
      }

      if (parse_tone_zone(cfg, cxt)) {
         goto return_cleanup;
      }
   }

   ao2_callback(ast_tone_zones, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
         prune_tone_zone, NULL);

   /* determine which country is the default */
   country = ast_variable_retrieve(cfg, "general", "country");
   if (ast_strlen_zero(country) || ast_set_indication_country(country)) {
      ast_log(LOG_WARNING, "Unable to set the default country (for indication tones)\n");
   }

   res = 0;

return_cleanup:
   ao2_unlock(ast_tone_zones);
   ast_config_destroy(cfg);

   return res;
}
static int parse_tone_zone ( struct ast_config cfg,
const char *  country 
) [static]

Definition at line 943 of file indications.c.

References ao2_find, ast_copy_string(), ast_log(), ast_register_indication_country(), ast_tone_zone_alloc(), ast_tone_zone_lock, ast_tone_zone_unlock, ast_tone_zone_unref(), ast_variable_browse(), ast_tone_zone::country, is_valid_tone_zone(), LOG_WARNING, ast_variable::name, ast_variable::next, ast_tone_zone::nrringcadence, OBJ_POINTER, reset_tone_zone(), store_config_tone_zone(), and ast_variable::value.

Referenced by load_indications().

{
   struct ast_variable *v;
   struct ast_tone_zone *zone;
   struct ast_tone_zone tmp_zone = {
      .nrringcadence = 0,
   };
   int allocd = 0;

   ast_copy_string(tmp_zone.country, country, sizeof(tmp_zone.country));

   if ((zone = ao2_find(ast_tone_zones, &tmp_zone, OBJ_POINTER))) {
      reset_tone_zone(zone);
   } else if ((zone = ast_tone_zone_alloc())) {
      allocd = 1;
      ast_copy_string(zone->country, country, sizeof(zone->country));
   } else {
      return -1;
   }

   ast_tone_zone_lock(zone);
   for (v = ast_variable_browse(cfg, country); v; v = v->next) {
      store_config_tone_zone(zone, v->name, v->value);
   }
   ast_tone_zone_unlock(zone);

   if (allocd) {
      if (!is_valid_tone_zone(zone)) {
         ast_log(LOG_WARNING, "Indication country '%s' is invalid\n", country);
      } else if (ast_register_indication_country(zone)) {
         ast_log(LOG_WARNING, "Unable to register indication country '%s'.\n",
               country);
      }
   }

   zone = ast_tone_zone_unref(zone);

   return 0;
}
static void* playtones_alloc ( struct ast_channel chan,
void *  params 
) [static]
static int playtones_generator ( struct ast_channel chan,
void *  data,
int  len,
int  samples 
) [static]

Definition at line 160 of file indications.c.

References AST_FORMAT_SLINEAR, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_write(), ast_frame::data, playtones_state::data, ast_frame::datalen, playtones_item::duration, playtones_state::f, playtones_item::fac1, playtones_item::fac2, ast_frame::frametype, playtones_item::init_v2_1, playtones_item::init_v2_2, playtones_item::init_v3_1, playtones_item::init_v3_2, playtones_state::items, len(), LOG_WARNING, playtones_item::modulate, playtones_state::nitems, playtones_state::npos, ast_frame::offset, playtones_state::oldnpos, playtones_state::pos, ps, ast_frame::ptr, playtones_state::reppos, ast_frame::samples, ast_frame::subclass, playtones_state::v1_1, playtones_state::v1_2, playtones_state::v2_1, playtones_state::v2_2, playtones_state::v3_1, and playtones_state::v3_2.

{
   struct playtones_state *ps = data;
   struct playtones_item *pi;
   int x;

   /* we need to prepare a frame with 16 * timelen samples as we're
    * generating SLIN audio */

   len = samples * 2;
   if (len > sizeof(ps->data) / 2 - 1) {
      ast_log(LOG_WARNING, "Can't generate that much data!\n");
      return -1;
   }

   memset(&ps->f, 0, sizeof(ps->f));

   pi = &ps->items[ps->npos];

   if (ps->oldnpos != ps->npos) {
      /* Load new parameters */
      ps->v1_1 = 0;
      ps->v2_1 = pi->init_v2_1;
      ps->v3_1 = pi->init_v3_1;
      ps->v1_2 = 0;
      ps->v2_2 = pi->init_v2_2;
      ps->v3_2 = pi->init_v3_2;
      ps->oldnpos = ps->npos;
   }

   for (x = 0; x < samples; x++) {
      ps->v1_1 = ps->v2_1;
      ps->v2_1 = ps->v3_1;
      ps->v3_1 = (pi->fac1 * ps->v2_1 >> 15) - ps->v1_1;

      ps->v1_2 = ps->v2_2;
      ps->v2_2 = ps->v3_2;
      ps->v3_2 = (pi->fac2 * ps->v2_2 >> 15) - ps->v1_2;
      if (pi->modulate) {
         int p;
         p = ps->v3_2 - 32768;
         if (p < 0) {
            p = -p;
         }
         p = ((p * 9) / 10) + 1;
         ps->data[x] = (ps->v3_1 * p) >> 15;
      } else {
         ps->data[x] = ps->v3_1 + ps->v3_2;
      }
   }

   ps->f.frametype = AST_FRAME_VOICE;
   ps->f.subclass = AST_FORMAT_SLINEAR;
   ps->f.datalen = len;
   ps->f.samples = samples;
   ps->f.offset = AST_FRIENDLY_OFFSET;
   ps->f.data.ptr = ps->data;

   if (ast_write(chan, &ps->f)) {
      return -1;
   }

   ps->pos += x;

   if (pi->duration && ps->pos >= pi->duration * 8) { /* item finished? */
      ps->pos = 0;               /* start new item */
      ps->npos++;
      if (ps->npos >= ps->nitems) {       /* last item? */
         if (ps->reppos == -1) {       /* repeat set? */
            return -1;
         }
         ps->npos = ps->reppos;        /* redo from top */
      }
   }

   return 0;
}
static void playtones_release ( struct ast_channel chan,
void *  params 
) [static]

Definition at line 111 of file indications.c.

References ast_free, ast_set_write_format(), playtones_state::items, playtones_state::origwfmt, and ps.

Referenced by playtones_alloc().

{
   struct playtones_state *ps = params;

   if (chan) {
      ast_set_write_format(chan, ps->origwfmt);
   }

   if (ps->items) {
      ast_free(ps->items);
      ps->items = NULL;
   }

   ast_free(ps);
}
static int prune_tone_zone ( void *  obj,
void *  arg,
int  flags 
) [static]

Prune tones no longer in the configuration, and have the tone zone unlinked if it is no longer in the configuration at all.

Definition at line 1009 of file indications.c.

References AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_tone_zone_lock, ast_tone_zone_sound_unref(), ast_tone_zone_unlock, CMP_MATCH, ast_tone_zone_sound::entry, ast_tone_zone::killme, ast_tone_zone_sound::killme, s, and ast_tone_zone::tones.

Referenced by load_indications().

static void reset_tone_zone ( struct ast_tone_zone zone) [static]
static void store_config_tone_zone ( struct ast_tone_zone zone,
const char *  var,
const char *  value 
) [static]

Definition at line 914 of file indications.c.

References ast_register_indication(), CV_END, CV_F, CV_START, CV_STR, ast_tone_zone::description, and store_tone_zone_ring_cadence().

Referenced by parse_tone_zone().

{
   CV_START(var, value);

   CV_STR("description", zone->description);
   CV_F("ringcadence", store_tone_zone_ring_cadence(zone, value));
   CV_F("ringcadance", store_tone_zone_ring_cadence(zone, value));

   ast_register_indication(zone, var, value);

   CV_END;
}
static void store_tone_zone_ring_cadence ( struct ast_tone_zone zone,
const char *  val 
) [static]
Note:
This is called with the tone zone locked.

Definition at line 887 of file indications.c.

References ast_copy_string(), ast_log(), ast_realloc, ast_strip(), buf, LOG_WARNING, ast_tone_zone::nrringcadence, ring(), ast_tone_zone::ringcadence, strsep(), and val.

Referenced by store_config_tone_zone().

{
   char buf[1024];
   char *ring, *c = buf;

   ast_copy_string(buf, val, sizeof(buf));

   while ((ring = strsep(&c, ","))) {
      int *tmp, val;

      ring = ast_strip(ring);

      if (!isdigit(ring[0]) || (val = atoi(ring)) == -1) {
         ast_log(LOG_WARNING, "Invalid ringcadence given '%s'.\n", ring);
         continue;
      }

      if (!(tmp = ast_realloc(zone->ringcadence, (zone->nrringcadence + 1) * sizeof(int)))) {
         return;
      }

      zone->ringcadence = tmp;
      tmp[zone->nrringcadence] = val;
      zone->nrringcadence++;
   }
}
static int tone_zone_mark ( void *  obj,
void *  arg,
int  flags 
) [static]

Mark the zone and its tones before parsing configuration. We will use this to know what to remove after configuration is parsed.

Definition at line 987 of file indications.c.

References AST_LIST_TRAVERSE, ast_tone_zone_lock, ast_tone_zone_unlock, ast_tone_zone_sound::entry, ast_tone_zone_sound::killme, ast_tone_zone::killme, s, and ast_tone_zone::tones.

Referenced by load_indications().

{
   struct ast_tone_zone *zone = obj;
   struct ast_tone_zone_sound *s;

   ast_tone_zone_lock(zone);

   zone->killme = 1;

   AST_LIST_TRAVERSE(&zone->tones, s, entry) {
      s->killme = 1;
   }

   ast_tone_zone_unlock(zone);

   return 0;
}

Variable Documentation

struct ao2_container* ast_tone_zones [static]

Definition at line 63 of file indications.c.

struct ast_cli_entry cli_indications[] [static]
Initial value:
 {
   AST_CLI_DEFINE(handle_cli_indication_add,    "Add the given indication to the country"),
   AST_CLI_DEFINE(handle_cli_indication_remove, "Remove the given indication from the country"),
   AST_CLI_DEFINE(handle_cli_indication_show,   "Display a list of all countries/indications")
}

CLI entries for commands provided by this module.

Definition at line 1083 of file indications.c.

const char config[] = "indications.conf" [static]

Definition at line 45 of file indications.c.

struct ast_tone_zone* default_tone_zone [static]
Note:
Access to this is protected by locking the ast_tone_zones container

Definition at line 70 of file indications.c.

const int midi_tohz[128] [static]

Definition at line 47 of file indications.c.

struct ast_generator playtones [static]
Initial value:
 {
   .alloc     = playtones_alloc,
   .release   = playtones_release,
   .generate  = playtones_generator,
}

Definition at line 238 of file indications.c.