]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
freetdm: Added FTDM_SIGEVENT_DIALING
authorMoises Silva <moy@sangoma.com>
Mon, 10 Jan 2011 21:49:58 +0000 (16:49 -0500)
committerMoises Silva <moy@sangoma.com>
Mon, 10 Jan 2011 21:49:58 +0000 (16:49 -0500)
         Added hunting scheme to support new ftdm_call_place API
         Make ftdm_channel_call_answer use ftdm_channel_call_indicate with FTDM_CHANNEL_INDICATE_ANSWER
         Updated doxygen docs in freetdm.h

libs/freetdm/docs/async.txt [new file with mode: 0644]
libs/freetdm/mod_freetdm/mod_freetdm.c
libs/freetdm/src/ftdm_io.c
libs/freetdm/src/ftdm_state.c
libs/freetdm/src/include/freetdm.h

diff --git a/libs/freetdm/docs/async.txt b/libs/freetdm/docs/async.txt
new file mode 100644 (file)
index 0000000..04069eb
--- /dev/null
@@ -0,0 +1,14 @@
+APIs that result in an event when the API returns FTDM_SUCCESS
+
+ftdm_channel_call_answer()
+ftdm_channel_call_indicate()
+       FTDM_SIGEVENT_INDICATION_COMPLETED
+       *note that FTDM_SIGEVENT_INDICATION_COMPLETED has associated data to indicate the result of the indication
+       *note this event is only delivered on non-blocking channels
+
+ftdm_call_place
+       FTDM_SIGEVENT_DIALING
+
+ftdm_channel_call_hangup
+       FTDM_SIGEVENT_RELEASED
+
index f50d26c290bf7f20b4727e8376d58853d5d9b45b..7ac1b281a43e1f72f79027eef7c0653e6aa54a1c 100755 (executable)
@@ -1073,6 +1073,64 @@ static const char* channel_get_variable(switch_core_session_t *session, switch_e
        return NULL;
 }
 
+typedef struct {
+       switch_event_t *var_event;
+       switch_core_session_t *new_session;
+       private_t *tech_pvt;
+       switch_caller_profile_t *caller_profile;
+} hunt_data_t;
+
+static ftdm_status_t on_channel_found(ftdm_channel_t *fchan, ftdm_caller_data_t *caller_data)
+{
+       uint32_t span_id, chan_id;
+       const char *var;
+       char *sess_uuid;
+       char name[128];
+       ftdm_status_t status;
+       hunt_data_t *hdata = caller_data->priv;
+       switch_channel_t *channel = switch_core_session_get_channel(hdata->new_session);
+
+       if ((var = switch_event_get_header(hdata->var_event, "freetdm_pre_buffer_size"))) {
+               int tmp = atoi(var);
+               if (tmp > -1) {
+                       ftdm_channel_command(fchan, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tmp);
+               }
+       }
+
+       span_id = ftdm_channel_get_span_id(fchan);
+       chan_id = ftdm_channel_get_id(fchan);
+
+       tech_init(hdata->tech_pvt, hdata->new_session, fchan);
+       hdata->tech_pvt->caller_profile = hdata->caller_profile;
+
+       snprintf(name, sizeof(name), "FreeTDM/%u:%u/%s", span_id, chan_id, caller_data->dnis.digits);
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name);
+       switch_channel_set_name(channel, name);
+       switch_channel_set_variable(channel, "freetdm_span_name", ftdm_channel_get_span_name(fchan));
+       switch_channel_set_variable_printf(channel, "freetdm_span_number", "%d", span_id);
+       switch_channel_set_variable_printf(channel, "freetdm_chan_number", "%d", chan_id);
+
+       switch_channel_set_state(channel, CS_INIT);
+       sess_uuid = switch_core_session_get_uuid(hdata->new_session);
+       status = ftdm_channel_add_token(fchan, sess_uuid, ftdm_channel_get_token_count(fchan));
+       switch_assert(status == FTDM_SUCCESS);
+
+       if (SPAN_CONFIG[span_id].limit_calls) {
+               char spanresource[512];
+               snprintf(spanresource, sizeof(spanresource), "span_%s_%s", ftdm_channel_get_span_name(fchan), 
+                               caller_data->dnis.digits);
+               ftdm_log(FTDM_LOG_DEBUG, "Adding rate limit resource on channel %d:%d (%s/%s/%d/%d)\n", 
+                               span_id, chan_id, FREETDM_LIMIT_REALM, 
+                               spanresource, SPAN_CONFIG[span_id].limit_calls, SPAN_CONFIG[span_id].limit_seconds);
+               if (switch_limit_incr("hash", hdata->new_session, FREETDM_LIMIT_REALM, spanresource, 
+                                       SPAN_CONFIG[span_id].limit_calls, SPAN_CONFIG[span_id].limit_seconds) != SWITCH_STATUS_SUCCESS) {
+                       return FTDM_BREAK;
+               }
+       }
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Attached session %s to channel %d:%d\n", sess_uuid, span_id, chan_id);
+       return FTDM_SUCCESS;
+}
+
 /* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
 that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
 */
@@ -1081,13 +1139,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
                                                                                                        switch_core_session_t **new_session, switch_memory_pool_t **pool,
                                                                                                        switch_originate_flag_t flags, switch_call_cause_t *cancel_cause)
 {
-
+       hunt_data_t hunt_data;
        const char *dest = NULL;
        char *data = NULL;
        int span_id = -1, group_id = -1, chan_id = 0;
-       ftdm_channel_t *ftdmchan = NULL;
        switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
-       char name[128];
        ftdm_status_t status;
        int direction = FTDM_TOP_DOWN;
        ftdm_caller_data_t caller_data = {{ 0 }};
@@ -1097,6 +1153,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
        int argc = 0;
        const char *var;
        const char *dest_num = NULL, *callerid_num = NULL;
+       ftdm_hunting_scheme_t hunting;
 
        if (!outbound_profile) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing caller profile\n");
@@ -1125,7 +1182,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
        
        if ((argc = switch_separate_string(data, '/', argv, (sizeof(argv) / sizeof(argv[0])))) < 2) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid dial string\n");
-        return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+               return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
        }
        
        if (switch_is_number(argv[0])) {
@@ -1309,30 +1366,21 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
        ftdm_set_string(caller_data.cid_name, outbound_profile->caller_id_name);
        ftdm_set_string(caller_data.cid_num.digits, switch_str_nil(outbound_profile->caller_id_number));
 
+       memset(&hunting, 0, sizeof(hunting));
+
        if (group_id >= 0) {
-               status = ftdm_channel_open_by_group(group_id, direction, &caller_data, &ftdmchan);
+               hunting.mode = FTDM_HUNT_GROUP;
+               hunting.mode_data.group.group_id = group_id;
+               hunting.mode_data.group.direction = direction;
        } else if (chan_id) {
-               status = ftdm_channel_open(span_id, chan_id, &ftdmchan);
+               hunting.mode = FTDM_HUNT_CHAN;
+               hunting.mode_data.chan.span_id = span_id;
+               hunting.mode_data.chan.chan_id = chan_id;
        } else {
-               status = ftdm_channel_open_by_span(span_id, direction, &caller_data, &ftdmchan);
+               hunting.mode = FTDM_HUNT_SPAN;
+               hunting.mode_data.span.span_id = span_id;
+               hunting.mode_data.span.direction = direction;
        }
-       
-       if (status != FTDM_SUCCESS) {
-               if (caller_data.hangup_cause == SWITCH_CAUSE_NONE) {
-                       caller_data.hangup_cause = SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
-               }
-               return caller_data.hangup_cause;
-       }
-
-       if ((var = switch_event_get_header(var_event, "freetdm_pre_buffer_size"))) {
-               int tmp = atoi(var);
-               if (tmp > -1) {
-                       ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tmp);
-               }
-       }
-
-       span_id = ftdm_channel_get_span_id(ftdmchan);
-       chan_id = ftdm_channel_get_id(ftdmchan);
 
        for (h = var_event->headers; h; h = h->next) {
                if (!strncasecmp(h->name, FREETDM_VAR_PREFIX, FREETDM_VAR_PREFIX_LEN)) {
@@ -1343,57 +1391,33 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
                        }
                }
        }
-       
+
        if ((*new_session = switch_core_session_request(freetdm_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, flags, pool)) != 0) {
                private_t *tech_pvt;
                switch_caller_profile_t *caller_profile;
                switch_channel_t *channel = switch_core_session_get_channel(*new_session);
                
                switch_core_session_add_stream(*new_session, NULL);
-               if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) {
-                       tech_init(tech_pvt, *new_session, ftdmchan);
-               } else {
+               if (!(tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t)))) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
                        switch_core_session_destroy(new_session);
                        cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
                        goto fail;
                }
 
-               snprintf(name, sizeof(name), "FreeTDM/%u:%u/%s", span_id, chan_id, dest);
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name);
-               switch_channel_set_name(channel, name);
-               switch_channel_set_variable(channel, "freetdm_span_name", ftdm_channel_get_span_name(ftdmchan));
-               switch_channel_set_variable_printf(channel, "freetdm_span_number", "%d", span_id);
-               switch_channel_set_variable_printf(channel, "freetdm_chan_number", "%d", chan_id);
-               ftdm_channel_set_caller_data(ftdmchan, &caller_data);
                caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
                caller_profile->destination_number = switch_core_strdup(caller_profile->pool, switch_str_nil(dest_num));
                caller_profile->caller_id_number = switch_core_strdup(caller_profile->pool, switch_str_nil(callerid_num));
                switch_channel_set_caller_profile(channel, caller_profile);
-               tech_pvt->caller_profile = caller_profile;
-               
-               
-               switch_channel_set_state(channel, CS_INIT);
-               if (ftdm_channel_add_token(ftdmchan, switch_core_session_get_uuid(*new_session), ftdm_channel_get_token_count(ftdmchan)) != FTDM_SUCCESS) {
-                       switch_core_session_destroy(new_session);
-                       cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
-                       goto fail;
-               }
 
+               hunting.result_cb = on_channel_found;
+               hunt_data.var_event = var_event;
+               hunt_data.new_session = *new_session;
+               hunt_data.caller_profile = caller_profile;
+               hunt_data.tech_pvt = tech_pvt;
+               caller_data.priv = &hunt_data;
 
-               if (SPAN_CONFIG[span_id].limit_calls) {
-                       char spanresource[512];
-                       snprintf(spanresource, sizeof(spanresource), "span_%s_%s", ftdm_channel_get_span_name(ftdmchan), caller_data.dnis.digits);
-                       ftdm_log(FTDM_LOG_DEBUG, "Adding rate limit resource on channel %d:%d (%s/%s/%d/%d)\n", span_id, chan_id, FREETDM_LIMIT_REALM, 
-                                       spanresource, SPAN_CONFIG[span_id].limit_calls, SPAN_CONFIG[span_id].limit_seconds);
-                       if (switch_limit_incr("hash", *new_session, FREETDM_LIMIT_REALM, spanresource, SPAN_CONFIG[span_id].limit_calls, SPAN_CONFIG[span_id].limit_seconds) != SWITCH_STATUS_SUCCESS) {
-                               switch_core_session_destroy(new_session);
-                               cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
-                               goto fail;
-                       }
-               }
-
-               if ((status = ftdm_channel_call_place(ftdmchan)) != FTDM_SUCCESS) {
+               if ((status = ftdm_call_place(&caller_data, &hunting)) != FTDM_SUCCESS) {
                        if (tech_pvt->read_codec.implementation) {
                                switch_core_codec_destroy(&tech_pvt->read_codec);
                        }
@@ -1402,28 +1426,22 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
                                switch_core_codec_destroy(&tech_pvt->write_codec);
                        }
                        switch_core_session_destroy(new_session);
-                       if (status == FTDM_BREAK) { /* glare, we don't want to touch the channel since is being used for incoming call now */
+                       if (status == FTDM_BREAK || status == FTDM_EBUSY) { 
                                cause = SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
-                               ftdmchan = NULL;
                        } else {
                                cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
                        }
-            goto fail;
+                       goto fail;
                }
 
-               ftdm_channel_init(ftdmchan);
+               ftdm_channel_init(caller_data.fchan);
                
                return SWITCH_CAUSE_SUCCESS;
        }
 
 fail:
 
-       if (ftdmchan) {
-               ftdm_channel_call_hangup_with_cause(ftdmchan, FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE);
-       }
-
        return cause;
-
 }
 
 static void ftdm_enable_channel_dtmf(ftdm_channel_t *fchan, switch_channel_t *channel)
@@ -1645,6 +1663,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_common_signal)
 
        case FTDM_SIGEVENT_RELEASED: 
        case FTDM_SIGEVENT_INDICATION_COMPLETED:
+       case FTDM_SIGEVENT_DIALING:
                { 
                        /* Swallow these events */
                        return FTDM_BREAK;
index cce3963c3b8164307519b35b9f5086210b46044a..f111c8e754333bc023da42bc00aae14ec5dc152b 100644 (file)
@@ -1425,8 +1425,9 @@ static __inline__ int request_voice_channel(ftdm_channel_t *check, ftdm_channel_
                                 * sometimes with the group or span lock held and were
                                 * blocking anyone hunting for channels available and
                                 * I believe teh channel_request() function may take
-                                * a bit of time 
-                                * */
+                                * a bit of time. However channel_request is a callback
+                                * used by boost and may be only a few other old sig mods
+                                * and it should be deprecated */
                                ftdm_mutex_unlock(check->mutex);
                                ftdm_set_caller_data(check->span, caller_data);
                                status = check->span->channel_request(check->span, check->chan_id, 
@@ -1439,7 +1440,9 @@ static __inline__ int request_voice_channel(ftdm_channel_t *check, ftdm_channel_
                                if (status == FTDM_SUCCESS) {
                                        *ftdmchan = check;
                                        ftdm_set_flag(check, FTDM_CHANNEL_OUTBOUND);
+#if 0
                                        ftdm_mutex_unlock(check->mutex);
+#endif
                                        return 1;
                                }
                        }
@@ -1491,9 +1494,9 @@ static ftdm_status_t __inline__ get_best_rated(ftdm_channel_t **fchan, ftdm_chan
        }
        *fchan = best_rated;
        ftdm_set_flag(best_rated, FTDM_CHANNEL_OUTBOUND);
-       
+#if 0  
        ftdm_mutex_unlock(best_rated->mutex);
-
+#endif
        return FTDM_SUCCESS;
 }
 
@@ -1523,7 +1526,7 @@ FT_DECLARE(int) ftdm_channel_get_availability(ftdm_channel_t *ftdmchan)
        return availability;
 }
 
-FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
+static ftdm_status_t _ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
 {
        ftdm_status_t status = FTDM_FAIL;
        ftdm_channel_t *check = NULL;
@@ -1604,6 +1607,16 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_dir
        return status;
 }
 
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
+{
+       ftdm_status_t status;
+       status = _ftdm_channel_open_by_group(group_id, direction, caller_data, ftdmchan);
+       if (status == FTDM_SUCCESS) {
+               ftdm_channel_t *fchan = *ftdmchan;
+               ftdm_channel_unlock(fchan);
+       }
+       return status;
+}
 
 FT_DECLARE(ftdm_status_t) ftdm_span_channel_use_count(ftdm_span_t *span, uint32_t *count)
 {
@@ -1626,7 +1639,8 @@ FT_DECLARE(ftdm_status_t) ftdm_span_channel_use_count(ftdm_span_t *span, uint32_
        return FTDM_SUCCESS;
 }
 
-FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
+/* Hunt a channel by span, if successful the channel is returned locked */
+static ftdm_status_t _ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
 {
        ftdm_status_t status = FTDM_FAIL;
        ftdm_channel_t *check = NULL;
@@ -1724,6 +1738,17 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc
        return status;
 }
 
+FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
+{
+       ftdm_status_t status;
+       status = _ftdm_channel_open_by_span(span_id, direction, caller_data, ftdmchan);
+       if (status == FTDM_SUCCESS) {
+               ftdm_channel_t *fchan = *ftdmchan;
+               ftdm_channel_unlock(fchan);
+       }
+       return status;
+}
+
 FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan)
 {
        ftdm_status_t status = FTDM_FAIL;
@@ -1774,7 +1799,7 @@ done:
        return status;
 }
 
-FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan)
+static ftdm_status_t _ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan)
 {
        ftdm_channel_t *check = NULL;
        ftdm_span_t *span = NULL;
@@ -1855,6 +1880,10 @@ openchan:
        ftdm_set_flag(check, FTDM_CHANNEL_INUSE);
        ftdm_set_flag(check, FTDM_CHANNEL_OUTBOUND);
        *ftdmchan = check;
+#if 1
+       /* we've got the channel, do not unlock it */
+       goto done;
+#endif
 
 unlockchan:
        ftdm_mutex_unlock(check->mutex);
@@ -1868,6 +1897,17 @@ done:
        return status;
 }
 
+FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan)
+{
+       ftdm_status_t status;
+       status = _ftdm_channel_open(span_id, chan_id, ftdmchan);
+       if (status == FTDM_SUCCESS) {
+               ftdm_channel_t *fchan = *ftdmchan;
+               ftdm_channel_unlock(fchan);
+       }
+       return status;
+}
+
 FT_DECLARE(uint32_t) ftdm_channel_get_id(const ftdm_channel_t *ftdmchan)
 {
        return ftdmchan->chan_id;
@@ -2048,25 +2088,11 @@ FT_DECLARE(void) ftdm_ack_indication(ftdm_channel_t *fchan, ftdm_channel_indicat
        ftdm_span_send_signal(fchan->span, &msg);
 }
 
-/*! \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  */
+/*! Answer call without locking the channel. The caller must have locked first */
 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;
 
-       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;
-               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
@@ -2116,13 +2142,12 @@ done:
 
 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);
+       ftdm_status_t status;
 
-       status = _ftdm_channel_call_answer_nl(file, func, line, ftdmchan);
+       /* we leave the locking up to ftdm_channel_call_indicate, DO NOT lock here since ftdm_channel_call_indicate expects
+        * the lock recursivity to be 1 */
+       status = _ftdm_channel_call_indicate(file, func, line, ftdmchan, FTDM_CHANNEL_INDICATE_ANSWER);
 
-       ftdm_channel_unlock(ftdmchan);
        return status;
 }
 
@@ -2319,7 +2344,6 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch
                status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
                break;
        case FTDM_CHANNEL_INDICATE_ANSWER:
-               /* _ftdm_channel_call_answer takes care of the indication ack */
                status = _ftdm_channel_call_answer_nl(file, func, line, ftdmchan);
                break;
        default:
@@ -2365,7 +2389,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_reset(const char *file, const char *func
        return FTDM_SUCCESS;
 }
 
-FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
+static ftdm_status_t _ftdm_channel_call_place_nl(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
 {
        ftdm_status_t status = FTDM_FAIL;
        
@@ -2374,8 +2398,6 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char
 
        ftdm_set_echocancel_call_begin(ftdmchan);
 
-       ftdm_channel_lock(ftdmchan);
-
        if (!ftdmchan->span->outgoing_call) {
                ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "outgoing_call method not implemented in this span!\n");
                status = FTDM_ENOSYS;
@@ -2427,8 +2449,6 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char
        }
 
 done:
-       ftdm_channel_unlock(ftdmchan);
-
 #ifdef __WINDOWS__
        UNREFERENCED_PARAMETER(file);
        UNREFERENCED_PARAMETER(func);
@@ -2437,6 +2457,64 @@ done:
        return status;
 }
 
+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;
+       ftdm_channel_lock(ftdmchan);
+
+       status = _ftdm_channel_call_place_nl(file, func, line, ftdmchan);
+
+       ftdm_channel_unlock(ftdmchan);
+       return status;
+}
+
+FT_DECLARE(ftdm_status_t) _ftdm_call_place(const char *file, const char *func, int line, 
+               ftdm_caller_data_t *caller_data, ftdm_hunting_scheme_t *hunting)
+{
+       ftdm_assert_return(caller_data, FTDM_EINVAL, "Invalid caller data\n");
+       ftdm_assert_return(hunting, FTDM_EINVAL, "Invalid hunting scheme\n");
+
+       ftdm_status_t status = FTDM_SUCCESS;
+       ftdm_channel_t *fchan = NULL;
+
+       if (hunting->mode == FTDM_HUNT_SPAN) {
+               status = _ftdm_channel_open_by_span(hunting->mode_data.span.span_id, 
+                               hunting->mode_data.span.direction, caller_data, &fchan);
+       } else if (hunting->mode == FTDM_HUNT_GROUP) {
+               status = _ftdm_channel_open_by_group(hunting->mode_data.group.group_id, 
+                               hunting->mode_data.group.direction, caller_data, &fchan);
+       } else if (hunting->mode == FTDM_HUNT_CHAN) {
+               status = _ftdm_channel_open(hunting->mode_data.chan.span_id, hunting->mode_data.chan.chan_id, &fchan);
+       } else {
+               ftdm_log(FTDM_LOG_ERROR, "Cannot make outbound call with invalid hunting mode %d\n", hunting->mode);
+               return FTDM_EINVAL;
+       }
+
+       if (status != FTDM_SUCCESS) {
+               return FTDM_EBUSY;
+       }
+
+       /* we have a locked channel and are not afraid of using it! */
+       status = hunting->result_cb(fchan, caller_data);
+       if (status != FTDM_SUCCESS) {
+               status = FTDM_ECANCELED;
+               goto done;
+       }
+
+       ftdm_channel_set_caller_data(fchan, caller_data);
+
+       status = _ftdm_channel_call_place_nl(file, func, line, fchan);
+       if (status != FTDM_SUCCESS) {
+               goto done;
+       }
+
+       caller_data->fchan = fchan;
+done:
+       ftdm_channel_unlock(fchan);
+
+       return status;
+}
+
 FT_DECLARE(ftdm_status_t) ftdm_channel_set_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t sigstatus)
 {
        ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel\n");
index 593dc5858b1d5299838f256bcdb2ee53a208489a..574d85845b50f4bc3fc63c8cdb668ab8d0789822 100644 (file)
@@ -77,6 +77,12 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const c
        } else if (state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
                ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);    
                ftdm_set_flag(fchan, FTDM_CHANNEL_MEDIA);       
+       } else if (state == FTDM_CHANNEL_STATE_DIALING) {
+               ftdm_sigmsg_t msg;
+               memset(&msg, 0, sizeof(msg));
+               msg.channel = fchan;
+               msg.event_id = FTDM_SIGEVENT_DIALING;
+               ftdm_span_send_signal(fchan->span, &msg);
        }
 
        /* MAINTENANCE WARNING
index 5f61b0e257a6fdaaee341b5c1f9c3fdc2b6b741a..121aa18bf73bdf8742ddbcd31e5be835577ad6bd 100644 (file)
@@ -321,8 +321,57 @@ typedef struct ftdm_caller_data {
         * should use the call_id from sigmsg otherwise */
        uint32_t call_id; /*!< Unique call ID for this call */
        ftdm_channel_t *fchan; /*!< FreeTDM channel associated (can be NULL) */
+       void *priv; /*!< Private data for the FreeTDM user */
 } ftdm_caller_data_t;
 
+/*! \brief Hunting mode */
+typedef enum {
+       FTDM_HUNT_SPAN, /*!< Hunt channels in a given span */
+       FTDM_HUNT_GROUP, /*!< Hunt channels in a given group */
+       FTDM_HUNT_CHAN, /*!< Hunt for a specific channel */
+} ftdm_hunt_mode_t;
+
+/*! \brief Structure used for FTDM_HUNT_SPAN mode */
+typedef struct {
+       uint32_t span_id;
+       ftdm_direction_t direction;
+} ftdm_span_hunt_t;
+
+/*! \brief Structure used for FTDM_HUNT_GROUP mode */
+typedef struct {
+       uint32_t group_id;
+       ftdm_direction_t direction;
+} ftdm_group_hunt_t;
+
+/*! \brief Structure used for FTDM_HUNT_CHAN mode */
+typedef struct {
+       uint32_t span_id;
+       uint32_t chan_id;
+} ftdm_chan_hunt_t;
+
+/*! \brief Function called before placing the call in the hunted channel
+ *         The user can have a last saying in whether to proceed or abort 
+ *         the call attempt. Be aware that this callback will be called with 
+ *         the channel lock and you must not do any blocking operations during 
+ *         its execution.
+ *  \param fchan The channel that will be used to place the call
+ *  \param caller_data The caller data provided to ftdm_call_place
+ *  \return FTDM_SUCCESS to proceed or FTDM_BREAK to abort the hunting
+ */
+typedef ftdm_status_t (*ftdm_hunt_result_cb_t)(ftdm_channel_t *fchan, ftdm_caller_data_t *caller_data);
+
+/*! \brief Channel Hunting provided to ftdm_call_place() */
+typedef struct {
+       ftdm_hunt_mode_t mode;
+       union {
+               ftdm_span_hunt_t span;
+               ftdm_group_hunt_t group;
+               ftdm_chan_hunt_t chan;
+       } mode_data;
+       ftdm_hunt_result_cb_t result_cb; 
+} ftdm_hunting_scheme_t;
+
+
 /*! \brief Tone type */
 typedef enum {
        FTDM_TONE_DTMF = (1 << 0)
@@ -335,7 +384,7 @@ typedef enum {
        FTDM_SIGEVENT_RELEASED, /*!< Channel is completely released and available */
        FTDM_SIGEVENT_UP, /*!< Outgoing call has been answered */
        FTDM_SIGEVENT_FLASH, /*!< Flash event  (typically on-hook/off-hook for analog devices) */
-       FTDM_SIGEVENT_PROCEED, /*!< Outgoing call got a response */
+       FTDM_SIGEVENT_PROCEED, /*!< Outgoing call got an initial positive response from the other end */
        FTDM_SIGEVENT_RINGING, /*!< Remote side is in ringing state */
        FTDM_SIGEVENT_PROGRESS, /*!< Outgoing call is making progress */
        FTDM_SIGEVENT_PROGRESS_MEDIA, /*!< Outgoing call is making progress and there is media available */
@@ -350,12 +399,13 @@ typedef enum {
        FTDM_SIGEVENT_TRACE, /*!<Interpreted trace event */
        FTDM_SIGEVENT_TRACE_RAW, /*!<Raw trace event */
        FTDM_SIGEVENT_INDICATION_COMPLETED, /*!< Last requested indication was completed */
+       FTDM_SIGEVENT_DIALING, /* Outgoing call just started */
        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", "INDICATION_COMPLETED", "INVALID"
+               "TRACE", "TRACE_RAW", "INDICATION_COMPLETED", "DIALING", "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)
 
@@ -782,8 +832,10 @@ 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. 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,
+ *         cases you will get a FTDM_SIGEVENT_INDICATION_COMPLETED when the indication is sent (or an error occurs).
+ *         Just as with ftdm_channel_call_indicate you won't receive FTDM_SIGEVENT_INDICATION_COMPLETED when this function
+ *         returns anything else than FTDM_SUCCESS
+ *  \note Although this API may 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 
  */
@@ -792,12 +844,36 @@ FT_DECLARE(int) ftdm_channel_get_availability(ftdm_channel_t *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 */
+/*! \brief Place an outgoing call in the given channel 
+ *  \deprecated This macro is deprecated since leaves the door open to glare issues, use ftdm_call_place instead
+ */
 #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) */
+/*! \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) 
+ *  \deprecated This function is deprecated since leaves the door open to glare issues, use ftdm_call_place instead
+ */
 FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan);
 
+/*! \brief Place an outgoing call with the given caller data in a channel according to the hunting scheme provided */
+#define ftdm_call_place(callerdata, hunting) _ftdm_call_place(__FILE__, __FUNCTION__, __LINE__, (callerdata), (hunting))
+
+/*! \brief Place an outgoing call with the given caller data in a channel according to the hunting scheme provided and records
+ *         the place where it was called. See ftdm_call_place for an easy to use macro
+ *  \return FTDM_SUCCESS if the call attempt was successful 
+ *          FTDM_FAIL if there was an unspecified error
+ *          FTDM_EBUSY if the channel was busy 
+ *          FTDM_BREAK if glare was detected and you must try again
+ *  \note Even when FTDM_SUCCESS is returned, the call may still fail later on due to glare, in such case FTDM_SIGEVENT_STOP
+ *        will be sent with the hangup cause field set to FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL
+ *
+ *  \note When this function returns FTDM_SUCCESS, the member .fchan from caller_data will be set to the channel used to place the call
+ *        and .call_id to the generated call id for that call
+ *
+ *  \note When this function is successful you are guaranteed to receive FTDM_SIGEVENT_DIALING, this event could even be delivered
+ *        before your execution thread returns from this function
+ */
+FT_DECLARE(ftdm_status_t) _ftdm_call_place(const char *file, const char *func, int line, ftdm_caller_data_t *caller_data, ftdm_hunting_scheme_t *hunting);
+
 /*! \brief Indicate a new condition in an incoming call 
  *
  *  \note Every indication request will result in FTDM_SIGEVENT_INDICATION_COMPLETED event being delivered with
@@ -1133,6 +1209,8 @@ FT_DECLARE(uint32_t) ftdm_group_get_id(const ftdm_group_t *group);
 /*! 
  * \brief Open a channel specifying the span id and chan id (required before placing a call on the channel)
  *
+ * \warning Try using ftdm_call_place instead if you plan to place a call after opening the channel
+ *
  * \note You must call ftdm_channel_close() or ftdm_channel_call_hangup() to release the channel afterwards
  *     Only use ftdm_channel_close if there is no call (incoming or outgoing) in the channel
  *
@@ -1148,6 +1226,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id,
 /*! 
  * \brief Hunts and opens a channel specifying the span id only
  *
+ * \warning Try using ftdm_call_place instead if you plan to place a call after opening the channel
+ *
  * \note You must call ftdm_channel_close() or ftdm_channel_call_hangup() to release the channel afterwards
  *     Only use ftdm_channel_close if there is no call (incoming or outgoing) in the channel
  *
@@ -1164,6 +1244,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc
 /*! 
  * \brief Hunts and opens a channel specifying group id
  *
+ * \warning Try using ftdm_call_place instead if you plan to place a call after opening the channel
+ *
  * \note You must call ftdm_channel_close() or ftdm_channel_call_hangup() to release the channel afterwards
  *     Only use ftdm_channel_close if there is no call (incoming or outgoing) in the channel
  *
@@ -1180,8 +1262,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_dir
 /*! 
  * \brief Close a previously open channel
  *
- * \note If you call ftdm_channel_call_hangup() you MUST NOT call this function, the signaling
- *       stack will close the channel.
+ * \warning FreeTDM is more and more a signaling API rather than just a plane IO API, unless you are using
+ *          FreeTDM as a pure IO API without its signaling modules, you should not use this function
+ *
+ * \note If you placed a call in this channel use ftdm_channel_call_hangup(), you MUST NOT call this function, 
+ *       the signaling stack will close the channel when the call is done.
  *
  * \param ftdmchan pointer to the channel to close
  *
@@ -1351,7 +1436,9 @@ FT_DECLARE(const char *) ftdm_channel_get_number(const ftdm_channel_t *ftdmchan)
 FT_DECLARE(uint32_t) ftdm_channel_get_ph_id(const ftdm_channel_t *ftdmchan);
 
 /*! 
- * \brief Configure span with a signaling type (deprecated use ftdm_configure_span_signaling instead)
+ * \brief Configure span with a signaling type 
+ *
+ * \deprecated use ftdm_configure_span_signaling instead
  *
  * \note This function does the same as ftdm_configure_span_signaling
  *
@@ -1552,7 +1639,7 @@ 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
- *  \note This API will eventually be deprecated, is only needed if you use boost signaling 
+ *  \deprecated This API is only used for boost signaling
  */
 FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan);