summaryrefslogtreecommitdiff
path: root/channels/chan_dahdi.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/chan_dahdi.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/chan_dahdi.c')
-rw-r--r--channels/chan_dahdi.c105
1 files changed, 48 insertions, 57 deletions
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 92de02391..109fac06d 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -131,6 +131,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/ccss.h"
#include "asterisk/data.h"
#include "asterisk/features_config.h"
+#include "asterisk/bridging.h"
/*** DOCUMENTATION
<application name="DAHDISendKeypadFacility" language="en_US">
@@ -7841,55 +7842,49 @@ static int dahdi_ring_phone(struct dahdi_pvt *p)
static void *analog_ss_thread(void *data);
+/*!
+ * \internal
+ * \brief Attempt to transfer 3-way call.
+ *
+ * \param p DAHDI private structure.
+ *
+ * \note On entry these locks are held: real-call, private, 3-way call.
+ * \note On exit these locks are held: real-call, private.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
static int attempt_transfer(struct dahdi_pvt *p)
{
- /* 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 (but then, why would we want to?) */
- if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
- /* The three-way person we're about to transfer to could still be in MOH, so
- stop it now */
- ast_queue_unhold(p->subs[SUB_THREEWAY].owner);
- if (ast_channel_state(p->subs[SUB_REAL].owner) == AST_STATE_RINGING) {
- ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_RINGING);
- }
- if (ast_channel_state(p->subs[SUB_THREEWAY].owner) == AST_STATE_RING) {
- tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
- }
- if (ast_channel_masquerade(p->subs[SUB_THREEWAY].owner, ast_bridged_channel(p->subs[SUB_REAL].owner))) {
- ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
- ast_channel_name(ast_bridged_channel(p->subs[SUB_REAL].owner)), ast_channel_name(p->subs[SUB_THREEWAY].owner));
- return -1;
- }
- /* Orphan the channel after releasing the lock */
- ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
- unalloc_sub(p, SUB_THREEWAY);
- } else if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
- ast_queue_unhold(p->subs[SUB_REAL].owner);
- if (ast_channel_state(p->subs[SUB_THREEWAY].owner) == AST_STATE_RINGING) {
- ast_queue_control(p->subs[SUB_THREEWAY].owner, AST_CONTROL_RINGING);
- }
- if (ast_channel_state(p->subs[SUB_REAL].owner) == AST_STATE_RING) {
- tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
- }
- if (ast_channel_masquerade(p->subs[SUB_REAL].owner, ast_bridged_channel(p->subs[SUB_THREEWAY].owner))) {
- ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
- ast_channel_name(ast_bridged_channel(p->subs[SUB_THREEWAY].owner)), ast_channel_name(p->subs[SUB_REAL].owner));
- return -1;
- }
- /* Three-way is now the REAL */
- swap_subs(p, SUB_THREEWAY, SUB_REAL);
- ast_channel_unlock(p->subs[SUB_REAL].owner);
- unalloc_sub(p, SUB_THREEWAY);
- /* Tell the caller not to hangup */
- return 1;
- } else {
- ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
- ast_channel_name(p->subs[SUB_REAL].owner), ast_channel_name(p->subs[SUB_THREEWAY].owner));
- ast_channel_softhangup_internal_flag_add(p->subs[SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
- return -1;
+ struct ast_channel *owner_real;
+ struct ast_channel *owner_3way;
+ enum ast_transfer_result xfer_res;
+ int res = 0;
+
+ owner_real = ast_channel_ref(p->subs[SUB_REAL].owner);
+ owner_3way = ast_channel_ref(p->subs[SUB_THREEWAY].owner);
+
+ ast_verb(3, "TRANSFERRING %s to %s\n",
+ ast_channel_name(owner_3way), ast_channel_name(owner_real));
+
+ ast_channel_unlock(owner_real);
+ ast_channel_unlock(owner_3way);
+ ast_mutex_unlock(&p->lock);
+
+ 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;
}
- return 0;
+
+ /* Must leave with these locked. */
+ ast_channel_lock(owner_real);
+ ast_mutex_lock(&p->lock);
+
+ ast_channel_unref(owner_real);
+ ast_channel_unref(owner_3way);
+
+ return res;
}
static int check_for_conference(struct dahdi_pvt *p)
@@ -8399,17 +8394,13 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
p->owner = NULL;
/* Ring the phone */
dahdi_ring_phone(p);
- } else {
- if ((res = attempt_transfer(p)) < 0) {
- ast_channel_softhangup_internal_flag_add(p->subs[SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
- if (p->subs[SUB_THREEWAY].owner)
- ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
- } else if (res) {
- /* Don't actually hang up at this point */
- if (p->subs[SUB_THREEWAY].owner)
- ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
- break;
- }
+ } else if (!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_channel_softhangup_internal_flag_add(p->subs[SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);