Esempio n. 1
0
FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan)
{
	uint8_t i = 0;
	ftdm_time_t currtime = 0;
	ftdm_time_t prevtime = 0;

	ftdm_stream_handle_t stream = { 0 };
	FTDM_STANDARD_STREAM(stream);
	if (!fchan->history[0].file) {
		stream.write_function(&stream, "-- No state history --\n");
		return stream.data;
	}

	stream.write_function(&stream, "%-30.30s %-30.30s %-30.30s %s", 
			"-- States --", "-- Function --", "-- Location --", "-- Time Offset --\n");

	for (i = fchan->hindex; i < ftdm_array_len(fchan->history); i++) {
		if (!fchan->history[i].file) {
			break;
		}
		write_history_entry(fchan, &stream, i, &prevtime);
	}

	for (i = 0; i < fchan->hindex; i++) {
		write_history_entry(fchan, &stream, i, &prevtime);
	}

	currtime = ftdm_current_time_in_ms();

	stream.write_function(&stream, "\nTime since last state change: %lums\n", (currtime - prevtime));

	return stream.data;
}
Esempio n. 2
0
/**
 * \brief Executes an FreeTDM command on a Wanpipe channel
 * \param ftdmchan Channel to execute command on
 * \param command FreeTDM command to execute
 * \param obj Object (unused)
 * \return Success or failure
 */
static FIO_COMMAND_FUNCTION(wanpipe_command)
{
	wanpipe_tdm_api_t tdm_api;
	int err = 0;

	memset(&tdm_api, 0, sizeof(tdm_api));

	switch(command) {
	case FTDM_COMMAND_OFFHOOK:
		{
			err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
			if (err) {
				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "OFFHOOK Failed");
				return FTDM_FAIL;
			}
			ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
		}
		break;
	case FTDM_COMMAND_ONHOOK:
		{
			err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
			if (err) {
				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
				return FTDM_FAIL;
			}
			ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
		}
		break;
	case FTDM_COMMAND_GENERATE_RING_ON:
		{
			err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api);
			if (err) {
				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
				return FTDM_FAIL;
			}
			ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
			ftdm_set_pflag_locked(ftdmchan, WP_RINGING);
			ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms;
		}
		break;
	case FTDM_COMMAND_GENERATE_RING_OFF:
		{
			err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
			if (err) {
				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed");
				return FTDM_FAIL;
			}
			ftdm_clear_pflag_locked(ftdmchan, WP_RINGING);
			ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
		}
		break;
	case FTDM_COMMAND_GET_INTERVAL:
		{
			err=sangoma_tdm_get_usr_period(ftdmchan->sockfd, &tdm_api);
			if (err > 0 ) {
				FTDM_COMMAND_OBJ_INT = err;
				err=0;
			}
		}
		break;
	case FTDM_COMMAND_ENABLE_ECHOCANCEL:
		{
			err=sangoma_tdm_enable_hwec(ftdmchan->sockfd, &tdm_api);
			if (err) {
             			snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Enable Failed");
				return FTDM_FAIL;
			}
		}
		break;
	case FTDM_COMMAND_DISABLE_ECHOCANCEL:
		{
			err=sangoma_tdm_disable_hwec(ftdmchan->sockfd, &tdm_api);
			if (err) {
             			snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Disable Failed");
				return FTDM_FAIL;
			}
		}
		break;
	case FTDM_COMMAND_ENABLE_DTMF_DETECT:
		{
#ifdef WP_API_FEATURE_DTMF_EVENTS
			err = sangoma_tdm_enable_dtmf_events(ftdmchan->sockfd, &tdm_api);
			if (err) {
				ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Enabling of Sangoma HW DTMF failed\n");
             			snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HW DTMF Enable Failed");
				return FTDM_FAIL;
			}
			ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Enabled DTMF events\n");
#else
			return FTDM_NOTIMPL;
#endif
		}
		break;
	case FTDM_COMMAND_DISABLE_DTMF_DETECT:
		{
#ifdef WP_API_FEATURE_DTMF_EVENTS
			err = sangoma_tdm_disable_dtmf_events(ftdmchan->sockfd, &tdm_api);
			if (err) {
				ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Disabling of Sangoma HW DTMF failed\n");
             			snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HW DTMF Disable Failed");
				return FTDM_FAIL;
			}
			ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Disabled DTMF events\n");
#else
			return FTDM_NOTIMPL;
#endif
		}
		break;
	case FTDM_COMMAND_ENABLE_LOOP:
		{
#ifdef WP_API_FEATURE_LOOP
         	err=sangoma_tdm_enable_loop(ftdmchan->sockfd, &tdm_api);
			if (err) {
				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Enable Failed");
				return FTDM_FAIL;
			}
#endif		
		}
		break;
	case FTDM_COMMAND_DISABLE_LOOP:
		{
#ifdef WP_API_FEATURE_LOOP
         	err=sangoma_tdm_disable_loop(ftdmchan->sockfd, &tdm_api);
			if (err) {
				snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Disable Failed");
				return FTDM_FAIL;
			}
#endif	 
		}
		break;
	case FTDM_COMMAND_SET_INTERVAL: 
		{
			err=sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, FTDM_COMMAND_OBJ_INT);
			ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
		}
		break;
	case FTDM_COMMAND_SET_CAS_BITS:
		{
#ifdef LIBSANGOMA_VERSION
			err = sangoma_tdm_write_rbs(ftdmchan->sockfd,&tdm_api, ftdmchan->physical_chan_id, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT));
#else
			err = sangoma_tdm_write_rbs(ftdmchan->sockfd, &tdm_api, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT));
#endif
		}
		break;
	case FTDM_COMMAND_GET_CAS_BITS:
		{
#ifdef LIBSANGOMA_VERSION
			unsigned char rbsbits;
			err = sangoma_tdm_read_rbs(ftdmchan->sockfd, &tdm_api, ftdmchan->physical_chan_id, &rbsbits);
			if (!err) {
				FTDM_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits);
			}
#else
			// does sangoma_tdm_read_rbs is available here?
			FTDM_COMMAND_OBJ_INT = ftdmchan->rx_cas_bits;
#endif
		}
		break;
	case FTDM_COMMAND_SET_LINK_STATUS:
		{
			ftdm_channel_hw_link_status_t status = FTDM_COMMAND_OBJ_INT;
			char sangoma_status = status == FTDM_HW_LINK_CONNECTED ? FE_CONNECTED : FE_DISCONNECTED;
			err = sangoma_tdm_set_fe_status(ftdmchan->sockfd, &tdm_api, sangoma_status);
		}
		break;
	case FTDM_COMMAND_GET_LINK_STATUS:
		{
			unsigned char sangoma_status = 0;
			err = sangoma_tdm_get_fe_status(ftdmchan->sockfd, &tdm_api, &sangoma_status);
			if (!err) {
				FTDM_COMMAND_OBJ_INT = sangoma_status == FE_CONNECTED ? FTDM_HW_LINK_CONNECTED : FTDM_HW_LINK_DISCONNECTED;
			}
		}
		break;
	default:
		break;
	};

	if (err) {
		snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
		return FTDM_FAIL;
	}


	return FTDM_SUCCESS;
}
Esempio n. 3
0
static ftdm_status_t ftdm_core_set_state(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int waitrq)
{
	ftdm_status_t status;
	int ok = 1;
	int waitms = DEFAULT_WAIT_TIME;	

	if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
		ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR, "Ignored state change request from %s to %s, the channel is not ready\n",
				ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
		return FTDM_FAIL;
	}

	if (ftdmchan->state_status != FTDM_STATE_STATUS_COMPLETED) {
		ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR, 
		"Ignored state change request from %s to %s, the previous state change has not been processed yet (status = %s)\n",
		ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state),
		ftdm_state_status2str(ftdmchan->state_status));
		return FTDM_FAIL;
	}

	if (ftdmchan->state == state) {
		ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "Why bother changing state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
		return FTDM_FAIL;
	}

	if (!ftdmchan->state_completed_interrupt) {
		status = ftdm_interrupt_create(&ftdmchan->state_completed_interrupt, FTDM_INVALID_SOCKET);
		if (status != FTDM_SUCCESS) {
			ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_CRIT, 
					"Failed to create state change interrupt when moving from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
			return status;
		}
	}


	if (ftdmchan->span->state_map) {
		ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map);
		goto end;
	}

	/* basic core state validation (by-passed if the signaling module provides a state_map) */
	switch(ftdmchan->state) {
	case FTDM_CHANNEL_STATE_HANGUP:
	case FTDM_CHANNEL_STATE_TERMINATING:
		{
			ok = 0;
			switch(state) {
			case FTDM_CHANNEL_STATE_DOWN:
			case FTDM_CHANNEL_STATE_BUSY:
			case FTDM_CHANNEL_STATE_RESTART:
				ok = 1;
				break;
			default:
				break;
			}
		}
		break;
	case FTDM_CHANNEL_STATE_UP:
		{
			ok = 1;
			switch(state) {
			case FTDM_CHANNEL_STATE_PROGRESS:
			case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
			case FTDM_CHANNEL_STATE_RING:
				ok = 0;
				break;
			default:
				break;
			}
		}
		break;
	case FTDM_CHANNEL_STATE_DOWN:
		{
			ok = 0;
			
			switch(state) {
			case FTDM_CHANNEL_STATE_DIALTONE:
			case FTDM_CHANNEL_STATE_COLLECT:
			case FTDM_CHANNEL_STATE_DIALING:
			case FTDM_CHANNEL_STATE_RING:
			case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
			case FTDM_CHANNEL_STATE_PROGRESS:				
			case FTDM_CHANNEL_STATE_IDLE:				
			case FTDM_CHANNEL_STATE_GET_CALLERID:
			case FTDM_CHANNEL_STATE_GENRING:
				ok = 1;
				break;
			default:
				break;
			}
		}
		break;
	case FTDM_CHANNEL_STATE_BUSY:
		{
			switch(state) {
			case FTDM_CHANNEL_STATE_UP:
				ok = 0;
				break;
			default:
				break;
			}
		}
		break;
	case FTDM_CHANNEL_STATE_RING:
		{
			switch(state) {
			case FTDM_CHANNEL_STATE_UP:
				ok = 1;
				break;
			default:
				break;
			}
		}
		break;
	default:
		break;
	}

end:

	if (!ok) {
		ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "VETO state change from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
		goto done;
	}

	ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Changed state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
	ftdmchan->last_state = ftdmchan->state; 
	ftdmchan->state = state;
	ftdmchan->state_status = FTDM_STATE_STATUS_NEW;
	ftdmchan->history[ftdmchan->hindex].file = file;
	ftdmchan->history[ftdmchan->hindex].func = func;
	ftdmchan->history[ftdmchan->hindex].line = line;
	ftdmchan->history[ftdmchan->hindex].state = ftdmchan->state;
	ftdmchan->history[ftdmchan->hindex].last_state = ftdmchan->last_state;
	ftdmchan->history[ftdmchan->hindex].time = ftdm_current_time_in_ms();
	ftdmchan->history[ftdmchan->hindex].end_time = 0;
	ftdmchan->hindex++;
	if (ftdmchan->hindex == ftdm_array_len(ftdmchan->history)) {
		ftdmchan->hindex = 0;
	}
	ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);

	ftdm_mutex_lock(ftdmchan->span->mutex);
	ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
	if (ftdmchan->span->pendingchans) {
		ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan);
	}
	ftdm_mutex_unlock(ftdmchan->span->mutex);

	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NONBLOCK)) {
		/* the channel should not block waiting for state processing */
		goto done;
	}

	if (!waitrq) {
		/* no waiting was requested */
		goto done;
	}

	/* let's wait for the state change to be completed by the signaling stack */
	ftdm_set_flag(ftdmchan, FTDM_CHANNEL_BLOCKING);

	ftdm_mutex_unlock(ftdmchan->mutex);

	status = ftdm_interrupt_wait(ftdmchan->state_completed_interrupt, waitms);

	ftdm_mutex_lock(ftdmchan->mutex);

	if (status != FTDM_SUCCESS) {
		ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_BLOCKING);
		ftdm_log_chan_ex(ftdmchan, file, func, line, 
				FTDM_LOG_LEVEL_WARNING, "state change from %s to %s was most likely not completed after aprox %dms\n",
				ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(state), DEFAULT_WAIT_TIME);
		ok = 0;
		goto done;
	}
done:
	return ok ? FTDM_SUCCESS : FTDM_FAIL;
}
Esempio n. 4
0
FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const char *func, int line, ftdm_channel_t *fchan)
{
	uint8_t hindex = 0;
	ftdm_time_t diff = 0;
	ftdm_channel_state_t state = fchan->state;

	if (fchan->state_status == FTDM_STATE_STATUS_COMPLETED) {
		ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL, 
				"State change flag set but state is not completed\n");
		return FTDM_SUCCESS;
	}

	ftdm_usrmsg_free(&fchan->usrmsg);
	
	ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);

	if (state == FTDM_CHANNEL_STATE_PROGRESS) {
		ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
	} else if (state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
		ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);	
		ftdm_test_and_set_media(fchan);
	} else if (state == FTDM_CHANNEL_STATE_UP) {
		ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
		ftdm_set_flag(fchan, FTDM_CHANNEL_ANSWERED);	
		ftdm_test_and_set_media(fchan);
	} else if (state == FTDM_CHANNEL_STATE_DIALING) {
		ftdm_sigmsg_t msg;
		memset(&msg, 0, sizeof(msg));
		msg.channel = fchan;
		msg.event_id = FTDM_SIGEVENT_DIALING;
		ftdm_span_send_signal(fchan->span, &msg);
	} else if (state == FTDM_CHANNEL_STATE_HANGUP) {
		ftdm_set_echocancel_call_end(fchan);
	}

	/* MAINTENANCE WARNING
	 * we're assuming an indication performed 
	 * via state change will involve a single state change */
	ftdm_ack_indication(fchan, fchan->indication, FTDM_SUCCESS);

	hindex = (fchan->hindex == 0) ? (ftdm_array_len(fchan->history) - 1) : (fchan->hindex - 1);
	
	ftdm_assert(!fchan->history[hindex].end_time, "End time should be zero!\n");

	fchan->history[hindex].end_time = ftdm_current_time_in_ms();

	fchan->state_status = FTDM_STATE_STATUS_COMPLETED;

	diff = fchan->history[hindex].end_time - fchan->history[hindex].time;

	ftdm_log_chan_ex(fchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Completed state change from %s to %s in %llums\n", 
			ftdm_channel_state2str(fchan->last_state), ftdm_channel_state2str(state), diff);
	

	if (ftdm_test_flag(fchan, FTDM_CHANNEL_BLOCKING)) {
		ftdm_clear_flag(fchan, FTDM_CHANNEL_BLOCKING);
		ftdm_interrupt_signal(fchan->state_completed_interrupt);
	}

	return FTDM_SUCCESS;
}
Esempio n. 5
0
int main(int argc, char *argv[])
{
	ftdm_span_t *span;
	ftdm_conf_parameter_t parameters[20];
	
	ftdm_mutex_create(&the_mutex);

	if (argc < 2) {
		printf("umm no\n");
		exit(1);
	}

	ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);

	if (ftdm_global_init() != FTDM_SUCCESS) {
		fprintf(stderr, "Error loading FreeTDM\n");
		exit(1);
	}

	ftdm_global_configuration();

	printf("FreeTDM loaded\n");

	if (ftdm_span_find_by_name(argv[1], &span) != FTDM_SUCCESS) {
		fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]);
		goto done;
	}
	
	/* testing non-blocking operation */
	//ftdm_span_set_blocking_mode(span, FTDM_FALSE);

	parameters[0].var = "variant";
	parameters[0].val = "br";

	parameters[1].var = "max_ani";
	parameters[1].val = "4";

	parameters[2].var = "max_dnis";
	parameters[2].val = "4";

	parameters[3].var = "logging";
	parameters[3].val = "all";

	parameters[4].var = NULL;
	parameters[4].val = NULL;

	if (ftdm_configure_span_signaling(span, "r2", on_r2_signal, parameters) == FTDM_SUCCESS) {
		ftdm_span_start(span);
	} else {
		fprintf(stderr, "Error starting R2 span\n");
		goto done;
	}

	running = 1;
	signal(SIGINT, stop_test);
	while(running) {
		ftdm_sleep(20);
		if (fchan && indication != FTDM_CHANNEL_INDICATE_NONE) {
			ftdm_channel_t *lchan = NULL;
			ftdm_channel_indication_t ind = FTDM_CHANNEL_INDICATE_NONE;
			ftdm_time_t start, stop, diff;

			ftdm_mutex_lock(the_mutex);
			ind = indication;
			indication = FTDM_CHANNEL_INDICATE_NONE;
			lchan = fchan;
			ftdm_mutex_unlock(the_mutex);

			start = ftdm_current_time_in_ms();
			ftdm_channel_call_indicate(lchan, ind);
			stop = ftdm_current_time_in_ms();
			diff = stop - start;
			ftdm_log(FTDM_LOG_DEBUG, "Setting indication %s took %"FTDM_TIME_FMT" ms\n",
					ftdm_channel_indication2str(ind), diff);
		}
	}

done:

	ftdm_global_destroy();

	return 0;
}