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
char *chan_name;
/*! unique id */
char *uuid;
+ /*! context */
+ char *context;
+ struct switch_caller_profile *next;
};
/*! \brief An Abstract Representation of a dialplan Application */
char *ani2,
char *rdnis,
char *source,
+ char *context,
char *destination_number);
/*!
#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
///\}
+///\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
\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);
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
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 */
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>
CS_TRANSMIT,
CS_EXECUTE,
CS_LOOPBACK,
+ CS_HOLD,
CS_HANGUP,
CS_DONE
} switch_channel_state;
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>
*/
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;
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
NULL,
caller_caller_profile->rdnis,
caller_caller_profile->source,
+ caller_caller_profile->context,
chan_data);
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");
}
+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
};
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;
+ }
+
}
}
char *extip;
char *lanaddr;
char *exten;
+ char *context;
ldl_handle_t *handle;
unsigned int flags;
};
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);
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,
NULL,
NULL,
(char *)modname,
+ NULL,
event->request->req_uri->username)) != 0) {
switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
}
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,
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->
NULL,
NULL,
(char *)modname,
+ NULL,
event->ring.callednum))) {
switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
}
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);
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;
}
}
char *ani = "";
char *ani2 = "";
char *rdnis = "";
+ char *context = "";
*rval = BOOLEAN_TO_JSVAL( JS_FALSE );
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;
char *ani2,
char *rdnis,
char *source,
+ char *context,
char *destination_number)
{
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);
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);
}
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);
}
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);
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;
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;
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)
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;
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;
}
"CS_TRANSMIT",
"CS_EXECUTE",
"CS_LOOPBACK",
+ "CS_HOLD",
"CS_HANGUP",
"CS_DONE"
};
case CS_TRANSMIT:
case CS_RING:
case CS_EXECUTE:
+ case CS_HOLD:
ok++;
default:
break;
case CS_TRANSMIT:
case CS_RING:
case CS_EXECUTE:
+ case CS_HOLD:
ok++;
default:
break;
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;
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;
case CS_LOOPBACK:
case CS_TRANSMIT:
case CS_RING:
+ case CS_HOLD:
ok++;
default:
break;
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));
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)
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,
{
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) {
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) {
switch_mutex_t *mutex;
switch_thread_cond_t *cond;
+ switch_thread_rwlock_t *rwlock;
+
void *streams[SWITCH_MAX_STREAMS];
int stream_count;
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 */
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)
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,
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)) {
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);
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();
}
}
}
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) {
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);
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;
}
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;
}
}
}
}
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 {
}
}
- 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)) {
}
} 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;
}
}
}
} 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;
}
}
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));
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);
}
his_thread->running = 0;
}
-
+ switch_channel_clear_flag(chan_a, CF_BRIDGED);
data->running = 0;
return NULL;
}
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;
/*.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,
};
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);
/* 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) {
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);
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;
}
+
+