diff --git a/apps/app_queue.c b/apps/app_queue.c
index 17e35f9bbb03545f4a9044f2cd2e5315ca6eed7a..2e59bf67430d572f8f4b569eb4e1b9c19cb869ea 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -5890,13 +5890,13 @@ static void queue_agent_cb(void *userdata, struct stasis_subscription *sub,
 	agent_blob = stasis_message_data(msg);
 
 	if (ast_channel_agent_login_type() == stasis_message_type(msg)) {
-		ast_queue_log("NONE", agent_blob->snapshot->uniqueid,
+		ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
 			ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
-			"AGENTLOGIN", "%s", agent_blob->snapshot->name);
+			"AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
 	} else if (ast_channel_agent_logoff_type() == stasis_message_type(msg)) {
-		ast_queue_log("NONE", agent_blob->snapshot->uniqueid,
+		ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
 			ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
-			"AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->name,
+			"AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
 			(long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
 	}
 }
@@ -6088,8 +6088,8 @@ static void log_attended_transfer(struct queue_stasis_data *queue_data, struct a
 		ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
 		break;
 	case AST_ATTENDED_TRANSFER_DEST_LINK:
-		ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->name,
-				atxfer_msg->dest.links[1]->name);
+		ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
+				atxfer_msg->dest.links[1]->base->name);
 		break;
 	case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
 	case AST_ATTENDED_TRANSFER_DEST_FAIL:
@@ -6098,7 +6098,7 @@ static void log_attended_transfer(struct queue_stasis_data *queue_data, struct a
 		return;
 	}
 
-	ast_queue_log(queue_data->queue->name, caller->uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
+	ast_queue_log(queue_data->queue->name, caller->base->uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
 			ast_str_buffer(transfer_str),
 			(long) (queue_data->starttime - queue_data->holdstart),
 			(long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
@@ -6131,11 +6131,11 @@ static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub,
 		return;
 	}
 
-	if (!strcmp(enter_blob->channel->uniqueid, queue_data->caller_uniqueid)) {
+	if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
 		ast_string_field_set(queue_data, bridge_uniqueid,
 				enter_blob->bridge->uniqueid);
 		ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
-				enter_blob->channel->name, queue_data->bridge_uniqueid);
+				enter_blob->channel->base->name, queue_data->bridge_uniqueid);
 	}
 }
 
@@ -6186,7 +6186,7 @@ static void handle_blind_transfer(void *userdata, struct stasis_subscription *su
 	context = transfer_msg->context;
 
 	ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
-	ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
+	ast_queue_log(queue_data->queue->name, caller_snapshot->base->uniqueid, queue_data->member->membername,
 			"BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
 			exten, context,
 			(long) (queue_data->starttime - queue_data->holdstart),
@@ -6302,9 +6302,9 @@ static void handle_local_optimization_begin(void *userdata, struct stasis_subscr
 		return;
 	}
 
-	if (!strcmp(local_one->uniqueid, queue_data->member_uniqueid)) {
+	if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
 		optimization = &queue_data->member_optimize;
-	} else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
+	} else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
 		optimization = &queue_data->caller_optimize;
 	} else {
 		return;
@@ -6313,9 +6313,9 @@ static void handle_local_optimization_begin(void *userdata, struct stasis_subscr
 	/* We only allow move-swap optimizations, so there had BETTER be a source */
 	ast_assert(source != NULL);
 
-	optimization->source_chan_uniqueid = ast_strdup(source->uniqueid);
+	optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
 	if (!optimization->source_chan_uniqueid) {
-		ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->name);
+		ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
 		return;
 	}
 	id = ast_json_integer_get(ast_json_object_get(ast_multi_channel_blob_get_json(optimization_blob), "id"));
@@ -6354,10 +6354,10 @@ static void handle_local_optimization_end(void *userdata, struct stasis_subscrip
 		return;
 	}
 
-	if (!strcmp(local_one->uniqueid, queue_data->member_uniqueid)) {
+	if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
 		optimization = &queue_data->member_optimize;
 		is_caller = 0;
-	} else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
+	} else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
 		optimization = &queue_data->caller_optimize;
 		is_caller = 1;
 	} else {
@@ -6420,16 +6420,16 @@ static void handle_hangup(void *userdata, struct stasis_subscription *sub,
 		return;
 	}
 
-	if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->caller_uniqueid)) {
+	if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
 		reason = CALLER;
-	} else if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->member_uniqueid)) {
+	} else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
 		reason = AGENT;
 	} else {
 		ao2_unlock(queue_data);
 		return;
 	}
 
-	chan = ast_channel_get_by_name(channel_blob->snapshot->name);
+	chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
 	if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
 		     !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
 		     !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
@@ -6446,9 +6446,9 @@ static void handle_hangup(void *userdata, struct stasis_subscription *sub,
 	ao2_unlock(queue_data);
 
 	ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
-			channel_blob->snapshot->name);
+			channel_blob->snapshot->base->name);
 
-	ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
+	ast_queue_log(queue_data->queue->name, caller_snapshot->base->uniqueid, queue_data->member->membername,
 			reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
 		(long) (queue_data->starttime - queue_data->holdstart),
 		(long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index d0a74cd40e638597076eeb4295a59025ae05ff00..e44f3283dc9c6ffedd1857e04028c90b4adb7fbf 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -1169,7 +1169,7 @@ static int chan_pjsip_devicestate(const char *data)
 			continue;
 		}
 
-		if (chan_pjsip_get_hold(snapshot->uniqueid)) {
+		if (chan_pjsip_get_hold(snapshot->base->uniqueid)) {
 			ast_devstate_aggregate_add(&aggregate, AST_DEVICE_ONHOLD);
 		} else {
 			ast_devstate_aggregate_add(&aggregate, ast_state_chan2dev(snapshot->state));
diff --git a/channels/pjsip/cli_commands.c b/channels/pjsip/cli_commands.c
index 9a8dc2938afe01c14566a97a40cc9c041cb02faf..2ce236997ac259c301467483c7bacbc77f88fd0b 100644
--- a/channels/pjsip/cli_commands.c
+++ b/channels/pjsip/cli_commands.c
@@ -61,13 +61,13 @@ static int cli_channel_sort(const void *obj, const void *arg, int flags)
 
 	switch (flags & OBJ_SEARCH_MASK) {
 	case OBJ_SEARCH_OBJECT:
-		right_key = right_obj->name;
+		right_key = right_obj->base->name;
 		/* Fall through */
 	case OBJ_SEARCH_KEY:
-		cmp = strcmp(left_obj->name, right_key);
+		cmp = strcmp(left_obj->base->name, right_key);
 		break;
 	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(left_obj->name, right_key, strlen(right_key));
+		cmp = strncmp(left_obj->base->name, right_key, strlen(right_key));
 		break;
 	default:
 		cmp = 0;
@@ -86,17 +86,17 @@ static int cli_channelstats_sort(const void *obj, const void *arg, int flags)
 
 	switch (flags & OBJ_SEARCH_MASK) {
 	case OBJ_SEARCH_OBJECT:
-		cmp = strcmp(left_obj->bridgeid, right_obj->bridgeid);
+		cmp = strcmp(left_obj->bridge->id, right_obj->bridge->id);
 		if (cmp) {
 			return cmp;
 		}
-		right_key = right_obj->name;
+		right_key = right_obj->base->name;
 		/* Fall through */
 	case OBJ_SEARCH_KEY:
-		cmp = strcmp(left_obj->name, right_key);
+		cmp = strcmp(left_obj->base->name, right_key);
 		break;
 	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncmp(left_obj->name, right_key, strlen(right_key));
+		cmp = strncmp(left_obj->base->name, right_key, strlen(right_key));
 		break;
 	default:
 		cmp = 0;
@@ -115,15 +115,15 @@ static int cli_channel_compare(void *obj, void *arg, int flags)
 
 	switch (flags & OBJ_SEARCH_MASK) {
 	case OBJ_SEARCH_OBJECT:
-		right_key = right_obj->name;
+		right_key = right_obj->base->name;
 		/* Fall through */
 	case OBJ_SEARCH_KEY:
-		if (strcmp(left_obj->name, right_key) == 0) {
+		if (strcmp(left_obj->base->name, right_key) == 0) {
 			cmp = CMP_MATCH | CMP_STOP;
 		}
 		break;
 	case OBJ_SEARCH_PARTIAL_KEY:
-		if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
+		if (strncmp(left_obj->base->name, right_key, strlen(right_key)) == 0) {
 			cmp = CMP_MATCH;
 		}
 		break;
@@ -144,18 +144,18 @@ static int cli_channelstats_compare(void *obj, void *arg, int flags)
 
 	switch (flags & OBJ_SEARCH_MASK) {
 	case OBJ_SEARCH_OBJECT:
-		if (strcmp(left_obj->bridgeid, right_obj->bridgeid) == 0
-			&& strcmp(left_obj->name, right_obj->name) == 0) {
+		if (strcmp(left_obj->bridge->id, right_obj->bridge->id) == 0
+			&& strcmp(left_obj->base->name, right_obj->base->name) == 0) {
 			return CMP_MATCH | CMP_STOP;
 		}
 		break;
 	case OBJ_SEARCH_KEY:
-		if (strcmp(left_obj->name, right_key) == 0) {
+		if (strcmp(left_obj->base->name, right_key) == 0) {
 			cmp = CMP_MATCH | CMP_STOP;
 		}
 		break;
 	case OBJ_SEARCH_PARTIAL_KEY:
-		if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
+		if (strncmp(left_obj->base->name, right_key, strlen(right_key)) == 0) {
 			cmp = CMP_MATCH;
 		}
 		break;
@@ -172,7 +172,7 @@ static int cli_message_to_snapshot(void *obj, void *arg, int flags)
 	struct ast_channel_snapshot *snapshot = obj;
 	struct ao2_container *snapshots = arg;
 
-	if (!strcmp(snapshot->type, "PJSIP")) {
+	if (!strcmp(snapshot->base->type, "PJSIP")) {
 		ao2_link(snapshots, snapshot);
 		return CMP_MATCH;
 	}
@@ -185,8 +185,8 @@ static int cli_filter_channels(void *obj, void *arg, int flags)
 	struct ast_channel_snapshot *channel = obj;
 	regex_t *regexbuf = arg;
 
-	if (!regexec(regexbuf, channel->name, 0, NULL, 0)
-		|| !regexec(regexbuf, channel->appl, 0, NULL, 0)) {
+	if (!regexec(regexbuf, channel->base->name, 0, NULL, 0)
+		|| !regexec(regexbuf, channel->dialplan->appl, 0, NULL, 0)) {
 		return 0;
 	}
 
@@ -236,7 +236,7 @@ static const char *cli_channel_get_id(const void *obj)
 {
 	const struct ast_channel_snapshot *snapshot = obj;
 
-	return snapshot->name;
+	return snapshot->base->name;
 }
 
 static void *cli_channel_retrieve_by_id(const char *id)
@@ -280,16 +280,16 @@ static int cli_channel_print_body(void *obj, void *arg, int flags)
 
 	ast_assert(context->output_buffer != NULL);
 
-	print_name_len = strlen(snapshot->name) + strlen(snapshot->appl) + 2;
+	print_name_len = strlen(snapshot->base->name) + strlen(snapshot->dialplan->appl) + 2;
 	print_name = alloca(print_name_len);
 
 	/* Append the application */
-	snprintf(print_name, print_name_len, "%s/%s", snapshot->name, snapshot->appl);
+	snprintf(print_name, print_name_len, "%s/%s", snapshot->base->name, snapshot->dialplan->appl);
 
 	indent = CLI_INDENT_TO_SPACES(context->indent_level);
 	flexwidth = CLI_LAST_TABSTOP - indent;
 
-	ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32);
+	ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->base->creationtime.tv_sec, print_time, 32);
 
 	ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s  %-11.11s\n",
 		CLI_INDENT_TO_SPACES(context->indent_level), "Channel",
@@ -307,9 +307,9 @@ static int cli_channel_print_body(void *obj, void *arg, int flags)
 			"%*s: %-*.*s  CLCID: \"%s\" <%s>\n",
 			indent, "Exten",
 			flexwidth, flexwidth,
-			snapshot->exten,
-			snapshot->connected_name,
-			snapshot->connected_number
+			snapshot->dialplan->exten,
+			snapshot->connected->name,
+			snapshot->connected->number
 			);
 		context->indent_level--;
 		if (context->indent_level == 0) {
@@ -338,7 +338,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 {
 	struct ast_sip_cli_context *context = arg;
 	const struct ast_channel_snapshot *snapshot = obj;
-	struct ast_channel *channel = ast_channel_get_by_name(snapshot->name);
+	struct ast_channel *channel = ast_channel_get_by_name(snapshot->base->name);
 	struct ast_sip_channel_pvt *cpvt = channel ? ast_channel_tech_pvt(channel) : NULL;
 	struct ast_sip_session *session;
 	struct ast_sip_session_media *media;
@@ -351,7 +351,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 	ast_assert(context->output_buffer != NULL);
 
 	if (!channel) {
-		ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
+		ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->base->name);
 		return -1;
 	}
 
@@ -359,7 +359,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 
 	session = cpvt->session;
 	if (!session) {
-		ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
+		ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->base->name);
 		ast_channel_unlock(channel);
 		ao2_cleanup(channel);
 		return -1;
@@ -367,7 +367,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 
 	media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
 	if (!media || !media->rtp) {
-		ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
+		ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->base->name);
 		ast_channel_unlock(channel);
 		ao2_cleanup(channel);
 		return -1;
@@ -383,18 +383,18 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 
 	ast_channel_unlock(channel);
 
-	print_name = ast_strdupa(snapshot->name);
+	print_name = ast_strdupa(snapshot->base->name);
 	/* Skip the PJSIP/.  We know what channel type it is and we need the space. */
 	print_name += 6;
 
-	ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32);
+	ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->base->creationtime.tv_sec, print_time, 32);
 
 	if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
-		ast_str_append(&context->output_buffer, 0, "%s direct media\n", snapshot->name);
+		ast_str_append(&context->output_buffer, 0, "%s direct media\n", snapshot->base->name);
 	} else {
 		ast_str_append(&context->output_buffer, 0,
 			" %8.8s %-18.18s %-8.8s %-6.6s %6u%s %6u%s %3u %7.3f %6u%s %6u%s %3u %7.3f %7.3f\n",
-			snapshot->bridgeid,
+			snapshot->bridge->id,
 			print_name,
 			print_time,
 			codec_in_use,
diff --git a/configs/samples/ari.conf.sample b/configs/samples/ari.conf.sample
index 8729b1e09e84f3499d00858bb692e3c917dcdb44..5ce3166bfa77ffdf7c8aa8786b8902e72047578b 100644
--- a/configs/samples/ari.conf.sample
+++ b/configs/samples/ari.conf.sample
@@ -17,6 +17,8 @@ enabled = yes       ; When set to no, ARI support is disabled.
 ; Display certain channel variables every time a channel-oriented
 ; event is emitted:
 ;
+; Note that this does incur a performance penalty and should be avoided if possible.
+;
 ;channelvars = var1,var2,var3
 
 ;[username]
diff --git a/configs/samples/manager.conf.sample b/configs/samples/manager.conf.sample
index 989441a615bb6b1ec47a5dc507a57d533b798720..405e0d32c55044416c1aac5b88944a6796f4944d 100644
--- a/configs/samples/manager.conf.sample
+++ b/configs/samples/manager.conf.sample
@@ -55,6 +55,8 @@ bindaddr = 0.0.0.0
 ; Display certain channel variables every time a channel-oriented
 ; event is emitted:
 ;
+; Note that this does incur a performance penalty and should be avoided if possible.
+;
 ;channelvars = var1,var2,var3
 
 ; debug = on	; enable some debugging info in AMI messages (default off).
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 9627ae216f98d8ecd473f6b95119d24fcecebeb5..58a4879b00a9dc4318553726524a7432fb8ec0bd 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -4258,6 +4258,7 @@ enum ast_channel_state ast_channel_state(const struct ast_channel *chan);
 ast_callid ast_channel_callid(const struct ast_channel *chan);
 struct ast_channel_snapshot *ast_channel_snapshot(const struct ast_channel *chan);
 void ast_channel_snapshot_set(struct ast_channel *chan, struct ast_channel_snapshot *snapshot);
+struct ast_flags *ast_channel_snapshot_segment_flags(struct ast_channel *chan);
 
 /*!
  * \pre chan is locked
diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h
index 2aeff6f0b1c507c4ecb2d177634c4270cc91f0c6..c90470a73d4edb350d7337f5e7e5075fc4c169ed 100644
--- a/include/asterisk/stasis_channels.h
+++ b/include/asterisk/stasis_channels.h
@@ -28,51 +28,134 @@
  * @{
  */
 
+/*!
+ * \since 17
+ * \brief Channel snapshot invalidation flags, used to force generation of segments
+ */
+enum ast_channel_snapshot_segment_invalidation {
+	/*! Invalidate the bridge segment */
+	AST_CHANNEL_SNAPSHOT_INVALIDATE_BRIDGE = (1 << 1),
+	/*! Invalidate the dialplan segment */
+	AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN = (1 << 2),
+	/*! Invalidate the connected segment */
+	AST_CHANNEL_SNAPSHOT_INVALIDATE_CONNECTED = (1 << 3),
+	/*! Invalidate the caller segment */
+	AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER = (1 << 4),
+	/*! Invalidate the hangup segment */
+	AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP = (1 << 5),
+	/*! Invalidate the peer segment */
+	AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER = (1 << 6),
+	/*! Invalidate the base segment */
+	AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE = (1 << 7),
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing bridge information for a channel snapshot.
+ */
+struct ast_channel_snapshot_bridge {
+	char id[0]; /*!< Unique Bridge Identifier */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing dialplan information for a channel snapshot.
+ */
+struct ast_channel_snapshot_dialplan {
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(appl);             /*!< Current application */
+		AST_STRING_FIELD(data);             /*!< Data passed to current application */
+		AST_STRING_FIELD(context);          /*!< Current extension context */
+		AST_STRING_FIELD(exten);            /*!< Current extension number */
+	);
+	int priority; /*!< Current extension priority */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing caller information for a channel snapshot.
+ */
+struct ast_channel_snapshot_caller {
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(name);           /*!< Caller ID Name */
+		AST_STRING_FIELD(number);         /*!< Caller ID Number */
+		AST_STRING_FIELD(dnid);           /*!< Dialed ID Number */
+		AST_STRING_FIELD(dialed_subaddr); /*!< Dialed subaddress */
+		AST_STRING_FIELD(ani);            /*!< Caller ID ANI Number */
+		AST_STRING_FIELD(rdnis);          /*!< Caller ID RDNIS Number */
+		AST_STRING_FIELD(subaddr);        /*!< Caller subaddress */
+	);
+	int pres; /*!< Caller ID presentation. */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing connected information for a channel snapshot.
+ */
+struct ast_channel_snapshot_connected {
+	char *number; /*!< Connected Line Number */
+	char name[0]; /*!< Connected Line Name */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing base information for a channel snapshot.
+ */
+struct ast_channel_snapshot_base {
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(name);        /*!< ASCII unique channel name */
+		AST_STRING_FIELD(uniqueid);    /*!< Unique Channel Identifier */
+		AST_STRING_FIELD(accountcode); /*!< Account code for billing */
+		AST_STRING_FIELD(userfield);   /*!< Userfield for CEL billing */
+		AST_STRING_FIELD(language);    /*!< The default spoken language for the channel */
+		AST_STRING_FIELD(type);        /*!< Type of channel technology */
+	);
+	struct timeval creationtime; /*!< The time of channel creation */
+	int tech_properties;         /*!< Properties of the channel's technology */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing peer information for a channel snapshot.
+ */
+struct ast_channel_snapshot_peer {
+	char *linkedid;   /*!< Linked Channel Identifier -- gets propagated by linkage */
+	char account[0]; /*!< Peer account code for billing */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing hangup information for a channel snapshot.
+ */
+struct ast_channel_snapshot_hangup {
+	int cause;      /*!< Why is the channel hanged up. See causes.h */
+	char source[0]; /*!< Who is responsible for hanging up this channel */
+};
+
 /*!
  * \since 12
  * \brief Structure representing a snapshot of channel state.
  *
  * While not enforced programmatically, this object is shared across multiple
  * threads, and should be treated as an immutable object.
+ *
+ * It is guaranteed that the segments of this snapshot will always exist
+ * when accessing the snapshot.
  */
 struct ast_channel_snapshot {
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(name);             /*!< ASCII unique channel name */
-		AST_STRING_FIELD(uniqueid);         /*!< Unique Channel Identifier */
-		AST_STRING_FIELD(linkedid);         /*!< Linked Channel Identifier -- gets propagated by linkage */
-		AST_STRING_FIELD(appl);             /*!< Current application */
-		AST_STRING_FIELD(data);             /*!< Data passed to current application */
-		AST_STRING_FIELD(context);          /*!< Dialplan: Current extension context */
-		AST_STRING_FIELD(exten);            /*!< Dialplan: Current extension number */
-		AST_STRING_FIELD(accountcode);      /*!< Account code for billing */
-		AST_STRING_FIELD(peeraccount);      /*!< Peer account code for billing */
-		AST_STRING_FIELD(userfield);        /*!< Userfield for CEL billing */
-		AST_STRING_FIELD(hangupsource);     /*!< Who is responsible for hanging up this channel */
-		AST_STRING_FIELD(caller_name);      /*!< Caller ID Name */
-		AST_STRING_FIELD(caller_number);    /*!< Caller ID Number */
-		AST_STRING_FIELD(caller_dnid);      /*!< Dialed ID Number */
-		AST_STRING_FIELD(caller_ani);       /*!< Caller ID ANI Number */
-		AST_STRING_FIELD(caller_rdnis);     /*!< Caller ID RDNIS Number */
-		AST_STRING_FIELD(caller_subaddr);   /*!< Caller subaddress */
-		AST_STRING_FIELD(dialed_subaddr);   /*!< Dialed subaddress */
-		AST_STRING_FIELD(connected_name);   /*!< Connected Line Name */
-		AST_STRING_FIELD(connected_number); /*!< Connected Line Number */
-		AST_STRING_FIELD(language);         /*!< The default spoken language for the channel */
-		AST_STRING_FIELD(bridgeid);         /*!< Unique Bridge Identifier */
-		AST_STRING_FIELD(type);             /*!< Type of channel technology */
-	);
-
-	struct timeval creationtime;            /*!< The time of channel creation */
-	enum ast_channel_state state;           /*!< State of line */
-	int priority;                           /*!< Dialplan: Current extension priority */
-	int amaflags;                           /*!< AMA flags for billing */
-	int hangupcause;                        /*!< Why is the channel hanged up. See causes.h */
-	int caller_pres;                        /*!< Caller ID presentation. */
-	struct ast_flags flags;                 /*!< channel flags of AST_FLAG_ type */
-	struct ast_flags softhangup_flags;      /*!< softhangup channel flags */
-	struct varshead *manager_vars;          /*!< Variables to be appended to manager events */
-	int tech_properties;                    /*!< Properties of the channel's technology */
-	struct varshead *ari_vars;              /*!< Variables to be appended to ARI events */
+	struct ast_channel_snapshot_base *base;           /*!< Base information about the channel */
+	struct ast_channel_snapshot_peer *peer;           /*!< Peer information */
+	struct ast_channel_snapshot_caller *caller;       /*!< Information about the caller */
+	struct ast_channel_snapshot_connected *connected; /*!< Information about who this channel is connected to */
+	struct ast_channel_snapshot_bridge *bridge;       /*!< Information about the bridge */
+	struct ast_channel_snapshot_dialplan *dialplan;   /*!< Information about the dialplan */
+	struct ast_channel_snapshot_hangup *hangup;       /*!< Hangup information */
+	enum ast_channel_state state;                     /*!< State of line */
+	int amaflags;                                     /*!< AMA flags for billing */
+	struct ast_flags flags;                           /*!< channel flags of AST_FLAG_ type */
+	struct ast_flags softhangup_flags;                /*!< softhangup channel flags */
+	struct varshead *manager_vars;                    /*!< Variables to be appended to manager events */
+	struct varshead *ari_vars;                        /*!< Variables to be appended to ARI events */
 };
 
 /*!
@@ -359,6 +442,18 @@ void ast_channel_stage_snapshot(struct ast_channel *chan);
  */
 void ast_channel_stage_snapshot_done(struct ast_channel *chan);
 
+/*!
+ * \since 17
+ * \brief Invalidate a channel snapshot segment from being reused
+ *
+ * \pre chan is locked
+ *
+ * \param chan Channel to invalidate the segment on.
+ * \param segment The segment to invalidate.
+ */
+void ast_channel_snapshot_invalidate_segment(struct ast_channel *chan,
+	enum ast_channel_snapshot_segment_invalidation segment);
+
 /*!
  * \since 12
  * \brief Publish a \ref ast_channel_snapshot for a channel.
diff --git a/main/bridge.c b/main/bridge.c
index 024c6abfeae94a115db6bbbbc6dcea44d1d87136..a65927d4b558f308e7faece7741dd4b9596bd5c9 100644
--- a/main/bridge.c
+++ b/main/bridge.c
@@ -5157,7 +5157,7 @@ static int bridge_show_specific_print_channel(void *obj, void *arg, int flags)
 		return 0;
 	}
 
-	ast_cli(a->fd, "Channel: %s\n", snapshot->name);
+	ast_cli(a->fd, "Channel: %s\n", snapshot->base->name);
 	ao2_ref(snapshot, -1);
 
 	return 0;
diff --git a/main/cdr.c b/main/cdr.c
index e321c2215d80ace726b1b2f68c7fd0e9cb46d428..2e3b2058a93ed1442a79b0a6325474b738b23ea9 100644
--- a/main/cdr.c
+++ b/main/cdr.c
@@ -803,7 +803,7 @@ static void cdr_object_snapshot_copy(struct cdr_object_snapshot *dst, struct cdr
 static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table)
 {
 	CDR_DEBUG("%p - Transitioning CDR for %s from state %s to %s\n",
-		cdr, cdr->party_a.snapshot->name,
+		cdr, cdr->party_a.snapshot->base->name,
 		cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name);
 	cdr->fn_table = fn_table;
 	if (cdr->fn_table->init_function) {
@@ -938,9 +938,9 @@ static void cdr_all_relink(struct cdr_object *cdr)
 {
 	ao2_lock(active_cdrs_all);
 	if (cdr->party_b.snapshot) {
-		if (strcasecmp(cdr->party_b_name, cdr->party_b.snapshot->name)) {
+		if (strcasecmp(cdr->party_b_name, cdr->party_b.snapshot->base->name)) {
 			ao2_unlink_flags(active_cdrs_all, cdr, OBJ_NOLOCK);
-			ast_string_field_set(cdr, party_b_name, cdr->party_b.snapshot->name);
+			ast_string_field_set(cdr, party_b_name, cdr->party_b.snapshot->base->name);
 			ao2_link_flags(active_cdrs_all, cdr, OBJ_NOLOCK);
 		}
 	} else {
@@ -1039,16 +1039,16 @@ static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan)
 		ao2_cleanup(cdr);
 		return NULL;
 	}
-	ast_string_field_set(cdr, uniqueid, chan->uniqueid);
-	ast_string_field_set(cdr, name, chan->name);
-	ast_string_field_set(cdr, linkedid, chan->linkedid);
+	ast_string_field_set(cdr, uniqueid, chan->base->uniqueid);
+	ast_string_field_set(cdr, name, chan->base->name);
+	ast_string_field_set(cdr, linkedid, chan->peer->linkedid);
 	cdr->disposition = AST_CDR_NULL;
 	cdr->sequence = ast_atomic_fetchadd_int(&global_cdr_sequence, +1);
 
 	cdr->party_a.snapshot = chan;
 	ao2_t_ref(cdr->party_a.snapshot, +1, "bump snapshot during CDR creation");
 
-	CDR_DEBUG("%p - Created CDR for channel %s\n", cdr, chan->name);
+	CDR_DEBUG("%p - Created CDR for channel %s\n", cdr, chan->base->name);
 
 	cdr_object_transition_state(cdr, &single_state_fn_table);
 
@@ -1145,11 +1145,11 @@ static int snapshot_cep_changed(struct ast_channel_snapshot *old_snapshot,
 	 * will attempt to clear the application and restore the dummy originate application
 	 * of "AppDialX". Ignore application changes to AppDialX as a result.
 	 */
-	if (strcmp(new_snapshot->appl, old_snapshot->appl)
-		&& strncasecmp(new_snapshot->appl, "appdial", 7)
-		&& (strcmp(new_snapshot->context, old_snapshot->context)
-			|| strcmp(new_snapshot->exten, old_snapshot->exten)
-			|| new_snapshot->priority != old_snapshot->priority)) {
+	if (strcmp(new_snapshot->dialplan->appl, old_snapshot->dialplan->appl)
+		&& strncasecmp(new_snapshot->dialplan->appl, "appdial", 7)
+		&& (strcmp(new_snapshot->dialplan->context, old_snapshot->dialplan->context)
+			|| strcmp(new_snapshot->dialplan->exten, old_snapshot->dialplan->exten)
+			|| new_snapshot->dialplan->priority != old_snapshot->dialplan->priority)) {
 		return 1;
 	}
 
@@ -1196,11 +1196,11 @@ static struct cdr_object_snapshot *cdr_object_pick_party_a(struct cdr_object_sna
 
 	/* Neither party is dialed and neither has the Party A flag - defer to
 	 * creation time */
-	if (left->snapshot->creationtime.tv_sec < right->snapshot->creationtime.tv_sec) {
+	if (left->snapshot->base->creationtime.tv_sec < right->snapshot->base->creationtime.tv_sec) {
 		return left;
-	} else if (left->snapshot->creationtime.tv_sec > right->snapshot->creationtime.tv_sec) {
+	} else if (left->snapshot->base->creationtime.tv_sec > right->snapshot->base->creationtime.tv_sec) {
 		return right;
-	} else if (left->snapshot->creationtime.tv_usec > right->snapshot->creationtime.tv_usec) {
+	} else if (left->snapshot->base->creationtime.tv_usec > right->snapshot->base->creationtime.tv_usec) {
 		return right;
 	} else {
 		/* Okay, fine, take the left one */
@@ -1285,7 +1285,7 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
 		/* Don't create records for CDRs where the party A was a dialed channel */
 		if (snapshot_is_dialed(it_cdr->party_a.snapshot) && !it_cdr->party_b.snapshot) {
 			ast_debug(1, "CDR for %s is dialed and has no Party B; discarding\n",
-				it_cdr->party_a.snapshot->name);
+				it_cdr->party_a.snapshot->base->name);
 			continue;
 		}
 
@@ -1300,12 +1300,12 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
 
 		/* Party A */
 		ast_assert(party_a != NULL);
-		ast_copy_string(cdr_copy->accountcode, party_a->accountcode, sizeof(cdr_copy->accountcode));
+		ast_copy_string(cdr_copy->accountcode, party_a->base->accountcode, sizeof(cdr_copy->accountcode));
 		cdr_copy->amaflags = party_a->amaflags;
-		ast_copy_string(cdr_copy->channel, party_a->name, sizeof(cdr_copy->channel));
-		ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller_name, party_a->caller_number, "");
-		ast_copy_string(cdr_copy->src, party_a->caller_number, sizeof(cdr_copy->src));
-		ast_copy_string(cdr_copy->uniqueid, party_a->uniqueid, sizeof(cdr_copy->uniqueid));
+		ast_copy_string(cdr_copy->channel, party_a->base->name, sizeof(cdr_copy->channel));
+		ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller->name, party_a->caller->number, "");
+		ast_copy_string(cdr_copy->src, party_a->caller->number, sizeof(cdr_copy->src));
+		ast_copy_string(cdr_copy->uniqueid, party_a->base->uniqueid, sizeof(cdr_copy->uniqueid));
 		ast_copy_string(cdr_copy->lastapp, it_cdr->appl, sizeof(cdr_copy->lastapp));
 		ast_copy_string(cdr_copy->lastdata, it_cdr->data, sizeof(cdr_copy->lastdata));
 		ast_copy_string(cdr_copy->dst, it_cdr->exten, sizeof(cdr_copy->dst));
@@ -1313,8 +1313,8 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
 
 		/* Party B */
 		if (party_b) {
-			ast_copy_string(cdr_copy->dstchannel, party_b->name, sizeof(cdr_copy->dstchannel));
-			ast_copy_string(cdr_copy->peeraccount, party_b->accountcode, sizeof(cdr_copy->peeraccount));
+			ast_copy_string(cdr_copy->dstchannel, party_b->base->name, sizeof(cdr_copy->dstchannel));
+			ast_copy_string(cdr_copy->peeraccount, party_b->base->accountcode, sizeof(cdr_copy->peeraccount));
 			if (!ast_strlen_zero(it_cdr->party_b.userfield)) {
 				snprintf(cdr_copy->userfield, sizeof(cdr_copy->userfield), "%s;%s", it_cdr->party_a.userfield, it_cdr->party_b.userfield);
 			}
@@ -1375,8 +1375,8 @@ static void cdr_object_dispatch(struct cdr_object *cdr)
 	struct ast_cdr *pub_cdr;
 
 	CDR_DEBUG("%p - Dispatching CDR for Party A %s, Party B %s\n", cdr,
-		cdr->party_a.snapshot->name,
-		cdr->party_b.snapshot ? cdr->party_b.snapshot->name : "<none>");
+		cdr->party_a.snapshot->base->name,
+		cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<none>");
 	pub_cdr = cdr_object_create_public_records(cdr);
 	cdr_detach(pub_cdr);
 }
@@ -1434,10 +1434,10 @@ static void cdr_object_finalize(struct cdr_object *cdr)
 	if (cdr->disposition == AST_CDR_NULL) {
 		if (!ast_tvzero(cdr->answer)) {
 			cdr->disposition = AST_CDR_ANSWERED;
-		} else if (cdr->party_a.snapshot->hangupcause) {
-			cdr_object_set_disposition(cdr, cdr->party_a.snapshot->hangupcause);
-		} else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangupcause) {
-			cdr_object_set_disposition(cdr, cdr->party_b.snapshot->hangupcause);
+		} else if (cdr->party_a.snapshot->hangup->cause) {
+			cdr_object_set_disposition(cdr, cdr->party_a.snapshot->hangup->cause);
+		} else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangup->cause) {
+			cdr_object_set_disposition(cdr, cdr->party_b.snapshot->hangup->cause);
 		} else {
 			cdr->disposition = AST_CDR_FAILED;
 		}
@@ -1445,7 +1445,7 @@ static void cdr_object_finalize(struct cdr_object *cdr)
 
 	/* tv_usec is suseconds_t, which could be int or long */
 	ast_debug(1, "Finalized CDR for %s - start %ld.%06ld answer %ld.%06ld end %ld.%06ld dispo %s\n",
-			cdr->party_a.snapshot->name,
+			cdr->party_a.snapshot->base->name,
 			(long)cdr->start.tv_sec,
 			(long)cdr->start.tv_usec,
 			(long)cdr->answer.tv_sec,
@@ -1491,19 +1491,19 @@ static void cdr_object_check_party_a_answer(struct cdr_object *cdr)
 static void cdr_object_update_cid(struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
 {
 	if (!old_snapshot->snapshot) {
-		set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller_dnid);
-		set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller_subaddr);
-		set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->dialed_subaddr);
+		set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
+		set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
+		set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
 		return;
 	}
-	if (strcmp(old_snapshot->snapshot->caller_dnid, new_snapshot->caller_dnid)) {
-		set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller_dnid);
+	if (strcmp(old_snapshot->snapshot->caller->dnid, new_snapshot->caller->dnid)) {
+		set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
 	}
-	if (strcmp(old_snapshot->snapshot->caller_subaddr, new_snapshot->caller_subaddr)) {
-		set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller_subaddr);
+	if (strcmp(old_snapshot->snapshot->caller->subaddr, new_snapshot->caller->subaddr)) {
+		set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
 	}
-	if (strcmp(old_snapshot->snapshot->dialed_subaddr, new_snapshot->dialed_subaddr)) {
-		set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->dialed_subaddr);
+	if (strcmp(old_snapshot->snapshot->caller->dialed_subaddr, new_snapshot->caller->dialed_subaddr)) {
+		set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
 	}
 }
 
@@ -1524,7 +1524,7 @@ static void cdr_object_swap_snapshot(struct cdr_object_snapshot *old_snapshot,
 
 static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
 {
-	ast_assert(strcasecmp(snapshot->name, cdr->party_a.snapshot->name) == 0);
+	ast_assert(strcasecmp(snapshot->base->name, cdr->party_a.snapshot->base->name) == 0);
 
 	/* Finalize the CDR if we're in hangup logic and we're set to do so */
 	if (ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)
@@ -1539,11 +1539,11 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps
 	 */
 	if (!ast_test_flag(&snapshot->flags, AST_FLAG_SUBROUTINE_EXEC)
 		|| ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)) {
-		if (strcmp(cdr->context, snapshot->context)) {
-			ast_string_field_set(cdr, context, snapshot->context);
+		if (strcmp(cdr->context, snapshot->dialplan->context)) {
+			ast_string_field_set(cdr, context, snapshot->dialplan->context);
 		}
-		if (strcmp(cdr->exten, snapshot->exten)) {
-			ast_string_field_set(cdr, exten, snapshot->exten);
+		if (strcmp(cdr->exten, snapshot->dialplan->exten)) {
+			ast_string_field_set(cdr, exten, snapshot->dialplan->exten);
 		}
 	}
 
@@ -1555,13 +1555,13 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps
 	 * here.
 	 */
 	if (!ast_test_flag(&cdr->flags, AST_CDR_LOCK_APP)
-		&& !ast_strlen_zero(snapshot->appl)
-		&& (strncasecmp(snapshot->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))) {
-		if (strcmp(cdr->appl, snapshot->appl)) {
-			ast_string_field_set(cdr, appl, snapshot->appl);
+		&& !ast_strlen_zero(snapshot->dialplan->appl)
+		&& (strncasecmp(snapshot->dialplan->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))) {
+		if (strcmp(cdr->appl, snapshot->dialplan->appl)) {
+			ast_string_field_set(cdr, appl, snapshot->dialplan->appl);
 		}
-		if (strcmp(cdr->data, snapshot->data)) {
-			ast_string_field_set(cdr, data, snapshot->data);
+		if (strcmp(cdr->data, snapshot->dialplan->data)) {
+			ast_string_field_set(cdr, data, snapshot->dialplan->data);
 		}
 
 		/* Dial (app_dial) is a special case. Because pre-dial handlers, which
@@ -1569,13 +1569,13 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps
 		 * something people typically don't want to see, if we see a channel enter
 		 * into Dial here, we set the appl/data accordingly and lock it.
 		 */
-		if (!strcmp(snapshot->appl, "Dial")) {
+		if (!strcmp(snapshot->dialplan->appl, "Dial")) {
 			ast_set_flag(&cdr->flags, AST_CDR_LOCK_APP);
 		}
 	}
 
-	if (strcmp(cdr->linkedid, snapshot->linkedid)) {
-		ast_string_field_set(cdr, linkedid, snapshot->linkedid);
+	if (strcmp(cdr->linkedid, snapshot->peer->linkedid)) {
+		ast_string_field_set(cdr, linkedid, snapshot->peer->linkedid);
 	}
 	cdr_object_check_party_a_answer(cdr);
 	cdr_object_check_party_a_hangup(cdr);
@@ -1603,7 +1603,7 @@ static int base_process_parked_channel(struct cdr_object *cdr, struct ast_parked
 {
 	char park_info[128];
 
-	ast_assert(!strcasecmp(parking_info->parkee->name, cdr->party_a.snapshot->name));
+	ast_assert(!strcasecmp(parking_info->parkee->base->name, cdr->party_a.snapshot->base->name));
 
 	/* Update Party A information regardless */
 	cdr->fn_table->process_party_a(cdr, parking_info->parkee);
@@ -1637,25 +1637,25 @@ static void single_state_process_party_b(struct cdr_object *cdr, struct ast_chan
 
 static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
 {
-	if (caller && !strcasecmp(cdr->party_a.snapshot->name, caller->name)) {
+	if (caller && !strcasecmp(cdr->party_a.snapshot->base->name, caller->base->name)) {
 		base_process_party_a(cdr, caller);
 		CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr,
-			cdr->party_a.snapshot->name);
+			cdr->party_a.snapshot->base->name);
 		cdr_object_swap_snapshot(&cdr->party_b, peer);
 		cdr_all_relink(cdr);
 		CDR_DEBUG("%p - Updated Party B %s snapshot\n", cdr,
-			cdr->party_b.snapshot->name);
+			cdr->party_b.snapshot->base->name);
 
 		/* If we have two parties, lock the application that caused the
 		 * two parties to be associated. This prevents mid-call event
 		 * macros/gosubs from perturbing the CDR application/data
 		 */
 		ast_set_flag(&cdr->flags, AST_CDR_LOCK_APP);
-	} else if (!strcasecmp(cdr->party_a.snapshot->name, peer->name)) {
+	} else if (!strcasecmp(cdr->party_a.snapshot->base->name, peer->base->name)) {
 		/* We're the entity being dialed, i.e., outbound origination */
 		base_process_party_a(cdr, peer);
 		CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr,
-			cdr->party_a.snapshot->name);
+			cdr->party_a.snapshot->base->name);
 	}
 
 	cdr_object_transition_state(cdr, &dial_state_fn_table);
@@ -1680,15 +1680,15 @@ static int single_state_bridge_enter_comparison(struct cdr_object *cdr,
 	struct cdr_object_snapshot *party_a;
 
 	/* Don't match on ourselves */
-	if (!strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name)) {
+	if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
 		return 1;
 	}
 
 	/* Try the candidate CDR's Party A first */
 	party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
-	if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
+	if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
 		CDR_DEBUG("%p - Party A %s has new Party B %s\n",
-			cdr, cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name);
+			cdr, cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name);
 		cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
 		cdr_all_relink(cdr);
 		if (!cand_cdr->party_b.snapshot) {
@@ -1703,13 +1703,13 @@ static int single_state_bridge_enter_comparison(struct cdr_object *cdr,
 
 	/* Try their Party B, unless it's us */
 	if (!cand_cdr->party_b.snapshot
-		|| !strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name)) {
+		|| !strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_b.snapshot->base->name)) {
 		return 1;
 	}
 	party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_b);
-	if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
+	if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
 		CDR_DEBUG("%p - Party A %s has new Party B %s\n",
-			cdr, cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name);
+			cdr, cdr->party_a.snapshot->base->name, cand_cdr->party_b.snapshot->base->name);
 		cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_b);
 		cdr_all_relink(cdr);
 		return 0;
@@ -1788,7 +1788,7 @@ static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channe
 {
 	ast_assert(snapshot != NULL);
 	ast_assert(cdr->party_b.snapshot
-		&& !strcasecmp(cdr->party_b.snapshot->name, snapshot->name));
+		&& !strcasecmp(cdr->party_b.snapshot->base->name, snapshot->base->name));
 
 	cdr_object_swap_snapshot(&cdr->party_b, snapshot);
 
@@ -1839,11 +1839,11 @@ static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channe
 	} else {
 		party_a = peer;
 	}
-	ast_assert(!strcasecmp(cdr->party_a.snapshot->name, party_a->name));
+	ast_assert(!strcasecmp(cdr->party_a.snapshot->base->name, party_a->base->name));
 	cdr_object_swap_snapshot(&cdr->party_a, party_a);
 
 	if (cdr->party_b.snapshot) {
-		if (strcasecmp(cdr->party_b.snapshot->name, peer->name)) {
+		if (strcasecmp(cdr->party_b.snapshot->base->name, peer->base->name)) {
 			/* Not the status for this CDR - defer back to the message router */
 			return 1;
 		}
@@ -1901,7 +1901,7 @@ static enum process_bridge_enter_results dial_state_process_bridge_enter(struct
 				}
 
 				/* Skip any records that aren't our Party B */
-				if (strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name)) {
+				if (strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
 					continue;
 				}
 				cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
@@ -1982,7 +1982,7 @@ static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struc
 static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
 {
 	ast_assert(cdr->party_b.snapshot
-		&& !strcasecmp(cdr->party_b.snapshot->name, snapshot->name));
+		&& !strcasecmp(cdr->party_b.snapshot->base->name, snapshot->base->name));
 
 	cdr_object_swap_snapshot(&cdr->party_b, snapshot);
 
@@ -1997,9 +1997,9 @@ static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_
 	if (strcmp(cdr->bridge, bridge->uniqueid)) {
 		return 1;
 	}
-	if (strcasecmp(cdr->party_a.snapshot->name, channel->name)
+	if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)
 		&& cdr->party_b.snapshot
-		&& strcasecmp(cdr->party_b.snapshot->name, channel->name)) {
+		&& strcasecmp(cdr->party_b.snapshot->base->name, channel->base->name)) {
 		return 1;
 	}
 	cdr_object_transition_state(cdr, &finalized_state_fn_table);
@@ -2011,7 +2011,7 @@ static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_
 
 static int parked_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 {
-	if (strcasecmp(cdr->party_a.snapshot->name, channel->name)) {
+	if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)) {
 		return 1;
 	}
 	cdr_object_transition_state(cdr, &finalized_state_fn_table);
@@ -2043,7 +2043,7 @@ static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_ch
  */
 static int filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
 {
-	return snapshot->tech_properties & AST_CHAN_TP_INTERNAL;
+	return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
 }
 
 /*!
@@ -2114,19 +2114,19 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
 
 	CDR_DEBUG("Dial %s message for %s, %s: %u.%08u\n",
 		ast_strlen_zero(dial_status) ? "Begin" : "End",
-		caller ? caller->name : "(none)",
-		peer ? peer->name : "(none)",
+		caller ? caller->base->name : "(none)",
+		peer ? peer->base->name : "(none)",
 		(unsigned int)stasis_message_timestamp(message)->tv_sec,
 		(unsigned int)stasis_message_timestamp(message)->tv_usec);
 
 	/* Figure out who is running this show */
 	if (caller) {
-		cdr = ao2_find(active_cdrs_master, caller->uniqueid, OBJ_SEARCH_KEY);
+		cdr = ao2_find(active_cdrs_master, caller->base->uniqueid, OBJ_SEARCH_KEY);
 	} else {
-		cdr = ao2_find(active_cdrs_master, peer->uniqueid, OBJ_SEARCH_KEY);
+		cdr = ao2_find(active_cdrs_master, peer->base->uniqueid, OBJ_SEARCH_KEY);
 	}
 	if (!cdr) {
-		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->name : peer->name);
+		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->base->name : peer->base->name);
 		ast_assert(0);
 		return;
 	}
@@ -2139,8 +2139,8 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
 			}
 			CDR_DEBUG("%p - Processing Dial Begin message for channel %s, peer %s\n",
 				it_cdr,
-				caller ? caller->name : "(none)",
-				peer ? peer->name : "(none)");
+				caller ? caller->base->name : "(none)",
+				peer ? peer->base->name : "(none)");
 			res &= it_cdr->fn_table->process_dial_begin(it_cdr,
 					caller,
 					peer);
@@ -2150,8 +2150,8 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
 			}
 			CDR_DEBUG("%p - Processing Dial End message for channel %s, peer %s\n",
 				it_cdr,
-				caller ? caller->name : "(none)",
-				peer ? peer->name : "(none)");
+				caller ? caller->base->name : "(none)",
+				peer ? peer->base->name : "(none)");
 			it_cdr->fn_table->process_dial_end(it_cdr,
 					caller,
 					peer,
@@ -2185,7 +2185,7 @@ static int cdr_object_finalize_party_b(void *obj, void *arg, void *data, int fla
 		 * is consistent with the key.
 		 */
 		ast_assert(cdr->party_b.snapshot
-			&& !strcasecmp(cdr->party_b.snapshot->name, party_b->name));
+			&& !strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name));
 #endif
 
 		/* Don't transition to the finalized state - let the Party A do
@@ -2210,11 +2210,11 @@ static int cdr_object_update_party_b(void *obj, void *arg, void *data, int flags
 		 * asserts the snapshot to be this way.
 		 */
 		if (!cdr->party_b.snapshot
-			|| strcasecmp(cdr->party_b.snapshot->name, party_b->name)) {
+			|| strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name)) {
 			ast_log(LOG_NOTICE,
 				"CDR for Party A %s(%s) has inconsistent Party B %s name.  Message can be ignored but this shouldn't happen.\n",
 				cdr->linkedid,
-				cdr->party_a.snapshot->name,
+				cdr->party_a.snapshot->base->name,
 				cdr->party_b_name);
 			return 0;
 		}
@@ -2236,7 +2236,7 @@ static int check_new_cdr_needed(struct ast_channel_snapshot *old_snapshot,
 	}
 
 	/* Auto-fall through will increment the priority but have no application */
-	if (ast_strlen_zero(new_snapshot->appl)) {
+	if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
 		return 0;
 	}
 
@@ -2272,12 +2272,12 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
 		cdr->is_root = 1;
 		ao2_link(active_cdrs_master, cdr);
 	} else {
-		cdr = ao2_find(active_cdrs_master, update->new_snapshot->uniqueid, OBJ_SEARCH_KEY);
+		cdr = ao2_find(active_cdrs_master, update->new_snapshot->base->uniqueid, OBJ_SEARCH_KEY);
 	}
 
 	/* Handle Party A */
 	if (!cdr) {
-		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", update->new_snapshot->name);
+		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", update->new_snapshot->base->name);
 		ast_assert(0);
 	} else {
 		int all_reject = 1;
@@ -2303,7 +2303,7 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
 
 	if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
 		ao2_lock(cdr);
-		CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, update->old_snapshot->name);
+		CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, update->old_snapshot->base->name);
 		for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
 			cdr_object_finalize(it_cdr);
 		}
@@ -2317,12 +2317,12 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
 	/* Handle Party B */
 	if (update->new_snapshot) {
 		ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,
-			cdr_object_update_party_b, (char *) update->new_snapshot->name, update->new_snapshot);
+			cdr_object_update_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
 	}
 
 	if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
 		ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,
-			cdr_object_finalize_party_b, (char *) update->new_snapshot->name, update->new_snapshot);
+			cdr_object_finalize_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
 	}
 
 	ao2_cleanup(cdr);
@@ -2347,7 +2347,7 @@ static int cdr_object_party_b_left_bridge_cb(void *obj, void *arg, void *data, i
 		 * is consistent with the key.
 		 */
 		ast_assert(cdr->party_b.snapshot
-			&& !strcasecmp(cdr->party_b.snapshot->name, leave_data->channel->name));
+			&& !strcasecmp(cdr->party_b.snapshot->base->name, leave_data->channel->base->name));
 
 		/* It is our Party B, in our bridge. Set the end time and let the handler
 		 * transition our CDR appropriately when we leave the bridge.
@@ -2399,13 +2399,13 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
 	}
 
 	CDR_DEBUG("Bridge Leave message for %s: %u.%08u\n",
-		channel->name,
+		channel->base->name,
 		(unsigned int)stasis_message_timestamp(message)->tv_sec,
 		(unsigned int)stasis_message_timestamp(message)->tv_usec);
 
-	cdr = ao2_find(active_cdrs_master, channel->uniqueid, OBJ_SEARCH_KEY);
+	cdr = ao2_find(active_cdrs_master, channel->base->uniqueid, OBJ_SEARCH_KEY);
 	if (!cdr) {
-		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
+		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
 		ast_assert(0);
 		return;
 	}
@@ -2417,7 +2417,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
 			continue;
 		}
 		CDR_DEBUG("%p - Processing Bridge Leave for %s\n",
-			it_cdr, channel->name);
+			it_cdr, channel->base->name);
 		if (!it_cdr->fn_table->process_bridge_leave(it_cdr, bridge, channel)) {
 			ast_string_field_set(it_cdr, bridge, "");
 			left_bridge = 1;
@@ -2429,7 +2429,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
 	if (left_bridge
 		&& strcmp(bridge->subclass, "parking")) {
 		ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,
-			cdr_object_party_b_left_bridge_cb, (char *) leave_data.channel->name,
+			cdr_object_party_b_left_bridge_cb, (char *) leave_data.channel->base->name,
 			&leave_data);
 	}
 
@@ -2457,8 +2457,8 @@ static void bridge_candidate_add_to_cdr(struct cdr_object *cdr,
 	ast_string_field_set(new_cdr, bridge, cdr->bridge);
 	cdr_object_transition_state(new_cdr, &bridge_state_fn_table);
 	CDR_DEBUG("%p - Party A %s has new Party B %s\n",
-		new_cdr, new_cdr->party_a.snapshot->name,
-		party_b->snapshot->name);
+		new_cdr, new_cdr->party_a.snapshot->base->name,
+		party_b->snapshot->base->name);
 }
 
 /*!
@@ -2487,16 +2487,16 @@ static void bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *
 		}
 
 		/* If the candidate is us or someone we've taken on, pass on by */
-		if (!strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name)
+		if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)
 			|| (cdr->party_b.snapshot
-				&& !strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name))) {
+				&& !strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name))) {
 			break;
 		}
 
 		party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
 		/* We're party A - make a new CDR, append it to us, and set the candidate as
 		 * Party B */
-		if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
+		if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
 			bridge_candidate_add_to_cdr(cdr, &cand_cdr->party_a);
 			break;
 		}
@@ -2504,12 +2504,12 @@ static void bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *
 		/* We're Party B. Check if we can add ourselves immediately or if we need
 		 * a new CDR for them (they already have a Party B) */
 		if (cand_cdr->party_b.snapshot
-			&& strcasecmp(cand_cdr->party_b.snapshot->name, cdr->party_a.snapshot->name)) {
+			&& strcasecmp(cand_cdr->party_b.snapshot->base->name, cdr->party_a.snapshot->base->name)) {
 			bridge_candidate_add_to_cdr(cand_cdr, &cdr->party_a);
 		} else {
 			CDR_DEBUG("%p - Party A %s has new Party B %s\n",
-				cand_cdr, cand_cdr->party_a.snapshot->name,
-				cdr->party_a.snapshot->name);
+				cand_cdr, cand_cdr->party_a.snapshot->base->name,
+				cdr->party_a.snapshot->base->name);
 			cdr_object_snapshot_copy(&cand_cdr->party_b, &cdr->party_a);
 			cdr_all_relink(cand_cdr);
 			/* It's possible that this joined at one point and was never chosen
@@ -2572,7 +2572,7 @@ static void handle_parking_bridge_enter_message(struct cdr_object *cdr,
 		}
 		if (it_cdr->fn_table->process_party_a) {
 			CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
-				channel->name);
+				channel->base->name);
 			it_cdr->fn_table->process_party_a(it_cdr, channel);
 		}
 	}
@@ -2609,14 +2609,14 @@ try_again:
 	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
 		if (it_cdr->fn_table->process_party_a) {
 			CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
-				channel->name);
+				channel->base->name);
 			it_cdr->fn_table->process_party_a(it_cdr, channel);
 		}
 
 		/* Notify all states that they have entered a bridge */
 		if (it_cdr->fn_table->process_bridge_enter) {
 			CDR_DEBUG("%p - Processing bridge enter for %s\n", it_cdr,
-				channel->name);
+				channel->base->name);
 			result = it_cdr->fn_table->process_bridge_enter(it_cdr, bridge, channel);
 			switch (result) {
 			case BRIDGE_ENTER_ONLY_PARTY:
@@ -2689,13 +2689,13 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription *
 	}
 
 	CDR_DEBUG("Bridge Enter message for channel %s: %u.%08u\n",
-		channel->name,
+		channel->base->name,
 		(unsigned int)stasis_message_timestamp(message)->tv_sec,
 		(unsigned int)stasis_message_timestamp(message)->tv_usec);
 
-	cdr = ao2_find(active_cdrs_master, channel->uniqueid, OBJ_SEARCH_KEY);
+	cdr = ao2_find(active_cdrs_master, channel->base->uniqueid, OBJ_SEARCH_KEY);
 	if (!cdr) {
-		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
+		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
 		ast_assert(0);
 		return;
 	}
@@ -2739,13 +2739,13 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s
 	}
 
 	CDR_DEBUG("Parked Call message for channel %s: %u.%08u\n",
-		channel->name,
+		channel->base->name,
 		(unsigned int)stasis_message_timestamp(message)->tv_sec,
 		(unsigned int)stasis_message_timestamp(message)->tv_usec);
 
-	cdr = ao2_find(active_cdrs_master, channel->uniqueid, OBJ_SEARCH_KEY);
+	cdr = ao2_find(active_cdrs_master, channel->base->uniqueid, OBJ_SEARCH_KEY);
 	if (!cdr) {
-		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
+		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
 		ast_assert(0);
 		return;
 	}
@@ -3094,8 +3094,8 @@ static int cdr_object_select_all_by_name_cb(void *obj, void *arg, int flags)
 	struct cdr_object *cdr = obj;
 	const char *name = arg;
 
-	if (!strcasecmp(cdr->party_a.snapshot->name, name) ||
-			(cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->name, name))) {
+	if (!strcasecmp(cdr->party_a.snapshot->base->name, name) ||
+			(cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->base->name, name))) {
 		return CMP_MATCH;
 	}
 	return 0;
@@ -3110,7 +3110,7 @@ static int cdr_object_get_by_name_cb(void *obj, void *arg, int flags)
 	struct cdr_object *cdr = obj;
 	const char *name = arg;
 
-	if (!strcasecmp(cdr->party_a.snapshot->name, name)) {
+	if (!strcasecmp(cdr->party_a.snapshot->base->name, name)) {
 		return CMP_MATCH;
 	}
 	return 0;
@@ -3170,10 +3170,10 @@ int ast_cdr_setvar(const char *channel_name, const char *name, const char *value
 			if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
 				continue;
 			}
-			if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->name)) {
+			if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->base->name)) {
 				headp = &it_cdr->party_a.variables;
 			} else if (it_cdr->party_b.snapshot
-				&& !strcasecmp(channel_name, it_cdr->party_b.snapshot->name)) {
+				&& !strcasecmp(channel_name, it_cdr->party_b.snapshot->base->name)) {
 				headp = &it_cdr->party_b.variables;
 			}
 			if (headp) {
@@ -3212,25 +3212,25 @@ static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *na
 	struct ast_channel_snapshot *party_b = cdr_obj->party_b.snapshot;
 
 	if (!strcasecmp(name, "clid")) {
-		ast_callerid_merge(value, length, party_a->caller_name, party_a->caller_number, "");
+		ast_callerid_merge(value, length, party_a->caller->name, party_a->caller->number, "");
 	} else if (!strcasecmp(name, "src")) {
-		ast_copy_string(value, party_a->caller_number, length);
+		ast_copy_string(value, party_a->caller->number, length);
 	} else if (!strcasecmp(name, "dst")) {
-		ast_copy_string(value, party_a->exten, length);
+		ast_copy_string(value, party_a->dialplan->exten, length);
 	} else if (!strcasecmp(name, "dcontext")) {
-		ast_copy_string(value, party_a->context, length);
+		ast_copy_string(value, party_a->dialplan->context, length);
 	} else if (!strcasecmp(name, "channel")) {
-		ast_copy_string(value, party_a->name, length);
+		ast_copy_string(value, party_a->base->name, length);
 	} else if (!strcasecmp(name, "dstchannel")) {
 		if (party_b) {
-			ast_copy_string(value, party_b->name, length);
+			ast_copy_string(value, party_b->base->name, length);
 		} else {
 			ast_copy_string(value, "", length);
 		}
 	} else if (!strcasecmp(name, "lastapp")) {
-		ast_copy_string(value, party_a->appl, length);
+		ast_copy_string(value, party_a->dialplan->appl, length);
 	} else if (!strcasecmp(name, "lastdata")) {
-		ast_copy_string(value, party_a->data, length);
+		ast_copy_string(value, party_a->dialplan->data, length);
 	} else if (!strcasecmp(name, "start")) {
 		cdr_get_tv(cdr_obj->start, NULL, value, length);
 	} else if (!strcasecmp(name, "answer")) {
@@ -3246,15 +3246,15 @@ static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *na
 	} else if (!strcasecmp(name, "amaflags")) {
 		snprintf(value, length, "%d", party_a->amaflags);
 	} else if (!strcasecmp(name, "accountcode")) {
-		ast_copy_string(value, party_a->accountcode, length);
+		ast_copy_string(value, party_a->base->accountcode, length);
 	} else if (!strcasecmp(name, "peeraccount")) {
 		if (party_b) {
-			ast_copy_string(value, party_b->accountcode, length);
+			ast_copy_string(value, party_b->base->accountcode, length);
 		} else {
 			ast_copy_string(value, "", length);
 		}
 	} else if (!strcasecmp(name, "uniqueid")) {
-		ast_copy_string(value, party_a->uniqueid, length);
+		ast_copy_string(value, party_a->base->uniqueid, length);
 	} else if (!strcasecmp(name, "linkedid")) {
 		ast_copy_string(value, cdr_obj->linkedid, length);
 	} else if (!strcasecmp(name, "userfield")) {
@@ -3431,7 +3431,7 @@ static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, void *da
 		 * is consistent with the key.
 		 */
 		ast_assert(cdr->party_b.snapshot
-			&& !strcasecmp(cdr->party_b.snapshot->name, info->channel_name));
+			&& !strcasecmp(cdr->party_b.snapshot->base->name, info->channel_name));
 
 		ast_copy_string(cdr->party_b.userfield, info->userfield,
 			sizeof(cdr->party_b.userfield));
@@ -3624,7 +3624,7 @@ int ast_cdr_fork(const char *channel_name, struct ast_flags *options)
 		/* Copy over the basic CDR information. The Party A information is
 		 * copied over automatically as part of the append
 		 */
-		ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->name);
+		ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->base->name);
 		new_cdr = cdr_object_create_and_append(cdr);
 		if (!new_cdr) {
 			return -1;
@@ -3938,8 +3938,8 @@ static char *cli_complete_show(struct ast_cli_args *a)
 
 	it_cdrs = ao2_iterator_init(active_cdrs_master, 0);
 	while ((cdr = ao2_iterator_next(&it_cdrs))) {
-		if (!strncasecmp(a->word, cdr->party_a.snapshot->name, wordlen)) {
-			if (ast_cli_completion_add(ast_strdup(cdr->party_a.snapshot->name))) {
+		if (!strncasecmp(a->word, cdr->party_a.snapshot->base->name, wordlen)) {
+			if (ast_cli_completion_add(ast_strdup(cdr->party_a.snapshot->base->name))) {
 				ao2_ref(cdr, -1);
 				break;
 			}
@@ -4001,8 +4001,8 @@ static void cli_show_channels(struct ast_cli_args *a)
 		cdr_get_tv(start_time, "%T", start_time_buffer, sizeof(start_time_buffer));
 		cdr_get_tv(answer_time, "%T", answer_time_buffer, sizeof(answer_time_buffer));
 		cdr_get_tv(end_time, "%T", end_time_buffer, sizeof(end_time_buffer));
-		ast_cli(a->fd, FORMAT_STRING, it_cdr->party_a.snapshot->name,
-				it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<none>",
+		ast_cli(a->fd, FORMAT_STRING, it_cdr->party_a.snapshot->base->name,
+				it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
 				it_cdr->appl,
 				start_time_buffer,
 				answer_time_buffer,
@@ -4046,7 +4046,7 @@ static void cli_show_channel(struct ast_cli_args *a)
 		if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
 			continue;
 		}
-		ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller_name, it_cdr->party_a.snapshot->caller_number, "");
+		ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller->name, it_cdr->party_a.snapshot->caller->number, "");
 		if (ast_tvzero(it_cdr->end)) {
 			end = ast_tvnow();
 		} else {
@@ -4056,9 +4056,9 @@ static void cli_show_channel(struct ast_cli_args *a)
 		cdr_get_tv(it_cdr->answer, "%T", answer_time_buffer, sizeof(answer_time_buffer));
 		cdr_get_tv(end, "%T", end_time_buffer, sizeof(end_time_buffer));
 		ast_cli(a->fd, FORMAT_STRING,
-				it_cdr->party_a.snapshot->accountcode,
+				it_cdr->party_a.snapshot->base->accountcode,
 				clid,
-				it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<none>",
+				it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
 				it_cdr->appl,
 				it_cdr->data,
 				start_time_buffer,
@@ -4415,8 +4415,8 @@ static void cdr_master_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
 	}
 	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
 		prnt(where, "Party A: %s; Party B: %s; Bridge %s\n",
-			it_cdr->party_a.snapshot->name,
-			it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<unknown>",
+			it_cdr->party_a.snapshot->base->name,
+			it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<unknown>",
 			it_cdr->bridge);
 	}
 }
@@ -4440,8 +4440,8 @@ static void cdr_all_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
 		return;
 	}
 	prnt(where, "Party A: %s; Party B: %s; Bridge %s",
-		cdr->party_a.snapshot->name,
-		cdr->party_b.snapshot ? cdr->party_b.snapshot->name : "<unknown>",
+		cdr->party_a.snapshot->base->name,
+		cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<unknown>",
 		cdr->bridge);
 }
 
diff --git a/main/cel.c b/main/cel.c
index 97e35adf55abe7af094ceb74f4a40c61db80c868..242aeffa6be8a50cb94b291555cfd3a739a0460f 100644
--- a/main/cel.c
+++ b/main/cel.c
@@ -528,22 +528,22 @@ struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
 		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, S_OR(userdefevname, ""),
-		AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_name,
-		AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_number,
-		AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_ani,
-		AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_rdnis,
-		AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_dnid,
-		AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, snapshot->exten,
-		AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, snapshot->context,
-		AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->name,
-		AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->appl,
-		AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, snapshot->data,
+		AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->name,
+		AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->number,
+		AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->ani,
+		AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->rdnis,
+		AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->dnid,
+		AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, snapshot->dialplan->exten,
+		AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, snapshot->dialplan->context,
+		AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->base->name,
+		AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->dialplan->appl,
+		AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, snapshot->dialplan->data,
 		AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, snapshot->amaflags,
-		AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, snapshot->accountcode,
-		AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, snapshot->peeraccount,
-		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_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, snapshot->base->accountcode,
+		AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, snapshot->peer->account,
+		AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, snapshot->base->uniqueid,
+		AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, snapshot->peer->linkedid,
+		AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, snapshot->base->userfield,
 		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, ""),
 		AST_EVENT_IE_END);
@@ -573,7 +573,7 @@ static int cel_report_event(struct ast_channel_snapshot *snapshot,
 	 * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
 	if (event_type == AST_CEL_CHANNEL_START
 		&& ast_cel_track_event(AST_CEL_LINKEDID_END)) {
-		if (cel_linkedid_ref(snapshot->linkedid)) {
+		if (cel_linkedid_ref(snapshot->peer->linkedid)) {
 			return -1;
 		}
 	}
@@ -583,7 +583,7 @@ static int cel_report_event(struct ast_channel_snapshot *snapshot,
 	}
 
 	if ((event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END)
-		&& !cel_track_app(snapshot->appl)) {
+		&& !cel_track_app(snapshot->dialplan->appl)) {
 		return 0;
 	}
 
@@ -606,14 +606,14 @@ static void check_retire_linkedid(struct ast_channel_snapshot *snapshot)
 	RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
 	struct cel_linkedid *lid;
 
-	if (!linkedids || ast_strlen_zero(snapshot->linkedid)) {
+	if (!linkedids || ast_strlen_zero(snapshot->peer->linkedid)) {
 		/* The CEL module is shutdown.  Abort. */
 		return;
 	}
 
 	ao2_lock(linkedids);
 
-	lid = ao2_find(linkedids, (void *) snapshot->linkedid, OBJ_SEARCH_KEY);
+	lid = ao2_find(linkedids, (void *) snapshot->peer->linkedid, OBJ_SEARCH_KEY);
 	if (!lid) {
 		ao2_unlock(linkedids);
 
@@ -623,7 +623,7 @@ static void check_retire_linkedid(struct ast_channel_snapshot *snapshot)
 		 * of change to make after starting Asterisk.
 		 */
 		ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n",
-			snapshot->linkedid);
+			snapshot->peer->linkedid);
 		return;
 	}
 
@@ -898,11 +898,11 @@ static void cel_channel_state_change(
 
 	if (!was_hungup && is_hungup) {
 		struct ast_json *extra;
-		struct cel_dialstatus *dialstatus = get_dialstatus(new_snapshot->uniqueid);
+		struct cel_dialstatus *dialstatus = get_dialstatus(new_snapshot->base->uniqueid);
 
 		extra = ast_json_pack("{s: i, s: s, s: s}",
-			"hangupcause", new_snapshot->hangupcause,
-			"hangupsource", new_snapshot->hangupsource,
+			"hangupcause", new_snapshot->hangup->cause,
+			"hangupsource", new_snapshot->hangup->source,
 			"dialstatus", dialstatus ? dialstatus->dialstatus : "");
 		cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL);
 		ast_json_unref(extra);
@@ -929,12 +929,12 @@ static void cel_channel_linkedid_change(
 		return;
 	}
 
-	ast_assert(!ast_strlen_zero(new_snapshot->linkedid));
-	ast_assert(!ast_strlen_zero(old_snapshot->linkedid));
+	ast_assert(!ast_strlen_zero(new_snapshot->peer->linkedid));
+	ast_assert(!ast_strlen_zero(old_snapshot->peer->linkedid));
 
 	if (ast_cel_track_event(AST_CEL_LINKEDID_END)
-		&& strcmp(old_snapshot->linkedid, new_snapshot->linkedid)) {
-		cel_linkedid_ref(new_snapshot->linkedid);
+		&& strcmp(old_snapshot->peer->linkedid, new_snapshot->peer->linkedid)) {
+		cel_linkedid_ref(new_snapshot->peer->linkedid);
 		check_retire_linkedid(old_snapshot);
 	}
 }
@@ -943,17 +943,17 @@ static void cel_channel_app_change(
 	struct ast_channel_snapshot *old_snapshot,
 	struct ast_channel_snapshot *new_snapshot)
 {
-	if (old_snapshot && !strcmp(old_snapshot->appl, new_snapshot->appl)) {
+	if (old_snapshot && !strcmp(old_snapshot->dialplan->appl, new_snapshot->dialplan->appl)) {
 		return;
 	}
 
 	/* old snapshot has an application, end it */
-	if (old_snapshot && !ast_strlen_zero(old_snapshot->appl)) {
+	if (old_snapshot && !ast_strlen_zero(old_snapshot->dialplan->appl)) {
 		cel_report_event(old_snapshot, AST_CEL_APP_END, NULL, NULL, NULL);
 	}
 
 	/* new snapshot has an application, start it */
-	if (!ast_strlen_zero(new_snapshot->appl)) {
+	if (!ast_strlen_zero(new_snapshot->dialplan->appl)) {
 		cel_report_event(new_snapshot, AST_CEL_APP_START, NULL, NULL, NULL);
 	}
 }
@@ -974,7 +974,7 @@ static int cel_filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
 	if (!snapshot) {
 		return 0;
 	}
-	return snapshot->tech_properties & AST_CHAN_TP_INTERNAL;
+	return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
 }
 
 static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub,
@@ -1010,7 +1010,7 @@ static struct ast_str *cel_generate_peer_str(
 		struct ast_channel_snapshot *current_snapshot;
 
 		/* Don't add the channel for which this message is being generated */
-		if (!strcmp(current_chan, chan->uniqueid)) {
+		if (!strcmp(current_chan, chan->base->uniqueid)) {
 			continue;
 		}
 
@@ -1019,7 +1019,7 @@ static struct ast_str *cel_generate_peer_str(
 			continue;
 		}
 
-		ast_str_append(&peer_str, 0, "%s,", current_snapshot->name);
+		ast_str_append(&peer_str, 0, "%s,", current_snapshot->base->name);
 		ao2_cleanup(current_snapshot);
 	}
 	ao2_iterator_destroy(&i);
@@ -1125,7 +1125,7 @@ static void cel_parking_cb(
 	if (parked_payload->retriever) {
 		extra = ast_json_pack("{s: s, s: s}",
 			"reason", reason ?: "",
-			"retriever", parked_payload->retriever->name);
+			"retriever", parked_payload->retriever->base->name);
 	} else {
 		extra = ast_json_pack("{s: s}", "reason", reason ?: "");
 	}
@@ -1147,7 +1147,7 @@ static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_chan
 		return;
 	}
 
-	dialstatus = ao2_find(dial_statuses, snapshot->uniqueid, OBJ_SEARCH_KEY);
+	dialstatus = ao2_find(dial_statuses, snapshot->base->uniqueid, OBJ_SEARCH_KEY);
 	if (dialstatus) {
 		if (!strcasecmp(dialstatus_string, "ANSWER") && strcasecmp(dialstatus->dialstatus, "ANSWER")) {
 			/* In the case of an answer after we already have a dial status we give
@@ -1171,7 +1171,7 @@ static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_chan
 		return;
 	}
 
-	ast_copy_string(dialstatus->uniqueid, snapshot->uniqueid, sizeof(dialstatus->uniqueid));
+	ast_copy_string(dialstatus->uniqueid, snapshot->base->uniqueid, sizeof(dialstatus->uniqueid));
 	ast_copy_string(dialstatus->dialstatus, dialstatus_string, dialstatus_string_len);
 
 	ao2_link(dial_statuses, dialstatus);
@@ -1273,8 +1273,8 @@ static void cel_blind_transfer_cb(
 		"extension", transfer_msg->exten,
 		"context", transfer_msg->context,
 		"bridge_id", bridge_snapshot->uniqueid,
-		"transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->name : "N/A",
-		"transferee_channel_uniqueid", transfer_msg->transferee ? transfer_msg->transferee->uniqueid  : "N/A");
+		"transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->base->name : "N/A",
+		"transferee_channel_uniqueid", transfer_msg->transferee ? transfer_msg->transferee->base->uniqueid  : "N/A");
 	if (extra) {
 		cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, NULL, extra, NULL);
 		ast_json_unref(extra);
@@ -1312,13 +1312,13 @@ static void cel_attended_transfer_cb(
 	case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
 		extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
 			"bridge1_id", bridge1->uniqueid,
-			"channel2_name", channel2->name,
-			"channel2_uniqueid", channel2->uniqueid,
+			"channel2_name", channel2->base->name,
+			"channel2_uniqueid", channel2->base->uniqueid,
 			"bridge2_id", bridge2->uniqueid,
-			"transferee_channel_name", xfer->transferee ? xfer->transferee->name : "N/A",
-			"transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->uniqueid : "N/A",
-			"transfer_target_channel_name", xfer->target ? xfer->target->name : "N/A",
-			"transfer_target_channel_uniqueid", xfer->target ? xfer->target->uniqueid : "N/A");
+			"transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
+			"transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
+			"transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
+			"transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
 		if (!extra) {
 			return;
 		}
@@ -1327,13 +1327,13 @@ static void cel_attended_transfer_cb(
 	case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
 		extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
 			"bridge1_id", bridge1->uniqueid,
-			"channel2_name", channel2->name,
-			"channel2_uniqueid", channel2->uniqueid,
+			"channel2_name", channel2->base->name,
+			"channel2_uniqueid", channel2->base->uniqueid,
 			"app", xfer->dest.app,
-			"transferee_channel_name", xfer->transferee ? xfer->transferee->name : "N/A",
-			"transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->uniqueid : "N/A",
-			"transfer_target_channel_name", xfer->target ? xfer->target->name : "N/A",
-			"transfer_target_channel_uniqueid", xfer->target ? xfer->target->uniqueid : "N/A");
+			"transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
+			"transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
+			"transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
+			"transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
 		if (!extra) {
 			return;
 		}
@@ -1357,8 +1357,8 @@ static void cel_pickup_cb(
 	}
 
 	extra = ast_json_pack("{s: s, s: s}",
-		"pickup_channel", channel->name,
-		"pickup_channel_uniqueid", channel->uniqueid);
+		"pickup_channel", channel->base->name,
+		"pickup_channel_uniqueid", channel->base->uniqueid);
 	if (!extra) {
 		return;
 	}
@@ -1381,8 +1381,8 @@ static void cel_local_cb(
 	}
 
 	extra = ast_json_pack("{s: s, s: s}",
-		"local_two", localtwo->name,
-		"local_two_uniqueid", localtwo->uniqueid);
+		"local_two", localtwo->base->name,
+		"local_two_uniqueid", localtwo->base->uniqueid);
 	if (!extra) {
 		return;
 	}
diff --git a/main/channel.c b/main/channel.c
index 3d8e244fd8c2228fdd94833f08d93d53d1990f0a..7e12f304923f337917fd16141380c4fef185e1f2 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -6761,6 +6761,12 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
 		ast_channel_name(clonechan), ast_channel_state(clonechan),
 		ast_channel_name(original), ast_channel_state(original));
 
+	/* When all is said and done force new snapshot segments so they are
+	 * up to date.
+	 */
+	ast_set_flag(ast_channel_snapshot_segment_flags(original), AST_FLAGS_ALL);
+	ast_set_flag(ast_channel_snapshot_segment_flags(clonechan), AST_FLAGS_ALL);
+
 	/*
 	 * Remember the original read/write formats.  We turn off any
 	 * translation on either one
@@ -7183,6 +7189,7 @@ void ast_channel_set_caller(struct ast_channel *chan, const struct ast_party_cal
 
 	ast_channel_lock(chan);
 	ast_party_caller_set(ast_channel_caller(chan), caller, update);
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
 	ast_channel_unlock(chan);
 }
 
@@ -7195,6 +7202,7 @@ void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_par
 
 	ast_channel_lock(chan);
 	ast_party_caller_set(ast_channel_caller(chan), caller, update);
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
 	ast_channel_publish_snapshot(chan);
 	ast_channel_unlock(chan);
 }
@@ -8120,6 +8128,7 @@ void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_p
 
 	ast_channel_lock(chan);
 	ast_party_connected_line_set(ast_channel_connected(chan), connected, update);
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CONNECTED);
 	ast_channel_publish_snapshot(chan);
 	ast_channel_unlock(chan);
 }
@@ -8930,6 +8939,7 @@ void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_part
 
 	ast_channel_lock(chan);
 	ast_party_redirecting_set(ast_channel_redirecting(chan), redirecting, update);
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
 	ast_channel_unlock(chan);
 }
 
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c
index 436ba23034700b9aff2cacc277dd9eeb66031042..30d39097e0a7dde03839f9c1db9a14844289ca31 100644
--- a/main/channel_internal_api.c
+++ b/main/channel_internal_api.c
@@ -221,6 +221,7 @@ struct ast_channel {
 	void *stream_topology_change_source; /*!< Source that initiated a stream topology change */
 	struct ast_stream *default_streams[AST_MEDIA_TYPE_END]; /*!< Default streams indexed by media type */
 	struct ast_channel_snapshot *snapshot; /*!< The current up to date snapshot of the channel */
+	struct ast_flags snapshot_segment_flags; /*!< Flags regarding the segments of the snapshot */
 };
 
 /*! \brief The monotonically increasing integer counter for channel uniqueids */
@@ -228,18 +229,40 @@ static int uniqueint;
 
 /* ACCESSORS */
 
-#define DEFINE_STRINGFIELD_SETTERS_FOR(field, publish, assert_on_null) \
+#define DEFINE_STRINGFIELD_SETTERS_FOR(field, assert_on_null) \
 void ast_channel_##field##_set(struct ast_channel *chan, const char *value) \
 { \
 	if ((assert_on_null)) ast_assert(!ast_strlen_zero(value)); \
 	if (!strcmp(value, chan->field)) return; \
 	ast_string_field_set(chan, field, value); \
+} \
+  \
+void ast_channel_##field##_build_va(struct ast_channel *chan, const char *fmt, va_list ap) \
+{ \
+	ast_string_field_build_va(chan, field, fmt, ap); \
+} \
+void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...) \
+{ \
+	va_list ap; \
+	va_start(ap, fmt); \
+	ast_channel_##field##_build_va(chan, fmt, ap); \
+	va_end(ap); \
+}
+
+#define DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(field, publish, assert_on_null, invalidate) \
+void ast_channel_##field##_set(struct ast_channel *chan, const char *value) \
+{ \
+	if ((assert_on_null)) ast_assert(!ast_strlen_zero(value)); \
+	if (!strcmp(value, chan->field)) return; \
+	ast_string_field_set(chan, field, value); \
+	ast_channel_snapshot_invalidate_segment(chan, invalidate); \
 	if (publish && ast_channel_internal_is_finalized(chan)) ast_channel_publish_snapshot(chan); \
 } \
   \
 void ast_channel_##field##_build_va(struct ast_channel *chan, const char *fmt, va_list ap) \
 { \
 	ast_string_field_build_va(chan, field, fmt, ap); \
+	ast_channel_snapshot_invalidate_segment(chan, invalidate); \
 	if (publish && ast_channel_internal_is_finalized(chan)) ast_channel_publish_snapshot(chan); \
 } \
 void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...) \
@@ -250,17 +273,17 @@ void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...)
 	va_end(ap); \
 }
 
-DEFINE_STRINGFIELD_SETTERS_FOR(name, 0, 1);
-DEFINE_STRINGFIELD_SETTERS_FOR(language, 1, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(musicclass, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(latest_musicclass, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(accountcode, 1, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(peeraccount, 1, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(userfield, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(call_forward, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(parkinglot, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(hangupsource, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(dialcontext, 0, 0);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(name, 0, 1, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(language, 1, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+DEFINE_STRINGFIELD_SETTERS_FOR(musicclass, 0);
+DEFINE_STRINGFIELD_SETTERS_FOR(latest_musicclass, 0);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(accountcode, 1, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(peeraccount, 1, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(userfield, 0, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+DEFINE_STRINGFIELD_SETTERS_FOR(call_forward, 0);
+DEFINE_STRINGFIELD_SETTERS_FOR(parkinglot, 0);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(hangupsource, 0, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP);
+DEFINE_STRINGFIELD_SETTERS_FOR(dialcontext, 0);
 
 #define DEFINE_STRINGFIELD_GETTER_FOR(field) const char *ast_channel_##field(const struct ast_channel *chan) \
 { \
@@ -298,6 +321,7 @@ const char *ast_channel_appl(const struct ast_channel *chan)
 void ast_channel_appl_set(struct ast_channel *chan, const char *value)
 {
 	chan->appl = value;
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 const char *ast_channel_blockproc(const struct ast_channel *chan)
 {
@@ -314,6 +338,7 @@ const char *ast_channel_data(const struct ast_channel *chan)
 void ast_channel_data_set(struct ast_channel *chan, const char *value)
 {
 	chan->data = value;
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 
 const char *ast_channel_context(const struct ast_channel *chan)
@@ -323,6 +348,7 @@ const char *ast_channel_context(const struct ast_channel *chan)
 void ast_channel_context_set(struct ast_channel *chan, const char *value)
 {
 	ast_copy_string(chan->context, value, sizeof(chan->context));
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 const char *ast_channel_exten(const struct ast_channel *chan)
 {
@@ -331,6 +357,7 @@ const char *ast_channel_exten(const struct ast_channel *chan)
 void ast_channel_exten_set(struct ast_channel *chan, const char *value)
 {
 	ast_copy_string(chan->exten, value, sizeof(chan->exten));
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 const char *ast_channel_macrocontext(const struct ast_channel *chan)
 {
@@ -404,6 +431,7 @@ int ast_channel_hangupcause(const struct ast_channel *chan)
 void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
 {
 	chan->hangupcause = value;
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP);
 }
 int ast_channel_macropriority(const struct ast_channel *chan)
 {
@@ -420,6 +448,7 @@ int ast_channel_priority(const struct ast_channel *chan)
 void ast_channel_priority_set(struct ast_channel *chan, int value)
 {
 	chan->priority = value;
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 int ast_channel_rings(const struct ast_channel *chan)
 {
@@ -909,18 +938,22 @@ void ast_channel_jb_set(struct ast_channel *chan, struct ast_jb *value)
 void ast_channel_caller_set(struct ast_channel *chan, struct ast_party_caller *value)
 {
 	chan->caller = *value;
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
 }
 void ast_channel_connected_set(struct ast_channel *chan, struct ast_party_connected_line *value)
 {
 	chan->connected = *value;
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CONNECTED);
 }
 void ast_channel_dialed_set(struct ast_channel *chan, struct ast_party_dialed *value)
 {
 	chan->dialed = *value;
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
 }
 void ast_channel_redirecting_set(struct ast_channel *chan, struct ast_party_redirecting *value)
 {
 	chan->redirecting = *value;
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
 }
 void ast_channel_dtmf_tv_set(struct ast_channel *chan, struct timeval *value)
 {
@@ -941,6 +974,7 @@ struct timeval ast_channel_creationtime(struct ast_channel *chan)
 void ast_channel_creationtime_set(struct ast_channel *chan, struct timeval *value)
 {
 	chan->creationtime = *value;
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
 }
 
 struct timeval ast_channel_answertime(struct ast_channel *chan)
@@ -1204,6 +1238,7 @@ struct ast_bridge *ast_channel_internal_bridge(const struct ast_channel *chan)
 void ast_channel_internal_bridge_set(struct ast_channel *chan, struct ast_bridge *value)
 {
 	chan->bridge = value;
+	ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_BRIDGE);
 	ast_channel_publish_snapshot(chan);
 }
 
@@ -1335,6 +1370,11 @@ struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj),
 
 	AST_VECTOR_INIT(&tmp->fds, AST_MAX_FDS);
 
+	/* Force all channel snapshot segments to be created on first use, so we don't have to check if
+	 * an old snapshot exists.
+	 */
+	ast_set_flag(&tmp->snapshot_segment_flags, AST_FLAGS_ALL);
+
 	return tmp;
 }
 
@@ -1363,6 +1403,7 @@ void ast_channel_internal_copy_linkedid(struct ast_channel *dest, struct ast_cha
 		return;
 	}
 	dest->linkedid = source->linkedid;
+	ast_channel_snapshot_invalidate_segment(dest, AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER);
 	ast_channel_publish_snapshot(dest);
 }
 
@@ -1370,6 +1411,10 @@ void ast_channel_internal_swap_uniqueid_and_linkedid(struct ast_channel *a, stru
 {
 	struct ast_channel_id temp;
 
+	/* This operation is used as part of masquerading and so does not invalidate the peer
+	 * segment. This is due to the masquerade process invalidating all segments.
+	 */
+
 	temp = a->uniqueid;
 	a->uniqueid = b->uniqueid;
 	b->uniqueid = temp;
@@ -1584,3 +1629,8 @@ void ast_channel_snapshot_set(struct ast_channel *chan, struct ast_channel_snaps
 	ao2_cleanup(chan->snapshot);
 	chan->snapshot = ao2_bump(snapshot);
 }
+
+struct ast_flags *ast_channel_snapshot_segment_flags(struct ast_channel *chan)
+{
+	return &chan->snapshot_segment_flags;
+}
diff --git a/main/cli.c b/main/cli.c
index 5484e47e7ef2986a7b1a3d600bfe428111819acd..e2224f7ddb0b13a607286e6c833f499e6ce0d989 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -1004,8 +1004,8 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 		char durbuf[16] = "-";
 
 		if (!count) {
-			if ((concise || verbose)  && !ast_tvzero(cs->creationtime)) {
-				int duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->creationtime) / 1000);
+			if ((concise || verbose)  && !ast_tvzero(cs->base->creationtime)) {
+				int duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->base->creationtime) / 1000);
 				if (verbose) {
 					int durh = duration / 3600;
 					int durm = (duration % 3600) / 60;
@@ -1016,36 +1016,36 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 				}
 			}
 			if (concise) {
-				ast_cli(a->fd, CONCISE_FORMAT_STRING, cs->name, cs->context, cs->exten, cs->priority, ast_state2str(cs->state),
-					S_OR(cs->appl, "(None)"),
-					cs->data,
-					cs->caller_number,
-					cs->accountcode,
-					cs->peeraccount,
+				ast_cli(a->fd, CONCISE_FORMAT_STRING, cs->base->name, cs->dialplan->context, cs->dialplan->exten, cs->dialplan->priority, ast_state2str(cs->state),
+					S_OR(cs->dialplan->appl, "(None)"),
+					cs->dialplan->data,
+					cs->caller->number,
+					cs->base->accountcode,
+					cs->peer->account,
 					cs->amaflags,
 					durbuf,
-					cs->bridgeid,
-					cs->uniqueid);
+					cs->bridge->id,
+					cs->base->uniqueid);
 			} else if (verbose) {
-				ast_cli(a->fd, VERBOSE_FORMAT_STRING, cs->name, cs->context, cs->exten, cs->priority, ast_state2str(cs->state),
-					S_OR(cs->appl, "(None)"),
-					S_OR(cs->data, "(Empty)"),
-					cs->caller_number,
+				ast_cli(a->fd, VERBOSE_FORMAT_STRING, cs->base->name, cs->dialplan->context, cs->dialplan->exten, cs->dialplan->priority, ast_state2str(cs->state),
+					S_OR(cs->dialplan->appl, "(None)"),
+					S_OR(cs->dialplan->data, "(Empty)"),
+					cs->caller->number,
 					durbuf,
-					cs->accountcode,
-					cs->peeraccount,
-					cs->bridgeid);
+					cs->base->accountcode,
+					cs->peer->account,
+					cs->bridge->id);
 			} else {
 				char locbuf[40] = "(None)";
 				char appdata[40] = "(None)";
 
-				if (!ast_strlen_zero(cs->context) && !ast_strlen_zero(cs->exten)) {
-					snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", cs->exten, cs->context, cs->priority);
+				if (!ast_strlen_zero(cs->dialplan->context) && !ast_strlen_zero(cs->dialplan->exten)) {
+					snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", cs->dialplan->exten, cs->dialplan->context, cs->dialplan->priority);
 				}
-				if (!ast_strlen_zero(cs->appl)) {
-					snprintf(appdata, sizeof(appdata), "%s(%s)", cs->appl, S_OR(cs->data, ""));
+				if (!ast_strlen_zero(cs->dialplan->appl)) {
+					snprintf(appdata, sizeof(appdata), "%s(%s)", cs->dialplan->appl, S_OR(cs->dialplan->data, ""));
 				}
-				ast_cli(a->fd, FORMAT_STRING, cs->name, locbuf, ast_state2str(cs->state), appdata);
+				ast_cli(a->fd, FORMAT_STRING, cs->base->name, locbuf, ast_state2str(cs->state), appdata);
 			}
 		}
 	}
@@ -1684,14 +1684,14 @@ char *ast_complete_channels(const char *line, const char *word, int pos, int sta
 
 	iter = ao2_iterator_init(cached_channels, 0);
 	for (; (snapshot = ao2_iterator_next(&iter)); ao2_ref(snapshot, -1)) {
-		if (!strncasecmp(word, snapshot->name, wordlen) && (++which > state)) {
+		if (!strncasecmp(word, snapshot->base->name, wordlen) && (++which > state)) {
 			if (state != -1) {
-				ret = ast_strdup(snapshot->name);
+				ret = ast_strdup(snapshot->base->name);
 				ao2_ref(snapshot, -1);
 				break;
 			}
 
-			if (ast_cli_completion_add(ast_strdup(snapshot->name))) {
+			if (ast_cli_completion_add(ast_strdup(snapshot->base->name))) {
 				ao2_ref(snapshot, -1);
 				break;
 			}
diff --git a/main/core_local.c b/main/core_local.c
index c3fa15f6c273c13f672a1ea63443fbca4b5f6e98..f56aac76b1395961dbe76cbc2b9a5970e978291c 100644
--- a/main/core_local.c
+++ b/main/core_local.c
@@ -493,7 +493,7 @@ static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message
 		}
 
 		dest_uniqueid = ast_json_object_get(blob, "dest") == AST_UNREAL_OWNER ?
-				local_snapshot_one->uniqueid : local_snapshot_two->uniqueid;
+				local_snapshot_one->base->uniqueid : local_snapshot_two->base->uniqueid;
 
 		event = "LocalOptimizationBegin";
 		if (source_str) {
diff --git a/main/endpoints.c b/main/endpoints.c
index f3e337225d662dec94602ce18ccdfb950cf58897..b95893270b904598566a1b6a3a3a8453a5826bd1 100644
--- a/main/endpoints.c
+++ b/main/endpoints.c
@@ -195,7 +195,7 @@ static void endpoint_cache_clear(void *data,
 	ast_assert(endpoint != NULL);
 
 	ao2_lock(endpoint);
-	ast_str_container_remove(endpoint->channel_ids, update->new_snapshot->uniqueid);
+	ast_str_container_remove(endpoint->channel_ids, update->new_snapshot->base->uniqueid);
 	ao2_unlock(endpoint);
 	endpoint_publish_snapshot(endpoint);
 }
diff --git a/main/manager.c b/main/manager.c
index 76a827c09c85578354288e5f410a7cfa6eb95dda..3e41198c0f03b81c8653b5f2753f8fd2bb86213e 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -6271,10 +6271,10 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
 			continue;
 		}
 
-		if (!ast_tvzero(cs->creationtime)) {
+		if (!ast_tvzero(cs->base->creationtime)) {
 			int duration, durh, durm, durs;
 
-			duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->creationtime) / 1000);
+			duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->base->creationtime) / 1000);
 			durh = duration / 3600;
 			durm = (duration % 3600) / 60;
 			durs = duration % 60;
@@ -6292,10 +6292,10 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
 			"\r\n",
 			idText,
 			ast_str_buffer(built),
-			cs->appl,
-			cs->data,
+			cs->dialplan->appl,
+			cs->dialplan->data,
 			durbuf,
-			cs->bridgeid);
+			cs->bridge->id);
 
 		numchans++;
 
diff --git a/main/manager_bridges.c b/main/manager_bridges.c
index 1b5704968f087582adf18bd214d4fd046288c730..4f2cb35306c24927577ad290ce5cb7d374dd4e0b 100644
--- a/main/manager_bridges.c
+++ b/main/manager_bridges.c
@@ -536,7 +536,7 @@ static int send_bridge_info_item_cb(void *obj, void *arg, void *data, int flags)
 		return 0;
 	}
 
-	if (snapshot->tech_properties & AST_CHAN_TP_INTERNAL) {
+	if (snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL) {
 		return 0;
 	}
 
diff --git a/main/manager_channels.c b/main/manager_channels.c
index 887f77e19351244bf7ae713b860c03dc1f171761..edbc770a075ae9a9a59c8dcb13f0f863874fac6e 100644
--- a/main/manager_channels.c
+++ b/main/manager_channels.c
@@ -493,7 +493,7 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
 	char *connected_name;
 	int res;
 
-	if (snapshot->tech_properties & AST_CHAN_TP_INTERNAL) {
+	if (snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL) {
 		return NULL;
 	}
 
@@ -502,8 +502,8 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
 		return NULL;
 	}
 
-	caller_name = ast_escape_c_alloc(snapshot->caller_name);
-	connected_name = ast_escape_c_alloc(snapshot->connected_name);
+	caller_name = ast_escape_c_alloc(snapshot->caller->name);
+	connected_name = ast_escape_c_alloc(snapshot->connected->name);
 
 	res = ast_str_set(&out, 0,
 		"%sChannel: %s\r\n"
@@ -520,20 +520,20 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
 		"%sPriority: %d\r\n"
 		"%sUniqueid: %s\r\n"
 		"%sLinkedid: %s\r\n",
-		prefix, snapshot->name,
+		prefix, snapshot->base->name,
 		prefix, snapshot->state,
 		prefix, ast_state2str(snapshot->state),
-		prefix, S_OR(snapshot->caller_number, "<unknown>"),
+		prefix, S_OR(snapshot->caller->number, "<unknown>"),
 		prefix, S_OR(caller_name, "<unknown>"),
-		prefix, S_OR(snapshot->connected_number, "<unknown>"),
+		prefix, S_OR(snapshot->connected->number, "<unknown>"),
 		prefix, S_OR(connected_name, "<unknown>"),
-		prefix, snapshot->language,
-		prefix, snapshot->accountcode,
-		prefix, snapshot->context,
-		prefix, snapshot->exten,
-		prefix, snapshot->priority,
-		prefix, snapshot->uniqueid,
-		prefix, snapshot->linkedid);
+		prefix, snapshot->base->language,
+		prefix, snapshot->base->accountcode,
+		prefix, snapshot->dialplan->context,
+		prefix, snapshot->dialplan->exten,
+		prefix, snapshot->dialplan->priority,
+		prefix, snapshot->base->uniqueid,
+		prefix, snapshot->peer->linkedid);
 
 	ast_free(caller_name);
 	ast_free(connected_name);
@@ -594,8 +594,8 @@ static struct ast_manager_event_blob *channel_state_change(
 			EVENT_FLAG_CALL, "Hangup",
 			"Cause: %d\r\n"
 			"Cause-txt: %s\r\n",
-			new_snapshot->hangupcause,
-			ast_cause2str(new_snapshot->hangupcause));
+			new_snapshot->hangup->cause,
+			ast_cause2str(new_snapshot->hangup->cause));
 	}
 
 	if (old_snapshot->state != new_snapshot->state) {
@@ -612,7 +612,7 @@ static struct ast_manager_event_blob *channel_newexten(
 	struct ast_channel_snapshot *new_snapshot)
 {
 	/* Empty application is not valid for a Newexten event */
-	if (ast_strlen_zero(new_snapshot->appl)) {
+	if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
 		return NULL;
 	}
 
@@ -632,9 +632,9 @@ static struct ast_manager_event_blob *channel_newexten(
 		"Extension: %s\r\n"
 		"Application: %s\r\n"
 		"AppData: %s\r\n",
-		new_snapshot->exten,
-		new_snapshot->appl,
-		new_snapshot->data);
+		new_snapshot->dialplan->exten,
+		new_snapshot->dialplan->appl,
+		new_snapshot->dialplan->data);
 }
 
 static struct ast_manager_event_blob *channel_new_callerid(
@@ -654,14 +654,14 @@ static struct ast_manager_event_blob *channel_new_callerid(
 	}
 
 	if (!(callerid = ast_escape_c_alloc(
-		      ast_describe_caller_presentation(new_snapshot->caller_pres)))) {
+		      ast_describe_caller_presentation(new_snapshot->caller->pres)))) {
 		return NULL;
 	}
 
 	res = ast_manager_event_blob_create(
 		EVENT_FLAG_CALL, "NewCallerid",
 		"CID-CallingPres: %d (%s)\r\n",
-		new_snapshot->caller_pres,
+		new_snapshot->caller->pres,
 		callerid);
 
 	ast_free(callerid);
@@ -693,13 +693,13 @@ static struct ast_manager_event_blob *channel_new_accountcode(
 		return NULL;
 	}
 
-	if (!strcmp(old_snapshot->accountcode, new_snapshot->accountcode)) {
+	if (!strcmp(old_snapshot->base->accountcode, new_snapshot->base->accountcode)) {
 		return NULL;
 	}
 
 	return ast_manager_event_blob_create(
 		EVENT_FLAG_CALL, "NewAccountCode",
-		"OldAccountCode: %s\r\n", old_snapshot->accountcode);
+		"OldAccountCode: %s\r\n", old_snapshot->base->accountcode);
 }
 
 channel_snapshot_monitor channel_monitors[] = {
diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c
index 59b9685ef3191492d425057b2739f1207e8d88ab..42bf6bc2dae899c79b32deafc5f6ae4855edb94f 100644
--- a/main/stasis_bridges.c
+++ b/main/stasis_bridges.c
@@ -1069,7 +1069,7 @@ static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_mes
 	case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
 		ast_str_append(&variable_data, 0, "DestType: Threeway\r\n");
 		ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.threeway.bridge_snapshot->uniqueid);
-		ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->name);
+		ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->base->name);
 		break;
 	case AST_ATTENDED_TRANSFER_DEST_FAIL:
 		ast_str_append(&variable_data, 0, "DestType: Fail\r\n");
@@ -1189,7 +1189,7 @@ int ast_attended_transfer_message_add_threeway(struct ast_attended_transfer_mess
 {
 	transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_THREEWAY;
 
-	if (!strcmp(ast_channel_uniqueid(survivor_channel), transfer_msg->to_transferee.channel_snapshot->uniqueid)) {
+	if (!strcmp(ast_channel_uniqueid(survivor_channel), transfer_msg->to_transferee.channel_snapshot->base->uniqueid)) {
 		transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transferee.channel_snapshot;
 	} else {
 		transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transfer_target.channel_snapshot;
diff --git a/main/stasis_channels.c b/main/stasis_channels.c
index ec8d70cd22f284a01840a5f30918b13fcd01cc8d..d39fb08fbf41570fd74e895e725b370a53190b4d 100644
--- a/main/stasis_channels.c
+++ b/main/stasis_channels.c
@@ -149,7 +149,7 @@ static int channel_snapshot_hash_cb(const void *obj, const int flags)
 		key = obj;
 		break;
 	case OBJ_SEARCH_OBJECT:
-		key = object->name;
+		key = object->base->name;
 		break;
 	default:
 		ast_assert(0);
@@ -171,12 +171,12 @@ static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
 
 	switch (flags & OBJ_SEARCH_MASK) {
 	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->name;
+		right_key = object_right->base->name;
 	case OBJ_SEARCH_KEY:
-		cmp = strcasecmp(object_left->name, right_key);
+		cmp = strcasecmp(object_left->base->name, right_key);
 		break;
 	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncasecmp(object_left->name, right_key, strlen(right_key));
+		cmp = strncasecmp(object_left->base->name, right_key, strlen(right_key));
 		break;
 	default:
 		cmp = 0;
@@ -202,7 +202,7 @@ static int channel_snapshot_uniqueid_hash_cb(const void *obj, const int flags)
 		key = obj;
 		break;
 	case OBJ_SEARCH_OBJECT:
-		key = object->uniqueid;
+		key = object->base->uniqueid;
 		break;
 	default:
 		ast_assert(0);
@@ -224,12 +224,12 @@ static int channel_snapshot_uniqueid_cmp_cb(void *obj, void *arg, int flags)
 
 	switch (flags & OBJ_SEARCH_MASK) {
 	case OBJ_SEARCH_OBJECT:
-		right_key = object_right->uniqueid;
+		right_key = object_right->base->uniqueid;
 	case OBJ_SEARCH_KEY:
-		cmp = strcasecmp(object_left->uniqueid, right_key);
+		cmp = strcasecmp(object_left->base->uniqueid, right_key);
 		break;
 	case OBJ_SEARCH_PARTIAL_KEY:
-		cmp = strncasecmp(object_left->uniqueid, right_key, strlen(right_key));
+		cmp = strncasecmp(object_left->base->uniqueid, right_key, strlen(right_key));
 		break;
 	default:
 		cmp = 0;
@@ -245,88 +245,312 @@ static void channel_snapshot_dtor(void *obj)
 {
 	struct ast_channel_snapshot *snapshot = obj;
 
-	ast_string_field_free_memory(snapshot);
+	ao2_cleanup(snapshot->base);
+	ao2_cleanup(snapshot->peer);
+	ao2_cleanup(snapshot->caller);
+	ao2_cleanup(snapshot->connected);
+	ao2_cleanup(snapshot->bridge);
+	ao2_cleanup(snapshot->dialplan);
+	ao2_cleanup(snapshot->hangup);
 	ao2_cleanup(snapshot->manager_vars);
 	ao2_cleanup(snapshot->ari_vars);
 }
 
-struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
+static void channel_snapshot_base_dtor(void *obj)
 {
-	struct ast_channel_snapshot *snapshot;
-	struct ast_bridge *bridge;
+	struct ast_channel_snapshot_base *snapshot = obj;
 
-	/* no snapshots for dummy channels */
-	if (!ast_channel_tech(chan)) {
+	ast_string_field_free_memory(snapshot);
+}
+
+static struct ast_channel_snapshot_base *channel_snapshot_base_create(struct ast_channel *chan)
+{
+	struct ast_channel_snapshot_base *snapshot;
+
+	snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_base_dtor,
+		AO2_ALLOC_OPT_LOCK_NOLOCK);
+	if (!snapshot) {
 		return NULL;
 	}
 
-	snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dtor,
-		AO2_ALLOC_OPT_LOCK_NOLOCK);
-	if (!snapshot || ast_string_field_init(snapshot, 1024)) {
-		ao2_cleanup(snapshot);
+	if (ast_string_field_init(snapshot, 256)) {
+		ao2_ref(snapshot, -1);
 		return NULL;
 	}
 
 	ast_string_field_set(snapshot, name, ast_channel_name(chan));
 	ast_string_field_set(snapshot, type, ast_channel_tech(chan)->type);
 	ast_string_field_set(snapshot, accountcode, ast_channel_accountcode(chan));
-	ast_string_field_set(snapshot, peeraccount, ast_channel_peeraccount(chan));
 	ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan));
 	ast_string_field_set(snapshot, uniqueid, ast_channel_uniqueid(chan));
-	ast_string_field_set(snapshot, linkedid, ast_channel_linkedid(chan));
-	ast_string_field_set(snapshot, hangupsource, ast_channel_hangupsource(chan));
-	if (ast_channel_appl(chan)) {
-		ast_string_field_set(snapshot, appl, ast_channel_appl(chan));
+	ast_string_field_set(snapshot, language, ast_channel_language(chan));
+
+	snapshot->creationtime = ast_channel_creationtime(chan);
+	snapshot->tech_properties = ast_channel_tech(chan)->properties;
+
+	return snapshot;
+}
+
+static struct ast_channel_snapshot_peer *channel_snapshot_peer_create(struct ast_channel *chan)
+{
+	const char *linkedid = S_OR(ast_channel_linkedid(chan), "");
+	const char *peeraccount = S_OR(ast_channel_peeraccount(chan), "");
+	size_t linkedid_len = strlen(linkedid) + 1;
+	size_t peeraccount_len = strlen(peeraccount) + 1;
+	struct ast_channel_snapshot_peer *snapshot;
+
+	snapshot = ao2_alloc_options(sizeof(*snapshot) + linkedid_len + peeraccount_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+	if (!snapshot) {
+		return NULL;
 	}
-	if (ast_channel_data(chan)) {
-		ast_string_field_set(snapshot, data, ast_channel_data(chan));
+
+	strcpy(snapshot->account, peeraccount); /* Safe */
+	snapshot->linkedid = snapshot->account + peeraccount_len;
+	strcpy(snapshot->linkedid, linkedid); /* Safe */
+
+	return snapshot;
+}
+
+static void channel_snapshot_caller_dtor(void *obj)
+{
+	struct ast_channel_snapshot_caller *snapshot = obj;
+
+	ast_string_field_free_memory(snapshot);
+}
+
+static struct ast_channel_snapshot_caller *channel_snapshot_caller_create(struct ast_channel *chan)
+{
+	struct ast_channel_snapshot_caller *snapshot;
+
+	snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_caller_dtor,
+		AO2_ALLOC_OPT_LOCK_NOLOCK);
+	if (!snapshot) {
+		return NULL;
+	}
+
+	if (ast_string_field_init(snapshot, 256)) {
+		ao2_ref(snapshot, -1);
+		return NULL;
 	}
-	ast_string_field_set(snapshot, context, ast_channel_context(chan));
-	ast_string_field_set(snapshot, exten, ast_channel_exten(chan));
 
-	ast_string_field_set(snapshot, caller_name,
+	ast_string_field_set(snapshot, name,
 		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""));
-	ast_string_field_set(snapshot, caller_number,
+	ast_string_field_set(snapshot, number,
 		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
-	ast_string_field_set(snapshot, caller_subaddr,
+	ast_string_field_set(snapshot, subaddr,
 		S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, ""));
-	ast_string_field_set(snapshot, caller_ani,
+	ast_string_field_set(snapshot, ani,
 		S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""));
 
-	ast_string_field_set(snapshot, caller_rdnis,
+	ast_string_field_set(snapshot, rdnis,
 		S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""));
 
-	ast_string_field_set(snapshot, caller_dnid,
+	ast_string_field_set(snapshot, dnid,
 		S_OR(ast_channel_dialed(chan)->number.str, ""));
 	ast_string_field_set(snapshot, dialed_subaddr,
 		S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, ""));
 
-	ast_string_field_set(snapshot, connected_name,
-		S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, ""));
-	ast_string_field_set(snapshot, connected_number,
-		S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, ""));
+	snapshot->pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
 
-	ast_string_field_set(snapshot, language, ast_channel_language(chan));
+	return snapshot;
+}
+
+static struct ast_channel_snapshot_connected *channel_snapshot_connected_create(struct ast_channel *chan)
+{
+	const char *name = S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "");
+	const char *number = S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "");
+	size_t name_len = strlen(name) + 1;
+	size_t number_len = strlen(number) + 1;
+	struct ast_channel_snapshot_connected *snapshot;
+
+	snapshot = ao2_alloc_options(sizeof(*snapshot) + name_len + number_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+	if (!snapshot) {
+		return NULL;
+	}
+
+	strcpy(snapshot->name, name); /* Safe */
+	snapshot->number = snapshot->name + name_len;
+	strcpy(snapshot->number, number); /* Safe */
+
+	return snapshot;
+}
+
+static struct ast_channel_snapshot_bridge *channel_snapshot_bridge_create(struct ast_channel *chan)
+{
+	const char *uniqueid = "";
+	struct ast_bridge *bridge;
+	struct ast_channel_snapshot_bridge *snapshot;
+
+	bridge = ast_channel_get_bridge(chan);
+	if (bridge && !ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
+		uniqueid = bridge->uniqueid;
+	}
+	ao2_cleanup(bridge);
+
+	snapshot = ao2_alloc_options(sizeof(*snapshot) + strlen(uniqueid) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+	if (!snapshot) {
+		return NULL;
+	}
+
+	strcpy(snapshot->id, uniqueid); /* Safe */
+
+	return snapshot;
+}
+
+static void channel_snapshot_dialplan_dtor(void *obj)
+{
+	struct ast_channel_snapshot_dialplan *snapshot = obj;
+
+	ast_string_field_free_memory(snapshot);
+}
+
+static struct ast_channel_snapshot_dialplan *channel_snapshot_dialplan_create(struct ast_channel *chan)
+{
+	struct ast_channel_snapshot_dialplan *snapshot;
+
+	snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dialplan_dtor,
+		AO2_ALLOC_OPT_LOCK_NOLOCK);
+	if (!snapshot) {
+		return NULL;
+	}
 
-	if ((bridge = ast_channel_get_bridge(chan))) {
-		if (!ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
-			ast_string_field_set(snapshot, bridgeid, bridge->uniqueid);
+	if (ast_string_field_init(snapshot, 256)) {
+		ao2_ref(snapshot, -1);
+		return NULL;
+	}
+
+	if (ast_channel_appl(chan)) {
+		ast_string_field_set(snapshot, appl, ast_channel_appl(chan));
+	}
+	if (ast_channel_data(chan)) {
+		ast_string_field_set(snapshot, data, ast_channel_data(chan));
+	}
+	ast_string_field_set(snapshot, context, ast_channel_context(chan));
+	ast_string_field_set(snapshot, exten, ast_channel_exten(chan));
+	snapshot->priority = ast_channel_priority(chan);
+
+	return snapshot;
+}
+
+static struct ast_channel_snapshot_hangup *channel_snapshot_hangup_create(struct ast_channel *chan)
+{
+	const char *hangupsource = S_OR(ast_channel_hangupsource(chan), "");
+	struct ast_channel_snapshot_hangup *snapshot;
+
+	snapshot = ao2_alloc_options(sizeof(*snapshot) + strlen(hangupsource) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+	if (!snapshot) {
+		return NULL;
+	}
+
+	snapshot->cause = ast_channel_hangupcause(chan);
+	strcpy(snapshot->source, hangupsource); /* Safe */
+
+	return snapshot;
+}
+
+struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
+{
+	struct ast_channel_snapshot *old_snapshot;
+	struct ast_channel_snapshot *snapshot;
+
+	/* no snapshots for dummy channels */
+	if (!ast_channel_tech(chan)) {
+		return NULL;
+	}
+
+	snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dtor,
+		AO2_ALLOC_OPT_LOCK_NOLOCK);
+	if (!snapshot) {
+		return NULL;
+	}
+
+	old_snapshot = ast_channel_snapshot(chan);
+
+	/* Channels automatically have all segments invalidated on them initially so a check for an old
+	 * snapshot existing before usage is not done here, as it can not happen. If the stored snapshot
+	 * on the channel is updated as a result of this then all segments marked as invalidated will be
+	 * cleared.
+	 */
+	if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE)) {
+		/* The base information has changed so update our snapshot */
+		snapshot->base = channel_snapshot_base_create(chan);
+		if (!snapshot->base) {
+			ao2_ref(snapshot, -1);
+			return NULL;
 		}
-		ao2_cleanup(bridge);
+	} else {
+		snapshot->base = ao2_bump(old_snapshot->base);
+	}
+
+	if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER)) {
+		/* The peer information has changed so update our snapshot */
+		snapshot->peer = channel_snapshot_peer_create(chan);
+		if (!snapshot->peer) {
+			ao2_ref(snapshot, -1);
+			return NULL;
+		}
+	} else {
+		snapshot->peer = ao2_bump(old_snapshot->peer);
+	}
+
+	/* Unfortunately both caller and connected information do not have an enforced contract with
+	 * the channel API. This has allowed consumers to directly get the caller or connected structure
+	 * and manipulate it. Until such time as there is an enforced contract (which is being tracked under
+	 * ASTERISK-28164) they are each regenerated every time a channel snapshot is created.
+	 */
+	snapshot->caller = channel_snapshot_caller_create(chan);
+	if (!snapshot->caller) {
+		ao2_ref(snapshot, -1);
+		return NULL;
+	}
+
+	snapshot->connected = channel_snapshot_connected_create(chan);
+	if (!snapshot->connected) {
+		ao2_ref(snapshot, -1);
+		return NULL;
+	}
+
+	if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_BRIDGE)) {
+		/* The bridge has changed so update our snapshot */
+		snapshot->bridge = channel_snapshot_bridge_create(chan);
+		if (!snapshot->bridge) {
+			ao2_ref(snapshot, -1);
+			return NULL;
+		}
+	} else {
+		snapshot->bridge = ao2_bump(old_snapshot->bridge);
+	}
+
+	if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN)) {
+		/* The dialplan information has changed so update our snapshot */
+		snapshot->dialplan = channel_snapshot_dialplan_create(chan);
+		if (!snapshot->dialplan) {
+			ao2_ref(snapshot, -1);
+			return NULL;
+		}
+	} else {
+		snapshot->dialplan = ao2_bump(old_snapshot->dialplan);
+	}
+
+	if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP)) {
+		/* The hangup information has changed so update our snapshot */
+		snapshot->hangup = channel_snapshot_hangup_create(chan);
+		if (!snapshot->hangup) {
+			ao2_ref(snapshot, -1);
+			return NULL;
+		}
+	} else {
+		snapshot->hangup = ao2_bump(old_snapshot->hangup);
 	}
 
-	snapshot->creationtime = ast_channel_creationtime(chan);
 	snapshot->state = ast_channel_state(chan);
-	snapshot->priority = ast_channel_priority(chan);
 	snapshot->amaflags = ast_channel_amaflags(chan);
-	snapshot->hangupcause = ast_channel_hangupcause(chan);
 	ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF);
-	snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
 	ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan));
 
+	/* These have to be recreated as they may have changed, unfortunately */
 	snapshot->manager_vars = ast_channel_get_manager_vars(chan);
 	snapshot->ari_vars = ast_channel_get_ari_vars(chan);
-	snapshot->tech_properties = ast_channel_tech(chan)->properties;
 
 	return snapshot;
 }
@@ -822,6 +1046,12 @@ void ast_channel_stage_snapshot_done(struct ast_channel *chan)
 	ast_channel_publish_snapshot(chan);
 }
 
+void ast_channel_snapshot_invalidate_segment(struct ast_channel *chan,
+	enum ast_channel_snapshot_segment_invalidation segment)
+{
+	ast_set_flag(ast_channel_snapshot_segment_flags(chan), segment);
+}
+
 void ast_channel_publish_snapshot(struct ast_channel *chan)
 {
 	struct ast_channel_snapshot_update *update;
@@ -840,6 +1070,14 @@ void ast_channel_publish_snapshot(struct ast_channel *chan)
 		return;
 	}
 
+	/* If an old snapshot exists and is the same as this newly created one don't bother
+	 * raising a message as it hasn't changed.
+	 */
+	if (update->old_snapshot && !memcmp(update->old_snapshot, update->new_snapshot, sizeof(struct ast_channel_snapshot))) {
+		ao2_ref(update, -1);
+		return;
+	}
+
 	message = stasis_message_create(ast_channel_snapshot_type(), update);
 	/* In the success path message holds a reference to update so it will be valid
 	 * for the lifetime of this function until the end.
@@ -869,6 +1107,11 @@ void ast_channel_publish_snapshot(struct ast_channel *chan)
 
 	ast_channel_snapshot_set(chan, update->new_snapshot);
 
+	/* As this is now the new snapshot any existing invalidated segments have been
+	 * created fresh and are up to date.
+	 */
+	ast_clear_flag(ast_channel_snapshot_segment_flags(chan), AST_FLAGS_ALL);
+
 	ast_assert(ast_channel_topic(chan) != NULL);
 	stasis_publish(ast_channel_topic(chan), message);
 	ao2_ref(message, -1);
@@ -1028,20 +1271,20 @@ struct ast_json *ast_channel_snapshot_to_json(
 		"  s: o, s: o, s: s,"
 		"  s: o, s: o, s: s }",
 		/* First line */
-		"id", snapshot->uniqueid,
-		"name", snapshot->name,
+		"id", snapshot->base->uniqueid,
+		"name", snapshot->base->name,
 		"state", ast_state2str(snapshot->state),
 		/* Second line */
 		"caller", ast_json_name_number(
-			snapshot->caller_name, snapshot->caller_number),
+			snapshot->caller->name, snapshot->caller->number),
 		"connected", ast_json_name_number(
-			snapshot->connected_name, snapshot->connected_number),
-		"accountcode", snapshot->accountcode,
+			snapshot->connected->name, snapshot->connected->number),
+		"accountcode", snapshot->base->accountcode,
 		/* Third line */
 		"dialplan", ast_json_dialplan_cep(
-			snapshot->context, snapshot->exten, snapshot->priority),
-		"creationtime", ast_json_timeval(snapshot->creationtime, NULL),
-		"language", snapshot->language);
+			snapshot->dialplan->context, snapshot->dialplan->exten, snapshot->dialplan->priority),
+		"creationtime", ast_json_timeval(snapshot->base->creationtime, NULL),
+		"language", snapshot->base->language);
 
 	if (snapshot->ari_vars && !AST_LIST_EMPTY(snapshot->ari_vars)) {
 		ast_json_object_set(json_chan, "channelvars", ast_json_channel_vars(snapshot->ari_vars));
@@ -1061,14 +1304,14 @@ int ast_channel_snapshot_cep_equal(
 	 * application is set. Since empty application is invalid, we treat
 	 * setting the application from nothing as a CEP change.
 	 */
-	if (ast_strlen_zero(old_snapshot->appl) &&
-	    !ast_strlen_zero(new_snapshot->appl)) {
+	if (ast_strlen_zero(old_snapshot->dialplan->appl) &&
+	    !ast_strlen_zero(new_snapshot->dialplan->appl)) {
 		return 0;
 	}
 
-	return old_snapshot->priority == new_snapshot->priority &&
-		strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
-		strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
+	return old_snapshot->dialplan->priority == new_snapshot->dialplan->priority &&
+		strcmp(old_snapshot->dialplan->context, new_snapshot->dialplan->context) == 0 &&
+		strcmp(old_snapshot->dialplan->exten, new_snapshot->dialplan->exten) == 0;
 }
 
 int ast_channel_snapshot_caller_id_equal(
@@ -1077,8 +1320,8 @@ int ast_channel_snapshot_caller_id_equal(
 {
 	ast_assert(old_snapshot != NULL);
 	ast_assert(new_snapshot != NULL);
-	return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
-		strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
+	return strcmp(old_snapshot->caller->number, new_snapshot->caller->number) == 0 &&
+		strcmp(old_snapshot->caller->name, new_snapshot->caller->name) == 0;
 }
 
 int ast_channel_snapshot_connected_line_equal(
@@ -1087,8 +1330,8 @@ int ast_channel_snapshot_connected_line_equal(
 {
 	ast_assert(old_snapshot != NULL);
 	ast_assert(new_snapshot != NULL);
-	return strcmp(old_snapshot->connected_number, new_snapshot->connected_number) == 0 &&
-		strcmp(old_snapshot->connected_name, new_snapshot->connected_name) == 0;
+	return strcmp(old_snapshot->connected->number, new_snapshot->connected->number) == 0 &&
+		strcmp(old_snapshot->connected->name, new_snapshot->connected->name) == 0;
 }
 
 static struct ast_json *channel_blob_to_json(
diff --git a/pbx/pbx_realtime.c b/pbx/pbx_realtime.c
index 75e6654f07be863946f078e0290a0de7d346910b..970bb3cbb5f8217bb11fe007944fbf425ed32b06 100644
--- a/pbx/pbx_realtime.c
+++ b/pbx/pbx_realtime.c
@@ -344,6 +344,11 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch
 						 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
 				if (ast_channel_snapshot_type()) {
 					ast_channel_lock(chan);
+					/* Force a new dialplan segment that will be unique to use so we can update it with the
+					 * information we want. In the future when a channel snapshot is published this will
+					 * occur again and unset this flag.
+					 */
+					ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 					snapshot = ast_channel_snapshot_create(chan);
 					ast_channel_unlock(chan);
 				}
@@ -351,8 +356,8 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch
 					/* pbx_exec sets application name and data, but we don't want to log
 					 * every exec. Just update the snapshot here instead.
 					 */
-					ast_string_field_set(snapshot, appl, app);
-					ast_string_field_set(snapshot, data, !ast_strlen_zero(appdata) ? appdata : "(NULL)");
+					ast_string_field_set(snapshot->dialplan, appl, app);
+					ast_string_field_set(snapshot->dialplan, data, !ast_strlen_zero(appdata) ? appdata : "(NULL)");
 					msg = stasis_message_create(ast_channel_snapshot_type(), snapshot);
 					if (msg) {
 						stasis_publish(ast_channel_topic(chan), msg);
diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c
index e5fa41c1d9a21e1a9929935f850156352b034d97..3c0eeb7751e2dc8268796abf78c0501c0bafb482 100644
--- a/res/ari/resource_bridges.c
+++ b/res/ari/resource_bridges.c
@@ -377,7 +377,7 @@ static int ari_bridges_play_helper(const char **args_media,
 		return -1;
 	}
 
-	language = S_OR(args_lang, snapshot->language);
+	language = S_OR(args_lang, snapshot->base->language);
 
 	playback = stasis_app_control_play_uri(control, args_media, args_media_count,
 		language, bridge->uniqueid, STASIS_PLAYBACK_TARGET_BRIDGE, args_skipms,
diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c
index f96192b52fa05049eebcf48cb97c594ae3e73122..311358ef4db03fec7ef10cc0371129a8dc09d9d0 100644
--- a/res/ari/resource_channels.c
+++ b/res/ari/resource_channels.c
@@ -170,8 +170,8 @@ void ast_ari_channels_continue_in_dialplan(
 	}
 
 	if (ast_strlen_zero(args->context)) {
-		context = snapshot->context;
-		exten = S_OR(args->extension, snapshot->exten);
+		context = snapshot->dialplan->context;
+		exten = S_OR(args->extension, snapshot->dialplan->exten);
 	} else {
 		context = args->context;
 		exten = S_OR(args->extension, "s");
@@ -203,7 +203,7 @@ void ast_ari_channels_continue_in_dialplan(
 		ipri = args->priority;
 	} else if (ast_strlen_zero(args->context) && ast_strlen_zero(args->extension)) {
 		/* Special case. No exten, context, or priority provided, then move on to the next priority */
-		ipri = snapshot->priority + 1;
+		ipri = snapshot->dialplan->priority + 1;
 	} else {
 		ipri = 1;
 	}
@@ -263,10 +263,10 @@ void ast_ari_channels_redirect(struct ast_variable *headers,
 		return;
 	}
 
-	if (strncasecmp(chan_snapshot->type, tech, tech_len)) {
+	if (strncasecmp(chan_snapshot->base->type, tech, tech_len)) {
 		ast_ari_response_error(response, 422, "Unprocessable Entity",
 			"Endpoint technology '%s' does not match channel technology '%s'",
-			tech, chan_snapshot->type);
+			tech, chan_snapshot->base->type);
 		return;
 	}
 
@@ -628,7 +628,7 @@ static void ari_channels_handle_play(
 		return;
 	}
 
-	language = S_OR(args_lang, snapshot->language);
+	language = S_OR(args_lang, snapshot->base->language);
 
 	playback = stasis_app_control_play_uri(control, args_media, args_media_count, language,
 		args_channel_id, STASIS_PLAYBACK_TARGET_CHANNEL, args_skipms, args_offsetms, args_playback_id);
diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c
index f9b3e85d26a19e9132c4d0a8159c5b2e2c3168d4..46dbedf38d07a7c2b4a763c227bf8645665b5dd9 100644
--- a/res/parking/parking_applications.c
+++ b/res/parking/parking_applications.c
@@ -819,12 +819,12 @@ static void announce_to_dial(char *dial_string, char *announce_string, int parki
 	snprintf(buf, sizeof(buf), "%d", parkingspace);
 	oh.vars = ast_variable_new("_PARKEDAT", buf, "");
 
-	inherit_channel_vars_from_id(&oh, parkee_snapshot->uniqueid);
+	inherit_channel_vars_from_id(&oh, parkee_snapshot->base->uniqueid);
 
 	dchan = __ast_request_and_dial(dial_tech, cap_slin, NULL, NULL, dial_string, 30000,
 		&outstate,
-		parkee_snapshot->caller_number,
-		parkee_snapshot->caller_name,
+		parkee_snapshot->caller->number,
+		parkee_snapshot->caller->name,
 		&oh);
 
 	ast_variables_destroy(oh.vars);
@@ -877,7 +877,7 @@ static void park_announce_update_cb(void *data, struct stasis_subscription *sub,
 		return;
 	}
 
-	if (strcmp(payload->parkee->uniqueid, pa_data->parkee_uuid)) {
+	if (strcmp(payload->parkee->base->uniqueid, pa_data->parkee_uuid)) {
 		/* We are only concerned with the parkee we are subscribed for. */
 		return;
 	}
diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c
index 1d3b9e4da8f9b2f27d30dda6ea3f09c88cfc8fee..d61947189e35cdd54e05702742a4a0f376f040e7 100644
--- a/res/parking/parking_bridge_features.c
+++ b/res/parking/parking_bridge_features.c
@@ -111,7 +111,7 @@ static void parker_parked_call_message_response(struct ast_parked_call_payload *
 	RAII_VAR(struct ast_channel *, parker, NULL, ast_channel_cleanup);
 	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
 
-	if (strcmp(parkee_to_act_on, parkee_snapshot->uniqueid)) {
+	if (strcmp(parkee_to_act_on, parkee_snapshot->base->uniqueid)) {
 		return;
 	}
 
diff --git a/res/res_chan_stats.c b/res/res_chan_stats.c
index bed95a03fb067d807ad6c09d3e97265a20bf70a4..e32498bab904c81685c12c77e7d3d4da2d3d9139 100644
--- a/res/res_chan_stats.c
+++ b/res/res_chan_stats.c
@@ -110,7 +110,7 @@ static void updates(void *data, struct stasis_subscription *sub,
 		int64_t age;
 
 		age = ast_tvdiff_ms(*stasis_message_timestamp(message),
-			update->new_snapshot->creationtime);
+			update->new_snapshot->base->creationtime);
 		ast_statsd_log("channels.calltime", AST_STATSD_TIMER, age);
 
 		/* And decrement the channel count */
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 41195be2b793796e46b6ed5e0d4eda4ebf889ead..d88024a80b074a23cfbf92b3e0f7c22cad6ee4de 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1351,7 +1351,7 @@ static int active_channels_to_str_cb(void *object, void *arg, int flags)
 {
 	const struct ast_channel_snapshot *snapshot = object;
 	struct ast_str **buf = arg;
-	ast_str_append(buf, 0, "%s,", snapshot->name);
+	ast_str_append(buf, 0, "%s,", snapshot->base->name);
 	return 0;
 }
 
diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c
index 3dfaabc445ab8b4dad6d8389aef4a09a5f1888f7..9b751469384888bc5f066362a8ccbfb2f0ba5d11 100644
--- a/res/res_pjsip_refer.c
+++ b/res/res_pjsip_refer.c
@@ -179,7 +179,7 @@ static void refer_progress_bridge(void *data, struct stasis_subscription *sub,
 	}
 
 	enter_blob = stasis_message_data(message);
-	if (strcmp(enter_blob->channel->uniqueid, progress->transferee)) {
+	if (strcmp(enter_blob->channel->base->uniqueid, progress->transferee)) {
 		/* Don't care */
 		return;
 	}
diff --git a/res/res_stasis.c b/res/res_stasis.c
index 704d779c48485b835750b8b89efe06b151135a15..43833e17cd3d785369bd68e017eea891548d6db9 100644
--- a/res/res_stasis.c
+++ b/res/res_stasis.c
@@ -1019,7 +1019,7 @@ static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app
 	}
 
 	if (replace_channel_snapshot) {
-		app_unsubscribe_channel_id(app, replace_channel_snapshot->uniqueid);
+		app_unsubscribe_channel_id(app, replace_channel_snapshot->base->uniqueid);
 	}
 	stasis_publish(ast_app_get_topic(app), msg);
 	ao2_ref(msg, -1);
@@ -2051,7 +2051,7 @@ static int unload_module(void)
 /* \brief Sanitization callback for channel snapshots */
 static int channel_snapshot_sanitizer(const struct ast_channel_snapshot *snapshot)
 {
-	if (!snapshot || !(snapshot->tech_properties & AST_CHAN_TP_INTERNAL)) {
+	if (!snapshot || !(snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL)) {
 		return 0;
 	}
 	return 1;
diff --git a/res/stasis/app.c b/res/stasis/app.c
index b4f3bc6cfc422413ede0122fb23dcd0e16b7572c..78f5765809d085fd67cf1cfa89959997efb26266 100644
--- a/res/stasis/app.c
+++ b/res/stasis/app.c
@@ -315,7 +315,7 @@ static void call_forwarded_handler(struct stasis_app *app, struct stasis_message
 		return;
 	}
 
-	chan = ast_channel_get_by_name(snapshot->uniqueid);
+	chan = ast_channel_get_by_name(snapshot->base->uniqueid);
 	if (!chan) {
 		return;
 	}
@@ -391,8 +391,8 @@ static struct ast_json *channel_destroyed_event(
 	return ast_json_pack("{s: s, s: o, s: i, s: s, s: o}",
 		"type", "ChannelDestroyed",
 		"timestamp", ast_json_timeval(*tv, NULL),
-		"cause", snapshot->hangupcause,
-		"cause_txt", ast_cause2str(snapshot->hangupcause),
+		"cause", snapshot->hangup->cause,
+		"cause_txt", ast_cause2str(snapshot->hangup->cause),
 		"channel", json_channel);
 }
 
@@ -436,7 +436,7 @@ static struct ast_json *channel_dialplan(
 	}
 
 	/* Empty application is not valid for a Newexten event */
-	if (ast_strlen_zero(new_snapshot->appl)) {
+	if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
 		return NULL;
 	}
 
@@ -452,8 +452,8 @@ static struct ast_json *channel_dialplan(
 	return ast_json_pack("{s: s, s: o, s: s, s: s, s: o}",
 		"type", "ChannelDialplan",
 		"timestamp", ast_json_timeval(*tv, NULL),
-		"dialplan_app", new_snapshot->appl,
-		"dialplan_app_data", AST_JSON_UTF8_VALIDATE(new_snapshot->data),
+		"dialplan_app", new_snapshot->dialplan->appl,
+		"dialplan_app_data", AST_JSON_UTF8_VALIDATE(new_snapshot->dialplan->data),
 		"channel", json_channel);
 }
 
@@ -481,9 +481,9 @@ static struct ast_json *channel_callerid(
 	return ast_json_pack("{s: s, s: o, s: i, s: s, s: o}",
 		"type", "ChannelCallerId",
 		"timestamp", ast_json_timeval(*tv, NULL),
-		"caller_presentation", new_snapshot->caller_pres,
+		"caller_presentation", new_snapshot->caller->pres,
 		"caller_presentation_txt", ast_describe_caller_presentation(
-			new_snapshot->caller_pres),
+			new_snapshot->caller->pres),
 		"channel", json_channel);
 }
 
@@ -541,7 +541,7 @@ static void sub_channel_update_handler(void *data,
 	}
 
 	if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
-		unsubscribe(app, "channel", update->new_snapshot->uniqueid, 1);
+		unsubscribe(app, "channel", update->new_snapshot->base->uniqueid, 1);
 	}
 }
 
@@ -768,7 +768,7 @@ static void bridge_blind_transfer_handler(void *data, struct stasis_subscription
 	struct ast_blind_transfer_message *transfer_msg = stasis_message_data(message);
 	struct ast_bridge_snapshot *bridge = transfer_msg->bridge;
 
-	if (bridge_app_subscribed(app, transfer_msg->transferer->uniqueid) ||
+	if (bridge_app_subscribed(app, transfer_msg->transferer->base->uniqueid) ||
 		(bridge && bridge_app_subscribed_involved(app, bridge))) {
 		stasis_publish(app->topic, message);
 	}
@@ -781,9 +781,9 @@ static void bridge_attended_transfer_handler(void *data, struct stasis_subscript
 	struct ast_attended_transfer_message *transfer_msg = stasis_message_data(message);
 	int subscribed = 0;
 
-	subscribed = bridge_app_subscribed(app, transfer_msg->to_transferee.channel_snapshot->uniqueid);
+	subscribed = bridge_app_subscribed(app, transfer_msg->to_transferee.channel_snapshot->base->uniqueid);
 	if (!subscribed) {
-		subscribed = bridge_app_subscribed(app, transfer_msg->to_transfer_target.channel_snapshot->uniqueid);
+		subscribed = bridge_app_subscribed(app, transfer_msg->to_transfer_target.channel_snapshot->base->uniqueid);
 	}
 	if (!subscribed && transfer_msg->to_transferee.bridge_snapshot) {
 		subscribed = bridge_app_subscribed_involved(app, transfer_msg->to_transferee.bridge_snapshot);
@@ -798,16 +798,16 @@ static void bridge_attended_transfer_handler(void *data, struct stasis_subscript
 			subscribed = bridge_app_subscribed(app, transfer_msg->dest.bridge);
 			break;
 		case AST_ATTENDED_TRANSFER_DEST_LINK:
-			subscribed = bridge_app_subscribed(app, transfer_msg->dest.links[0]->uniqueid);
+			subscribed = bridge_app_subscribed(app, transfer_msg->dest.links[0]->base->uniqueid);
 			if (!subscribed) {
-				subscribed = bridge_app_subscribed(app, transfer_msg->dest.links[1]->uniqueid);
+				subscribed = bridge_app_subscribed(app, transfer_msg->dest.links[1]->base->uniqueid);
 			}
 			break;
 		break;
 		case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
 			subscribed = bridge_app_subscribed_involved(app, transfer_msg->dest.threeway.bridge_snapshot);
 			if (!subscribed) {
-				subscribed = bridge_app_subscribed(app, transfer_msg->dest.threeway.channel_snapshot->uniqueid);
+				subscribed = bridge_app_subscribed(app, transfer_msg->dest.threeway.channel_snapshot->base->uniqueid);
 			}
 			break;
 		default:
diff --git a/tests/test_cel.c b/tests/test_cel.c
index c1e73403bd7d86c8e528565f5e15b77d2233f53b..6c8bd61866cf4a1b6ed42431cdc6b8b1ac5e76d1 100644
--- a/tests/test_cel.c
+++ b/tests/test_cel.c
@@ -329,7 +329,7 @@ static struct ast_str *__test_cel_generate_peer_str(struct ast_channel_snapshot
 			ao2_cleanup);
 
 		/* Don't add the channel for which this message is being generated */
-		if (!strcmp(current_chan, chan->uniqueid)) {
+		if (!strcmp(current_chan, chan->base->uniqueid)) {
 			continue;
 		}
 
@@ -338,7 +338,7 @@ static struct ast_str *__test_cel_generate_peer_str(struct ast_channel_snapshot
 			continue;
 		}
 
-		ast_str_append(&peer_str, 0, "%s,", current_snapshot->name);
+		ast_str_append(&peer_str, 0, "%s,", current_snapshot->base->name);
 	}
 	ao2_iterator_destroy(&i);
 
@@ -1668,8 +1668,8 @@ AST_TEST_DEFINE(test_cel_local_optimize)
 	stasis_publish(ast_channel_topic(chan_alice), local_opt_begin);
 	stasis_publish(ast_channel_topic(chan_alice), local_opt_end);
 
-	extra = ast_json_pack("{s: s, s: s}", "local_two", bob_snapshot->name,
-		"local_two_uniqueid", bob_snapshot->uniqueid);
+	extra = ast_json_pack("{s: s, s: s}", "local_two", bob_snapshot->base->name,
+		"local_two_uniqueid", bob_snapshot->base->uniqueid);
 	ast_test_validate(test, extra != NULL);
 
 	APPEND_EVENT_SNAPSHOT(alice_snapshot, AST_CEL_LOCAL_OPTIMIZE, NULL, extra, NULL);
diff --git a/tests/test_stasis_channels.c b/tests/test_stasis_channels.c
index f73d882e3c3cfc361a9e0d70f957a107e8a1394d..f8d2a03f818495150f1c04eea0e1bd950f107edd 100644
--- a/tests/test_stasis_channels.c
+++ b/tests/test_stasis_channels.c
@@ -220,12 +220,12 @@ AST_TEST_DEFINE(multi_channel_blob_snapshots)
 	/* Test for single match */
 	snapshot = ast_multi_channel_blob_get_channel(blob, "Caller");
 	ast_test_validate(test, NULL != snapshot);
-	ast_test_validate(test, 0 == strcmp("TEST/Alice", snapshot->name));
+	ast_test_validate(test, 0 == strcmp("TEST/Alice", snapshot->base->name));
 
 	/* Test for single match, multiple possibilities */
 	snapshot = ast_multi_channel_blob_get_channel(blob, "Peer");
 	ast_test_validate(test, NULL != snapshot);
-	ast_test_validate(test, 0 != strcmp("TEST/Alice", snapshot->name));
+	ast_test_validate(test, 0 != strcmp("TEST/Alice", snapshot->base->name));
 
 	/* Multi-match */
 	matches = ast_multi_channel_blob_get_channels(blob, "Peer");