From 269906c8918dfb4247e4087fbb0e5390c4d44fa6 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 24 Feb 2011 18:41:07 -0500 Subject: [PATCH] freetdm: Added support for hardware (native) R2 MF generation --- libs/freetdm/Makefile.am | 2 +- libs/freetdm/src/ftdm_cpu_monitor.c | 6 +- libs/freetdm/src/ftdm_dso.c | 2 +- libs/freetdm/src/ftdm_threadmutex.c | 6 +- .../src/ftmod/ftmod_r2/ftmod_r2.2008.vcproj | 4 + libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c | 39 ++++- .../src/ftmod/ftmod_r2/ftmod_r2_io_mf_lib.c | 163 ++++++++++++++++++ .../src/ftmod/ftmod_r2/ftmod_r2_io_mf_lib.h | 73 ++++++++ libs/freetdm/src/include/freetdm.h | 13 ++ libs/freetdm/src/include/ftdm_dso.h | 2 +- libs/freetdm/src/include/private/ftdm_types.h | 1 + 11 files changed, 298 insertions(+), 13 deletions(-) mode change 100644 => 100755 libs/freetdm/src/ftdm_dso.c mode change 100644 => 100755 libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c create mode 100755 libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2_io_mf_lib.c create mode 100755 libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2_io_mf_lib.h mode change 100644 => 100755 libs/freetdm/src/include/freetdm.h mode change 100644 => 100755 libs/freetdm/src/include/ftdm_dso.h mode change 100644 => 100755 libs/freetdm/src/include/private/ftdm_types.h diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index a26035b2ef..4b08dd3d3c 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -248,7 +248,7 @@ endif if HAVE_OPENR2 mod_LTLIBRARIES += ftmod_r2.la -ftmod_r2_la_SOURCES = $(SRC)/ftmod/ftmod_r2/ftmod_r2.c +ftmod_r2_la_SOURCES = $(SRC)/ftmod/ftmod_r2/ftmod_r2.c $(SRC)/ftmod/ftmod_r2/ftmod_r2_io_mf_lib.c ftmod_r2_la_CFLAGS = $(AM_CFLAGS) $(FTDM_CFLAGS) ftmod_r2_la_LDFLAGS = -shared -module -avoid-version -lopenr2 ftmod_r2_la_LIBADD = libfreetdm.la diff --git a/libs/freetdm/src/ftdm_cpu_monitor.c b/libs/freetdm/src/ftdm_cpu_monitor.c index 4ebe353b57..b543f05210 100644 --- a/libs/freetdm/src/ftdm_cpu_monitor.c +++ b/libs/freetdm/src/ftdm_cpu_monitor.c @@ -37,8 +37,10 @@ */ #ifdef WIN32 -#define _WIN32_WINNT 0x0501 // To make GetSystemTimes visible in windows.h -#include +# if (_WIN32_WINNT < 0x0501) +# error "Need to target at least Windows XP/Server 2003 because GetSystemTimes is needed" +# endif +# include #else /* LINUX */ #include diff --git a/libs/freetdm/src/ftdm_dso.c b/libs/freetdm/src/ftdm_dso.c old mode 100644 new mode 100755 index 6e7403165d..5b33a44347 --- a/libs/freetdm/src/ftdm_dso.c +++ b/libs/freetdm/src/ftdm_dso.c @@ -122,5 +122,5 @@ FT_DECLARE(void *) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char * * c-basic-offset:4 * End: * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: */ diff --git a/libs/freetdm/src/ftdm_threadmutex.c b/libs/freetdm/src/ftdm_threadmutex.c index 6efa27714c..57a8fb4830 100644 --- a/libs/freetdm/src/ftdm_threadmutex.c +++ b/libs/freetdm/src/ftdm_threadmutex.c @@ -22,8 +22,10 @@ */ #ifdef WIN32 -/* required for TryEnterCriticalSection definition. Must be defined before windows.h include */ -#define _WIN32_WINNT 0x0400 +# if (_WIN32_WINNT < 0x0400) +# error "Need to target at least Windows 95/WINNT 4.0 because TryEnterCriticalSection is needed" +# endif +# include #endif #include "private/ftdm_core.h" diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2008.vcproj index 8942a8f5b6..565a31e505 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2008.vcproj +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2008.vcproj @@ -185,6 +185,10 @@ RelativePath=".\ftmod_r2.c" > + + diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c old mode 100644 new mode 100755 index 540d7cb6e9..3908535a67 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -47,8 +47,10 @@ #endif #include #include -#include "freetdm.h" -#include "private/ftdm_core.h" +#include +#include + +#include "ftmod_r2_io_mf_lib.h" // ftdm_r2_get_native_channel_mf_generation_iface /* when the user stops a span, we clear FTDM_R2_SPAN_STARTED, so that the signaling thread * knows it must stop, and we wait for FTDM_R2_RUNNING to be clear, which tells us the @@ -105,6 +107,7 @@ typedef struct ft_r2_conf_s { int charge_calls; int forced_release; int allow_collect_calls; + int use_channel_native_mf_generation; } ft_r2_conf_t; /* r2 configuration stored in span->signal_data */ @@ -1447,7 +1450,8 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling) /* .double_answer */ -1, /* .charge_calls */ -1, /* .forced_release */ -1, - /* .allow_collect_calls */ -1 + /* .allow_collect_calls */ -1, + /* .use_channel_native_mf_generation */ 0 }; ftdm_assert_return(sig_cb != NULL, FTDM_FAIL, "No signaling cb provided\n"); @@ -1566,6 +1570,9 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling) } else if (!strcasecmp(var, "max_dnis")) { r2conf.max_dnis = atoi(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with max dnis = %d\n", span->name, r2conf.max_dnis); + } else if (!strcasecmp(var, "use_channel_native_mf_generation")) { + r2conf.use_channel_native_mf_generation = ftdm_true(val); + ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with \"use native channel MF generation\" = %d\n", span->name, r2conf.use_channel_native_mf_generation); } else { snprintf(span->last_error, sizeof(span->last_error), "Unknown R2 parameter [%s]", var); return FTDM_FAIL; @@ -1617,6 +1624,10 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling) openr2_context_configure_from_advanced_file(r2data->r2context, r2conf.advanced_protocol_file); } + if(r2conf.use_channel_native_mf_generation) { + openr2_context_set_mflib_interface(r2data->r2context, ftdm_r2_get_native_channel_mf_generation_iface()); + } + spanpvt->r2calls = create_hashtable(FTDM_MAX_CHANNELS_SPAN, ftdm_hash_hashfromstring, ftdm_hash_equalkeys); if (!spanpvt->r2calls) { snprintf(span->last_error, sizeof(span->last_error), "Cannot create channel calls hash for span."); @@ -1634,13 +1645,29 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling) openr2_chan_enable_call_files(r2chan); } - r2call = ftdm_malloc(sizeof(*r2call)); + if (r2conf.use_channel_native_mf_generation) { + /* Allocate a new write handle per r2chan */ + ftdm_r2_mf_write_handle_t *mf_write_handle = ftdm_calloc(1, sizeof(*mf_write_handle)); + /* Associate to the FreeTDM channel */ + mf_write_handle->ftdmchan = span->channels[i]; + /* Make sure the FreeTDM channel supports MF the generation feature */ + if (!ftdm_channel_test_feature(mf_write_handle->ftdmchan, FTDM_CHANNEL_FEATURE_MF_GENERATE)) { + ftdm_log_chan_msg(mf_write_handle->ftdmchan, FTDM_LOG_ERROR, + "FreeTDM channel does not support native MF generation: " + "\"use_channel_native_mf_generation\" configuration parameter cannot" + " be used\n"); + goto fail; + } + /* Associate the mf_write_handle to the openR2 channel */ + openr2_chan_set_mflib_handles(r2chan, mf_write_handle, NULL); + } + + r2call = ftdm_calloc(1, sizeof(*r2call)); if (!r2call) { snprintf(span->last_error, sizeof(span->last_error), "Cannot create all R2 call data structures for the span."); ftdm_safe_free(r2chan); goto fail; } - memset(r2call, 0, sizeof(*r2call)); openr2_chan_set_logging_func(r2chan, ftdm_r2_on_chan_log); openr2_chan_set_client_data(r2chan, span->channels[i]); r2call->r2chan = r2chan; @@ -2370,5 +2397,5 @@ EX_DECLARE_DATA ftdm_module_t ftdm_module = { * c-basic-offset:4 * End: * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: */ diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2_io_mf_lib.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2_io_mf_lib.c new file mode 100755 index 0000000000..961da2cede --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2_io_mf_lib.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2011 Sebastien Trottier + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include + +#include "ftmod_r2_io_mf_lib.h" + +/* Convert openr2 MF tone enum value to FreeTDM MF tone value + 1-15 bitwise OR FTDM_MF_DIRECTION_FORWARD/BACKWARD + 0 (stop playing) + openr2_mf_tone_t defined in r2proto.h +*/ +static int ftdm_r2_openr2_mf_tone_to_ftdm_mf_tone(openr2_mf_tone_t + openr2_tone_value, int forward_signals) +{ + int tone; + + switch (openr2_tone_value) { + case 0: return 0; +#define TONE_FROM_NAME(name) case OR2_MF_TONE_##name: tone = name; break; + TONE_FROM_NAME(1) + TONE_FROM_NAME(2) + TONE_FROM_NAME(3) + TONE_FROM_NAME(4) + TONE_FROM_NAME(5) + TONE_FROM_NAME(6) + TONE_FROM_NAME(7) + TONE_FROM_NAME(8) + TONE_FROM_NAME(9) + TONE_FROM_NAME(10) + TONE_FROM_NAME(11) + TONE_FROM_NAME(12) + TONE_FROM_NAME(13) + TONE_FROM_NAME(14) + TONE_FROM_NAME(15) +#undef TONE_FROM_NAME + default: + ftdm_assert(0, "Invalid openr2_tone_value\n"); + return -1; + } + + /* Add flag corresponding to direction */ + if (forward_signals) { + tone |= FTDM_MF_DIRECTION_FORWARD; + } else { + tone |= FTDM_MF_DIRECTION_BACKWARD; + } + + return tone; +} + +/* MF generation routines (using IO command of a FreeTDM channel) + write_init stores the direction of the MF to generate */ +static void *ftdm_r2_io_mf_write_init(ftdm_r2_mf_write_handle_t *handle, int forward_signals) +{ + ftdm_log_chan(handle->ftdmchan, FTDM_LOG_DEBUG, "ftdm_r2_io_mf_write_init, " + "forward = %d\n", forward_signals); + + handle->fwd = forward_signals; + return handle; +} + +static int ftdm_r2_io_mf_generate_tone(ftdm_r2_mf_write_handle_t *handle, int16_t buffer[], int samples) +{ + /* Our mf_want_generate implementation always return 0, so mf_generate_tone should never be called */ + ftdm_assert(0, "ftdm_r2_io_mf_generate_tone not implemented\n"); + return 0; +} + +/* \brief mf_select_tone starts tone generation or stops current tone + * \return 0 on success, -1 on error + */ +static int ftdm_r2_io_mf_select_tone(ftdm_r2_mf_write_handle_t *handle, char signal) +{ + int tone; /* (0, 1-15) (0 meaning to stop playing) */ + + ftdm_log_chan(handle->ftdmchan, FTDM_LOG_DEBUG, "ftdm_r2_io_mf_select_tone, " + "signal = %c\n", signal); + + if (-1 == (tone = ftdm_r2_openr2_mf_tone_to_ftdm_mf_tone(signal, handle->fwd))) { + return -1; + } + + /* Start/stop playback directly here, as select tone is called each time a tone + is started or stopped (called if tone changes, but silence is tone 0, + triggering a tone change) */ + if (tone > 0) { + ftdm_channel_command(handle->ftdmchan, FTDM_COMMAND_START_MF_PLAYBACK, &tone); + } else { + /* tone 0 means to stop current tone */ + ftdm_channel_command(handle->ftdmchan, FTDM_COMMAND_STOP_MF_PLAYBACK, NULL); + } + return 0; +} + +static int ftdm_r2_io_mf_want_generate(ftdm_r2_mf_write_handle_t *handle, int signal) +{ + /* Return 0, meaning mf_generate_tone doesn't need to be called */ + return 0; +} + +/* MF lib interface that generate MF tones via FreeTDM channel IO commands + MF detection using the default openr2 provider (r2engine) */ +static openr2_mflib_interface_t g_mf_ftdm_io_iface = { + /* .mf_read_init */ (openr2_mf_read_init_func)openr2_mf_rx_init, + /* .mf_write_init */ (openr2_mf_write_init_func)ftdm_r2_io_mf_write_init, + /* .mf_detect_tone */ (openr2_mf_detect_tone_func)openr2_mf_rx, + /* .mf_generate_tone */ (openr2_mf_generate_tone_func)ftdm_r2_io_mf_generate_tone, + /* .mf_select_tone */ (openr2_mf_select_tone_func)ftdm_r2_io_mf_select_tone, + /* .mf_want_generate */ (openr2_mf_want_generate_func)ftdm_r2_io_mf_want_generate, + /* .mf_read_dispose */ NULL, + /* .mf_write_dispose */ NULL +}; + +openr2_mflib_interface_t *ftdm_r2_get_native_channel_mf_generation_iface() +{ + return &g_mf_ftdm_io_iface; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 + */ diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2_io_mf_lib.h b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2_io_mf_lib.h new file mode 100755 index 0000000000..10fe3f3aab --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2_io_mf_lib.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Sebastien Trottier + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _FTMOD_R2_IO_MFLIB_H_ +#define _FTMOD_R2_IO_MFLIB_H_ + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* MFC/R2 tone generator handle (mf_write_handle) */ +typedef struct { + /*! FTDM channel performing the MF generation */ + ftdm_channel_t *ftdmchan; + /*! 1 if generating forward tones, otherwise generating reverse tones. */ + int fwd; +} ftdm_r2_mf_write_handle_t; + +/* MF lib interface that generate MF tones via FreeTDM channel IO commands + MF detection using the default openr2 provider (r2engine) */ +openr2_mflib_interface_t *ftdm_r2_get_native_channel_mf_generation_iface(void); + +#if defined(__cplusplus) +} /* endif extern "C" */ +#endif + +#endif /* endif defined _FTMOD_R2_IO_MFLIB_H_ */ + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h old mode 100644 new mode 100755 index 77abf6ab3e..b1bcd46ae5 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -673,6 +673,9 @@ typedef enum { FTDM_COMMAND_SET_RX_QUEUE_SIZE = 54, FTDM_COMMAND_SET_TX_QUEUE_SIZE = 55, FTDM_COMMAND_SET_POLARITY = 56, + FTDM_COMMAND_START_MF_PLAYBACK = 57, + FTDM_COMMAND_STOP_MF_PLAYBACK = 58, + FTDM_COMMAND_COUNT, } ftdm_command_t; @@ -847,6 +850,16 @@ typedef enum { FTDM_ALARM_GENERAL = (1 << 30) } ftdm_alarm_flag_t; +/*! \brief MF generation direction flags + * \note Used in bitwise OR with channel ID as argument to MF_PLAYBACK I/O command, so value must be higher that 255 + * \see FTDM_COMMAND_START_MF_PLAYBACK + * */ + +typedef enum { + FTDM_MF_DIRECTION_FORWARD = (1 << 8), + FTDM_MF_DIRECTION_BACKWARD = (1 << 9) +} ftdm_mf_direction_flag_t; + /*! \brief Override the default queue handler */ FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *handler); diff --git a/libs/freetdm/src/include/ftdm_dso.h b/libs/freetdm/src/include/ftdm_dso.h old mode 100644 new mode 100755 index b56ad93e39..8cdc13cba4 --- a/libs/freetdm/src/include/ftdm_dso.h +++ b/libs/freetdm/src/include/ftdm_dso.h @@ -49,6 +49,6 @@ FT_DECLARE(char *) ftdm_build_dso_path(const char *name, char *path, ftdm_size_t * c-basic-offset:4 * End: * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: */ diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h old mode 100644 new mode 100755 index 9e8df1f5f2..b263b64a2d --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -203,6 +203,7 @@ typedef enum { FTDM_CHANNEL_FEATURE_HWEC = (1<<7), /*!< Channel has a hardware echo canceller */ FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE = (1<<8), /*!< hardware echo canceller is disabled when there are no calls on this channel */ FTDM_CHANNEL_FEATURE_IO_STATS = (1<<9), /*!< Channel supports IO statistics (HDLC channels only) */ + FTDM_CHANNEL_FEATURE_MF_GENERATE = (1<<10), /*!< Channel can generate R2 MF tones (read-only) */ } ftdm_channel_feature_t; /*!< Channel flags. This used to be an enum but we reached the 32bit limit for enums, is safer this way */