aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2010-11-24 16:48:39 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2010-11-24 16:48:39 +0000
commitba7980f1afa6aebb50c1cb2f1a17175514f53ea7 (patch)
tree2b9a2275020814a603f7a3cebdeceab5d905b456
parent66e16582fdaafd43aea99c45e27ab7a9c0ce7887 (diff)
Handle failures building translation paths more effectively.
The problem scenario occurred on a heavily loaded system that was using the codec_dahdi module and exceeded the hardware transcoding capacity. The failure mode at that point was not good. The report came in to us as an Asterisk lock-up. The "core show locks" shows a ton of threads locked up (but no obvious deadlock). Upon deeper investigation, when the system is in this state, the CPU was maxed out. The CPU was being consumed by the Asterisk logger spewing messages on every audio frame for calls set up after transcoder capacity was reached. The purpose of this patch is to make Asterisk handle failures to create a translation path in a more graceful manner. If we can't translate, then the call just needs to be dropped, as it's not going to work. These are the changes: 1) In set_format() of channel.c (which is called by set_read_format() and set_write_format()), it was ignoring if ast_translator_build_path() failed and returned NULL. It now pays attention to that case and returns a result reflecting failure. With this change in place, the bridging code will immediately detect a failure and end the bridge instead of proceeding to try to bridge frames that can't be translated and making channel drivers freak out by sending them frames in a format they weren't expecting. 2) In ast_indicate_data() of channel.c, failure of ast_playtones_start() was ignored. It is now reflected in the return value of the function. This didn't turn out to have any affect on the bug, but seemed like a good change to leave in. 3) In app_dial(), when only sending a call to a single endpoint, it will attempt to do some bridging of its own of early audio. It uses make_compatible() when it's going to do this. However, it ignored failure from make compatible. So, even with the fix from #1, if there was early audio going through app_dial, there would still be a period of invalid frames passing through. After detecting failure here, Dial() exits. ABE-2658 git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@296000 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--apps/app_dial.c11
-rw-r--r--main/channel.c6
2 files changed, 13 insertions, 4 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c
index a6e0f3d79..a3a32999a 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -436,7 +436,16 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l
/* Turn off hold music, etc */
ast_deactivate_generator(in);
/* If we are calling a single channel, make them compatible for in-band tone purpose */
- ast_channel_make_compatible(outgoing->chan, in);
+ if (ast_channel_make_compatible(outgoing->chan, in) < 0) {
+ /* If these channels can not be made compatible,
+ * there is no point in continuing. The bridge
+ * will just fail if it gets that far.
+ */
+ *to = -1;
+ strcpy(status, "CONGESTION");
+ ast_cdr_failed(in->cdr);
+ return NULL;
+ }
}
diff --git a/main/channel.c b/main/channel.c
index 43443287a..8630ded01 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -2827,8 +2827,7 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
if (option_debug) {
ast_log(LOG_DEBUG, "Driver for channel '%s' does not support indication %d, emulating it\n", chan->name, condition);
}
- ast_playtones_start(chan, 0, ts->data, 1);
- res = 0;
+ res = ast_playtones_start(chan, 0, ts->data, 1);
chan->visible_indication = condition;
}
@@ -3410,11 +3409,12 @@ static int set_format(struct ast_channel *chan, int fmt, int *rawformat, int *fo
else
/* writing */
*trans = ast_translator_build_path(*rawformat, *format);
+ res = *trans ? 0 : -1;
ast_channel_unlock(chan);
if (option_debug)
ast_log(LOG_DEBUG, "Set channel %s to %s format %s\n", chan->name,
direction ? "write" : "read", ast_getformatname(fmt));
- return 0;
+ return res;
}
int ast_set_read_format(struct ast_channel *chan, int fmt)