]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: initial changes to make FreeTDM APIs non-blocking
authorMoises Silva <moy@sangoma.com>
Thu, 23 Dec 2010 20:39:20 +0000 (15:39 -0500)
committerMoises Silva <moy@sangoma.com>
Thu, 23 Dec 2010 20:39:20 +0000 (15:39 -0500)
libs/freetdm/src/ftdm_io.c
libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
libs/freetdm/src/include/freetdm.h
libs/freetdm/src/include/ftdm_declare.h
libs/freetdm/src/include/private/ftdm_core.h
libs/freetdm/src/include/private/ftdm_types.h

index 451441ec97086754dfc0c56e625dffb1af7ffe41..89e9321fcf94f1493a291bcd31eaf389fc525239 100644 (file)
@@ -304,6 +304,9 @@ FTDM_STR2ENUM(ftdm_str2ftdm_usr_layer1_prot, ftdm_user_layer1_prot2str, ftdm_use
 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)
@@ -1549,6 +1552,11 @@ end:
                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) {
@@ -1575,6 +1583,7 @@ end:
        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;
@@ -2124,6 +2133,27 @@ FT_DECLARE(void) ftdm_span_set_trunk_type(ftdm_span_t *span, ftdm_trunk_type_t t
        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;
@@ -2210,19 +2240,37 @@ FT_DECLARE(ftdm_bool_t) ftdm_channel_call_check_done(const ftdm_channel_t *ftdmc
 
 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)
@@ -2233,46 +2281,61 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
 
        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;
 }
@@ -2280,6 +2343,8 @@ done:
 /* 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);
@@ -2292,7 +2357,7 @@ static ftdm_status_t call_hangup(ftdm_channel_t *chan, const char *file, const c
                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
@@ -2305,28 +2370,34 @@ static ftdm_status_t call_hangup(ftdm_channel_t *chan, const char *file, const c
                        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)
@@ -2411,13 +2482,31 @@ FT_DECLARE(uint32_t) ftdm_channel_get_ph_span_id(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;
        }
 
@@ -2425,55 +2514,71 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch
        /* 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)
index 097ffcac02d7ac1109edc1f692da714a835f1da6..3809b224c4e729a8b82159f58fdc56be6b689e2a 100644 (file)
@@ -1595,6 +1595,9 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
        /* use signals queue */
        ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
 
+       /* we can skip states (going straight from RING to UP) */
+       ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);
+
        /* setup the scheduler */
        snprintf(schedname, sizeof(schedname), "ftmod_r2_%s", span->name);
        ftdm_assert(ftdm_sched_create(&r2data->sched, schedname) == FTDM_SUCCESS, "Failed to create schedule!\n");
index d27353ddb0d413959ecc39c0ee316cefe22861f6..68c9fdc7c414bdd027bfa41a874161fdac126d0e 100644 (file)
@@ -349,11 +349,13 @@ typedef enum {
        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)
@@ -434,6 +436,31 @@ typedef struct {
        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 */
@@ -444,7 +471,8 @@ struct ftdm_sigmsg {
        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 */
@@ -708,17 +736,6 @@ typedef enum {
        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,
@@ -741,7 +758,12 @@ FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *ha
  */
 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) */
@@ -753,7 +775,13 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
 /*! \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) */
@@ -1494,9 +1522,14 @@ FT_DECLARE(const char *) ftdm_channel_get_last_state_str(const ftdm_channel_t *c
  */
 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);
 
index bfec44825367dd4841b5111458374d310ae862ef..2e41281baf7b66dcbc141a03d9f02afb1cd65abe 100644 (file)
@@ -183,7 +183,15 @@ typedef enum {
        FTDM_TIMEOUT, /*!< Operation timed out (ie: polling on a device)*/
        FTDM_NOTIMPL, /*!< Operation not implemented */
        FTDM_BREAK, /*!< Request the caller to perform a break (context-dependant, ie: stop getting DNIS/ANI) */
-       FTDM_EINVAL /*!< Invalid argument */
+
+       /*!< Any new return codes should try to mimc unix style error codes, no need to reinvent */
+       /* Remapping some of the codes that were before */
+       FTDM_ENOMEM = FTDM_MEMERR, /*!< Memory error */
+       FTDM_ETIMEDOUT = FTDM_TIMEOUT, /*!< Operation timedout */
+       FTDM_ENOSYS = FTDM_NOTIMPL, /*!< The function is not implemented */
+
+       FTDM_EINVAL, /*!< Invalid argument */
+       FTDM_ECANCELED, /*!< Operation cancelled */
 } ftdm_status_t;
 
 /*! \brief FreeTDM bool type. */
index 650fce2fcc26493f1847f8ba25a5590b0055b1aa..dd70dd10ed0c9ccb1f23517d26acb1e8d6ddfc55 100644 (file)
@@ -606,6 +606,7 @@ FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap);
 
 FT_DECLARE(ftdm_status_t) ftdm_span_close_all(void);
 FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan);
+FT_DECLARE(void) ftdm_ack_indication(const ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication, ftdm_status_t status);
 
 /*! 
  * \brief Retrieves an event from the span
index 5b9d05e6c6f30f15dfc956edd2483b60d5977ea8..d70bc69b3a20fb9e46aa1723c89d8c1d23642774 100644 (file)
@@ -260,9 +260,16 @@ FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channe
 #define FTDM_CHANNEL_OUTBOUND        (1ULL << 18)
 #define FTDM_CHANNEL_SUSPENDED       (1ULL << 19)
 #define FTDM_CHANNEL_3WAY            (1ULL << 20)
+
+/* this 3 flags are really nonsense used by boost module only, as soon
+ * as we deprecate/delete boost module we can get rid of them 
+ * ==================
+ * */
 #define FTDM_CHANNEL_PROGRESS        (1ULL << 21)
 #define FTDM_CHANNEL_MEDIA           (1ULL << 22)
 #define FTDM_CHANNEL_ANSWERED        (1ULL << 23)
+/* ================== */
+
 #define FTDM_CHANNEL_MUTE            (1ULL << 24)
 #define FTDM_CHANNEL_USE_RX_GAIN     (1ULL << 25)
 #define FTDM_CHANNEL_USE_TX_GAIN     (1ULL << 26)
@@ -273,6 +280,8 @@ FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channe
 #define FTDM_CHANNEL_TX_DISABLED     (1ULL << 31)
 /*!< The user knows about a call in this channel */
 #define FTDM_CHANNEL_CALL_STARTED    (1ULL << 32)
+/*!< The user wants non-blocking operations in the channel */
+#define FTDM_CHANNEL_NONBLOCK        (1ULL << 33)
 
 typedef enum {
        ZSM_NONE,