[asterisk-commits] mmichelson: trunk r397877 - in /trunk: ./ res/res_pjsip_refer.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Aug 28 16:09:44 CDT 2013
Author: mmichelson
Date: Wed Aug 28 16:09:43 2013
New Revision: 397877
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=397877
Log:
Improve detection of answer on SIP blind transfer.
A problem encountered during testing was that res_pjsip_refer would
not ever send a NOTIFY with a 200 OK sipfrag. This is because the framehook
that was supposed to send the NOTIFY would never be told that an answer
had occurred. This happened for two reasons:
1) The transferee channel on which the framehook was on was already up.
2) Answers are rarely if ever written to channels. Rather, the ast_answer()
or ast_raw_answer() function is used to answer channels.
Thanks to a suggestion by Matt Jordan, the best way to detect that the call
had been answered was to find out when the transferee channel joined a bridge.
With stasis this is an easy task. So now, in addition to the framehook logic,
there is a stasis subscription used to determine when the transferee has entered
a bridge. Once it has entered, an appropriate NOTIFY is sent.
........
Merged revisions 397876 from http://svn.asterisk.org/svn/asterisk/branches/12
Modified:
trunk/ (props changed)
trunk/res/res_pjsip_refer.c
Propchange: trunk/
------------------------------------------------------------------------------
--- branch-12-merged (original)
+++ branch-12-merged Wed Aug 28 16:09:43 2013
@@ -1,1 +1,1 @@
-/branches/12:1-397816,397854,397856,397859,397870,397874
+/branches/12:1-397816,397854,397856,397859,397870,397874,397876
Modified: trunk/res/res_pjsip_refer.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_pjsip_refer.c?view=diff&rev=397877&r1=397876&r2=397877
==============================================================================
--- trunk/res/res_pjsip_refer.c (original)
+++ trunk/res/res_pjsip_refer.c Wed Aug 28 16:09:43 2013
@@ -36,6 +36,8 @@
#include "asterisk/taskprocessor.h"
#include "asterisk/bridge.h"
#include "asterisk/framehook.h"
+#include "asterisk/stasis_bridges.h"
+#include "asterisk/stasis_channels.h"
/*! \brief REFER Progress structure */
struct refer_progress {
@@ -51,6 +53,10 @@
int subclass;
/*! \brief Serializer for notifications */
struct ast_taskprocessor *serializer;
+ /*! \brief Stasis subscription for bridge events */
+ struct stasis_subscription *bridge_sub;
+ /*! \brief Uniqueid of transferee channel */
+ char *transferee;
};
/*! \brief REFER Progress notification structure */
@@ -134,6 +140,39 @@
}
return 0;
+}
+
+static void refer_progress_bridge(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic, struct stasis_message *message)
+{
+ struct refer_progress *progress = data;
+ struct ast_bridge_blob *enter_blob;
+ struct refer_progress_notification *notification;
+
+ if (stasis_subscription_final_message(sub, message)) {
+ ao2_ref(progress, -1);
+ return;
+ }
+
+ if (ast_channel_entered_bridge_type() != stasis_message_type(message)) {
+ /* Don't care */
+ return;
+ }
+
+ enter_blob = stasis_message_data(message);
+ if (strcmp(enter_blob->channel->uniqueid, progress->transferee)) {
+ /* Don't care */
+ return;
+ }
+
+ /* OMG the transferee is joining a bridge. His call got answered! */
+ notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
+ if (notification) {
+ if (ast_sip_push_task(progress->serializer, refer_progress_notify, notification)) {
+ ao2_cleanup(notification);
+ }
+ progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
+ }
}
/*! \brief Progress monitoring frame hook - examines frames to determine state of transfer */
@@ -182,7 +221,6 @@
ast_channel_name(chan));
ast_framehook_detach(chan, progress->framehook);
}
-
}
return f;
@@ -250,6 +288,11 @@
{
struct refer_progress *progress = obj;
+ if (progress->bridge_sub) {
+ progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
+ }
+
+ ast_free(progress->transferee);
ast_taskprocessor_unreference(progress->serializer);
}
@@ -438,6 +481,19 @@
.data = refer->progress,
};
+ refer->progress->transferee = ast_strdup(ast_channel_uniqueid(chan));
+ if (!refer->progress->transferee) {
+ struct refer_progress_notification *notification = refer_progress_notification_alloc(refer->progress, 200,
+ PJSIP_EVSUB_STATE_TERMINATED);
+
+ ast_log(LOG_WARNING, "Could not copy channel name '%s' during transfer - assuming success\n",
+ ast_channel_name(chan));
+
+ if (notification) {
+ refer_progress_notify(notification);
+ }
+ }
+
/* We need to bump the reference count up on the progress structure since it is in the frame hook now */
ao2_ref(refer->progress, +1);
@@ -452,6 +508,28 @@
if (notification) {
refer_progress_notify(notification);
}
+
+ ao2_cleanup(refer->progress);
+ }
+
+ /* We need to bump the reference count for the stasis subscription */
+ ao2_ref(refer->progress, +1);
+ /* We also will need to detect if the transferee enters a bridge. This is currently the only reliable way to
+ * detect if the transfer target has answered the call
+ */
+ refer->progress->bridge_sub = stasis_subscribe(ast_bridge_topic_all(), refer_progress_bridge, refer->progress);
+ if (!refer->progress->bridge_sub) {
+ struct refer_progress_notification *notification = refer_progress_notification_alloc(refer->progress, 200,
+ PJSIP_EVSUB_STATE_TERMINATED);
+
+ ast_log(LOG_WARNING, "Could not create bridge stasis subscription for monitoring progress on transfer of channel '%s' - assuming success\n",
+ ast_channel_name(chan));
+
+ if (notification) {
+ refer_progress_notify(notification);
+ }
+
+ ast_framehook_detach(chan, refer->progress->framehook);
ao2_cleanup(refer->progress);
}
More information about the asterisk-commits
mailing list