summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/asterisk/features_config.h15
-rw-r--r--main/astmm.c107
-rw-r--r--main/bridge_basic.c80
-rw-r--r--main/features_config.c15
-rw-r--r--main/taskprocessor.c5
5 files changed, 182 insertions, 40 deletions
diff --git a/include/asterisk/features_config.h b/include/asterisk/features_config.h
index b15759ba6..baaff183b 100644
--- a/include/asterisk/features_config.h
+++ b/include/asterisk/features_config.h
@@ -102,6 +102,21 @@ struct ast_features_xfer_config {
struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_channel *chan);
/*!
+ * \brief Get the transfer configuration option xferfailsound
+ *
+ * \note The channel should be locked before calling this function.
+ * \note The returned value has to be freed.
+ *
+ * If no channel is provided, then option is pulled from the global
+ * transfer configuration.
+ *
+ * \param chan The channel to get configuration options for
+ * \retval NULL Failed to get configuration
+ * \retval non-NULL The xferfailsound
+ */
+char *ast_get_chan_features_xferfailsound(struct ast_channel *chan);
+
+/*!
* \brief Configuration relating to call pickup
*/
struct ast_features_pickup_config {
diff --git a/main/astmm.c b/main/astmm.c
index 5812174d5..331778489 100644
--- a/main/astmm.c
+++ b/main/astmm.c
@@ -672,6 +672,32 @@ int __ast_vasprintf(char **strp, const char *fmt, va_list ap, const char *file,
return size;
}
+/*!
+ * \internal
+ * \brief Count the number of bytes in the specified freed region.
+ *
+ * \param freed Already freed region blocks storage.
+ *
+ * \note reglock must be locked before calling.
+ *
+ * \return Number of bytes in freed region.
+ */
+static size_t freed_regions_size(struct ast_freed_regions *freed)
+{
+ size_t total_len = 0;
+ int idx;
+ struct ast_region *old;
+
+ for (idx = 0; idx < ARRAY_LEN(freed->regions); ++idx) {
+ old = freed->regions[idx];
+ if (old) {
+ total_len += old->len;
+ }
+ }
+
+ return total_len;
+}
+
static char *handle_memory_atexit_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
switch (cmd) {
@@ -774,12 +800,54 @@ static char *handle_memory_atexit_summary(struct ast_cli_entry *e, int cmd, stru
return CLI_SUCCESS;
}
+/*!
+ * \internal
+ * \brief Common summary output at the end of the memory show commands.
+ *
+ * \param fd CLI output file descriptor.
+ * \param whales_len Accumulated size of free large allocations.
+ * \param minnows_len Accumulated size of free small allocations.
+ * \param total_len Accumulated size of all current allocations.
+ * \param selected_len Accumulated size of the selected allocations.
+ * \param cache_len Accumulated size of the allocations that are part of a cache.
+ * \param count Number of selected allocations.
+ *
+ * \return Nothing
+ */
+static void print_memory_show_common_stats(int fd,
+ unsigned int whales_len,
+ unsigned int minnows_len,
+ unsigned int total_len,
+ unsigned int selected_len,
+ unsigned int cache_len,
+ unsigned int count)
+{
+ if (cache_len) {
+ ast_cli(fd, "%10u bytes allocated (%u in caches) in %u selected allocations\n\n",
+ selected_len, cache_len, count);
+ } else {
+ ast_cli(fd, "%10u bytes allocated in %u selected allocations\n\n",
+ selected_len, count);
+ }
+
+ ast_cli(fd, "%10u bytes in all allocations\n", total_len);
+ ast_cli(fd, "%10u bytes in deferred free large allocations\n", whales_len);
+ ast_cli(fd, "%10u bytes in deferred free small allocations\n", minnows_len);
+ ast_cli(fd, "%10u bytes in deferred free allocations\n",
+ whales_len + minnows_len);
+ ast_cli(fd, "%10u bytes in all allocations and deferred free allocations\n",
+ total_len + whales_len + minnows_len);
+}
+
static char *handle_memory_show_allocations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
const char *fn = NULL;
struct ast_region *reg;
unsigned int idx;
- unsigned int len = 0;
+ unsigned int whales_len;
+ unsigned int minnows_len;
+ unsigned int total_len = 0;
+ unsigned int selected_len = 0;
unsigned int cache_len = 0;
unsigned int count = 0;
@@ -813,6 +881,7 @@ static char *handle_memory_show_allocations(struct ast_cli_entry *e, int cmd, st
ast_mutex_lock(&reglock);
for (idx = 0; idx < ARRAY_LEN(regions); ++idx) {
for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) {
+ total_len += reg->len;
if (fn && strcasecmp(fn, reg->file)) {
continue;
}
@@ -823,21 +892,21 @@ static char *handle_memory_show_allocations(struct ast_cli_entry *e, int cmd, st
(unsigned int) reg->len, reg->cache ? " (cache)" : "",
reg->func, reg->lineno, reg->file);
- len += reg->len;
+ selected_len += reg->len;
if (reg->cache) {
cache_len += reg->len;
}
++count;
}
}
+
+ whales_len = freed_regions_size(&whales);
+ minnows_len = freed_regions_size(&minnows);
ast_mutex_unlock(&reglock);
- if (cache_len) {
- ast_cli(a->fd, "%u bytes allocated (%u in caches) in %u allocations\n",
- len, cache_len, count);
- } else {
- ast_cli(a->fd, "%u bytes allocated in %u allocations\n", len, count);
- }
+ print_memory_show_common_stats(a->fd,
+ whales_len, minnows_len, total_len,
+ selected_len, cache_len, count);
return CLI_SUCCESS;
}
@@ -850,7 +919,10 @@ static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct
int idx;
int cmp;
struct ast_region *reg;
- unsigned int len = 0;
+ unsigned int whales_len;
+ unsigned int minnows_len;
+ unsigned int total_len = 0;
+ unsigned int selected_len = 0;
unsigned int cache_len = 0;
unsigned int count = 0;
struct file_summary {
@@ -868,7 +940,7 @@ static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct
e->usage =
"Usage: memory show summary [<file>]\n"
" Summarizes heap memory allocations by file, or optionally\n"
- " by line, if a file is specified.\n";
+ " by line if a file is specified.\n";
return NULL;
case CLI_GENERATE:
return NULL;
@@ -883,6 +955,7 @@ static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct
ast_mutex_lock(&reglock);
for (idx = 0; idx < ARRAY_LEN(regions); ++idx) {
for (reg = regions[idx]; reg; reg = AST_LIST_NEXT(reg, node)) {
+ total_len += reg->len;
if (fn) {
if (strcasecmp(fn, reg->file)) {
continue;
@@ -941,11 +1014,14 @@ static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct
++cur->count;
}
}
+
+ whales_len = freed_regions_size(&whales);
+ minnows_len = freed_regions_size(&minnows);
ast_mutex_unlock(&reglock);
/* Dump the whole list */
for (cur = list; cur; cur = cur->next) {
- len += cur->len;
+ selected_len += cur->len;
cache_len += cur->cache_len;
count += cur->count;
if (cur->cache_len) {
@@ -967,12 +1043,9 @@ static char *handle_memory_show_summary(struct ast_cli_entry *e, int cmd, struct
}
}
- if (cache_len) {
- ast_cli(a->fd, "%u bytes allocated (%u in caches) in %u allocations\n",
- len, cache_len, count);
- } else {
- ast_cli(a->fd, "%u bytes allocated in %u allocations\n", len, count);
- }
+ print_memory_show_common_stats(a->fd,
+ whales_len, minnows_len, total_len,
+ selected_len, cache_len, count);
return CLI_SUCCESS;
}
diff --git a/main/bridge_basic.c b/main/bridge_basic.c
index dc5d7f016..c4cf2a074 100644
--- a/main/bridge_basic.c
+++ b/main/bridge_basic.c
@@ -1296,8 +1296,6 @@ struct attended_transfer_properties {
AST_STRING_FIELD(exten);
/*! Context of transfer target */
AST_STRING_FIELD(context);
- /*! Sound to play on failure */
- AST_STRING_FIELD(failsound);
/*! Sound to play when transfer completes */
AST_STRING_FIELD(xfersound);
/*! The channel technology of the transferer channel */
@@ -1421,12 +1419,21 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc(
struct ast_flags *transferer_features;
props = ao2_alloc(sizeof(*props), attended_transfer_properties_destructor);
- if (!props || ast_string_field_init(props, 64)) {
+ if (!props) {
+ ast_log(LOG_ERROR, "Unable to create props - channel %s, context %s\n",
+ ast_channel_name(transferer), context);
return NULL;
}
ast_cond_init(&props->cond, NULL);
+ if (ast_string_field_init(props, 64)) {
+ ast_log(LOG_ERROR, "Unable to initialize prop fields - channel %s, context %s\n",
+ ast_channel_name(transferer), context);
+ ao2_ref(props, -1);
+ return NULL;
+ }
+
props->target_framehook_id = -1;
props->transferer = ast_channel_ref(transferer);
@@ -1447,7 +1454,6 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc(
props->atxfernoanswertimeout = xfer_cfg->atxfernoanswertimeout;
props->atxferloopdelay = xfer_cfg->atxferloopdelay;
ast_string_field_set(props, context, get_transfer_context(transferer, context));
- ast_string_field_set(props, failsound, xfer_cfg->xferfailsound);
ast_string_field_set(props, xfersound, xfer_cfg->xfersound);
ao2_ref(xfer_cfg, -1);
@@ -1708,6 +1714,44 @@ static void play_sound(struct ast_channel *chan, const char *sound)
}
/*!
+ * \brief Helper method to play a fail sound on a channel in a bridge
+ *
+ * \param chan The channel to play the fail sound to
+ */
+static void play_failsound(struct ast_channel *chan)
+{
+ char *sound;
+
+ ast_channel_lock(chan);
+ sound = ast_get_chan_features_xferfailsound(chan);
+ ast_channel_unlock(chan);
+
+ if (sound) {
+ play_sound(chan, sound);
+ ast_free(sound);
+ }
+}
+
+/*!
+ * \brief Helper method to stream a fail sound on a channel
+ *
+ * \param chan The channel to stream the fail sound to
+ */
+static void stream_failsound(struct ast_channel *chan)
+{
+ char *sound;
+
+ ast_channel_lock(chan);
+ sound = ast_get_chan_features_xferfailsound(chan);
+ ast_channel_unlock(chan);
+
+ if (sound) {
+ ast_stream_and_wait(chan, sound, AST_DIGIT_NONE);
+ ast_free(sound);
+ }
+}
+
+/*!
* \brief Helper method to place a channel in a bridge on hold
*/
static void hold(struct ast_channel *chan)
@@ -2049,7 +2093,7 @@ static enum attended_transfer_state calling_target_exit(struct attended_transfer
{
switch (stimulus) {
case STIMULUS_TRANSFEREE_HANGUP:
- play_sound(props->transferer, props->failsound);
+ play_failsound(props->transferer);
publish_transfer_fail(props);
return TRANSFER_FAIL;
case STIMULUS_DTMF_ATXFER_COMPLETE:
@@ -2061,7 +2105,7 @@ static enum attended_transfer_state calling_target_exit(struct attended_transfer
case STIMULUS_TRANSFER_TARGET_HANGUP:
case STIMULUS_TIMEOUT:
case STIMULUS_DTMF_ATXFER_ABORT:
- play_sound(props->transferer, props->failsound);
+ play_failsound(props->transferer);
return TRANSFER_REBRIDGE;
case STIMULUS_DTMF_ATXFER_THREEWAY:
bridge_unhold(props->transferee_bridge);
@@ -2090,7 +2134,7 @@ static enum attended_transfer_state hesitant_exit(struct attended_transfer_prope
{
switch (stimulus) {
case STIMULUS_TRANSFEREE_HANGUP:
- play_sound(props->transferer, props->failsound);
+ play_failsound(props->transferer);
publish_transfer_fail(props);
return TRANSFER_FAIL;
case STIMULUS_DTMF_ATXFER_COMPLETE:
@@ -2101,7 +2145,7 @@ static enum attended_transfer_state hesitant_exit(struct attended_transfer_prope
case STIMULUS_TRANSFER_TARGET_HANGUP:
case STIMULUS_TIMEOUT:
case STIMULUS_DTMF_ATXFER_ABORT:
- play_sound(props->transferer, props->failsound);
+ play_failsound(props->transferer);
return TRANSFER_RESUME;
case STIMULUS_DTMF_ATXFER_THREEWAY:
return TRANSFER_THREEWAY;
@@ -2163,7 +2207,7 @@ static enum attended_transfer_state consulting_exit(struct attended_transfer_pro
* a sound to the transferer to indicate the transferee is gone.
*/
bridge_basic_change_personality(props->target_bridge, BRIDGE_BASIC_PERSONALITY_NORMAL, NULL);
- play_sound(props->transferer, props->failsound);
+ play_failsound(props->transferer);
ast_bridge_merge_inhibit(props->target_bridge, -1);
/* These next two lines are here to ensure that our reference to the target bridge
* is cleaned up properly and that the target bridge is not destroyed when the
@@ -2180,7 +2224,7 @@ static enum attended_transfer_state consulting_exit(struct attended_transfer_pro
case STIMULUS_TRANSFER_TARGET_HANGUP:
return TRANSFER_REBRIDGE;
case STIMULUS_DTMF_ATXFER_ABORT:
- play_sound(props->transferer, props->failsound);
+ play_failsound(props->transferer);
return TRANSFER_REBRIDGE;
case STIMULUS_DTMF_ATXFER_THREEWAY:
bridge_unhold(props->transferee_bridge);
@@ -2212,7 +2256,7 @@ static enum attended_transfer_state double_checking_exit(struct attended_transfe
{
switch (stimulus) {
case STIMULUS_TRANSFEREE_HANGUP:
- play_sound(props->transferer, props->failsound);
+ play_failsound(props->transferer);
publish_transfer_fail(props);
return TRANSFER_FAIL;
case STIMULUS_TRANSFERER_HANGUP:
@@ -2222,7 +2266,7 @@ static enum attended_transfer_state double_checking_exit(struct attended_transfe
return TRANSFER_COMPLETE;
case STIMULUS_TRANSFER_TARGET_HANGUP:
case STIMULUS_DTMF_ATXFER_ABORT:
- play_sound(props->transferer, props->failsound);
+ play_failsound(props->transferer);
return TRANSFER_RESUME;
case STIMULUS_DTMF_ATXFER_THREEWAY:
bridge_unhold(props->target_bridge);
@@ -3298,7 +3342,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
props->transfer_target = dial_transfer(bridge_channel->chan, destination);
if (!props->transfer_target) {
ast_log(LOG_ERROR, "Unable to request outbound channel for attended transfer target.\n");
- ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE);
+ stream_failsound(props->transferer);
ast_bridge_channel_write_unhold(bridge_channel);
attended_transfer_properties_shutdown(props);
return 0;
@@ -3309,7 +3353,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
props->target_bridge = ast_bridge_basic_new();
if (!props->target_bridge) {
ast_log(LOG_ERROR, "Unable to create bridge for attended transfer target.\n");
- ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE);
+ stream_failsound(props->transferer);
ast_bridge_channel_write_unhold(bridge_channel);
ast_hangup(props->transfer_target);
props->transfer_target = NULL;
@@ -3320,7 +3364,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
if (attach_framehook(props, props->transfer_target)) {
ast_log(LOG_ERROR, "Unable to attach framehook to transfer target.\n");
- ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE);
+ stream_failsound(props->transferer);
ast_bridge_channel_write_unhold(bridge_channel);
ast_hangup(props->transfer_target);
props->transfer_target = NULL;
@@ -3335,7 +3379,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
if (ast_call(props->transfer_target, destination, 0)) {
ast_log(LOG_ERROR, "Unable to place outbound call to transfer target.\n");
- ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE);
+ stream_failsound(props->transferer);
ast_bridge_channel_write_unhold(bridge_channel);
ast_hangup(props->transfer_target);
props->transfer_target = NULL;
@@ -3351,7 +3395,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
if (ast_bridge_impart(props->target_bridge, props->transfer_target, NULL, NULL,
AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
ast_log(LOG_ERROR, "Unable to place transfer target into bridge.\n");
- ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE);
+ stream_failsound(props->transferer);
ast_bridge_channel_write_unhold(bridge_channel);
ast_hangup(props->transfer_target);
props->transfer_target = NULL;
@@ -3361,7 +3405,7 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
if (ast_pthread_create_detached(&thread, NULL, attended_transfer_monitor_thread, props)) {
ast_log(LOG_ERROR, "Unable to create monitoring thread for attended transfer.\n");
- ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE);
+ stream_failsound(props->transferer);
ast_bridge_channel_write_unhold(bridge_channel);
attended_transfer_properties_shutdown(props);
return 0;
diff --git a/main/features_config.c b/main/features_config.c
index 9fed53b32..9126a86c7 100644
--- a/main/features_config.c
+++ b/main/features_config.c
@@ -1158,6 +1158,21 @@ struct ast_features_xfer_config *ast_get_chan_features_xfer_config(struct ast_ch
return cfg->global->xfer;
}
+char *ast_get_chan_features_xferfailsound(struct ast_channel *chan)
+{
+ char *res;
+ struct ast_features_xfer_config *cfg = ast_get_chan_features_xfer_config(chan);
+
+ if (!cfg) {
+ return NULL;
+ }
+
+ res = ast_strdup(cfg->xferfailsound);
+ ao2_ref(cfg, -1);
+
+ return res;
+}
+
struct ast_features_pickup_config *ast_get_chan_features_pickup_config(struct ast_channel *chan)
{
RAII_VAR(struct features_config *, cfg, NULL, ao2_cleanup);
diff --git a/main/taskprocessor.c b/main/taskprocessor.c
index 59e4a2fa1..05d646128 100644
--- a/main/taskprocessor.c
+++ b/main/taskprocessor.c
@@ -713,12 +713,7 @@ struct ast_taskprocessor *ast_taskprocessor_get(const char *name, enum ast_tps_o
}
p = __allocate_taskprocessor(name, listener);
- if (!p) {
- ao2_ref(listener, -1);
- return NULL;
- }
- /* Unref listener here since the taskprocessor has gained a reference to the listener */
ao2_ref(listener, -1);
return p;
}