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"
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_sound * | ast_get_indication_tone (const struct ast_tone_zone *_zone, const char *indication) |
Locate a tone zone sound. | |
struct ast_tone_zone * | ast_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_zone * | ast_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_container * | ast_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_zone * | default_tone_zone |
static const int | midi_tohz [128] |
static struct ast_generator | playtones |
Indication Tone Handling.
Definition in file indications.c.
#define NUM_TONE_ZONE_BUCKETS 53 |
Definition at line 65 of file indications.c.
Referenced by ast_indications_init().
struct ast_tone_zone_sound* ast_get_indication_tone | ( | const struct ast_tone_zone * | zone, |
const char * | indication | ||
) | [read] |
Locate a tone zone sound.
zone | Zone to look in for a sound, if NULL, the default will be used |
indication | Sound to look for, such as "busy" |
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
country | country to find. If NULL is provided, get the default. |
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 | ) |
Load indications module.
Provided by indications.c
Definition at line 1106 of file indications.c.
References ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_tone_zone_cmp(), ast_tone_zone_hash(), load_indications(), and NUM_TONE_ZONE_BUCKETS.
Referenced by main().
{ if (!(ast_tone_zones = ao2_container_alloc(NUM_TONE_ZONE_BUCKETS, ast_tone_zone_hash, ast_tone_zone_cmp))) { return -1; } if (load_indications(0)) { return -1; } ast_cli_register_multiple(cli_indications, ARRAY_LEN(cli_indications)); return 0; }
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.
chan | the channel to play tones on |
vol | volume |
tonelist | the list of tones to play, comma separated |
interruptible | whether or not this tone can be interrupted |
0 | success |
non-zero | failure |
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 | ) |
Stop playing tones on a channel.
Stop the tones from playing
Definition at line 390 of file indications.c.
References ast_deactivate_generator().
Referenced by ast_app_dtget(), ast_indicate_data(), ast_senddigit_end(), disa_exec(), handle_stopplaytones(), pbx_builtin_waitexten(), playtone(), read_exec(), readexten_exec(), stop_indicate(), and unistim_indicate().
{ ast_deactivate_generator(chan); }
static int ast_register_indication | ( | struct ast_tone_zone * | zone, |
const char * | indication, | ||
const char * | tonelist | ||
) | [static] |
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.
Definition at line 395 of file indications.c.
References ao2_container_count().
{ return ao2_container_count(ast_tone_zones); }
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.
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().
{ return ao2_iterator_init(ast_tone_zones, 0); }
int ast_tone_zone_part_parse | ( | const char * | s, |
struct ast_tone_zone_part * | tone_data | ||
) |
Parse a tone part.
s | The 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_data | An output parameter that contains the result of the parsing. |
0 | success |
-1 | failure, 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().
static int ast_unregister_indication | ( | struct ast_tone_zone * | zone, |
const char * | indication | ||
) | [static] |
Definition at line 600 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, ast_tone_zone_sound::entry, ast_tone_zone_sound::name, and ast_tone_zone::tones.
Referenced by handle_cli_indication_remove().
{ struct ast_tone_zone_sound *ts; int res = -1; ast_tone_zone_lock(zone); 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); res = 0; break; } } AST_LIST_TRAVERSE_SAFE_END; ast_tone_zone_unlock(zone); return res; }
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] |
Definition at line 873 of file indications.c.
References AST_LIST_EMPTY, ast_strlen_zero(), ast_tone_zone_lock, ast_tone_zone_unlock, ast_tone_zone::description, and ast_tone_zone::tones.
Referenced by parse_tone_zone().
{ int res; ast_tone_zone_lock(zone); res = (!ast_strlen_zero(zone->description) && !AST_LIST_EMPTY(&zone->tones)); ast_tone_zone_unlock(zone); return res; }
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] |
Definition at line 127 of file indications.c.
References ast_calloc, ast_clear_flag, AST_FLAG_WRITE_INT, AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), playtones_def::interruptible, playtones_def::items, playtones_state::items, LOG_WARNING, ast_channel::name, playtones_def::nitems, playtones_state::nitems, playtones_state::oldnpos, playtones_state::origwfmt, pd, playtones_release(), ps, playtones_def::reppos, playtones_state::reppos, playtones_def::vol, playtones_state::vol, and ast_channel::writeformat.
{ struct playtones_def *pd = params; struct playtones_state *ps = NULL; if (!(ps = ast_calloc(1, sizeof(*ps)))) { return NULL; } ps->origwfmt = chan->writeformat; if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) { ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name); playtones_release(NULL, ps); ps = NULL; } else { ps->vol = pd->vol; ps->reppos = pd->reppos; ps->nitems = pd->nitems; ps->items = pd->items; ps->oldnpos = -1; } /* Let interrupts interrupt :) */ if (pd->interruptible) { ast_set_flag(chan, AST_FLAG_WRITE_INT); } else { ast_clear_flag(chan, AST_FLAG_WRITE_INT); } return ps; }
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().
{ struct ast_tone_zone *zone = obj; struct ast_tone_zone_sound *s; ast_tone_zone_lock(zone); AST_LIST_TRAVERSE_SAFE_BEGIN(&zone->tones, s, entry) { if (s->killme) { AST_LIST_REMOVE_CURRENT(entry); s = ast_tone_zone_sound_unref(s); } } AST_LIST_TRAVERSE_SAFE_END; ast_tone_zone_unlock(zone); return zone->killme ? CMP_MATCH : 0; }
static void reset_tone_zone | ( | struct ast_tone_zone * | zone | ) | [static] |
Definition at line 928 of file indications.c.
References ast_free, ast_tone_zone_lock, ast_tone_zone_unlock, ast_tone_zone::killme, ast_tone_zone::nrringcadence, and ast_tone_zone::ringcadence.
Referenced by parse_tone_zone().
{ ast_tone_zone_lock(zone); zone->killme = 0; if (zone->nrringcadence) { zone->nrringcadence = 0; ast_free(zone->ringcadence); zone->ringcadence = NULL; } ast_tone_zone_unlock(zone); }
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] |
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; }
struct ao2_container* ast_tone_zones [static] |
Definition at line 63 of file indications.c.
struct ast_cli_entry cli_indications[] [static] |
{ 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] |
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] |
{ .alloc = playtones_alloc, .release = playtones_release, .generate = playtones_generator, }
Definition at line 238 of file indications.c.