switch (msg->message_id) {
case SWITCH_MESSAGE_INDICATE_RINGING:
{
-#if 0
- if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
- ftdm_set_flag(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
- } else {
- ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
- }
-#else
ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_PROGRESS);
-#endif
}
break;
case SWITCH_MESSAGE_INDICATE_PROGRESS:
{
-#if 0
- if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
- ftdm_set_flag(tech_pvt->ftdmchan, FTDM_CHANNEL_PROGRESS);
- ftdm_set_flag(tech_pvt->ftdmchan, FTDM_CHANNEL_MEDIA);
- } else {
- /* Don't skip messages in the ISDN call setup
- * TODO: make the isdn stack smart enough to handle that itself
- * until then, this is here for safety...
- */
- if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
- ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
- }
- ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
- }
-#else
ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA);
-#endif
}
break;
case SWITCH_MESSAGE_INDICATE_ANSWER:
{
-#if 0
- if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
- ftdm_set_flag(tech_pvt->ftdmchan, FTDM_CHANNEL_ANSWERED);
- } else {
- /* Don't skip messages in the ISDN call setup
- * TODO: make the isdn stack smart enough to handle that itself
- * until then, this is here for safety...
- */
- if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
- ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
- }
- if (tech_pvt->ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
- ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
- }
- ftdm_set_state_wait(tech_pvt->ftdmchan, FTDM_CHANNEL_STATE_UP);
- }
-#else
ftdm_channel_call_answer(tech_pvt->ftdmchan);
-#endif
}
break;
default:
return ok;
}
-FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int lock)
+/* this function MUST be called with the channel lock held. If waitrq == 1, the channel will be unlocked/locked (never call it with waitrq == 1 with an lock recursivity > 1) */
+#define DEFAULT_WAIT_TIME 1000
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int waitrq)
{
int ok = 1;
-
+ int waitms = DEFAULT_WAIT_TIME;
+
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
+ ftdm_log(file, func, line, FTDM_LOG_LEVEL_ERROR, "%d:%d Ignored state change request from %s to %s, the channel is not ready\n",
+ ftdmchan->span_id, ftdmchan->chan_id,
+ ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
return FTDM_FAIL;
}
if (ftdm_test_flag(ftdmchan->span, FTDM_SPAN_SUSPENDED)) {
if (state != FTDM_CHANNEL_STATE_RESTART && state != FTDM_CHANNEL_STATE_DOWN) {
+ ftdm_log(file, func, line, FTDM_LOG_LEVEL_ERROR, "%d:%d Ignored state change request from %s to %s, span %s is suspended\n",
+ ftdmchan->span_id, ftdmchan->chan_id,
+ ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state), ftdmchan->span->name);
return FTDM_FAIL;
}
}
- if (lock) {
- ftdm_mutex_lock(ftdmchan->mutex);
- }
-
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
- ftdm_log(FTDM_LOG_CRIT, "Ignored state change request from %s to %s, the previous state change has not been processed yet\n",
+ ftdm_log(file, func, line, FTDM_LOG_LEVEL_ERROR, "%d:%d Ignored state change request from %s to %s, the previous state change has not been processed yet\n",
+ ftdmchan->span_id, ftdmchan->chan_id,
ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
- if (lock) {
- ftdm_mutex_unlock(ftdmchan->mutex);
- }
return FTDM_FAIL;
}
+ if (ftdmchan->state == state) {
+ ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "%d:%d Why bother changing state from %s to %s\n",
+ ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
+ return FTDM_FAIL;
+ }
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:
break;
}
- end:
-
- if (state == ftdmchan->state) {
- ok = 0;
- }
-
+end:
if (ok) {
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
+ ftdm_log(file, func, line, FTDM_LOG_LEVEL_DEBUG, "%d:%d Changed state from %s to %s\n",
+ ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
+ ftdmchan->last_state = ftdmchan->state;
+ ftdmchan->state = state;
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_mutex_lock(ftdmchan->span->mutex);
ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan);
}
ftdm_mutex_unlock(ftdmchan->span->mutex);
-
- ftdmchan->last_state = ftdmchan->state;
- ftdmchan->state = state;
+ } else {
+ ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "%d:%d VETO state change from %s to %s\n",
+ ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
}
- if (lock) {
+ /* there is an inherent race here between set and check of the change flag but we do not care because
+ * the flag should never last raised for more than a few ms for any state change */
+ while (waitrq && waitms > 0) {
+ /* give a chance to the signaling stack to process it */
ftdm_mutex_unlock(ftdmchan->mutex);
+
+ ftdm_sleep(10);
+ waitms -= 10;
+
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ /* if the flag is no longer set, the state change was processed (or is being processed) */
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
+ break;
+ }
+
+ /* if the state is no longer what we set, the state change was
+ * obviously processed (and the current state change flag is for other state change) */
+ if (ftdmchan->state != state) {
+ break;
+ }
+ }
+
+ if (waitms <= 0) {
+ ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "%d:%d state change from %s to %s was most likely not processed after aprox %dms\n",
+ ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(state), DEFAULT_WAIT_TIME);
}
return ok ? FTDM_SUCCESS : FTDM_FAIL;
FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan)
{
if (ftdmchan->init_state != FTDM_CHANNEL_STATE_DOWN) {
- ftdm_set_state_locked(ftdmchan, ftdmchan->init_state);
+ ftdm_set_state(ftdmchan, ftdmchan->init_state);
ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN;
}
return condition;
}
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_hold(ftdm_channel_t *ftdmchan)
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hold(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
ftdm_channel_lock(ftdmchan);
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_HOLD);
- ftdm_set_state_wait(ftdmchan, FTDM_CHANNEL_STATE_DIALTONE);
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_DIALTONE, 1);
ftdm_channel_unlock(ftdmchan);
return FTDM_SUCCESS;
}
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_unhold(ftdm_channel_t *ftdmchan)
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_unhold(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
ftdm_channel_lock(ftdmchan);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_HOLD)) {
- ftdm_set_state_wait(ftdmchan, FTDM_CHANNEL_STATE_UP);
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1);
}
ftdm_channel_unlock(ftdmchan);
return FTDM_SUCCESS;
}
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_answer(ftdm_channel_t *ftdmchan)
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
ftdm_channel_lock(ftdmchan);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_ANSWERED)) {
+ ftdm_channel_unlock(ftdmchan);
return FTDM_SUCCESS;
}
}
if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
- ftdm_set_state_wait(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
}
if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
- ftdm_set_state_wait(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
}
- ftdm_set_state_wait(ftdmchan, FTDM_CHANNEL_STATE_UP);
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1);
ftdm_channel_unlock(ftdmchan);
return FTDM_SUCCESS;
}
-
-static ftdm_status_t call_hangup(ftdm_channel_t *chan)
+/* 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)
{
if (chan->state != FTDM_CHANNEL_STATE_DOWN) {
- ftdm_set_state_wait(chan, FTDM_CHANNEL_STATE_HANGUP);
+ ftdm_channel_set_state(file, func, line, chan, FTDM_CHANNEL_STATE_HANGUP, 1);
} else {
/* the signaling stack did not touch the state,
* core is responsible from clearing flags and stuff */
return FTDM_SUCCESS;
}
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_hangup_with_cause(ftdm_channel_t *ftdmchan, ftdm_call_cause_t cause)
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup_with_cause(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_call_cause_t cause)
{
ftdm_channel_lock(ftdmchan);
ftdmchan->caller_data.hangup_cause = cause;
- call_hangup(ftdmchan);
+ call_hangup(ftdmchan, file, func, line);
ftdm_channel_unlock(ftdmchan);
return FTDM_SUCCESS;
}
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_hangup(ftdm_channel_t *ftdmchan)
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
ftdm_channel_lock(ftdmchan);
- call_hangup(ftdmchan);
+ call_hangup(ftdmchan, file, func, line);
ftdm_channel_unlock(ftdmchan);
return FTDM_SUCCESS;
}
return id;
}
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_indicate(ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication)
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication)
{
+ ftdm_status_t status = FTDM_SUCCESS;
+ ftdm_channel_lock(ftdmchan);
switch (indication) {
/* FIXME: ring and busy cannot be used with all signaling stacks
* (particularly isdn stacks I think, we should emulate or just move to hangup with busy cause) */
case FTDM_CHANNEL_INDICATE_RING:
- ftdm_set_state_locked_wait(ftdmchan, FTDM_CHANNEL_STATE_RING);
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_RING, 1);
break;
case FTDM_CHANNEL_INDICATE_BUSY:
- ftdm_set_state_locked_wait(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_BUSY, 1);
break;
case FTDM_CHANNEL_INDICATE_PROGRESS:
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
- ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_PROGRESS);
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
} else {
- ftdm_set_state_locked_wait(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
}
break;
case FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA:
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
- ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_PROGRESS);
- ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MEDIA);
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
} else {
if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
- ftdm_set_state_locked_wait(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
}
- ftdm_set_state_locked_wait(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
}
break;
default:
- ftdm_log(FTDM_LOG_WARNING, "Do not know how to indicate %d\n", indication);
- return FTDM_FAIL;
+ ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "Do not know how to indicate %d\n", indication);
+ status = FTDM_FAIL;
+ break;
}
+
+ ftdm_channel_unlock(ftdmchan);
+
return FTDM_SUCCESS;
}
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_place(ftdm_channel_t *ftdmchan)
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
ftdm_status_t status;
ft_r2_clean_call(ftdmchan->call_data);
R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
- ftdm_channel_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING, 0);
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
R2CALL(ftdmchan)->ftdm_started = 1;
ftdm_mutex_unlock(ftdmchan->mutex);
}
ft_r2_clean_call(ftdmchan->call_data);
R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
- ftdm_channel_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT, 0);
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
ftdm_mutex_unlock(ftdmchan->mutex);
status = ftdm_thread_create_detached(ftdm_r2_channel_run, ftdmchan);
ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA ||
ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS) {
ftdm_log(FTDM_LOG_CRIT, "FTDMCHAN CALL ACK STATE UP -> Changed to TERMINATING %d:%d\n", event_span, event_chan);
- ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, r);
} else if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP || ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) {
ftdm_log(FTDM_LOG_CRIT, "FTDMCHAN CALL ACK STATE HANGUP -> Changed to HANGUP COMPLETE %d:%d\n", event_span, event_chan);
- ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, 0, r);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, r);
} else {
ftdm_log(FTDM_LOG_CRIT, "FTDMCHAN STATE INVALID State %s on IN CALL ACK %d:%d\n",
ftdm_channel_state2str(ftdmchan->state), event_span, event_chan);
goto done;
}
- ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, 0, r);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, r);
if (r) {
ftdm_mutex_unlock(ftdmchan->mutex);
return;
CALL_DATA(ftdmchan)->last_event_id = event->event_id;
ftdm_mutex_lock(ftdmchan->mutex);
- ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
- if (r == FTDM_STATE_CHANGE_SUCCESS) {
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, r);
+ if (r == FTDM_SUCCESS) {
ftdmchan->caller_data.hangup_cause = event->release_cause;
}
ftdm_mutex_unlock(ftdmchan->mutex);
ftdm_mutex_unlock(ftdmchan->mutex);
return;
} else {
- ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, r);
}
- if (r == FTDM_STATE_CHANGE_SUCCESS) {
+ if (r == FTDM_SUCCESS) {
ftdmchan->caller_data.hangup_cause = event->release_cause;
}
} else {
int r = 0;
- ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_UP, 0, r);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_UP, r);
}
ftdm_mutex_unlock(ftdmchan->mutex);
} else {
ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS) {
ftdm_log(FTDM_LOG_CRIT, "s%dc%d: FTDMCHAN STATE UP -> Changed to TERMINATING\n",
BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
- ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, r);
} else if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP || ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) {
ftdm_log(FTDM_LOG_CRIT, "s%dc%d: FTDMCHAN STATE HANGUP -> Changed to HANGUP COMPLETE\n",
BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
- ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, 0, r);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, r);
} else if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
ftdm_log(FTDM_LOG_WARNING, "s%dc%d: Collision, hanging up incoming call\n",
BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
* when receiving call start nack we move the channel from DOWN to TERMINATING ( cuz we already
* hangup here ) and the channel gets stuck in terminating forever. So at this point we're trusting
* the other side to send the call start nack ( or proceed with the call )
- * ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r);
+ * ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, r);
*/
} else {
ftdm_log(FTDM_LOG_ERROR, "s%dc%d: rejecting incoming call in channel state %s\n",
return;
}
- ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_IN_LOOP, 0, res);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_IN_LOOP, res);
if (res != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "yay, could not set the state of the channel to IN_LOOP, loop will fail\n");
ftdm_channel_done(ftdmchan);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_LOOP, NULL);
/* even when we did not sent a msg we set this flag to avoid sending call stop in the DOWN state handler */
ftdm_set_flag(ftdmchan, SFLAG_SENT_FINAL_MSG);
- ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_DOWN, 0, res);
+ ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_DOWN, res);
}
/**
ftdm_mutex_lock(span->channels[j]->mutex);
ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
if (susp && span->channels[j]->state != FTDM_CHANNEL_STATE_DOWN) {
- ftdm_channel_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART, 0);
+ ftdm_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART);
}
state_advance(span->channels[j]);
ftdm_channel_complete_state(span->channels[j]);
FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *handler);
/*! \brief Answer call */
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_answer(ftdm_channel_t *ftdmchan);
+#define ftdm_channel_call_answer(ftdmchan) _ftdm_channel_call_answer(__FILE__, __FUNCTION__, __LINE__, (ftdmchan))
+
+/*! \brief Answer call recording the source code point where the it was called (see ftdm_channel_call_answer for an easy to use macro) */
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan);
/*! \brief Place an outgoing call */
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_place(ftdm_channel_t *ftdmchan);
+#define ftdm_channel_call_place(ftdmchan) _ftdm_channel_call_place(__FILE__, __FUNCTION__, __LINE__, (ftdmchan))
+
+/*! \brief Place an outgoing call recording the source code point where it was called (see ftdm_channel_call_place for an easy to use macro) */
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan);
/*! \brief Indicate a new condition in an incoming call */
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_indicate(ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication);
+#define ftdm_channel_call_indicate(ftdmchan, indication) _ftdm_channel_call_indicate(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), (indication))
+
+/*! \brief Indicate a new condition in an incoming call recording the source code point where it was called (see ftdm_channel_call_indicate for an easy to use macro) */
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication);
/*! \brief Hangup the call without cause */
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_hangup(ftdm_channel_t *ftdmchan);
+#define ftdm_channel_call_hangup(ftdmchan) _ftdm_channel_call_hangup(__FILE__, __FUNCTION__, __LINE__, (ftdmchan))
+
+/*! \brief Hangup the call without cause recording the source code point where it was called (see ftdm_channel_call_hangup for an easy to use macro)*/
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan);
/*! \brief Hangup the call with cause */
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_hangup_with_cause(ftdm_channel_t *ftdmchan, ftdm_call_cause_t);
+#define ftdm_channel_call_hangup_with_cause(ftdmchan, cause) _ftdm_channel_call_hangup_with_cause(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), (cause))
+
+/*! \brief Hangup the call with cause recording the source code point where it was called (see ftdm_channel_call_hangup_with_cause for an easy to use macro) */
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup_with_cause(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_call_cause_t);
/*! \brief Put a call on hold (if supported by the signaling stack) */
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_hold(ftdm_channel_t *ftdmchan);
+#define ftdm_channel_call_hold(ftdmchan) _ftdm_channel_call_hold(__FILE__, __FUNCTION__, __LINE__, (ftdmchan))
+
+/*! \brief Put a call on hold recording the source code point where it was called (see ftdm_channel_call_hold for an easy to use macro) */
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hold(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan);
/*! \brief Unhold a call */
-FT_DECLARE(ftdm_status_t) ftdm_channel_call_unhold(ftdm_channel_t *ftdmchan);
+#define ftdm_channel_call_unhold(ftdmchan) _ftdm_channel_call_unhold(__FILE__, __FUNCTION__, __LINE__, (ftdmchan))
+
+/*! \brief Unhold a call recording the source code point where it was called (see ftdm_channel_call_unhold for an easy to use macro) */
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_unhold(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan);
/*! \brief Check if the call is answered already */
FT_DECLARE(ftdm_bool_t) ftdm_channel_call_check_answered(const ftdm_channel_t *ftdmchan);
#define ftdm_clear_sflag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->sflags &= ~(flag); ftdm_mutex_unlock(obj->mutex);
+#define ftdm_set_state(obj, s) ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); \
-#define ftdm_set_state_locked(obj, s) if ( obj->state == s ) { \
- ftdm_log(FTDM_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(obj->state), ftdm_channel_state2str(s)); \
- } else if (ftdm_test_flag(obj, FTDM_CHANNEL_READY)) { \
- ftdm_channel_state_t st = obj->state; \
- ftdm_channel_set_state(obj, s, 1); \
- if (obj->state == s) ftdm_log(FTDM_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
- else ftdm_log(FTDM_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
- }
+#define ftdm_set_state_locked(obj, s) \
+ do { \
+ ftdm_channel_lock(obj); \
+ ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); \
+ ftdm_channel_unlock(obj); \
+ } while(0);
-#define ftdm_set_state(obj, s) if ( obj->state == s ) { \
- ftdm_log(FTDM_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(obj->state), ftdm_channel_state2str(s)); \
- } else if (ftdm_test_flag(obj, FTDM_CHANNEL_READY)) { \
- ftdm_channel_state_t st = obj->state; \
- ftdm_channel_set_state(obj, s, 0); \
- if (obj->state == s) ftdm_log(FTDM_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
- else ftdm_log(FTDM_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
- }
+#define ftdm_set_state_r(obj, s, r) r = ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0);
#ifdef _MSC_VER
/* The while(0) below throws a conditional expression is constant warning */
#pragma warning(disable:4127)
#endif
-#define ftdm_set_state_locked_wait(obj, s) \
- do { \
- int __safety = 100; \
- ftdm_set_state_locked(obj, s); \
- while(__safety-- && ftdm_test_flag(obj, FTDM_CHANNEL_STATE_CHANGE)) { \
- ftdm_sleep(10); \
- } \
- if(!__safety) { \
- ftdm_log(FTDM_LOG_CRIT, "State change not completed\n"); \
- } \
- } while(0);
-
+/* this macro assumes obj is locked! */
#define ftdm_wait_for_flag_cleared(obj, flag, time) \
do { \
int __safety = time; \
} \
} while(0);
-#define ftdm_set_state_wait(obj, s) \
- do { \
- ftdm_channel_set_state(obj, s, 0); \
- ftdm_wait_for_flag_cleared(obj, FTDM_CHANNEL_STATE_CHANGE, 100); \
- } while(0);
-
-
-#define ftdm_set_state_r(obj, s, l, r) if ( obj->state == s ) { \
- if (s != FTDM_CHANNEL_STATE_HANGUP) ftdm_log(FTDM_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(obj->state), ftdm_channel_state2str(s)); r = FTDM_STATE_CHANGE_SAME; \
- } else if (ftdm_test_flag(obj, FTDM_CHANNEL_READY)) { \
- int st = obj->state; \
- r = (ftdm_channel_set_state(obj, s, l) == FTDM_SUCCESS) ? FTDM_STATE_CHANGE_SUCCESS : FTDM_STATE_CHANGE_FAIL; \
- if (obj->state == s) {ftdm_log(FTDM_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s));} \
- else ftdm_log(FTDM_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \
- }
-
-
#define ftdm_is_dtmf(key) ((key > 47 && key < 58) || (key > 64 && key < 69) || (key > 96 && key < 101) || key == 35 || key == 42 || key == 87 || key == 119)
/*!
*/
#define ftdm_copy_flags(dest, src, flags) (dest)->flags &= ~(flags); (dest)->flags |= ((src)->flags & (flags))
-/*! \brief channel state change result */
-typedef enum {
- FTDM_STATE_CHANGE_FAIL,
- FTDM_STATE_CHANGE_SUCCESS,
- FTDM_STATE_CHANGE_SAME,
-} ftdm_state_change_result_t;
-
struct ftdm_stream_handle {
ftdm_stream_handle_write_function_t write_function;
ftdm_stream_handle_raw_write_function_t raw_write_function;
FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_sdmf(ftdm_fsk_data_state_t *state, const char *date, char *number);
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_channel_set_state(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int lock);
+FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line,
+ ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int wait);
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);