[asterisk-commits] kmoore: trunk r394858 - in /trunk: ./ apps/ channels/ include/asterisk/ main/...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sat Jul 20 08:10:28 CDT 2013


Author: kmoore
Date: Sat Jul 20 08:10:22 2013
New Revision: 394858

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=394858
Log:
Add transfer support to CEL

This adds CEL support for blind and attended transfers and call pickup.
During the course of adding this functionality I noticed that
CONF_ENTER, CONF_EXIT, and BRIDGE_TO_CONF events are particularly
useless without a bridge identifier, so I added that as well.

This adds tests for blind transfers, several types of attended
transfers, and call pickup.

The extra field in CEL records now consists of a JSON blob whose fields
are defined on a per-event basis.

Review: https://reviewboard.asterisk.org/r/2658/
(closes issue ASTERISK-21565)

Modified:
    trunk/CHANGES
    trunk/apps/app_celgenuserevent.c
    trunk/apps/app_dial.c
    trunk/apps/app_directed_pickup.c
    trunk/apps/app_queue.c
    trunk/channels/chan_dahdi.c
    trunk/channels/chan_sip.c
    trunk/channels/sig_analog.c
    trunk/include/asterisk/cel.h
    trunk/main/cel.c
    trunk/main/channel.c
    trunk/main/features.c
    trunk/main/pbx.c
    trunk/tests/test_cel.c

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Sat Jul 20 08:10:22 2013
@@ -319,6 +319,23 @@
  * When a CDR is dispatched, user defined CDR variables from both parties are
    included in the resulting CDR. If both parties have the same variable, only
    the Party A value is provided.
+
+CEL (Channel Event Logging)
+------------------
+ * The 'extra' field of all CEL events that use it now consists of a JSON blob
+   with key/value pairs which are defined in the Asterisk 12 CEL documentation.
+
+ * AST_CEL_BLINDTRANSFER events now report the transferee bridge unique
+   identifier, extension, and context in a JSON blob as the extra string
+   instead of the transferee channel name as the peer.
+
+ * AST_CEL_ATTENDEDTRANSFER events now report the peer as NULL and additional
+   information in the 'extra' string as a JSON blob. For transfers that occur
+   between two bridged channels, the 'extra' JSON blob contains the primary
+   bridge unique identifier, the secondary channel name, and the secondary
+   bridge unique identifier. For transfers that occur between a bridged channel
+   and a channel running an app, the 'extra' JSON blob contains the primary
+   bridge unique identifier, the secondary channel name, and the app name.
 
 Features
 -------------------

Modified: trunk/apps/app_celgenuserevent.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_celgenuserevent.c?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/apps/app_celgenuserevent.c (original)
+++ trunk/apps/app_celgenuserevent.c Sat Jul 20 08:10:22 2013
@@ -75,9 +75,9 @@
 	parse = ast_strdupa(data);
 	AST_STANDARD_APP_ARGS(args, parse);
 
-	blob = ast_json_pack("{s: s, s: s}",
+	blob = ast_json_pack("{s: s, s: {s: s}}",
 		"event", args.event,
-		"extra", args.extra);
+		"extra", "extra", args.extra);
 	if (!blob) {
 		return res;
 	}

Modified: trunk/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_dial.c?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/apps/app_dial.c (original)
+++ trunk/apps/app_dial.c Sat Jul 20 08:10:22 2013
@@ -60,7 +60,6 @@
 #include "asterisk/stringfields.h"
 #include "asterisk/global_datastores.h"
 #include "asterisk/dsp.h"
-#include "asterisk/cel.h"
 #include "asterisk/aoc.h"
 #include "asterisk/ccss.h"
 #include "asterisk/indications.h"

Modified: trunk/apps/app_directed_pickup.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_directed_pickup.c?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/apps/app_directed_pickup.c (original)
+++ trunk/apps/app_directed_pickup.c Sat Jul 20 08:10:22 2013
@@ -46,7 +46,6 @@
 #include "asterisk/features.h"
 #include "asterisk/manager.h"
 #include "asterisk/callerid.h"
-#include "asterisk/cel.h"
 
 #define PICKUPMARK "PICKUPMARK"
 

Modified: trunk/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_queue.c?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/apps/app_queue.c (original)
+++ trunk/apps/app_queue.c Sat Jul 20 08:10:22 2013
@@ -103,7 +103,6 @@
 #include "asterisk/taskprocessor.h"
 #include "asterisk/aoc.h"
 #include "asterisk/callerid.h"
-#include "asterisk/cel.h"
 #include "asterisk/data.h"
 #include "asterisk/term.h"
 #include "asterisk/dial.h"

Modified: trunk/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_dahdi.c?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/channels/chan_dahdi.c (original)
+++ trunk/channels/chan_dahdi.c Sat Jul 20 08:10:22 2013
@@ -107,7 +107,6 @@
 #include "asterisk/callerid.h"
 #include "asterisk/adsi.h"
 #include "asterisk/cli.h"
-#include "asterisk/cel.h"
 #include "asterisk/features.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/say.h"

Modified: trunk/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_sip.c?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Sat Jul 20 08:10:22 2013
@@ -276,7 +276,6 @@
 #include "asterisk/translate.h"
 #include "asterisk/ast_version.h"
 #include "asterisk/event.h"
-#include "asterisk/cel.h"
 #include "asterisk/data.h"
 #include "asterisk/aoc.h"
 #include "asterisk/message.h"

Modified: trunk/channels/sig_analog.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_analog.c?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/channels/sig_analog.c (original)
+++ trunk/channels/sig_analog.c Sat Jul 20 08:10:22 2013
@@ -41,7 +41,6 @@
 #include "asterisk/manager.h"
 #include "asterisk/astdb.h"
 #include "asterisk/features.h"
-#include "asterisk/cel.h"
 #include "asterisk/causes.h"
 #include "asterisk/features_config.h"
 #include "asterisk/bridging.h"

Modified: trunk/include/asterisk/cel.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/cel.h?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/include/asterisk/cel.h (original)
+++ trunk/include/asterisk/cel.h Sat Jul 20 08:10:22 2013
@@ -67,8 +67,6 @@
 	AST_CEL_BLINDTRANSFER = 13,
 	/*! \brief a transfer occurs */
 	AST_CEL_ATTENDEDTRANSFER = 14,
-	/*! \brief a transfer occurs */
-	AST_CEL_TRANSFER = 15,
 	/*! \brief a 3-way conference, usually part of a transfer */
 	AST_CEL_HOOKFLASH = 16,
 	/*! \brief a 3-way conference, usually part of a transfer */
@@ -166,31 +164,6 @@
  *       some point.
  */
 struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event);
-
-/*!
- * \brief Report a channel event
- *
- * \param chan This argument is required.  This is the primary channel associated with
- *        this channel event.
- * \param event_type This is the type of call event being reported.
- * \param userdefevname This is an optional custom name for the call event.
- * \param extra This is an optional opaque field that will go into the "CEL_EXTRA"
- *        information element of the call event.
- * \param peer2 All CEL events contain a "peer name" information element.  The first
- *        place the code will look to get a peer name is from the bridged channel to
- *        chan.  If chan has no bridged channel and peer2 is specified, then the name
- *        of peer2 will go into the "peer name" field.  If neither are available, the
- *        peer name field will be blank.
- *
- * \since 1.8
- *
- * \pre chan and peer2 are both unlocked
- *
- * \retval 0 success
- * \retval non-zero failure
- */
-int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
-		const char *userdefevname, const char *extra, struct ast_channel *peer2);
 
 /*!
  * \brief Helper struct for getting the fields out of a CEL event
@@ -312,8 +285,8 @@
  *        with this channel event.
  * \param event_type The type of call event being reported.
  * \param userdefevname Custom name for the call event. (optional)
- * \param extra An opaque field that will go into the "CEL_EXTRA" information
- *        element of the call event. (optional)
+ * \param extra An event-specific opaque JSON blob to be rendered and placed
+ *        in the "CEL_EXTRA" information element of the call event. (optional)
  * \param peer_name The peer name to be placed into the event. (optional)
  *
  * \since 12
@@ -323,7 +296,7 @@
  */
 struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
 		enum ast_cel_event_type event_type, const char *userdefevname,
-		const char *extra, const char *peer_name);
+		struct ast_json *extra, const char *peer_name);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }

Modified: trunk/main/cel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/cel.c?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/main/cel.c (original)
+++ trunk/main/cel.c Sat Jul 20 08:10:22 2013
@@ -61,6 +61,7 @@
 #include "asterisk/stasis_bridging.h"
 #include "asterisk/bridging.h"
 #include "asterisk/parking.h"
+#include "asterisk/features.h"
 
 /*** DOCUMENTATION
 	<configInfo name="cel" language="en_US">
@@ -101,7 +102,6 @@
 						<enum name="CONF_END"/>
 						<enum name="PARK_START"/>
 						<enum name="PARK_END"/>
-						<enum name="TRANSFER"/>
 						<enum name="USER_DEFINED"/>
 						<enum name="CONF_ENTER"/>
 						<enum name="CONF_EXIT"/>
@@ -308,7 +308,6 @@
 	[AST_CEL_CONF_END]         = "CONF_END",
 	[AST_CEL_PARK_START]       = "PARK_START",
 	[AST_CEL_PARK_END]         = "PARK_END",
-	[AST_CEL_TRANSFER]         = "TRANSFER",
 	[AST_CEL_USER_DEFINED]     = "USER_DEFINED",
 	[AST_CEL_CONF_ENTER]       = "CONF_ENTER",
 	[AST_CEL_CONF_EXIT]        = "CONF_EXIT",
@@ -634,9 +633,13 @@
 static int cel_linkedid_ref(const char *linkedid);
 struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
 		enum ast_cel_event_type event_type, const char *userdefevname,
-		const char *extra, const char *peer_name)
+		struct ast_json *extra, const char *peer_name)
 {
 	struct timeval eventtime = ast_tvnow();
+	RAII_VAR(char *, extra_txt, NULL, ast_free);
+	if (extra) {
+		extra_txt = ast_json_dump_string(extra);
+	}
 	return ast_event_new(AST_EVENT_CEL,
 		AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
 		AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
@@ -658,14 +661,14 @@
 		AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, snapshot->uniqueid,
 		AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, snapshot->linkedid,
 		AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, snapshot->userfield,
-		AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, S_OR(extra, ""),
+		AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, S_OR(extra_txt, ""),
 		AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, S_OR(peer_name, ""),
 		AST_EVENT_IE_END);
 }
 
-static int report_event_snapshot(struct ast_channel_snapshot *snapshot,
+static int cel_report_event(struct ast_channel_snapshot *snapshot,
 		enum ast_cel_event_type event_type, const char *userdefevname,
-		const char *extra, const char *peer2_name)
+		struct ast_json *extra, const char *peer2_name)
 {
 	struct ast_event *ev;
 	char *linkedid = ast_strdupa(snapshot->linkedid);
@@ -735,7 +738,7 @@
 	 * before unreffing the channel we have a refcount of 3, we're done. Unlink and report. */
 	if (ao2_ref(lid, -1) == 3) {
 		ast_str_container_remove(linkedids, lid);
-		report_event_snapshot(snapshot, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
+		cel_report_event(snapshot, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
 	}
 	ao2_ref(lid, -1);
 }
@@ -892,109 +895,6 @@
 	}
 	/* If we've found, go ahead and keep the ref to increment count of how many channels
 	 * have this linkedid. We'll clean it up in check_retire */
-	return 0;
-}
-
-int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
-		const char *userdefevname, const char *extra, struct ast_channel *peer2)
-{
-	struct timeval eventtime;
-	struct ast_event *ev;
-	const char *peername = "";
-	struct ast_channel *peer;
-	char *linkedid = ast_strdupa(ast_channel_linkedid(chan));
-
-	if (!ast_cel_check_enabled()) {
-		return 0;
-	}
-
-	/* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
-	 * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
-	if (ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
-		if (cel_linkedid_ref(linkedid)) {
-			return -1;
-		}
-	}
-
-	if (!ast_cel_track_event(event_type)) {
-		return 0;
-	}
-
-	if ((event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END)
-		&& !cel_track_app(ast_channel_appl(chan))) {
-		return 0;
-	}
-
-	ast_channel_lock(chan);
-	peer = ast_bridged_channel(chan);
-	if (peer) {
-		ast_channel_ref(peer);
-	}
-	ast_channel_unlock(chan);
-
-	if (peer) {
-		ast_channel_lock(peer);
-		peername = ast_strdupa(ast_channel_name(peer));
-		ast_channel_unlock(peer);
-	} else if (peer2) {
-		ast_channel_lock(peer2);
-		peername = ast_strdupa(ast_channel_name(peer2));
-		ast_channel_unlock(peer2);
-	}
-
-	if (!userdefevname) {
-		userdefevname = "";
-	}
-
-	if (!extra) {
-		extra = "";
-	}
-
-	eventtime = ast_tvnow();
-
-	ast_channel_lock(chan);
-
-	ev = ast_event_new(AST_EVENT_CEL,
-		AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
-		AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
-		AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
-		AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
-		AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
-			S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""),
-		AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
-			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
-		AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
-			S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""),
-		AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
-			S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""),
-		AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
-			S_OR(ast_channel_dialed(chan)->number.str, ""),
-		AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, ast_channel_exten(chan),
-		AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, ast_channel_context(chan),
-		AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, ast_channel_name(chan),
-		AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_appl(chan), ""),
-		AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_data(chan), ""),
-		AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, ast_channel_amaflags(chan),
-		AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, ast_channel_accountcode(chan),
-		AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, ast_channel_peeraccount(chan),
-		AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, ast_channel_uniqueid(chan),
-		AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, ast_channel_linkedid(chan),
-		AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, ast_channel_userfield(chan),
-		AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
-		AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
-		AST_EVENT_IE_END);
-
-	ast_channel_unlock(chan);
-
-	if (peer) {
-		peer = ast_channel_unref(peer);
-	}
-
-	if (ev && ast_event_queue(ev)) {
-		ast_event_destroy(ev);
-		return -1;
-	}
-
 	return 0;
 }
 
@@ -1074,13 +974,13 @@
 	int is_hungup, was_hungup;
 
 	if (!new_snapshot) {
-		report_event_snapshot(old_snapshot, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
+		cel_report_event(old_snapshot, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
 		check_retire_linkedid(old_snapshot);
 		return;
 	}
 
 	if (!old_snapshot) {
-		report_event_snapshot(new_snapshot, AST_CEL_CHANNEL_START, NULL, NULL, NULL);
+		cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, NULL, NULL, NULL);
 		return;
 	}
 
@@ -1088,22 +988,22 @@
 	is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
 
 	if (!was_hungup && is_hungup) {
-		RAII_VAR(struct ast_str *, extra_str, ast_str_create(128), ast_free);
+		RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
 		RAII_VAR(struct ast_multi_channel_blob *, blob, get_dialstatus_blob(new_snapshot->uniqueid), ao2_cleanup);
 		const char *dialstatus = "";
 		if (blob && !ast_strlen_zero(get_blob_variable(blob, "dialstatus"))) {
 			dialstatus = get_blob_variable(blob, "dialstatus");
 		}
-		ast_str_set(&extra_str, 0, "%d,%s,%s",
-			new_snapshot->hangupcause,
-			new_snapshot->hangupsource,
-			dialstatus);
-		report_event_snapshot(new_snapshot, AST_CEL_HANGUP, NULL, ast_str_buffer(extra_str), NULL);
+		extra = ast_json_pack("{s: i, s: s, s: s}",
+			"hangupcause", new_snapshot->hangupcause,
+			"hangupsource", new_snapshot->hangupsource,
+			"dialstatus", dialstatus);
+		cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL);
 		return;
 	}
 
 	if (old_snapshot->state != new_snapshot->state && new_snapshot->state == AST_STATE_UP) {
-		report_event_snapshot(new_snapshot, AST_CEL_ANSWER, NULL, NULL, NULL);
+		cel_report_event(new_snapshot, AST_CEL_ANSWER, NULL, NULL, NULL);
 		return;
 	}
 }
@@ -1136,12 +1036,12 @@
 
 	/* old snapshot has an application, end it */
 	if (old_snapshot && !ast_strlen_zero(old_snapshot->appl)) {
-		report_event_snapshot(old_snapshot, AST_CEL_APP_END, NULL, NULL, NULL);
+		cel_report_event(old_snapshot, AST_CEL_APP_END, NULL, NULL, NULL);
 	}
 
 	/* new snapshot has an application, start it */
 	if (new_snapshot && !ast_strlen_zero(new_snapshot->appl)) {
-		report_event_snapshot(new_snapshot, AST_CEL_APP_START, NULL, NULL, NULL);
+		cel_report_event(new_snapshot, AST_CEL_APP_START, NULL, NULL, NULL);
 	}
 }
 
@@ -1260,7 +1160,11 @@
 
 	if (snapshot->capabilities & (AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE)) {
 		if (assoc && assoc->track_as_conf) {
-			report_event_snapshot(chan_snapshot, AST_CEL_CONF_ENTER, NULL, NULL, NULL);
+			RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
+			extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
+			if (extra) {
+				cel_report_event(chan_snapshot, AST_CEL_CONF_ENTER, NULL, extra, NULL);
+			}
 			return;
 		}
 
@@ -1286,7 +1190,7 @@
 			}
 
 			add_bridge_primary(latest_primary, snapshot->uniqueid, chan_snapshot->name);
-			report_event_snapshot(latest_primary, AST_CEL_BRIDGE_START, NULL, NULL, chan_snapshot->name);
+			cel_report_event(latest_primary, AST_CEL_BRIDGE_START, NULL, NULL, chan_snapshot->name);
 		} else if (ao2_container_count(snapshot->channels) > 2) {
 			if (!assoc) {
 				ast_log(LOG_ERROR, "No association found for bridge %s\n", snapshot->uniqueid);
@@ -1295,18 +1199,31 @@
 
 			/* this bridge will no longer be treated like a bridge, so mark the bridge_assoc as such */
 			if (!assoc->track_as_conf) {
+				RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
 				assoc->track_as_conf = 1;
-				report_event_snapshot(assoc->primary_snapshot, AST_CEL_BRIDGE_TO_CONF, NULL,
-					chan_snapshot->name, assoc->secondary_name);
+
+				extra = ast_json_pack("{s: s, s: s}",
+					"channel_name", chan_snapshot->name,
+					"bridge_id", snapshot->uniqueid);
+
+				if (extra) {
+					cel_report_event(assoc->primary_snapshot, AST_CEL_BRIDGE_TO_CONF, NULL,
+						extra, assoc->secondary_name);
+				}
+
 				ast_string_field_set(assoc, secondary_name, "");
 			}
 		}
 	} else if (snapshot->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) {
+		RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
 		if (!assoc) {
 			add_bridge_primary(chan_snapshot, snapshot->uniqueid, "");
 			return;
 		}
-		report_event_snapshot(chan_snapshot, AST_CEL_CONF_ENTER, NULL, NULL, NULL);
+		extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
+		if (extra) {
+			cel_report_event(chan_snapshot, AST_CEL_CONF_ENTER, NULL, extra, NULL);
+		}
 	}
 }
 
@@ -1333,17 +1250,25 @@
 		}
 
 		if (assoc->track_as_conf) {
-			report_event_snapshot(chan_snapshot, AST_CEL_CONF_EXIT, NULL, NULL, NULL);
+			RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
+			extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
+			if (extra) {
+				cel_report_event(chan_snapshot, AST_CEL_CONF_EXIT, NULL, extra, NULL);
+			}
 			return;
 		}
 
 		if (ao2_container_count(snapshot->channels) == 1) {
-			report_event_snapshot(assoc->primary_snapshot, AST_CEL_BRIDGE_END, NULL, NULL, assoc->secondary_name);
+			cel_report_event(assoc->primary_snapshot, AST_CEL_BRIDGE_END, NULL, NULL, assoc->secondary_name);
 			remove_bridge_primary(assoc->primary_snapshot->uniqueid);
 			return;
 		}
 	} else if (snapshot->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) {
-		report_event_snapshot(chan_snapshot, AST_CEL_CONF_EXIT, NULL, NULL, NULL);
+		RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
+		extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
+		if (extra) {
+			cel_report_event(chan_snapshot, AST_CEL_CONF_EXIT, NULL, extra, NULL);
+		}
 	}
 }
 
@@ -1353,25 +1278,35 @@
 	struct stasis_message *message)
 {
 	struct ast_parked_call_payload *parked_payload = stasis_message_data(message);
+	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
+	const char *reason = NULL;
 
 	switch (parked_payload->event_type) {
 	case PARKED_CALL:
-		report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_START, NULL,
-			parked_payload->parkinglot,
-			parked_payload->parker_dial_string);
-		break;
+		extra = ast_json_pack("{s: s, s: s}",
+			"parker_dial_string", parked_payload->parker_dial_string,
+			"parking_lot", parked_payload->parkinglot);
+		if (extra) {
+			cel_report_event(parked_payload->parkee, AST_CEL_PARK_START, NULL, extra, NULL);
+		}
+		return;
 	case PARKED_CALL_TIMEOUT:
-		report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
+		reason = "ParkedCallTimeOut";
 		break;
 	case PARKED_CALL_GIVEUP:
-		report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", NULL);
+		reason = "ParkedCallGiveUp";
 		break;
 	case PARKED_CALL_UNPARKED:
-		report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_END, NULL, "ParkedCallUnparked", NULL);
+		reason = "ParkedCallUnparked";
 		break;
 	case PARKED_CALL_FAILED:
-		report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_END, NULL, "ParkedCallFailed", NULL);
+		reason = "ParkedCallFailed";
 		break;
+	}
+
+	extra = ast_json_pack("{s: s}", "reason", reason);
+	if (extra) {
+		cel_report_event(parked_payload->parkee, AST_CEL_PARK_END, NULL, extra, NULL);
 	}
 }
 
@@ -1396,11 +1331,15 @@
 
 	if (!ast_strlen_zero(get_blob_variable(blob, "forward"))) {
 		struct ast_channel_snapshot *caller = ast_multi_channel_blob_get_channel(blob, "caller");
+		RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
 		if (!caller) {
 			return;
 		}
 
-		report_event_snapshot(caller, AST_CEL_FORWARD, NULL, get_blob_variable(blob, "forward"), NULL);
+		extra = ast_json_pack("{s: s}", "forward", get_blob_variable(blob, "forward"));
+		if (extra) {
+			cel_report_event(caller, AST_CEL_FORWARD, NULL, extra, NULL);
+		}
 	}
 
 	if (ast_strlen_zero(get_blob_variable(blob, "dialstatus"))) {
@@ -1423,14 +1362,115 @@
 	case AST_CEL_USER_DEFINED:
 		{
 			const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
-			const char *extra = ast_json_string_get(ast_json_object_get(event_details, "extra"));
-			report_event_snapshot(obj->snapshot, event_type, event, extra, NULL);
+			struct ast_json *extra = ast_json_object_get(event_details, "extra");
+			cel_report_event(obj->snapshot, event_type, event, extra, NULL);
 			break;
 		}
 	default:
 		ast_log(LOG_ERROR, "Unhandled %s event blob\n", ast_cel_get_type_name(event_type));
 		break;
 	}
+}
+
+static void cel_blind_transfer_cb(
+	void *data, struct stasis_subscription *sub,
+	struct stasis_topic *topic,
+	struct stasis_message *message)
+{
+	struct ast_bridge_blob *obj = stasis_message_data(message);
+	struct ast_channel_snapshot *chan_snapshot = obj->channel;
+	struct ast_bridge_snapshot *bridge_snapshot = obj->bridge;
+	struct ast_json *blob = obj->blob;
+	struct ast_json *json_exten = ast_json_object_get(blob, "exten");
+	struct ast_json *json_context = ast_json_object_get(blob, "context");
+	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
+	const char *exten, *context;
+
+	if (!json_exten || !json_context) {
+		return;
+	}
+
+	exten = ast_json_string_get(json_exten);
+	context = ast_json_string_get(json_context);
+	if (!exten || !context) {
+		return;
+	}
+	extra = ast_json_pack("{s: s, s: s, s: s}",
+		"extension", exten,
+		"context", context,
+		"bridge_id", bridge_snapshot->uniqueid);
+
+	if (extra) {
+		cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, NULL, extra, NULL);
+	}
+}
+
+static void cel_attended_transfer_cb(
+	void *data, struct stasis_subscription *sub,
+	struct stasis_topic *topic,
+	struct stasis_message *message)
+{
+	struct ast_attended_transfer_message *xfer = stasis_message_data(message);
+	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
+	struct ast_bridge_snapshot *bridge1, *bridge2;
+	struct ast_channel_snapshot *channel1, *channel2;
+
+	/* Make sure bridge1 is always non-NULL */
+	if (!xfer->to_transferee.bridge_snapshot) {
+		bridge1 = xfer->to_transfer_target.bridge_snapshot;
+		bridge2 = xfer->to_transferee.bridge_snapshot;
+		channel1 = xfer->to_transfer_target.channel_snapshot;
+		channel2 = xfer->to_transferee.channel_snapshot;
+	} else {
+		bridge1 = xfer->to_transferee.bridge_snapshot;
+		bridge2 = xfer->to_transfer_target.bridge_snapshot;
+		channel1 = xfer->to_transferee.channel_snapshot;
+		channel2 = xfer->to_transfer_target.channel_snapshot;
+	}
+
+	switch (xfer->dest_type) {
+	case AST_ATTENDED_TRANSFER_DEST_FAIL:
+		return;
+		/* handle these two the same */
+	case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
+	case AST_ATTENDED_TRANSFER_DEST_LINK:
+		extra = ast_json_pack("{s: s, s: s, s: s}",
+			"bridge1_id", bridge1->uniqueid,
+			"channel2_name", channel2->name,
+			"bridge2_id", bridge2->uniqueid);
+
+		if (!extra) {
+			return;
+		}
+		break;
+	case AST_ATTENDED_TRANSFER_DEST_APP:
+		extra = ast_json_pack("{s: s, s: s, s: s}",
+			"bridge1_id", bridge1->uniqueid,
+			"channel2_name", channel2->name,
+			"app", xfer->dest.app);
+
+		if (!extra) {
+			return;
+		}
+		break;
+	}
+	cel_report_event(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra, NULL);
+}
+
+static void cel_pickup_cb(
+	void *data, struct stasis_subscription *sub,
+	struct stasis_topic *topic,
+	struct stasis_message *message)
+{
+	struct ast_multi_channel_blob *obj = stasis_message_data(message);
+	struct ast_channel_snapshot *channel = ast_multi_channel_blob_get_channel(obj, "channel");
+	struct ast_channel_snapshot *target = ast_multi_channel_blob_get_channel(obj, "target");
+
+	if (!channel || !target) {
+		return;
+	}
+
+	cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, channel->name);
 }
 
 static void ast_cel_engine_term(void)
@@ -1554,6 +1594,21 @@
 		cel_generic_cb,
 		NULL);
 
+	ret |= stasis_message_router_add(cel_state_router,
+		ast_blind_transfer_type(),
+		cel_blind_transfer_cb,
+		NULL);
+
+	ret |= stasis_message_router_add(cel_state_router,
+		ast_attended_transfer_type(),
+		cel_attended_transfer_cb,
+		NULL);
+
+	ret |= stasis_message_router_add(cel_state_router,
+		ast_call_pickup_type(),
+		cel_pickup_cb,
+		NULL);
+
 	/* If somehow we failed to add any routes, just shut down the whole
 	 * thing and fail it.
 	 */

Modified: trunk/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/channel.c?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/main/channel.c (original)
+++ trunk/main/channel.c Sat Jul 20 08:10:22 2013
@@ -50,7 +50,6 @@
 #include "asterisk/cli.h"
 #include "asterisk/translate.h"
 #include "asterisk/manager.h"
-#include "asterisk/cel.h"
 #include "asterisk/chanvars.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/indications.h"

Modified: trunk/main/features.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/features.c?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/main/features.c (original)
+++ trunk/main/features.c Sat Jul 20 08:10:22 2013
@@ -70,7 +70,6 @@
 #include "asterisk/audiohook.h"
 #include "asterisk/global_datastores.h"
 #include "asterisk/astobj2.h"
-#include "asterisk/cel.h"
 #include "asterisk/test.h"
 #include "asterisk/bridging.h"
 #include "asterisk/bridging_basic.h"
@@ -2553,8 +2552,6 @@
 	}
 
 	/* Initiate the channel transfer of party A to party C (or recalled party B). */
-	ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
-
 	xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(transferee), 0, "Transfered/%s", ast_channel_name(transferee));
 	if (!xferchan) {
 		ast_autoservice_chan_hangup_peer(transferee, newchan);
@@ -4739,8 +4736,6 @@
 	ast_channel_unlock(chan);
 	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
 
-	ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
-
 	if (ast_answer(chan)) {
 		ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
 		goto pickup_failed;

Modified: trunk/main/pbx.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/pbx.c?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/main/pbx.c (original)
+++ trunk/main/pbx.c Sat Jul 20 08:10:22 2013
@@ -50,7 +50,6 @@
 #include "asterisk/file.h"
 #include "asterisk/callerid.h"
 #include "asterisk/cdr.h"
-#include "asterisk/cel.h"
 #include "asterisk/config.h"
 #include "asterisk/term.h"
 #include "asterisk/time.h"

Modified: trunk/tests/test_cel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/tests/test_cel.c?view=diff&rev=394858&r1=394857&r2=394858
==============================================================================
--- trunk/tests/test_cel.c (original)
+++ trunk/tests/test_cel.c Sat Jul 20 08:10:22 2013
@@ -47,6 +47,8 @@
 #include "asterisk/bridging_basic.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/stasis_bridging.h"
+#include "asterisk/json.h"
+#include "asterisk/features.h"
 
 #define TEST_CATEGORY "/main/cel/"
 
@@ -78,6 +80,73 @@
 	} \
 	} while (0)
 
+#define APPEND_EVENT_SNAPSHOT(snapshot, ev_type, userevent, extra, peer) do { \
+	if (append_expected_event_snapshot(snapshot, ev_type, userevent, extra, peer)) { \
+		return AST_TEST_FAIL; \
+	} \
+	} while (0)
+
+#define APPEND_DUMMY_EVENT() do { \
+	if (append_dummy_event()) { \
+		return AST_TEST_FAIL; \
+	} \
+	} while (0)
+
+#define CONF_EXIT(channel, bridge) do { \
+	ast_test_validate(test, 0 == ast_bridge_depart(channel)); \
+	CONF_EXIT_EVENT(channel, bridge); \
+	} while (0)
+
+#define CONF_EXIT_EVENT(channel, bridge) do { \
+	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
+	extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
+	ast_test_validate(test, extra != NULL); \
+	APPEND_EVENT(channel, AST_CEL_CONF_EXIT, NULL, extra, NULL); \
+	} while (0)
+
+#define CONF_EXIT_SNAPSHOT(channel, bridge) do { \
+	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
+	extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
+	ast_test_validate(test, extra != NULL); \
+	APPEND_EVENT_SNAPSHOT(channel, AST_CEL_CONF_EXIT, NULL, extra, NULL); \
+	} while (0)
+
+#define CONF_ENTER_EVENT(channel, bridge) do { \
+	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
+	extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
+	ast_test_validate(test, extra != NULL); \
+	APPEND_EVENT(channel, AST_CEL_CONF_ENTER, NULL, extra, NULL); \
+	} while (0)
+
+#define BRIDGE_TO_CONF(first, second, third, bridge) do { \
+	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
+	extra = ast_json_pack("{s: s, s: s}", \
+		"channel_name", ast_channel_name(third), \
+		"bridge_id", bridge->uniqueid); \
+	ast_test_validate(test, extra != NULL); \
+	APPEND_EVENT(first, AST_CEL_BRIDGE_TO_CONF, NULL, extra, ast_channel_name(second)); \
+	} while (0)
+
+#define BLINDTRANSFER_EVENT(channel, bridge, extension, context) do { \
+	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
+	extra = ast_json_pack("{s: s, s: s, s: s}", \
+		"extension", extension, \
+		"context", context, \
+		"bridge_id", bridge->uniqueid); \
+	ast_test_validate(test, extra != NULL); \
+	APPEND_EVENT(channel, AST_CEL_BLINDTRANSFER, NULL, extra, NULL); \
+	} while (0)
+
+#define ATTENDEDTRANSFER_BRIDGE(channel1, bridge1, channel2, bridge2) do { \
+	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
+	extra = ast_json_pack("{s: s, s: s, s: s}", \
+		"bridge1_id", bridge1->uniqueid, \
+		"channel2_name", ast_channel_name(channel2), \
+		"bridge2_id", bridge2->uniqueid); \
+	ast_test_validate(test, extra != NULL); \
+	APPEND_EVENT(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra, NULL); \
+	} while (0)
+
 /*! \brief Alice's Caller ID */
 #define ALICE_CALLERID { .id.name.str = "Alice", .id.name.valid = 1, .id.number.str = "100", .id.number.valid = 1, }
 
@@ -89,32 +158,46 @@
 
 /*! \brief David's Caller ID */
 #define DAVID_CALLERID { .id.name.str = "David", .id.name.valid = 1, .id.number.str = "400", .id.number.valid = 1, }
+
+/*! \brief Eve's Caller ID */
+#define EVE_CALLERID { .id.name.str = "Eve", .id.name.valid = 1, .id.number.str = "500", .id.number.valid = 1, }
+
+/*! \brief Fred's Caller ID */
+#define FRED_CALLERID { .id.name.str = "Fred", .id.name.valid = 1, .id.number.str = "600", .id.number.valid = 1, }
 
 /*! \brief Create a \ref test_cel_chan_tech for Alice. */
 #define CREATE_ALICE_CHANNEL(channel_var, caller_id) do { \
 	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice"); \
-	/*ast_channel_set_caller((channel_var), (caller_id), NULL);*/ \
 	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
 	} while (0)
 
 /*! \brief Create a \ref test_cel_chan_tech for Bob. */
 #define CREATE_BOB_CHANNEL(channel_var, caller_id) do { \
 	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "200", "200", "default", NULL, 0, CHANNEL_TECH_NAME "/Bob"); \
-	/*ast_channel_set_caller((channel_var), (caller_id), NULL);*/ \
 	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
 	} while (0)
 
 /*! \brief Create a \ref test_cel_chan_tech for Charlie. */
 #define CREATE_CHARLIE_CHANNEL(channel_var, caller_id) do { \
 	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "300", "300", "default", NULL, 0, CHANNEL_TECH_NAME "/Charlie"); \
-	/*ast_channel_set_caller((channel_var), (caller_id), NULL);*/ \
 	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
 	} while (0)
 
-/*! \brief Create a \ref test_cel_chan_tech for Charlie. */
+/*! \brief Create a \ref test_cel_chan_tech for David. */
 #define CREATE_DAVID_CHANNEL(channel_var, caller_id) do { \
 	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "400", "400", "default", NULL, 0, CHANNEL_TECH_NAME "/David"); \
-	/*ast_channel_set_caller((channel_var), (caller_id), NULL);*/ \
+	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
+	} while (0)
+
+/*! \brief Create a \ref test_cel_chan_tech for Eve. */
+#define CREATE_EVE_CHANNEL(channel_var, caller_id) do { \
+	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "500", "500", "default", NULL, 0, CHANNEL_TECH_NAME "/Eve"); \
+	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
+	} while (0)
+
+/*! \brief Create a \ref test_cel_chan_tech for Eve. */
+#define CREATE_FRED_CHANNEL(channel_var, caller_id) do { \
+	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "600", "600", "default", NULL, 0, CHANNEL_TECH_NAME "/Fred"); \
 	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
 	} while (0)
 
@@ -139,24 +222,41 @@
 	} while (0)
 
 /*! \brief Hang up a test channel safely */
-#define HANGUP_CHANNEL(channel, cause, hangup_extra) \
-	do { \
-		ast_channel_hangupcause_set((channel), (cause)); \
-		ao2_ref(channel, +1); \
-		ast_hangup(channel); \
-		APPEND_EVENT(channel, AST_CEL_HANGUP, NULL, hangup_extra, NULL); \
-		APPEND_EVENT(channel, AST_CEL_CHANNEL_END, NULL, NULL, NULL); \
-		ao2_cleanup(stasis_cache_get_extended(ast_channel_topic_all_cached(), \
-			ast_channel_snapshot_type(), ast_channel_uniqueid(channel), 1)); \
-		ao2_cleanup(channel); \
-		channel = NULL; \
+#define HANGUP_CHANNEL(channel, cause, dialstatus) do { \
+	ast_channel_hangupcause_set((channel), (cause)); \
+	ao2_ref(channel, +1); \
+	ast_hangup((channel)); \
+	HANGUP_EVENT(channel, cause, dialstatus); \
+	APPEND_EVENT(channel, AST_CEL_CHANNEL_END, NULL, NULL, NULL); \
+	ao2_cleanup(stasis_cache_get_extended(ast_channel_topic_all_cached(), \
+		ast_channel_snapshot_type(), ast_channel_uniqueid(channel), 1)); \
+	ao2_cleanup(channel); \
+	channel = NULL; \
+	} while (0)
+
+#define HANGUP_EVENT(channel, cause, dialstatus) do { \
+	RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
+	extra = ast_json_pack("{s: i, s: s, s: s}", \
+		"hangupcause", cause, \
+		"hangupsource", "", \
+		"dialstatus", dialstatus); \
+	ast_test_validate(test, extra != NULL); \
+	APPEND_EVENT(channel, AST_CEL_HANGUP, NULL, extra, NULL); \
 	} while (0)
 
 static int append_expected_event(
 	struct ast_channel *chan,
 	enum ast_cel_event_type type,
 	const char *userdefevname,
-	const char *extra, const char *peer);
+	struct ast_json *extra, const char *peer);
+
+static int append_expected_event_snapshot(
+	struct ast_channel_snapshot *snapshot,
+	enum ast_cel_event_type type,
+	const char *userdefevname,
+	struct ast_json *extra, const char *peer);
+
+static int append_dummy_event(void);
 
 static void safe_channel_release(struct ast_channel *chan)
 {
@@ -185,7 +285,7 @@
 
 	CREATE_ALICE_CHANNEL(chan, (&caller));
 
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "16,,");
+	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
 
 	return AST_TEST_PASS;
 }
@@ -213,7 +313,7 @@
 
 	EMULATE_APP_DATA(chan, 1, "Wait", "1");
 
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "16,,");
+	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
 
 	return AST_TEST_PASS;
 }
@@ -246,7 +346,7 @@
 	ast_channel_context_set(chan, "default");
 	ast_set_flag(ast_channel_flags(chan), AST_FLAG_ORIGINATED);
 	EMULATE_APP_DATA(chan, 0, "AppDial", "(Outgoing Line)");
-	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "16,,");
+	HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
 
 	return AST_TEST_PASS;
 }
@@ -273,7 +373,7 @@
 	ANSWER_CHANNEL(chan);

[... 790 lines stripped ...]



More information about the asterisk-commits mailing list