diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-08-23 12:31:20 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-08-23 12:31:20 +0000 |
commit | dc52cb4acbf5069b4f3aa81722361041f572b9ca (patch) | |
tree | 14b78989776c5307d2783c93ea3d4f8470eaa353 /main | |
parent | 815b5b09da5e555add7bba3d8fca588e7611248a (diff) |
Tack on ${eventextra} to the sample cel_custom.conf.
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.8@283207 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main')
-rw-r--r-- | main/ccss.c | 49 | ||||
-rw-r--r-- | main/cdr.c | 39 | ||||
-rw-r--r-- | main/channel.c | 14 | ||||
-rw-r--r-- | main/cli.c | 43 | ||||
-rw-r--r-- | main/netsock2.c | 16 | ||||
-rw-r--r-- | main/pbx.c | 43 | ||||
-rw-r--r-- | main/sched.c | 2 | ||||
-rw-r--r-- | main/translate.c | 295 | ||||
-rw-r--r-- | main/utils.c | 16 |
9 files changed, 406 insertions, 111 deletions
diff --git a/main/ccss.c b/main/ccss.c index 2cf828470..4dcacd360 100644 --- a/main/ccss.c +++ b/main/ccss.c @@ -501,38 +501,45 @@ static int count_agents_cb(void *obj, void *arg, void *data, int flags) return 0; } -static const unsigned int CC_OFFER_TIMER_DEFAULT = 20u; -static const unsigned int CCNR_AVAILABLE_TIMER_DEFAULT = 7200u; -static const unsigned int CCBS_AVAILABLE_TIMER_DEFAULT = 4800u; -static const unsigned int CC_RECALL_TIMER_DEFAULT = 20u; -static const unsigned int CC_MAX_AGENTS_DEFAULT = 5u; -static const unsigned int CC_MAX_MONITORS_DEFAULT = 5u; -static const unsigned int GLOBAL_CC_MAX_REQUESTS_DEFAULT = 20u; +#define CC_OFFER_TIMER_DEFAULT 20 /* Seconds */ +#define CCNR_AVAILABLE_TIMER_DEFAULT 7200 /* Seconds */ +#define CCBS_AVAILABLE_TIMER_DEFAULT 4800 /* Seconds */ +#define CC_RECALL_TIMER_DEFAULT 20 /* Seconds */ +#define CC_MAX_AGENTS_DEFAULT 5 +#define CC_MAX_MONITORS_DEFAULT 5 +#define GLOBAL_CC_MAX_REQUESTS_DEFAULT 20 + +static const struct ast_cc_config_params cc_default_params = { + .cc_agent_policy = AST_CC_AGENT_NEVER, + .cc_monitor_policy = AST_CC_MONITOR_NEVER, + .cc_offer_timer = CC_OFFER_TIMER_DEFAULT, + .ccnr_available_timer = CCNR_AVAILABLE_TIMER_DEFAULT, + .ccbs_available_timer = CCBS_AVAILABLE_TIMER_DEFAULT, + .cc_recall_timer = CC_RECALL_TIMER_DEFAULT, + .cc_max_agents = CC_MAX_AGENTS_DEFAULT, + .cc_max_monitors = CC_MAX_MONITORS_DEFAULT, + .cc_callback_macro = "", + .cc_agent_dialstring = "", +}; + +void ast_cc_default_config_params(struct ast_cc_config_params *params) +{ + *params = cc_default_params; +} struct ast_cc_config_params *__ast_cc_config_params_init(const char *file, int line, const char *function) { #if defined(__AST_DEBUG_MALLOC) - struct ast_cc_config_params *params = __ast_calloc(1, sizeof(*params), file, line, function); + struct ast_cc_config_params *params = __ast_malloc(sizeof(*params), file, line, function); #else - struct ast_cc_config_params *params = ast_calloc(1, sizeof(*params)); + struct ast_cc_config_params *params = ast_malloc(sizeof(*params)); #endif if (!params) { return NULL; } - /* Yeah, I could use the get/set functions, but what's the point since - * I have direct access to the structure fields in this file. - */ - params->cc_agent_policy = AST_CC_AGENT_NEVER; - params->cc_monitor_policy = AST_CC_MONITOR_NEVER; - params->cc_offer_timer = CC_OFFER_TIMER_DEFAULT; - params->ccnr_available_timer = CCNR_AVAILABLE_TIMER_DEFAULT; - params->ccbs_available_timer = CCBS_AVAILABLE_TIMER_DEFAULT; - params->cc_recall_timer = CC_RECALL_TIMER_DEFAULT; - params->cc_max_agents = CC_MAX_AGENTS_DEFAULT; - params->cc_max_monitors = CC_MAX_MONITORS_DEFAULT; - /* No need to set cc_callback_macro since calloc will 0 it out anyway */ + ast_cc_default_config_params(params); return params; } diff --git a/main/cdr.c b/main/cdr.c index a6096976d..c9b58238b 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -84,18 +84,26 @@ static struct sched_context *sched; static int cdr_sched = -1; static pthread_t cdr_thread = AST_PTHREADT_NULL; -#define BATCH_SIZE_DEFAULT 100 -#define BATCH_TIME_DEFAULT 300 -#define BATCH_SCHEDULER_ONLY_DEFAULT 0 -#define BATCH_SAFE_SHUTDOWN_DEFAULT 1 +static int enabled; +static const int ENABLED_DEFAULT = 1; -static int enabled; /*! Is the CDR subsystem enabled ? */ -static int unanswered; static int batchmode; +static const int BATCHMODE_DEFAULT = 0; + +static int unanswered; +static const int UNANSWERED_DEFAULT = 0; + static int batchsize; +static const int BATCH_SIZE_DEFAULT = 100; + static int batchtime; +static const int BATCH_TIME_DEFAULT = 300; + static int batchscheduleronly; +static const int BATCH_SCHEDULER_ONLY_DEFAULT = 0; + static int batchsafeshutdown; +static const int BATCH_SAFE_SHUTDOWN_DEFAULT = 1; AST_MUTEX_DEFINE_STATIC(cdr_batch_lock); @@ -1492,22 +1500,27 @@ static int do_reload(int reload) int res=0; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; - if ((config = ast_config_load2("cdr.conf", "cdr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) - return 0; - if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEUNCHANGED || config == CONFIG_STATUS_FILEINVALID) { + if ((config = ast_config_load2("cdr.conf", "cdr", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) { return 0; } ast_mutex_lock(&cdr_batch_lock); + was_enabled = enabled; + was_batchmode = batchmode; + batchsize = BATCH_SIZE_DEFAULT; batchtime = BATCH_TIME_DEFAULT; batchscheduleronly = BATCH_SCHEDULER_ONLY_DEFAULT; batchsafeshutdown = BATCH_SAFE_SHUTDOWN_DEFAULT; - was_enabled = enabled; - was_batchmode = batchmode; - enabled = 1; - batchmode = 0; + enabled = ENABLED_DEFAULT; + batchmode = BATCHMODE_DEFAULT; + unanswered = UNANSWERED_DEFAULT; + + if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) { + ast_mutex_unlock(&cdr_batch_lock); + return 0; + } /* don't run the next scheduled CDR posting while reloading */ AST_SCHED_DEL(sched, cdr_sched); diff --git a/main/channel.c b/main/channel.c index 32d559d0f..c0a37aaa6 100644 --- a/main/channel.c +++ b/main/channel.c @@ -5863,6 +5863,7 @@ int ast_do_masquerade(struct ast_channel *original) struct ast_party_redirecting redirecting; } exchange; struct ast_channel *clonechan, *chans[2]; + struct ast_channel *bridged; struct ast_cdr *cdr; format_t rformat = original->readformat; format_t wformat = original->writeformat; @@ -6185,6 +6186,14 @@ int ast_do_masquerade(struct ast_channel *original) pthread_kill(original->blocker, SIGURG); ast_debug(1, "Done Masquerading %s (%d)\n", original->name, original->_state); + if ((bridged = ast_bridged_channel(original))) { + ast_channel_lock(bridged); + ast_indicate(bridged, AST_CONTROL_SRCCHANGE); + ast_channel_unlock(bridged); + } + + ast_indicate(original, AST_CONTROL_SRCCHANGE); + done: /* it is possible for the clone channel to disappear during this */ if (clonechan) { @@ -6196,6 +6205,7 @@ done: ast_channel_unlock(original); ao2_link(channels, original); } + return 0; } @@ -6716,8 +6726,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha manager_bridge_event(1, 1, c0, c1); /* Before we enter in and bridge these two together tell them both the source of audio has changed */ - ast_indicate(c0, AST_CONTROL_SRCUPDATE); - ast_indicate(c1, AST_CONTROL_SRCUPDATE); + ast_indicate(c0, AST_CONTROL_SRCCHANGE); + ast_indicate(c1, AST_CONTROL_SRCCHANGE); for (/* ever */;;) { struct timeval now = { 0, }; diff --git a/main/cli.c b/main/cli.c index c9dbc6d02..77e52b863 100644 --- a/main/cli.c +++ b/main/cli.c @@ -46,6 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/lock.h" #include "editline/readline/readline.h" #include "asterisk/threadstorage.h" +#include "asterisk/translate.h" /*! * \brief List of restrictions per user. @@ -302,6 +303,28 @@ static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args return CLI_SUCCESS; } +static char *handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + switch (cmd) { + case CLI_INIT: + e->command = "core reload"; + e->usage = + "Usage: core reload\n" + " Execute a global reload.\n"; + return NULL; + + case CLI_GENERATE: + return NULL; + } + + if (a->argc != e->args) { + return CLI_SHOWUSAGE; + } + + ast_module_reload(NULL); + + return CLI_SUCCESS; +} /*! * \brief Find the debug or verbose file setting * \arg debug 1 for debug, 0 for verbose @@ -1343,6 +1366,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar struct ast_str *out = ast_str_thread_get(&ast_str_thread_global_buf, 16); char cdrtime[256]; char nf[256], wf[256], rf[256]; + struct ast_str *write_transpath = ast_str_alloca(256); + struct ast_str *read_transpath = ast_str_alloca(256); long elapsed_seconds=0; int hour=0, min=0, sec=0; #ifdef CHANNEL_TRACE @@ -1398,8 +1423,8 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar " NativeFormats: %s\n" " WriteFormat: %s\n" " ReadFormat: %s\n" - " WriteTranscode: %s\n" - " ReadTranscode: %s\n" + " WriteTranscode: %s %s\n" + " ReadTranscode: %s %s\n" "1st File Descriptor: %d\n" " Frames in: %d%s\n" " Frames out: %d%s\n" @@ -1426,7 +1451,9 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar ast_getformatname_multiple(wf, sizeof(wf), c->writeformat), ast_getformatname_multiple(rf, sizeof(rf), c->readformat), c->writetrans ? "Yes" : "No", + ast_translate_path_to_str(c->writetrans, &write_transpath), c->readtrans ? "Yes" : "No", + ast_translate_path_to_str(c->readtrans, &read_transpath), c->fds[0], c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", @@ -1485,7 +1512,13 @@ char *ast_complete_channels(const char *line, const char *word, int pos, int sta return NULL; } - if (!(iter = ast_channel_iterator_by_name_new(word, strlen(word)))) { + if (ast_strlen_zero(word)) { + iter = ast_channel_iterator_all_new(); + } else { + iter = ast_channel_iterator_by_name_new(word, strlen(word)); + } + + if (!iter) { return NULL; } @@ -1609,7 +1642,9 @@ static struct ast_cli_entry cli_cli[] = { AST_CLI_DEFINE(handle_load, "Load a module by name"), - AST_CLI_DEFINE(handle_reload, "Reload configuration"), + AST_CLI_DEFINE(handle_reload, "Reload configuration for a module"), + + AST_CLI_DEFINE(handle_core_reload, "Global reload"), AST_CLI_DEFINE(handle_unload, "Unload a module by name"), diff --git a/main/netsock2.c b/main/netsock2.c index 929f4b337..99f7eac89 100644 --- a/main/netsock2.c +++ b/main/netsock2.c @@ -118,7 +118,7 @@ char *ast_sockaddr_stringify_fmt(const struct ast_sockaddr *sa, int format) return ast_str_buffer(str); } -int static _ast_sockaddr_parse(char *str, char **host, char **port, int flags) +int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags) { char *s = str; @@ -187,7 +187,7 @@ int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags) int e; s = ast_strdupa(str); - if (!_ast_sockaddr_parse(s, &host, &port, flags)) { + if (!ast_sockaddr_split_hostport(s, &host, &port, flags)) { return 0; } @@ -233,7 +233,7 @@ int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int e, i, res_cnt; s = ast_strdupa(str); - if (!_ast_sockaddr_parse(s, &host, &port, flags)) { + if (!ast_sockaddr_split_hostport(s, &host, &port, flags)) { return 0; } @@ -343,7 +343,9 @@ uint16_t _ast_sockaddr_port(const struct ast_sockaddr *addr, const char *file, i addr->len == sizeof(struct sockaddr_in6)) { return ntohs(((struct sockaddr_in6 *)&addr->ss)->sin6_port); } - ast_log(__LOG_DEBUG, file, line, func, "Not an IPv4 nor IPv6 address, cannot get port.\n"); + if (option_debug >= 1) { + ast_log(__LOG_DEBUG, file, line, func, "Not an IPv4 nor IPv6 address, cannot get port.\n"); + } return 0; } @@ -355,7 +357,7 @@ void _ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port, const char } else if (addr->ss.ss_family == AF_INET6 && addr->len == sizeof(struct sockaddr_in6)) { ((struct sockaddr_in6 *)&addr->ss)->sin6_port = htons(port); - } else { + } else if (option_debug >= 1) { ast_log(__LOG_DEBUG, file, line, func, "Not an IPv4 nor IPv6 address, cannot set port.\n"); } @@ -485,7 +487,7 @@ int _ast_sockaddr_to_sin(const struct ast_sockaddr *addr, return 0; } - if (addr->ss.ss_family != AF_INET) { + if (addr->ss.ss_family != AF_INET && option_debug >= 1) { ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n"); } @@ -498,7 +500,7 @@ void _ast_sockaddr_from_sin(struct ast_sockaddr *addr, const struct sockaddr_in { memcpy(&addr->ss, sin, sizeof(*sin)); - if (addr->ss.ss_family != AF_INET) { + if (addr->ss.ss_family != AF_INET && option_debug >= 1) { ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n"); } diff --git a/main/pbx.c b/main/pbx.c index 4216b853a..67163de3e 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -1164,7 +1164,11 @@ static struct pbx_builtin { static struct ast_context *contexts; static struct ast_hashtab *contexts_table = NULL; -AST_RWLOCK_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */ +/*!\brief Lock for the ast_context list + * This lock MUST be recursive, or a deadlock on reload may result. See + * https://issues.asterisk.org/view.php?id=17643 + */ +AST_MUTEX_DEFINE_STATIC(conlock); static AST_RWLIST_HEAD_STATIC(apps, ast_app); @@ -6850,7 +6854,7 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */ ast_unlock_contexts(); ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar); - ast_verb(3, "Registered extension context '%s' (%p) in table %p; registrar: %s\n", tmp->name, tmp, contexts_table, registrar); + ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar); } else { tmp->next = *local_contexts; if (exttable) @@ -6858,7 +6862,7 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, *local_contexts = tmp; ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar); - ast_verb(3, "Registered extension context '%s' (%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar); + ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar); } return tmp; } @@ -7016,7 +7020,6 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_ */ struct timeval begintime, writelocktime, endlocktime, enddeltime; - int wrlock_ver; begintime = ast_tvnow(); ast_rdlock_contexts(); @@ -7025,15 +7028,6 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_ context_merge(extcontexts, exttable, tmp, registrar); } ast_hashtab_end_traversal(iter); - wrlock_ver = ast_wrlock_contexts_version(); - - ast_unlock_contexts(); /* this feels real retarded, but you must do - what you must do If this isn't done, the following - wrlock is a guraranteed deadlock */ - ast_wrlock_contexts(); - if (ast_wrlock_contexts_version() > wrlock_ver+1) { - ast_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n"); - } AST_RWLIST_WRLOCK(&hints); writelocktime = ast_tvnow(); @@ -8209,11 +8203,11 @@ static int ast_add_extension2_lockopt(struct ast_context *con, } if (tmp->matchcid) { - ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n", - tmp->exten, tmp->priority, tmp->cidmatch, con->name, con); + ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s\n", + tmp->exten, tmp->priority, tmp->cidmatch, con->name); } else { - ast_verb(3, "Added extension '%s' priority %d to %s (%p)\n", - tmp->exten, tmp->priority, con->name, con); + ast_verb(3, "Added extension '%s' priority %d to %s\n", + tmp->exten, tmp->priority, con->name); } return 0; @@ -9836,32 +9830,23 @@ int load_pbx(void) return 0; } -static int conlock_wrlock_version = 0; - -int ast_wrlock_contexts_version(void) -{ - return conlock_wrlock_version; -} /* * Lock context list functions ... */ int ast_wrlock_contexts() { - int res = ast_rwlock_wrlock(&conlock); - if (!res) - ast_atomic_fetchadd_int(&conlock_wrlock_version, 1); - return res; + return ast_mutex_lock(&conlock); } int ast_rdlock_contexts() { - return ast_rwlock_rdlock(&conlock); + return ast_mutex_lock(&conlock); } int ast_unlock_contexts() { - return ast_rwlock_unlock(&conlock); + return ast_mutex_unlock(&conlock); } /* diff --git a/main/sched.c b/main/sched.c index 78de1a99e..8a3602a39 100644 --- a/main/sched.c +++ b/main/sched.c @@ -604,13 +604,13 @@ int ast_sched_runq(struct sched_context *con) ast_mutex_lock(&con->lock); + when = ast_tvadd(ast_tvnow(), ast_tv(0, 1000)); for (numevents = 0; (current = ast_heap_peek(con->sched_heap, 1)); numevents++) { /* schedule all events which are going to expire within 1ms. * We only care about millisecond accuracy anyway, so this will * help us get more than one event at one time if they are very * close together. */ - when = ast_tvadd(ast_tvnow(), ast_tv(0, 1000)); if (ast_tvcmp(current->when, when) != -1) { break; } diff --git a/main/translate.c b/main/translate.c index 24d886473..61b4a4686 100644 --- a/main/translate.c +++ b/main/translate.c @@ -45,10 +45,23 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") /*! \brief the list of translators */ static AST_RWLIST_HEAD_STATIC(translators, ast_translator); + +/*! \brief these values indicate how a translation path will affect the sample rate + * + * \note These must stay in this order. They are ordered by most optimal selection first. + */ +enum path_samp_change { + RATE_CHANGE_NONE = 0, /*!< path uses the same sample rate consistently */ + RATE_CHANGE_UPSAMP = 1, /*!< path will up the sample rate during a translation */ + RATE_CHANGE_DOWNSAMP = 2, /*!< path will have to down the sample rate during a translation. */ + RATE_CHANGE_UPSAMP_DOWNSAMP = 3, /*!< path will both up and down the sample rate during translation */ +}; + struct translator_path { struct ast_translator *step; /*!< Next step translator */ unsigned int cost; /*!< Complete cost to destination */ unsigned int multistep; /*!< Multiple conversions required for this translation */ + enum path_samp_change rate_change; /*!< does this path require a sample rate change, if so what kind. */ }; /*! \brief a matrix that, for any pair of supported formats, @@ -402,6 +415,24 @@ static void calc_cost(struct ast_translator *t, int seconds) t->cost = 1; } +static enum path_samp_change get_rate_change_result(format_t src, format_t dst) +{ + int src_rate = ast_format_rate(src); + int dst_rate = ast_format_rate(dst); + + /* if src rate is less than dst rate, a sample upgrade is required */ + if (src_rate < dst_rate) { + return RATE_CHANGE_UPSAMP; + } + + /* if src rate is larger than dst rate, a downgrade is required */ + if (src_rate > dst_rate) { + return RATE_CHANGE_DOWNSAMP; + } + + return RATE_CHANGE_NONE; +} + /*! * \brief rebuild a translation matrix. * \note This function expects the list of translators to be locked @@ -409,6 +440,8 @@ static void calc_cost(struct ast_translator *t, int seconds) static void rebuild_matrix(int samples) { struct ast_translator *t; + int new_rate_change; + int newcost; int x; /* source format index */ int y; /* intermediate format index */ int z; /* destination format index */ @@ -427,10 +460,21 @@ static void rebuild_matrix(int samples) if (samples) calc_cost(t, samples); - - if (!tr_matrix[x][z].step || t->cost < tr_matrix[x][z].cost) { + + new_rate_change = get_rate_change_result(1LL << t->srcfmt, 1LL << t->dstfmt); + + /* this translator is the best choice if any of the below are true. + * 1. no translation path is set between x and z yet. + * 2. the new translation costs less and sample rate is no worse than old one. + * 3. the new translation has a better sample rate conversion than the old one. + */ + if (!tr_matrix[x][z].step || + ((t->cost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) || + (new_rate_change < tr_matrix[x][z].rate_change)) { + tr_matrix[x][z].step = t; tr_matrix[x][z].cost = t->cost; + tr_matrix[x][z].rate_change = new_rate_change; } } @@ -442,31 +486,73 @@ static void rebuild_matrix(int samples) */ for (;;) { int changed = 0; + int better_choice = 0; for (x = 0; x < MAX_FORMAT; x++) { /* source format */ for (y = 0; y < MAX_FORMAT; y++) { /* intermediate format */ if (x == y) /* skip ourselves */ continue; - - for (z = 0; z<MAX_FORMAT; z++) { /* dst format */ - int newcost; - + for (z = 0; z < MAX_FORMAT; z++) { /* dst format */ if (z == x || z == y) /* skip null conversions */ continue; if (!tr_matrix[x][y].step) /* no path from x to y */ continue; if (!tr_matrix[y][z].step) /* no path from y to z */ continue; + + /* Does x->y->z result in a less optimal sample rate change? + * Never downgrade the sample rate conversion quality regardless + * of any cost improvements */ + if (tr_matrix[x][z].step && + ((tr_matrix[x][z].rate_change < tr_matrix[x][y].rate_change) || + (tr_matrix[x][z].rate_change < tr_matrix[y][z].rate_change))) { + continue; + } + + /* is x->y->z a better sample rate confersion that the current x->z? */ + new_rate_change = tr_matrix[x][y].rate_change + tr_matrix[y][z].rate_change; + + /* calculate cost from x->y->z */ newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost; - if (tr_matrix[x][z].step && newcost >= tr_matrix[x][z].cost) - continue; /* x->y->z is more expensive than - * the existing path */ + + /* Is x->y->z a better choice than x->z? + * There are three conditions for x->y->z to be a better choice than x->z + * 1. if there is no step directly between x->z then x->y->z is the best and only current option. + * 2. if x->y->z costs less and the sample rate conversion is no less optimal. + * 3. if x->y->z results in a more optimal sample rate conversion. */ + if (!tr_matrix[x][z].step) { + better_choice = 1; + } else if ((newcost < tr_matrix[x][z].cost) && (new_rate_change <= tr_matrix[x][z].rate_change)) { + better_choice = 1; + } else if (new_rate_change < tr_matrix[x][z].rate_change) { + better_choice = 1; + } else { + better_choice = 0; + } + + if (!better_choice) { + continue; + } /* ok, we can get from x to z via y with a cost that - is the sum of the transition from x to y and - from y to z */ - + is the sum of the transition from x to y and from y to z */ tr_matrix[x][z].step = tr_matrix[x][y].step; tr_matrix[x][z].cost = newcost; tr_matrix[x][z].multistep = 1; + + /* now calculate what kind of sample rate change is required for this multi-step path + * + * if both paths require a change in rate, and they are not in the same direction + * then this is a up sample down sample conversion scenario. */ + if ((tr_matrix[x][y].rate_change > RATE_CHANGE_NONE) && + (tr_matrix[y][z].rate_change > RATE_CHANGE_NONE) && + (tr_matrix[x][y].rate_change != tr_matrix[y][z].rate_change)) { + + tr_matrix[x][z].rate_change = RATE_CHANGE_UPSAMP_DOWNSAMP; + } else { + /* else just set the rate change to whichever is worse */ + tr_matrix[x][z].rate_change = tr_matrix[x][y].rate_change > tr_matrix[y][z].rate_change + ? tr_matrix[x][y].rate_change : tr_matrix[y][z].rate_change; + } + ast_debug(3, "Discovered %d cost path from %s to %s, via %s\n", tr_matrix[x][z].cost, ast_getformatname(1LL << x), ast_getformatname(1LL << z), ast_getformatname(1LL << y)); changed++; @@ -478,30 +564,134 @@ static void rebuild_matrix(int samples) } } +const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str) +{ + struct ast_trans_pvt *pn = p; + + if (!p || !p->t) { + return ""; + } + + ast_str_set(str, 0, "%s", ast_getformatname(1LL << p->t->srcfmt)); + + while ( (p = pn) ) { + pn = p->next; + ast_str_append(str, 0, "->%s", ast_getformatname(1LL << p->t->dstfmt)); + } + + return ast_str_buffer(*str); +} + +static char *complete_trans_path_choice(const char *line, const char *word, int pos, int state) +{ + int which = 0; + int wordlen = strlen(word); + int i; + char *ret = NULL; + size_t len = 0; + const struct ast_format_list *format_list = ast_get_format_list(&len); + + for (i = 0; i < len; i++) { + if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) { + continue; + } + if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) { + ret = ast_strdup(format_list[i].name); + break; + } + } + return ret; +} + static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { -#define SHOW_TRANS 16 +#define SHOW_TRANS 64 + static const char * const option1[] = { "recalc", "paths", NULL }; int x, y, z; int curlen = 0, longest = 0, magnitude[SHOW_TRANS] = { 0, }; switch (cmd) { case CLI_INIT: - e->command = "core show translation [recalc]"; + e->command = "core show translation"; e->usage = - "Usage: core show translation [recalc [<recalc seconds>]]\n" - " Displays known codec translators and the cost associated\n" - " with each conversion. If the argument 'recalc' is supplied along\n" - " with optional number of seconds to test a new test will be performed\n" - " as the chart is being displayed.\n"; + "Usage: 'core show translation' can be used in two ways.\n" + " 1. 'core show translation [recalc [<recalc seconds>]]\n" + " Displays known codec translators and the cost associated\n" + " with each conversion. If the argument 'recalc' is supplied along\n" + " with optional number of seconds to test a new test will be performed\n" + " as the chart is being displayed.\n" + " 2. 'core show translation paths [codec]'\n" + " This will display all the translation paths associated with a codec\n"; return NULL; case CLI_GENERATE: + if (a->pos == 3) { + return ast_cli_complete(a->word, option1, a->n); + } + if (a->pos == 4 && !strcasecmp(a->argv[3], option1[1])) { + return complete_trans_path_choice(a->line, a->word, a->pos, a->n); + } return NULL; } if (a->argc > 5) return CLI_SHOWUSAGE; - if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) { + if (a->argv[3] && !strcasecmp(a->argv[3], option1[1]) && a->argc == 5) { + format_t input_src = 0; + format_t src = 0; + size_t len = 0; + int dst; + int i; + const struct ast_format_list *format_list = ast_get_format_list(&len); + struct ast_str *str = ast_str_alloca(256); + struct ast_translator *step; + + for (i = 0; i < len; i++) { + if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK)) { + continue; + } + if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) { + input_src = format_list[i].bits; + } + } + + if (!input_src) { + ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]); + return CLI_FAILURE; + } + + AST_RWLIST_RDLOCK(&translators); + ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(input_src)); + for (i = 0; i < len; i++) { + if (!(format_list[i].bits & AST_FORMAT_AUDIO_MASK) || (format_list[i].bits == input_src)) { + continue; + } + dst = powerof(format_list[i].bits); + src = powerof(input_src); + ast_str_reset(str); + if (tr_matrix[src][dst].step) { + ast_str_append(&str, 0, "%s", ast_getformatname(1LL << tr_matrix[src][dst].step->srcfmt)); + while (src != dst) { + step = tr_matrix[src][dst].step; + if (!step) { + ast_str_reset(str); + break; + } + ast_str_append(&str, 0, "->%s", ast_getformatname(1LL << step->dstfmt)); + src = step->dstfmt; + } + } + + if (ast_strlen_zero(ast_str_buffer(str))) { + ast_str_set(&str, 0, "No Translation Path"); + } + + ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str)); + } + AST_RWLIST_UNLOCK(&translators); + + return CLI_SUCCESS; + } else if (a->argv[3] && !strcasecmp(a->argv[3], "recalc")) { z = a->argv[4] ? atoi(a->argv[4]) : 1; if (z <= 0) { @@ -526,22 +716,33 @@ static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, ast_cli(a->fd, " Source Format (Rows) Destination Format (Columns)\n\n"); /* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */ for (x = 0; x < SHOW_TRANS; x++) { + /* translation only applies to audio right now. */ + if (!(AST_FORMAT_AUDIO_MASK & (1LL << (x)))) + continue; curlen = strlen(ast_getformatname(1LL << (x))); if (curlen > longest) longest = curlen; for (y = 0; y < SHOW_TRANS; y++) { + if (!(AST_FORMAT_AUDIO_MASK & (1LL << (y)))) + continue; if (tr_matrix[x][y].cost > pow(10, magnitude[x])) { magnitude[y] = floor(log10(tr_matrix[x][y].cost)); } } } for (x = -1; x < SHOW_TRANS; x++) { - struct ast_str *out = ast_str_alloca(125); + struct ast_str *out = ast_str_alloca(256); + /* translation only applies to audio right now. */ + if (x >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (x)))) + continue; /*Go ahead and move to next iteration if dealing with an unknown codec*/ if(x >= 0 && !strcmp(ast_getformatname(1LL << (x)), "unknown")) continue; ast_str_set(&out, -1, " "); for (y = -1; y < SHOW_TRANS; y++) { + /* translation only applies to audio right now. */ + if (y >= 0 && !(AST_FORMAT_AUDIO_MASK & (1LL << (y)))) + continue; /*Go ahead and move to next iteration if dealing with an unknown codec*/ if (y >= 0 && !strcmp(ast_getformatname(1LL << (y)), "unknown")) continue; @@ -715,37 +916,65 @@ void ast_translator_deactivate(struct ast_translator *t) format_t ast_translator_best_choice(format_t *dst, format_t *srcs) { int x,y; + int better = 0; + int besttime = INT_MAX; + int beststeps = INT_MAX; + unsigned int best_rate_change = INT_MAX; format_t best = -1; format_t bestdst = 0; format_t cur, cursrc; - int besttime = INT_MAX; - int beststeps = INT_MAX; format_t common = ((*dst) & (*srcs)) & AST_FORMAT_AUDIO_MASK; /* are there common formats ? */ if (common) { /* yes, pick one and return */ for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) { - if (cur & common) /* guaranteed to find one */ - break; + if (!(cur & common)) { + continue; + } + + /* We are guaranteed to find one common format. */ + if (best == -1) { + best = cur; + continue; + } + /* If there are multiple common formats, pick the one with the highest sample rate */ + if (ast_format_rate(best) < ast_format_rate(cur)) { + best = cur; + continue; + } } /* We are done, this is a common format to both. */ - *srcs = *dst = cur; + *srcs = *dst = best; return 0; - } else { /* No, we will need to translate */ + } else { /* No, we will need to translate */ AST_RWLIST_RDLOCK(&translators); for (cur = 1, y = 0; y <= MAX_AUDIO_FORMAT; cur <<= 1, y++) { - if (! (cur & *dst)) + if (! (cur & *dst)) { continue; + } for (cursrc = 1, x = 0; x <= MAX_AUDIO_FORMAT; cursrc <<= 1, x++) { - if (!(*srcs & cursrc) || !tr_matrix[x][y].step || - tr_matrix[x][y].cost > besttime) - continue; /* not existing or no better */ - if (tr_matrix[x][y].cost < besttime || - tr_matrix[x][y].multistep < beststeps) { + if (!(*srcs & cursrc) || !tr_matrix[x][y].step) { + continue; + } + + /* This is a better choice if any of the following are true. + * 1. The sample rate conversion is better than the current pick. + * 2. the sample rate conversion is no worse than the current pick and the cost or multistep is better + */ + better = 0; + if (tr_matrix[x][y].rate_change < best_rate_change) { + better = 1; /* this match has a better rate conversion */ + } + if ((tr_matrix[x][y].rate_change <= best_rate_change) && + (tr_matrix[x][y].cost < besttime || tr_matrix[x][y].multistep < beststeps)) { + better = 1; /* this match has no worse rate conversion and the conversion cost is less */ + } + if (better) { /* better than what we have so far */ best = cursrc; bestdst = cur; besttime = tr_matrix[x][y].cost; beststeps = tr_matrix[x][y].multistep; + best_rate_change = tr_matrix[x][y].rate_change; } } } diff --git a/main/utils.c b/main/utils.c index 5961a7339..6f2c884d0 100644 --- a/main/utils.c +++ b/main/utils.c @@ -1615,7 +1615,8 @@ ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr size_t space = (*pool_head)->size - (*pool_head)->used; size_t to_alloc = needed + sizeof(ast_string_field_allocation); - if (__builtin_expect(to_alloc > space, 0)) { + /* This +1 accounts for alignment on SPARC */ + if (__builtin_expect(to_alloc + 1 > space, 0)) { size_t new_size = (*pool_head)->size; while (new_size < to_alloc) { @@ -1632,6 +1633,13 @@ ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr } result = (*pool_head)->base + (*pool_head)->used; +#ifdef __sparc__ + /* SPARC requires that the allocation field be aligned. */ + if ((long) result % sizeof(ast_string_field_allocation)) { + result++; + (*pool_head)->used++; + } +#endif (*pool_head)->used += to_alloc; (*pool_head)->active += needed; result += sizeof(ast_string_field_allocation); @@ -1706,6 +1714,12 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr, } } else { target = (*pool_head)->base + (*pool_head)->used + sizeof(ast_string_field_allocation); +#ifdef __sparc__ + if ((long) target % sizeof(ast_string_field_allocation)) { + target++; + space--; + } +#endif available = space - sizeof(ast_string_field_allocation); } |