summaryrefslogtreecommitdiff
path: root/channels/sig_analog.c
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2013-06-07 01:06:49 +0000
committerRichard Mudgett <rmudgett@digium.com>2013-06-07 01:06:49 +0000
commit611416623748504be81c58b455205a4bc7fff414 (patch)
tree03695f0b52686c022a797f7a3beb667c8119350e /channels/sig_analog.c
parentb8b7e8ab45c9786788c3a7121edc2a1413815590 (diff)
Refactor chan_dahdi/sig_analog/sig_pri and chan_misdn to use the common transfer functions.
(closes issue ASTERISK-21523) Reported by: Matt Jordan (closes issue ASTERISK-21524) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2600/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@390804 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels/sig_analog.c')
-rw-r--r--channels/sig_analog.c119
1 files changed, 35 insertions, 84 deletions
diff --git a/channels/sig_analog.c b/channels/sig_analog.c
index 956c4a654..9660d3fe6 100644
--- a/channels/sig_analog.c
+++ b/channels/sig_analog.c
@@ -44,6 +44,7 @@
#include "asterisk/cel.h"
#include "asterisk/causes.h"
#include "asterisk/features_config.h"
+#include "asterisk/bridging.h"
#include "sig_analog.h"
@@ -688,87 +689,44 @@ static int analog_is_dialing(struct analog_pvt *p, enum analog_sub index)
* \brief Attempt to transfer 3-way call.
*
* \param p Analog private structure.
- * \param inthreeway TRUE if the 3-way call is conferenced.
*
- * \note
- * On entry these locks are held: real-call, private, 3-way call.
+ * \note On entry these locks are held: real-call, private, 3-way call.
+ * \note On exit these locks are held: real-call, private.
*
- * \retval 1 Transfer successful. 3-way call is unlocked and subchannel is unalloced.
- * Swapped real and 3-way subchannel.
- * \retval 0 Transfer successful. 3-way call is unlocked and subchannel is unalloced.
- * \retval -1 on error. Caller must unlock 3-way call.
+ * \retval 0 on success.
+ * \retval -1 on error.
*/
-static int analog_attempt_transfer(struct analog_pvt *p, int inthreeway)
+static int analog_attempt_transfer(struct analog_pvt *p)
{
struct ast_channel *owner_real;
struct ast_channel *owner_3way;
- struct ast_channel *bridge_real;
- struct ast_channel *bridge_3way;
-
- owner_real = p->subs[ANALOG_SUB_REAL].owner;
- owner_3way = p->subs[ANALOG_SUB_THREEWAY].owner;
- bridge_real = ast_bridged_channel(owner_real);
- bridge_3way = ast_bridged_channel(owner_3way);
-
- /*
- * In order to transfer, we need at least one of the channels to
- * actually be in a call bridge. We can't conference two
- * applications together. Why would we want to?
- */
- if (bridge_3way) {
- ast_verb(3, "TRANSFERRING %s to %s\n", ast_channel_name(owner_3way), ast_channel_name(owner_real));
- ast_cel_report_event(owner_3way,
- (ast_channel_state(owner_real) == AST_STATE_RINGING
- || ast_channel_state(owner_3way) == AST_STATE_RINGING)
- ? AST_CEL_BLINDTRANSFER : AST_CEL_ATTENDEDTRANSFER,
- NULL, ast_channel_linkedid(owner_3way), NULL);
+ enum ast_transfer_result xfer_res;
+ int res = 0;
- /*
- * The three-way party we're about to transfer is on hold if he
- * is not in a three way conference.
- */
- if (ast_channel_transfer_masquerade(owner_real, ast_channel_connected(owner_real), 0,
- bridge_3way, ast_channel_connected(owner_3way), !inthreeway)) {
- ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
- ast_channel_name(bridge_3way), ast_channel_name(owner_real));
- return -1;
- }
+ owner_real = ast_channel_ref(p->subs[ANALOG_SUB_REAL].owner);
+ owner_3way = ast_channel_ref(p->subs[ANALOG_SUB_THREEWAY].owner);
- /* Three-way is now the REAL */
- analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
- ast_channel_unlock(owner_3way);
- analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
- /* Tell the caller not to hangup */
- return 1;
- } else if (bridge_real) {
- /* Try transferring the other way. */
- ast_verb(3, "TRANSFERRING %s to %s\n", ast_channel_name(owner_real), ast_channel_name(owner_3way));
- ast_cel_report_event(owner_3way,
- (ast_channel_state(owner_real) == AST_STATE_RINGING
- || ast_channel_state(owner_3way) == AST_STATE_RINGING)
- ? AST_CEL_BLINDTRANSFER : AST_CEL_ATTENDEDTRANSFER,
- NULL, ast_channel_linkedid(owner_3way), NULL);
+ ast_verb(3, "TRANSFERRING %s to %s\n",
+ ast_channel_name(owner_3way), ast_channel_name(owner_real));
- /*
- * The three-way party we're about to transfer is on hold if he
- * is not in a three way conference.
- */
- if (ast_channel_transfer_masquerade(owner_3way, ast_channel_connected(owner_3way),
- !inthreeway, bridge_real, ast_channel_connected(owner_real), 0)) {
- ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
- ast_channel_name(bridge_real), ast_channel_name(owner_3way));
- return -1;
- }
+ ast_channel_unlock(owner_real);
+ ast_channel_unlock(owner_3way);
+ analog_unlock_private(p);
- /* Orphan the channel after releasing the lock */
- ast_channel_unlock(owner_3way);
- analog_unalloc_sub(p, ANALOG_SUB_THREEWAY);
- return 0;
- } else {
- ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
- ast_channel_name(owner_real), ast_channel_name(owner_3way));
- return -1;
+ xfer_res = ast_bridge_transfer_attended(owner_3way, owner_real);
+ if (xfer_res != AST_BRIDGE_TRANSFER_SUCCESS) {
+ ast_softhangup(owner_3way, AST_SOFTHANGUP_DEV);
+ res = -1;
}
+
+ /* Must leave with these locked. */
+ ast_channel_lock(owner_real);
+ analog_lock_private(p);
+
+ ast_channel_unref(owner_real);
+ ast_channel_unref(owner_3way);
+
+ return res;
}
static int analog_update_conf(struct analog_pvt *p)
@@ -2892,10 +2850,6 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
} else if ((ast_channel_pbx(ast)) || (ast_channel_state(ast) == AST_STATE_UP)) {
if (p->transfer) {
- int inthreeway;
-
- inthreeway = p->subs[ANALOG_SUB_THREEWAY].inthreeway;
-
/* In any case this isn't a threeway call anymore */
analog_set_inthreeway(p, ANALOG_SUB_REAL, 0);
analog_set_inthreeway(p, ANALOG_SUB_THREEWAY, 0);
@@ -2909,16 +2863,13 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
analog_set_new_owner(p, NULL);
/* Ring the phone */
analog_ring(p);
- } else {
- res = analog_attempt_transfer(p, inthreeway);
- if (res < 0) {
- /* Transfer attempt failed. */
- ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
- ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
- } else if (res) {
- /* Don't actually hang up at this point */
- break;
- }
+ } else if (!analog_attempt_transfer(p)) {
+ /*
+ * Transfer successful. Don't actually hang up at this point.
+ * Let our channel legs of the calls die off as the transfer
+ * percolates through the core.
+ */
+ break;
}
} else {
ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);