Skip to content

Instantly share code, notes, and snippets.

@brianmay
Last active September 24, 2023 04:00
Show Gist options
  • Save brianmay/d5e2bfdb7330f618a8eb424100c09a6c to your computer and use it in GitHub Desktop.
Save brianmay/d5e2bfdb7330f618a8eb424100c09a6c to your computer and use it in GitHub Desktop.
Ancient freetdm patch
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index 96fd235..142bbfd 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -1240,12 +1240,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, f
}
if (ftdmchan->token_count > 1) {
- ftdm_fsk_modulator_init(&fsk_trans, FSK_BELL202, ftdmchan->rate, fsk_data, db_level, 80, 5, 0, ftdmchan_fsk_write_sample, ftdmchan);
+ ftdm_fsk_modulator_init(&fsk_trans, ftdmchan->span->modem_type, ftdmchan->rate, fsk_data, db_level, 80, 5, 0, ftdmchan_fsk_write_sample, ftdmchan);
ftdm_fsk_modulator_send_all((&fsk_trans));
} else {
- ftdm_fsk_modulator_init(&fsk_trans, FSK_BELL202, ftdmchan->rate, fsk_data, db_level, 180, 5, 300, ftdmchan_fsk_write_sample, ftdmchan);
+ ftdm_fsk_modulator_init(&fsk_trans, ftdmchan->span->modem_type, ftdmchan->rate, fsk_data, db_level, 180, 5, 300, ftdmchan_fsk_write_sample, ftdmchan);
ftdm_fsk_modulator_send_all((&fsk_trans));
- ftdmchan->buffer_delay = 3500 / ftdmchan->effective_interval;
}
return FTDM_SUCCESS;
@@ -3839,6 +3838,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data
if (ftdm_fsk_demod_feed(&ftdmchan->fsk, sln, slen) != FTDM_SUCCESS) {
ftdm_size_t type, mlen;
char str[128], *sp;
+ char firstcaller[128] = { '*', '\0'};
while(ftdm_fsk_data_parse(&ftdmchan->fsk, &type, &sp, &mlen) == FTDM_SUCCESS) {
*(str+mlen) = '\0';
@@ -3883,9 +3883,29 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data
ftdm_set_string(ftdmchan->caller_data.cid_date, str);
}
break;
+ case MDMF_FIRST_PHONE_NUM:
+ {
+ if (mlen > sizeof(firstcaller) - 2) {
+ mlen = sizeof(firstcaller) - 2;
+ }
+ ftdm_copy_string(&firstcaller[1], str, mlen);
+ }
+ break;
}
}
ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_CALLERID_DETECT, NULL);
+ if (! ftdm_strlen_zero(&firstcaller[1])) {
+ if ((strncmp("private", ftdmchan->caller_data.ani.digits, sizeof ("private") - 1) == 0) ||
+ (strncmp("unknown", ftdmchan->caller_data.ani.digits, sizeof ("unknown") - 1) == 0)) {
+ ftdm_set_string(ftdmchan->caller_data.ani.digits, firstcaller);
+ ftdm_set_string(ftdmchan->caller_data.cid_name, "FWD ");
+ ftdm_copy_string((char *) (ftdmchan->caller_data.cid_name + 4), & firstcaller[1], strlen(& firstcaller[1]));
+ } else if ((strncmp("private", ftdmchan->caller_data.cid_name, sizeof ("private") - 1) == 0) ||
+ (strncmp("unknown", ftdmchan->caller_data.cid_name, sizeof ("unknown") - 1) == 0)) {
+ ftdm_set_string(ftdmchan->caller_data.cid_name, "FWD ");
+ ftdm_copy_string((char *) (ftdmchan->caller_data.cid_name + 4), & firstcaller[1], strlen(& firstcaller[1]));
+ }
+ }
}
}
@@ -4546,6 +4566,8 @@ static ftdm_status_t load_config(void)
if (ftdm_span_create(type, name, &span) == FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_DEBUG, "created span %d (%s) of type %s\n", span->span_id, span->name, type);
+ /* default modem type (not used for non-fsk but does not hurt either) */
+ span->modem_type = FSK_BELL202;
d = 0;
/* it is confusing that parameters from one span affect others, so let's clear them */
memset(&chan_config, 0, sizeof(chan_config));
@@ -4684,6 +4706,18 @@ static ftdm_status_t load_config(void)
}
memcpy(chan_config.group_name, val, len);
chan_config.group_name[len] = '\0';
+ } else if (!strcasecmp(var, "modem_type")) {
+ if (!strcasecmp(val, "FSK_V23_FORWARD_MODE1")) {
+ span->modem_type = FSK_V23_FORWARD_MODE1;
+ } else if (!strcasecmp(val, "FSK_V23_FORWARD_MODE2")) {
+ span->modem_type = FSK_V23_FORWARD_MODE2;
+ } else if (!strcasecmp(val, "FSK_V23_BACKWARD")) {
+ span->modem_type = FSK_V23_BACKWARD;
+ } else if (!strcasecmp(val, "FSK_BELL202")) {
+ span->modem_type = FSK_BELL202;
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "unknown modem type '%s'\n", val);
+ }
} else {
ftdm_log(FTDM_LOG_ERROR, "unknown span variable '%s'\n", var);
}
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
index 21008e6..899c6e4 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
@@ -80,8 +80,19 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CALLWAITING);
} else {
+#if 0
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_GENRING);
+#endif
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ /* we trust the thread not to proceed until we unlock the channel */
ftdm_thread_create_detached(ftdm_analog_channel_run, ftdmchan);
+
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GENRING);
+
+ ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100);
+
+ ftdm_mutex_unlock(ftdmchan->mutex);
}
return FTDM_SUCCESS;
@@ -427,6 +438,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
uint32_t answer_on_polarity_counter = 0;
ftdm_sigmsg_t sig;
ftdm_status_t status;
+ uint32_t time = 0;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "ANALOG CHANNEL thread starting.\n");
@@ -450,7 +462,9 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
}
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Initialized DTMF detection\n");
+ /* important to lock here to not proceed with the rest of this function until the thread that launched us is done with the channel */
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INTHREAD);
+
teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
ts.rate = 8000;
#if 0
@@ -508,7 +522,15 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
break;
case FTDM_CHANNEL_STATE_GENRING:
{
- if (state_counter > 60000) {
+ if (state_counter == 260) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+ } else if (state_counter == 900) {
+ send_caller_id(ftdmchan);
+ } else if (state_counter > 900 && !ftdm_buffer_inuse(ftdmchan->fsk_buffer) && time == 0) {
+ time = state_counter + 400;
+ } else if (state_counter == time) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_ON, NULL);
+ } else if (state_counter > 60000) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
} else if (!ftdmchan->fsk_buffer || !ftdm_buffer_inuse(ftdmchan->fsk_buffer)) {
ftdm_sleep(interval);
@@ -562,24 +584,13 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
{
int done = 0;
- if (ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] == 1) {
- send_caller_id(ftdmchan);
- ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
- } else if (state_counter > 600 && !ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]) {
- send_caller_id(ftdmchan);
- ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
- } else if (state_counter > 1000 && !ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]) {
- done = 1;
- } else if (state_counter > 10000) {
- if (ftdmchan->fsk_buffer) {
- ftdm_buffer_zero(ftdmchan->fsk_buffer);
- } else {
- ftdm_buffer_create(&ftdmchan->fsk_buffer, 128, 128, 0);
- }
-
+ if (state_counter == 760) {
ts.user_data = ftdmchan->fsk_buffer;
- teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_SAS]);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_CAS]);
ts.user_data = dt_buffer;
+ } else if (state_counter == 1100) {
+ send_caller_id(ftdmchan);
+ } else if (state_counter > 10000) {
done = 1;
}
@@ -748,7 +759,6 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
ts.user_data = ftdmchan->fsk_buffer;
teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_SAS]);
- teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_CAS]);
ts.user_data = dt_buffer;
}
break;
@@ -756,8 +766,8 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
{
ftdm_sigmsg_t sig;
- send_caller_id(ftdmchan);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_ON, NULL);
+ time = 0;
memset(&sig, 0, sizeof(sig));
sig.chan_id = ftdmchan->chan_id;
@@ -780,6 +790,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
ftdm_buffer_zero(dt_buffer);
teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
indicate = 1;
+ time = 0;
}
break;
diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h
index c2de07b..16d4f6e 100644
--- a/libs/freetdm/src/include/private/ftdm_core.h
+++ b/libs/freetdm/src/include/private/ftdm_core.h
@@ -472,6 +472,7 @@ struct ftdm_channel {
struct ftdm_span {
ftdm_data_type_t data_type;
+ fsk_modem_types_t modem_type;
char *name;
uint32_t span_id;
uint32_t chan_count;
diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h
index b263b64..98be4d0 100755
--- a/libs/freetdm/src/include/private/ftdm_types.h
+++ b/libs/freetdm/src/include/private/ftdm_types.h
@@ -87,9 +87,15 @@ typedef enum {
MDMF_PHONE_NAME = 7,
MDMF_NO_NAME = 8,
MDMF_ALT_ROUTE = 9,
- MDMF_INVALID = 10
+ MDMF_MESSAGE_ID = 13,
+ MDMF_LAST_VM_FROM = 14,
+ MDMF_CALL_TYPE = 17,
+ MDMF_FIRST_PHONE_NUM = 18,
+ MDMF_AMOUNT_MESSAGES = 19,
+ MDMF_FWD_TYPE = 21,
+ MDMF_INVALID = 22
} ftdm_mdmf_type_t;
-#define MDMF_STRINGS "X", "DATETIME", "PHONE_NUM", "DDN", "NO_NUM", "X", "X", "PHONE_NAME", "NO_NAME", "ALT_ROUTE", "INVALID"
+#define MDMF_STRINGS "X", "DATETIME", "PHONE_NUM", "DDN", "NO_NUM", "X", "X", "PHONE_NAME", "NO_NAME", "ALT_ROUTE", "INVALID", "X", "X", "MESSAGE_ID", "LAST_VM_FROM", "X", "X", "CALL_TYPE", "FIRST_PHONE_NUM", "AMOUNT_OF_MESSAGES", "X", "FWD_TYPE", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_mdmf_type, ftdm_mdmf_type2str, ftdm_mdmf_type_t)
#define FTDM_TONEMAP_LEN 128
diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c
index d2c142e..17520a1 100644
--- a/libs/freetdm/mod_freetdm/mod_freetdm.c
+++ b/libs/freetdm/mod_freetdm/mod_freetdm.c
@@ -2021,6 +2021,114 @@ static void ftdm_logger(const char *file, const char *func, int line, int level,
}
+static switch_status_t ftdm_send_mwi (int span_no, int chan_no, int messages)
+{
+ ftdm_span_t *span;
+ ftdm_channel_t *chan = NULL;
+ char span_name[128];
+ ftdm_status_t status = FTDM_FAIL;
+
+ sprintf(span_name, "%i", span_no);
+ ftdm_span_find_by_name(span_name, &span);
+
+ if (span == NULL) {
+ ftdm_log(FTDM_LOG_ERROR, "invalid span %d, cannot send MWI\n", span_no);
+ return FTDM_FAIL;
+ }
+
+ if ((chan = ftdm_span_get_channel(span, chan_no)) == NULL) {
+ ftdm_log(FTDM_LOG_ERROR, "invalid channel %d:%d, cannot send MWI\n", span_no, chan_no);
+ return FTDM_FAIL;
+ }
+
+ while (ftdm_channel_call_check_done(chan) != FTDM_TRUE) {
+ ftdm_sleep(2000);
+ }
+ ftdm_sleep(2000);
+
+ status = ftdm_channel_open(span_no, chan_no, &chan);
+ if (status != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "failed to open channel %d:%d to send MWI\n", span_no, chan_no);
+ return FTDM_FAIL;
+ }
+
+ status = ftdm_channel_call_place(chan);
+ if (status != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "failed to place call on channel %d:%d to send MWI\n", span_no, chan_no);
+ ftdm_channel_call_hangup(chan);
+ return FTDM_FAIL;
+ }
+
+ status = ftdm_channel_command(chan, FTDM_COMMAND_SET_MWI, &messages);
+ if (status != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "failed to send MWI command to channel %d:%d\n", span_no, chan_no);
+ ftdm_channel_call_hangup(chan);
+ return FTDM_FAIL;
+ }
+ ftdm_channel_init(chan);
+
+ return FTDM_SUCCESS;
+}
+
+static void mod_freetdm_mwi_handler(switch_event_t *event)
+{
+ char *account, *amount;
+ char *seek_ptr, *end_ptr;
+ int span_no = 0;
+ int chan_no = 0;
+ int amount_new = 0;
+ int amount_saved = 0;
+
+ switch_assert(event);
+
+ if (event->event_id == SWITCH_EVENT_MESSAGE_WAITING) {
+
+ if (!(account = switch_event_get_header(event, "mwi-message-account"))) {
+ ftdm_log(FTDM_LOG_ERROR, "Missing required Header 'MWI-Message-Account'\n");
+ return;
+ }
+
+ if (strncmp ("freetdm/", account, sizeof("freetdm/") - 1)) {
+ return;
+ }
+
+ if ((seek_ptr = strchr(account, '/')) == NULL) {
+ span_no = chan_no = 0;
+ } else if ((end_ptr = strchr (++seek_ptr, '/')) == NULL) {
+ span_no = atoi(seek_ptr);
+ chan_no = 0;
+ } else {
+ span_no = atoi(seek_ptr);
+ chan_no = atoi(++end_ptr);
+ }
+
+ if (!(amount = switch_event_get_header(event, "mwi-voice-message"))) {
+ ftdm_log(FTDM_LOG_ERROR, "Missing required Header 'mwi-voice-message'\n");
+ return;
+ }
+
+ if ((seek_ptr = strchr(amount, '/')) == NULL) {
+ amount_new = atoi(amount);
+ } else {
+ amount_new = atoi(amount);
+ amount_saved = atoi(++seek_ptr);
+ }
+
+ if (amount_new > 0) {
+ amount_new |= 0x80;
+ } else {
+ amount_new += amount_saved;
+ }
+
+ ftdm_log(FTDM_LOG_DEBUG, "Sending MWI on [%d:%d] : 0x%X\n", span_no, chan_no, amount_new);
+ ftdm_send_mwi(span_no, chan_no, amount_new);
+
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "Unexpected event %d for this handler\n", event->event_id);
+ }
+
+}
+
static uint32_t enable_analog_option(const char *str, uint32_t current_options)
{
if (!strcasecmp(str, "3-way")) {
@@ -3144,7 +3252,8 @@ void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *
switch_channel_cause2str(caller_data->hangup_cause));
}
-#define FT_SYNTAX "list || dump <span_id> [<chan_id>] || q931_pcap <span_id> on|off [pcapfilename without suffix] || gains <txgain> <rxgain> <span_id> [<chan_id>] || dtmf on|off <span_id> [<chan_id>]"
+#define FT_SYNTAX "list || dump <span_id> [<chan_id>] || q931_pcap <span_id> on|off [pcapfilename without suffix] || gains <txgain> <rxgain> <span_id> [<chan_id>] || dtmf on|off <span_id> [<chan_id>]" \
+ " || iotrace <span_id> <chan_id> in|out [filename] || mwi <span_id> <chan_id> <mwi data>"
SWITCH_STANDARD_API(ft_function)
{
char *mycmd = NULL, *argv[10] = { 0 };
@@ -3462,7 +3571,7 @@ SWITCH_STANDARD_API(ft_function)
ftdm_channel_t *fchan = NULL;
ftdm_span_t *span = NULL;
if (argc < 2) {
- stream->write_function(stream, "-ERR Usage: oz notrace <span_id> [<chan_id>]\n");
+ stream->write_function(stream, "-ERR Usage: ftdm notrace <span_id> [<chan_id>]\n");
goto end;
}
ftdm_span_find_by_name(argv[1], &span);
@@ -3497,7 +3606,7 @@ SWITCH_STANDARD_API(ft_function)
ftdm_channel_t *chan;
ftdm_span_t *span = NULL;
if (argc < 4) {
- stream->write_function(stream, "-ERR Usage: ft gains <txgain> <rxgain> <span_id> [<chan_id>]\n");
+ stream->write_function(stream, "-ERR Usage: ftdm gains <txgain> <rxgain> <span_id> [<chan_id>]\n");
goto end;
}
ftdm_span_find_by_name(argv[3], &span);
@@ -3532,6 +3641,82 @@ SWITCH_STANDARD_API(ft_function)
}
}
stream->write_function(stream, "+OK gains set to Rx %f and Tx %f\n", rxgain, txgain);
+ } else if (!strcasecmp(argv[0], "iotrace")) {
+ int32_t span_id = 0;
+ int32_t chan_id = 0;
+ ftdm_span_t *span;
+ ftdm_channel_t *chan;
+ const char *pcapfn = NULL;
+ char *tmp_path = NULL;
+ ftdm_command_t command;
+
+ if (argc < 3) {
+ stream->write_function(stream, "-ERR Usage: ftdm iotrace <span_id> <chan_id> in|out <filename>\n");
+ goto end;
+ }
+ ftdm_span_find_by_name(argv[1], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+ chan_id = atoi(argv[2]);
+ if (chan_id > ftdm_span_get_chan_count(span)) {
+ stream->write_function(stream, "-ERR invalid chan\n");
+ goto end;
+ }
+ chan = ftdm_span_get_channel(span, chan_id);
+ if (chan == NULL) {
+ stream->write_function(stream, "-ERR invalid chan\n");
+ goto end;
+ }
+
+ if (strcasecmp(argv[3], "in")) {
+ command = FTDM_COMMAND_TRACE_INPUT;
+ } else {
+ if (strcasecmp(argv[3], "out")) {
+ command = FTDM_COMMAND_TRACE_OUTPUT;
+ } else {
+ stream->write_function(stream, "-ERR invalid recording direction\n");
+ goto end;
+ }
+ }
+
+ /* Look for a given file name or use default file name */
+ if (argc > 4) {
+ if(argv[4]){
+ pcapfn=argv[4];
+ }
+ }
+ else {
+ tmp_path = switch_mprintf("%s%sftdm-%1d-%1d-%s.dmp", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, span_id, chan_id, argv[3]);
+ }
+
+ if (ftdm_channel_command(chan, command, tmp_path) != FTDM_SUCCESS) {
+ stream->write_function(stream, "-ERR\n");
+ goto end;
+ } else {
+ stream->write_function(stream, "+OK\n");
+ }
+ } else if (!strcasecmp(argv[0], "mwi")) {
+ int32_t span_id = 0;
+ int32_t chan_id = 0;
+ int32_t indicator = 0;
+
+ if (argc < 4) {
+ stream->write_function(stream, "-ERR Usage: ftdm mwi <span_id> <chan_id> <0|1>\n");
+ goto end;
+ }
+ span_id = atoi(argv[1]);
+ chan_id = atoi(argv[2]);
+ indicator = atoi(argv[3]);
+
+ ftdm_log(FTDM_LOG_DEBUG, "Sending MWI on [%d:%d] : 0x%X\n", span_id, chan_id, indicator);
+
+ if (ftdm_send_mwi(span_id, chan_id, indicator) == FTDM_SUCCESS) {
+ stream->write_function(stream, "+OK\n");
+ } else {
+ stream->write_function(stream, "-ERR\n");
+ }
} else {
char *rply = ftdm_api_execute(cmd);
@@ -3646,6 +3831,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load)
freetdm_endpoint_interface->io_routines = &freetdm_io_routines;
freetdm_endpoint_interface->state_handler = &freetdm_state_handlers;
+ if (switch_event_bind(freetdm_endpoint_interface->interface_name, SWITCH_EVENT_MESSAGE_WAITING, SWITCH_EVENT_SUBCLASS_ANY, mod_freetdm_mwi_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error binding MWI to OpenZAP\n");
+ }
+
SWITCH_ADD_API(commands_api_interface, "ftdm", "FreeTDM commands", ft_function, FT_SYNTAX);
SWITCH_ADD_APP(app_interface, "disable_ec", "Disable Echo Canceller", "Disable Echo Canceller", disable_ec_function, "", SAF_NONE);
@@ -3669,6 +3858,8 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_freetdm_shutdown)
ftdm_conf_node_destroy(val);
}
+ switch_event_unbind_callback(mod_freetdm_mwi_handler);
+
ftdm_global_destroy();
// this breaks pika but they are MIA so *shrug*
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index c0e26de..323363c 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -930,12 +930,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, f
}
if (ftdmchan->token_count > 1) {
- ftdm_fsk_modulator_init(&fsk_trans, FSK_BELL202, ftdmchan->rate, fsk_data, db_level, 80, 5, 0, ftdmchan_fsk_write_sample, ftdmchan);
+ ftdm_fsk_modulator_init(&fsk_trans, ftdmchan->span->modem_type, ftdmchan->rate, fsk_data, db_level, 80, 5, 0, ftdmchan_fsk_write_sample, ftdmchan);
ftdm_fsk_modulator_send_all((&fsk_trans));
} else {
- ftdm_fsk_modulator_init(&fsk_trans, FSK_BELL202, ftdmchan->rate, fsk_data, db_level, 180, 5, 300, ftdmchan_fsk_write_sample, ftdmchan);
+ ftdm_fsk_modulator_init(&fsk_trans, ftdmchan->span->modem_type, ftdmchan->rate, fsk_data, db_level, 180, 5, 300, ftdmchan_fsk_write_sample, ftdmchan);
ftdm_fsk_modulator_send_all((&fsk_trans));
- ftdmchan->buffer_delay = 3500 / ftdmchan->effective_interval;
}
return FTDM_SUCCESS;
@@ -1230,6 +1229,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *f
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_GET_CALLERID:
case FTDM_CHANNEL_STATE_GENRING:
+ case FTDM_CHANNEL_STATE_MWI:
ok = 1;
break;
default:
@@ -2499,6 +2499,15 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
GOTO_STATUS(done, FTDM_SUCCESS);
}
break;
+ case FTDM_COMMAND_SET_MWI:
+ {
+ ftdmchan->pre_buffer_size = FTDM_COMMAND_OBJ_INT;
+
+ status = ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, ftdmchan, FTDM_CHANNEL_STATE_MWI, 1);
+
+ GOTO_STATUS(done, status);
+ }
+ break;
default:
break;
}
@@ -2523,21 +2532,22 @@ done:
FT_DECLARE(ftdm_status_t) ftdm_channel_wait(ftdm_channel_t *ftdmchan, ftdm_wait_flag_t *flags, int32_t to)
{
- assert(ftdmchan != NULL);
- assert(ftdmchan->fio != NULL);
+ ftdm_assert_return(ftdmchan != NULL, FTDM_EINVAL, "chan is null\n");
+ ftdm_assert_return(ftdmchan->fio != NULL, FTDM_EINVAL, "no I/O attached to channel\n");
- if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "channel not open\n");
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open");
- return FTDM_FAIL;
- }
+ return FTDM_FAIL;
+ }
if (!ftdmchan->fio->wait) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "wait method not implemented\n");
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
return FTDM_FAIL;
}
- return ftdmchan->fio->wait(ftdmchan, flags, to);
-
+ return ftdmchan->fio->wait(ftdmchan, flags, to);
}
/*******************************/
@@ -2983,6 +2993,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data
if (ftdm_fsk_demod_feed(&ftdmchan->fsk, sln, slen) != FTDM_SUCCESS) {
ftdm_size_t type, mlen;
char str[128], *sp;
+ char firstcaller[128] = { '*', '\0'};
while(ftdm_fsk_data_parse(&ftdmchan->fsk, &type, &sp, &mlen) == FTDM_SUCCESS) {
*(str+mlen) = '\0';
@@ -3027,9 +3038,29 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data
ftdm_set_string(ftdmchan->caller_data.cid_date, str);
}
break;
+ case MDMF_FIRST_PHONE_NUM:
+ {
+ if (mlen > sizeof(firstcaller) - 2) {
+ mlen = sizeof(firstcaller) - 2;
+ }
+ ftdm_copy_string(&firstcaller[1], str, mlen);
+ }
+ break;
}
}
ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_CALLERID_DETECT, NULL);
+ if (! ftdm_strlen_zero(&firstcaller[1])) {
+ if ((strncmp("private", ftdmchan->caller_data.ani.digits, sizeof ("private") - 1) == 0) ||
+ (strncmp("unknown", ftdmchan->caller_data.ani.digits, sizeof ("unknown") - 1) == 0)) {
+ ftdm_set_string(ftdmchan->caller_data.ani.digits, firstcaller);
+ ftdm_set_string(ftdmchan->caller_data.cid_name, "FWD ");
+ ftdm_copy_string((char *) (ftdmchan->caller_data.cid_name + 4), & firstcaller[1], strlen(& firstcaller[1]));
+ } else if ((strncmp("private", ftdmchan->caller_data.cid_name, sizeof ("private") - 1) == 0) ||
+ (strncmp("unknown", ftdmchan->caller_data.cid_name, sizeof ("unknown") - 1) == 0)) {
+ ftdm_set_string(ftdmchan->caller_data.cid_name, "FWD ");
+ ftdm_copy_string((char *) (ftdmchan->caller_data.cid_name + 4), & firstcaller[1], strlen(& firstcaller[1]));
+ }
+ }
}
}
@@ -3399,6 +3430,8 @@ static ftdm_status_t load_config(void)
if (ftdm_span_create(type, name, &span) == FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_DEBUG, "created span %d (%s) of type %s\n", span->span_id, span->name, type);
+ /* default modem type (not used for non-fsk but does not hurt either) */
+ span->modem_type = FSK_BELL202;
d = 0;
} else {
ftdm_log(FTDM_LOG_CRIT, "failure creating span of type %s\n", type);
@@ -3531,6 +3564,18 @@ static ftdm_status_t load_config(void)
}
memcpy(chan_config.group_name, val, len);
chan_config.group_name[len] = '\0';
+ } else if (!strcasecmp(var, "modem_type")) {
+ if (!strcasecmp(val, "FSK_V23_FORWARD_MODE1")) {
+ span->modem_type = FSK_V23_FORWARD_MODE1;
+ } else if (!strcasecmp(val, "FSK_V23_FORWARD_MODE2")) {
+ span->modem_type = FSK_V23_FORWARD_MODE2;
+ } else if (!strcasecmp(val, "FSK_V23_BACKWARD")) {
+ span->modem_type = FSK_V23_BACKWARD;
+ } else if (!strcasecmp(val, "FSK_BELL202")) {
+ span->modem_type = FSK_BELL202;
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "unknown modem type '%s'\n", val);
+ }
} else {
ftdm_log(FTDM_LOG_ERROR, "unknown span variable '%s'\n", var);
}
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
index 2863dc1..af2349c 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
@@ -77,8 +77,19 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CALLWAITING);
} else {
+#if 0
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_GENRING);
+#endif
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ /* we trust the thread not to proceed until we unlock the channel */
ftdm_thread_create_detached(ftdm_analog_channel_run, ftdmchan);
+
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GENRING);
+
+ ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100);
+
+ ftdm_mutex_unlock(ftdmchan->mutex);
}
return FTDM_SUCCESS;
@@ -325,6 +336,52 @@ static void send_caller_id(ftdm_channel_t *ftdmchan)
}
/**
+ * \brief Sends message wainting indicator on an analog channel (FSK coded)
+ * \param ftdmchan Channel to send caller id on
+ * \param state indicator value as follows : if bit 0x80 is set, light on indicator - bits 0x7F : amount of messages waiting
+ */
+static void send_mwi(ftdm_channel_t *ftdmchan, int state)
+{
+ ftdm_fsk_data_state_t fsk_data;
+ uint8_t databuf[1024] = "";
+ char time_str[9];
+ struct tm tm;
+ time_t now;
+ char indicator;
+ char amount_messages;
+
+ time(&now);
+#ifdef WIN32
+ _tzset();
+ _localtime64_s(&tm, &now);
+#else
+ localtime_r(&now, &tm);
+#endif
+ strftime(time_str, sizeof(time_str), "%m%d%H%M", &tm);
+
+ ftdm_fsk_data_init(&fsk_data, databuf, sizeof(databuf));
+ ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_DATETIME, (uint8_t *) time_str, 8);
+
+ if (state & 0x80) {
+ indicator = 0xFF;
+ amount_messages = state & 0x7F;
+ } else {
+ indicator = 0;
+ amount_messages = state;
+ }
+
+ ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_MWI, (uint8_t *) & indicator, (uint8_t) sizeof (indicator));
+
+ ftdm_fsk_data_add_mdmf(&fsk_data, MDMF_AMOUNT_MESSAGES, (uint8_t *) & amount_messages, (uint8_t) sizeof (amount_messages));
+
+ fsk_data.buf[0] = FTDM_CID_TYPE_MWI;
+
+ ftdm_fsk_data_add_checksum(&fsk_data);
+
+ ftdm_channel_send_fsk_data(ftdmchan, &fsk_data, -14);
+}
+
+/**
* \brief Main thread function for analog channel (outgoing call)
* \param me Current thread
* \param obj Channel to run in this thread
@@ -344,6 +401,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
ftdm_sigmsg_t sig;
ftdm_status_t status;
+ uint32_t time = 0;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "ANALOG CHANNEL thread starting.\n");
@@ -366,7 +424,9 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
goto done;
}
+ /* important to lock here to not proceed with the rest of this function until the thread that launched us is done with the channel */
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INTHREAD);
+
teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
ts.rate = 8000;
#if 0
@@ -381,7 +441,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
- assert(interval != 0);
+ ftdm_assert(interval != 0, "invalid interval");
while (ftdm_running() && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
ftdm_wait_flag_t flags = FTDM_READ;
@@ -415,7 +475,15 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
break;
case FTDM_CHANNEL_STATE_GENRING:
{
- if (state_counter > 60000) {
+ if (state_counter == 260) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+ } else if (state_counter == 900) {
+ send_caller_id(ftdmchan);
+ } else if (state_counter > 900 && !ftdm_buffer_inuse(ftdmchan->fsk_buffer) && time == 0) {
+ time = state_counter + 400;
+ } else if (state_counter == time) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_ON, NULL);
+ } else if (state_counter > 60000) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
} else if (!ftdmchan->fsk_buffer || !ftdm_buffer_inuse(ftdmchan->fsk_buffer)) {
ftdm_sleep(interval);
@@ -423,6 +491,18 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
}
}
break;
+ case FTDM_CHANNEL_STATE_MWI:
+ {
+ if (state_counter == 400) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+ } else if (state_counter == 1100) {
+ send_mwi(ftdmchan, ftdmchan->pre_buffer_size);
+ } else if (state_counter > 1200 && !ftdm_buffer_inuse(ftdmchan->fsk_buffer)) {
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ continue;
+ }
+ }
+ break;
case FTDM_CHANNEL_STATE_DIALTONE:
{
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_HOLD) && state_counter > 10000) {
@@ -466,24 +546,13 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
{
int done = 0;
- if (ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] == 1) {
- send_caller_id(ftdmchan);
- ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
- } else if (state_counter > 600 && !ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]) {
- send_caller_id(ftdmchan);
- ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
- } else if (state_counter > 1000 && !ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]) {
- done = 1;
- } else if (state_counter > 10000) {
- if (ftdmchan->fsk_buffer) {
- ftdm_buffer_zero(ftdmchan->fsk_buffer);
- } else {
- ftdm_buffer_create(&ftdmchan->fsk_buffer, 128, 128, 0);
- }
-
+ if (state_counter == 760) {
ts.user_data = ftdmchan->fsk_buffer;
- teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_SAS]);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_CAS]);
ts.user_data = dt_buffer;
+ } else if (state_counter == 1100) {
+ send_caller_id(ftdmchan);
+ } else if (state_counter > 10000) {
done = 1;
}
@@ -602,7 +671,6 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
ts.user_data = ftdmchan->fsk_buffer;
teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_SAS]);
- teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_CAS]);
ts.user_data = dt_buffer;
}
break;
@@ -610,8 +678,8 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
{
ftdm_sigmsg_t sig;
- send_caller_id(ftdmchan);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_ON, NULL);
+ time = 0;
memset(&sig, 0, sizeof(sig));
sig.chan_id = ftdmchan->chan_id;
@@ -622,6 +690,17 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
}
break;
+ case FTDM_CHANNEL_STATE_MWI:
+ {
+ if (ftdmchan->fsk_buffer) {
+ ftdm_buffer_zero(ftdmchan->fsk_buffer);
+ } else {
+ ftdm_buffer_create(&ftdmchan->fsk_buffer, 128, 128, 0);
+ }
+
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_ON, NULL);
+ }
+ break;
case FTDM_CHANNEL_STATE_GET_CALLERID:
{
memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
@@ -741,6 +820,8 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "No Digits to send!\n");
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
} else {
+ /* I seem to have some trouble when dialing as soon as dialtone is detected */
+ ftdm_sleep(400);
if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_SEND_DTMF, ftdmchan->caller_data.dnis.digits) != FTDM_SUCCESS) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Send Digits Failed [%s]\n", ftdmchan->last_error);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h
index b1fea4a..61d500b 100644
--- a/libs/freetdm/src/include/freetdm.h
+++ b/libs/freetdm/src/include/freetdm.h
@@ -424,7 +424,8 @@ typedef enum {
FTDM_COMMAND_GET_LINK_STATUS,
FTDM_COMMAND_ENABLE_LOOP,
FTDM_COMMAND_DISABLE_LOOP,
- FTDM_COMMAND_COUNT
+ FTDM_COMMAND_SET_MWI,
+ FTDM_COMMAND_COUNT,
} ftdm_command_t;
/*! \brief Custom memory handler hooks. Not recommended to use unless you need memory allocation customizations */
diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h
index 53e8cd5..980d6ee 100644
--- a/libs/freetdm/src/include/private/ftdm_core.h
+++ b/libs/freetdm/src/include/private/ftdm_core.h
@@ -412,6 +412,7 @@ struct ftdm_channel {
struct ftdm_span {
ftdm_data_type_t data_type;
+ fsk_modem_types_t modem_type;
char *name;
uint32_t span_id;
uint32_t chan_count;
diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h
index 6f77859..64be6c2 100644
--- a/libs/freetdm/src/include/private/ftdm_types.h
+++ b/libs/freetdm/src/include/private/ftdm_types.h
@@ -77,7 +77,8 @@ typedef enum {
typedef enum {
FTDM_CID_TYPE_SDMF = 0x04,
- FTDM_CID_TYPE_MDMF = 0x80
+ FTDM_CID_TYPE_MDMF = 0x80,
+ FTDM_CID_TYPE_MWI = 0x82
} ftdm_cid_type_t;
typedef enum {
@@ -88,9 +89,16 @@ typedef enum {
MDMF_PHONE_NAME = 7,
MDMF_NO_NAME = 8,
MDMF_ALT_ROUTE = 9,
- MDMF_INVALID = 10
+ MDMF_MWI = 11,
+ MDMF_MESSAGE_ID = 13,
+ MDMF_LAST_VM_FROM = 14,
+ MDMF_CALL_TYPE = 17,
+ MDMF_FIRST_PHONE_NUM = 18,
+ MDMF_AMOUNT_MESSAGES = 19,
+ MDMF_FWD_TYPE = 21,
+ MDMF_INVALID = 22
} ftdm_mdmf_type_t;
-#define MDMF_STRINGS "X", "DATETIME", "PHONE_NUM", "DDN", "NO_NUM", "X", "X", "PHONE_NAME", "NO_NAME", "ALT_ROUTE", "INVALID"
+#define MDMF_STRINGS "X", "DATETIME", "PHONE_NUM", "DDN", "NO_NUM", "X", "X", "PHONE_NAME", "NO_NAME", "ALT_ROUTE", "X", "MWI", "X", "MESSAGE_ID", "LAST_VM_FROM", "X", "X", "CALL_TYPE", "FIRST_PHONE_NUM", "AMOUNT_OF_MESSAGES", "X", "FWD_TYPE", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_mdmf_type, ftdm_mdmf_type2str, ftdm_mdmf_type_t)
#define FTDM_TONEMAP_LEN 128
@@ -192,12 +200,13 @@ typedef enum {
FTDM_CHANNEL_STATE_HANGUP,
FTDM_CHANNEL_STATE_HANGUP_COMPLETE,
FTDM_CHANNEL_STATE_IN_LOOP,
+ FTDM_CHANNEL_STATE_MWI,
FTDM_CHANNEL_STATE_INVALID
} ftdm_channel_state_t;
#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
"RING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
"RESTART", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \
- "HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "INVALID"
+ "HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "MWI", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t)
typedef enum {
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index b275403..2f030be 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -968,12 +968,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, f
}
if (ftdmchan->token_count > 1) {
- ftdm_fsk_modulator_init(&fsk_trans, FSK_BELL202, ftdmchan->rate, fsk_data, db_level, 80, 5, 0, ftdmchan_fsk_write_sample, ftdmchan);
+ ftdm_fsk_modulator_init(&fsk_trans, ftdmchan->span->modem_type, ftdmchan->rate, fsk_data, db_level, 80, 5, 0, ftdmchan_fsk_write_sample, ftdmchan);
ftdm_fsk_modulator_send_all((&fsk_trans));
} else {
- ftdm_fsk_modulator_init(&fsk_trans, FSK_BELL202, ftdmchan->rate, fsk_data, db_level, 180, 5, 300, ftdmchan_fsk_write_sample, ftdmchan);
+ ftdm_fsk_modulator_init(&fsk_trans, ftdmchan->span->modem_type, ftdmchan->rate, fsk_data, db_level, 180, 5, 300, ftdmchan_fsk_write_sample, ftdmchan);
ftdm_fsk_modulator_send_all((&fsk_trans));
- ftdmchan->buffer_delay = 3500 / ftdmchan->effective_interval;
}
return FTDM_SUCCESS;
@@ -2712,21 +2721,22 @@ done:
FT_DECLARE(ftdm_status_t) ftdm_channel_wait(ftdm_channel_t *ftdmchan, ftdm_wait_flag_t *flags, int32_t to)
{
- assert(ftdmchan != NULL);
- assert(ftdmchan->fio != NULL);
+ ftdm_assert_return(ftdmchan != NULL, FTDM_EINVAL, "chan is null\n");
+ ftdm_assert_return(ftdmchan->fio != NULL, FTDM_EINVAL, "no I/O attached to channel\n");
- if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "channel not open\n");
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open");
- return FTDM_FAIL;
- }
+ return FTDM_FAIL;
+ }
if (!ftdmchan->fio->wait) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "wait method not implemented\n");
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
return FTDM_FAIL;
}
- return ftdmchan->fio->wait(ftdmchan, flags, to);
-
+ return ftdmchan->fio->wait(ftdmchan, flags, to);
}
/*******************************/
@@ -3281,6 +3291,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data
if (ftdm_fsk_demod_feed(&ftdmchan->fsk, sln, slen) != FTDM_SUCCESS) {
ftdm_size_t type, mlen;
char str[128], *sp;
+ char firstcaller[128] = { '*', '\0'};
while(ftdm_fsk_data_parse(&ftdmchan->fsk, &type, &sp, &mlen) == FTDM_SUCCESS) {
*(str+mlen) = '\0';
@@ -3325,9 +3336,29 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data
ftdm_set_string(ftdmchan->caller_data.cid_date, str);
}
break;
+ case MDMF_FIRST_PHONE_NUM:
+ {
+ if (mlen > sizeof(firstcaller) - 2) {
+ mlen = sizeof(firstcaller) - 2;
+ }
+ ftdm_copy_string(&firstcaller[1], str, mlen);
+ }
+ break;
}
}
ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_CALLERID_DETECT, NULL);
+ if (! ftdm_strlen_zero(&firstcaller[1])) {
+ if ((strncmp("private", ftdmchan->caller_data.ani.digits, sizeof ("private") - 1) == 0) ||
+ (strncmp("unknown", ftdmchan->caller_data.ani.digits, sizeof ("unknown") - 1) == 0)) {
+ ftdm_set_string(ftdmchan->caller_data.ani.digits, firstcaller);
+ ftdm_set_string(ftdmchan->caller_data.cid_name, "FWD ");
+ ftdm_copy_string((char *) (ftdmchan->caller_data.cid_name + 4), & firstcaller[1], strlen(& firstcaller[1]));
+ } else if ((strncmp("private", ftdmchan->caller_data.cid_name, sizeof ("private") - 1) == 0) ||
+ (strncmp("unknown", ftdmchan->caller_data.cid_name, sizeof ("unknown") - 1) == 0)) {
+ ftdm_set_string(ftdmchan->caller_data.cid_name, "FWD ");
+ ftdm_copy_string((char *) (ftdmchan->caller_data.cid_name + 4), & firstcaller[1], strlen(& firstcaller[1]));
+ }
+ }
}
}
@@ -3748,6 +3779,8 @@ static ftdm_status_t load_config(void)
if (ftdm_span_create(type, name, &span) == FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_DEBUG, "created span %d (%s) of type %s\n", span->span_id, span->name, type);
+ /* default modem type (not used for non-fsk but does not hurt either) */
+ span->modem_type = FSK_BELL202;
d = 0;
} else {
ftdm_log(FTDM_LOG_CRIT, "failure creating span of type %s\n", type);
@@ -3880,6 +3913,18 @@ static ftdm_status_t load_config(void)
}
memcpy(chan_config.group_name, val, len);
chan_config.group_name[len] = '\0';
+ } else if (!strcasecmp(var, "modem_type")) {
+ if (!strcasecmp(val, "FSK_V23_FORWARD_MODE1")) {
+ span->modem_type = FSK_V23_FORWARD_MODE1;
+ } else if (!strcasecmp(val, "FSK_V23_FORWARD_MODE2")) {
+ span->modem_type = FSK_V23_FORWARD_MODE2;
+ } else if (!strcasecmp(val, "FSK_V23_BACKWARD")) {
+ span->modem_type = FSK_V23_BACKWARD;
+ } else if (!strcasecmp(val, "FSK_BELL202")) {
+ span->modem_type = FSK_BELL202;
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "unknown modem type '%s'\n", val);
+ }
} else {
ftdm_log(FTDM_LOG_ERROR, "unknown span variable '%s'\n", var);
}
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
index 4dce190..7e53f5c 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
@@ -77,8 +77,19 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CALLWAITING);
} else {
+#if 0
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_GENRING);
+#endif
+ ftdm_mutex_lock(ftdmchan->mutex);
+
+ /* we trust the thread not to proceed until we unlock the channel */
ftdm_thread_create_detached(ftdm_analog_channel_run, ftdmchan);
+
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GENRING);
+
+ ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100);
+
+ ftdm_mutex_unlock(ftdmchan->mutex);
}
return FTDM_SUCCESS;
@@ -345,6 +402,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
ftdm_sigmsg_t sig;
ftdm_status_t status;
+ uint32_t time = 0;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "ANALOG CHANNEL thread starting.\n");
@@ -368,7 +427,9 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
}
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Initialized DTMF detection\n");
+ /* important to lock here to not proceed with the rest of this function until the thread that launched us is done with the channel */
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INTHREAD);
+
teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
ts.rate = 8000;
#if 0
@@ -383,7 +444,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
- assert(interval != 0);
+ ftdm_assert(interval != 0, "invalid interval");
while (ftdm_running() && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
ftdm_wait_flag_t flags = FTDM_READ;
@@ -417,7 +478,15 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
break;
case FTDM_CHANNEL_STATE_GENRING:
{
- if (state_counter > 60000) {
+ if (state_counter == 260) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
+ } else if (state_counter == 900) {
+ send_caller_id(ftdmchan);
+ } else if (state_counter > 900 && !ftdm_buffer_inuse(ftdmchan->fsk_buffer) && time == 0) {
+ time = state_counter + 400;
+ } else if (state_counter == time) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_ON, NULL);
+ } else if (state_counter > 60000) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
} else if (!ftdmchan->fsk_buffer || !ftdm_buffer_inuse(ftdmchan->fsk_buffer)) {
ftdm_sleep(interval);
@@ -468,24 +549,13 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
{
int done = 0;
- if (ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] == 1) {
- send_caller_id(ftdmchan);
- ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
- } else if (state_counter > 600 && !ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]) {
- send_caller_id(ftdmchan);
- ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]++;
- } else if (state_counter > 1000 && !ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK]) {
- done = 1;
- } else if (state_counter > 10000) {
- if (ftdmchan->fsk_buffer) {
- ftdm_buffer_zero(ftdmchan->fsk_buffer);
- } else {
- ftdm_buffer_create(&ftdmchan->fsk_buffer, 128, 128, 0);
- }
-
+ if (state_counter == 760) {
ts.user_data = ftdmchan->fsk_buffer;
- teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_SAS]);
+ teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_CAS]);
ts.user_data = dt_buffer;
+ } else if (state_counter == 1100) {
+ send_caller_id(ftdmchan);
+ } else if (state_counter > 10000) {
done = 1;
}
@@ -604,7 +693,6 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
ts.user_data = ftdmchan->fsk_buffer;
teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_SAS]);
- teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_CALLWAITING_CAS]);
ts.user_data = dt_buffer;
}
break;
@@ -612,8 +700,8 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
{
ftdm_sigmsg_t sig;
- send_caller_id(ftdmchan);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_ON, NULL);
+ time = 0;
memset(&sig, 0, sizeof(sig));
sig.chan_id = ftdmchan->chan_id;
@@ -636,6 +735,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
ftdm_buffer_zero(dt_buffer);
teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
indicate = 1;
+ time = 0;
}
break;
@@ -734,6 +835,8 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "No Digits to send!\n");
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
} else {
+ /* I seem to have some trouble when dialing as soon as dialtone is detected */
+ ftdm_sleep(400);
if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_SEND_DTMF, ftdmchan->caller_data.dnis.digits) != FTDM_SUCCESS) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Send Digits Failed [%s]\n", ftdmchan->last_error);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h
index 74bea81..39c9604 100644
--- a/libs/freetdm/src/include/private/ftdm_core.h
+++ b/libs/freetdm/src/include/private/ftdm_core.h
@@ -432,6 +432,7 @@ struct ftdm_channel {
struct ftdm_span {
ftdm_data_type_t data_type;
+ fsk_modem_types_t modem_type;
char *name;
uint32_t span_id;
uint32_t chan_count;
diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h
index d8e8b5c..4edb501 100644
--- a/libs/freetdm/src/include/private/ftdm_types.h
+++ b/libs/freetdm/src/include/private/ftdm_types.h
@@ -88,9 +89,15 @@ typedef enum {
MDMF_PHONE_NAME = 7,
MDMF_NO_NAME = 8,
MDMF_ALT_ROUTE = 9,
- MDMF_INVALID = 10
+ MDMF_MESSAGE_ID = 13,
+ MDMF_LAST_VM_FROM = 14,
+ MDMF_CALL_TYPE = 17,
+ MDMF_FIRST_PHONE_NUM = 18,
+ MDMF_AMOUNT_MESSAGES = 19,
+ MDMF_FWD_TYPE = 21,
+ MDMF_INVALID = 22
} ftdm_mdmf_type_t;
-#define MDMF_STRINGS "X", "DATETIME", "PHONE_NUM", "DDN", "NO_NUM", "X", "X", "PHONE_NAME", "NO_NAME", "ALT_ROUTE", "INVALID"
+#define MDMF_STRINGS "X", "DATETIME", "PHONE_NUM", "DDN", "NO_NUM", "X", "X", "PHONE_NAME", "NO_NAME", "ALT_ROUTE", "INVALID", "X", "X", "MESSAGE_ID", "LAST_VM_FROM", "X", "X", "CALL_TYPE", "FIRST_PHONE_NUM", "AMOUNT_OF_MESSAGES", "X", "FWD_TYPE", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_mdmf_type, ftdm_mdmf_type2str, ftdm_mdmf_type_t)
#define FTDM_TONEMAP_LEN 128
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment