Ejemplo n.º 1
0
SWITCH_DECLARE(bool) CoreSession::bridged() {

	this_check(false);

	if (!session) {
		return false;
	}
	sanity_check(false);

	return (switch_channel_up(channel) && switch_channel_test_flag(channel, CF_BRIDGED));
}
Ejemplo n.º 2
0
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);
	}

}
Ejemplo n.º 3
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();
	
}
Ejemplo n.º 4
0
int modem_close(modem_t *modem) 
{
	int r = 0;
	switch_status_t was_running = switch_test_flag(modem, MODEM_FLAG_RUNNING);

	switch_clear_flag(modem, MODEM_FLAG_RUNNING);

#ifndef WIN32
	if (modem->master > -1) {
		shutdown(modem->master, 2);
		close(modem->master);
		modem->master = -1;
#else
	if (modem->master) {
		SetEvent(modem->threadAbort);
		CloseHandle(modem->threadAbort);
		CloseHandle(modem->master);
		modem->master = 0;
#endif
		
		r++;
	}

	if (modem->slave > -1) {
		shutdown(modem->slave, 2);
		close(modem->slave);
		modem->slave = -1;
		r++;
	}


   	if (modem->t31_state) {
		t31_free(modem->t31_state);
		modem->t31_state = NULL;
	}

	unlink(modem->devlink);

	if (was_running) {
		switch_mutex_lock(globals.mutex);
		globals.REF_COUNT--;
		switch_mutex_unlock(globals.mutex);
	}

	return r;
}


switch_status_t modem_init(modem_t *modem, modem_control_handler_t control_handler)
{
	switch_status_t status = SWITCH_STATUS_SUCCESS;
#ifdef WIN32
	COMMTIMEOUTS timeouts={0};
#endif
	
	memset(modem, 0, sizeof(*modem));

	modem->master = -1;
	modem->slave = -1;

	/* windows will have to try something like:
	   http://com0com.cvs.sourceforge.net/viewvc/com0com/com0com/ReadMe.txt?revision=RELEASED

	 */

#if USE_OPENPTY
    if (openpty(&modem->master, &modem->slave, NULL, NULL, NULL)) {

	if (modem->master < 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to initialize pty\n");
		status = SWITCH_STATUS_FALSE;
		goto end;
    }

	modem->stty = ttyname(modem->slave);
#else
#if WIN32
	modem->slot = 4+globals.NEXT_ID++; /* need work here we start at COM4 for now*/
	snprintf(modem->devlink, sizeof(modem->devlink), "COM%d", modem->slot);

	modem->master = CreateFile(modem->devlink,
	GENERIC_READ | GENERIC_WRITE,
	0,
	0,
	OPEN_EXISTING,
	FILE_FLAG_OVERLAPPED,
	0);
	if(modem->master==INVALID_HANDLE_VALUE) {
		status = SWITCH_STATUS_FALSE;
		if(GetLastError()==ERROR_FILE_NOT_FOUND) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: Serial port does not exist\n");
			goto end;
		}
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: Serial port open error\n");
		goto end;
	}
#elif !defined(HAVE_POSIX_OPENPT)
    modem->master = open("/dev/ptmx", O_RDWR);
#else
    modem->master = posix_openpt(O_RDWR | O_NOCTTY);
#endif

#ifndef WIN32
    if (modem->master < 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to initialize UNIX98 master pty\n");
		
    }

    if (grantpt(modem->master) < 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to grant access to slave pty\n");
		
    }

    if (unlockpt(modem->master) < 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to unlock slave pty\n");
		
    }

    modem->stty = ptsname(modem->master);

    if (modem->stty == NULL) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to obtain slave pty filename\n");
		
    }

    modem->slave = open(modem->stty, O_RDWR);

    if (modem->slave < 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to open slave pty %s\n", modem->stty);
    }
#endif

#ifdef SOLARIS
    ioctl(modem->slave, I_PUSH, "ptem");  /* push ptem */
    ioctl(modem->slave, I_PUSH, "ldterm");    /* push ldterm*/
#endif
#endif

#ifndef WIN32
	modem->slot = globals.NEXT_ID++;
	snprintf(modem->devlink, sizeof(modem->devlink), "/dev/FS%d", modem->slot);
	
    unlink(modem->devlink);

    if (symlink(modem->stty, modem->devlink)) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to create %s symbolic link\n", modem->devlink);
		modem_close(modem);
		status = SWITCH_STATUS_FALSE;
		goto end;
    }

    if (fcntl(modem->master, F_SETFL, fcntl(modem->master, F_GETFL, 0) | O_NONBLOCK)) {
	    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot set up non-blocking read on %s\n", ttyname(modem->master));
	    modem_close(modem);
	    status = SWITCH_STATUS_FALSE;
	    goto end;
    }
#else
	timeouts.ReadIntervalTimeout=50;
	timeouts.ReadTotalTimeoutConstant=50;
	timeouts.ReadTotalTimeoutMultiplier=10;

	timeouts.WriteTotalTimeoutConstant=50;
	timeouts.WriteTotalTimeoutMultiplier=10;

	SetCommMask(modem->master, EV_RXCHAR);

	if(!SetCommTimeouts(modem->master, &timeouts)){
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot set up non-blocking read on %s\n", modem->devlink);
		modem_close(modem);
		status = SWITCH_STATUS_FALSE;
		goto end;
	}
	modem->threadAbort = CreateEvent(NULL, TRUE, FALSE, NULL);
#endif
	
	if (!(modem->t31_state = t31_init(NULL, t31_at_tx_handler, modem, t31_call_control_handler, modem, NULL, NULL))) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot initialize the T.31 modem\n");
		modem_close(modem);
		status = SWITCH_STATUS_FALSE;
		goto end;
	}

	if (spandsp_globals.modem_verbose) {
		span_log_set_message_handler(&modem->t31_state->logging, spanfax_log_message, NULL);
		span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v17_rx.logging, spanfax_log_message, NULL);
		span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v29_rx.logging, spanfax_log_message, NULL);
		span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v27ter_rx.logging, spanfax_log_message, NULL);

		modem->t31_state->logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
		modem->t31_state->audio.modems.fast_modems.v17_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
		modem->t31_state->audio.modems.fast_modems.v29_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
		modem->t31_state->audio.modems.fast_modems.v27ter_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
	}

	modem->control_handler = control_handler;
	modem->flags = 0;
	switch_set_flag(modem, MODEM_FLAG_RUNNING);

	switch_mutex_init(&modem->mutex, SWITCH_MUTEX_NESTED, globals.pool);
	switch_mutex_init(&modem->cond_mutex, SWITCH_MUTEX_NESTED, globals.pool);
	switch_thread_cond_create(&modem->cond, globals.pool);

	modem_set_state(modem, MODEM_STATE_INIT);

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Modem [%s]->[%s] Ready\n", modem->devlink, modem->stty);

	switch_mutex_lock(globals.mutex);
	globals.REF_COUNT++;
	switch_mutex_unlock(globals.mutex);

end:
	return status;
}

static switch_endpoint_interface_t *modem_endpoint_interface = NULL;

struct private_object {
	switch_mutex_t *mutex;
	switch_core_session_t *session;
	switch_channel_t *channel;
	switch_codec_t read_codec;
	switch_codec_t write_codec;
	switch_frame_t read_frame;
	unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
	switch_timer_t timer;
	modem_t *modem;
	switch_caller_profile_t *caller_profile;
	int dead;
};

typedef struct private_object private_t;

static switch_status_t channel_on_init(switch_core_session_t *session);
static switch_status_t channel_on_hangup(switch_core_session_t *session);
static switch_status_t channel_on_destroy(switch_core_session_t *session);
static switch_status_t channel_on_routing(switch_core_session_t *session);
static switch_status_t channel_on_exchange_media(switch_core_session_t *session);
static switch_status_t channel_on_soft_execute(switch_core_session_t *session);
static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
													switch_caller_profile_t *outbound_profile,
													switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags,
													switch_call_cause_t *cancel_cause);
static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);


/* 
   State methods they get called when the state changes to the specific state 
   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
*/
static switch_status_t channel_on_init(switch_core_session_t *session)
{
	switch_channel_t *channel;
	private_t *tech_pvt = NULL;
	int to_ticks = 60, ring_ticks = 10, rt = ring_ticks;
	int rest = 500000;
	
	tech_pvt = switch_core_session_get_private(session);
	switch_assert(tech_pvt != NULL);

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

	if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
#ifndef WIN32
		int tioflags;
#endif
		char call_time[16];
		char call_date[16];
		switch_size_t retsize;
		switch_time_exp_t tm;

		switch_time_exp_lt(&tm, switch_micro_time_now());
		switch_strftime(call_date, &retsize, sizeof(call_date), "%m%d", &tm);
		switch_strftime(call_time, &retsize, sizeof(call_time), "%H%M", &tm);

#ifndef WIN32
		ioctl(tech_pvt->modem->slave, TIOCMGET, &tioflags);
		tioflags |= TIOCM_RI;
		ioctl(tech_pvt->modem->slave, TIOCMSET, &tioflags);
#endif

		at_reset_call_info(&tech_pvt->modem->t31_state->at_state);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "DATE", call_date);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "TIME", call_time);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NAME", tech_pvt->caller_profile->caller_id_name);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NMBR", tech_pvt->caller_profile->caller_id_number);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "ANID", tech_pvt->caller_profile->ani);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "USER", tech_pvt->caller_profile->username);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "CDID", tech_pvt->caller_profile->context);
		at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NDID", tech_pvt->caller_profile->destination_number);

		modem_set_state(tech_pvt->modem, MODEM_STATE_RINGING);
		t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ALERTING);
		
		while(to_ticks > 0 && switch_channel_up(channel) && modem_get_state(tech_pvt->modem) == MODEM_STATE_RINGING) {
			if (--rt <= 0) {
				t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ALERTING);
				rt = ring_ticks;
			}
			
			switch_yield(rest);
			to_ticks--;
		}
		
		if (to_ticks < 1 || modem_get_state(tech_pvt->modem) != MODEM_STATE_ANSWERED) {
			t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_NO_ANSWER);
			switch_channel_hangup(channel, SWITCH_CAUSE_NO_ANSWER);
		} else {
			t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ANSWERED);
			modem_set_state(tech_pvt->modem, MODEM_STATE_CONNECTED);
			switch_channel_mark_answered(channel);
		}
	}

	switch_channel_set_state(channel, CS_ROUTING);
	
	return SWITCH_STATUS_SUCCESS;
}
Ejemplo n.º 5
0
static int control_handler(modem_t *modem, const char *num, int op)
{
	switch_core_session_t *session = NULL;
	
	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Control Handler op:%d state:[%s] %s\n", 
					  op, modem_state2name(modem_get_state(modem)), modem->devlink);

    switch (op) {

    case AT_MODEM_CONTROL_ANSWER:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - Answering\n", modem->devlink, modem_state2name(modem_get_state(modem)));
		modem_set_state(modem, MODEM_STATE_ANSWERED);
        break;
    case AT_MODEM_CONTROL_CALL:
		{
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
							  "Modem %s [%s] - Dialing '%s'\n", modem->devlink, modem_state2name(modem_get_state(modem)), num);
			modem_set_state(modem, MODEM_STATE_DIALING);
			switch_clear_flag(modem, MODEM_FLAG_XOFF);
			wake_modem_thread(modem);

			switch_set_string(modem->digits, num);
			
			if (create_session(&session, modem) != SWITCH_STATUS_SUCCESS) {
				t31_call_event(modem->t31_state, AT_CALL_EVENT_HANGUP);
			} else {
				switch_core_session_thread_launch(session);
			}
		}
		break;
    case AT_MODEM_CONTROL_OFFHOOK:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - Going off hook\n", modem->devlink, modem_state2name(modem_get_state(modem)));
		modem_set_state(modem, MODEM_STATE_OFFHOOK);
		break;
    case AT_MODEM_CONTROL_ONHOOK:
    case AT_MODEM_CONTROL_HANGUP: 
		{
			if (modem_get_state(modem) != MODEM_STATE_RINGING) {
				int set_state = 1;
				
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
								  "Modem %s [%s] - Hanging up\n", modem->devlink, modem_state2name(modem_get_state(modem)));
				switch_clear_flag(modem, MODEM_FLAG_XOFF);
				wake_modem_thread(modem);
				

				modem_set_state(modem, MODEM_STATE_HANGUP);
			

				if (!zstr(modem->uuid_str)) {
					switch_core_session_t *session;
					
					if ((session = switch_core_session_force_locate(modem->uuid_str))) {
						switch_channel_t *channel = switch_core_session_get_channel(session);
						
						if (switch_channel_up(channel)) {
							switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
							set_state = 0;
						}
						switch_core_session_rwunlock(session);
					}
				}
				

				if (set_state) {
					modem_set_state(modem, MODEM_STATE_ONHOOK);
				}
			}
		}
        break;
    case AT_MODEM_CONTROL_DTR:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - DTR %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num);
        break;
    case AT_MODEM_CONTROL_RTS:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - RTS %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num);
        break;
    case AT_MODEM_CONTROL_CTS:
		{
			u_char x[1];
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1,
							  "Modem %s [%s] - CTS %s\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num ? "XON" : "XOFF");

			if (num) {
				x[0] = 0x11;
				t31_at_tx_handler(&modem->t31_state->at_state, modem, x, 1);
				switch_clear_flag(modem, MODEM_FLAG_XOFF);
				wake_modem_thread(modem);
			} else {
				x[0] = 0x13;
				t31_at_tx_handler(&modem->t31_state->at_state, modem, x, 1);
				switch_set_flag(modem, MODEM_FLAG_XOFF);
			}
		}
        break;
    case AT_MODEM_CONTROL_CAR:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - CAR %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num);
        break;
    case AT_MODEM_CONTROL_RNG:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - RNG %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num);
        break;
    case AT_MODEM_CONTROL_DSR:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - DSR %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num);
        break;
    default:
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
						  "Modem %s [%s] - operation %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), op);
        break;
    }
    /*endswitch*/
    return 0;
}
Ejemplo n.º 6
0
/* NB. this starts the input thread after some initial setup for the call leg */
void conference_loop_output(conference_member_t *member)
{
	switch_channel_t *channel;
	switch_frame_t write_frame = { 0 };
	uint8_t *data = NULL;
	switch_timer_t timer = { 0 };
	uint32_t interval;
	uint32_t samples;
	//uint32_t csamples;
	uint32_t tsamples;
	uint32_t flush_len;
	uint32_t low_count, bytes;
	call_list_t *call_list, *cp;
	switch_codec_implementation_t read_impl = { 0 };
	int sanity;
	switch_status_t st;

	switch_core_session_get_read_impl(member->session, &read_impl);


	channel = switch_core_session_get_channel(member->session);
	interval = read_impl.microseconds_per_packet / 1000;
	samples = switch_samples_per_packet(member->conference->rate, interval);
	//csamples = samples;
	tsamples = member->orig_read_impl.samples_per_packet;
	low_count = 0;
	bytes = samples * 2 * member->conference->channels;
	call_list = NULL;
	cp = NULL;

	member->loop_loop = 0;

	switch_assert(member->conference != NULL);

	flush_len = switch_samples_per_packet(member->conference->rate, member->conference->interval) * 2 * member->conference->channels * (500 / member->conference->interval);

	if (switch_core_timer_init(&timer, member->conference->timer_name, interval, tsamples, NULL) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Timer Setup Failed.  Conference Cannot Start\n");
		return;
	}

	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Setup timer %s success interval: %u  samples: %u\n",
					  member->conference->timer_name, interval, tsamples);


	write_frame.data = data = switch_core_session_alloc(member->session, SWITCH_RECOMMENDED_BUFFER_SIZE);
	write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;


	write_frame.codec = &member->write_codec;

	/* Start the input thread */
	conference_loop_launch_input(member, switch_core_session_get_pool(member->session));

	if ((call_list = switch_channel_get_private(channel, "_conference_autocall_list_"))) {
		const char *cid_name = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_name");
		const char *cid_num = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_number");
		const char *toval = switch_channel_get_variable(channel, "conference_auto_outcall_timeout");
		const char *flags = switch_channel_get_variable(channel, "conference_utils_auto_outcall_flags");
		const char *profile = switch_channel_get_variable(channel, "conference_auto_outcall_profile");
		const char *ann = switch_channel_get_variable(channel, "conference_auto_outcall_announce");
		const char *prefix = switch_channel_get_variable(channel, "conference_auto_outcall_prefix");
		const char *maxwait = switch_channel_get_variable(channel, "conference_auto_outcall_maxwait");
		const char *delimiter_val = switch_channel_get_variable(channel, "conference_auto_outcall_delimiter");
		int to = 60;
		int wait_sec = 2;
		int loops = 0;

		if (ann && !switch_channel_test_app_flag_key("conference_silent", channel, CONF_SILENT_REQ)) {
			member->conference->special_announce = switch_core_strdup(member->conference->pool, ann);
		}

		switch_channel_set_private(channel, "_conference_autocall_list_", NULL);

		conference_utils_set_flag(member->conference, CFLAG_OUTCALL);

		if (toval) {
			to = atoi(toval);
			if (to < 10 || to > 500) {
				to = 60;
			}
		}

		for (cp = call_list; cp; cp = cp->next) {
			int argc;
			char *argv[512] = { 0 };
			char *cpstr = strdup(cp->string);
			int x = 0;

			switch_assert(cpstr);
			if (!zstr(delimiter_val) && strlen(delimiter_val) == 1) {
				char delimiter = *delimiter_val;
				argc = switch_separate_string(cpstr, delimiter, argv, (sizeof(argv) / sizeof(argv[0])));
			} else {
				argc = switch_separate_string(cpstr, ',', argv, (sizeof(argv) / sizeof(argv[0])));
			}
			for (x = 0; x < argc; x++) {
				char *dial_str = switch_mprintf("%s%s", switch_str_nil(prefix), argv[x]);
				switch_assert(dial_str);
				conference_outcall_bg(member->conference, NULL, NULL, dial_str, to, switch_str_nil(flags), cid_name, cid_num, NULL,
									  profile, &member->conference->cancel_cause, NULL);
				switch_safe_free(dial_str);
			}
			switch_safe_free(cpstr);
		}

		if (maxwait) {
			int tmp = atoi(maxwait);
			if (tmp > 0) {
				wait_sec = tmp;
			}
		}


		loops = wait_sec * 10;

		switch_channel_set_app_flag(channel, CF_APP_TAGGED);
		do {
			switch_ivr_sleep(member->session, 100, SWITCH_TRUE, NULL);
		} while(switch_channel_up(channel) && (member->conference->originating && --loops));
		switch_channel_clear_app_flag(channel, CF_APP_TAGGED);

		if (!switch_channel_ready(channel)) {
			member->conference->cancel_cause = SWITCH_CAUSE_ORIGINATOR_CANCEL;
			goto end;
		}

		conference_member_play_file(member, "tone_stream://%(500,0,640)", 0, SWITCH_TRUE);
	}

	if (!conference_utils_test_flag(member->conference, CFLAG_ANSWERED)) {
		switch_channel_answer(channel);
	}


	sanity = 2000;
	while(!conference_utils_member_test_flag(member, MFLAG_ITHREAD) && sanity > 0) {
		switch_cond_next();
		sanity--;
	}

	/* Fair WARNING, If you expect the caller to hear anything or for digit handling to be processed,      */
	/* you better not block this thread loop for more than the duration of member->conference->timer_name!  */
	while (!member->loop_loop && conference_utils_member_test_flag(member, MFLAG_RUNNING) && conference_utils_member_test_flag(member, MFLAG_ITHREAD)
		   && switch_channel_ready(channel)) {
		switch_event_t *event;
		int use_timer = 0;
		switch_buffer_t *use_buffer = NULL;
		uint32_t mux_used = 0;


		//if (member->reset_media || switch_channel_test_flag(member->channel, CF_CONFERENCE_RESET_MEDIA)) {
		//	switch_cond_next();
		//	continue;
		//}

		switch_mutex_lock(member->write_mutex);


		if (switch_channel_test_flag(member->channel, CF_CONFERENCE_ADV)) {
			if (member->conference->la) {
				conference_event_adv_la(member->conference, member, SWITCH_TRUE);
			}
			switch_channel_clear_flag(member->channel, CF_CONFERENCE_ADV);
		}


		if (switch_core_session_dequeue_event(member->session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
			if (event->event_id == SWITCH_EVENT_MESSAGE) {
				char *from = switch_event_get_header(event, "from");
				char *to = switch_event_get_header(event, "to");
				char *body = switch_event_get_body(event);

				if (to && from && body) {
					if (strchr(to, '+') && strncmp(to, CONF_CHAT_PROTO, strlen(CONF_CHAT_PROTO))) {
						switch_event_del_header(event, "to");
						switch_event_add_header(event, SWITCH_STACK_BOTTOM,
												"to", "%s+%s@%s", CONF_CHAT_PROTO, member->conference->name, member->conference->domain);
					} else {
						switch_event_del_header(event, "to");
						switch_event_add_header(event, SWITCH_STACK_BOTTOM, "to", "%s", member->conference->name);
					}
					chat_send(event);
				}
			}
			switch_event_destroy(&event);
		}

		if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
			/* test to see if outbound channel has answered */
			if (switch_channel_test_flag(channel, CF_ANSWERED) && !conference_utils_test_flag(member->conference, CFLAG_ANSWERED)) {
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG,
								  "Outbound conference channel answered, setting CFLAG_ANSWERED\n");
				conference_utils_set_flag(member->conference, CFLAG_ANSWERED);
			}
		} else {
			if (conference_utils_test_flag(member->conference, CFLAG_ANSWERED) && !switch_channel_test_flag(channel, CF_ANSWERED)) {
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "CLFAG_ANSWERED set, answering inbound channel\n");
				switch_channel_answer(channel);
			}
		}

		use_buffer = NULL;
		mux_used = (uint32_t) switch_buffer_inuse(member->mux_buffer);

		use_timer = 1;

		if (mux_used) {
			if (mux_used < bytes) {
				if (++low_count >= 5) {
					/* partial frame sitting around this long is useless and builds delay */
					conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
				}
			} else if (mux_used > flush_len) {
				/* getting behind, clear the buffer */
				conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
			}
		}

		if (switch_channel_test_app_flag(channel, CF_APP_TAGGED)) {
			conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
		} else if (mux_used >= bytes) {
			/* Flush the output buffer and write all the data (presumably muxed) back to the channel */
			switch_mutex_lock(member->audio_out_mutex);
			write_frame.data = data;
			use_buffer = member->mux_buffer;
			low_count = 0;

			if ((write_frame.datalen = (uint32_t) switch_buffer_read(use_buffer, write_frame.data, bytes))) {
				if (write_frame.datalen) {
					write_frame.samples = write_frame.datalen / 2 / member->conference->channels;

					if( !conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) {
						memset(write_frame.data, 255, write_frame.datalen);
					} else if (member->volume_out_level) { /* Check for output volume adjustments */
						switch_change_sln_volume(write_frame.data, write_frame.samples * member->conference->channels, member->volume_out_level);
					}

					write_frame.timestamp = timer.samplecount;

					if (member->fnode) {
						conference_member_add_file_data(member, write_frame.data, write_frame.datalen);
					}

					conference_member_check_channels(&write_frame, member, SWITCH_FALSE);

					if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
						switch_mutex_unlock(member->audio_out_mutex);
						break;
					}
				}
			}

			switch_mutex_unlock(member->audio_out_mutex);
		}

		if (conference_utils_member_test_flag(member, MFLAG_FLUSH_BUFFER)) {
			if (switch_buffer_inuse(member->mux_buffer)) {
				switch_mutex_lock(member->audio_out_mutex);
				switch_buffer_zero(member->mux_buffer);
				switch_mutex_unlock(member->audio_out_mutex);
			}
			conference_utils_member_clear_flag_locked(member, MFLAG_FLUSH_BUFFER);
		}

		switch_mutex_unlock(member->write_mutex);


		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_MUTE)) {
			if (!zstr(member->conference->muted_sound)) {
				conference_member_play_file(member, member->conference->muted_sound, 0, SWITCH_TRUE);
			} else {
				char msg[512];

				switch_snprintf(msg, sizeof(msg), "Muted");
				conference_member_say(member, msg, 0);
			}
			conference_utils_member_clear_flag(member, MFLAG_INDICATE_MUTE);
		}

		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_MUTE_DETECT)) {
			if (!zstr(member->conference->mute_detect_sound)) {
				conference_member_play_file(member, member->conference->mute_detect_sound, 0, SWITCH_TRUE);
			} else {
				char msg[512];

				switch_snprintf(msg, sizeof(msg), "Currently Muted");
				conference_member_say(member, msg, 0);
			}
			conference_utils_member_clear_flag(member, MFLAG_INDICATE_MUTE_DETECT);
		}

		if (conference_utils_member_test_flag(member, MFLAG_INDICATE_UNMUTE)) {
			if (!zstr(member->conference->unmuted_sound)) {
				conference_member_play_file(member, member->conference->unmuted_sound, 0, SWITCH_TRUE);
			} else {
				char msg[512];

				switch_snprintf(msg, sizeof(msg), "Un-Muted");
				conference_member_say(member, msg, 0);
			}
			conference_utils_member_clear_flag(member, MFLAG_INDICATE_UNMUTE);
		}

		if (switch_core_session_private_event_count(member->session)) {
			switch_channel_set_app_flag(channel, CF_APP_TAGGED);
			switch_ivr_parse_all_events(member->session);
			switch_channel_clear_app_flag(channel, CF_APP_TAGGED);
			conference_utils_member_set_flag_locked(member, MFLAG_FLUSH_BUFFER);
			switch_core_session_set_read_codec(member->session, &member->read_codec);
		} else {
			switch_ivr_parse_all_messages(member->session);
		}

		if (use_timer) {
			switch_core_timer_next(&timer);
		} else {
			switch_cond_next();
		}

	} /* Rinse ... Repeat */

 end:

	if (!member->loop_loop) {
		conference_utils_member_clear_flag_locked(member, MFLAG_RUNNING);

		/* Wait for the input thread to end */
		if (member->input_thread) {
			switch_thread_join(&st, member->input_thread);
			member->input_thread = NULL;
		}
	}

	switch_core_timer_destroy(&timer);

	if (member->loop_loop) {
		return;
	}

	switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_INFO, "Channel leaving conference, cause: %s\n",
					  switch_channel_cause2str(switch_channel_get_cause(channel)));

	/* if it's an outbound channel, store the release cause in the conference struct, we might need it */
	if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
		member->conference->bridge_hangup_cause = switch_channel_get_cause(channel);
	}
}