Last active
September 24, 2023 04:00
-
-
Save brianmay/d5e2bfdb7330f618a8eb424100c09a6c to your computer and use it in GitHub Desktop.
Ancient freetdm patch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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