add transfer capability and small ways to test it

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@1290 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2006-04-28 19:46:57 +00:00
parent e1dc35f734
commit 35dc32018c
23 changed files with 501 additions and 104 deletions

View File

@ -1352,6 +1352,18 @@ DoxyDefine(apr_status_t switch_queue_trypop(switch_queue_t *queue, void **data);
DoxyDefine(apr_status_t switch_queue_trypush(switch_queue_t *queue, void *data);)
#define switch_queue_trypush apr_queue_trypush
typedef apr_thread_rwlock_t switch_thread_rwlock_t;
#define switch_thread_rwlock_create apr_thread_rwlock_create
#define switch_thread_rwlock_destroy apr_thread_rwlock_destroy
#define switch_thread_rwlock_pool_get apr_thread_rwlock_pool_get
#define switch_thread_rwlock_rdlock apr_thread_rwlock_rdlock
#define switch_thread_rwlock_tryrdlock apr_thread_rwlock_tryrdlock
#define switch_thread_rwlock_trywrlock apr_thread_rwlock_trywrlock
#define switch_thread_rwlock_unlock apr_thread_rwlock_unlock
#define switch_thread_rwlock_wrlock apr_thread_rwlock_wrlock
/**
* @defgroup switch_thread_mutex Thread Mutex Routines
* @ingroup switch_apr

View File

@ -87,6 +87,9 @@ struct switch_caller_profile {
char *chan_name;
/*! unique id */
char *uuid;
/*! context */
char *context;
struct switch_caller_profile *next;
};
/*! \brief An Abstract Representation of a dialplan Application */
@ -162,6 +165,7 @@ SWITCH_DECLARE(switch_caller_profile *) switch_caller_profile_new(switch_memory_
char *ani2,
char *rdnis,
char *source,
char *context,
char *destination_number);
/*!

View File

@ -41,14 +41,20 @@
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __FORMATBUG
}
#endif
#include <switch.h>
typedef struct {
struct switch_channel_timetable {
switch_time_t created;
switch_time_t answered;
switch_time_t hungup;
} switch_channel_timetable_t;
struct switch_channel_timetable *next;
};
typedef struct switch_channel_timetable switch_channel_timetable_t;
/**
* @defgroup switch_channel Channel Functions

View File

@ -118,6 +118,28 @@ SWITCH_DECLARE(switch_status) switch_core_destroy(void);
///\}
///\defgroup sh Read/Write Locking
///\ingroup core1
///\{
/*!
\brief Acquire a read lock on the session
\param session the session to acquire from
\return success if it is safe to read from the session
*/
SWITCH_DECLARE(switch_status) switch_core_session_read_lock(switch_core_session *session);
/*!
\brief Acquire a write lock on the session
\param session the session to acquire from
*/
SWITCH_DECLARE(void) switch_core_session_write_lock(switch_core_session *session);
/*!
\brief Unlock a read or write lock on as given session
\param session the session
*/
SWITCH_DECLARE(void) switch_core_session_rwunlock(switch_core_session *session);
///\}
///\defgroup sh State Handlers
///\ingroup core1
@ -277,6 +299,7 @@ SWITCH_DECLARE(char *) switch_core_session_get_uuid(switch_core_session *session
\brief Locate a session based on it's uuiid
\param uuid_str the unique id of the session you want to find
\return the session or NULL
\note if the session was located it will have a read lock obtained which will need to be released with switch_core_session_rwunlock()
*/
SWITCH_DECLARE(switch_core_session *) switch_core_session_locate(char *uuid_str);

View File

@ -167,6 +167,16 @@ SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_sessi
void *session_data,
void *peer_session_data);
/*!
\brief Transfer an existing session to another location
\param session the session to transfer
\param extension the new extension
\param dialplan the new dialplan (OPTIONAL, may be NULL)
\param context the new context (OPTIONAL, may be NULL)
*/
SWITCH_DECLARE(switch_status) switch_ivr_session_transfer(switch_core_session *session, char *extension, char *dialplan, char *context);
/** @} */
#ifdef __cplusplus

View File

@ -60,6 +60,8 @@ struct switch_state_handler_table {
switch_state_handler on_loopback;
/*! executed when the state changes to transmit*/
switch_state_handler on_transmit;
/*! executed when the state changes to hold*/
switch_state_handler on_hold;
};
/*! \brief Node in which to store custom outgoing channel callback hooks */

View File

@ -297,6 +297,7 @@ CS_RING - Channel is looking for a dialplan
CS_TRANSMIT - Channel is in a passive transmit state
CS_EXECUTE - Channel is executing it's dialplan
CS_LOOPBACK - Channel is in loopback
CS_HOLD - Channel is on hold
CS_HANGUP - Channel is flagged for hangup and ready to end
CS_DONE - Channel is ready to be destroyed and out of the state machine
</pre>
@ -308,6 +309,7 @@ typedef enum {
CS_TRANSMIT,
CS_EXECUTE,
CS_LOOPBACK,
CS_HOLD,
CS_HANGUP,
CS_DONE
} switch_channel_state;
@ -325,6 +327,8 @@ CF_ORIGINATOR = (1 << 3) - Channel is an originator
CF_TRANSFER = (1 << 4) - Channel is being transfered
CF_ACCEPT_CNG = (1 << 5) - Channel will accept CNG frames
CF_LOCK_THREAD = (1 << 6) - Prevent the channel thread from exiting while this flag is set
CF_BRIDGED = (1 << 7) - Channel in a bridge
CF_HOLD = (1 << 8) - Channel is on hold
</pre>
*/
@ -335,7 +339,9 @@ typedef enum {
CF_ORIGINATOR = (1 << 3),
CF_TRANSFER = (1 << 4),
CF_ACCEPT_CNG = (1 << 5),
CF_LOCK_THREAD = (1 << 6)
CF_LOCK_THREAD = (1 << 6),
CF_BRIDGED = (1 << 7),
CF_HOLD = (1 << 8)
} switch_channel_flag;

View File

@ -180,6 +180,8 @@ SWITCH_DECLARE(char *) switch_cut_path(char *in);
SWITCH_DECLARE(char *) switch_string_replace(const char *string, const char *search, const char *replace);
SWITCH_DECLARE(switch_status) switch_string_match(const char *string, size_t string_len, const char *search, size_t search_len);
#define SWITCH_READ_ACCEPTABLE(status) status == SWITCH_STATUS_SUCCESS || status == SWITCH_STATUS_BREAK
#ifdef __cplusplus
}
#endif

View File

@ -64,6 +64,7 @@ static void audio_bridge_function(switch_core_session *session, char *data)
NULL,
caller_caller_profile->rdnis,
caller_caller_profile->source,
caller_caller_profile->context,
chan_data);

View File

@ -49,6 +49,7 @@ static switch_status kill_function(char *dest, char *out, size_t outlen)
switch_channel *channel = switch_core_session_get_channel(session);
switch_core_session_kill_channel(session, SWITCH_SIG_KILL);
switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
switch_core_session_rwunlock(session);
snprintf(out, outlen, "OK\n");
} else {
snprintf(out, outlen, "No Such Channel!\n");
@ -58,11 +59,96 @@ static switch_status kill_function(char *dest, char *out, size_t outlen)
}
static switch_status transfer_function(char *cmd, char *out, size_t outlen)
{
switch_core_session *session = NULL;
char *argv[4] = {0};
int argc = 0;
argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 2 || argc > 4) {
snprintf(out, outlen, "Invalid Parameters\n");
} else {
char *uuid = argv[0];
char *dest = argv[1];
char *dp = argv[2];
char *context = argv[3];
if ((session = switch_core_session_locate(uuid))) {
if (switch_ivr_session_transfer(session, dest, dp, context) == SWITCH_STATUS_SUCCESS) {
snprintf(out, outlen, "OK\n");
} else {
snprintf(out, outlen, "ERROR\n");
}
switch_core_session_rwunlock(session);
} else {
snprintf(out, outlen, "No Such Channel!\n");
}
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status pause_function(char *cmd, char *out, size_t outlen)
{
switch_core_session *session = NULL;
char *argv[4] = {0};
int argc = 0;
argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
if (argc < 2) {
snprintf(out, outlen, "Invalid Parameters\n");
} else {
char *uuid = argv[0];
char *dest = argv[1];
if ((session = switch_core_session_locate(uuid))) {
switch_channel *channel = switch_core_session_get_channel(session);
if (!strcasecmp(dest, "on")) {
switch_channel_set_flag(channel, CF_HOLD);
} else {
switch_channel_clear_flag(channel, CF_HOLD);
}
switch_core_session_rwunlock(session);
} else {
snprintf(out, outlen, "No Such Channel!\n");
}
}
return SWITCH_STATUS_SUCCESS;
}
static struct switch_api_interface pause_api_interface = {
/*.interface_name */ "pause",
/*.desc */ "Pause",
/*.function */ pause_function,
/*.next */ NULL
};
static struct switch_api_interface transfer_api_interface = {
/*.interface_name */ "transfer",
/*.desc */ "Transfer",
/*.function */ transfer_function,
/*.next */ &pause_api_interface
};
static struct switch_api_interface load_api_interface = {
/*.interface_name */ "load",
/*.desc */ "Load Modile",
/*.function */ load_function,
/*.next */ NULL
/*.next */ &transfer_api_interface
};

View File

@ -87,6 +87,12 @@ static switch_caller_extension *dialplan_hunt(switch_core_session *session)
if (strcasecmp(exten_name, caller_profile->source)) {
skip = 1;
}
} else if (*exten_name == 'c' && *(exten_name+1) == ':') {
exten_name += 2;
if (strcasecmp(exten_name, caller_profile->context)) {
skip = 1;
}
}
}

View File

@ -89,6 +89,7 @@ struct mdl_profile {
char *extip;
char *lanaddr;
char *exten;
char *context;
ldl_handle_t *handle;
unsigned int flags;
};
@ -1246,6 +1247,8 @@ static switch_status load_config(void)
profile->lanaddr = switch_core_strdup(module_pool, val);
} else if (!strcmp(var, "exten")) {
profile->exten = switch_core_strdup(module_pool, val);
} else if (!strcmp(var, "context")) {
profile->context = switch_core_strdup(module_pool, val);
} else if (!strcmp(var, "vad")) {
if (!strcasecmp(val, "in")) {
switch_set_flag(profile, TFLAG_VAD_IN);
@ -1341,6 +1344,7 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi
NULL,
NULL,
(char *)modname,
profile->context,
profile->exten)) != 0) {
char name[128];
snprintf(name, sizeof(name), "DingaLing/%s-%04x", tech_pvt->caller_profile->destination_number,

View File

@ -1193,6 +1193,7 @@ static switch_status exosip_create_call(eXosip_event_t * event)
NULL,
NULL,
(char *)modname,
NULL,
event->request->req_uri->username)) != 0) {
switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
}

View File

@ -1004,6 +1004,7 @@ SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
NULL,
NULL,
(char *)modname,
NULL,
iaxevent->ies.called_number)) != 0) {
char name[128];
snprintf(name, sizeof(name), "IAX/%s-%04x", tech_pvt->caller_profile->destination_number,

View File

@ -811,7 +811,7 @@ static switch_status place_call(char *dest, char *out, size_t outlen)
if ((tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
globals.dialplan,
globals.cid_name,
globals.cid_num, NULL, NULL, NULL, NULL, (char *)modname, dest)) != 0) {
globals.cid_num, NULL, NULL, NULL, NULL, (char *)modname, NULL, dest)) != 0) {
char name[128];
snprintf(name, sizeof(name), "PortAudio/%s-%04x",
tech_pvt->caller_profile->destination_number ? tech_pvt->caller_profile->

View File

@ -1135,6 +1135,7 @@ static int on_ring(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri
NULL,
NULL,
(char *)modname,
NULL,
event->ring.callednum))) {
switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
}

View File

@ -1068,7 +1068,7 @@ static void *woomera_channel_thread_run(switch_thread *thread, void *obj)
if ((tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
tech_pvt->profile->dialplan,
cid_name, cid_num, ip, NULL, NULL, NULL, (char *)modname, exten)) != 0) {
cid_name, cid_num, ip, NULL, NULL, NULL, (char *)modname, NULL, exten)) != 0) {
char name[128];
snprintf(name, sizeof(name), "Woomera/%s-%04x", tech_pvt->caller_profile->destination_number,
rand() & 0xffff);

View File

@ -45,7 +45,7 @@ static void event_handler(switch_event *event)
return;
default:
switch_event_serialize(event, buf, sizeof(buf), NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\nEVENT\n--------------------------------\n%s\n", buf);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "\nEVENT\n--------------------------------\n%s\n", buf);
break;
}
}

View File

@ -980,6 +980,7 @@ static JSBool session_construct(JSContext *cx, JSObject *obj, uintN argc, jsval
char *ani = "";
char *ani2 = "";
char *rdnis = "";
char *context = "";
*rval = BOOLEAN_TO_JSVAL( JS_FALSE );
@ -997,30 +998,34 @@ static JSBool session_construct(JSContext *cx, JSObject *obj, uintN argc, jsval
dialplan = JS_GetStringBytes(JS_ValueToString(cx, argv[3]));
}
if (argc > 4) {
cid_name = JS_GetStringBytes(JS_ValueToString(cx, argv[4]));
context = JS_GetStringBytes(JS_ValueToString(cx, argv[4]));
}
if (argc > 5) {
cid_num = JS_GetStringBytes(JS_ValueToString(cx, argv[5]));
cid_name = JS_GetStringBytes(JS_ValueToString(cx, argv[5]));
}
if (argc > 6) {
network_addr = JS_GetStringBytes(JS_ValueToString(cx, argv[6]));
cid_num = JS_GetStringBytes(JS_ValueToString(cx, argv[6]));
}
if (argc > 7) {
ani = JS_GetStringBytes(JS_ValueToString(cx, argv[7]));
network_addr = JS_GetStringBytes(JS_ValueToString(cx, argv[7]));
}
if (argc > 8) {
ani2 = JS_GetStringBytes(JS_ValueToString(cx, argv[8]));
ani = JS_GetStringBytes(JS_ValueToString(cx, argv[8]));
}
if (argc > 9) {
rdnis = JS_GetStringBytes(JS_ValueToString(cx, argv[9]));
ani2 = JS_GetStringBytes(JS_ValueToString(cx, argv[9]));
}
if (argc > 10) {
rdnis = JS_GetStringBytes(JS_ValueToString(cx, argv[10]));
}
if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
return JS_FALSE;
}
caller_profile = switch_caller_profile_new(pool, dialplan, cid_name, cid_num, network_addr, ani, ani2, rdnis, (char *)modname, dest);
caller_profile = switch_caller_profile_new(pool, dialplan, cid_name, cid_num, network_addr, ani, ani2, rdnis, (char *)modname, context, dest);
if (switch_core_session_outgoing_channel(session, channel_type, caller_profile, &peer_session, pool) == SWITCH_STATUS_SUCCESS) {
jss = switch_core_session_alloc(peer_session, sizeof(*jss));
jss->session = peer_session;

View File

@ -40,6 +40,7 @@ SWITCH_DECLARE(switch_caller_profile *) switch_caller_profile_new(switch_memory_
char *ani2,
char *rdnis,
char *source,
char *context,
char *destination_number)
{
@ -47,6 +48,9 @@ SWITCH_DECLARE(switch_caller_profile *) switch_caller_profile_new(switch_memory_
switch_caller_profile *profile = NULL;
if ((profile = switch_core_alloc(pool, sizeof(switch_caller_profile))) != 0) {
if (!context) {
context = "default";
}
profile->dialplan = switch_core_strdup(pool, dialplan);
profile->caller_id_name = switch_core_strdup(pool, caller_id_name);
profile->caller_id_number = switch_core_strdup(pool, caller_id_number);
@ -55,6 +59,7 @@ SWITCH_DECLARE(switch_caller_profile *) switch_caller_profile_new(switch_memory_
profile->ani2 = switch_core_strdup(pool, ani2);
profile->rdnis = switch_core_strdup(pool, rdnis);
profile->source = switch_core_strdup(pool, source);
profile->context = switch_core_strdup(pool, context);
profile->destination_number = switch_core_strdup(pool, destination_number);
}
@ -77,6 +82,7 @@ SWITCH_DECLARE(switch_caller_profile *) switch_caller_profile_clone(switch_core_
profile->destination_number = switch_core_session_strdup(session, tocopy->destination_number);
profile->uuid = switch_core_session_strdup(session, tocopy->uuid);
profile->source = switch_core_session_strdup(session, tocopy->source);
profile->context = switch_core_session_strdup(session, tocopy->context);
profile->chan_name = switch_core_session_strdup(session, tocopy->chan_name);
}
@ -121,9 +127,13 @@ SWITCH_DECLARE(void) switch_caller_profile_event_set_data(switch_caller_profile
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->uuid);
}
if (caller_profile->source) {
snprintf(header_name, sizeof(header_name), "%s-RDNIS", prefix);
snprintf(header_name, sizeof(header_name), "%s-Source", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->source);
}
if (caller_profile->context) {
snprintf(header_name, sizeof(header_name), "%s-Context", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->context);
}
if (caller_profile->rdnis) {
snprintf(header_name, sizeof(header_name), "%s-RDNIS", prefix);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->rdnis);

View File

@ -89,6 +89,7 @@ struct switch_channel {
char *name;
switch_buffer *dtmf_buffer;
switch_mutex_t *dtmf_mutex;
switch_mutex_t *profile_mutex;
switch_core_session *session;
switch_channel_state state;
uint32_t flags;
@ -99,7 +100,7 @@ struct switch_channel {
const struct switch_state_handler_table *state_handlers[SWITCH_MAX_STATE_HANDLERS];
int state_handler_index;
switch_hash *variables;
switch_channel_timetable_t times;
switch_channel_timetable_t *times;
void *private_info;
switch_call_cause_t hangup_cause;
int freq;
@ -144,7 +145,7 @@ SWITCH_DECLARE(switch_call_cause_t) switch_channel_get_cause(switch_channel *cha
SWITCH_DECLARE(switch_channel_timetable_t *) switch_channel_get_timetable(switch_channel *channel)
{
return &channel->times;
return channel->times;
}
SWITCH_DECLARE(switch_status) switch_channel_alloc(switch_channel **channel, switch_memory_pool *pool)
@ -158,7 +159,7 @@ SWITCH_DECLARE(switch_status) switch_channel_alloc(switch_channel **channel, swi
switch_core_hash_init(&(*channel)->variables, pool);
switch_buffer_create(pool, &(*channel)->dtmf_buffer, 128);
switch_mutex_init(&(*channel)->dtmf_mutex, SWITCH_MUTEX_NESTED, pool);
(*channel)->times.created = switch_time_now();
switch_mutex_init(&(*channel)->profile_mutex, SWITCH_MUTEX_NESTED, pool);
(*channel)->hangup_cause = SWITCH_CAUSE_UNALLOCATED;
return SWITCH_STATUS_SUCCESS;
@ -297,8 +298,9 @@ SWITCH_DECLARE(switch_status) switch_channel_set_name(switch_channel *channel, c
assert(channel != NULL);
channel->name = NULL;
if (name) {
char *uuid = switch_core_session_get_uuid(channel->session);
channel->name = switch_core_session_strdup(channel->session, name);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "New Channel %s\n", name);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "New Chan %s [%s]\n", name, uuid);
}
return SWITCH_STATUS_SUCCESS;
}
@ -354,6 +356,7 @@ static const char *state_names[] = {
"CS_TRANSMIT",
"CS_EXECUTE",
"CS_LOOPBACK",
"CS_HOLD",
"CS_HANGUP",
"CS_DONE"
};
@ -418,6 +421,7 @@ SWITCH_DECLARE(switch_channel_state) switch_channel_perform_set_state(switch_cha
case CS_TRANSMIT:
case CS_RING:
case CS_EXECUTE:
case CS_HOLD:
ok++;
default:
break;
@ -429,6 +433,7 @@ SWITCH_DECLARE(switch_channel_state) switch_channel_perform_set_state(switch_cha
case CS_TRANSMIT:
case CS_RING:
case CS_EXECUTE:
case CS_HOLD:
ok++;
default:
break;
@ -440,6 +445,19 @@ SWITCH_DECLARE(switch_channel_state) switch_channel_perform_set_state(switch_cha
case CS_LOOPBACK:
case CS_RING:
case CS_EXECUTE:
case CS_HOLD:
ok++;
default:
break;
}
break;
case CS_HOLD:
switch (state) {
case CS_LOOPBACK:
case CS_RING:
case CS_EXECUTE:
case CS_TRANSMIT:
ok++;
default:
break;
@ -447,10 +465,12 @@ SWITCH_DECLARE(switch_channel_state) switch_channel_perform_set_state(switch_cha
break;
case CS_RING:
switch_clear_flag(channel, CF_TRANSFER);
switch (state) {
case CS_LOOPBACK:
case CS_EXECUTE:
case CS_TRANSMIT:
case CS_HOLD:
ok++;
default:
break;
@ -462,6 +482,7 @@ SWITCH_DECLARE(switch_channel_state) switch_channel_perform_set_state(switch_cha
case CS_LOOPBACK:
case CS_TRANSMIT:
case CS_RING:
case CS_HOLD:
ok++;
default:
break;
@ -569,8 +590,11 @@ SWITCH_DECLARE(void) switch_channel_event_set_data(switch_channel *channel, swit
SWITCH_DECLARE(void) switch_channel_set_caller_profile(switch_channel *channel, switch_caller_profile *caller_profile)
{
switch_channel_timetable_t *times;
assert(channel != NULL);
assert(channel->session != NULL);
switch_mutex_lock(channel->profile_mutex);
if (!caller_profile->uuid) {
caller_profile->uuid = switch_core_session_strdup(channel->session, switch_core_session_get_uuid(channel->session));
@ -587,35 +611,62 @@ SWITCH_DECLARE(void) switch_channel_set_caller_profile(switch_channel *channel,
switch_channel_event_set_data(channel, event);
switch_event_fire(&event);
}
}
if ((times = (switch_channel_timetable_t *) switch_core_session_alloc(channel->session, sizeof(*times)))) {
times->next = channel->times;
channel->times = times;
}
channel->times->created = switch_time_now();
caller_profile->next = channel->caller_profile;
channel->caller_profile = caller_profile;
switch_mutex_unlock(channel->profile_mutex);
}
SWITCH_DECLARE(switch_caller_profile *) switch_channel_get_caller_profile(switch_channel *channel)
{
switch_caller_profile *profile;
assert(channel != NULL);
return channel->caller_profile;
switch_mutex_lock(channel->profile_mutex);
profile = channel->caller_profile;
switch_mutex_unlock(channel->profile_mutex);
return profile;
}
SWITCH_DECLARE(void) switch_channel_set_originator_caller_profile(switch_channel *channel,
switch_caller_profile *caller_profile)
{
assert(channel != NULL);
switch_mutex_lock(channel->profile_mutex);
caller_profile->next = channel->originator_caller_profile;
channel->originator_caller_profile = caller_profile;
switch_mutex_unlock(channel->profile_mutex);
}
SWITCH_DECLARE(void) switch_channel_set_originatee_caller_profile(switch_channel *channel,
switch_caller_profile *caller_profile)
{
assert(channel != NULL);
switch_mutex_lock(channel->profile_mutex);
caller_profile->next = channel->originatee_caller_profile;
channel->originatee_caller_profile = caller_profile;
switch_mutex_unlock(channel->profile_mutex);
}
SWITCH_DECLARE(switch_caller_profile *) switch_channel_get_originator_caller_profile(switch_channel *channel)
{
switch_caller_profile *profile;
assert(channel != NULL);
return channel->originator_caller_profile;
switch_mutex_lock(channel->profile_mutex);
profile = channel->originator_caller_profile;
switch_mutex_unlock(channel->profile_mutex);
return profile;
}
SWITCH_DECLARE(char *) switch_channel_get_uuid(switch_channel *channel)
@ -627,8 +678,14 @@ SWITCH_DECLARE(char *) switch_channel_get_uuid(switch_channel *channel)
SWITCH_DECLARE(switch_caller_profile *) switch_channel_get_originatee_caller_profile(switch_channel *channel)
{
switch_caller_profile *profile;
assert(channel != NULL);
return channel->originatee_caller_profile;
switch_mutex_lock(channel->profile_mutex);
profile = channel->originatee_caller_profile;
switch_mutex_unlock(channel->profile_mutex);
return profile;
}
SWITCH_DECLARE(int) switch_channel_add_state_handler(switch_channel *channel,
@ -704,8 +761,8 @@ SWITCH_DECLARE(switch_channel_state) switch_channel_perform_hangup(switch_channe
{
assert(channel != NULL);
if (!channel->times.hungup) {
channel->times.hungup = switch_time_now();
if (!channel->times->hungup) {
channel->times->hungup = switch_time_now();
}
if (channel->state < CS_HANGUP) {
@ -769,7 +826,7 @@ SWITCH_DECLARE(switch_status) switch_channel_perform_answer(switch_channel *chan
if (switch_core_session_answer_channel(channel->session) == SWITCH_STATUS_SUCCESS) {
switch_event *event;
channel->times.answered = switch_time_now();
channel->times->answered = switch_time_now();
switch_channel_set_flag(channel, CF_ANSWERED);
switch_log_printf(SWITCH_CHANNEL_ID_LOG, (char *) file, func, line, SWITCH_LOG_NOTICE, "Answer %s!\n", channel->name);
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_ANSWER) == SWITCH_STATUS_SUCCESS) {

View File

@ -69,6 +69,8 @@ struct switch_core_session {
switch_mutex_t *mutex;
switch_thread_cond_t *cond;
switch_thread_rwlock_t *rwlock;
void *streams[SWITCH_MAX_STREAMS];
int stream_count;
@ -101,6 +103,7 @@ static void switch_core_standard_on_ring(switch_core_session *session);
static void switch_core_standard_on_execute(switch_core_session *session);
static void switch_core_standard_on_loopback(switch_core_session *session);
static void switch_core_standard_on_transmit(switch_core_session *session);
static void switch_core_standard_on_hold(switch_core_session *session);
/* The main runtime obj we keep this hidden for ourselves */
@ -223,37 +226,70 @@ SWITCH_DECLARE(const switch_state_handler_table *) switch_core_get_state_handler
return runtime.state_handlers[index];
}
SWITCH_DECLARE(switch_status) switch_core_session_read_lock(switch_core_session *session)
{
return (switch_status) switch_thread_rwlock_tryrdlock(session->rwlock);
}
SWITCH_DECLARE(void) switch_core_session_write_lock(switch_core_session *session)
{
switch_thread_rwlock_wrlock(session->rwlock);
}
SWITCH_DECLARE(void) switch_core_session_rwunlock(switch_core_session *session)
{
switch_thread_rwlock_unlock(session->rwlock);
}
SWITCH_DECLARE(switch_core_session *) switch_core_session_locate(char *uuid_str)
{
switch_core_session *session;
session = switch_core_hash_find(runtime.session_table, uuid_str);
if ((session = switch_core_hash_find(runtime.session_table, uuid_str))) {
/* Acquire a read lock on the session */
if (switch_thread_rwlock_tryrdlock(session->rwlock) != SWITCH_STATUS_SUCCESS) {
/* not available, forget it */
session = NULL;
}
}
/* if its not NULL, now it's up to you to rwunlock this */
return session;
}
SWITCH_DECLARE(switch_status) switch_core_session_message_send(char *uuid_str, switch_core_session_message *message)
{
switch_core_session *session = NULL;
switch_status status = SWITCH_STATUS_FALSE;
if ((session = switch_core_hash_find(runtime.session_table, uuid_str)) != 0) {
if (switch_channel_get_state(session->channel) < CS_HANGUP) {
return switch_core_session_receive_message(session, message);
/* Acquire a read lock on the session or forget it the channel is dead */
if (switch_thread_rwlock_tryrdlock(session->rwlock) == SWITCH_STATUS_SUCCESS) {
if (switch_channel_get_state(session->channel) < CS_HANGUP) {
status = switch_core_session_receive_message(session, message);
}
switch_thread_rwlock_unlock(session->rwlock);
}
}
return SWITCH_STATUS_FALSE;
return status;
}
SWITCH_DECLARE(switch_status) switch_core_session_event_send(char *uuid_str, switch_event *event)
{
switch_core_session *session = NULL;
switch_status status = SWITCH_STATUS_FALSE;
if ((session = switch_core_hash_find(runtime.session_table, uuid_str)) != 0) {
if (switch_channel_get_state(session->channel) < CS_HANGUP) {
return switch_core_session_queue_event(session, event);
/* Acquire a read lock on the session or forget it the channel is dead */
if (switch_thread_rwlock_tryrdlock(session->rwlock) == SWITCH_STATUS_SUCCESS) {
if (switch_channel_get_state(session->channel) < CS_HANGUP) {
status = switch_core_session_queue_event(session, event);
}
switch_thread_rwlock_unlock(session->rwlock);
}
}
return SWITCH_STATUS_FALSE;
return status;
}
SWITCH_DECLARE(char *) switch_core_session_get_uuid(switch_core_session *session)
@ -987,6 +1023,10 @@ SWITCH_DECLARE(switch_status) switch_core_session_read_frame(switch_core_session
assert(session != NULL);
*frame = NULL;
while (switch_channel_test_flag(session->channel, CF_HOLD)) {
return SWITCH_STATUS_BREAK;
}
if (session->endpoint_interface->io_routines->read_frame) {
if ((status = session->endpoint_interface->io_routines->read_frame(session,
frame,
@ -1175,6 +1215,10 @@ SWITCH_DECLARE(switch_status) switch_core_session_write_frame(switch_core_sessio
assert(frame != NULL);
assert(frame->codec != NULL);
if (switch_channel_test_flag(session->channel, CF_HOLD)) {
return SWITCH_STATUS_SUCCESS;
}
if (switch_test_flag(frame, SFF_CNG)) {
if (switch_channel_test_flag(session->channel, CF_ACCEPT_CNG)) {
@ -1803,6 +1847,12 @@ static void switch_core_standard_on_transmit(switch_core_session *session)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard TRANSMIT\n");
}
static void switch_core_standard_on_hold(switch_core_session *session)
{
assert(session != NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard HOLD\n");
}
SWITCH_DECLARE(void) switch_core_session_signal_state_change(switch_core_session *session)
{
switch_thread_cond_signal(session->cond);
@ -1855,7 +1905,7 @@ static int handle_fatality(int sig)
print_trace();
longjmp(*env, sig);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Caught SEGV for unmapped thread!");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Caught signal %d for unmapped thread!", sig);
abort();
}
@ -2150,6 +2200,43 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session *session)
}
}
break;
case CS_HOLD: /* wait in limbo */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State HOLD\n", switch_channel_get_name(session->channel));
if (!driver_state_handler->on_hold ||
(driver_state_handler->on_hold &&
driver_state_handler->on_hold(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
while((application_state_handler = switch_channel_get_state_handler(session->channel, index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_hold ||
(application_state_handler->on_hold &&
application_state_handler->on_hold(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
index = 0;
while(proceed && (application_state_handler = switch_core_get_state_handler(index++)) != 0) {
if (!application_state_handler || !application_state_handler->on_hold ||
(application_state_handler->on_hold &&
application_state_handler->on_hold(session) == SWITCH_STATUS_SUCCESS &&
midstate == switch_channel_get_state(session->channel))) {
proceed++;
continue;
} else {
proceed = 0;
break;
}
}
if (proceed) {
switch_core_standard_on_hold(session);
}
}
break;
}
if (midstate == CS_DONE) {
@ -2282,13 +2369,11 @@ static void *SWITCH_THREAD_FUNC switch_core_session_thread(switch_thread *thread
switch_core_hash_insert(runtime.session_table, session->uuid_str, session);
switch_core_session_run(session);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Session %u (%s) Locked, Waiting on external entities\n", session->id, switch_channel_get_name(session->channel));
switch_core_session_write_lock(session);
switch_core_session_rwunlock(session);
if (switch_channel_test_flag(session->channel, CF_LOCK_THREAD)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Session %u (%s) Locked\n", session->id, switch_channel_get_name(session->channel));
while(switch_channel_test_flag(session->channel, CF_LOCK_THREAD)) {
switch_yield(10000);
}
}
switch_core_hash_delete(runtime.session_table, session->uuid_str);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Session %u (%s) Ended\n", session->id, switch_channel_get_name(session->channel));
switch_core_session_destroy(&session);
@ -2393,6 +2478,7 @@ SWITCH_DECLARE(switch_core_session *) switch_core_session_request(const switch_e
switch_mutex_init(&session->mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_thread_cond_create(&session->cond, session->pool);
switch_thread_rwlock_create(&session->rwlock, session->pool);
return session;
}

View File

@ -63,7 +63,9 @@ SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_callback(switch_core_ses
break;
}
if (switch_core_session_read_frame(session, &read_frame, -1, 0) != SWITCH_STATUS_SUCCESS) {
status = switch_core_session_read_frame(session, &read_frame, -1, 0);
if (!SWITCH_READ_ACCEPTABLE(status)) {
break;
}
}
@ -135,7 +137,9 @@ SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_count(switch_core_sessio
}
}
if (poll_channel) {
if ((status = switch_core_session_read_frame(session, &read_frame, -1, 0)) != SWITCH_STATUS_SUCCESS) {
status = switch_core_session_read_frame(session, &read_frame, -1, 0);
if (!SWITCH_READ_ACCEPTABLE(status)) {
break;
}
} else {
@ -230,7 +234,8 @@ SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *sessio
}
}
if ((status = switch_core_session_read_frame(session, &read_frame, -1, 0)) != SWITCH_STATUS_SUCCESS) {
status = switch_core_session_read_frame(session, &read_frame, -1, 0);
if (!SWITCH_READ_ACCEPTABLE(status)) {
break;
}
if (!switch_test_flag(fh, SWITCH_FILE_PAUSE)) {
@ -449,7 +454,12 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
}
} else { /* time off the channel (if you must) */
switch_frame *read_frame;
if (switch_core_session_read_frame(session, &read_frame, -1, 0) != SWITCH_STATUS_SUCCESS) {
while (switch_channel_test_flag(channel, CF_HOLD)) {
switch_yield(10000);
}
switch_status status = switch_core_session_read_frame(session, &read_frame, -1, 0);
if (!SWITCH_READ_ACCEPTABLE(status)) {
break;
}
}
@ -655,7 +665,13 @@ SWITCH_DECLARE(switch_status) switch_ivr_speak_text(switch_core_session *session
}
} else { /* time off the channel (if you must) */
switch_frame *read_frame;
if (switch_core_session_read_frame(session, &read_frame, -1, 0) != SWITCH_STATUS_SUCCESS) {
switch_status status = switch_core_session_read_frame(session, &read_frame, -1, 0);
while (switch_channel_test_flag(channel, CF_HOLD)) {
switch_yield(10000);
}
if (!SWITCH_READ_ACCEPTABLE(status)) {
break;
}
}
@ -718,53 +734,66 @@ static void *audio_bridge_thread(switch_thread *thread, void *obj)
ans_a = switch_channel_test_flag(chan_a, CF_ANSWERED);
ans_b = switch_channel_test_flag(chan_b, CF_ANSWERED);
switch_channel_set_flag(chan_a, CF_BRIDGED);
while (data->running > 0 && his_thread->running > 0) {
switch_channel_state b_state = switch_channel_get_state(chan_b);
switch_status status;
switch (b_state) {
case CS_HANGUP:
case CS_DONE:
data->running = -1;
continue;
default:
break;
}
/* If this call is running on early media and it answers for real, pass it along... */
if (!ans_b && switch_channel_test_flag(chan_a, CF_ANSWERED)) {
if (!switch_channel_test_flag(chan_b, CF_ANSWERED)) {
switch_channel_answer(chan_b);
}
ans_b++;
if (switch_channel_test_flag(chan_a, CF_TRANSFER)) {
break;
}
if (!ans_a && switch_channel_test_flag(chan_b, CF_ANSWERED)) {
if (!switch_channel_test_flag(chan_a, CF_ANSWERED)) {
switch_channel_answer(chan_a);
if (!switch_channel_test_flag(chan_a, CF_HOLD)) {
/* If this call is running on early media and it answers for real, pass it along... */
if (!ans_b && switch_channel_test_flag(chan_a, CF_ANSWERED)) {
if (!switch_channel_test_flag(chan_b, CF_ANSWERED)) {
switch_channel_answer(chan_b);
}
ans_b++;
}
ans_a++;
}
/* if 1 channel has DTMF pass it to the other */
if (switch_channel_has_dtmf(chan_a)) {
char dtmf[128];
switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf));
switch_core_session_send_dtmf(session_b, dtmf);
if (!ans_a && switch_channel_test_flag(chan_b, CF_ANSWERED)) {
if (!switch_channel_test_flag(chan_a, CF_ANSWERED)) {
switch_channel_answer(chan_a);
}
ans_a++;
}
if (dtmf_callback) {
if (dtmf_callback(session_a, dtmf, user_data, 0) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s ended call via DTMF\n", switch_channel_get_name(chan_a));
data->running = -1;
break;
/* if 1 channel has DTMF pass it to the other */
if (switch_channel_has_dtmf(chan_a)) {
char dtmf[128];
switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf));
switch_core_session_send_dtmf(session_b, dtmf);
if (dtmf_callback) {
if (dtmf_callback(session_a, dtmf, user_data, 0) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s ended call via DTMF\n", switch_channel_get_name(chan_a));
data->running = -1;
break;
}
}
}
}
/* read audio from 1 channel and write it to the other */
if (switch_core_session_read_frame(session_a, &read_frame, -1, stream_id) == SWITCH_STATUS_SUCCESS && read_frame->datalen) {
if (switch_core_session_write_frame(session_b, read_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "write: %s Bad Frame....[%u] Bubye!\n", switch_channel_get_name(chan_b), read_frame->datalen);
data->running = -1;
status = switch_core_session_read_frame(session_a, &read_frame, -1, stream_id);
if (SWITCH_READ_ACCEPTABLE(status)) {
if (status != SWITCH_STATUS_BREAK) {
if (switch_core_session_write_frame(session_b, read_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "write: %s Bad Frame....[%u] Bubye!\n", switch_channel_get_name(chan_b), read_frame->datalen);
data->running = -1;
}
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "read: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_a));
@ -783,13 +812,7 @@ static void *audio_bridge_thread(switch_thread *thread, void *obj)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "BRIDGE THREAD DONE [%s]\n", switch_channel_get_name(chan_a));
if (switch_channel_test_flag(chan_a, CF_ORIGINATOR)) {
if (switch_channel_test_flag(chan_b, CF_TRANSFER)) {
if (switch_channel_get_state(chan_b) < CS_HANGUP) {
switch_channel_set_state(chan_b, CS_RING);
/* TBD we need to teach all the endpoints to honor this still */
switch_core_session_kill_channel(session_b, SWITCH_SIG_XFER);
}
} else {
if (!switch_channel_test_flag(chan_b, CF_TRANSFER)) {
switch_core_session_kill_channel(session_b, SWITCH_SIG_KILL);
switch_channel_hangup(chan_b, SWITCH_CAUSE_NORMAL_CLEARING);
}
@ -797,7 +820,7 @@ static void *audio_bridge_thread(switch_thread *thread, void *obj)
his_thread->running = 0;
}
switch_channel_clear_flag(chan_a, CF_BRIDGED);
data->running = 0;
return NULL;
}
@ -832,18 +855,18 @@ static switch_status audio_bridge_on_ring(switch_core_session *session)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CUSTOM RING\n");
/* put the channel in a passive state so we can loop audio to it */
switch_channel_set_state(channel, CS_TRANSMIT);
switch_channel_set_state(channel, CS_HOLD);
return SWITCH_STATUS_FALSE;
}
static switch_status audio_bridge_on_transmit(switch_core_session *session)
static switch_status audio_bridge_on_hold(switch_core_session *session)
{
switch_channel *channel = NULL;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CUSTOM TRANSMIT\n");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CUSTOM HOLD\n");
/* put the channel in a passive state so we can loop audio to it */
return SWITCH_STATUS_FALSE;
@ -855,7 +878,8 @@ static const switch_state_handler_table audio_bridge_peer_state_handlers = {
/*.on_execute */ NULL,
/*.on_hangup */ NULL,
/*.on_loopback */ audio_bridge_on_loopback,
/*.on_transmit */ audio_bridge_on_transmit,
/*.on_transmit */ NULL,
/*.on_hold */ audio_bridge_on_hold,
};
@ -874,7 +898,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_sessi
time_t start;
int stream_id = 0;
switch_frame *read_frame = NULL;
switch_status status = SWITCH_STATUS_SUCCESS;
caller_channel = switch_core_session_get_channel(session);
@ -941,7 +965,9 @@ SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_sessi
/* read from the channel while we wait if the audio is up on it */
if (switch_channel_test_flag(caller_channel, CF_ANSWERED) || switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA)) {
if (switch_core_session_read_frame(session, &read_frame, 1000, 0) != SWITCH_STATUS_SUCCESS) {
switch_status status = switch_core_session_read_frame(session, &read_frame, 1000, 0);
if (!SWITCH_READ_ACCEPTABLE(status)) {
break;
}
if (read_frame) {
@ -964,8 +990,8 @@ SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_sessi
if (switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
switch_event *event;
switch_core_session_message msg = {0};
switch_channel_set_state(peer_channel, CS_TRANSMIT);
switch_channel_set_state(peer_channel, CS_HOLD);
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_BRIDGE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(caller_channel, event);
@ -980,31 +1006,79 @@ SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_sessi
msg.pointer_arg = peer_session;
switch_core_session_receive_message(session, &msg);
switch_channel_set_flag(peer_channel, CF_LOCK_THREAD);
switch_channel_set_private(peer_channel, other_audio_thread);
switch_channel_set_state(peer_channel, CS_LOOPBACK);
audio_bridge_thread(NULL, (void *) this_audio_thread);
if (switch_core_session_read_lock(peer_session) == SWITCH_STATUS_SUCCESS) {
switch_channel_set_private(peer_channel, other_audio_thread);
switch_channel_set_state(peer_channel, CS_LOOPBACK);
audio_bridge_thread(NULL, (void *) this_audio_thread);
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_UNBRIDGE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(caller_channel, event);
switch_event_fire(&event);
}
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_UNBRIDGE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(caller_channel, event);
switch_event_fire(&event);
}
this_audio_thread->objs[0] = NULL;
this_audio_thread->objs[1] = NULL;
this_audio_thread->objs[2] = NULL;
this_audio_thread->objs[3] = NULL;
this_audio_thread->objs[4] = NULL;
this_audio_thread->objs[5] = NULL;
this_audio_thread->running = 2;
switch_channel_clear_flag(peer_channel, CF_LOCK_THREAD);
this_audio_thread->objs[0] = NULL;
this_audio_thread->objs[1] = NULL;
this_audio_thread->objs[2] = NULL;
this_audio_thread->objs[3] = NULL;
this_audio_thread->objs[4] = NULL;
this_audio_thread->objs[5] = NULL;
this_audio_thread->running = 2;
switch_core_session_rwunlock(peer_session);
} else {
status = SWITCH_STATUS_FALSE;
}
} else {
status = SWITCH_STATUS_FALSE;
}
if (status != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Bridge Failed %s->%s\n",
switch_channel_get_name(caller_channel),
switch_channel_get_name(peer_channel)
);
return SWITCH_STATUS_FALSE;
}
return SWITCH_STATUS_SUCCESS;
return status;
}
SWITCH_DECLARE(switch_status) switch_ivr_session_transfer(switch_core_session *session, char *extension, char *dialplan, char *context)
{
switch_channel *channel;
switch_caller_profile *profile, *new_profile;
assert(session != NULL);
assert(extension != NULL);
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
if ((profile = switch_channel_get_caller_profile(channel))) {
new_profile = switch_caller_profile_clone(session, profile);
new_profile->destination_number = switch_core_session_strdup(session, extension);
if (dialplan) {
new_profile->dialplan = switch_core_session_strdup(session, dialplan);
} else {
dialplan = new_profile->dialplan;
}
if (context) {
new_profile->context = switch_core_session_strdup(session, context);
} else {
context = new_profile->context;
}
switch_channel_set_caller_profile(channel, new_profile);
switch_channel_set_flag(channel, CF_TRANSFER);
switch_channel_set_state(channel, CS_RING);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Transfer %s to %s[%s@%s]\n",
switch_channel_get_name(channel), dialplan, extension, context);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}