add pickup endpoint and app to dptools add pickup/keyname to forked dial, then route a call to call app pickup(keyname) to have your channel return from originate. sub to pickup+keyname or presence map the pickup proto to use on blf

This commit is contained in:
Anthony Minessale 2012-05-04 18:59:25 -05:00
parent 5c66ab4793
commit 64d4d9ea57
4 changed files with 549 additions and 1 deletions

View File

@ -1211,6 +1211,7 @@ typedef enum {
CF_SERVICE_VIDEO,
CF_ZRTP_HASH,
CF_ZRTP_PASS,
CF_CHANNEL_SWAP,
/* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
/* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */
CF_FLAG_MAX

View File

@ -38,7 +38,8 @@
#include <switch.h>
SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load);
SWITCH_MODULE_DEFINITION(mod_dptools, mod_dptools_load, NULL, NULL);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_dptools_shutdown);
SWITCH_MODULE_DEFINITION(mod_dptools, mod_dptools_load, mod_dptools_shutdown, NULL);
SWITCH_STANDARD_DIALPLAN(inline_dialplan_hunt)
{
@ -3094,6 +3095,484 @@ SWITCH_STANDARD_APP(audio_bridge_function)
}
}
static struct {
switch_memory_pool_t *pool;
switch_hash_t *pickup_hash;
switch_mutex_t *pickup_mutex;
} globals;
/* pickup channel */
typedef struct pickup_node_s {
char *key;
char *uuid;
struct pickup_node_s *next;
} pickup_node_t;
#define PICKUP_PROTO "pickup"
static int EC = 0;
static int pickup_count(const char *key_name)
{
int count = 0;
pickup_node_t *head, *np;
switch_mutex_lock(globals.pickup_mutex);
if ((head = switch_core_hash_find(globals.pickup_hash, key_name))) {
for (np = head; np; np = np->next) count++;
}
switch_mutex_unlock(globals.pickup_mutex);
return count;
}
static void pickup_send_presence(const char *key_name)
{
char *domain_name, *dup_key_name = NULL, *dup_domain_name = NULL, *dup_id = NULL;
switch_event_t *event;
int count;
dup_key_name = strdup(key_name);
key_name = dup_key_name;
if ((domain_name = strchr(dup_key_name, '@'))) {
*domain_name++ = '\0';
}
if (zstr(domain_name)) {
dup_domain_name = switch_core_get_variable_dup("domain");
domain_name = dup_domain_name;
}
if (zstr(domain_name)) {
domain_name = "cluecon.com";
}
dup_id = switch_mprintf("%s@%s", key_name, domain_name);
count = pickup_count(dup_id);
if (count > 0) {
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", PICKUP_PROTO);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", dup_id);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", dup_id);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "force-status", "Active (%d call%s)", count, count == 1 ? "" : "s");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "active");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", key_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "confirmed");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
switch_event_fire(&event);
}
} else {
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", PICKUP_PROTO);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", dup_id);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", dup_id);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", "Idle");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", dup_id);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "terminated");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
switch_event_fire(&event);
}
}
switch_safe_free(dup_domain_name);
switch_safe_free(dup_key_name);
switch_safe_free(dup_id);
}
static void pickup_pres_event_handler(switch_event_t *event)
{
char *to = switch_event_get_header(event, "to");
char *dup_to = NULL, *key_name, *dup_key_name = NULL, *domain_name, *dup_domain_name = NULL;
int count = 0;
if (!to || strncasecmp(to, "pickup+", 7) || !strchr(to, '@')) {
return;
}
if (!(dup_to = strdup(to))) {
return;
}
key_name = dup_to + 7;
if ((domain_name = strchr(key_name, '@'))) {
*domain_name++ = '\0';
} else {
dup_domain_name = switch_core_get_variable_dup("domain");
domain_name = dup_domain_name;
}
if (zstr(domain_name)) {
switch_safe_free(dup_to);
return;
}
dup_key_name = switch_mprintf("%q@%q", key_name, domain_name);
count = pickup_count(dup_key_name);
switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN);
if (count) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", PICKUP_PROTO);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", key_name);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", key_name, domain_name);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "force-status", "Active (%d call%s)", count, count == 1 ? "" : "s");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "active");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", key_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "confirmed");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
} else {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", PICKUP_PROTO);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", key_name);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", key_name, domain_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", "Idle");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", key_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "terminated");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
}
switch_event_fire(&event);
switch_safe_free(dup_to);
switch_safe_free(dup_key_name);
switch_safe_free(dup_domain_name);
}
static void pickup_add_session(switch_core_session_t *session, const char *key)
{
pickup_node_t *head, *node, *np;
char *dup_key = NULL;
if (!strchr(key, '@')) {
dup_key = switch_mprintf("%s@%s", key, switch_core_get_variable("domain"));
key = dup_key;
}
node = malloc(sizeof(*node));
node->key = strdup(key);
node->uuid = strdup(switch_core_session_get_uuid(session));
node->next = NULL;
switch_mutex_lock(globals.pickup_mutex);
head = switch_core_hash_find(globals.pickup_hash, key);
if (head) {
for (np = head; np && np->next; np = np->next);
np->next = node;
} else {
head = node;
switch_core_hash_insert(globals.pickup_hash, key, head);
}
switch_mutex_unlock(globals.pickup_mutex);
pickup_send_presence(key);
switch_safe_free(dup_key);
}
static char *pickup_pop_uuid(const char *key, const char *uuid)
{
pickup_node_t *node = NULL, *head;
char *r = NULL;
char *dup_key = NULL;
if (!strchr(key, '@')) {
dup_key = switch_mprintf("%s@%s", key, switch_core_get_variable("domain"));
key = dup_key;
}
switch_mutex_lock(globals.pickup_mutex);
if ((head = switch_core_hash_find(globals.pickup_hash, key))) {
switch_core_hash_delete(globals.pickup_hash, key);
if (uuid) {
pickup_node_t *np, *lp = NULL;
for(np = head; np; np = np->next) {
if (!strcmp(np->uuid, uuid)) {
if (lp) {
lp->next = np->next;
} else {
head = np->next;
}
node = np;
break;
}
lp = np;
}
} else {
node = head;
head = head->next;
}
if (head) {
switch_core_hash_insert(globals.pickup_hash, key, head);
}
}
if (node) {
r = node->uuid;
free(node->key);
free(node);
}
switch_mutex_unlock(globals.pickup_mutex);
if (r) pickup_send_presence(key);
switch_safe_free(dup_key);
return r;
}
typedef struct pickup_pvt_s {
char *key;
switch_event_t *vars;
} pickup_pvt_t;
switch_endpoint_interface_t *pickup_endpoint_interface;
static switch_call_cause_t pickup_outgoing_channel(switch_core_session_t *session,
switch_event_t *var_event,
switch_caller_profile_t *outbound_profile,
switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags,
switch_call_cause_t *cancel_cause);
switch_io_routines_t pickup_io_routines = {
/*.outgoing_channel */ pickup_outgoing_channel
};
static switch_status_t pickup_event_handler(switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_channel_state_t state = switch_channel_get_running_state(channel);
pickup_pvt_t *tech_pvt = switch_core_session_get_private(session);
switch(state) {
case CS_DESTROY:
if (tech_pvt->vars) {
switch_event_destroy(&tech_pvt->vars);
}
break;
case CS_REPORTING:
return SWITCH_STATUS_FALSE;
case CS_HANGUP:
{
if (switch_channel_test_flag(channel, CF_CHANNEL_SWAP)) {
const char *key = switch_channel_get_variable(channel, "channel_swap_uuid");
switch_core_session_t *swap_session;
if ((swap_session = switch_core_session_locate(key))) {
switch_channel_t *swap_channel = switch_core_session_get_channel(swap_session);
switch_channel_hangup(swap_channel, SWITCH_CAUSE_PICKED_OFF);
switch_core_session_rwunlock(swap_session);
}
switch_channel_clear_flag(channel, CF_CHANNEL_SWAP);
}
pickup_pop_uuid(tech_pvt->key, switch_core_session_get_uuid(session));
}
break;
default:
break;
}
return SWITCH_STATUS_SUCCESS;
}
switch_state_handler_table_t pickup_event_handlers = {
/*.on_init */ pickup_event_handler,
/*.on_routing */ pickup_event_handler,
/*.on_execute */ pickup_event_handler,
/*.on_hangup */ pickup_event_handler,
/*.on_exchange_media */ pickup_event_handler,
/*.on_soft_execute */ pickup_event_handler,
/*.on_consume_media */ pickup_event_handler,
/*.on_hibernate */ pickup_event_handler,
/*.on_reset */ pickup_event_handler,
/*.on_park */ pickup_event_handler,
/*.on_reporting */ pickup_event_handler,
/*.on_destroy */ pickup_event_handler
};
static switch_call_cause_t pickup_outgoing_channel(switch_core_session_t *session,
switch_event_t *var_event,
switch_caller_profile_t *outbound_profile,
switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags,
switch_call_cause_t *cancel_cause)
{
char *pickup;
switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
switch_core_session_t *nsession;
switch_channel_t *nchannel;
char *name;
pickup_pvt_t *tech_pvt;
switch_caller_profile_t *caller_profile;
if (zstr(outbound_profile->destination_number)) {
goto done;
}
pickup = outbound_profile->destination_number;
if (!(nsession = switch_core_session_request(pickup_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, flags, pool))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
goto error;
}
tech_pvt = switch_core_session_alloc(nsession, sizeof(*tech_pvt));
tech_pvt->key = switch_core_session_strdup(nsession, pickup);
switch_event_dup(&tech_pvt->vars, var_event);
switch_core_session_set_private(nsession, tech_pvt);
nchannel = switch_core_session_get_channel(nsession);
caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
switch_channel_set_caller_profile(nchannel, caller_profile);
switch_channel_set_state(nchannel, CS_ROUTING);
*new_session = nsession;
cause = SWITCH_CAUSE_SUCCESS;
name = switch_core_session_sprintf(nsession, "pickup/%s", pickup);
switch_channel_set_name(nchannel, name);
switch_channel_set_variable(nchannel, "process_cdr", "false");
pickup_add_session(nsession, pickup);
goto done;
error:
if (nsession) {
switch_core_session_destroy(&nsession);
}
if (pool) {
*pool = NULL;
}
done:
return cause;
}
#define PICKUP_SYNTAX "[<key>]"
SWITCH_STANDARD_APP(pickup_function)
{
char *uuid = NULL;
switch_core_session_t *pickup_session;
switch_channel_t *channel = switch_core_session_get_channel(session);
if (zstr(data)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing data. Usage: pickup %s\n", PICKUP_SYNTAX);
return;
}
if ((uuid = pickup_pop_uuid((char *)data, NULL))) {
if ((pickup_session = switch_core_session_locate(uuid))) {
switch_channel_t *pickup_channel = switch_core_session_get_channel(pickup_session);
switch_caller_profile_t *pickup_caller_profile = switch_channel_get_caller_profile(pickup_channel),
*caller_profile = switch_channel_get_caller_profile(channel);
const char *name, *num;
switch_event_t *event;
switch_event_header_t *hp;
pickup_pvt_t *tech_pvt = switch_core_session_get_private(pickup_session);
for(hp = tech_pvt->vars->headers; hp; hp = hp->next) {
switch_channel_set_variable(channel, hp->name, hp->value);
}
switch_channel_set_flag(pickup_channel, CF_CHANNEL_SWAP);
switch_channel_set_variable(pickup_channel, "channel_swap_uuid", switch_core_session_get_uuid(session));
name = caller_profile->caller_id_name;
num = caller_profile->caller_id_number;
caller_profile->caller_id_name = switch_core_strdup(caller_profile->pool, pickup_caller_profile->caller_id_name);
caller_profile->caller_id_number = switch_core_strdup(caller_profile->pool, pickup_caller_profile->caller_id_number);
caller_profile->callee_id_name = name;
caller_profile->callee_id_number = num;
if (switch_event_create(&event, SWITCH_EVENT_CALL_UPDATE) == SWITCH_STATUS_SUCCESS) {
const char *uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Direction", "RECV");
if (!uuid) {
uuid = switch_channel_get_variable(channel, "originate_signal_bond");
}
if (uuid) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridged-To", uuid);
}
switch_channel_event_set_data(channel, event);
switch_event_fire(&event);
}
switch_channel_set_state(channel, CS_HIBERNATE);
switch_channel_mark_answered(pickup_channel);
switch_core_session_rwunlock(pickup_session);
}
free(uuid);
}
}
/* fake chan_error */
switch_endpoint_interface_t *error_endpoint_interface;
static switch_call_cause_t error_outgoing_channel(switch_core_session_t *session,
@ -3985,6 +4464,14 @@ static char *file_string_supported_formats[SWITCH_MAX_CODECS] = { 0 };
#define LOG_LONG_DESC "Logs a channel variable for the channel calling the application."
#define TRANSFER_LONG_DESC "Immediately transfer the calling channel to a new extension"
#define SLEEP_LONG_DESC "Pause the channel for a given number of milliseconds, consuming the audio for that period of time."
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_dptools_shutdown)
{
switch_event_unbind_callback(pickup_pres_event_handler);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
{
switch_api_interface_t *api_interface;
@ -3993,9 +4480,16 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
switch_chat_interface_t *chat_interface;
switch_file_interface_t *file_interface;
globals.pool = pool;
switch_core_hash_init(&globals.pickup_hash, NULL);
switch_mutex_init(&globals.pickup_mutex, SWITCH_MUTEX_NESTED, globals.pool);
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
switch_event_bind(modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, pickup_pres_event_handler, NULL);
file_string_supported_formats[0] = "file_string";
file_interface = (switch_file_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
@ -4019,6 +4513,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
user_endpoint_interface->interface_name = "user";
user_endpoint_interface->io_routines = &user_io_routines;
pickup_endpoint_interface = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
pickup_endpoint_interface->interface_name = "pickup";
pickup_endpoint_interface->io_routines = &pickup_io_routines;
pickup_endpoint_interface->state_handler = &pickup_event_handlers;
SWITCH_ADD_CHAT(chat_interface, "event", event_chat_send);
SWITCH_ADD_CHAT(chat_interface, "api", api_chat_send);
@ -4193,6 +4692,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
SWITCH_ADD_APP(app_interface, "limit_execute", "Limit", LIMITEXECUTE_DESC, limit_execute_function, LIMITEXECUTE_USAGE, SAF_SUPPORT_NOMEDIA);
SWITCH_ADD_APP(app_interface, "limit_hash_execute", "Limit", LIMITHASHEXECUTE_DESC, limit_hash_execute_function, LIMITHASHEXECUTE_USAGE, SAF_SUPPORT_NOMEDIA);
SWITCH_ADD_APP(app_interface, "pickup", "Pickup", "Pickup a call", pickup_function, PICKUP_SYNTAX, SAF_SUPPORT_NOMEDIA);
SWITCH_ADD_DIALPLAN(dp_interface, "inline", inline_dialplan_hunt);
/* indicate that the module should continue to be loaded */

View File

@ -1761,6 +1761,20 @@ static int sofia_dialog_probe_callback(void *pArg, int argc, char **argv, char *
remote_user = to_user;
remote_host = local_host;
}
else if (proto && !strcasecmp(proto, "pickup")) {
local_user = to_user;
local_user_param = switch_mprintf(";proto=%s", proto);
event_status = "hold";
if (skip_proto) {
buf_to_free = switch_mprintf("sip:%s", to_user);
} else {
buf_to_free = switch_mprintf("sip:pickup+%s", to_user);
}
remote_uri = buf_to_free;
strcpy(remote_display_buf, "pickup");
remote_user = to_user;
remote_host = local_host;
}
else if (proto && !strcasecmp(proto, "conf")) {
local_user = to_user;
local_user_param = switch_mprintf(";proto=%s", proto);
@ -2626,6 +2640,18 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
stream.write_function(&stream, "<target uri=\"sip:park+%s\"/>\n", uuid);
}
stream.write_function(&stream, "</remote>\n");
} else if (!strcasecmp(proto, "pickup")) {
stream.write_function(&stream, "<local>\n<identity display=\"pickup\">sip:%s@%s;proto=pickup</identity>\n",
!zstr(clean_to_user) ? clean_to_user : "unknown", host);
stream.write_function(&stream, "<target uri=\"sip:%s@%s;proto=pickup\">\n", !zstr(clean_to_user) ? clean_to_user : "unknown", host);
stream.write_function(&stream, "<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n</target>\n</local>\n");
stream.write_function(&stream, "<remote>\n<identity display=\"pickup\">sip:%s</identity>\n", uuid);
if (skip_proto) {
stream.write_function(&stream, "<target uri=\"sip:%s\"/>\n", uuid);
} else {
stream.write_function(&stream, "<target uri=\"sip:pickup+%s\"/>\n", uuid);
}
stream.write_function(&stream, "</remote>\n");
} else if (!strcasecmp(proto, "conf")) {
stream.write_function(&stream, "<local>\n<identity display=\"conference\">sip:%s@%s;proto=conference</identity>\n",
!zstr(clean_to_user) ? clean_to_user : "unknown", host);

View File

@ -3541,6 +3541,25 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
if (*bleg) {
switch_channel_t *bchan = switch_core_session_get_channel(*bleg);
if (switch_channel_test_flag(bchan, CF_CHANNEL_SWAP)) {
const char *key = switch_channel_get_variable(bchan, "channel_swap_uuid");
switch_core_session_t *swap_session, *old_session;
if ((swap_session = switch_core_session_locate(key))) {
switch_channel_clear_flag(bchan, CF_CHANNEL_SWAP);
switch_channel_hangup(bchan, SWITCH_CAUSE_PICKED_OFF);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(bchan), SWITCH_LOG_DEBUG, "Swapping %s for %s\n",
switch_core_session_get_name(swap_session), switch_channel_get_name(bchan));
old_session = *bleg;
*bleg = swap_session;
bchan = switch_core_session_get_channel(*bleg);
switch_channel_answer(bchan);
switch_core_session_rwunlock(old_session);
}
}
if (session && caller_channel) {