[svn-commits] mmichelson: branch mmichelson/queue_bugbug r395139 - in /team/mmichelson/queu...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jul 23 10:16:22 CDT 2013


Author: mmichelson
Date: Tue Jul 23 10:16:20 2013
New Revision: 395139

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=395139
Log:
Re-rework local channel optimization handling.

I realized that because of the fact that multiple local
channel optimizations can be reported to me at once, and the
events for local channel optimizations occur after they have
already happened, it simply is not possible for me to get
an accurate picture of all channels involved.

The remedy for this problem is to restrict what types of local
channel optimization are permitted when using queues. The only
type of local channel optimization that is allowed is move-swap
optimization and it's only allowed to happen towards the queue
bridge. This means that the following types of local channels
will not be able to optimize out:

* A local channel between a queue and a multi-party bridge
* A local channel between two queues.

Luckily, this still means that an estimated 99.999% of queue
usage will still have local channel optimizations work properly.
In the cases where the local channels do not optimize away, the
calls will still work, but there may be more channels in use
than expected. Tough luck.


Modified:
    team/mmichelson/queue_bugbug/apps/app_queue.c
    team/mmichelson/queue_bugbug/include/asterisk/features.h
    team/mmichelson/queue_bugbug/main/features.c

Modified: team/mmichelson/queue_bugbug/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/queue_bugbug/apps/app_queue.c?view=diff&rev=395139&r1=395138&r2=395139
==============================================================================
--- team/mmichelson/queue_bugbug/apps/app_queue.c (original)
+++ team/mmichelson/queue_bugbug/apps/app_queue.c Tue Jul 23 10:16:20 2013
@@ -5171,17 +5171,19 @@
 }
 
 struct local_optimization {
-	char dest_bridge[AST_UUID_STR_LEN];
-	struct ao2_container *source_channels;
-	struct ao2_container *dest_channels;
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(source_chan_uniqueid);
+	);
+	int in_progress;
 	unsigned int id;
-	enum ast_unreal_channel_indicator dest;
 };
 
 struct queue_stasis_data {
-	char bridge_uniqueid[AST_UUID_STR_LEN];
-	struct ao2_container *callers;
-	struct ao2_container *agents;
+	AST_DECLARE_STRING_FIELDS(
+		AST_STRING_FIELD(caller_uniqueid);
+		AST_STRING_FIELD(agent_uniqueid);
+		AST_STRING_FIELD(bridge_uniqueid);
+	);
 	struct call_queue *queue;
 	struct member *member;
 	struct stasis_topic *caller_topic;
@@ -5192,7 +5194,8 @@
 	int dying;
 	struct stasis_subscription *bridge_sub;
 	struct stasis_subscription *channel_sub;
-	struct ao2_container *optimizations;
+	struct local_optimization caller_optimize;
+	struct local_optimization agent_optimize;
 };
 
 static void queue_stasis_data_destructor(void *obj)
@@ -5203,9 +5206,9 @@
 
 	ao2_cleanup(queue_data->member);
 	ao2_cleanup(queue_data->queue);
-	ao2_cleanup(queue_data->callers);
-	ao2_cleanup(queue_data->agents);
-	ao2_cleanup(queue_data->optimizations);
+	ast_string_field_free_memory(&queue_data->caller_optimize);
+	ast_string_field_free_memory(&queue_data->agent_optimize);
+	ast_string_field_free_memory(queue_data);
 }
 
 static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
@@ -5217,46 +5220,6 @@
 	queue_data->channel_sub = stasis_unsubscribe(queue_data->channel_sub);
 }
 
-static int optimization_hash(const void *obj, int flags)
-{
-	const struct local_optimization *optimize;
-	const unsigned int *key;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_KEY:
-		key = obj;
-		return *key;
-	case OBJ_PARTIAL_KEY:
-		ast_assert(0);
-		return 0;
-	case OBJ_POINTER:
-	default:
-		optimize = obj;
-		return optimize->id;
-	}
-}
-
-static int optimization_cmp(void *obj, void *arg, int flags)
-{
-	struct local_optimization *optimize1 = obj;
-	struct local_optimization *optimize2;
-	unsigned int *key2;
-
-	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
-	case OBJ_KEY:
-		key2 = arg;
-		return *key2 == optimize1->id ? CMP_MATCH : 0;
-	case OBJ_PARTIAL_KEY:
-		ast_assert(0);
-		return 0;
-	case OBJ_POINTER:
-		optimize2 = arg;
-		return optimize1->id == optimize2->id ? CMP_MATCH : 0;
-	default:
-		return CMP_STOP;
-	}
-}
-
 static struct queue_stasis_data *queue_stasis_data_alloc(struct queue_ent *qe,
 		struct ast_channel *peer, struct member *mem, time_t holdstart,
 		time_t starttime, int callcompletedinsl)
@@ -5268,26 +5231,16 @@
 		return NULL;
 	}
 
-	queue_data->callers = ast_str_container_alloc(5);
-	if (!queue_data->callers || ast_str_container_add(queue_data->callers, 
-				ast_channel_uniqueid(qe->chan))) {
+	if (ast_string_field_init(queue_data, 64) || ast_string_field_init(&queue_data->agent_optimize, 64) ||
+			ast_string_field_init(&queue_data->caller_optimize, 64)) {
 		ao2_cleanup(queue_data);
 		return NULL;
 	}
 
-	queue_data->agents = ast_str_container_alloc(5);
-	if (!queue_data->agents || ast_str_container_add(queue_data->agents,
-				ast_channel_uniqueid(peer))) {
-		ao2_cleanup(queue_data);
-		return NULL;
-	}
-
-	queue_data->optimizations = ao2_container_alloc(5, optimization_hash, optimization_cmp);
-	if (!queue_data->optimizations) {
-		ao2_cleanup(queue_data);
-		return NULL;
-	}
-
+	ast_string_field_set(queue_data, caller_uniqueid, ast_channel_uniqueid(qe->chan));
+	ast_log(LOG_NOTICE, "Initial caller uniqueid is %s\n", queue_data->caller_uniqueid);
+	ast_string_field_set(queue_data, agent_uniqueid, ast_channel_uniqueid(peer));
+	ast_log(LOG_NOTICE, "Initial agent uniqueid is %s\n", queue_data->agent_uniqueid);
 	queue_data->queue = queue_ref(qe->parent);
 	queue_data->starttime = starttime;
 	queue_data->holdstart = holdstart;
@@ -5313,29 +5266,20 @@
 	
 	if (ast_channel_entered_bridge_type() == stasis_message_type(msg)) {
 		struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
-		const char *caller;
 
 		if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
 			return;
 		}
 
-		caller = ao2_callback(queue_data->callers, 0, NULL, NULL);
-		
-		if (!caller) {
-			return;
-		}
-
-		if (!strcmp(enter_blob->channel->uniqueid, caller)) {
-			ast_copy_string(queue_data->bridge_uniqueid, enter_blob->bridge->uniqueid,
-					sizeof(queue_data->bridge_uniqueid));
+		if (!strcmp(enter_blob->channel->uniqueid, queue_data->caller_uniqueid)) {
+			ast_string_field_set(queue_data, bridge_uniqueid,
+					enter_blob->bridge->uniqueid);
 			ast_log(LOG_NOTICE, "Detected entry into bridge %s\n", queue_data->bridge_uniqueid);
 		}
 	} else if (ast_blind_transfer_type() == stasis_message_type(msg)) {
 		struct ast_bridge_blob *blind_blob = stasis_message_data(msg);
-		const char *caller;
-		const char *agent;
-		RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
-		RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
+		RAII_VAR(struct ast_channel_snapshot *, caller, NULL, ao2_cleanup);
+		RAII_VAR(struct ast_channel_snapshot *, agent, NULL, ao2_cleanup);
 
 		if (ast_json_integer_get(ast_json_object_get(blind_blob->blob, "result")) == AST_BRIDGE_TRANSFER_FAIL) {
 			return;
@@ -5348,32 +5292,27 @@
 			return;
 		}
 
-		caller = ao2_callback(queue_data->callers, 0, NULL, NULL);
-		agent = ao2_callback(queue_data->agents, 0, NULL, NULL);
-
-		caller_snapshot = ast_channel_snapshot_get_latest(caller);
-		agent_snapshot = ast_channel_snapshot_get_latest(agent);
+		caller = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
+		agent = ast_channel_snapshot_get_latest(queue_data->agent_uniqueid);
 
 		ao2_unlock(queue_data);
 
 		ast_log(LOG_NOTICE, "Detected blind transfer in queue %s\n", queue_data->queue->name);
-		ast_queue_log(queue_data->queue->name, caller, queue_data->member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
+		ast_queue_log(queue_data->queue->name, caller->uniqueid, queue_data->member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
 				ast_json_string_get(ast_json_object_get(blind_blob->blob, "exten")),
 				ast_json_string_get(ast_json_object_get(blind_blob->blob, "context")),
 				(long) queue_data->starttime - queue_data->holdstart,
 				(long) time(NULL) - queue_data->starttime, queue_data->caller_pos);
 
-		send_agent_complete(queue_data->queue->name, caller_snapshot, agent_snapshot, queue_data->member,
+		send_agent_complete(queue_data->queue->name, caller, agent, queue_data->member,
 				queue_data->holdstart, queue_data->starttime, TRANSFER);
 		update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
 				time(NULL) - queue_data->starttime);
 		remove_stasis_subscriptions(queue_data);
 	} else if (ast_attended_transfer_type() == stasis_message_type(msg)) {
 		struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
-		const char *caller;
-		const char *agent;
-		RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
-		RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
+		RAII_VAR(struct ast_channel_snapshot *, caller, NULL, ao2_cleanup);
+		RAII_VAR(struct ast_channel_snapshot *, agent, NULL, ao2_cleanup);
 
 		ast_log(LOG_NOTICE, "Getting a transfer event...\n");
 		/* BUGBUG Once atxfer_features is merged, we need to also return when
@@ -5398,11 +5337,8 @@
 			return;
 		}
 
-		caller = ao2_callback(queue_data->callers, 0, NULL, NULL);
-		agent = ao2_callback(queue_data->agents, 0, NULL, NULL);
-
-		caller_snapshot = ast_channel_snapshot_get_latest(caller);
-		agent_snapshot = ast_channel_snapshot_get_latest(agent);
+		caller = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
+		agent = ast_channel_snapshot_get_latest(queue_data->agent_uniqueid);
 
 		ao2_unlock(queue_data);
 
@@ -5411,7 +5347,7 @@
 		 * sense to specify an exten and context on an attended transfer. Perhaps separate queue log message
 		 * type?
 		 */
-		send_agent_complete(queue_data->queue->name, caller_snapshot, agent_snapshot, queue_data->member,
+		send_agent_complete(queue_data->queue->name, caller, agent, queue_data->member,
 				queue_data->holdstart, queue_data->starttime, TRANSFER);
 		update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
 				time(NULL) - queue_data->starttime);
@@ -5419,201 +5355,117 @@
 	}
 }
 
-static int get_ids(void *obj, void *arg, void *data, int flags)
-{
-	const char *peer_id = obj;
-	struct ao2_container *id_container = arg;
-	struct ast_channel_snapshot *exception = data;
-
-	if (strcmp(peer_id, exception->uniqueid)) {
-		ast_str_container_add(id_container, peer_id);
-	}
-
-	return 0;
-}
-
-static int get_channels(struct ao2_container *id_container, struct ast_channel_snapshot *snapshot)
-{
-	RAII_VAR(struct ast_bridge_snapshot *, bridge_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, peers, NULL, ao2_cleanup);
-
-	bridge_snapshot = ast_bridge_snapshot_get_latest(snapshot->bridgeid);
-
-	if (!bridge_snapshot) {
-		ast_log(LOG_NOTICE, "Channel %s has no bridge?\n", snapshot->name);
-		return -1;
-	}
-
-	ao2_callback_data(bridge_snapshot->channels, 0, get_ids, id_container, snapshot);
-	return 0;
-}
-
-static void optimize_destructor(void *obj)
-{
-	struct local_optimization *optimize = obj;
-
-	ao2_cleanup(optimize->source_channels);
-	ao2_cleanup(optimize->dest_channels);
-}
-
-static struct local_optimization *local_optimization_alloc(struct queue_stasis_data *queue_data,
-		unsigned int id, enum ast_unreal_channel_indicator dest, struct ast_channel_snapshot *local_one,
-		struct ast_channel_snapshot *local_two)
-{
-	RAII_VAR(struct local_optimization *, optimize, NULL, ao2_cleanup);
-
-	optimize = ao2_alloc(sizeof(*optimize), optimize_destructor);
-	if (!optimize) {
-		return NULL;
-	}
-
-	optimize->source_channels = ast_str_container_alloc(5);
-	if (!optimize->source_channels) {
-		return NULL;
-	}
-
-	optimize->dest_channels = ast_str_container_alloc(5);
-	if (!optimize->dest_channels) {
-		return NULL;
-	}
-
-	optimize->id = id;
-	optimize->dest = dest;
-	
-	if (get_channels(optimize->source_channels, dest == AST_UNREAL_OWNER ? local_two : local_one)) {
-		return NULL;
-	}
-
-	if (get_channels(optimize->dest_channels, dest == AST_UNREAL_OWNER ? local_one : local_two)) {
-		return NULL;
-	}
-
-	ast_copy_string(optimize->dest_bridge, dest == AST_UNREAL_OWNER ? local_one->bridgeid : local_two->bridgeid,
-			sizeof(optimize->dest_bridge));
-
-	ao2_ref(optimize, +1);
-	return optimize;
-}
-
 static void handle_local_optimization_begin(struct queue_stasis_data *queue_data, struct stasis_message *msg)
 {
-	RAII_VAR(struct local_optimization *, optimize, NULL, ao2_cleanup);
 	struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
 	struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
 	struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
-	enum ast_unreal_channel_indicator dest;
-	int bridge_on_local_one;
+	struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
+	struct local_optimization *optimization;
 	unsigned int id;
 
-	if (!strcmp(local_one->bridgeid, queue_data->bridge_uniqueid)) {
-		bridge_on_local_one = 1;
-	} else if (!strcmp(local_two->bridgeid, queue_data->bridge_uniqueid)) {
-		bridge_on_local_one = 0;
+	if (!strcmp(local_one->uniqueid, queue_data->agent_uniqueid)) {
+		optimization = &queue_data->agent_optimize;
+	} else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
+		optimization = &queue_data->caller_optimize;
 	} else {
-		/* We're not involved here */
 		return;
 	}
 
+	/* We only allow move-swap optimizations, so there had BETTER be a source */
+	ast_assert(source != NULL);
+
+	/* First going to make sure things are detected properly. */
+	ast_log(LOG_NOTICE, "OPTIMIZATION IS HAPPENING. PREPARE FOR DUMPAGE!\n");
+	ast_log(LOG_NOTICE, "Local ;1 channel is %s\n", local_one->name);
+	ast_log(LOG_NOTICE, "Local ;2 channel is %s\n", local_two->name);
+	ast_log(LOG_NOTICE, "Source channel is %s\n", source->name);
+
 	id = ast_json_integer_get(ast_json_object_get(ast_multi_channel_blob_get_json(optimization_blob), "id"));
-	dest = ast_json_integer_get(ast_json_object_get(ast_multi_channel_blob_get_json(optimization_blob), "dest"));
-
-	optimize = local_optimization_alloc(queue_data, id, dest, local_one, local_two);
-	if (!optimize) {
-		ast_log(LOG_WARNING, "Unable to deal properly with local optimization. Will not be able to report "
-				"when Queue call has been completed\n");
+	ast_log(LOG_NOTICE, "ID for optimization is %u\n", id);
+
+	ast_string_field_set(optimization, source_chan_uniqueid, source->uniqueid);
+
+	optimization->id = id;
+	optimization->in_progress = 1;
+}
+
+static void handle_local_optimization_end(struct queue_stasis_data *queue_data, struct stasis_message *msg)
+{
+	struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
+	struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
+	struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
+	struct local_optimization *optimization;
+	int is_caller;
+	unsigned int id;
+
+	if (!strcmp(local_one->uniqueid, queue_data->agent_uniqueid)) {
+		optimization = &queue_data->agent_optimize;
+		is_caller = 0;
+	} else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
+		optimization = &queue_data->caller_optimize;
+		is_caller = 1;
+	} else {
 		return;
 	}
-	ao2_link(queue_data->optimizations, optimize);
-
-	return;
-}
-
-static void update_ids(struct ao2_container *to_update, struct ao2_container *new_values)
-{
-	ao2_callback(to_update, OBJ_NOLOCK | OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, NULL, NULL);
-	ao2_container_dup(to_update, new_values, OBJ_NOLOCK);
-}
-
-static void handle_local_optimization_end(struct queue_stasis_data *queue_data, struct stasis_message *msg)
-{
-	struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
-	RAII_VAR(struct local_optimization *, optimize, NULL, ao2_cleanup);
-	unsigned int id;
-	unsigned int success;
 
 	id = ast_json_integer_get(ast_json_object_get(ast_multi_channel_blob_get_json(optimization_blob), "id"));
 
-	optimize = ao2_find(queue_data->optimizations, &id, OBJ_KEY | OBJ_UNLINK);
-	if (!optimize) {
+	if (!optimization->in_progress) {
+		ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
 		return;
 	}
 
-	success = ast_json_integer_get(ast_json_object_get(ast_multi_channel_blob_get_json(optimization_blob), "success"));
-	if (!success) {
-		/* If optimization was unsuccessful, we don't need to do anything */
+	if (id != optimization->id) {
+		ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
+				id, optimization->id);
 		return;
 	}
 
-	update_ids(optimize->dest == AST_UNREAL_OWNER ? queue_data->agents : queue_data->callers, optimize->source_channels);
-
-	if (strcmp(optimize->dest_bridge, queue_data->bridge_uniqueid)) {
-		update_ids(optimize->dest == AST_UNREAL_OWNER ? queue_data->callers : queue_data->agents, optimize->dest_channels);
-		ast_copy_string(queue_data->bridge_uniqueid, optimize->dest_bridge, sizeof(queue_data->bridge_uniqueid));
-	}
+	if (is_caller) {
+		ast_log(LOG_NOTICE, "Changing caller uniqueid from %s to %s\n",
+				queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
+		ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
+	} else {
+		ast_log(LOG_NOTICE, "Changing agent uniqueid from %s to %s\n",
+				queue_data->agent_uniqueid, optimization->source_chan_uniqueid);
+		ast_string_field_set(queue_data, agent_uniqueid, optimization->source_chan_uniqueid);
+	}
+
+	optimization->in_progress = 0;
 }
 
 static void handle_hangup(struct queue_stasis_data *queue_data, struct stasis_message *msg)
 {
 	struct ast_channel_blob *channel_blob = stasis_message_data(msg);
-	const char *caller;
-	const char *agent;
-	RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_channel_snapshot *, caller, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_channel_snapshot *, agent, NULL, ao2_cleanup);
 	enum agent_complete_reason reason;
-	const char *match;
 
 	ao2_lock(queue_data);
 
-	match = ao2_find(queue_data->callers, channel_blob->snapshot->uniqueid, OBJ_KEY | OBJ_NOLOCK | OBJ_UNLINK);
-	if (match) {
-		if (ao2_container_count(queue_data->callers) == 0) {
-			/* Last caller has hung up */
-			reason = CALLER;
-		} else {
-			/* Caller hung up, but others remain */
-			ao2_unlock(queue_data);
-			return;
-		}
+	if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->caller_uniqueid)) {
+		reason = CALLER;
+	} else if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->agent_uniqueid)) {
+		reason = AGENT;
 	} else {
-		match = ao2_find(queue_data->agents, channel_blob->snapshot->uniqueid, OBJ_KEY | OBJ_NOLOCK | OBJ_UNLINK);
-		if (match) {
-			if (ao2_container_count(queue_data->agents) == 0) {
-				/* Last agent has hung up */
-				reason = AGENT;
-			} else {
-				/* Agent hung up, but others remain */
-				ao2_unlock(queue_data);
-				return;
-			}
-		}
-	}
-
-	caller = reason == CALLER ? match : ao2_callback(queue_data->callers, 0, NULL, NULL);
-	agent = reason == AGENT ? match : ao2_callback(queue_data->agents, 0, NULL, NULL);
-
-	caller_snapshot = ast_channel_snapshot_get_latest(caller);
-	agent_snapshot = ast_channel_snapshot_get_latest(agent);
+		ao2_unlock(queue_data);
+		return;
+	}
+
+	caller = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
+	agent = ast_channel_snapshot_get_latest(queue_data->agent_uniqueid);
 
 	ao2_unlock(queue_data);
 
-	ast_queue_log(queue_data->queue->name, match, queue_data->member->membername,
+	ast_queue_log(queue_data->queue->name, caller->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);
 
 	ast_log(LOG_NOTICE, "Detected hangup request on channel %s\n", channel_blob->snapshot->name);
 
-	send_agent_complete(queue_data->queue->name, caller_snapshot, agent_snapshot, queue_data->member,
+	send_agent_complete(queue_data->queue->name, caller, agent, queue_data->member,
 			queue_data->holdstart, queue_data->starttime, reason);
 	update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
 			time(NULL) - queue_data->starttime);
@@ -6390,7 +6242,8 @@
 
 		time(&callstart);
 		setup_stasis_subs(qe, peer, member, qe->start, callstart, callcompletedinsl);
-		bridge = ast_bridge_call(qe->chan, peer, &bridge_config);
+		bridge = ast_bridge_call_with_flags(qe->chan, peer, &bridge_config,
+				AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM | AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM);
 
 		res = bridge ? bridge : 1;
 		ao2_ref(member, -1);

Modified: team/mmichelson/queue_bugbug/include/asterisk/features.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/queue_bugbug/include/asterisk/features.h?view=diff&rev=395139&r1=395138&r2=395139
==============================================================================
--- team/mmichelson/queue_bugbug/include/asterisk/features.h (original)
+++ team/mmichelson/queue_bugbug/include/asterisk/features.h Tue Jul 23 10:16:20 2013
@@ -168,6 +168,8 @@
 /*! \brief Bridge a call, optionally allowing redirection */
 int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer,struct ast_bridge_config *config);
 
+int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags);
+
 /*!
  * \brief Add an arbitrary channel to a bridge
  * \since 12.0.0

Modified: team/mmichelson/queue_bugbug/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/queue_bugbug/main/features.c?view=diff&rev=395139&r1=395138&r2=395139
==============================================================================
--- team/mmichelson/queue_bugbug/main/features.c (original)
+++ team/mmichelson/queue_bugbug/main/features.c Tue Jul 23 10:16:20 2013
@@ -3665,19 +3665,7 @@
 	return 0;
 }
 
-/*!
- * \brief bridge the call and set CDR
- *
- * \param chan The bridge considers this channel the caller.
- * \param peer The bridge considers this channel the callee.
- * \param config Configuration for this bridge.
- *
- * Set start time, check for two channels,check if monitor on
- * check for feature activation, create new CDR
- * \retval res on success.
- * \retval -1 on failure to bridge.
- */
-int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
+int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags)
 {
 	int res;
 	struct ast_bridge *bridge;
@@ -3709,6 +3697,8 @@
 		bridge_failed_peer_goto(chan, peer);
 		return -1;
 	}
+
+	ast_set_flag(&bridge->feature_flags, flags);
 
 	/* Put peer into the bridge */
 	if (ast_bridge_impart(bridge, peer, NULL, peer_features, 1)) {
@@ -3742,6 +3732,23 @@
 	}
 
 	return res;
+}
+
+/*!
+ * \brief bridge the call and set CDR
+ *
+ * \param chan The bridge considers this channel the caller.
+ * \param peer The bridge considers this channel the callee.
+ * \param config Configuration for this bridge.
+ *
+ * Set start time, check for two channels,check if monitor on
+ * check for feature activation, create new CDR
+ * \retval res on success.
+ * \retval -1 on failure to bridge.
+ */
+int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
+{
+	return ast_bridge_call_with_flags(chan, peer, config, 0);
 }
 
 /*! \brief Output parking event to manager */




More information about the svn-commits mailing list