[asterisk-commits] jrose: trunk r405910 - in /trunk: ./ channels/chan_pjsip.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Jan 20 12:18:27 CST 2014


Author: jrose
Date: Mon Jan 20 12:18:25 2014
New Revision: 405910

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=405910
Log:
chan_pjsip: Provide a means for tracking device state when holding/unholding

Previously PJSIP did not track hold/unhold and it would always simply be
'inuse'. This patch fixes that.

review: https://reviewboard.asterisk.org/r/3129/
........

Merged revisions 405908 from http://svn.asterisk.org/svn/asterisk/branches/12

Modified:
    trunk/   (props changed)
    trunk/channels/chan_pjsip.c

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-12-merged' - no diff available.

Modified: trunk/channels/chan_pjsip.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_pjsip.c?view=diff&rev=405910&r1=405909&r2=405910
==============================================================================
--- trunk/channels/chan_pjsip.c (original)
+++ trunk/channels/chan_pjsip.c Mon Jan 20 12:18:25 2014
@@ -677,6 +677,114 @@
 	return 0;
 }
 
+/*! AO2 hash function for on hold UIDs */
+static int uid_hold_hash_fn(const void *obj, const int flags)
+{
+	const char *key = obj;
+
+	switch (flags & OBJ_SEARCH_MASK) {
+	case OBJ_SEARCH_KEY:
+		break;
+	case OBJ_SEARCH_OBJECT:
+		break;
+	default:
+		/* Hash can only work on something with a full key. */
+		ast_assert(0);
+		return 0;
+	}
+	return ast_str_hash(key);
+}
+
+/*! AO2 sort function for on hold UIDs */
+static int uid_hold_sort_fn(const void *obj_left, const void *obj_right, const int flags)
+{
+	const char *left = obj_left;
+	const char *right = obj_right;
+	int cmp;
+
+	switch (flags & OBJ_SEARCH_MASK) {
+	case OBJ_SEARCH_OBJECT:
+	case OBJ_SEARCH_KEY:
+		cmp = strcmp(left, right);
+		break;
+	case OBJ_SEARCH_PARTIAL_KEY:
+		cmp = strncmp(left, right, strlen(right));
+		break;
+	default:
+		/* Sort can only work on something with a full or partial key. */
+		ast_assert(0);
+		cmp = 0;
+		break;
+	}
+	return cmp;
+}
+
+static struct ao2_container *pjsip_uids_onhold;
+
+/*!
+ * \brief Add a channel ID to the list of PJSIP channels on hold
+ *
+ * \param chan_uid - Unique ID of the channel being put into the hold list
+ *
+ * \retval 0 Channel has been added to or was already in the hold list
+ * \retval -1 Failed to add channel to the hold list
+ */
+static int chan_pjsip_add_hold(const char *chan_uid)
+{
+	RAII_VAR(char *, hold_uid, NULL, ao2_cleanup);
+
+	hold_uid = ao2_find(pjsip_uids_onhold, chan_uid, OBJ_SEARCH_KEY);
+	if (hold_uid) {
+		/* Device is already on hold. Nothing to do. */
+		return 0;
+	}
+
+	/* Device wasn't in hold list already. Create a new one. */
+	hold_uid = ao2_alloc_options(strlen(chan_uid) + 1, NULL,
+		AO2_ALLOC_OPT_LOCK_NOLOCK);
+	if (!hold_uid) {
+		return -1;
+	}
+
+	ast_copy_string(hold_uid, chan_uid, strlen(chan_uid) + 1);
+
+	if (ao2_link(pjsip_uids_onhold, hold_uid) == 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+/*!
+ * \brief Remove a channel ID from the list of PJSIP channels on hold
+ *
+ * \param chan_uid - Unique ID of the channel being taken out of the hold list
+ */
+static void chan_pjsip_remove_hold(const char *chan_uid)
+{
+	ao2_find(pjsip_uids_onhold, chan_uid, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
+}
+
+/*!
+ * \brief Determine whether a channel ID is in the list of PJSIP channels on hold
+ *
+ * \param chan_uid - Channel being checked
+ *
+ * \retval 0 The channel is not in the hold list
+ * \retval 1 The channel is in the hold list
+ */
+static int chan_pjsip_get_hold(const char *chan_uid)
+{
+	RAII_VAR(char *, hold_uid, NULL, ao2_cleanup);
+
+	hold_uid = ao2_find(pjsip_uids_onhold, chan_uid, OBJ_SEARCH_KEY);
+	if (!hold_uid) {
+		return 0;
+	}
+
+	return 1;
+}
+
 /*! \brief Function called to get the device state of an endpoint */
 static int chan_pjsip_devicestate(const char *data)
 {
@@ -731,7 +839,11 @@
 			ast_devstate_aggregate_add(&aggregate, AST_DEVICE_RINGING);
 		} else if ((snapshot->state == AST_STATE_UP) || (snapshot->state == AST_STATE_RING) ||
 			(snapshot->state == AST_STATE_BUSY)) {
-			ast_devstate_aggregate_add(&aggregate, AST_DEVICE_INUSE);
+			if (chan_pjsip_get_hold(snapshot->uniqueid)) {
+				ast_devstate_aggregate_add(&aggregate, AST_DEVICE_ONHOLD);
+			} else {
+				ast_devstate_aggregate_add(&aggregate, AST_DEVICE_INUSE);
+			}
 			inuse++;
 		}
 	}
@@ -925,6 +1037,8 @@
 	struct ast_sip_session_media *media;
 	int response_code = 0;
 	int res = 0;
+	char *device_buf;
+	size_t device_buf_size;
 
 	switch (condition) {
 	case AST_CONTROL_RINGING:
@@ -1014,9 +1128,19 @@
 		res = -1;
 		break;
 	case AST_CONTROL_HOLD:
+		chan_pjsip_add_hold(ast_channel_uniqueid(ast));
+		device_buf_size = strlen(ast_channel_name(ast)) + 1;
+		device_buf = alloca(device_buf_size);
+		ast_channel_get_device_name(ast, device_buf, device_buf_size);
+		ast_devstate_changed_literal(AST_DEVICE_ONHOLD, 1, device_buf);
 		ast_moh_start(ast, data, NULL);
 		break;
 	case AST_CONTROL_UNHOLD:
+		chan_pjsip_remove_hold(ast_channel_uniqueid(ast));
+		device_buf_size = strlen(ast_channel_name(ast)) + 1;
+		device_buf = alloca(device_buf_size);
+		ast_channel_get_device_name(ast, device_buf, device_buf_size);
+		ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, 1, device_buf);
 		ast_moh_stop(ast);
 		break;
 	case AST_CONTROL_SRCUPDATE:
@@ -1755,6 +1879,8 @@
 		return;
 	}
 
+	chan_pjsip_remove_hold(ast_channel_uniqueid(session->channel));
+
 	if (!ast_channel_hangupcause(session->channel) && session->inv_session) {
 		int cause = hangup_sip2cause(session->inv_session->cause);
 
@@ -1934,6 +2060,13 @@
 		goto end;
 	}
 
+	if (!(pjsip_uids_onhold = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK,
+			AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, 37, uid_hold_hash_fn,
+			uid_hold_sort_fn, NULL))) {
+		ast_log(LOG_ERROR, "Unable to create held channels container\n");
+		goto end;
+	}
+
 	if (ast_sip_session_register_supplement(&pbx_start_supplement)) {
 		ast_log(LOG_ERROR, "Unable to register PJSIP pbx start supplement\n");
 		ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
@@ -1957,6 +2090,8 @@
 	return 0;
 
 end:
+	ao2_cleanup(pjsip_uids_onhold);
+	pjsip_uids_onhold = NULL;
 	ast_custom_function_unregister(&media_offer_function);
 	ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
 	ast_channel_unregister(&chan_pjsip_tech);
@@ -1974,6 +2109,9 @@
 /*! \brief Unload the PJSIP channel from Asterisk */
 static int unload_module(void)
 {
+	ao2_cleanup(pjsip_uids_onhold);
+	pjsip_uids_onhold = NULL;
+
 	ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
 	ast_sip_session_unregister_supplement(&pbx_start_supplement);
 	ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);




More information about the asterisk-commits mailing list