示例#1
0
static void switch_core_standard_on_execute(switch_core_session_t *session)
{
	switch_caller_extension_t *extension;
	const char *uuid;

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

	switch_channel_set_variable(session->channel, "call_uuid", switch_core_session_get_uuid(session));

	if (switch_channel_get_variable(session->channel, "recovered") && !switch_channel_test_flag(session->channel, CF_RECOVERED)) {
		switch_channel_set_flag(session->channel, CF_RECOVERED);
	}

  top:
	switch_channel_clear_flag(session->channel, CF_RESET);
	
	if ((extension = switch_channel_get_caller_extension(session->channel)) == 0) {
		switch_channel_hangup(session->channel, SWITCH_CAUSE_NORMAL_CLEARING);
		return;
	}

	while (switch_channel_get_state(session->channel) == CS_EXECUTE && extension->current_application) {
		switch_caller_application_t *current_application = extension->current_application;

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

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

		if (switch_channel_test_flag(session->channel, CF_RESET)) {
			goto top;
		}

	}

	if (switch_channel_ready(session->channel) && switch_channel_get_state(session->channel) == CS_EXECUTE && 
		switch_channel_test_flag(session->channel, CF_CONFIRM_BLIND_TRANSFER) && 
		(uuid = switch_channel_get_variable(session->channel, "blind_transfer_uuid"))) {
		switch_core_session_t *other_session;

		if ((other_session = switch_core_session_locate(uuid))) {
			switch_core_session_message_t msg = { 0 };			
			msg.message_id = SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE;
			msg.from = __FILE__;
			msg.numeric_arg = 0;
			switch_core_session_receive_message(other_session, &msg);
			switch_core_session_rwunlock(other_session);

			switch_channel_set_variable(session->channel, "park_timeout", "10:blind_transfer");
			switch_channel_set_state(session->channel, CS_PARK);
			switch_channel_clear_flag(session->channel, CF_CONFIRM_BLIND_TRANSFER);
		}
	}
	
	if (switch_channel_ready(session->channel) && switch_channel_get_state(session->channel) == CS_EXECUTE) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "%s has executed the last dialplan instruction, hanging up.\n",
						  switch_channel_get_name(session->channel));
		switch_channel_hangup(session->channel, SWITCH_CAUSE_NORMAL_CLEARING);
	}
}
SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
{
	switch_channel_state_t state = CS_NEW, midstate = CS_DESTROY, endstate;
	const switch_endpoint_interface_t *endpoint_interface;
	const switch_state_handler_table_t *driver_state_handler = NULL;
	const switch_state_handler_table_t *application_state_handler = NULL;
	int silly = 0;
	uint32_t new_loops = 500;

	/*
	   Life of the channel. you have channel and pool in your session
	   everywhere you go you use the session to malloc with
	   switch_core_session_alloc(session, <size>)

	   The endpoint module gets the first crack at implementing the state
	   if it wants to, it can cancel the default behavior by returning SWITCH_STATUS_FALSE

	   Next comes the channel's event handler table that can be set by an application
	   which also can veto the next behavior in line by returning SWITCH_STATUS_FALSE

	   Finally the default state behavior is called.


	 */
	switch_assert(session != NULL);

	switch_set_flag(session, SSF_THREAD_RUNNING);
	endpoint_interface = session->endpoint_interface;
	switch_assert(endpoint_interface != NULL);

	driver_state_handler = endpoint_interface->state_handler;
	switch_assert(driver_state_handler != NULL);

	switch_mutex_lock(session->mutex);

	while ((state = switch_channel_get_state(session->channel)) != CS_DESTROY) {

		if (switch_channel_test_flag(session->channel, CF_BLOCK_STATE)) {
			switch_channel_wait_for_flag(session->channel, CF_BLOCK_STATE, SWITCH_FALSE, 0, NULL);
			if ((state = switch_channel_get_state(session->channel)) == CS_DESTROY) {
				break;
			}
		}

		midstate = state;
		if (state != switch_channel_get_running_state(session->channel) || state >= CS_HANGUP) {
			int index = 0;
			int proceed = 1;
			int global_proceed = 1;
			int do_extra_handlers = 1;
			switch_io_event_hook_state_run_t *ptr;
			switch_status_t rstatus = SWITCH_STATUS_SUCCESS;

			switch_channel_set_running_state(session->channel, state);
			switch_channel_clear_flag(session->channel, CF_TRANSFER);
			switch_channel_clear_flag(session->channel, CF_REDIRECT);
			switch_ivr_parse_all_messages(session);

			if (session->endpoint_interface->io_routines->state_run) {
				rstatus = session->endpoint_interface->io_routines->state_run(session);
			}
			
			if (rstatus == SWITCH_STATUS_SUCCESS) {
				for (ptr = session->event_hooks.state_run; ptr; ptr = ptr->next) {
					if ((rstatus = ptr->state_run(session)) != SWITCH_STATUS_SUCCESS) {
						break;
					}
				}
			}

			switch (state) {
			case CS_NEW:		/* Just created, Waiting for first instructions */
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "(%s) State NEW\n", switch_channel_get_name(session->channel));
				break;
			case CS_DESTROY:
				goto done;
			case CS_REPORTING:	/* Call Detail */
				{
					switch_core_session_reporting_state(session);
					switch_channel_set_state(session->channel, CS_DESTROY);
				}
				goto done;
			case CS_HANGUP:	/* Deactivate and end the thread */
				{
					switch_core_session_hangup_state(session, SWITCH_TRUE);
					if (switch_channel_test_flag(session->channel, CF_VIDEO)) {
						switch_core_session_wake_video_thread(session);
					}
					switch_channel_set_state(session->channel, CS_REPORTING);
				}

				break;
			case CS_INIT:		/* Basic setup tasks */
				{
					switch_event_t *event;

					STATE_MACRO(init, "INIT");
					
					if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_CREATE) == SWITCH_STATUS_SUCCESS) {
						switch_channel_event_set_data(session->channel, event);
						switch_event_fire(&event);
					}

					if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
						if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_ORIGINATE) == SWITCH_STATUS_SUCCESS) {
							switch_channel_event_set_data(session->channel, event);
							switch_event_fire(&event);
						}
					}
				}
				break;
			case CS_ROUTING:	/* Look for a dialplan and find something to do */
				STATE_MACRO(routing, "ROUTING");
				break;
			case CS_RESET:		/* Reset */
				STATE_MACRO(reset, "RESET");
				break;
				/* These other states are intended for prolonged durations so we do not signal lock for them */
			case CS_EXECUTE:	/* Execute an Operation */
				STATE_MACRO(execute, "EXECUTE");
				break;
			case CS_EXCHANGE_MEDIA:	/* loop all data back to source */
				STATE_MACRO(exchange_media, "EXCHANGE_MEDIA");
				break;
			case CS_SOFT_EXECUTE:	/* send/recieve data to/from another channel */
				STATE_MACRO(soft_execute, "SOFT_EXECUTE");
				break;
			case CS_PARK:		/* wait in limbo */
				STATE_MACRO(park, "PARK");
				break;
			case CS_CONSUME_MEDIA:	/* wait in limbo */
				STATE_MACRO(consume_media, "CONSUME_MEDIA");
				break;
			case CS_HIBERNATE:	/* sleep */
				STATE_MACRO(hibernate, "HIBERNATE");
				break;
			case CS_NONE:
				abort();
				break;
			}

			check_presence(session);

			if (midstate == CS_DESTROY) {
				break;
			}

		}

		endstate = switch_channel_get_state(session->channel);

		if (endstate == switch_channel_get_running_state(session->channel)) {
			if (endstate == CS_NEW) {
				switch_yield(20000);
				switch_ivr_parse_all_events(session);
				if (!--new_loops) {
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s %s Abandoned\n",
									  session->uuid_str, switch_core_session_get_name(session));
					switch_channel_set_flag(session->channel, CF_NO_CDR);
					switch_channel_hangup(session->channel, SWITCH_CAUSE_WRONG_CALL_STATE);
				}
			} else {
				switch_ivr_parse_all_events(session);
				switch_ivr_parse_all_events(session);

				if (switch_channel_get_state(session->channel) == switch_channel_get_running_state(session->channel)) {
					switch_channel_state_thread_lock(session->channel);
					switch_channel_set_flag(session->channel, CF_THREAD_SLEEPING);
					if (switch_channel_get_state(session->channel) == switch_channel_get_running_state(session->channel)) {
						switch_ivr_parse_all_events(session);
						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s session thread sleep state: %s!\n", 
										  switch_channel_get_name(session->channel),
										  switch_channel_state_name(switch_channel_get_running_state(session->channel)));
						switch_thread_cond_wait(session->cond, session->mutex);
						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s session thread wake state: %s!\n", 
										  switch_channel_get_name(session->channel),
										  switch_channel_state_name(switch_channel_get_running_state(session->channel)));


					}
					switch_channel_clear_flag(session->channel, CF_THREAD_SLEEPING);
					switch_channel_state_thread_unlock(session->channel);
				}

				switch_ivr_parse_all_events(session);
				switch_ivr_parse_all_events(session);
			}
		}
	}
  done:
	switch_mutex_unlock(session->mutex);

	switch_clear_flag(session, SSF_THREAD_RUNNING);
}
示例#3
0
static void switch_core_standard_on_routing(switch_core_session_t *session)
{
	switch_dialplan_interface_t *dialplan_interface = NULL;
	switch_caller_profile_t *caller_profile;
	switch_caller_extension_t *extension = NULL;
	char *expanded = NULL;
	char *dpstr = NULL;

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

	switch_channel_set_variable(session->channel, "call_uuid", switch_core_session_get_uuid(session));
		
	if ((switch_channel_test_flag(session->channel, CF_ANSWERED) ||
		 switch_channel_test_flag(session->channel, CF_EARLY_MEDIA) ||
		 switch_channel_test_flag(session->channel, CF_SIGNAL_BRIDGE_TTL)) && switch_channel_test_flag(session->channel, CF_PROXY_MODE)) {
		switch_ivr_media(session->uuid_str, SMF_NONE);
	}

	if ((caller_profile = switch_channel_get_caller_profile(session->channel)) == 0) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't get profile!\n");
		switch_channel_hangup(session->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
		return;
	} else {
		char *dp[25];
		int argc, x, count = 0;

		if ((extension = switch_channel_get_queued_extension(session->channel))) {
			switch_channel_set_caller_extension(session->channel, extension);
			switch_channel_set_state(session->channel, CS_EXECUTE);
			goto end;
		}

		if (!zstr(caller_profile->dialplan)) {
			if ((dpstr = switch_core_session_strdup(session, caller_profile->dialplan))) {
				expanded = switch_channel_expand_variables(session->channel, dpstr);
				argc = switch_separate_string(expanded, ',', dp, (sizeof(dp) / sizeof(dp[0])));
				for (x = 0; x < argc; x++) {
					char *dpname = dp[x];
					char *dparg = NULL;

					if (dpname) {
						if ((dparg = strchr(dpname, ':'))) {
							*dparg++ = '\0';
						}
					} else {
						continue;
					}
					if (!(dialplan_interface = switch_loadable_module_get_dialplan_interface(dpname))) {
						continue;
					}

					count++;

					extension = dialplan_interface->hunt_function(session, dparg, NULL);
					UNPROTECT_INTERFACE(dialplan_interface);

					if (extension) {
						switch_channel_set_caller_extension(session->channel, extension);
						switch_channel_set_state(session->channel, CS_EXECUTE);
						goto end;
					}
				}
			}
		}

		if (!count) {
			if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
				if (switch_channel_test_flag(session->channel, CF_ANSWERED)) {
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
									  "No Dialplan on answered channel, changing state to HANGUP\n");
					switch_channel_hangup(session->channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION);
				} else {
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No Dialplan, changing state to CONSUME_MEDIA\n");
					switch_channel_set_state(session->channel, CS_CONSUME_MEDIA);
				}
				goto end;
			}
		}
	}

	if (!extension) {

		if (switch_ivr_blind_transfer_ack(session, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "No Route, Aborting\n");
			switch_channel_hangup(session->channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION);
		}
	}

  end:

	if (expanded && dpstr && expanded != dpstr) {
		free(expanded);
	}
}
示例#4
0
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)
{
	char name[128];

	if (session) {
		switch_channel_t *channel = switch_core_session_get_channel(session);
		switch_channel_clear_flag(channel, CF_PROXY_MEDIA);
		switch_channel_clear_flag(channel, CF_PROXY_MODE);
		switch_channel_pre_answer(channel);
	}

	if ((*new_session = switch_core_session_request(loopback_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool)) != 0) {
		private_t *tech_pvt;
		switch_channel_t *channel;
		switch_caller_profile_t *caller_profile;

		switch_core_session_add_stream(*new_session, NULL);

		if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) {
			channel = switch_core_session_get_channel(*new_session);
			switch_snprintf(name, sizeof(name), "loopback/%s-a", outbound_profile->destination_number);
			switch_channel_set_name(channel, name);
			if (tech_init(tech_pvt, *new_session, session ? switch_core_session_get_read_codec(session) : NULL) != SWITCH_STATUS_SUCCESS) {
				switch_core_session_destroy(new_session);
				return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
			}
		} else {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
			switch_core_session_destroy(new_session);
			return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
		}

		if (outbound_profile) {
			char *dialplan = NULL, *context = NULL;

			caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
			caller_profile->source = switch_core_strdup(caller_profile->pool, modname);
			if (!strncasecmp(caller_profile->destination_number, "app=", 4)) {
				char *dest = switch_core_session_strdup(*new_session, caller_profile->destination_number);
				char *app = dest + 4;
				char *arg = NULL;

				if ((arg = strchr(app, ':'))) {
					*arg++ = '\0';
				}

				switch_channel_set_variable(channel, "loopback_app", app);
				if (arg) {
					switch_channel_set_variable(channel, "loopback_app_arg", arg);
				}

				caller_profile->destination_number = switch_core_strdup(caller_profile->pool, app);
			}

			if ((context = strchr(caller_profile->destination_number, '/'))) {
				*context++ = '\0';

				if ((dialplan = strchr(context, '/'))) {
					*dialplan++ = '\0';
				}

				if (!zstr(context)) {
					caller_profile->context = switch_core_strdup(caller_profile->pool, context);
				}

				if (!zstr(dialplan)) {
					caller_profile->dialplan = switch_core_strdup(caller_profile->pool, dialplan);
				}
			}

			if (zstr(caller_profile->context)) {
				caller_profile->context = switch_core_strdup(caller_profile->pool, "default");
			}

			if (zstr(caller_profile->dialplan)) {
				caller_profile->dialplan = switch_core_strdup(caller_profile->pool, "xml");
			}

			switch_snprintf(name, sizeof(name), "loopback/%s-a", caller_profile->destination_number);
			switch_channel_set_name(channel, name);
			switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND);
			switch_channel_set_caller_profile(channel, caller_profile);
			tech_pvt->caller_profile = caller_profile;
		} else {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_ERROR, "Doh! no caller profile\n");
			switch_core_session_destroy(new_session);
			return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
		}

		switch_channel_set_state(channel, CS_INIT);

		return SWITCH_CAUSE_SUCCESS;
	}

	return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
}
示例#5
0
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)
{
    switch_channel_t *channel;
    char name[128];
    crtp_private_t *tech_pvt = NULL;    
    switch_caller_profile_t *caller_profile;
    switch_rtp_flag_t rtp_flags[SWITCH_RTP_FLAG_INVALID] = {0};
    
    const char *err;

    
    const char  *local_addr = switch_event_get_header_nil(var_event, kLOCALADDR),
                *szlocal_port = switch_event_get_header_nil(var_event, kLOCALPORT),
                *remote_addr = switch_event_get_header_nil(var_event, kREMOTEADDR),
                *szremote_port = switch_event_get_header_nil(var_event, kREMOTEPORT),
                *codec  = switch_event_get_header_nil(var_event, kCODEC),
                *szptime  = switch_event_get_header_nil(var_event, kPTIME),
                //*mode  = switch_event_get_header_nil(var_event, kMODE),
                //*szrfc2833_pt = switch_event_get_header_nil(var_event, kRFC2833PT),
                *szrate = switch_event_get_header_nil(var_event, kRATE),
                *szpt = switch_event_get_header_nil(var_event, kPT);
    
    
    switch_port_t local_port = !zstr(szlocal_port) ? atoi(szlocal_port) : 0,
                 remote_port = !zstr(szremote_port) ? atoi(szremote_port) : 0;
    
    int ptime  = !zstr(szptime) ? atoi(szptime) : 0,
        //rfc2833_pt = !zstr(szrfc2833_pt) ? atoi(szrfc2833_pt) : 0,
        rate = !zstr(szrate) ? atoi(szrate) : 8000,
        pt = !zstr(szpt) ? atoi(szpt) : 0;
    
        if (
            ((zstr(remote_addr) || remote_port == 0) && (zstr(local_addr) || local_port == 0)) ||
            zstr(codec) ||
            zstr(szpt)) {
        
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing required arguments\n");
        goto fail;
    }
    
    
    if (!(*new_session = switch_core_session_request(crtp.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n");
        goto fail;
    }
    
    channel = switch_core_session_get_channel(*new_session);
    
    tech_pvt = switch_core_session_alloc(*new_session, sizeof *tech_pvt);
    tech_pvt->session = *new_session;
    tech_pvt->channel = channel;
    tech_pvt->local_address = switch_core_session_strdup(*new_session, local_addr);
    tech_pvt->local_port = local_port;
    tech_pvt->remote_address = switch_core_session_strdup(*new_session, remote_addr);
    tech_pvt->remote_port = remote_port;
    tech_pvt->ptime = ptime;
    tech_pvt->agreed_pt = pt;
    tech_pvt->dtmf_type = DTMF_2833; /* XXX */
    
    if (zstr(local_addr) || local_port == 0) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "The local address and port must be set\n");
        goto fail;
    } else if (zstr(remote_addr) || remote_port == 0) {
        tech_pvt->mode = RTP_RECVONLY;
    } else {
        tech_pvt->mode = RTP_SENDRECV;
    }
    
    switch_core_session_set_private(*new_session, tech_pvt);
    
    caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
    switch_channel_set_caller_profile(channel, caller_profile);
    
    
    snprintf(name, sizeof(name), "rtp/%s", outbound_profile->destination_number);
	switch_channel_set_name(channel, name);
    
    switch_channel_set_state(channel, CS_INIT);

	if (switch_core_codec_init(&tech_pvt->read_codec,
							   codec,
							   NULL,
							   rate,
							   ptime,
							   1,
							   /*SWITCH_CODEC_FLAG_ENCODE |*/ SWITCH_CODEC_FLAG_DECODE,
							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
        goto fail;
	} else {
		if (switch_core_codec_init(&tech_pvt->write_codec,
								   codec,
								   NULL,
								   rate,
								   ptime,
								   1,
								   SWITCH_CODEC_FLAG_ENCODE /*| SWITCH_CODEC_FLAG_DECODE*/, 
								   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
            goto fail;
		}
	}
    
    if (switch_core_session_set_read_codec(*new_session, &tech_pvt->read_codec) != SWITCH_STATUS_SUCCESS) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set read codec?\n");
        goto fail;
    }
    
    if (switch_core_session_set_write_codec(*new_session, &tech_pvt->write_codec) != SWITCH_STATUS_SUCCESS) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n");
        goto fail;
    }
    
    if (!(tech_pvt->rtp_session = switch_rtp_new(local_addr, local_port, remote_addr, remote_port, tech_pvt->agreed_pt,
												 tech_pvt->read_codec.implementation->samples_per_packet, ptime * 1000,
												 rtp_flags, "soft", &err, switch_core_session_get_pool(*new_session)))) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't setup RTP session: [%s]\n", err);
        goto fail;
    }
    
    if (switch_core_session_thread_launch(*new_session) != SWITCH_STATUS_SUCCESS) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start session thread.\n"); 
        goto fail;
    }
    
    switch_channel_mark_answered(channel);
    
    return SWITCH_CAUSE_SUCCESS;
    
fail:
     if (tech_pvt) {
        if (tech_pvt->read_codec.implementation) {
			switch_core_codec_destroy(&tech_pvt->read_codec);
		}
		
		if (tech_pvt->write_codec.implementation) {
			switch_core_codec_destroy(&tech_pvt->write_codec);
		}
    }
    
    if (*new_session) {
        switch_core_session_destroy(new_session);
    }
    return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
}
WSChannel* WSClientParser::CreateCall(
		switch_core_session_t *session,
		const char *profileName,
		const char *profileContext,
		const char *profileDialplan,
		const char* ip
		) {
	WSChannel *wsChannel = NULL;

	switch_memory_pool_t *pool = NULL;
	switch_channel_t* channel = NULL;
	switch_caller_profile_t *caller_profile = NULL;

	char *user = mpUser;
	char *domain = mpDomain;
	const char *destNumber = mpDestNumber;
	const char *context = NULL;
	const char *dialplan = NULL;
	switch_status_t status = SWITCH_STATUS_SUCCESS;

	switch_log_printf(
			SWITCH_CHANNEL_UUID_LOG(this->GetUUID()),
			SWITCH_LOG_INFO,
			"WSClientParser::CreateCall( "
			"this : %p, "
			"profileName : '%s', "
			"profileContext : '%s', "
			"profileDialplan : '%s', "
			"ip : '%s' "
			") \n",
			this,
			profileName,
			profileContext,
			profileDialplan,
			ip
			);

	// 参数不能为空
	if ( !user || !domain || !destNumber ) {
		status = SWITCH_STATUS_FALSE;
	}

	// 不允许一个连接创建多个会话
	if( status == SWITCH_STATUS_SUCCESS && mpChannel ) {
		status = SWITCH_STATUS_FALSE;
	}

	if( status == SWITCH_STATUS_SUCCESS ) {
		pool = switch_core_session_get_pool(session);
		channel = switch_core_session_get_channel(session);
		switch_channel_set_name(
				channel,
				switch_core_session_sprintf(session, "ws/%s/%s/%s", profileName, user, destNumber)
				);
	}

//	if ( status == SWITCH_STATUS_SUCCESS && !zstr(user) && !zstr(domain)) {
//		// 拨号不做验证
//		const char *ivrUser = switch_core_session_sprintf(session, "%s@%s", user, domain);
//		status = switch_ivr_set_user(session, ivrUser);
//	}

	if( status == SWITCH_STATUS_SUCCESS ) {
		if (!(context = switch_channel_get_variable(channel, "user_context"))) {
			if (!(context = profileContext)) {
				context = "public";
			}
		}

		if (!(dialplan = switch_channel_get_variable(channel, "inbound_dialplan"))) {
			if (!(dialplan = profileDialplan)) {
				dialplan = "LUA";
			}
		}

		//	switch_log_printf(
		//			SWITCH_CHANNEL_SESSION_LOG(session),
		//			SWITCH_LOG_NOTICE,
		//			"WSClientParser::CreateCall( "
		//			"context : %s, "
		//			"dialplan : %s "
		//			") \n",
		//			context,
		//			dialplan
		//			);

		// 设置主叫
		caller_profile = switch_caller_profile_new(
				pool,
				switch_str_nil(user),
				dialplan,
				SWITCH_DEFAULT_CLID_NAME,
				!zstr(user) ? user : SWITCH_DEFAULT_CLID_NUMBER,
				ip /* net addr */,
				NULL /* ani   */,
				NULL /* anii  */,
				NULL /* rdnis */,
				"mod_ws",
				context,
				destNumber
				);
		switch_channel_set_caller_profile(channel, caller_profile);
		switch_core_session_add_stream(session, NULL);
		switch_channel_set_variable(channel, "caller", user);
		switch_channel_set_state(channel, CS_INIT);

		wsChannel = CreateChannel(session);
	}

	if( wsChannel ) {
		switch_log_printf(
				SWITCH_CHANNEL_UUID_LOG(this->GetUUID()),
				SWITCH_LOG_INFO,
				"WSClientParser::CreateCall( "
				"[Success], "
				"this : %p, "
				"wsChannel : %p, "
				"profileName : '%s', "
				"profileContext : '%s', "
				"profileDialplan : '%s', "
				"ip : '%s' "
				") \n",
				this,
				wsChannel,
				profileName,
				profileContext,
				profileDialplan,
				ip
				);
	} else {
		switch_log_printf(
				SWITCH_CHANNEL_UUID_LOG(this->GetUUID()),
				SWITCH_LOG_ERROR,
				"WSClientParser::CreateCall( "
				"[Fail], "
				"this : %p "
				") \n",
				this,
				profileName,
				profileContext,
				profileDialplan,
				ip
				);
	}

	return wsChannel;
}
示例#7
0
/* 
   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, *b_channel;
	private_t *tech_pvt = NULL, *b_tech_pvt = NULL;
	switch_core_session_t *b_session;
	char name[128];
	switch_caller_profile_t *caller_profile;

	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_test_flag(tech_pvt, TFLAG_OUTBOUND) && !switch_test_flag(tech_pvt, TFLAG_BLEG)) {

		if (!(b_session = switch_core_session_request(loopback_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL))) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failure.\n");
			goto end;
		}

		if (switch_core_session_read_lock(b_session) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failure.\n");
			switch_core_session_destroy(&b_session);
			goto end;
		}

		switch_core_session_add_stream(b_session, NULL);
		b_channel = switch_core_session_get_channel(b_session);
		b_tech_pvt = (private_t *) switch_core_session_alloc(b_session, sizeof(*b_tech_pvt));

		switch_snprintf(name, sizeof(name), "loopback/%s-b", tech_pvt->caller_profile->destination_number);
		switch_channel_set_name(b_channel, name);
		if (tech_init(b_tech_pvt, b_session, switch_core_session_get_read_codec(session)) != SWITCH_STATUS_SUCCESS) {
			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
			switch_core_session_destroy(&b_session);
			goto end;
		}

		caller_profile = switch_caller_profile_clone(b_session, tech_pvt->caller_profile);
		caller_profile->source = switch_core_strdup(caller_profile->pool, modname);
		switch_channel_set_caller_profile(b_channel, caller_profile);
		b_tech_pvt->caller_profile = caller_profile;
		switch_channel_set_state(b_channel, CS_INIT);

		tech_pvt->other_session = b_session;
		tech_pvt->other_tech_pvt = b_tech_pvt;
		tech_pvt->other_channel = b_channel;

		//b_tech_pvt->other_session = session;
		//b_tech_pvt->other_tech_pvt = tech_pvt;
		//b_tech_pvt->other_channel = channel;

		b_tech_pvt->other_uuid = switch_core_session_strdup(b_session, switch_core_session_get_uuid(session));

		switch_set_flag_locked(tech_pvt, TFLAG_LINKED);
		switch_set_flag_locked(b_tech_pvt, TFLAG_LINKED);
		switch_set_flag_locked(b_tech_pvt, TFLAG_BLEG);


		switch_channel_set_flag(channel, CF_ACCEPT_CNG);
		//switch_ivr_transfer_variable(session, tech_pvt->other_session, "process_cdr");
		switch_ivr_transfer_variable(session, tech_pvt->other_session, NULL);

		switch_channel_set_variable(channel, "other_loopback_leg_uuid", switch_channel_get_uuid(b_channel));
		switch_channel_set_variable(b_channel, "other_loopback_leg_uuid", switch_channel_get_uuid(channel));

		if (switch_core_session_thread_launch(b_session) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error spawning thread\n");
			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
			goto end;
		}
	} else if ((tech_pvt->other_session = switch_core_session_locate(tech_pvt->other_uuid))) {
		tech_pvt->other_tech_pvt = switch_core_session_get_private(tech_pvt->other_session);
		tech_pvt->other_channel = switch_core_session_get_channel(tech_pvt->other_session);
	}

	if (!tech_pvt->other_session) {
		switch_clear_flag_locked(tech_pvt, TFLAG_LINKED);
		switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
		goto end;
	}

	switch_channel_set_variable(channel, "loopback_leg", switch_test_flag(tech_pvt, TFLAG_BLEG) ? "B" : "A");
	switch_channel_set_state(channel, CS_ROUTING);

  end:

	return SWITCH_STATUS_SUCCESS;
}
示例#8
0
static switch_status_t process_event(switch_event_t *event)
{
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	switch_core_session_t *session = NULL;
	char *username[3] = { NULL };
	char *domain[3] = { NULL };
	char key[512];
	char *uuid = NULL, *my_uuid = NULL;
	int i;


	switch_thread_rwlock_rdlock(globals.spy_hash_lock);

	if (!globals.spy_count) {
		goto done;
	}

	username[0] = switch_event_get_header(event, "Caller-Username");
	domain[0] = switch_event_get_header(event, "variable_domain_name");

	username[1] = switch_event_get_header(event, "variable_dialed_user");
	domain[1] = switch_event_get_header(event, "variable_dialed_domain");

	username[2] = switch_event_get_header(event, "variable_user_name");
	domain[2] = switch_event_get_header(event, "variable_domain_name");

	for (i = 0; i < 3; i++) {

		if (username[i] && domain[i]) {
			spy_t *spy = NULL;
			switch_snprintf(key, sizeof(key), "%s@%s", username[i], domain[i]);

			if ((spy = switch_core_hash_find(globals.spy_hash, key))) {
				while (spy) {
					if ((session = switch_core_session_locate(spy->uuid))) {
						switch_channel_t *channel = switch_core_session_get_channel(session);
						
						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "UserSpy retrieved uuid %s for key %s, activating eavesdrop\n", uuid, key);
						my_uuid = switch_event_get_header(event, "Unique-ID");
						
						switch_channel_set_variable(channel, "spy_uuid", my_uuid);
						
						switch_channel_set_state(channel, CS_EXCHANGE_MEDIA);
						switch_channel_set_flag(channel, CF_BREAK);
						
						switch_core_session_rwunlock(session);
					}
					spy = spy->next;
				}
				break;
			} else {
				/* not found */
				status = SWITCH_STATUS_FALSE;
			}
		}
	}
	
	
 done:
	switch_thread_rwlock_unlock(globals.spy_hash_lock);
	return status;


}
示例#9
0
/* 
   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, *b_channel;
	private_t *tech_pvt = NULL, *b_tech_pvt = NULL;
	switch_core_session_t *b_session;
	char name[128];
	switch_caller_profile_t *caller_profile;
	switch_event_t *vars = NULL;
	const char *var;

	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_test_flag(tech_pvt, TFLAG_OUTBOUND) && !switch_test_flag(tech_pvt, TFLAG_BLEG)) {

		if (!(b_session = switch_core_session_request(loopback_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL))) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failure.\n");
			goto end;
		}

		if (switch_core_session_read_lock(b_session) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failure.\n");
			switch_core_session_destroy(&b_session);
			goto end;
		}

		switch_core_session_add_stream(b_session, NULL);
		b_channel = switch_core_session_get_channel(b_session);
		b_tech_pvt = (private_t *) switch_core_session_alloc(b_session, sizeof(*b_tech_pvt));

		switch_snprintf(name, sizeof(name), "loopback/%s-b", tech_pvt->caller_profile->destination_number);
		switch_channel_set_name(b_channel, name);
		if (tech_init(b_tech_pvt, b_session, switch_core_session_get_read_codec(session)) != SWITCH_STATUS_SUCCESS) {
			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
			switch_core_session_destroy(&b_session);
			goto end;
		}

		caller_profile = switch_caller_profile_clone(b_session, tech_pvt->caller_profile);
		caller_profile->source = switch_core_strdup(caller_profile->pool, modname);
		switch_channel_set_caller_profile(b_channel, caller_profile);
		b_tech_pvt->caller_profile = caller_profile;
		switch_channel_set_state(b_channel, CS_INIT);

		tech_pvt->other_session = b_session;
		tech_pvt->other_tech_pvt = b_tech_pvt;
		tech_pvt->other_channel = b_channel;

		//b_tech_pvt->other_session = session;
		//b_tech_pvt->other_tech_pvt = tech_pvt;
		//b_tech_pvt->other_channel = channel;

		b_tech_pvt->other_uuid = switch_core_session_strdup(b_session, switch_core_session_get_uuid(session));

		switch_set_flag_locked(tech_pvt, TFLAG_LINKED);
		switch_set_flag_locked(b_tech_pvt, TFLAG_LINKED);
		switch_set_flag_locked(b_tech_pvt, TFLAG_BLEG);


		switch_channel_set_flag(channel, CF_ACCEPT_CNG);

		if ((vars = (switch_event_t *) switch_channel_get_private(channel, "__loopback_vars__"))) {
			switch_event_header_t *h;
		
			switch_channel_set_private(channel, "__loopback_vars__", NULL);

			for (h = vars->headers; h; h = h->next) {
				switch_channel_set_variable(tech_pvt->other_channel, h->name, h->value);
			}

			switch_event_destroy(&vars);
		}

		if ((var = switch_channel_get_variable(channel, "loopback_export"))) {
			int argc = 0;
			char *argv[128] = { 0 };
			char *dup = switch_core_session_strdup(session, var);

			if ((argc = switch_split(dup, ',', argv))) {
				int i;
				for (i = 0; i < argc; i++) {
					
					if (!zstr(argv[i])) {
						const char *val = switch_channel_get_variable(channel, argv[i]);

						if(!zstr(val)) {
							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Transfer variable [%s]=[%s] %s -> %s\n",
											  argv[i], val, switch_channel_get_name(channel), switch_channel_get_name(tech_pvt->other_channel));
											  
							switch_channel_set_variable(tech_pvt->other_channel, argv[i], val);
						}
					}
				}
			}
		}

		if (switch_test_flag(tech_pvt, TFLAG_APP)) {
			switch_set_flag(b_tech_pvt, TFLAG_APP);
			switch_clear_flag(tech_pvt, TFLAG_APP);
		}

		switch_channel_set_variable(channel, "other_loopback_leg_uuid", switch_channel_get_uuid(b_channel));
		switch_channel_set_variable(b_channel, "other_loopback_leg_uuid", switch_channel_get_uuid(channel));

		if (switch_core_session_thread_launch(b_session) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error spawning thread\n");
			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
			goto end;
		}
	} else if ((tech_pvt->other_session = switch_core_session_locate(tech_pvt->other_uuid))) {
		tech_pvt->other_tech_pvt = switch_core_session_get_private(tech_pvt->other_session);
		tech_pvt->other_channel = switch_core_session_get_channel(tech_pvt->other_session);
	}

	if (!tech_pvt->other_session) {
		switch_clear_flag_locked(tech_pvt, TFLAG_LINKED);
		switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
		goto end;
	}

	switch_channel_set_variable(channel, "loopback_leg", switch_test_flag(tech_pvt, TFLAG_BLEG) ? "B" : "A");
	switch_channel_set_state(channel, CS_ROUTING);

  end:

	return SWITCH_STATUS_SUCCESS;
}
示例#10
0
static switch_status_t channel_on_execute(switch_core_session_t *session)
{
	switch_channel_t *channel = NULL;
	loopback_private_t *tech_pvt = NULL;
	switch_caller_extension_t *exten = NULL;
	const char *bowout = NULL;
	int bow = 0;

	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));

	if ((bowout = switch_channel_get_variable(tech_pvt->channel, "loopback_bowout_on_execute")) && switch_true(bowout)) {
		/* loopback_bowout_on_execute variable is set */
		bow = 1;
	} else if ((exten = switch_channel_get_caller_extension(channel))) {
		/* check for bowout flag */
		switch_caller_application_t *app_p;

		for (app_p = exten->applications; app_p; app_p = app_p->next) {
			int32_t flags;

			switch_core_session_get_app_flags(app_p->application_name, &flags);

			if ((flags & SAF_NO_LOOPBACK)) {
				bow = 1;
				break;
			}
		}
	}

	if (bow) {
		switch_core_session_t *other_session = NULL;
		switch_caller_profile_t *cp, *clone;
		const char *other_uuid = NULL;
		switch_event_t *event = NULL;

		switch_set_flag(tech_pvt, TFLAG_BOWOUT);

		if ((find_non_loopback_bridge(tech_pvt->other_session, &other_session, &other_uuid) == SWITCH_STATUS_SUCCESS)) {
			switch_channel_t *other_channel = switch_core_session_get_channel(other_session);

			switch_channel_wait_for_state_timeout(other_channel, CS_EXCHANGE_MEDIA, 5000);

			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_INFO, "BOWOUT Replacing loopback channel with real channel: %s\n",
							  switch_channel_get_name(other_channel));

			if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, "loopback::bowout") == SWITCH_STATUS_SUCCESS) {
				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Resigning-UUID", switch_channel_get_uuid(channel));
				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Acquired-UUID", switch_channel_get_uuid(other_channel));
				switch_event_fire(&event);
			}

			if ((cp = switch_channel_get_caller_profile(channel))) {
				clone = switch_caller_profile_clone(other_session, cp);
				clone->originator_caller_profile = NULL;
				clone->originatee_caller_profile = NULL;
				switch_channel_set_caller_profile(other_channel, clone);
			}

			switch_channel_caller_extension_masquerade(channel, other_channel, 0);
			switch_channel_set_state(other_channel, CS_RESET);
			switch_channel_wait_for_state(other_channel, NULL, CS_RESET);
			switch_channel_set_state(other_channel, CS_EXECUTE);
			switch_core_session_rwunlock(other_session);
			switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_UNSPECIFIED);
		}
	}

	return SWITCH_STATUS_SUCCESS;
}
示例#11
0
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)
{
    const char  *szchanid = switch_event_get_header(var_event, kCHAN_ID),
                *span_name = switch_event_get_header(var_event, kSPAN_NAME),
                *szprebuffer_len = switch_event_get_header(var_event, kPREBUFFER_LEN);
    int chan_id;
    int span_id;
    switch_caller_profile_t *caller_profile;
    ftdm_span_t *span;
    ftdm_channel_t *chan;
    switch_channel_t *channel;
    char name[128];
    const char *dname;
    ftdm_codec_t codec;
    uint32_t interval;
    ctdm_private_t *tech_pvt = NULL;

    if (zstr(szchanid) || zstr(span_name)) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Both ["kSPAN_ID"] and ["kCHAN_ID"] have to be set.\n");
        goto fail;
    }
    
    chan_id = atoi(szchanid);
    
    if (ftdm_span_find_by_name(span_name, &span) == FTDM_SUCCESS) {
         span_id = ftdm_span_get_id(span);   
    } else {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find span [%s]\n", span_name);
        goto fail;
    }

    if (!(*new_session = switch_core_session_request(ctdm.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n");
        goto fail;
    }
    
    channel = switch_core_session_get_channel(*new_session);
    
    if (ftdm_channel_open_ph(span_id, chan_id, &chan) != FTDM_SUCCESS) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open span or channel.\n"); 
        goto fail;
    }
    
    span = ftdm_channel_get_span(chan);
    
    tech_pvt = switch_core_session_alloc(*new_session, sizeof *tech_pvt);
    tech_pvt->chan_id = chan_id;
    tech_pvt->span_id = span_id;
    tech_pvt->ftdm_channel = chan;
    tech_pvt->session = *new_session;
    tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
    tech_pvt->read_frame.data = tech_pvt->databuf;
    tech_pvt->prebuffer_len = zstr(szprebuffer_len) ? 0 : atoi(szprebuffer_len);
    switch_core_session_set_private(*new_session, tech_pvt);
    
    
    caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
    switch_channel_set_caller_profile(channel, caller_profile);
    
    snprintf(name, sizeof(name), "tdm/%d:%d", span_id, chan_id);
	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name);
	switch_channel_set_name(channel, name);
    
    switch_channel_set_state(channel, CS_INIT);
    
	if (FTDM_SUCCESS != ftdm_channel_command(chan, FTDM_COMMAND_GET_CODEC, &codec)) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel codec.\n");
		return SWITCH_STATUS_GENERR;
	}
    
    if (FTDM_SUCCESS != ftdm_channel_command(chan, FTDM_COMMAND_GET_INTERVAL, &interval)) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel interval.\n");
		return SWITCH_STATUS_GENERR;
	}
    
    if (FTDM_SUCCESS != ftdm_channel_command(chan, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tech_pvt->prebuffer_len)) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set channel pre buffer size.\n");
		return SWITCH_STATUS_GENERR;        
    }

    if (FTDM_SUCCESS != ftdm_channel_command(tech_pvt->ftdm_channel, FTDM_COMMAND_ENABLE_ECHOCANCEL, NULL)) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to set enable echo cancellation.\n");
	}
    
	switch(codec) {
        case FTDM_CODEC_ULAW:
		{
			dname = "PCMU";
		}
            break;
        case FTDM_CODEC_ALAW:
		{
			dname = "PCMA";
		}
            break;
        case FTDM_CODEC_SLIN:
		{
			dname = "L16";
		}
            break;
        default:
		{
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid codec value retrieved from channel, codec value: %d\n", codec);
			goto fail;
		}
	}

    
	if (switch_core_codec_init(&tech_pvt->read_codec,
							   dname,
							   NULL,
							   8000,
							   interval,
							   1,
							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
        goto fail;
	} else {
		if (switch_core_codec_init(&tech_pvt->write_codec,
								   dname,
								   NULL,
								   8000,
								   interval,
								   1,
								   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
								   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
			switch_core_codec_destroy(&tech_pvt->read_codec);
            goto fail;
		}
	}
    
    if (switch_core_session_set_read_codec(*new_session, &tech_pvt->read_codec) != SWITCH_STATUS_SUCCESS) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set read codec?\n");
        goto fail;
    }
    
    if (switch_core_session_set_write_codec(*new_session, &tech_pvt->write_codec) != SWITCH_STATUS_SUCCESS) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n");        
    }
    
    if (switch_core_session_thread_launch(*new_session) != SWITCH_STATUS_SUCCESS) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start session thread.\n"); 
        goto fail;
    }
    
    switch_channel_mark_answered(channel);
    
    return SWITCH_CAUSE_SUCCESS;

fail:
    
    if (tech_pvt) {
        if (tech_pvt->ftdm_channel) {
            ftdm_channel_close(&tech_pvt->ftdm_channel);
        }
        
        if (tech_pvt->read_codec.implementation) {
			switch_core_codec_destroy(&tech_pvt->read_codec);
		}
		
		if (tech_pvt->write_codec.implementation) {
			switch_core_codec_destroy(&tech_pvt->write_codec);
		}
    }
    
    if (*new_session) {
        switch_core_session_destroy(new_session);
    }
    return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
}
static switch_status_t create_session(switch_core_session_t **new_session, modem_t *modem)
{
	switch_status_t status = SWITCH_STATUS_FALSE;
	switch_core_session_t *session;
	switch_channel_t *channel;
	private_t *tech_pvt = NULL;
	char name[1024];
	switch_caller_profile_t *caller_profile;
	char *ani = NULL, *p, *digits = NULL;
	
	if (!(session = switch_core_session_request(modem_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL))) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failure.\n");
		goto end;
	}

	switch_core_session_add_stream(session, NULL);
	channel = switch_core_session_get_channel(session);
	tech_pvt = (private_t *) switch_core_session_alloc(session, sizeof(*tech_pvt));
	
	p = switch_core_session_strdup(session, modem->digits);

	if (*p == '*') {
		ani = p + 1;
		if ((digits = strchr(ani, '*'))) {
			*digits++ = '\0';
		} else {
			ani = NULL;
		}
	}
	
	if (zstr(digits)) {
		digits = p;
	}

	if (zstr(ani)) {
		ani = modem->devlink + 5;
	}

	switch_snprintf(name, sizeof(name), "modem/%d/%s", modem->slot, digits);
	switch_channel_set_name(channel, name);

	if (tech_init(tech_pvt, session) != SWITCH_STATUS_SUCCESS) {
		switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
		switch_core_session_destroy(&session);
		goto end;
	}

	caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
											   modem->devlink,
											   spandsp_globals.modem_dialplan,
											   "FSModem", 
											   ani,
											   NULL, 
											   ani,
											   NULL, 
											   NULL, 
											   "mod_spandsp", 
											   spandsp_globals.modem_context, 
											   digits);


	
	caller_profile->source = switch_core_strdup(caller_profile->pool, "mod_spandsp");
	switch_channel_set_caller_profile(channel, caller_profile);
	tech_pvt->caller_profile = caller_profile;
	switch_channel_set_state(channel, CS_INIT);

	if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error spawning thread\n");
		switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
		goto end;
	}

	status = SWITCH_STATUS_SUCCESS;
	tech_attach(tech_pvt, modem);
	*new_session = session;

 end:

	return status;
}
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)
{
	char name[128];
	switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;

	if ((*new_session = switch_core_session_request(modem_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, flags, pool)) != 0) {
		private_t *tech_pvt;
		switch_channel_t *channel;
		switch_caller_profile_t *caller_profile;
		char *dest = switch_core_session_strdup(*new_session, outbound_profile->destination_number);
		char *modem_id_string = NULL;
		char *number = NULL;
		int modem_id = 0;
		modem_t *modem = NULL;

		if ((modem_id_string = dest)) {
			if ((number = strchr(modem_id_string, '/'))) {
				*number++ = '\0';
			}
		}

		if (zstr(modem_id_string) || zstr(number)) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_ERROR, "Invalid dial string.\n");
			cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; goto fail;
		}

		if (!strcasecmp(modem_id_string, "a")) {
			modem_id = -1;
		} else {
			modem_id = atoi(modem_id_string);
		}

		if (!(modem = acquire_modem(modem_id))) {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_ERROR, "Cannot find a modem.\n");
			cause = SWITCH_CAUSE_USER_BUSY; goto fail;
		}
		
		switch_core_session_add_stream(*new_session, NULL);

		if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) {
			channel = switch_core_session_get_channel(*new_session);
			switch_snprintf(name, sizeof(name), "modem/%d/%s", modem->slot, number);
			switch_channel_set_name(channel, name);

			if (tech_init(tech_pvt, *new_session) != SWITCH_STATUS_SUCCESS) {
				cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; goto fail;
			}

			switch_set_string(modem->digits, number);
			tech_attach(tech_pvt, modem);
		} else {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
			switch_core_session_destroy(new_session);
			cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; goto fail;
		}

		if (outbound_profile) {
			caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
			caller_profile->source = switch_core_strdup(caller_profile->pool, "mod_spandsp");
			switch_channel_set_caller_profile(channel, caller_profile);
			tech_pvt->caller_profile = caller_profile;
		} else {
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_ERROR, "Doh! no caller profile\n");
			cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; goto fail;
		}

		switch_channel_set_state(channel, CS_INIT);

		return SWITCH_CAUSE_SUCCESS;

	fail:

		if (new_session) {
			switch_core_session_destroy(new_session);
		}

		if (modem) {
			modem_set_state(modem, MODEM_STATE_ONHOOK);
		}
	}

	return cause;
}
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;
}