Add T31 modem support to mod_spandsp - similar to iaxmodem only wired into FS. Also merge configs into single spandsp.conf.xml --see in tree example--

This commit is contained in:
Anthony Minessale 2011-12-06 17:51:27 -06:00
parent 0ed06ad710
commit d91f67d0e3
10 changed files with 1848 additions and 301 deletions

View File

@ -1,4 +1,39 @@
<configuration name="spandsp.conf" description="Tone detector descriptors">
<configuration name="spandsp.conf" description="SpanDSP config">
<modem-settings>
<!--
total-modems set to N will create that many soft-modems.
If you use them with Hylafax you need the following for each one numbered 0..N:
1) A line like this in /etc/inittab:
f0:2345:respawn:/usr/lib/fax/faxgetty /dev/FS0
2) copy conf/config.FS0 to /var/spool/hylafax/etc (or wherver the appropriate dir is on your system)
Subsequent modem configs would incrment the 0 to 1 and so on.
-->
<param name="total-modems" value="1"/>
<!-- Default context and dialplan to use on inbound calls from the modems -->
<param name="context" value="default"/>
<param name="dialplan" value="XML"/>
<!-- Extra tracing for debugging -->
<param name="verbose" value="false"/>
</modem-settings>
<fax-settings>
<param name="use-ecm" value="true"/>
<param name="verbose" value="false"/>
<param name="disable-v17" value="false"/>
<param name="ident" value="SpanDSP Fax Ident"/>
<param name="header" value="SpanDSP Fax Header"/>
<param name="spool-dir" value="/tmp"/>
<param name="file-prefix" value="faxrx"/>
</fax-settings>
<descriptors>
<!-- These tones are defined in Annex to ITU Operational Bulletin No. 781 - 1.II.2003 -->

78
conf/config.FS0 Normal file
View File

@ -0,0 +1,78 @@
CountryCode: 1
AreaCode: 800
FAXNumber: +1.800.555.1212
LongDistancePrefix: 1
InternationalPrefix: 011
DialStringRules: etc/dialrules
ServerTracing: 0xFFF
SessionTracing: 0xFFF
RecvFileMode: 0600
LogFileMode: 0600
DeviceMode: 0600
RingsBeforeAnswer: 1
SpeakerVolume: off
GettyArgs: "-h %l dx_%s"
LocalIdentifier: "FS"
TagLineFont: etc/lutRS18.pcf
TagLineFormat: "From %%l|%c|Page %%P of %%T"
MaxRecvPages: 200
#
#
# Modem-related stuff: should reflect modem command interface
# and hardware connection/cabling (e.g. flow control).
#
ModemType: Class1 # use this to supply a hint
#
# Enabling this will use the hfaxd-protocol to set Caller*ID
#
#ModemSetOriginCmd: AT+VSID="%s","%d"
#
# If "glare" during initialization becomes a problem then take
# the modem off-hook during initialization, and then place it
# back on-hook when done.
#
#ModemResetCmds: "ATH1\nAT+VCID=1" # enables CallID display
#ModemReadyCmds: ATH0
Class1AdaptRecvCmd: AT+FAR=1
Class1TMConnectDelay: 400 # counteract quick CONNECT response
#
# If you have trouble with V.17 receiving or sending,
# you may want to enable one of these, respectively.
#
#Class1RMQueryCmd: "!24,48,72,96" # enable this to disable V.17 receiving
#Class1TMQueryCmd: "!24,48,72,96" # enable this to disable V.17 sending
#
# You'll likely want Caller*ID display (also displays DID) enabled.
#
ModemResetCmds: AT+VCID=1 # enables CallID display
#
# The pty does not support changing parity.
#
PagerTTYParity: none
#
# If you are "missing" Caller*ID data on some calls (but not all)
# and if you do not have adequate glare protection you may want to
# not answer based on RINGs, but rather enable the CallIDAnswerLength
# for NDID, disable AT+VCID=1 and do this:
#
#RingsBeforeAnswer: 0
#ModemRingResponse: AT+VRID=1
# Uncomment DATE and TIME if you really want them, but you probably don't.
#CallIDPattern: "DATE="
#CallIDPattern: "TIME="
CallIDPattern: "NMBR="
CallIDPattern: "NAME="
CallIDPattern: "ANID="
#CallIDPattern: "USER=" # username provided by call
#CallIDPattern: "PASS=" # password provided by call
#CallIDPattern: "CDID=" # DID context in call
CallIDPattern: "NDID="
#CallIDAnswerLength: 4

View File

@ -483,7 +483,7 @@ AC_PROG_GCC_TRADITIONAL
AC_FUNC_MALLOC
AC_TYPE_SIGNAL
AC_FUNC_STRFTIME
AC_CHECK_FUNCS([gethostname vasprintf mmap mlock mlockall usleep getifaddrs timerfd_create getdtablesize])
AC_CHECK_FUNCS([gethostname vasprintf mmap mlock mlockall usleep getifaddrs timerfd_create getdtablesize posix_openpt])
AC_CHECK_FUNCS([sched_setscheduler setpriority setrlimit setgroups initgroups])
AC_CHECK_FUNCS([wcsncmp setgroups asprintf setenv pselect gettimeofday localtime_r gmtime_r strcasecmp stricmp _stricmp])
@ -494,6 +494,9 @@ AC_CHECK_LIB(rt, clock_getres, [AC_DEFINE(HAVE_CLOCK_GETRES, 1, [Define if you h
AC_CHECK_LIB(rt, clock_nanosleep, [AC_DEFINE(HAVE_CLOCK_NANOSLEEP, 1, [Define if you have clock_nanosleep()])])
AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket))
AC_CHECK_FILE(/dev/ptmx, [AC_DEFINE(HAVE_DEV_PTMX, 1, [Define if you have /dev/ptmx])])
AC_CHECK_LIB(util, openpty, [AC_DEFINE(HAVE_OPENPTY, 1, [Define if you have openpty()])])
AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,[
#include <sys/types.h>
#include <time.h>])

View File

@ -4,15 +4,15 @@ MODNAME=mod_spandsp
TIFF_DIR=$(switch_srcdir)/libs/tiff-3.8.2
TIFF_BUILDDIR=$(switch_builddir)/libs/tiff-3.8.2
TIFF_LA=$(TIFF_BUILDDIR)/libtiff/libtiff.la
BUILD_CFLAGS=
SPANDSP_DIR=$(switch_srcdir)/libs/spandsp
SPANDSP_BUILDDIR=$(switch_builddir)/libs/spandsp
SPANDSP_LA=$(SPANDSP_BUILDDIR)/src/libspandsp.la
mod_LTLIBRARIES = mod_spandsp.la
mod_spandsp_la_SOURCES = mod_spandsp.c udptl.c mod_spandsp_fax.c mod_spandsp_dsp.c mod_spandsp_codecs.c
mod_spandsp_la_CFLAGS = $(AM_CFLAGS) -I$(SPANDSP_DIR)/src -I$(TIFF_DIR)/libtiff -I$(SPANDSP_BUILDDIR)/src -I$(TIFF_BUILDDIR)/libtiff -I.
mod_spandsp_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(SPANDSP_LA) $(TIFF_LA) -ljpeg -lz
mod_spandsp_la_SOURCES = mod_spandsp.c udptl.c mod_spandsp_fax.c mod_spandsp_dsp.c mod_spandsp_codecs.c mod_spandsp_modem.c
mod_spandsp_la_CFLAGS = $(BUILD_CFLAGS) $(AM_CFLAGS) -I$(SPANDSP_DIR)/src -I$(TIFF_DIR)/libtiff -I$(SPANDSP_BUILDDIR)/src -I$(TIFF_BUILDDIR)/libtiff -I.
mod_spandsp_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(SPANDSP_LA) $(TIFF_LA) -ljpeg -lz -lutil
mod_spandsp_la_LDFLAGS = -avoid-version -module -no-undefined -shared
$(SPANDSP_LA): $(TIFF_LA) $(SPANDSP_DIR) $(SPANDSP_DIR)/.update

View File

@ -36,11 +36,14 @@
#include "mod_spandsp.h"
#include <spandsp/version.h>
#include "mod_spandsp_modem.h"
/* **************************************************************************
FREESWITCH MODULE DEFINITIONS
************************************************************************* */
struct spandsp_globals spandsp_globals = { 0 };
#define SPANFAX_RX_USAGE "<filename>"
#define SPANFAX_TX_USAGE "<filename>"
@ -116,10 +119,9 @@ SWITCH_STANDARD_APP(spandsp_stop_fax_detect_session_function)
static void event_handler(switch_event_t *event)
{
mod_spandsp_fax_event_handler(event);
load_configuration(1);
}
SWITCH_STANDARD_APP(t38_gateway_function)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
@ -261,12 +263,239 @@ SWITCH_STANDARD_API(stop_tone_detect_api)
return status;
}
/* **************************************************************************
CONFIGURATION
************************************************************************* */
switch_status_t load_configuration(switch_bool_t reload)
{
switch_xml_t xml = NULL, x_lists = NULL, x_list = NULL, cfg = NULL, callprogress = NULL, xdescriptor = NULL;
switch_status_t status = SWITCH_STATUS_FALSE;
switch_mutex_lock(spandsp_globals.mutex);
if (spandsp_globals.tones) {
switch_core_hash_destroy(&spandsp_globals.tones);
}
if (spandsp_globals.config_pool) {
switch_core_destroy_memory_pool(&spandsp_globals.config_pool);
}
switch_core_new_memory_pool(&spandsp_globals.config_pool);
switch_core_hash_init(&spandsp_globals.tones, spandsp_globals.config_pool);
spandsp_globals.modem_dialplan = "XML";
spandsp_globals.modem_context = "default";
spandsp_globals.modem_count = 1;
spandsp_globals.enable_t38 = 1;
spandsp_globals.total_sessions = 0;
spandsp_globals.verbose = 0;
spandsp_globals.use_ecm = 1;
spandsp_globals.disable_v17 = 0;
spandsp_globals.prepend_string = switch_core_strdup(spandsp_globals.config_pool, "fax");
spandsp_globals.spool = switch_core_strdup(spandsp_globals.config_pool, "/tmp");
spandsp_globals.ident = "SpanDSP Fax Ident";
spandsp_globals.header = "SpanDSP Fax Header";
/* TODO make configuration param */
spandsp_globals.tonedebug = 1;
if ((xml = switch_xml_open_cfg("spandsp.conf", &cfg, NULL)) || (xml = switch_xml_open_cfg("fax.conf", &cfg, NULL))) {
status = SWITCH_STATUS_SUCCESS;
if ((x_lists = switch_xml_child(cfg, "modem-settings"))) {
for (x_list = switch_xml_child(x_lists, "param"); x_list; x_list = x_list->next) {
const char *name = switch_xml_attr(x_list, "name");
const char *value = switch_xml_attr(x_list, "value");
if (zstr(name)) {
continue;
}
if (zstr(value)) {
continue;
}
if (!reload && !strcmp(name, "total-modems")) {
int tmp = atoi(value);
if (tmp > 0 && tmp < MAX_MODEMS) {
spandsp_globals.modem_count = tmp;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid value [%d] for total-modems\n", tmp);
}
} else if (!strcmp(name, "dialplan")) {
spandsp_globals.modem_dialplan = switch_core_strdup(spandsp_globals.config_pool, value);
} else if (!strcmp(name, "context")) {
spandsp_globals.modem_context = switch_core_strdup(spandsp_globals.config_pool, value);
} else if (!strcmp(name, "verbose")) {
if (switch_true(value)) {
spandsp_globals.modem_verbose = 1;
} else {
spandsp_globals.modem_verbose = 0;
}
}
}
}
if ((x_lists = switch_xml_child(cfg, "fax-settings")) || (x_lists = switch_xml_child(cfg, "settings"))) {
for (x_list = switch_xml_child(x_lists, "param"); x_list; x_list = x_list->next) {
const char *name = switch_xml_attr(x_list, "name");
const char *value = switch_xml_attr(x_list, "value");
if (zstr(name)) {
continue;
}
if (zstr(value)) {
continue;
}
if (!strcmp(name, "use-ecm")) {
if (switch_true(value))
spandsp_globals.use_ecm = 1;
else
spandsp_globals.use_ecm = 0;
} else if (!strcmp(name, "verbose")) {
if (switch_true(value))
spandsp_globals.verbose = 1;
else
spandsp_globals.verbose = 0;
} else if (!strcmp(name, "disable-v17")) {
if (switch_true(value))
spandsp_globals.disable_v17 = 1;
else
spandsp_globals.disable_v17 = 0;
} else if (!strcmp(name, "enable-t38")) {
if (switch_true(value)) {
spandsp_globals.enable_t38= 1;
} else {
spandsp_globals.enable_t38 = 0;
}
} else if (!strcmp(name, "enable-t38-request")) {
if (switch_true(value)) {
spandsp_globals.enable_t38_request = 1;
} else {
spandsp_globals.enable_t38_request = 0;
}
} else if (!strcmp(name, "ident")) {
spandsp_globals.ident = switch_core_strdup(spandsp_globals.config_pool, value);
} else if (!strcmp(name, "header")) {
spandsp_globals.header = switch_core_strdup(spandsp_globals.config_pool, value);
} else if (!strcmp(name, "spool-dir")) {
spandsp_globals.spool = switch_core_strdup(spandsp_globals.config_pool, value);
} else if (!strcmp(name, "file-prefix")) {
spandsp_globals.prepend_string = switch_core_strdup(spandsp_globals.config_pool, value);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown parameter %s\n", name);
}
}
}
/* Configure call progress detector */
if ((callprogress = switch_xml_child(cfg, "descriptors"))) {
for (xdescriptor = switch_xml_child(callprogress, "descriptor"); xdescriptor; xdescriptor = switch_xml_next(xdescriptor)) {
const char *name = switch_xml_attr(xdescriptor, "name");
const char *tone_name = NULL;
switch_xml_t tone = NULL, element = NULL;
tone_descriptor_t *descriptor = NULL;
/* create descriptor */
if (zstr(name)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing <descriptor> name\n");
switch_goto_status(SWITCH_STATUS_FALSE, done);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s\n", name);
if (tone_descriptor_create(&descriptor, name, spandsp_globals.config_pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to allocate tone_descriptor: %s\n", name);
switch_goto_status(SWITCH_STATUS_FALSE, done);
}
switch_core_hash_insert(spandsp_globals.tones, name, descriptor);
/* add tones to descriptor */
for (tone = switch_xml_child(xdescriptor, "tone"); tone; tone = switch_xml_next(tone)) {
int id = 0;
tone_name = switch_xml_attr(tone, "name");
if (zstr(tone_name)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing <tone> name for <descriptor> %s\n", name);
switch_goto_status(SWITCH_STATUS_FALSE, done);
}
id = tone_descriptor_add_tone(descriptor, tone_name);
if (id == -1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
"Unable to add tone_descriptor: %s, tone: %s. (too many tones)\n", name, tone_name);
switch_goto_status(SWITCH_STATUS_FALSE, done);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
"Adding tone_descriptor: %s, tone: %s(%d)\n", name, tone_name, id);
/* add elements to tone */
for (element = switch_xml_child(tone, "element"); element; element = switch_xml_next(element)) {
const char *freq1_attr = switch_xml_attr(element, "freq1");
const char *freq2_attr = switch_xml_attr(element, "freq2");
const char *min_attr = switch_xml_attr(element, "min");
const char *max_attr = switch_xml_attr(element, "max");
int freq1, freq2, min, max;
if (zstr(freq1_attr)) {
freq1 = 0;
} else {
freq1 = atoi(freq1_attr);
}
if (zstr(freq2_attr)) {
freq2 = 0;
} else {
freq2 = atoi(freq2_attr);
}
if (zstr(min_attr)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
"Missing min in <element> of <descriptor> %s <tone> %s(%d)\n", name, tone_name, id);
switch_goto_status(SWITCH_STATUS_FALSE, done);
}
min = atoi(min_attr);
if (zstr(max_attr)) {
max = 0;
} else {
max = atoi(max_attr);
}
/* check params */
if ((freq1 < 0 || freq2 < 0 || min < 0 || max < 0) || (freq1 == 0 && min == 0 && max == 0)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid element param.\n");
switch_goto_status(SWITCH_STATUS_FALSE, done);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
"Adding tone_descriptor: %s, tone: %s(%d), element (%d, %d, %d, %d)\n", name, tone_name, id, freq1, freq2, min, max);
tone_descriptor_add_tone_element(descriptor, id, freq1, freq2, min, max);
}
}
}
}
done:
switch_xml_free(xml);
}
switch_mutex_unlock(spandsp_globals.mutex);
return status;
}
SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init)
{
switch_application_interface_t *app_interface;
switch_api_interface_t *api_interface;
memset(&spandsp_globals, 0, sizeof(spandsp_globals));
spandsp_globals.pool = pool;
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
switch_mutex_init(&spandsp_globals.mutex, SWITCH_MUTEX_NESTED, pool);
SWITCH_ADD_APP(app_interface, "t38_gateway", "Convert to T38 Gateway if tones are heard", "Convert to T38 Gateway if tones are heard",
t38_gateway_function, "", SAF_MEDIA_TAP);
@ -284,10 +513,12 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init)
SWITCH_ADD_APP(app_interface, "spandsp_stop_fax_detect", "stop fax detect", "stop fax detect", spandsp_stop_fax_detect_session_function, "", SAF_NONE);
load_configuration(0);
mod_spandsp_fax_load(pool);
mod_spandsp_codecs_load(module_interface, pool);
if (mod_spandsp_dsp_load(module_interface, pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't load or process spandsp.conf, not adding tone_detect applications\n");
} else {
@ -302,6 +533,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_spandsp_init)
/* Not such severe to prevent loading */
}
modem_global_init(module_interface, pool);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "mod_spandsp loaded, using spandsp library version [%s]\n", SPANDSP_RELEASE_DATETIME_STRING);
return SWITCH_STATUS_SUCCESS;
@ -313,6 +545,15 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_spandsp_shutdown)
mod_spandsp_fax_shutdown();
mod_spandsp_dsp_shutdown();
modem_global_shutdown();
if (spandsp_globals.tones) {
switch_core_hash_destroy(&spandsp_globals.tones);
}
if (spandsp_globals.config_pool) {
switch_core_destroy_memory_pool(&spandsp_globals.config_pool);
}
return SWITCH_STATUS_UNLOAD;
}

View File

@ -42,9 +42,40 @@ typedef HANDLE zap_socket_t;
typedef int zap_socket_t;
#endif
#define MAX_MODEMS 1024
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
#include <spandsp.h>
/* The global stuff */
struct spandsp_globals {
switch_memory_pool_t *pool;
switch_memory_pool_t *config_pool;
switch_mutex_t *mutex;
uint32_t total_sessions;
short int use_ecm;
short int verbose;
short int disable_v17;
short int enable_t38;
short int enable_t38_request;
short int enable_t38_insist;
char *ident;
char *header;
char *prepend_string;
char *spool;
switch_thread_cond_t *cond;
switch_mutex_t *cond_mutex;
int modem_count;
int modem_verbose;
char *modem_context;
char *modem_dialplan;
switch_hash_t *tones;
int tonedebug;
};
extern struct spandsp_globals spandsp_globals;
typedef enum {
FUNCTION_TX,
@ -52,6 +83,37 @@ typedef enum {
FUNCTION_GW
} mod_spandsp_fax_application_mode_t;
/******************************************************************************
* TONE DETECTION WITH CADENCE
*/
#define MAX_TONES 32
#define STRLEN 128
/**
* Tone descriptor
*
* Defines a set of tones to look for
*/
struct tone_descriptor {
/** The name of this descriptor set */
const char *name;
/** Describes the tones to watch */
super_tone_rx_descriptor_t *spandsp_tone_descriptor;
/** The mapping of tone id to key */
char tone_keys[MAX_TONES][STRLEN];
int idx;
};
typedef struct tone_descriptor tone_descriptor_t;
switch_status_t tone_descriptor_create(tone_descriptor_t **descriptor, const char *name, switch_memory_pool_t *memory_pool);
int tone_descriptor_add_tone(tone_descriptor_t *descriptor, const char *name);
switch_status_t tone_descriptor_add_tone_element(tone_descriptor_t *descriptor, int tone_id, int freq1, int freq2, int min, int max);
void mod_spandsp_fax_load(switch_memory_pool_t *pool);
switch_status_t mod_spandsp_codecs_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool);
switch_status_t mod_spandsp_dsp_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool);
@ -74,3 +136,5 @@ switch_status_t spandsp_fax_detect_session(switch_core_session_t *session,
int hits, const char *app, const char *data, switch_tone_detect_callback_t callback);
switch_status_t spandsp_fax_stop_detect_session(switch_core_session_t *session);
void spanfax_log_message(int level, const char *msg);
switch_status_t load_configuration(switch_bool_t reload);

View File

@ -155,48 +155,7 @@ switch_status_t spandsp_inband_dtmf_session(switch_core_session_t *session)
/* private channel data */
#define TONE_PRIVATE "mod_tone_detect_bug"
/**
* Module global variables
*/
struct globals {
/** Memory pool */
switch_memory_pool_t *pool;
/** Call progress tones mapped by descriptor name */
switch_hash_t *tones;
/** Default debug level */
int debug;
};
typedef struct globals globals_t;
static globals_t globals;
/******************************************************************************
* TONE DETECTION WITH CADENCE
*/
#define MAX_TONES 32
#define STRLEN 128
/**
* Tone descriptor
*
* Defines a set of tones to look for
*/
struct tone_descriptor {
/** The name of this descriptor set */
const char *name;
/** Describes the tones to watch */
super_tone_rx_descriptor_t *spandsp_tone_descriptor;
/** The mapping of tone id to key */
char tone_keys[MAX_TONES][STRLEN];
int idx;
};
typedef struct tone_descriptor tone_descriptor_t;
static switch_status_t tone_descriptor_create(tone_descriptor_t **descriptor, const char *name, switch_memory_pool_t *memory_pool);
static int tone_descriptor_add_tone(tone_descriptor_t *descriptor, const char *name);
static switch_status_t tone_descriptor_add_tone_element(tone_descriptor_t *descriptor, int tone_id, int freq1, int freq2, int min, int max);
/**
* Tone detector
@ -232,7 +191,7 @@ static switch_bool_t callprogress_detector_process_buffer(switch_media_bug_t *bu
* @param memory_pool the pool to use
* @return SWITCH_STATUS_SUCCESS if successful
*/
static switch_status_t tone_descriptor_create(tone_descriptor_t **descriptor, const char *name, switch_memory_pool_t *memory_pool)
switch_status_t tone_descriptor_create(tone_descriptor_t **descriptor, const char *name, switch_memory_pool_t *memory_pool)
{
tone_descriptor_t *ldescriptor = NULL;
ldescriptor = switch_core_alloc(memory_pool, sizeof(tone_descriptor_t));
@ -253,7 +212,7 @@ static switch_status_t tone_descriptor_create(tone_descriptor_t **descriptor, co
* @param key the tone key - this will be returned by the detector upon match
* @return the tone ID
*/
static int tone_descriptor_add_tone(tone_descriptor_t *descriptor, const char *key)
int tone_descriptor_add_tone(tone_descriptor_t *descriptor, const char *key)
{
int id = super_tone_rx_add_tone(descriptor->spandsp_tone_descriptor);
if (id >= MAX_TONES) {
@ -279,7 +238,7 @@ static int tone_descriptor_add_tone(tone_descriptor_t *descriptor, const char *k
* @param max the maximum tone duration in ms
* @return SWITCH_STATUS_SUCCESS if successful
*/
static switch_status_t tone_descriptor_add_tone_element(tone_descriptor_t *descriptor, int tone_id, int freq1, int freq2, int min, int max)
switch_status_t tone_descriptor_add_tone_element(tone_descriptor_t *descriptor, int tone_id, int freq1, int freq2, int min, int max)
{
if (super_tone_rx_add_element(descriptor->spandsp_tone_descriptor, tone_id, freq1, freq2, min, max) == 0) {
return SWITCH_STATUS_SUCCESS;
@ -337,7 +296,7 @@ static switch_status_t tone_detector_create(tone_detector_t **detector, tone_des
}
memset(ldetector, 0, sizeof(tone_detector_t));
ldetector->descriptor = descriptor;
ldetector->debug = globals.debug;
ldetector->debug = spandsp_globals.tonedebug;
*detector = ldetector;
return SWITCH_STATUS_SUCCESS;
}
@ -409,7 +368,7 @@ switch_status_t callprogress_detector_start(switch_core_session_t *session, cons
}
/* find the tone descriptor with the matching name and create the detector */
descriptor = switch_core_hash_find(globals.tones, name);
descriptor = switch_core_hash_find(spandsp_globals.tones, name);
if (!descriptor) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "(%s) no tone descriptor defined with name '%s'. Update configuration. \n", switch_channel_get_name(channel), name);
return SWITCH_STATUS_FALSE;
@ -509,116 +468,11 @@ switch_status_t callprogress_detector_stop(switch_core_session_t *session)
return SWITCH_STATUS_SUCCESS;
}
/**
* Process configuration file
*/
static switch_status_t do_config(void)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_xml_t cfg = NULL, xml = NULL, callprogress = NULL, xdescriptor = NULL;
if (!(xml = switch_xml_open_cfg("spandsp.conf", &cfg, NULL))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not open spandsp.conf\n");
status = SWITCH_STATUS_FALSE;
goto done;
}
/* TODO make configuration param */
globals.debug = 1;
/* Configure call progress detector */
if ((callprogress = switch_xml_child(cfg, "descriptors"))) {
for (xdescriptor = switch_xml_child(callprogress, "descriptor"); xdescriptor; xdescriptor = switch_xml_next(xdescriptor)) {
const char *name = switch_xml_attr(xdescriptor, "name");
const char *tone_name = NULL;
switch_xml_t tone = NULL, element = NULL;
tone_descriptor_t *descriptor = NULL;
/* create descriptor */
if (zstr(name)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing <descriptor> name\n");
return SWITCH_STATUS_FALSE;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s\n", name);
if (tone_descriptor_create(&descriptor, name, globals.pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to allocate tone_descriptor: %s\n", name);
return SWITCH_STATUS_FALSE;
}
switch_core_hash_insert(globals.tones, name, descriptor);
/* add tones to descriptor */
for (tone = switch_xml_child(xdescriptor, "tone"); tone; tone = switch_xml_next(tone)) {
int id = 0;
tone_name = switch_xml_attr(tone, "name");
if (zstr(tone_name)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing <tone> name for <descriptor> %s\n", name);
return SWITCH_STATUS_FALSE;
}
id = tone_descriptor_add_tone(descriptor, tone_name);
if (id == -1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unable to add tone_descriptor: %s, tone: %s. (too many tones)\n", name, tone_name);
return SWITCH_STATUS_FALSE;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s, tone: %s(%d)\n", name, tone_name, id);
/* add elements to tone */
for (element = switch_xml_child(tone, "element"); element; element = switch_xml_next(element)) {
const char *freq1_attr = switch_xml_attr(element, "freq1");
const char *freq2_attr = switch_xml_attr(element, "freq2");
const char *min_attr = switch_xml_attr(element, "min");
const char *max_attr = switch_xml_attr(element, "max");
int freq1, freq2, min, max;
if (zstr(freq1_attr)) {
freq1 = 0;
} else {
freq1 = atoi(freq1_attr);
}
if (zstr(freq2_attr)) {
freq2 = 0;
} else {
freq2 = atoi(freq2_attr);
}
if (zstr(min_attr)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing min in <element> of <descriptor> %s <tone> %s(%d)\n", name, tone_name, id);
return SWITCH_STATUS_FALSE;
}
min = atoi(min_attr);
if (zstr(max_attr)) {
max = 0;
} else {
max = atoi(max_attr);
}
/* check params */
if ((freq1 < 0 || freq2 < 0 || min < 0 || max < 0) || (freq1 == 0 && min == 0 && max == 0)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid element param.\n");
return SWITCH_STATUS_FALSE;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s, tone: %s(%d), element (%d, %d, %d, %d)\n", name, tone_name, id, freq1, freq2, min, max);
tone_descriptor_add_tone_element(descriptor, id, freq1, freq2, min, max);
}
}
}
}
done:
if (xml) {
switch_xml_free(xml);
}
return status;
}
/**
* Called when FreeSWITCH loads the module
*/
switch_status_t mod_spandsp_dsp_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool)
{
memset(&globals, 0, sizeof(globals_t));
globals.pool = pool;
switch_core_hash_init(&globals.tones, globals.pool);
if (do_config() != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_FALSE;
}
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
}
@ -628,7 +482,7 @@ switch_status_t mod_spandsp_dsp_load(switch_loadable_module_interface_t **module
*/
void mod_spandsp_dsp_shutdown(void)
{
switch_core_hash_destroy(&globals.tones);
return;
}

View File

@ -60,26 +60,6 @@ typedef enum {
T38_MODE_REFUSED = -1,
} t38_mode_t;
/* The global stuff */
static struct {
switch_memory_pool_t *pool;
switch_mutex_t *mutex;
uint32_t total_sessions;
short int use_ecm;
short int verbose;
short int disable_v17;
short int enable_t38;
short int enable_t38_request;
short int enable_t38_insist;
char ident[20];
char header[50];
char *prepend_string;
char *spool;
switch_thread_cond_t *cond;
switch_mutex_t *cond_mutex;
} globals;
struct pvt_s {
switch_core_session_t *session;
@ -128,13 +108,13 @@ static struct {
static void wake_thread(int force)
{
if (force) {
switch_thread_cond_signal(globals.cond);
switch_thread_cond_signal(spandsp_globals.cond);
return;
}
if (switch_mutex_trylock(globals.cond_mutex) == SWITCH_STATUS_SUCCESS) {
switch_thread_cond_signal(globals.cond);
switch_mutex_unlock(globals.cond_mutex);
if (switch_mutex_trylock(spandsp_globals.cond_mutex) == SWITCH_STATUS_SUCCESS) {
switch_thread_cond_signal(spandsp_globals.cond);
switch_mutex_unlock(spandsp_globals.cond_mutex);
}
}
@ -206,7 +186,7 @@ static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *
goto end;
}
switch_mutex_lock(globals.cond_mutex);
switch_mutex_lock(spandsp_globals.cond_mutex);
while(t38_state_list.thread_running) {
@ -214,7 +194,7 @@ static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *
if (!t38_state_list.head) {
switch_mutex_unlock(t38_state_list.mutex);
switch_thread_cond_wait(globals.cond, globals.cond_mutex);
switch_thread_cond_wait(spandsp_globals.cond, spandsp_globals.cond_mutex);
switch_core_timer_sync(&timer);
continue;
}
@ -230,7 +210,7 @@ static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *
switch_core_timer_next(&timer);
}
switch_mutex_unlock(globals.cond_mutex);
switch_mutex_unlock(spandsp_globals.cond_mutex);
end:
@ -252,9 +232,9 @@ static void launch_timer_thread(void)
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, globals.pool);
switch_threadattr_create(&thd_attr, spandsp_globals.pool);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&t38_state_list.thread, thd_attr, timer_thread_run, NULL, globals.pool);
switch_thread_create(&t38_state_list.thread, thd_attr, timer_thread_run, NULL, spandsp_globals.pool);
}
@ -264,12 +244,12 @@ static void launch_timer_thread(void)
static void counter_increment(void)
{
switch_mutex_lock(globals.mutex);
globals.total_sessions++;
switch_mutex_unlock(globals.mutex);
switch_mutex_lock(spandsp_globals.mutex);
spandsp_globals.total_sessions++;
switch_mutex_unlock(spandsp_globals.mutex);
}
static void spanfax_log_message(int level, const char *msg)
void spanfax_log_message(int level, const char *msg)
{
int fs_log_level;
@ -821,7 +801,7 @@ static t38_mode_t negotiate_t38(pvt_t *pvt)
} else if ((v = switch_channel_get_variable(channel, "fax_enable_t38"))) {
enabled = switch_true(v);
} else {
enabled = globals.enable_t38;
enabled = spandsp_globals.enable_t38;
}
if (!(enabled && t38_options)) {
@ -877,7 +857,7 @@ static t38_mode_t negotiate_t38(pvt_t *pvt)
if ((v = switch_channel_get_variable(channel, "fax_enable_t38_insist"))) {
insist = switch_true(v);
} else {
insist = globals.enable_t38_insist;
insist = spandsp_globals.enable_t38_insist;
}
/* This will send the options back in a response */
@ -907,14 +887,14 @@ static t38_mode_t request_t38(pvt_t *pvt)
} else if ((v = switch_channel_get_variable(channel, "fax_enable_t38"))) {
enabled = switch_true(v);
} else {
enabled = globals.enable_t38;
enabled = spandsp_globals.enable_t38;
}
if (enabled) {
if ((v = switch_channel_get_variable(channel, "fax_enable_t38_request"))) {
enabled = switch_true(v);
} else {
enabled = globals.enable_t38_request;
enabled = spandsp_globals.enable_t38_request;
}
}
@ -922,7 +902,7 @@ static t38_mode_t request_t38(pvt_t *pvt)
if ((v = switch_channel_get_variable(channel, "fax_enable_t38_insist"))) {
insist = switch_true(v);
} else {
insist = globals.enable_t38_insist;
insist = spandsp_globals.enable_t38_insist;
}
if ((t38_options = switch_channel_get_private(channel, "t38_options"))) {
@ -1004,19 +984,19 @@ static pvt_t *pvt_init(switch_core_session_t *session, mod_spandsp_fax_applicati
if ((tmp = switch_channel_get_variable(channel, "fax_use_ecm"))) {
pvt->use_ecm = switch_true(tmp);
} else {
pvt->use_ecm = globals.use_ecm;
pvt->use_ecm = spandsp_globals.use_ecm;
}
if ((tmp = switch_channel_get_variable(channel, "fax_disable_v17"))) {
pvt->disable_v17 = switch_true(tmp);
} else {
pvt->disable_v17 = globals.disable_v17;
pvt->disable_v17 = spandsp_globals.disable_v17;
}
if ((tmp = switch_channel_get_variable(channel, "fax_verbose"))) {
pvt->verbose = switch_true(tmp);
} else {
pvt->verbose = globals.verbose;
pvt->verbose = spandsp_globals.verbose;
}
if ((tmp = switch_channel_get_variable(channel, "fax_force_caller"))) {
@ -1036,7 +1016,7 @@ static pvt_t *pvt_init(switch_core_session_t *session, mod_spandsp_fax_applicati
switch_safe_free(data);
} else {
pvt->ident = switch_core_session_strdup(session, globals.ident);
pvt->ident = switch_core_session_strdup(session, spandsp_globals.ident);
}
if ((tmp = switch_channel_get_variable(channel, "fax_header"))) {
@ -1048,7 +1028,7 @@ static pvt_t *pvt_init(switch_core_session_t *session, mod_spandsp_fax_applicati
switch_safe_free(data);
} else {
pvt->header = switch_core_session_strdup(session, globals.header);
pvt->header = switch_core_session_strdup(session, spandsp_globals.header);
}
if (pvt->app_mode == FUNCTION_TX) {
@ -1118,10 +1098,10 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
time = switch_time_now();
if (!(prefix = switch_channel_get_variable(channel, "fax_prefix"))) {
prefix = globals.prepend_string;
prefix = spandsp_globals.prepend_string;
}
if (!(pvt->filename = switch_core_session_sprintf(session, "%s/%s-%ld-%ld.tif", globals.spool, prefix, globals.total_sessions, time))) {
if (!(pvt->filename = switch_core_session_sprintf(session, "%s/%s-%ld-%ld.tif", spandsp_globals.spool, prefix, spandsp_globals.total_sessions, time))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot automatically set fax RX destination file\n");
goto done;
}
@ -1338,107 +1318,17 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
}
}
/* **************************************************************************
CONFIGURATION
************************************************************************* */
void load_configuration(switch_bool_t reload)
{
switch_xml_t xml = NULL, x_lists = NULL, x_list = NULL, cfg = NULL;
if ((xml = switch_xml_open_cfg("fax.conf", &cfg, NULL))) {
if ((x_lists = switch_xml_child(cfg, "settings"))) {
for (x_list = switch_xml_child(x_lists, "param"); x_list; x_list = x_list->next) {
const char *name = switch_xml_attr(x_list, "name");
const char *value = switch_xml_attr(x_list, "value");
if (zstr(name)) {
continue;
}
if (zstr(value)) {
continue;
}
if (!strcmp(name, "use-ecm")) {
if (switch_true(value))
globals.use_ecm = 1;
else
globals.use_ecm = 0;
} else if (!strcmp(name, "verbose")) {
if (switch_true(value))
globals.verbose = 1;
else
globals.verbose = 0;
} else if (!strcmp(name, "disable-v17")) {
if (switch_true(value))
globals.disable_v17 = 1;
else
globals.disable_v17 = 0;
} else if (!strcmp(name, "enable-t38")) {
if (switch_true(value)) {
globals.enable_t38= 1;
} else {
globals.enable_t38 = 0;
}
} else if (!strcmp(name, "enable-t38-request")) {
if (switch_true(value)) {
globals.enable_t38_request = 1;
} else {
globals.enable_t38_request = 0;
}
} else if (!strcmp(name, "ident")) {
strncpy(globals.ident, value, sizeof(globals.ident) - 1);
} else if (!strcmp(name, "header")) {
strncpy(globals.header, value, sizeof(globals.header) - 1);
} else if (!strcmp(name, "spool-dir")) {
globals.spool = switch_core_strdup(globals.pool, value);
} else if (!strcmp(name, "file-prefix")) {
globals.prepend_string = switch_core_strdup(globals.pool, value);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown parameter %s\n", name);
}
}
}
switch_xml_free(xml);
}
}
void mod_spandsp_fax_event_handler(switch_event_t *event)
{
load_configuration(1);
}
void mod_spandsp_fax_load(switch_memory_pool_t *pool)
{
uint32_t sanity = 200;
memset(&globals, 0, sizeof(globals));
memset(&t38_state_list, 0, sizeof(t38_state_list));
globals.pool = pool;
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
switch_mutex_init(&t38_state_list.mutex, SWITCH_MUTEX_NESTED, globals.pool);
switch_mutex_init(&globals.cond_mutex, SWITCH_MUTEX_NESTED, globals.pool);
switch_thread_cond_create(&globals.cond, globals.pool);
globals.enable_t38 = 1;
globals.total_sessions = 0;
globals.verbose = 1;
globals.use_ecm = 1;
globals.disable_v17 = 0;
globals.prepend_string = switch_core_strdup(globals.pool, "fax");
globals.spool = switch_core_strdup(globals.pool, "/tmp");
strncpy(globals.ident, "SpanDSP Fax Ident", sizeof(globals.ident) - 1);
strncpy(globals.header, "SpanDSP Fax Header", sizeof(globals.header) - 1);
load_configuration(0);
switch_mutex_init(&spandsp_globals.mutex, SWITCH_MUTEX_NESTED, spandsp_globals.pool);
switch_mutex_init(&t38_state_list.mutex, SWITCH_MUTEX_NESTED, spandsp_globals.pool);
switch_mutex_init(&spandsp_globals.cond_mutex, SWITCH_MUTEX_NESTED, spandsp_globals.pool);
switch_thread_cond_create(&spandsp_globals.cond, spandsp_globals.pool);
launch_timer_thread();
@ -1454,7 +1344,7 @@ void mod_spandsp_fax_shutdown(void)
t38_state_list.thread_running = 0;
wake_thread(1);
switch_thread_join(&tstatus, t38_state_list.thread);
memset(&globals, 0, sizeof(globals));
memset(&spandsp_globals, 0, sizeof(spandsp_globals));
}
static const switch_state_handler_table_t t38_gateway_state_handlers;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,111 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH mod_fax.
*
* The Initial Developer of the Original Code is
* Massimo Cetra <devel@navynet.it>
*
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Brian West <brian@freeswitch.org>
* Anthony Minessale II <anthm@freeswitch.org>
* Steve Underwood <steveu@coppice.org>
* mod_spandsp_modem.h -- Fax modem applications provided by SpanDSP
*
*/
#include "switch_private.h"
#if defined(HAVE_OPENPTY) || defined(HAVE_DEV_PTMX) || defined(HAVE_POSIX_OPENPT)
#define MODEM_SUPPORT 1
#if !defined(HAVE_POSIX_OPENPT) && !defined(HAVE_DEV_PTMX)
#define USE_OPENPTY 1
#endif
#ifndef _MOD_SPANDSP_MODEM_H
#define _MOD_SPANDSP_MODEM_H
#include <stdio.h>
#include <string.h>
#include <pty.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <byteswap.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <tiffio.h>
#include <spandsp.h>
typedef enum {
MODEM_STATE_INIT,
MODEM_STATE_ONHOOK,
MODEM_STATE_OFFHOOK,
MODEM_STATE_ACQUIRED,
MODEM_STATE_RINGING,
MODEM_STATE_ANSWERED,
MODEM_STATE_DIALING,
MODEM_STATE_CONNECTED,
MODEM_STATE_HANGUP,
MODEM_STATE_LAST
} modem_state_t;
struct modem;
typedef int (*modem_control_handler_t)(struct modem *, const char *, int);
typedef enum {
MODEM_FLAG_RUNNING = ( 1 << 0),
MODEM_FLAG_XOFF = ( 1 << 1)
} modem_flags;
struct modem {
t31_state_t *t31_state;
char digits[512];
modem_flags flags;
int master;
int slave;
char *stty;
char devlink[128];
int id;
modem_state_t state;
modem_control_handler_t control_handler;
void *user_data;
switch_mutex_t *mutex;
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
switch_time_t last_event;
int slot;
};
typedef struct modem modem_t;
char *modem_state2name(int state);
int modem_close(struct modem *fm);
int modem_init(struct modem *fm, modem_control_handler_t control_handler);
#endif //MODEM_SUPPORT
switch_status_t modem_global_init(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool);
void modem_global_shutdown(void);
#endif //_MOD_SPANDSP_MODEM_H