freetdm: ftmod_r2 - now clearing FTDM_CHANNEL_STATE_CHANGE flag when needed

This commit is contained in:
Arnaldo Pereira 2010-12-01 16:23:21 -02:00
parent 3934682e9b
commit 85d2395d26
1 changed files with 41 additions and 13 deletions

View File

@ -56,15 +56,10 @@ typedef enum {
FTDM_R2_RUNNING = (1 << 0), FTDM_R2_RUNNING = (1 << 0),
} ftdm_r2_flag_t; } ftdm_r2_flag_t;
typedef enum {
FTDM_R2_WAITING_ACK = (1 << 0),
} ftdm_r2_call_flag_t;
/* private call information stored in ftdmchan->call_data void* ptr */ /* private call information stored in ftdmchan->call_data void* ptr */
#define R2CALL(ftdmchan) ((ftdm_r2_call_t*)((ftdmchan)->call_data)) #define R2CALL(ftdmchan) ((ftdm_r2_call_t*)((ftdmchan)->call_data))
typedef struct ftdm_r2_call_t { typedef struct ftdm_r2_call_t {
openr2_chan_t *r2chan; openr2_chan_t *r2chan;
ftdm_r2_call_flag_t flags;
int accepted:1; int accepted:1;
int answer_pending:1; int answer_pending:1;
int disconnect_rcvd:1; int disconnect_rcvd:1;
@ -154,6 +149,12 @@ static ftdm_io_interface_t g_ftdm_r2_interface;
static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan); static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan);
static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan); static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan);
/* whether R2 call accept process is pending */
#define IS_ACCEPTING_PENDING(ftdmchan) \
( (!ftdm_test_flag((ftdmchan), FTDM_CHANNEL_OUTBOUND)) && !R2CALL((ftdmchan))->accepted && \
((ftdmchan)->state == FTDM_CHANNEL_STATE_PROGRESS || \
(ftdmchan)->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA || \
(ftdmchan)->state == FTDM_CHANNEL_STATE_UP) )
/* functions not available on windows */ /* functions not available on windows */
#ifdef WIN32 #ifdef WIN32
@ -374,7 +375,6 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
if (ftdmchan->state != FTDM_CHANNEL_STATE_DIALING) { if (ftdmchan->state != FTDM_CHANNEL_STATE_DIALING) {
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Collision after call attempt, try another channel, new state = %s\n", ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Collision after call attempt, try another channel, new state = %s\n",
ftdm_channel_state2str(ftdmchan->state)); ftdm_channel_state2str(ftdmchan->state));
ftdm_clear_flag(R2CALL(ftdmchan), FTDM_R2_WAITING_ACK);
return FTDM_BREAK; return FTDM_BREAK;
} }
@ -451,16 +451,43 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
} }
/*
* Accepting a call in R2 is a lengthy process due to MF tones,
* when the user sends PROGRESS indication (implicitly moving the
* ftdm channel to PROGRESS state) the R2 processing loop
* does not clear FTDM_CHANNEL_STATE_CHANGE immediately as it does
* for all the other states, instead has to wait for on_call_accepted
* callback from openr2, which means the MF has ended and the progress
* indication is done, in order to clear the flag. However, if
* a protocol error or call disconnection (which is indicated using CAS bits)
* occurrs while accepting, we must clear the pending flag, this function
* takes care of that
* */
static void clear_accept_pending(ftdm_channel_t *fchan)
{
if (IS_ACCEPTING_PENDING(fchan)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(fchan);
} else if (ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_log_chan(fchan, FTDM_LOG_CRIT, "State change flag set in state %s, last state = %s\n",
ftdm_channel_state2str(fchan->state), ftdm_channel_state2str(fchan->last_state));
ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(fchan);
}
}
static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode) static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
{ {
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call accepted\n"); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call accepted\n");
clear_accept_pending(ftdmchan);
/* at this point the MF signaling has ended and there is no point on keep reading */ /* at this point the MF signaling has ended and there is no point on keep reading */
openr2_chan_disable_read(r2chan); openr2_chan_disable_read(r2chan);
R2CALL(ftdmchan)->accepted = 1; R2CALL(ftdmchan)->accepted = 1;
if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) { if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
if (R2CALL(ftdmchan)->answer_pending) { if (R2CALL(ftdmchan)->answer_pending) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Answer was pending, answering now.\n"); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Answer was pending, answering now.\n");
ft_r2_answer_call(ftdmchan); ft_r2_answer_call(ftdmchan);
@ -493,6 +520,8 @@ static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_discon
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Got openr2 disconnection, clearing call\n"); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Got openr2 disconnection, clearing call\n");
clear_accept_pending(ftdmchan);
R2CALL(ftdmchan)->disconnect_rcvd = 1; R2CALL(ftdmchan)->disconnect_rcvd = 1;
if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) { if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) {
@ -564,6 +593,8 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Protocol error\n"); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Protocol error\n");
clear_accept_pending(ftdmchan);
R2CALL(ftdmchan)->disconnect_rcvd = 1; R2CALL(ftdmchan)->disconnect_rcvd = 1;
R2CALL(ftdmchan)->protocol_error = 1; R2CALL(ftdmchan)->protocol_error = 1;
@ -1204,12 +1235,9 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state)); ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
R2CALL(ftdmchan)->chanstate = ftdmchan->state; R2CALL(ftdmchan)->chanstate = ftdmchan->state;
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && !R2CALL(ftdmchan)->accepted && if (IS_ACCEPTING_PENDING(ftdmchan)) {
(ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS ||
ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA ||
ftdmchan->state == FTDM_CHANNEL_STATE_UP) ) {
/* /*
Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call, and accepting Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting
the call in R2 means sending a tone, then waiting for the acknowledge from the other end, the call in R2 means sending a tone, then waiting for the acknowledge from the other end,
since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100) since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100)
which means during that time the user should not try to perform any operations like answer, hangup or anything which means during that time the user should not try to perform any operations like answer, hangup or anything