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:
parent
e1dc35f734
commit
35dc32018c
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*!
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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->
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
204
src/switch_ivr.c
204
src/switch_ivr.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue