ftdm_span_send_signal(fchan->span, &msg);
}
-FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
+/*! \brief Answer call without locking the channel. The caller must have locked first
+ * \note This function was added because ftdm_channel_call_indicate needs to answer the call
+ * when its already locking the channel, ftdm_channel_set_state cannot be called with the same
+ * lock locked once or more (recursive lock) and wait for the result */
+static ftdm_status_t _ftdm_channel_call_answer_nl(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
ftdm_status_t status = FTDM_SUCCESS;
- ftdm_channel_lock(ftdmchan);
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ status = FTDM_EINVAL;
+ goto done;
+ }
if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call is already TERMINATING\n");
status = FTDM_ECANCELED;
- ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status);
- goto done;
- }
-
- if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
- status = FTDM_EINVAL;
- ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status);
goto done;
}
if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
if (status != FTDM_SUCCESS) {
- ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status);
+ status = FTDM_ECANCELED;
goto done;
}
}
if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n");
status = FTDM_ECANCELED;
- ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status);
goto done;
}
if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
if (status != FTDM_SUCCESS) {
- ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status);
+ status = FTDM_ECANCELED;
goto done;
}
}
if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to UP\n");
status = FTDM_ECANCELED;
- ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status);
goto done;
}
}
status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1);
if (status != FTDM_SUCCESS) {
- ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status);
+ status = FTDM_ECANCELED;
+ goto done;
}
done:
+
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
+{
+ ftdm_status_t status = FTDM_SUCCESS;
+
+ ftdm_channel_lock(ftdmchan);
+
+ status = _ftdm_channel_call_answer_nl(file, func, line, ftdmchan);
+
ftdm_channel_unlock(ftdmchan);
return status;
}
/* lock must be acquired by the caller! */
-static ftdm_status_t call_hangup(ftdm_channel_t *chan, const char *file, const char *func, int line)
+static ftdm_status_t _ftdm_channel_call_hangup_nl(ftdm_channel_t *chan, const char *file, const char *func, int line)
{
ftdm_status_t status = FTDM_SUCCESS;
ftdmchan->caller_data.hangup_cause = cause;
- status = call_hangup(ftdmchan, file, func, line);
+ status = _ftdm_channel_call_hangup_nl(ftdmchan, file, func, line);
ftdm_channel_unlock(ftdmchan);
return status;
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
- status = call_hangup(ftdmchan, file, func, line);
+ status = _ftdm_channel_call_hangup_nl(ftdmchan, file, func, line);
ftdm_channel_unlock(ftdmchan);
return status;
break;
case FTDM_CHANNEL_INDICATE_ANSWER:
/* _ftdm_channel_call_answer takes care of the indication ack */
- status = _ftdm_channel_call_answer(file, func, line, ftdmchan);
+ status = _ftdm_channel_call_answer_nl(file, func, line, ftdmchan);
break;
default:
ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "Do not know how to indicate %d\n", indication);
fchan->hangup_timer = 0;
if (fchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Forcing hangup since the user did not confirmed our hangup after %dms\n", FORCE_HANGUP_TIMER);
- call_hangup(fchan, __FILE__, __FUNCTION__, __LINE__);
+ _ftdm_channel_call_hangup_nl(fchan, __FILE__, __FUNCTION__, __LINE__);
} else {
ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Not performing safety hangup, channel state is %s\n", ftdm_channel_state2str(fchan->state));
}
#include <unistd.h>
#endif
+/*! \brief time data type */
+typedef uint64_t ftdm_time_t;
+
/*! \brief sleep x amount of milliseconds */
#ifdef __WINDOWS__
#define ftdm_sleep(x) Sleep(x)
/*! \brief Duplicate string with limit */
FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen);
+/*! \brief Get the current time in milliseconds */
+FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void);
#ifdef __cplusplus
} /* extern C */
FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, ftdm_fsk_data_state_t *fsk_data, float db_level);
FT_DECLARE(ftdm_status_t) ftdm_span_load_tones(ftdm_span_t *span, const char *mapname);
-FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void);
FT_DECLARE(ftdm_status_t) ftdm_channel_use(ftdm_channel_t *ftdmchan);
#define FTDM_END -1
#define FTDM_ANY_STATE -1
-typedef uint64_t ftdm_time_t;
-
typedef enum {
FTDM_ENDIAN_BIG = 1,
FTDM_ENDIAN_LITTLE = -1
#include <signal.h>
#include <stdlib.h>
-static int R = 0;
-static ftdm_mutex_t *mutex = NULL;
+static volatile int running = 0;
+static ftdm_mutex_t *the_mutex = NULL;
+static ftdm_channel_t *fchan = NULL;
+static ftdm_channel_indication_t indication = FTDM_CHANNEL_INDICATE_NONE;
static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
{
int chanid = ftdm_channel_get_ph_id(sigmsg->channel);
- ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), chanid);
- return FTDM_SUCCESS;
+ ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), chanid);
+ switch (sigmsg->event_id) {
+ case FTDM_SIGEVENT_START:
+ {
+ ftdm_mutex_lock(the_mutex);
+ if (!fchan) {
+ fchan = sigmsg->channel;
+ indication = FTDM_CHANNEL_INDICATE_PROCEED;
+ }
+ ftdm_mutex_unlock(the_mutex);
+ }
+ break;
+ case FTDM_SIGEVENT_INDICATION_COMPLETED:
+ {
+ ftdm_channel_indication_t ind = FTDM_CHANNEL_INDICATE_NONE;
+ if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROCEED) {
+ ftdm_log(FTDM_LOG_DEBUG, "Proceed indication result = %d\n", sigmsg->ev_data.indication_completed.status);
+ ind = FTDM_CHANNEL_INDICATE_PROGRESS;
+ } else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROGRESS) {
+ ftdm_log(FTDM_LOG_DEBUG, "Progress indication result = %d\n", sigmsg->ev_data.indication_completed.status);
+ ind = FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA;
+ } else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA) {
+ ftdm_log(FTDM_LOG_DEBUG, "Progress media indication result = %d\n", sigmsg->ev_data.indication_completed.status);
+ ind = FTDM_CHANNEL_INDICATE_ANSWER;
+ } else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_ANSWER) {
+ ftdm_log(FTDM_LOG_DEBUG, "Answer indication result = %d\n", sigmsg->ev_data.indication_completed.status);
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "Unexpected indication, result = %d\n", sigmsg->ev_data.indication_completed.status);
+ exit(1);
+ }
+ ftdm_mutex_lock(the_mutex);
+ if (fchan) {
+ indication = ind;
+ }
+ ftdm_mutex_unlock(the_mutex);
+ }
+ break;
+ case FTDM_SIGEVENT_STOP:
+ {
+ ftdm_channel_call_hangup(sigmsg->channel);
+ }
+ break;
+ case FTDM_SIGEVENT_RELEASED:
+ {
+ ftdm_mutex_lock(the_mutex);
+ if (fchan && fchan == sigmsg->channel) {
+ fchan = NULL;
+ }
+ ftdm_mutex_unlock(the_mutex);
+ }
+ break;
+ default:
+ break;
+ }
+ return FTDM_SUCCESS;
}
-static void handle_SIGINT(int sig)
+static void stop_test(int sig)
{
- ftdm_mutex_lock(mutex);
- R = 0;
- ftdm_mutex_unlock(mutex);
- return;
+ running = 0;
}
int main(int argc, char *argv[])
{
ftdm_span_t *span;
- ftdm_mutex_create(&mutex);
-
- ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
+ ftdm_conf_parameter_t parameters[20];
+
+ ftdm_mutex_create(&the_mutex);
if (argc < 2) {
printf("umm no\n");
- exit(-1);
+ 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);
+ exit(1);
}
+ ftdm_global_configuration();
+
printf("FreeTDM loaded\n");
- if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
- fprintf(stderr, "Error finding FreeTDM span\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";
- if (ftdm_configure_span(span, "r2", on_r2_signal,
- "variant", "mx",
- "max_ani", 10,
- "max_dnis", 4,
- "logging", "all",
- FTDM_TAG_END) == FTDM_SUCCESS) {
-
+ 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;
}
- signal(SIGINT, handle_SIGINT);
- ftdm_mutex_lock(mutex);
- R = 1;
- ftdm_mutex_unlock(mutex);
- while(R) {
- ftdm_sleep(1 * 1000);
+ 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 %llums\n",
+ ftdm_channel_indication2str(ind), diff);
+ }
}
- done:
+done:
ftdm_global_destroy();
- return 1;
-
+ return 0;
}
/* For Emacs: