FTDM_ENUM_NAMES(CALLING_PARTY_CATEGORY_NAMES, CALLING_PARTY_CATEGORY_STRINGS)
FTDM_STR2ENUM(ftdm_str2ftdm_calling_party_category, ftdm_calling_party_category2str, ftdm_calling_party_category_t, CALLING_PARTY_CATEGORY_NAMES, FTDM_CPC_INVALID)
+FTDM_ENUM_NAMES(INDICATION_NAMES, INDICATION_STRINGS)
+FTDM_STR2ENUM(ftdm_str2channel_indication, ftdm_channel_indication2str, ftdm_channel_indication_t, INDICATION_NAMES, FTDM_CHANNEL_INDICATE_INVALID)
+
static ftdm_status_t ftdm_group_add_channels(ftdm_span_t* span, int currindex, const char* name);
static const char *cut_path(const char *in)
goto done;
}
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NONBLOCK)) {
+ /* the channel should not block waiting for state processing */
+ goto done;
+ }
+
/* 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) {
if (waitms <= 0) {
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "state change from %s to %s was most likely not processed after aprox %dms\n",
ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(state), DEFAULT_WAIT_TIME);
+ ok = 0;
}
done:
return ok ? FTDM_SUCCESS : FTDM_FAIL;
span->trunk_type = type;
}
+FT_DECLARE(ftdm_status_t) ftdm_span_set_blocking_mode(const ftdm_span_t *span, ftdm_bool_t enabled)
+{
+ ftdm_channel_t *fchan = NULL;
+ ftdm_iterator_t *citer = NULL;
+ ftdm_iterator_t *curr = NULL;
+
+ citer = ftdm_span_get_chan_iterator(span, NULL);
+ if (!citer) {
+ return FTDM_ENOMEM;
+ }
+ for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) {
+ fchan = ftdm_iterator_current(curr);
+ if (enabled) {
+ ftdm_clear_flag_locked(fchan, FTDM_CHANNEL_NONBLOCK);
+ } else {
+ ftdm_set_flag_locked(fchan, FTDM_CHANNEL_NONBLOCK);
+ }
+ }
+ return FTDM_SUCCESS;
+}
+
FT_DECLARE(ftdm_trunk_type_t) ftdm_span_get_trunk_type(const ftdm_span_t *span)
{
return span->trunk_type;
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hold(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
+ ftdm_status_t status;
ftdm_channel_lock(ftdmchan);
+
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_HOLD);
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_DIALTONE, 0);
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_DIALTONE, 0);
ftdm_channel_unlock(ftdmchan);
- return FTDM_SUCCESS;
+
+ return status;
}
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_unhold(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
+ ftdm_status_t status;
+
ftdm_channel_lock(ftdmchan);
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 0);
+
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 0);
+
ftdm_channel_unlock(ftdmchan);
- return FTDM_SUCCESS;
+
+ return status;
+}
+
+FT_DECLARE(void) ftdm_ack_indication(const ftdm_channel_t *fchan, ftdm_channel_indication_t indication, ftdm_status_t status)
+{
+ ftdm_sigmsg_t msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.event_id = FTDM_SIGEVENT_INDICATION_COMPLETED;
+ msg.ev_data.indication_completed.indication = indication;
+ msg.ev_data.indication_completed.status = status;
+ 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)
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;
}
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_ANSWERED);
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
-
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ status = FTDM_EINVAL;
+ ftdm_ack_indication(ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER, status);
goto done;
}
if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) {
/* We will fail RFC's if we not skip states, but some modules apart from ftmod_sangoma_isdn
* expect the call to always to go PROGRESS and PROGRESS MEDIA state before going to UP, so
- * use FTDM_SPAN_USE_SKIP_STATESfor now while we update the sig modules */
+ * use FTDM_SPAN_USE_SKIP_STATES for now while we update the sig modules */
if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
+ 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);
+ goto done;
+ }
}
/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
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) {
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
+ 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);
+ goto done;
+ }
}
/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
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;
}
}
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1);
-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);
+ }
+done:
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)
{
+ ftdm_status_t status = FTDM_SUCCESS;
+
ftdm_set_flag(chan, FTDM_CHANNEL_USER_HANGUP);
ftdm_set_echocancel_call_end(chan);
if (chan->hangup_timer) {
ftdm_sched_cancel_timer(globals.timingsched, chan->hangup_timer);
}
- ftdm_channel_set_state(file, func, line, chan, FTDM_CHANNEL_STATE_HANGUP, 1);
+ status = 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, however, because ftmod_analog
ftdm_channel_close(&chan);
}
}
- return FTDM_SUCCESS;
+ return status;
}
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_status_t status = FTDM_SUCCESS;
ftdm_channel_lock(ftdmchan);
ftdmchan->caller_data.hangup_cause = cause;
- call_hangup(ftdmchan, file, func, line);
+ status = call_hangup(ftdmchan, file, func, line);
ftdm_channel_unlock(ftdmchan);
- return FTDM_SUCCESS;
+ return status;
}
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
+ ftdm_status_t status = FTDM_SUCCESS;
+
ftdm_channel_lock(ftdmchan);
+
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
- call_hangup(ftdmchan, file, func, line);
+
+ status = call_hangup(ftdmchan, file, func, line);
+
ftdm_channel_unlock(ftdmchan);
- return FTDM_SUCCESS;
+ return status;
}
FT_DECLARE(const char *) ftdm_channel_get_last_error(const ftdm_channel_t *ftdmchan)
return id;
}
+/*
+ * Every user requested indication *MUST* be acknowledged with the proper status (ftdm_status_t)
+ * If the indication fails before we notify the signaling stack, we *MUST* acknowledge ourselves,
+ * but if we already notified the signaling stack about the indication, the signaling stack is
+ * responsible for the acknowledge.
+ * */
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);
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot indicate %s in outgoing channel in state %s\n",
+ ftdm_channel_indication2str(indication), ftdm_channel_state2str(ftdmchan->state));
+ status = FTDM_EINVAL;
+ ftdm_ack_indication(ftdmchan, indication, status);
+ 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");
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring indication %s because the call is in %s state\n",
+ ftdm_channel_indication2str(indication), ftdm_channel_state2str(ftdmchan->state));
+ status = FTDM_ECANCELED;
+ ftdm_ack_indication(ftdmchan, indication, status);
goto done;
}
/* 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_RINGING:
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_RINGING, 1);
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_RINGING, 1);
+ if (status != FTDM_SUCCESS) {
+ ftdm_ack_indication(ftdmchan, indication, status);
+ }
break;
case FTDM_CHANNEL_INDICATE_BUSY:
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_BUSY, 1);
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_BUSY, 1);
+ if (status != FTDM_SUCCESS) {
+ ftdm_ack_indication(ftdmchan, indication, status);
+ }
break;
case FTDM_CHANNEL_INDICATE_PROCEED:
- if (ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_PROCEED_STATE)) {
- if (ftdmchan->state == FTDM_CHANNEL_STATE_RING) {
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROCEED, 1);
- }
+ if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_PROCEED_STATE)) {
+ ftdm_ack_indication(ftdmchan, indication, status);
+ goto done;
+ }
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROCEED, 1);
+ if (status != FTDM_SUCCESS) {
+ ftdm_ack_indication(ftdmchan, indication, status);
}
break;
case FTDM_CHANNEL_INDICATE_PROGRESS:
- if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
- } else {
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
+ if (status != FTDM_SUCCESS) {
+ ftdm_ack_indication(ftdmchan, indication, status);
}
break;
case FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA:
- if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
- } else {
- if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) {
- if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
- }
-
- /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
- 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");
+ if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) {
+ 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, indication, status);
goto done;
}
}
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
+ /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
+ 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, indication, status);
+ goto done;
+ }
}
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
+ if (status != FTDM_SUCCESS) {
+ ftdm_ack_indication(ftdmchan, indication, status);
+ }
+ break;
+ case FTDM_CHANNEL_INDICATE_ANSWER:
+ /* _ftdm_channel_call_indicate takes care of the indication ack */
+ status = _ftdm_channel_call_answer(file, func, line, ftdmchan);
break;
default:
ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "Do not know how to indicate %d\n", indication);
status = FTDM_FAIL;
+ ftdm_ack_indication(ftdmchan, indication, status);
break;
}
done:
ftdm_channel_unlock(ftdmchan);
- return FTDM_SUCCESS;
+ return status;
}
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_send_msg(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_sigmsg_t *sigmsg)
FTDM_SIGEVENT_FACILITY, /*!< In call facility event */
FTDM_SIGEVENT_TRACE, /*!<Interpreted trace event */
FTDM_SIGEVENT_TRACE_RAW, /*!<Raw trace event */
+ FTDM_SIGEVENT_INDICATION_COMPLETED, /*!< Last requested indication was completed */
FTDM_SIGEVENT_INVALID, /*!<Invalid */
} ftdm_signal_event_t;
#define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROCEED", "RINGING", "PROGRESS", \
"PROGRESS_MEDIA", "ALARM_TRAP", "ALARM_CLEAR", \
- "COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "COLLISION", "FACILITY", "TRACE", "TRACE_RAW", "INVALID"
+ "COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "COLLISION", "FACILITY", \
+ "TRACE", "TRACE_RAW", "INDICATION_COMPLETED", "INVALID"
/*! \brief Move from string to ftdm_signal_event_t and viceversa */
FTDM_STR2ENUM_P(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t)
char digits[FTDM_DIGITS_LIMIT];
} ftdm_event_collected_t;
+/*! \brief FreeTDM supported indications.
+ * This is used during incoming calls when you want to request the signaling stack
+ * to notify about indications occurring locally. See ftdm_channel_call_indicate for more info */
+typedef enum {
+ FTDM_CHANNEL_INDICATE_RINGING,
+ FTDM_CHANNEL_INDICATE_PROCEED,
+ FTDM_CHANNEL_INDICATE_PROGRESS,
+ FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA,
+ FTDM_CHANNEL_INDICATE_BUSY,
+ /* Using this indication is equivalent to call ftdm_channel_call_answer API */
+ FTDM_CHANNEL_INDICATE_ANSWER,
+ FTDM_CHANNEL_INDICATE_INVALID,
+} ftdm_channel_indication_t;
+#define INDICATION_STRINGS "RINGING", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "BUSY", "ANSWER", "INVALID"
+
+/*! \brief Move from string to ftdm_channel_indication_t and viceversa */
+FTDM_STR2ENUM_P(ftdm_str2channel_indication, ftdm_channel_indication2str, ftdm_channel_indication_t)
+
+typedef struct {
+ /* The indication that was completed */
+ ftdm_channel_indication_t indication;
+ /* Completion status of the indication */
+ ftdm_status_t status;
+} ftdm_event_indication_completed_t;
+
/*! \brief Generic signaling message */
struct ftdm_sigmsg {
ftdm_signal_event_t event_id; /*!< The type of message */
union {
ftdm_event_sigstatus_t sigstatus; /*!< valid if event_id is FTDM_SIGEVENT_SIGSTATUS_CHANGED */
ftdm_event_trace_t logevent; /*!< valid if event_id is FTDM_SIGEVENT_TRACE or FTDM_SIGEVENT_TRACE_RAW */
- ftdm_event_collected_t collected; /*!< valif if event_id is FTDM_SIGEVENT_COLLECTED_DIGIT */
+ ftdm_event_collected_t collected; /*!< valid if event_id is FTDM_SIGEVENT_COLLECTED_DIGIT */
+ ftdm_event_indication_completed_t indication_completed; /*!< valid if the event_id is FTDM_SIGEVENT_INDICATION_COMPLETED */
} ev_data;
struct {
uint8_t autofree; /*!< Whether the freetdm core will free it after message delivery */
FTDM_CODEC_NONE = (1 << 30)
} ftdm_codec_t;
-/*! \brief FreeTDM supported indications.
- * This is used during incoming calls when you want to request the signaling stack
- * to notify about indications occurring locally */
-typedef enum {
- FTDM_CHANNEL_INDICATE_RINGING,
- FTDM_CHANNEL_INDICATE_PROCEED,
- FTDM_CHANNEL_INDICATE_PROGRESS,
- FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA,
- FTDM_CHANNEL_INDICATE_BUSY,
-} ftdm_channel_indication_t;
-
/*! \brief FreeTDM supported hardware alarms. */
typedef enum {
FTDM_ALARM_NONE = 0,
*/
FT_DECLARE(int) ftdm_channel_get_availability(ftdm_channel_t *ftdmchan);
-/*! \brief Answer call */
+/*! \brief Answer call. This can also be accomplished by ftdm_channel_call_indicate with FTDM_CHANNEL_INDICATE_ANSWER, in both
+ * cases you will get a FTDM_SIGEVENT_INDICATION_COMPLETED when the indication is sent (or an error occurs)
+ * \note Although this API will result in FTDM_SIGEVENT_INDICATION_COMPLETED event being delivered,
+ * there is no guarantee of whether the event will arrive after or before your execution thread returns
+ * from ftdm_channel_call_answer
+ */
#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) */
/*! \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 */
+/*! \brief Indicate a new condition in an incoming call
+ * \note Every indication request will result in FTDM_SIGEVENT_INDICATION_COMPLETED event being delivered with
+ * the proper status that will inform you if the request was successful or not.
+ * Be aware there is no guarantee of whether the event will arrive after or before your execution thread returns
+ * from ftdm_channel_call_indicate. This means you could get FTDM_SIGEVENT_INDICATION_COMPLETED even before
+ * your execution thread returns from the ftdm_channel_call_indicate() API
+ */
#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(char *) ftdm_channel_get_history_str(const ftdm_channel_t *channel);
-/*! \brief Initialize channel state for an outgoing call */
+/*! \brief Initialize channel state for an outgoing call
+ * \note This API will eventually be deprecated, is only needed if you use boost signaling
+ */
FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan);
+/*! \brief Enable/disable blocking mode in the channels for this span */
+FT_DECLARE(ftdm_status_t) ftdm_span_set_blocking_mode(const ftdm_span_t *span, ftdm_bool_t enabled);
+
/*! \brief Initialize the library */
FT_DECLARE(ftdm_status_t) ftdm_global_init(void);