freetdm: Added support for hardware (native) R2 MF generation
This commit is contained in:
parent
c22816c39c
commit
269906c891
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
||||
*/
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -185,6 +185,10 @@
|
|||
RelativePath=".\ftmod_r2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ftmod_r2_io_mf_lib.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
|
|
|
@ -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:
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
*/
|
|
@ -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:
|
||||
*/
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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:
|
||||
*/
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue