SWITCH_DECLARE(int) CoreSession::speak(char *text)
{
    switch_status_t status;

	this_check(-1);
	sanity_check(-1);

	if (!tts_name) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No TTS engine specified\n");
		return SWITCH_STATUS_FALSE;
	}

	if (!voice_name) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No TTS voice specified\n");
		return SWITCH_STATUS_FALSE;
	}


	begin_allow_threads();
	status = switch_ivr_speak_text(session, tts_name, voice_name, text, ap);
	end_allow_threads();
    return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
}
SWITCH_DECLARE(void) CoreSession::sayPhrase(const char *phrase_name, const char *phrase_data, const char *phrase_lang) 
{
	this_check_void();
	sanity_check_noreturn;
	
	if (!(phrase_name)) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error! invalid args.\n");
		return;
	}

	begin_allow_threads();
	switch_ivr_phrase_macro(session, phrase_name, phrase_data, phrase_lang, ap);
    end_allow_threads();
}
Example #3
0
static switch_status_t channel_on_hangup(switch_core_session_t *session)
{
	switch_channel_t *channel = NULL;
	loopback_private_t *tech_pvt = NULL;

	channel = switch_core_session_get_channel(session);
	switch_assert(channel != NULL);
	switch_channel_set_variable(channel, "is_loopback", "1");

	tech_pvt = switch_core_session_get_private(session);
	switch_assert(tech_pvt != NULL);
	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));

	switch_clear_flag_locked(tech_pvt, TFLAG_LINKED);

	switch_mutex_lock(tech_pvt->mutex);

	if (tech_pvt->other_tech_pvt) {
		switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_LINKED);
		if (tech_pvt->other_tech_pvt->session && tech_pvt->other_tech_pvt->session != tech_pvt->other_session) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "OTHER SESSION MISMATCH????\n");
			tech_pvt->other_session = tech_pvt->other_tech_pvt->session;
		}
		tech_pvt->other_tech_pvt = NULL;
	}

	if (tech_pvt->other_session) {
		switch_channel_hangup(tech_pvt->other_channel, switch_channel_get_cause(channel));
		switch_core_session_rwunlock(tech_pvt->other_session);
		tech_pvt->other_channel = NULL;
		tech_pvt->other_session = NULL;
	}
	switch_mutex_unlock(tech_pvt->mutex);

	return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_limit_incr(const char *backend, switch_core_session_t *session, const char *realm, const char *resource, const int max, const int interval) {
	switch_limit_interface_t *limit = NULL;
	switch_channel_t *channel = NULL;
	int status = SWITCH_STATUS_SUCCESS;
	
	assert(session);

	channel = switch_core_session_get_channel(session);

	/* locate impl, call appropriate func */
	if (!(limit = get_backend(backend))) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Limit subsystem %s not found!\n", backend);
		switch_goto_status(SWITCH_STATUS_GENERR, end);
	}

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "incr called: %s_%s max:%d, interval:%d\n",
					  realm, resource, max, interval);
	
	if ((status = limit->incr(session, realm, resource, max, interval)) == SWITCH_STATUS_SUCCESS) {
		/* race condition? what if another leg is doing the same thing? */
		const char *existing = switch_channel_get_variable(channel, LIMIT_BACKEND_VARIABLE);
		if (existing) {
			if (!strstr(existing, backend)) {
				switch_channel_set_variable_printf(channel, LIMIT_BACKEND_VARIABLE, "%s,%s", existing, backend);
			}
		} else {
			switch_channel_set_variable(channel, LIMIT_BACKEND_VARIABLE, backend);
			switch_core_event_hook_add_state_change(session, limit_state_handler);
		}
	}
	
	release_backend(limit);
	
end:
	return status;
}
Example #5
0
static switch_status_t channel_on_execute(switch_core_session_t *session)
{
	switch_channel_t *channel = NULL;
	private_t *tech_pvt = NULL;

	channel = switch_core_session_get_channel(session);
	assert(channel != NULL);

	tech_pvt = switch_core_session_get_private(session);
	assert(tech_pvt != NULL);

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel));

	return SWITCH_STATUS_SUCCESS;
}
Example #6
0
static switch_status_t channel_on_consume_media(switch_core_session_t *session)
{
	switch_channel_t *channel = NULL;
	private_t *tech_pvt = NULL;

	channel = switch_core_session_get_channel(session);
	assert(channel != NULL);

	tech_pvt = switch_core_session_get_private(session);
	assert(tech_pvt != NULL);

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "CHANNEL CONSUME_MEDIA\n");

	return SWITCH_STATUS_SUCCESS;
}
Example #7
0
static switch_status_t channel_on_exchange_media(switch_core_session_t *session)
{
	switch_channel_t *channel = NULL;
	loopback_private_t *tech_pvt = NULL;

	channel = switch_core_session_get_channel(session);
	assert(channel != NULL);

	tech_pvt = switch_core_session_get_private(session);
	assert(tech_pvt != NULL);

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "CHANNEL LOOPBACK\n");

	return SWITCH_STATUS_SUCCESS;
}
static void switch_core_standard_on_init(switch_core_session_t *session)
{
	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard INIT\n", switch_channel_get_name(session->channel));

	if (switch_channel_test_flag(session->channel, CF_RECOVERING_BRIDGE)) {
		switch_channel_set_state(session->channel, CS_RESET);
	} else {
		if (switch_channel_test_flag(session->channel, CF_RECOVERING)) {
			switch_channel_set_state(session->channel, CS_EXECUTE);
		} else {
			switch_channel_set_state(session->channel, CS_ROUTING);
		}
	}

	switch_channel_clear_flag(session->channel, CF_RECOVERING);
}
SWITCH_DECLARE(switch_status_t) switch_limit_release(const char *backend, switch_core_session_t *session, const char *realm, const char *resource) {
	switch_limit_interface_t *limit = NULL;
	int status = SWITCH_STATUS_SUCCESS;
	
	/* locate impl, call appropriate func */
	if (!(limit = get_backend(backend))) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Limit subsystem %s not found!\n", backend);
		switch_goto_status(SWITCH_STATUS_GENERR, end);
	}
	
	status = limit->release(session, realm, resource);
	
end:
	release_backend(limit);
	return status;
}
static switch_status_t channel_on_hangup(switch_core_session_t *session)
{
	switch_channel_t *channel = NULL;
	private_t *tech_pvt = NULL;

	channel = switch_core_session_get_channel(session);
	switch_assert(channel != NULL);

	tech_pvt = switch_core_session_get_private(session);
	switch_assert(tech_pvt != NULL);
	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));

	t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_HANGUP);

	return SWITCH_STATUS_SUCCESS;
}
Example #11
0
SWITCH_DECLARE(const char *) API::execute(const char *cmd, const char *arg)
{
	switch_stream_handle_t stream = { 0 };
	this_check("");

	SWITCH_STANDARD_STREAM(stream);

	if (zstr(cmd)) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No application specified\n");
		stream.write_function(&stream, "-ERR No application specified");
	} else {
		switch_api_execute(cmd, arg, session, &stream);
	}

	return (char *) stream.data;
}
Example #12
0
void eventpipe_events_on_dtmf(switch_core_session_t *session, switch_event_t *event) {
	char args[8192];
	const char *dtmf_digit = switch_str_nil(switch_event_get_header(event, "dtmf-digit"));
	switch_channel_t *channel = switch_core_session_get_channel(session);
	const char *hangup_on_star = switch_str_nil(switch_channel_get_variable(channel, "eventpipe_conference_hangup_on_star"));
	const char *conf_room = switch_str_nil(switch_channel_get_variable(channel, "eventpipe_conference_room"));
	const char *conf_member_id = switch_str_nil(switch_channel_get_variable(channel, "eventpipe_conference_member_id"));

	/* handle conference kick if channel is in conference and digit '*' was pressed */
	if ((!strcmp(hangup_on_star, "true")) && (!strcmp(dtmf_digit, "*")) && (!zstr(conf_room)) && (!zstr(conf_member_id))) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, 
				"Conference, dtmf '*' pressed, kick member %s from room %s\n",
				conf_member_id, conf_room);
		switch_snprintf(args, sizeof(args), "%s kick %s", conf_room, conf_member_id);
		eventpipe_execute_api(session, "conference", args);
	}
}
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_recordings(switch_core_session_t *orig_session, switch_core_session_t *new_session)
{
	switch_media_bug_t *bp;
	char *list[100] = { 0 };
	int stop_times[100] = { 0 };
	int i = 0, x = 0;

	if (orig_session->bugs) {
		switch_channel_t *new_channel = switch_core_session_get_channel(new_session);
		switch_channel_t *orig_channel = switch_core_session_get_channel(orig_session);
		const char *save_append = switch_channel_get_variable(new_channel, "record_append");
		const char *save_stereo = switch_channel_get_variable(new_channel, "record_stereo");
		const char *orig_stereo = switch_channel_get_variable(orig_channel, "record_stereo");
		const char *new_stereo = orig_stereo;
		
		switch_thread_rwlock_wrlock(orig_session->bug_rwlock);
		switch_channel_set_variable(new_channel, "RECORD_MIN_SEC", "0");
		switch_channel_set_variable(new_channel, "record_append", "true");
		switch_channel_set_variable(new_channel, "record_stereo", new_stereo);

		for (bp = orig_session->bugs; bp; bp = bp->next) {
			if (!strcmp(bp->function, "session_record")) {
				list[x] = switch_core_session_strdup(new_session, bp->target);
				if (bp->stop_time > 0) {
					stop_times[x] = (int)(bp->stop_time - switch_epoch_time_now(NULL));
				}
				x++;
			}
		}

		switch_thread_rwlock_unlock(orig_session->bug_rwlock);

		for(i = 0; i < x; i++) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(orig_session), SWITCH_LOG_DEBUG, "Transfering %s from %s to %s\n", list[i],
							  switch_core_session_get_name(orig_session), switch_core_session_get_name(new_session));
			switch_ivr_stop_record_session(orig_session, list[i]);
			switch_ivr_record_session(new_session, list[i], stop_times[i], NULL);
		}

		switch_channel_set_variable(new_channel, "record_append", save_append);
		switch_channel_set_variable(new_channel, "record_stereo", save_stereo);

	}

	return x ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
}
Example #14
0
static void switch_core_standard_on_hangup(switch_core_session_t *session)
{
	switch_caller_extension_t *extension;
	int rec;

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard HANGUP, cause: %s\n",
					  switch_channel_get_name(session->channel), switch_channel_cause2str(switch_channel_get_cause(session->channel)));


	rec = switch_channel_test_flag(session->channel, CF_RECOVERING);
	switch_channel_clear_flag(session->channel, CF_RECOVERING);

	if (!rec) {
		switch_core_recovery_untrack(session, SWITCH_TRUE);
	}

	
	if (!switch_channel_test_flag(session->channel, CF_ZOMBIE_EXEC)) {
		return;
	}

	if ((extension = switch_channel_get_caller_extension(session->channel)) == 0) {
		return;
	}

	while(extension->current_application) {
		switch_caller_application_t *current_application = extension->current_application;
		switch_status_t status;

		extension->current_application = extension->current_application->next;

		status = switch_core_session_execute_application(session,
														 current_application->application_name, current_application->application_data);
														 
		
		if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_IGNORE) {
			return;
		}
	}





}
Example #15
0
void eventpipe_events_on_conference(switch_core_session_t *session, switch_event_t *event) {
	char args[8192];
	char record_args[8192];
	const char *action = switch_str_nil(switch_event_get_header(event, "action"));
	const char *member_id = switch_str_nil(switch_event_get_header(event, "member-id"));
	const char *conf_room = switch_str_nil(switch_event_get_header(event, "conference-name"));
	const char *calluuid = switch_core_session_get_uuid(session);
	switch_channel_t *channel = switch_core_session_get_channel(session);
	if (!channel) {
		return;
	}

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, 
				"Event-Name: %s, Event-Subclass: %s, Conference-Name: %s, Action: %s, Member-ID: %s, Unique-ID: %s\n", 
				switch_str_nil(switch_event_get_header(event, "event-name")), 
				switch_str_nil(switch_event_get_header(event, "event-subclass")), 
				conf_room, action, member_id, calluuid);

	if (!strcmp(action, "add-member")) {
		const char *enter_sound = switch_str_nil(switch_channel_get_variable(channel, "eventpipe_conference_enter_sound"));
		const char *record_file = switch_str_nil(switch_channel_get_variable(channel, "eventpipe_conference_record_file"));
		switch_channel_set_variable(channel, "eventpipe_conference_member_id", member_id);
		switch_channel_set_variable(channel, "eventpipe_conference_room", conf_room);
		if (!zstr(enter_sound)) {
			switch_snprintf(args, sizeof(args), "%s play %s async",
					conf_room, enter_sound);
			eventpipe_execute_api(session, "conference", args);
		}
		if (!zstr(record_file)) {
			switch_snprintf(record_args, sizeof(record_args), "%s record %s",
					conf_room, record_file);
			eventpipe_execute_api(session, "conference", record_args);
		}
	} else if (!strcmp(action, "del-member")) {
		const char *exit_sound = switch_str_nil(switch_channel_get_variable(channel, "eventpipe_conference_exit_sound"));
		switch_channel_set_variable(channel, "eventpipe_conference_member_id", "");
		switch_channel_set_variable(channel, "eventpipe_conference_room", "");
		switch_channel_set_variable(channel, "eventpipe_conference_record_file", "");
		if (!zstr(exit_sound)) {
			switch_snprintf(args, sizeof(args), "conference %s play %s async",
					conf_room, exit_sound);
			eventpipe_execute_api(session, "conference", args);
		}
	}
}
static void switch_core_standard_on_reset(switch_core_session_t *session)
{
	switch_channel_set_variable(session->channel, "call_uuid", switch_core_session_get_uuid(session));

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Standard RESET\n", switch_channel_get_name(session->channel));

	if (switch_channel_test_flag(session->channel, CF_RECOVERING_BRIDGE)) {
		switch_core_session_t *other_session = NULL;
		const char *uuid = switch_core_session_get_uuid(session);

		if (switch_channel_test_flag(session->channel, CF_BRIDGE_ORIGINATOR)) {
			const char *other_uuid = switch_channel_get_partner_uuid(session->channel);
			int x = 0;

			if (other_uuid) {
				for (x = 0; other_session == NULL && x < 20; x++) {
					if (!switch_channel_up(session->channel)) {
						break;
					}
					other_session = switch_core_session_locate(other_uuid);
					switch_yield(100000);
				}
			}

			if (other_session) {
				switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
				switch_channel_clear_flag(session->channel, CF_BRIDGE_ORIGINATOR);
				switch_channel_wait_for_state_timeout(other_channel, CS_RESET, 5000);
				switch_channel_wait_for_flag(other_channel, CF_MEDIA_ACK, SWITCH_TRUE, 2000, NULL);

				if (switch_channel_test_flag(session->channel, CF_PROXY_MODE) && switch_channel_test_flag(other_channel, CF_PROXY_MODE)) {
					switch_ivr_signal_bridge(session, other_session);
				} else {
					switch_ivr_uuid_bridge(uuid, other_uuid);
				}
				switch_core_session_rwunlock(other_session);
			}
		}

		switch_channel_clear_flag(session->channel, CF_RECOVERING_BRIDGE);
	}

}
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_callback(switch_core_session_t *orig_session, switch_core_session_t *new_session, 
																		switch_media_bug_callback_t callback, void * (*user_data_dup_func) (switch_core_session_t *, void *))
{
	switch_media_bug_t *new_bug = NULL, *cur = NULL, *bp = NULL, *last = NULL;
	int total = 0;

	switch_thread_rwlock_wrlock(orig_session->bug_rwlock);
	bp = orig_session->bugs;
	while (bp) {
		cur = bp;
		bp = bp->next;
		
		if (cur->callback == callback) {
			if (last) {
				last->next = cur->next;
			} else {
				orig_session->bugs = cur->next;
			}

			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(orig_session), SWITCH_LOG_DEBUG, "Transfering %s from %s to %s\n", cur->target,
							  switch_core_session_get_name(orig_session), switch_core_session_get_name(new_session));

			switch_core_media_bug_add(new_session, cur->function, cur->target, cur->callback,
									  user_data_dup_func(new_session, cur->user_data),
									  cur->stop_time, cur->flags, &new_bug);
			switch_core_media_bug_destroy(cur);
			total++;
		} else {
			last = cur;
		}
	}

	if (!orig_session->bugs && switch_core_codec_ready(&orig_session->bug_codec)) {
		switch_core_codec_destroy(&orig_session->bug_codec);
	}

	switch_thread_rwlock_unlock(orig_session->bug_rwlock);


	return total ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
}
static void put_text_msg(void *user_data, const uint8_t *msg, int len)
{
	switch_tdd_t *pvt = (switch_tdd_t *) user_data;
	switch_event_t *event, *clone;
	switch_channel_t *channel = switch_core_session_get_channel(pvt->session);
	switch_core_session_t *other_session;


	switch_channel_add_variable_var_check(channel, "tdd_messages", (char *)msg, SWITCH_FALSE, SWITCH_STACK_PUSH);


	if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_TDD_RECV_MESSAGE) == SWITCH_STATUS_SUCCESS) {

		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", "mod_spandsp");
		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", "tdd");
		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "subject", "TDD MESSAGE");
		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "TDD-Data", (char *)msg);
		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(pvt->session));
		switch_event_add_body(event, "%s\n\n", (char *)msg);

		if (switch_core_session_get_partner(pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) {

			if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
				switch_core_session_receive_event(other_session, &clone);
			}

			if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
				switch_core_session_queue_event(other_session, &clone);
			}

			switch_core_session_rwunlock(other_session);
		}

		switch_event_fire(&event);


	}

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "%s got TDD Message [%s]\n", switch_channel_get_name(channel), (char *)msg);

}
Example #19
0
static switch_status_t channel_on_routing(switch_core_session_t *session)
{
	switch_channel_t *channel = NULL;
	private_t *tech_pvt = NULL;
	const char *app, *arg;

	channel = switch_core_session_get_channel(session);
	assert(channel != NULL);

	tech_pvt = switch_core_session_get_private(session);
	assert(tech_pvt != NULL);

	do_reset(tech_pvt);

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel));
	
	if (switch_test_flag(tech_pvt, TFLAG_RUNNING_APP)) {
		switch_clear_flag(tech_pvt, TFLAG_RUNNING_APP);
	}

	if (switch_test_flag(tech_pvt, TFLAG_APP) && !switch_test_flag(tech_pvt, TFLAG_OUTBOUND) && 
		(app = switch_channel_get_variable(channel, "loopback_app"))) {
		switch_caller_extension_t *extension = NULL;

		switch_clear_flag(tech_pvt, TFLAG_APP);
		switch_set_flag(tech_pvt, TFLAG_RUNNING_APP);

		arg = switch_channel_get_variable(channel, "loopback_app_arg");
		extension = switch_caller_extension_new(session, app, app);
		switch_caller_extension_add_application(session, extension, "pre_answer", NULL);
		switch_caller_extension_add_application(session, extension, app, arg);

		switch_channel_set_caller_extension(channel, extension);
		switch_channel_set_state(channel, CS_EXECUTE);
		return SWITCH_STATUS_FALSE;
	}



	return SWITCH_STATUS_SUCCESS;
}
Example #20
0
SWITCH_DECLARE(switch_status_t) switch_core_session_set_video_read_codec(switch_core_session_t *session, switch_codec_t *codec)
{
	switch_event_t *event;
	switch_channel_t *channel = switch_core_session_get_channel(session);
	char tmp[30];
	switch_status_t status = SWITCH_STATUS_SUCCESS;

	if (!codec || !codec->implementation || !switch_core_codec_ready(codec)) {
		if (session->video_read_codec) {
			session->video_read_codec = NULL;
			status = SWITCH_STATUS_SUCCESS;
			goto end;
		}
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot set NULL codec!\n");
		status = SWITCH_STATUS_FALSE;
		goto end;
	}

	if (switch_event_create(&event, SWITCH_EVENT_CODEC) == SWITCH_STATUS_SUCCESS) {
		switch_channel_event_set_data(session->channel, event);
		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-video-read-codec-name", codec->implementation->iananame);
		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "channel-video-read-codec-rate", "%d", codec->implementation->actual_samples_per_second);
		switch_event_fire(&event);
	}

	switch_channel_set_variable(channel, "video_read_codec", codec->implementation->iananame);
	switch_snprintf(tmp, sizeof(tmp), "%d", codec->implementation->actual_samples_per_second);
	switch_channel_set_variable(channel, "video_read_rate", tmp);

	session->video_read_codec = codec;
	if (codec->implementation) {
		session->video_read_impl = *codec->implementation;
	} else {
		memset(&session->video_read_impl, 0, sizeof(session->video_read_impl));
	}
  end:

	return status;
}
Example #21
0
/**
 * Select a URL for replacement and remove it from the cache.
 * Currently implemented with the clock replacement algorithm.  It's not
 * great, but is better than least recently used and is simple to implement.
 *
 * @param cache the cache
 * @param session the (optional) session 
 * @return SWITCH_STATUS_SUCCESS if successful
 */
static switch_status_t url_cache_replace(url_cache_t *cache, switch_core_session_t *session)
{
	switch_status_t status = SWITCH_STATUS_FALSE;
	int i = 0;
	simple_queue_t *queue = &cache->queue;
	
	if (queue->size < queue->max_size || queue->size == 0) {
		return SWITCH_STATUS_FALSE;
	}

	for (i = 0; i < queue->max_size * 2; i++) {
		cached_url_t *to_replace = (cached_url_t *)queue->data[queue->pos];

		/* check for queue corruption */
		if (to_replace == NULL) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Unexpected empty URL at cache index %d\n", queue->pos);
			status = SWITCH_STATUS_SUCCESS;
			break;
		}

		/* check if available for replacement */
		if (!to_replace->used && !to_replace->waiters) {
			/* remove from cache and destroy it */
			url_cache_remove(cache, session, to_replace);
			cached_url_destroy(to_replace, cache->pool);
			status = SWITCH_STATUS_SUCCESS;
			break;
		}

		/* not available for replacement.  Mark as not used and move to back of queue */
		if (to_replace->status == CACHED_URL_AVAILABLE) {
			to_replace->used = 0;
		}
		queue->pos = (queue->pos + 1) % queue->max_size;
	}

	return status;
}
Example #22
0
static void api_hook(switch_core_session_t *session, const char *hook_var, int use_session)
{
	if (!zstr(hook_var)) {
		switch_stream_handle_t stream = { 0 };
		char *cmd = strdup(hook_var);
		char *arg = NULL;
		char *expanded = NULL;

		if ((arg = strchr(cmd, ':')) && *(arg + 1) == ':') {
			*arg++ = '\0';
			*arg++ = '\0';
		} else {
			if ((arg = strchr(cmd, ' '))) {
				*arg++ = '\0';
			}
		}

		SWITCH_STANDARD_STREAM(stream);

		switch_channel_get_variables(session->channel, &stream.param_event);
		switch_channel_event_set_data(session->channel, stream.param_event);
		expanded = switch_event_expand_headers(stream.param_event, arg);

		switch_api_execute(cmd, expanded, use_session ? session : NULL, &stream);

		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Hangup Command %s %s(%s):\n%s\n",
						  use_session ? "with Session" : "with no Session", cmd, switch_str_nil(expanded),
						  switch_str_nil((char *) stream.data) );

		if (expanded != arg) {
			switch_safe_free(expanded);
		}

		switch_safe_free(cmd);
		
		switch_safe_free(stream.data);
	}
}
Example #23
0
SWITCH_DECLARE(char *) CoreSession::getDigits(int maxdigits, 
											  char *terminators, 
											  int timeout,
											  int interdigit)
{
	this_check((char *)"");
	sanity_check((char *)"");
	begin_allow_threads();
	char terminator;

	memset(dtmf_buf, 0, sizeof(dtmf_buf));
	switch_ivr_collect_digits_count(session, 
									dtmf_buf,
									sizeof(dtmf_buf),
									maxdigits, 
									terminators, 
									&terminator, 
									(uint32_t) timeout, (uint32_t)interdigit, 0);

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "getDigits dtmf_buf: %s\n", dtmf_buf);
	end_allow_threads();
	return dtmf_buf;
}
Example #24
0
SWITCH_DECLARE(void) switch_caller_extension_add_application_printf(switch_core_session_t *session,
																	switch_caller_extension_t *caller_extension, const char *application_name,
																	const char *fmt, ...)
{
	va_list ap;
	char *data = NULL;

	va_start(ap, fmt);
	switch_vasprintf(&data, fmt, ap);
	va_end(ap);

	if (data) {
		char *p;

		if ((p = strstr(data, "\\'"))) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "App not added, Invalid character sequence in data string [%s]\n", data);
			free(data);
			return;
		}
		switch_caller_extension_add_application(session, caller_extension, application_name, data);
		free(data);
	}
}
Example #25
0
SWITCH_DECLARE(void) CoreSession::destroy(void)
{
	this_check_void();
	
	if (!allocated) {
		return;
	}

	allocated = 0;

	switch_safe_free(xml_cdr_text);
	switch_safe_free(uuid);	
	switch_safe_free(tts_name);
	switch_safe_free(voice_name);

	if (session) {
		if (!channel) {
			channel = switch_core_session_get_channel(session);
		}

		if (channel) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, 
							  "%s destroy/unlink session from object\n", switch_channel_get_name(channel));
			switch_channel_set_private(channel, "CoreSession", NULL);
			if (switch_channel_up(channel) && switch_test_flag(this, S_HUP) && !switch_channel_test_flag(channel, CF_TRANSFER)) {
				switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
			}
		}

        switch_core_session_rwunlock(session);
		session = NULL;
		channel = NULL;
    }

	init_vars();
	
}
Example #26
0
static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig)
{
	switch_channel_t *channel = NULL;
	private_t *tech_pvt = NULL;

	channel = switch_core_session_get_channel(session);
	switch_assert(channel != NULL);

	tech_pvt = switch_core_session_get_private(session);
	switch_assert(tech_pvt != NULL);

	switch (sig) {
	case SWITCH_SIG_BREAK:
		switch_set_flag_locked(tech_pvt, TFLAG_CNG);
		switch_mutex_lock(tech_pvt->mutex);
		if (tech_pvt->other_tech_pvt) {
			switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_CNG);
		}
		switch_mutex_unlock(tech_pvt->mutex);
		break;
	case SWITCH_SIG_KILL:
		switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
		switch_clear_flag_locked(tech_pvt, TFLAG_LINKED);
		switch_mutex_lock(tech_pvt->mutex);
		if (tech_pvt->other_tech_pvt) {
			switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_LINKED);
		}
		switch_mutex_unlock(tech_pvt->mutex);
		break;
	default:
		break;
	}

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL KILL\n", switch_channel_get_name(channel));

	return SWITCH_STATUS_SUCCESS;
}
Example #27
0
/**
 * Get a URL from the cache, add it if it does not exist
 * @param cache The cache
 * @param session the (optional) session requesting the URL
 * @param url The URL
 * @param download If true, the file will be downloaded if it does not exist in the cache.
 * @param pool The pool to use for allocating the filename
 * @return The filename or NULL if there is an error
 */
static char *url_cache_get(url_cache_t *cache, switch_core_session_t *session, const char *url, int download, switch_memory_pool_t *pool)
{
	char *filename = NULL;
	cached_url_t *u = NULL;
	if (zstr(url)) {
		return NULL;
	}

	url_cache_lock(cache, session);
	u = switch_core_hash_find(cache->map, url);

	if (u && u->status == CACHED_URL_AVAILABLE) {
		if (switch_time_now() >= (u->download_time + u->max_age)) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Cached URL has expired.\n");
			url_cache_remove_soft(cache, session, u); /* will get permanently deleted upon replacement */
			u = NULL;
		} else if (switch_file_exists(u->filename, pool) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Cached URL file is missing.\n");
			url_cache_remove_soft(cache, session, u); /* will get permanently deleted upon replacement */
			u = NULL;
		}
	}

	if (!u && download) {
		/* URL is not cached, let's add it.*/
		/* Set up URL entry and add to map to prevent simultaneous downloads */
		cache->misses++;
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Cache MISS: size = %zu (%zu MB), hit ratio = %d/%d\n", cache->queue.size, cache->size / 1000000, cache->hits, cache->hits + cache->misses);
		u = cached_url_create(cache, url);
		if (url_cache_add(cache, session, u) != SWITCH_STATUS_SUCCESS) {
			/* This error should never happen */
			url_cache_unlock(cache, session);
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed to add URL to cache!\n");
			cached_url_destroy(u, cache->pool);
			return NULL;
		}

		/* download the file */
		url_cache_unlock(cache, session);
		if (http_get(cache, u, session) == SWITCH_STATUS_SUCCESS) {
			/* Got the file, let the waiters know it is available */
			url_cache_lock(cache, session);
			u->status = CACHED_URL_AVAILABLE;
			filename = switch_core_strdup(pool, u->filename);
			cache->size += u->size;
		} else {
			/* Did not get the file, flag for replacement */
			url_cache_lock(cache, session);
			url_cache_remove_soft(cache, session, u);
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Failed to download URL %s\n", url);
			cache->errors++;
		}
	} else if (!u) {
		filename = DOWNLOAD_NEEDED;
	} else {
		/* Wait until file is downloaded */
		if (u->status == CACHED_URL_RX_IN_PROGRESS) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Waiting for URL %s to be available\n", url);
			u->waiters++;
			url_cache_unlock(cache, session);
			while(u->status == CACHED_URL_RX_IN_PROGRESS) {
				switch_sleep(10 * 1000); /* 10 ms */
			}
			url_cache_lock(cache, session);
			u->waiters--;
		}

		/* grab filename if everything is OK */
		if (u->status == CACHED_URL_AVAILABLE) {
			filename = switch_core_strdup(pool, u->filename);
			cache->hits++;
			u->used = 1;
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Cache HIT: size = %zu (%zu MB), hit ratio = %d/%d\n", cache->queue.size, cache->size / 1000000, cache->hits, cache->hits + cache->misses);
		}
	}
	url_cache_unlock(cache, session);
	return filename;
}
Example #28
0
/**
 * Relinquish exclusive access to the cache
 * @param cache The cache
 * @param session The session relinquishing the cache
 */
static void url_cache_unlock(url_cache_t *cache, switch_core_session_t *session)
{
	switch_mutex_unlock(cache->mutex);
	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Unlocked cache\n");
}
Example #29
0
/**
 * Put a file to the URL
 * @param cache the cache
 * @param session the (optional) session uploading the file
 * @param url The URL
 * @param filename The file to upload
 * @return SWITCH_STATUS_SUCCESS if successful
 */
static switch_status_t http_put(url_cache_t *cache, switch_core_session_t *session, const char *url, const char *filename)
{
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	CURL *curl_handle = NULL;
	long httpRes = 0;
	struct stat file_info = {0};
	FILE *file_to_put = NULL;
	int fd;
	
	/* open file and get the file size */
	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "opening %s for upload to %s\n", filename, url);
	fd = open(filename, O_RDONLY);
	if (fd == -1) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "open() error: %s\n", strerror(errno));
		status = SWITCH_STATUS_FALSE;
		goto done;
	}
	if (fstat(fd, &file_info) == -1) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "fstat() error: %s\n", strerror(errno));
	}
	close(fd);

	/* libcurl requires FILE* */
 	file_to_put = fopen(filename, "rb");
	if (!file_to_put) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "fopen() error: %s\n", strerror(errno));
		status = SWITCH_STATUS_FALSE;
		goto done;
	}
	
	curl_handle = switch_curl_easy_init();
	if (!curl_handle) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "switch_curl_easy_init() failure\n");
		status = SWITCH_STATUS_FALSE;
		goto done;
	}
	switch_curl_easy_setopt(curl_handle, CURLOPT_UPLOAD, 1);
	switch_curl_easy_setopt(curl_handle, CURLOPT_PUT, 1);
	switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
	switch_curl_easy_setopt(curl_handle, CURLOPT_URL, url);
	switch_curl_easy_setopt(curl_handle, CURLOPT_READDATA, file_to_put);
	switch_curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
	switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
	switch_curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 10);
	switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-http-cache/1.0");
	if (!cache->ssl_verifypeer) {
		switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
	} else {
		/* this is the file with all the trusted certificate authorities */ 
		if (!zstr(cache->ssl_cacert)) {
			switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, cache->ssl_cacert);
		}
		/* verify that the host name matches the cert */
		if (!cache->ssl_verifyhost) {
			switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
		}
	}
	switch_curl_easy_perform(curl_handle);
	switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes);
	switch_curl_easy_cleanup(curl_handle);

	if (httpRes == 200 || httpRes == 201 || httpRes == 204) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s saved to %s\n", filename, url);
	} else {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Received HTTP error %ld trying to save %s to %s\n", httpRes, filename, url);
		status = SWITCH_STATUS_GENERR;
	}
	
done:
	if (file_to_put) {
		fclose(file_to_put);
	}

	return status;
}
Example #30
0
/* This is where we actually charge the guy 
  This can be called anytime a call is in progress or at the end of a call before the session is destroyed */
static switch_status_t do_billing(switch_core_session_t *session)
{
	/* FS vars we will use */
	switch_channel_t *channel;
	switch_caller_profile_t *profile;

	/* Local vars */
	nibble_data_t *nibble_data;
	switch_time_t ts = switch_micro_time_now();
	double billamount;
	char date[80] = "";
	char *uuid;
	switch_size_t retsize;
	switch_time_exp_t tm;
	const char *billrate;
	const char *billincrement;
	const char *billaccount;
	double nobal_amt = globals.nobal_amt;
	double lowbal_amt = globals.lowbal_amt;
	double balance;

	if (!session) {
		/* Why are we here? */
		return SWITCH_STATUS_SUCCESS;
	}

	uuid = switch_core_session_get_uuid(session);

	/* Get channel var */
	if (!(channel = switch_core_session_get_channel(session))) {
		return SWITCH_STATUS_SUCCESS;
	}

	/* Variables kept in FS but relevant only to this module */
	billrate = switch_channel_get_variable(channel, "nibble_rate");
	billincrement = switch_channel_get_variable(channel, "nibble_increment");
	billaccount = switch_channel_get_variable(channel, "nibble_account");
	
	if (!zstr(switch_channel_get_variable(channel, "nobal_amt"))) {
		nobal_amt = atof(switch_channel_get_variable(channel, "nobal_amt"));
	}
	
	if (!zstr(switch_channel_get_variable(channel, "lowbal_amt"))) {
		lowbal_amt = atof(switch_channel_get_variable(channel, "lowbal_amt"));
	}
	
	/* Return if there's no billing information on this session */
	if (!billrate || !billaccount) {
		return SWITCH_STATUS_SUCCESS;
	}

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Attempting to bill at $%s per minute to account %s\n", billrate,
					  billaccount);

	/* Get caller profile info from channel */
	profile = switch_channel_get_caller_profile(channel);

	if (!profile || !profile->times) {
		/* No caller profile (why would this happen?) */
		return SWITCH_STATUS_SUCCESS;
	}

	if (profile->times->answered < 1) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Not billing %s - call is not in answered state\n", billaccount);

		/* See if this person has enough money left to continue the call */
		balance = get_balance(billaccount, channel);
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Comparing %f to hangup balance of %f\n", balance, nobal_amt);
		if (balance <= nobal_amt) {
			/* Not enough money - reroute call to nobal location */
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Balance of %f fell below allowed amount of %f! (Account %s)\n",
							  balance, nobal_amt, billaccount);

			transfer_call(session, globals.nobal_action);
		}

		return SWITCH_STATUS_SUCCESS;
	}

	/* Lock this session's data for this module while we tinker with it */
	if (globals.mutex) {
		switch_mutex_lock(globals.mutex);
	}

	/* Get our nibble data var. This will be NULL if it's our first call here for this session */
	nibble_data = (nibble_data_t *) switch_channel_get_private(channel, "_nibble_data_");

	/* Are we in paused mode? If so, we don't do anything here - go back! */
	if (nibble_data && (nibble_data->pausets > 0)) {
		if (globals.mutex) {
			switch_mutex_unlock(globals.mutex);
		}
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Received heartbeat, but we're paused - ignoring\n");
		return SWITCH_STATUS_SUCCESS;
	}

	/* Have we done any billing on this channel yet? If no, set up vars for doing so */
	if (!nibble_data) {
		nibble_data = switch_core_session_alloc(session, sizeof(*nibble_data));
		memset(nibble_data, 0, sizeof(*nibble_data));

		/* Setup new billing data (based on call answer time, in case this module started late with active calls) */
		nibble_data->lastts = profile->times->answered;	/* Set the initial answer time to match when the call was really answered */
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Beginning new billing on %s\n", uuid);
	}

	switch_time_exp_lt(&tm, nibble_data->lastts);
	switch_strftime_nocheck(date, &retsize, sizeof(date), "%Y-%m-%d %T", &tm);

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%d seconds passed since last bill time of %s\n",
					  (int) ((ts - nibble_data->lastts) / 1000000), date);

	if ((ts - nibble_data->lastts) >= 0) {
		/* If billincrement is set we bill by it and not by time elapsed */
		if (!(switch_strlen_zero(billincrement))) {
			switch_time_t chargedunits = (ts - nibble_data->lastts) / 1000000 <= atol(billincrement) ? atol(billincrement) * 1000000 : (switch_time_t)(ceil((ts - nibble_data->lastts) / (atol(billincrement) * 1000000.0))) * atol(billincrement) * 1000000;
			billamount = (atof(billrate) / 1000000 / 60) * chargedunits - nibble_data->bill_adjustments;
			/* Account for the prepaid amount */
			nibble_data->lastts += chargedunits;
		} else {		
			/* Convert billrate into microseconds and multiply by # of microseconds that have passed since last *successful* bill */
			billamount = (atof(billrate) / 1000000 / 60) * ((ts - nibble_data->lastts)) - nibble_data->bill_adjustments;
			/* Update the last time we billed */
			nibble_data->lastts = ts;
		}

		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Billing $%f to %s (Call: %s / %f so far)\n", billamount, billaccount,
						  uuid, nibble_data->total);

		/* DO ODBC BILLING HERE and reset counters if it's successful! */
		if (bill_event(billamount, billaccount, channel) == SWITCH_STATUS_SUCCESS) {
			/* Increment total cost */
			nibble_data->total += billamount;

			/* Reset manual billing adjustments from pausing */
			nibble_data->bill_adjustments = 0;

			/* Update channel variable with current billing */
			switch_channel_set_variable_printf(channel, "nibble_total_billed", "%f", nibble_data->total);
		} else {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed to log to database!\n");
		}
	} else {
		if (switch_strlen_zero(billincrement))
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Just tried to bill %s negative minutes! That should be impossible.\n", uuid);
	}

	/* Save this location */
	if (channel) {
		switch_channel_set_private(channel, "_nibble_data_", nibble_data);

		/* don't verify balance and transfer to nobal if we're done with call */
		if (switch_channel_get_state(channel) != CS_REPORTING && switch_channel_get_state(channel) != CS_HANGUP) {
			
			balance = get_balance(billaccount, channel);
			
			/* See if we've achieved low balance */
			if (!nibble_data->lowbal_action_executed && balance <= lowbal_amt) {
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Balance of %f fell below low balance amount of %f! (Account %s)\n",
								  balance, lowbal_amt, billaccount);

				if (exec_app(session, globals.lowbal_action) != SWITCH_STATUS_SUCCESS)
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Low balance action didn't execute\n");
				else
					nibble_data->lowbal_action_executed = 1;
			}

			/* See if this person has enough money left to continue the call */
			if (balance <= nobal_amt) {
				/* Not enough money - reroute call to nobal location */
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Balance of %f fell below allowed amount of %f! (Account %s)\n",
								  balance, nobal_amt, billaccount);

				/* IMPORTANT: Billing must be paused before the transfer occurs! This prevents infinite loops, since the transfer will result */
				/* in nibblebill checking the call again in the routing process for an allowed balance! */
				/* If you intend to give the user the option to re-up their balance, you must clear & resume billing once the balance is updated! */
				nibblebill_pause(session);
				transfer_call(session, globals.nobal_action);
			}
		}
	}


	/* Done changing - release lock */
	if (globals.mutex) {
		switch_mutex_unlock(globals.mutex);
	}

	/* Go check if this call is allowed to continue */

	return SWITCH_STATUS_SUCCESS;
}