[asterisk-commits] mjordan: trunk r434217 - in /trunk: ./ main/ res/ari/ rest-api/api-docs/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Apr 7 10:22:45 CDT 2015


Author: mjordan
Date: Tue Apr  7 10:22:42 2015
New Revision: 434217

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=434217
Log:
ARI: Add the ability to intercept hold and raise an event

For some applications - such as SLA - a phone pressing hold should not behave
in the fashion that the Asterisk core would like it to. Instead, the hold
action has some application specific behaviour associated with it - such as
disconnecting the channel that initiated the hold; only playing MoH to channels
in the bridge if the channels are of a particular type, etc.

One way of accomplishing this is to use a framehook to intercept the
hold/unhold frames, raise an event, and eat the frame. Tasty. This patch
accomplishes that using a new dialplan function, HOLD_INTERCEPT.

In addition, some general cleanup of raising hold/unhold Stasis messages was
done, including removing some RAII_VAR usage.

Review: https://reviewboard.asterisk.org/r/4549/

ASTERISK-24922 #close
........

Merged revisions 434216 from http://svn.asterisk.org/svn/asterisk/branches/13

Modified:
    trunk/   (props changed)
    trunk/CHANGES
    trunk/main/bridge_channel.c
    trunk/main/channel.c
    trunk/main/manager_channels.c
    trunk/main/stasis_channels.c
    trunk/res/ari/ari_model_validators.c
    trunk/res/ari/ari_model_validators.h
    trunk/rest-api/api-docs/events.json

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

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=434217&r1=434216&r2=434217
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Tue Apr  7 10:22:42 2015
@@ -117,6 +117,22 @@
    connected line information update.  See the online option documentation for
    more information.  Defaults to 'no' as setting it to 'yes' can result in
    many unnecessary messages being sent to the caller.
+
+res_ari_channels
+------------------
+ * Two new events, 'ChannelHold' and 'ChannelUnhold', have been added to the
+   events data model. These events are raised when a channel indicates a hold
+   or unhold, respectively.
+
+func_holdintercept
+------------------
+ * A new dialplan function, HOLD_INTERCEPT, has been added. This function, when
+   placed on a channel, intercepts hold/unhold indications signalled by the
+   channel and prevents them from moving on to other channels in a bridge with
+   the hold initiator. Instead, AMI or ARI events are raised indicating that
+   the channel wanted to place someone on hold. This allows external
+   applications to implement their own custom hold/unhold logic.
+
 
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 13.2.0 to Asterisk 13.3.0 ------------

Modified: trunk/main/bridge_channel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/bridge_channel.c?view=diff&rev=434217&r1=434216&r2=434217
==============================================================================
--- trunk/main/bridge_channel.c (original)
+++ trunk/main/bridge_channel.c Tue Apr  7 10:22:42 2015
@@ -979,7 +979,8 @@
 
 int ast_bridge_channel_write_hold(struct ast_bridge_channel *bridge_channel, const char *moh_class)
 {
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+	struct ast_json *blob;
+	int res;
 	size_t datalen;
 
 	if (!ast_strlen_zero(moh_class)) {
@@ -990,12 +991,16 @@
 	} else {
 		moh_class = NULL;
 		datalen = 0;
+		blob = NULL;
 	}
 
 	ast_channel_publish_cached_blob(bridge_channel->chan, ast_channel_hold_type(), blob);
 
-	return ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_HOLD,
+	res = ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_HOLD,
 		moh_class, datalen);
+
+	ast_json_unref(blob);
+	return res;
 }
 
 int ast_bridge_channel_write_unhold(struct ast_bridge_channel *bridge_channel)

Modified: trunk/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/channel.c?view=diff&rev=434217&r1=434216&r2=434217
==============================================================================
--- trunk/main/channel.c (original)
+++ trunk/main/channel.c Tue Apr  7 10:22:42 2015
@@ -1196,8 +1196,8 @@
 
 int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
 {
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HOLD };
+	struct ast_json *blob = NULL;
 	int res;
 
 	if (!ast_strlen_zero(musicclass)) {
@@ -1211,6 +1211,8 @@
 	ast_channel_publish_cached_blob(chan, ast_channel_hold_type(), blob);
 
 	res = ast_queue_frame(chan, &f);
+
+	ast_json_unref(blob);
 
 	return res;
 }

Modified: trunk/main/manager_channels.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/manager_channels.c?view=diff&rev=434217&r1=434216&r2=434217
==============================================================================
--- trunk/main/manager_channels.c (original)
+++ trunk/main/manager_channels.c Tue Apr  7 10:22:42 2015
@@ -1061,20 +1061,22 @@
 	struct stasis_message *message)
 {
 	struct ast_channel_blob *obj = stasis_message_data(message);
-	const char *musicclass;
-	RAII_VAR(struct ast_str *, musicclass_string, NULL, ast_free);
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-
-	if (!(musicclass_string = ast_str_create(32))) {
+	struct ast_str *musicclass_string = ast_str_create(32);
+	struct ast_str *channel_event_string;
+
+	if (!musicclass_string) {
 		return;
 	}
 
 	channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
 	if (!channel_event_string) {
+		ast_free(musicclass_string);
 		return;
 	}
 
 	if (obj->blob) {
+		const char *musicclass;
+
 		musicclass = ast_json_string_get(ast_json_object_get(obj->blob, "musicclass"));
 
 		if (!ast_strlen_zero(musicclass)) {
@@ -1087,13 +1089,16 @@
 		"%s",
 		ast_str_buffer(channel_event_string),
 		ast_str_buffer(musicclass_string));
+
+	ast_free(musicclass_string);
+	ast_free(channel_event_string);
 }
 
 static void channel_unhold_cb(void *data, struct stasis_subscription *sub,
 	struct stasis_message *message)
 {
 	struct ast_channel_blob *obj = stasis_message_data(message);
-	RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
+	struct ast_str *channel_event_string;
 
 	channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
 	if (!channel_event_string) {
@@ -1103,6 +1108,8 @@
 	manager_event(EVENT_FLAG_CALL, "Unhold",
 		"%s",
 		ast_str_buffer(channel_event_string));
+
+	ast_free(channel_event_string);
 }
 
 static void manager_channels_shutdown(void)

Modified: trunk/main/stasis_channels.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/stasis_channels.c?view=diff&rev=434217&r1=434216&r2=434217
==============================================================================
--- trunk/main/stasis_channels.c (original)
+++ trunk/main/stasis_channels.c Tue Apr  7 10:22:42 2015
@@ -1136,6 +1136,47 @@
 	return channel_blob_to_json(message, "ChannelTalkingFinished", sanitize);
 }
 
+static struct ast_json *hold_to_json(struct stasis_message *message,
+	const struct stasis_message_sanitizer *sanitize)
+{
+	struct ast_channel_blob *channel_blob = stasis_message_data(message);
+	struct ast_json *blob = channel_blob->blob;
+	struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
+	const char *musicclass = ast_json_string_get(ast_json_object_get(blob, "musicclass"));
+	const struct timeval *tv = stasis_message_timestamp(message);
+	struct ast_json *json_channel;
+
+	json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
+	if (!json_channel) {
+		return NULL;
+	}
+
+	return ast_json_pack("{s: s, s: o, s: s, s: o}",
+		"type", "ChannelHold",
+		"timestamp", ast_json_timeval(*tv, NULL),
+		"musicclass", S_OR(musicclass, "N/A"),
+		"channel", json_channel);
+}
+
+static struct ast_json *unhold_to_json(struct stasis_message *message,
+	const struct stasis_message_sanitizer *sanitize)
+{
+	struct ast_channel_blob *channel_blob = stasis_message_data(message);
+	struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
+	const struct timeval *tv = stasis_message_timestamp(message);
+	struct ast_json *json_channel;
+
+	json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
+	if (!json_channel) {
+		return NULL;
+	}
+
+	return ast_json_pack("{s: s, s: o, s: o}",
+		"type", "ChannelUnhold",
+		"timestamp", ast_json_timeval(*tv, NULL),
+		"channel", json_channel);
+}
+
 /*!
  * @{ \brief Define channel message types.
  */
@@ -1154,8 +1195,12 @@
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_end_type,
 	.to_json = dtmf_end_to_json,
 	);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_hold_type);
-STASIS_MESSAGE_TYPE_DEFN(ast_channel_unhold_type);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_hold_type,
+	.to_json = hold_to_json,
+	);
+STASIS_MESSAGE_TYPE_DEFN(ast_channel_unhold_type,
+	.to_json = unhold_to_json,
+	);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_start_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_stop_type);
 STASIS_MESSAGE_TYPE_DEFN(ast_channel_fax_type);

Modified: trunk/res/ari/ari_model_validators.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/ari/ari_model_validators.c?view=diff&rev=434217&r1=434216&r2=434217
==============================================================================
--- trunk/res/ari/ari_model_validators.c (original)
+++ trunk/res/ari/ari_model_validators.c Tue Apr  7 10:22:42 2015
@@ -3197,6 +3197,85 @@
 	return ast_ari_validate_channel_hangup_request;
 }
 
+int ast_ari_validate_channel_hold(struct ast_json *json)
+{
+	int res = 1;
+	struct ast_json_iter *iter;
+	int has_type = 0;
+	int has_application = 0;
+	int has_channel = 0;
+
+	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_type = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelHold field type failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_application = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelHold field application failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			prop_is_valid = ast_ari_validate_date(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelHold field timestamp failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_channel = 1;
+			prop_is_valid = ast_ari_validate_channel(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelHold field channel failed validation\n");
+				res = 0;
+			}
+		} else
+		{
+			ast_log(LOG_ERROR,
+				"ARI ChannelHold has undocumented field %s\n",
+				ast_json_object_iter_key(iter));
+			res = 0;
+		}
+	}
+
+	if (!has_type) {
+		ast_log(LOG_ERROR, "ARI ChannelHold missing required field type\n");
+		res = 0;
+	}
+
+	if (!has_application) {
+		ast_log(LOG_ERROR, "ARI ChannelHold missing required field application\n");
+		res = 0;
+	}
+
+	if (!has_channel) {
+		ast_log(LOG_ERROR, "ARI ChannelHold missing required field channel\n");
+		res = 0;
+	}
+
+	return res;
+}
+
+ari_validator ast_ari_validate_channel_hold_fn(void)
+{
+	return ast_ari_validate_channel_hold;
+}
+
 int ast_ari_validate_channel_left_bridge(struct ast_json *json)
 {
 	int res = 1;
@@ -3545,6 +3624,85 @@
 	return ast_ari_validate_channel_talking_started;
 }
 
+int ast_ari_validate_channel_unhold(struct ast_json *json)
+{
+	int res = 1;
+	struct ast_json_iter *iter;
+	int has_type = 0;
+	int has_application = 0;
+	int has_channel = 0;
+
+	for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+		if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_type = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelUnhold field type failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_application = 1;
+			prop_is_valid = ast_ari_validate_string(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelUnhold field application failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			prop_is_valid = ast_ari_validate_date(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelUnhold field timestamp failed validation\n");
+				res = 0;
+			}
+		} else
+		if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+			int prop_is_valid;
+			has_channel = 1;
+			prop_is_valid = ast_ari_validate_channel(
+				ast_json_object_iter_value(iter));
+			if (!prop_is_valid) {
+				ast_log(LOG_ERROR, "ARI ChannelUnhold field channel failed validation\n");
+				res = 0;
+			}
+		} else
+		{
+			ast_log(LOG_ERROR,
+				"ARI ChannelUnhold has undocumented field %s\n",
+				ast_json_object_iter_key(iter));
+			res = 0;
+		}
+	}
+
+	if (!has_type) {
+		ast_log(LOG_ERROR, "ARI ChannelUnhold missing required field type\n");
+		res = 0;
+	}
+
+	if (!has_application) {
+		ast_log(LOG_ERROR, "ARI ChannelUnhold missing required field application\n");
+		res = 0;
+	}
+
+	if (!has_channel) {
+		ast_log(LOG_ERROR, "ARI ChannelUnhold missing required field channel\n");
+		res = 0;
+	}
+
+	return res;
+}
+
+ari_validator ast_ari_validate_channel_unhold_fn(void)
+{
+	return ast_ari_validate_channel_unhold;
+}
+
 int ast_ari_validate_channel_userevent(struct ast_json *json)
 {
 	int res = 1;
@@ -4119,6 +4277,9 @@
 	if (strcmp("ChannelHangupRequest", discriminator) == 0) {
 		return ast_ari_validate_channel_hangup_request(json);
 	} else
+	if (strcmp("ChannelHold", discriminator) == 0) {
+		return ast_ari_validate_channel_hold(json);
+	} else
 	if (strcmp("ChannelLeftBridge", discriminator) == 0) {
 		return ast_ari_validate_channel_left_bridge(json);
 	} else
@@ -4130,6 +4291,9 @@
 	} else
 	if (strcmp("ChannelTalkingStarted", discriminator) == 0) {
 		return ast_ari_validate_channel_talking_started(json);
+	} else
+	if (strcmp("ChannelUnhold", discriminator) == 0) {
+		return ast_ari_validate_channel_unhold(json);
 	} else
 	if (strcmp("ChannelUserevent", discriminator) == 0) {
 		return ast_ari_validate_channel_userevent(json);
@@ -4290,6 +4454,9 @@
 	if (strcmp("ChannelHangupRequest", discriminator) == 0) {
 		return ast_ari_validate_channel_hangup_request(json);
 	} else
+	if (strcmp("ChannelHold", discriminator) == 0) {
+		return ast_ari_validate_channel_hold(json);
+	} else
 	if (strcmp("ChannelLeftBridge", discriminator) == 0) {
 		return ast_ari_validate_channel_left_bridge(json);
 	} else
@@ -4301,6 +4468,9 @@
 	} else
 	if (strcmp("ChannelTalkingStarted", discriminator) == 0) {
 		return ast_ari_validate_channel_talking_started(json);
+	} else
+	if (strcmp("ChannelUnhold", discriminator) == 0) {
+		return ast_ari_validate_channel_unhold(json);
 	} else
 	if (strcmp("ChannelUserevent", discriminator) == 0) {
 		return ast_ari_validate_channel_userevent(json);

Modified: trunk/res/ari/ari_model_validators.h
URL: http://svnview.digium.com/svn/asterisk/trunk/res/ari/ari_model_validators.h?view=diff&rev=434217&r1=434216&r2=434217
==============================================================================
--- trunk/res/ari/ari_model_validators.h (original)
+++ trunk/res/ari/ari_model_validators.h Tue Apr  7 10:22:42 2015
@@ -809,6 +809,24 @@
 ari_validator ast_ari_validate_channel_hangup_request_fn(void);
 
 /*!
+ * \brief Validator for ChannelHold.
+ *
+ * A channel initiated a media hold.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_hold(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_hold().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_hold_fn(void);
+
+/*!
  * \brief Validator for ChannelLeftBridge.
  *
  * Notification that a channel has left a bridge.
@@ -879,6 +897,24 @@
  * See \ref ast_ari_model_validators.h for more details.
  */
 ari_validator ast_ari_validate_channel_talking_started_fn(void);
+
+/*!
+ * \brief Validator for ChannelUnhold.
+ *
+ * A channel initiated a media unhold.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_unhold(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_unhold().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_unhold_fn(void);
 
 /*!
  * \brief Validator for ChannelUserevent.
@@ -1393,6 +1429,11 @@
  * - cause: int
  * - channel: Channel (required)
  * - soft: boolean
+ * ChannelHold
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - channel: Channel (required)
  * ChannelLeftBridge
  * - type: string (required)
  * - application: string (required)
@@ -1411,6 +1452,11 @@
  * - channel: Channel (required)
  * - duration: int (required)
  * ChannelTalkingStarted
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - channel: Channel (required)
+ * ChannelUnhold
  * - type: string (required)
  * - application: string (required)
  * - timestamp: Date

Modified: trunk/rest-api/api-docs/events.json
URL: http://svnview.digium.com/svn/asterisk/trunk/rest-api/api-docs/events.json?view=diff&rev=434217&r1=434216&r2=434217
==============================================================================
--- trunk/rest-api/api-docs/events.json (original)
+++ trunk/rest-api/api-docs/events.json Tue Apr  7 10:22:42 2015
@@ -161,6 +161,8 @@
 				"ChannelVarset",
 				"ChannelTalkingStarted",
 				"ChannelTalkingFinished",
+				"ChannelHold",
+				"ChannelUnhold",
 				"EndpointStateChange",
 				"Dial",
 				"StasisEnd",
@@ -598,6 +600,28 @@
 				}
 			}
 		},
+		"ChannelHold": {
+			"id": "ChannelHold",
+			"description": "A channel initiated a media hold.",
+			"properties": {
+				"channel": {
+					"required": true,
+					"type": "Channel",
+					"description": "The channel that initiated the hold event."
+				}
+			}
+		},
+		"ChannelUnhold": {
+			"id": "ChannelUnhold",
+			"description": "A channel initiated a media unhold.",
+			"properties": {
+				"channel": {
+					"required": true,
+					"type": "Channel",
+					"description": "The channel that initiated the unhold event."
+				}
+			}
+		},
 		"ChannelTalkingStarted": {
 			"id": "ChannelTalkingStarted",
 			"description": "Talking was detected on the channel.",




More information about the asterisk-commits mailing list