freetdm: Added support for hardware (native) R2 MF generation

This commit is contained in:
Moises Silva 2011-02-24 18:41:07 -05:00
parent c22816c39c
commit 269906c891
11 changed files with 298 additions and 13 deletions

View File

@ -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

View File

@ -37,8 +37,10 @@
*/
#ifdef WIN32
#define _WIN32_WINNT 0x0501 // To make GetSystemTimes visible in windows.h
#include <windows.h>
# if (_WIN32_WINNT < 0x0501)
# error "Need to target at least Windows XP/Server 2003 because GetSystemTimes is needed"
# endif
# include <windows.h>
#else /* LINUX */
#include <stdio.h>

2
libs/freetdm/src/ftdm_dso.c Normal file → Executable file
View File

@ -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:
*/

View File

@ -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 <windows.h>
#endif
#include "private/ftdm_core.h"

View File

@ -185,6 +185,10 @@
RelativePath=".\ftmod_r2.c"
>
</File>
<File
RelativePath=".\ftmod_r2_io_mf_lib.c"
>
</File>
</Filter>
</Files>
<Globals>

39
libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c Normal file → Executable file
View File

@ -47,8 +47,10 @@
#endif
#include <stdio.h>
#include <openr2.h>
#include "freetdm.h"
#include "private/ftdm_core.h"
#include <freetdm.h>
#include <private/ftdm_core.h>
#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:
*/

View File

@ -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 <freetdm.h>
#include <private/ftdm_core.h>
#include <openr2.h>
#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
*/

View File

@ -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 <ftdm_declare.h>
#include <openr2.h>
#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:
*/

13
libs/freetdm/src/include/freetdm.h Normal file → Executable file
View File

@ -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);

2
libs/freetdm/src/include/ftdm_dso.h Normal file → Executable file
View File

@ -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:
*/

1
libs/freetdm/src/include/private/ftdm_types.h Normal file → Executable file
View File

@ -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 */