remove mod_t38_gateway
This commit is contained in:
parent
8f32c80318
commit
bdb9ed8b8e
|
@ -1,17 +0,0 @@
|
|||
include $(top_srcdir)/build/modmake.rulesam
|
||||
MODNAME=mod_t38gateway
|
||||
|
||||
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
|
||||
|
||||
SPANDSP_DIR=$(switch_srcdir)/libs/spandsp
|
||||
SPANDSP_BUILDDIR=$(switch_builddir)/libs/spandsp
|
||||
SPANDSP_LA=$(SPANDSP_BUILDDIR)/src/libspandsp.la
|
||||
|
||||
mod_LTLIBRARIES = mod_t38gateway.la
|
||||
mod_t38gateway_la_SOURCES = mod_t38gateway.c udptl.c
|
||||
mod_t38gateway_la_CFLAGS = $(AM_CFLAGS) -I$(SPANDSP_DIR)/src -I$(TIFF_DIR)/libtiff -I$(SPANDSP_BUILDDIR)/src -I$(TIFF_BUILDDIR)/libtiff
|
||||
mod_t38gateway_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(SPANDSP_LA) $(TIFF_LA)
|
||||
mod_t38gateway_la_LDFLAGS = -avoid-version -module -no-undefined -shared -ljpeg
|
||||
|
|
@ -1,291 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="mod_t38gateway"
|
||||
ProjectGUID="{14E4A972-9CFB-436D-B0A5-4943F3F80D47}"
|
||||
RootNamespace="mod_t38gateway"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
<Platform
|
||||
Name="x64"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""$(InputDir)..\..\..\..\libs\spandsp\src\msvc";"$(InputDir)..\..\..\..\libs\spandsp\src";"$(InputDir)..\..\..\..\libs\tiff-3.8.2\libtiff""
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""$(InputDir)..\..\..\..\libs\spandsp\src\msvc";"$(InputDir)..\..\..\..\libs\spandsp\src";"$(InputDir)..\..\..\..\libs\tiff-3.8.2\libtiff""
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""$(InputDir)..\..\..\..\libs\spandsp\src\msvc";"$(InputDir)..\..\..\..\libs\spandsp\src";"$(InputDir)..\..\..\..\libs\tiff-3.8.2\libtiff""
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|x64"
|
||||
ConfigurationType="2"
|
||||
InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""$(InputDir)..\..\..\..\libs\spandsp\src\msvc";"$(InputDir)..\..\..\..\libs\spandsp\src";"$(InputDir)..\..\..\..\libs\tiff-3.8.2\libtiff""
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\mod_t38gateway.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\udptl.c"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -1,349 +0,0 @@
|
|||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2009, Steve Underwood <steveu@coppice.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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* mod_t38gateway.c -- A T.38 gateway
|
||||
*
|
||||
* This module uses the T.38 gateway engine of spandsp to create a T.38 gateway suitable for
|
||||
* V.17, V.29, and V.27ter FAX operation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
|
||||
#include <spandsp.h>
|
||||
#include <spandsp/version.h>
|
||||
|
||||
#include "udptl.h"
|
||||
|
||||
/*! Syntax of the API call. */
|
||||
#define T38GATEWAY_SYNTAX "<uuid> <command>"
|
||||
|
||||
/*! Number of expected parameters in api call. */
|
||||
#define T38GATEWAY_PARAMS 2
|
||||
|
||||
/*! FreeSWITCH CUSTOM event types. */
|
||||
#define T38GATEWAY_EVENT_CNG "t38gateway::cng"
|
||||
#define T38GATEWAY_EVENT_CED "t38gateway::ced"
|
||||
#define T38GATEWAY_EVENT_PAGE "t38gateway::page"
|
||||
|
||||
/* Prototypes */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_t38gateway_shutdown);
|
||||
SWITCH_STANDARD_API(t38gateway_api_main);
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_t38gateway_load);
|
||||
SWITCH_MODULE_DEFINITION(mod_t38gateway, mod_t38gateway_load, NULL, NULL);
|
||||
SWITCH_STANDARD_APP(t38gateway_start_function);
|
||||
|
||||
/*! Type that holds codec information. */
|
||||
typedef struct {
|
||||
/*! The sampling rate of the audio stream. */
|
||||
int rate;
|
||||
/*! The number of channels. */
|
||||
int channels;
|
||||
} t38gateway_codec_info_t;
|
||||
|
||||
/*! Type that holds session information pertinent to the t38gateway module. */
|
||||
typedef struct {
|
||||
/*! Internal FreeSWITCH session. */
|
||||
switch_core_session_t *session;
|
||||
/*! Codec information for the session. */
|
||||
t38gateway_codec_info_t t38gateway_codec;
|
||||
t38_gateway_state_t *t38;
|
||||
t38_core_state_t *t38_core;
|
||||
udptl_state_t *udptl;
|
||||
} t38gateway_session_info_t;
|
||||
|
||||
static int tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
|
||||
{
|
||||
t38gateway_session_info_t *t;
|
||||
|
||||
t = (t38gateway_session_info_t *) user_data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int rx_packet_handler(void *user_data, const uint8_t *buf, int len, int seq_no)
|
||||
{
|
||||
t38gateway_session_info_t *t;
|
||||
|
||||
t = (t38gateway_session_info_t *) user_data;
|
||||
t38_core_rx_ifp_packet(t->t38_core, buf, len, seq_no);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
/*! \brief The callback function that is called when new audio data becomes available
|
||||
*
|
||||
* @author Steve Underwood
|
||||
* @param bug A reference to the media bug.
|
||||
* @param user_data The session information for this call.
|
||||
* @param type The switch callback type.
|
||||
* @return The success or failure of the function.
|
||||
*/
|
||||
static switch_bool_t t38gateway_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
|
||||
{
|
||||
t38gateway_session_info_t *t38gateway_info;
|
||||
switch_codec_t *read_codec;
|
||||
switch_frame_t *frame;
|
||||
int16_t *amp;
|
||||
|
||||
t38gateway_info = (t38gateway_session_info_t *) user_data;
|
||||
if (t38gateway_info == NULL) {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SWITCH_ABC_TYPE_INIT:
|
||||
read_codec = switch_core_session_get_read_codec(t38gateway_info->session);
|
||||
t38gateway_info->t38gateway_codec.rate = read_codec->implementation->samples_per_second;
|
||||
t38gateway_info->t38gateway_codec.channels = read_codec->implementation->number_of_channels;
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_READ_PING:
|
||||
case SWITCH_ABC_TYPE_CLOSE:
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_READ:
|
||||
frame = switch_core_media_bug_get_read_replace_frame(bug);
|
||||
amp = (int16_t *) frame->data;
|
||||
t38_gateway_rx(t38gateway_info->t38, amp, frame->samples);
|
||||
break;
|
||||
case SWITCH_ABC_TYPE_WRITE:
|
||||
case SWITCH_ABC_TYPE_READ_REPLACE:
|
||||
case SWITCH_ABC_TYPE_WRITE_REPLACE:
|
||||
break;
|
||||
}
|
||||
|
||||
return SWITCH_TRUE;
|
||||
}
|
||||
|
||||
/*! \brief FreeSWITCH module loading function
|
||||
*
|
||||
* @author Steve Underwood
|
||||
* @return Load success or failure.
|
||||
*/
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_t38gateway_load)
|
||||
{
|
||||
switch_application_interface_t *app_interface;
|
||||
switch_api_interface_t *api_interface;
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "T.38 gateway enabled\n");
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "t38gateway", "T.38 gateway", "T.38 gateway", t38gateway_start_function, "[start] [stop]", SAF_NONE);
|
||||
|
||||
SWITCH_ADD_API(api_interface, "t38gateway", "T.38 gateway", t38gateway_api_main, T38GATEWAY_SYNTAX);
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*! \brief FreeSWITCH application handler function.
|
||||
* This handles calls made from applications such as LUA and the dialplan
|
||||
*
|
||||
* @author Steve Underwood
|
||||
* @return Success or failure of the function.
|
||||
*/
|
||||
SWITCH_STANDARD_APP(t38gateway_start_function)
|
||||
{
|
||||
switch_media_bug_t *bug;
|
||||
switch_status_t status;
|
||||
switch_channel_t *channel;
|
||||
t38gateway_session_info_t *t38gateway_info;
|
||||
|
||||
if (session == NULL)
|
||||
return;
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
|
||||
/* Is this channel already set? */
|
||||
bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_t38gateway_");
|
||||
/* If yes */
|
||||
if (bug != NULL) {
|
||||
/* If we have a stop remove audio bug */
|
||||
if (strcasecmp(data, "stop") == 0) {
|
||||
switch_channel_set_private(channel, "_t38gateway_", NULL);
|
||||
switch_core_media_bug_remove(session, &bug);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We have already started */
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot run 2 at once on the same channel!\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
t38gateway_info = (t38gateway_session_info_t *) switch_core_session_alloc(session, sizeof(t38gateway_session_info_t));
|
||||
|
||||
t38gateway_info->session = session;
|
||||
t38gateway_info->t38 = t38_gateway_init(NULL, tx_packet_handler, (void *) t38gateway_info);
|
||||
t38gateway_info->t38_core = t38_gateway_get_t38_core_state(t38gateway_info->t38);
|
||||
t38gateway_info->udptl = udptl_init(NULL, UDPTL_ERROR_CORRECTION_REDUNDANCY, 3, 3, rx_packet_handler, (void *) t38gateway_info);
|
||||
|
||||
status = switch_core_media_bug_add(session, "T.38 gateway", NULL, t38gateway_callback, t38gateway_info, 0, SMBF_READ_STREAM, &bug);
|
||||
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failure hooking to stream\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch_channel_set_private(channel, "_t38gateway_", bug);
|
||||
}
|
||||
|
||||
/*! \brief Called when the module shuts down
|
||||
*
|
||||
* @author Steve Underwood
|
||||
* @return The success or failure of the function.
|
||||
*/
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_t38gateway_shutdown)
|
||||
{
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "T.38 gateway disabled\n");
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*! \brief FreeSWITCH API handler function.
|
||||
* This function handles API calls such as the ones from mod_event_socket and in some cases
|
||||
* scripts such as LUA scripts.
|
||||
*
|
||||
* @author Steve Underwood
|
||||
* @return The success or failure of the function.
|
||||
*/
|
||||
SWITCH_STANDARD_API(t38gateway_api_main)
|
||||
{
|
||||
switch_core_session_t *t38gateway_session;
|
||||
switch_media_bug_t *bug;
|
||||
t38gateway_session_info_t *t38gateway_info;
|
||||
switch_channel_t *channel;
|
||||
switch_status_t status;
|
||||
int argc;
|
||||
char *argv[T38GATEWAY_PARAMS];
|
||||
char *ccmd;
|
||||
char *uuid;
|
||||
char *command;
|
||||
|
||||
/* No command? Display usage */
|
||||
if (cmd == NULL) {
|
||||
stream->write_function(stream, "-USAGE: %s\n", T38GATEWAY_SYNTAX);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Duplicated contents of original string */
|
||||
ccmd = strdup(cmd);
|
||||
/* Separate the arguments */
|
||||
argc = switch_separate_string(ccmd, ' ', argv, T38GATEWAY_PARAMS);
|
||||
|
||||
/* If we don't have the expected number of parameters
|
||||
* display usage */
|
||||
if (argc != T38GATEWAY_PARAMS) {
|
||||
stream->write_function(stream, "-USAGE: %s\n", T38GATEWAY_SYNTAX);
|
||||
switch_safe_free(ccmd);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
uuid = argv[0];
|
||||
command = argv[1];
|
||||
|
||||
/* using uuid locate a reference to the FreeSWITCH session */
|
||||
t38gateway_session = switch_core_session_locate(uuid);
|
||||
|
||||
/* If the session was not found exit */
|
||||
if (t38gateway_session == NULL) {
|
||||
switch_safe_free(ccmd);
|
||||
stream->write_function(stream, "-USAGE: %s\n", T38GATEWAY_SYNTAX);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* Get current channel of the session to tag the session
|
||||
* This indicates that our module is present */
|
||||
channel = switch_core_session_get_channel(t38gateway_session);
|
||||
|
||||
/* Is this channel already set? */
|
||||
bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_t38gateway_");
|
||||
/* If yes */
|
||||
if (bug != NULL) {
|
||||
/* If we have a stop remove audio bug */
|
||||
if (strcasecmp(command, "stop") == 0) {
|
||||
switch_channel_set_private(channel, "_t38gateway_", NULL);
|
||||
switch_core_media_bug_remove(t38gateway_session, &bug);
|
||||
switch_safe_free(ccmd);
|
||||
stream->write_function(stream, "+OK\n");
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* We have already started */
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot run 2 at once on the same channel!\n");
|
||||
|
||||
switch_safe_free(ccmd);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* If we don't see the expected start exit */
|
||||
if (strcasecmp(command, "start") != 0) {
|
||||
switch_safe_free(ccmd);
|
||||
stream->write_function(stream, "-USAGE: %s\n", T38GATEWAY_SYNTAX);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* Allocate memory attached to this FreeSWITCH session for
|
||||
* use in the callback routine and to store state information */
|
||||
t38gateway_info = (t38gateway_session_info_t *) switch_core_session_alloc(t38gateway_session, sizeof(t38gateway_session_info_t));
|
||||
|
||||
/* Set initial values and states */
|
||||
t38gateway_info->session = t38gateway_session;
|
||||
t38gateway_info->t38 = t38_gateway_init(NULL, tx_packet_handler, (void *) t38gateway_info);
|
||||
t38gateway_info->t38_core = t38_gateway_get_t38_core_state(t38gateway_info->t38);
|
||||
t38gateway_info->udptl = udptl_init(NULL, UDPTL_ERROR_CORRECTION_REDUNDANCY, 3, 3, rx_packet_handler, (void *) t38gateway_info);
|
||||
|
||||
/* Add a media bug that allows me to intercept the
|
||||
* reading leg of the audio stream */
|
||||
status = switch_core_media_bug_add(t38gateway_session, "T.38 gateway", NULL, t38gateway_callback, t38gateway_info, 0, SMBF_READ_STREAM, &bug);
|
||||
|
||||
/* If adding a media bug fails exit */
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failure hooking to stream\n");
|
||||
|
||||
switch_safe_free(ccmd);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* Set the t38gateway tag to detect an existing t38gateway media bug */
|
||||
switch_channel_set_private(channel, "_t38gateway_", bug);
|
||||
|
||||
/* Everything went according to plan! Notify the user */
|
||||
stream->write_function(stream, "+OK\n");
|
||||
|
||||
switch_safe_free(ccmd);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* 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:
|
||||
*/
|
|
@ -1,563 +0,0 @@
|
|||
//#define UDPTL_DEBUG
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2009, Steve Underwood <steveu@coppice.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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* udptl.c -- UDPTL handling for T.38
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "udptl.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE (!FALSE)
|
||||
|
||||
static int decode_length(const uint8_t *buf, int limit, int *len, int *pvalue)
|
||||
{
|
||||
if (*len >= limit)
|
||||
return -1;
|
||||
if ((buf[*len] & 0x80) == 0) {
|
||||
*pvalue = buf[(*len)++];
|
||||
return 0;
|
||||
}
|
||||
if ((buf[*len] & 0x40) == 0) {
|
||||
if (*len >= limit - 1)
|
||||
return -1;
|
||||
*pvalue = (buf[(*len)++] & 0x3F) << 8;
|
||||
*pvalue |= buf[(*len)++];
|
||||
return 0;
|
||||
}
|
||||
*pvalue = (buf[(*len)++] & 0x3F) << 14;
|
||||
/* Indicate we have a fragment */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int decode_open_type(const uint8_t *buf, int limit, int *len, const uint8_t ** p_object, int *p_num_octets)
|
||||
{
|
||||
int octet_cnt;
|
||||
int octet_idx;
|
||||
int stat;
|
||||
int i;
|
||||
const uint8_t **pbuf;
|
||||
|
||||
for (octet_idx = 0, *p_num_octets = 0;; octet_idx += octet_cnt) {
|
||||
if ((stat = decode_length(buf, limit, len, &octet_cnt)) < 0)
|
||||
return -1;
|
||||
if (octet_cnt > 0) {
|
||||
*p_num_octets += octet_cnt;
|
||||
|
||||
pbuf = &p_object[octet_idx];
|
||||
i = 0;
|
||||
/* Make sure the buffer contains at least the number of bits requested */
|
||||
if ((*len + octet_cnt) > limit)
|
||||
return -1;
|
||||
|
||||
*pbuf = &buf[*len];
|
||||
*len += octet_cnt;
|
||||
}
|
||||
if (stat == 0)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int encode_length(uint8_t *buf, int *len, int value)
|
||||
{
|
||||
int multiplier;
|
||||
|
||||
if (value < 0x80) {
|
||||
/* 1 octet */
|
||||
buf[(*len)++] = value;
|
||||
return value;
|
||||
}
|
||||
if (value < 0x4000) {
|
||||
/* 2 octets */
|
||||
/* Set the first bit of the first octet */
|
||||
buf[(*len)++] = ((0x8000 | value) >> 8) & 0xFF;
|
||||
buf[(*len)++] = value & 0xFF;
|
||||
return value;
|
||||
}
|
||||
/* Fragmentation */
|
||||
multiplier = (value < 0x10000) ? (value >> 14) : 4;
|
||||
/* Set the first 2 bits of the octet */
|
||||
buf[(*len)++] = 0xC0 | multiplier;
|
||||
return multiplier << 14;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int encode_open_type(uint8_t *buf, int *len, const uint8_t *data, int num_octets)
|
||||
{
|
||||
int enclen;
|
||||
int octet_idx;
|
||||
uint8_t zero_byte;
|
||||
|
||||
/* If open type is of zero length, add a single zero byte (10.1) */
|
||||
if (num_octets == 0) {
|
||||
zero_byte = 0;
|
||||
data = &zero_byte;
|
||||
num_octets = 1;
|
||||
}
|
||||
/* Encode the open type */
|
||||
for (octet_idx = 0;; num_octets -= enclen, octet_idx += enclen) {
|
||||
if ((enclen = encode_length(buf, len, num_octets)) < 0)
|
||||
return -1;
|
||||
if (enclen > 0) {
|
||||
memcpy(&buf[*len], &data[octet_idx], enclen);
|
||||
*len += enclen;
|
||||
}
|
||||
if (enclen >= num_octets)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len)
|
||||
{
|
||||
int stat;
|
||||
int stat2;
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
int l;
|
||||
int m;
|
||||
int x;
|
||||
int limit;
|
||||
int which;
|
||||
int ptr;
|
||||
int count;
|
||||
int total_count;
|
||||
int seq_no;
|
||||
const uint8_t *msg;
|
||||
const uint8_t *data;
|
||||
int msg_len;
|
||||
int repaired[16];
|
||||
const uint8_t *bufs[16];
|
||||
int lengths[16];
|
||||
int span;
|
||||
int entries;
|
||||
|
||||
ptr = 0;
|
||||
/* Decode seq_number */
|
||||
if (ptr + 2 > len)
|
||||
return -1;
|
||||
seq_no = (buf[0] << 8) | buf[1];
|
||||
ptr += 2;
|
||||
/* Break out the primary packet */
|
||||
if ((stat = decode_open_type(buf, len, &ptr, &msg, &msg_len)) != 0)
|
||||
return -1;
|
||||
/* Decode error_recovery */
|
||||
if (ptr + 1 > len)
|
||||
return -1;
|
||||
/* Our buffers cannot tolerate overlength packets */
|
||||
if (msg_len > LOCAL_FAX_MAX_DATAGRAM)
|
||||
return -1;
|
||||
/* Update any missed slots in the buffer */
|
||||
for (i = s->rx_seq_no; seq_no > i; i++) {
|
||||
x = i & UDPTL_BUF_MASK;
|
||||
s->rx[x].buf_len = -1;
|
||||
s->rx[x].fec_len[0] = 0;
|
||||
s->rx[x].fec_span = 0;
|
||||
s->rx[x].fec_entries = 0;
|
||||
}
|
||||
/* Save the new packet. Pure redundancy mode won't use this, but some systems will switch
|
||||
into FEC mode after sending some redundant packets. */
|
||||
x = seq_no & UDPTL_BUF_MASK;
|
||||
memcpy(s->rx[x].buf, msg, msg_len);
|
||||
s->rx[x].buf_len = msg_len;
|
||||
s->rx[x].fec_len[0] = 0;
|
||||
s->rx[x].fec_span = 0;
|
||||
s->rx[x].fec_entries = 0;
|
||||
if ((buf[ptr++] & 0x80) == 0) {
|
||||
/* Secondary packet mode for error recovery */
|
||||
/* We might have the packet we want, but we need to check through
|
||||
the redundant stuff, and verify the integrity of the UDPTL.
|
||||
This greatly reduces our chances of accepting garbage. */
|
||||
total_count = 0;
|
||||
do {
|
||||
if ((stat2 = decode_length(buf, len, &ptr, &count)) < 0)
|
||||
return -1;
|
||||
for (i = 0; i < count; i++) {
|
||||
if ((stat = decode_open_type(buf, len, &ptr, &bufs[total_count + i], &lengths[total_count + i])) != 0)
|
||||
return -1;
|
||||
}
|
||||
total_count += count;
|
||||
}
|
||||
while (stat2 > 0);
|
||||
/* We should now be exactly at the end of the packet. If not, this is a fault. */
|
||||
if (ptr != len)
|
||||
return -1;
|
||||
if (seq_no > s->rx_seq_no) {
|
||||
/* We received a later packet than we expected, so we need to check if we can fill in the gap from the
|
||||
secondary packets. */
|
||||
/* Step through in reverse order, so we go oldest to newest */
|
||||
for (i = total_count; i > 0; i--) {
|
||||
if (seq_no - i >= s->rx_seq_no) {
|
||||
/* This one wasn't seen before */
|
||||
/* Decode the secondary packet */
|
||||
#if defined(UDPTL_DEBUG)
|
||||
fprintf(stderr, "Secondary %d, len %d\n", seq_no - i, lengths[i - 1]);
|
||||
#endif
|
||||
/* Save the new packet. Redundancy mode won't use this, but some systems will switch into
|
||||
FEC mode after sending some redundant packets, and this may then be important. */
|
||||
x = (seq_no - i) & UDPTL_BUF_MASK;
|
||||
memcpy(s->rx[x].buf, bufs[i - 1], lengths[i - 1]);
|
||||
s->rx[x].buf_len = lengths[i - 1];
|
||||
s->rx[x].fec_len[0] = 0;
|
||||
s->rx[x].fec_span = 0;
|
||||
s->rx[x].fec_entries = 0;
|
||||
if (s->rx_packet_handler(s->user_data, bufs[i - 1], lengths[i - 1], seq_no - i) < 0)
|
||||
fprintf(stderr, "Bad IFP\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* FEC mode for error recovery */
|
||||
|
||||
/* Decode the FEC packets */
|
||||
/* The span is defined as an unconstrained integer, but will never be more
|
||||
than a small value. */
|
||||
if (ptr + 2 > len)
|
||||
return -1;
|
||||
if (buf[ptr++] != 1)
|
||||
return -1;
|
||||
span = buf[ptr++];
|
||||
|
||||
x = seq_no & UDPTL_BUF_MASK;
|
||||
|
||||
s->rx[x].fec_span = span;
|
||||
|
||||
memset(repaired, 0, sizeof(repaired));
|
||||
repaired[x] = TRUE;
|
||||
|
||||
/* The number of entries is defined as a length, but will only ever be a small
|
||||
value. Treat it as such. */
|
||||
if (ptr + 1 > len)
|
||||
return -1;
|
||||
entries = buf[ptr++];
|
||||
s->rx[x].fec_entries = entries;
|
||||
|
||||
/* Decode the elements */
|
||||
for (i = 0; i < entries; i++) {
|
||||
if ((stat = decode_open_type(buf, len, &ptr, &data, &s->rx[x].fec_len[i])) != 0)
|
||||
return -1;
|
||||
if (s->rx[x].fec_len[i] > LOCAL_FAX_MAX_DATAGRAM)
|
||||
return -1;
|
||||
|
||||
/* Save the new FEC data */
|
||||
memcpy(s->rx[x].fec[i], data, s->rx[x].fec_len[i]);
|
||||
#if 0
|
||||
fprintf(stderr, "FEC: ");
|
||||
for (j = 0; j < s->rx[x].fec_len[i]; j++)
|
||||
fprintf(stderr, "%02X ", data[j]);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
}
|
||||
/* We should now be exactly at the end of the packet. If not, this is a fault. */
|
||||
if (ptr != len)
|
||||
return -1;
|
||||
/* See if we can reconstruct anything which is missing */
|
||||
/* TODO: this does not comprehensively hunt back and repair everything that is possible */
|
||||
for (l = x; l != ((x - (16 - span * entries)) & UDPTL_BUF_MASK); l = (l - 1) & UDPTL_BUF_MASK) {
|
||||
if (s->rx[l].fec_len[0] <= 0)
|
||||
continue;
|
||||
for (m = 0; m < s->rx[l].fec_entries; m++) {
|
||||
limit = (l + m) & UDPTL_BUF_MASK;
|
||||
for (which = -1, k = (limit - s->rx[l].fec_span * s->rx[l].fec_entries) & UDPTL_BUF_MASK; k != limit;
|
||||
k = (k + s->rx[l].fec_entries) & UDPTL_BUF_MASK) {
|
||||
if (s->rx[k].buf_len <= 0)
|
||||
which = (which == -1) ? k : -2;
|
||||
}
|
||||
if (which >= 0) {
|
||||
/* Repairable */
|
||||
for (j = 0; j < s->rx[l].fec_len[m]; j++) {
|
||||
s->rx[which].buf[j] = s->rx[l].fec[m][j];
|
||||
for (k = (limit - s->rx[l].fec_span * s->rx[l].fec_entries) & UDPTL_BUF_MASK; k != limit;
|
||||
k = (k + s->rx[l].fec_entries) & UDPTL_BUF_MASK)
|
||||
s->rx[which].buf[j] ^= (s->rx[k].buf_len > j) ? s->rx[k].buf[j] : 0;
|
||||
}
|
||||
s->rx[which].buf_len = s->rx[l].fec_len[m];
|
||||
repaired[which] = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Now play any new packets forwards in time */
|
||||
for (l = (x + 1) & UDPTL_BUF_MASK, j = seq_no - UDPTL_BUF_MASK; l != x; l = (l + 1) & UDPTL_BUF_MASK, j++) {
|
||||
if (repaired[l]) {
|
||||
#if defined(UDPTL_DEBUG)
|
||||
fprintf(stderr, "Fixed packet %d, len %d\n", j, l);
|
||||
#endif
|
||||
if (s->rx_packet_handler(s->user_data, s->rx[l].buf, s->rx[l].buf_len, j) < 0)
|
||||
fprintf(stderr, "Bad IFP\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If packets are received out of sequence, we may have already processed this packet from the error
|
||||
recovery information in a packet already received. */
|
||||
if (seq_no >= s->rx_seq_no) {
|
||||
/* Decode the primary packet */
|
||||
#if defined(UDPTL_DEBUG)
|
||||
fprintf(stderr, "Primary packet %d, len %d\n", seq_no, msg_len);
|
||||
#endif
|
||||
if (s->rx_packet_handler(s->user_data, msg, msg_len, seq_no) < 0)
|
||||
fprintf(stderr, "Bad IFP\n");
|
||||
}
|
||||
|
||||
s->rx_seq_no = (seq_no + 1) & 0xFFFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int udptl_build_packet(udptl_state_t *s, uint8_t buf[], const uint8_t msg[], int msg_len)
|
||||
{
|
||||
uint8_t fec[LOCAL_FAX_MAX_DATAGRAM];
|
||||
int i;
|
||||
int j;
|
||||
int seq;
|
||||
int entry;
|
||||
int entries;
|
||||
int span;
|
||||
int m;
|
||||
int len;
|
||||
int limit;
|
||||
int high_tide;
|
||||
|
||||
/* UDPTL cannot cope with zero length messages, and our buffering for redundancy limits their
|
||||
maximum length. */
|
||||
if (msg_len < 1 || msg_len > LOCAL_FAX_MAX_DATAGRAM)
|
||||
return -1;
|
||||
seq = s->tx_seq_no & 0xFFFF;
|
||||
|
||||
/* Map the sequence number to an entry in the circular buffer */
|
||||
entry = seq & UDPTL_BUF_MASK;
|
||||
|
||||
/* We save the message in a circular buffer, for generating FEC or
|
||||
redundancy sets later on. */
|
||||
s->tx[entry].buf_len = msg_len;
|
||||
memcpy(s->tx[entry].buf, msg, msg_len);
|
||||
|
||||
/* Build the UDPTL packet */
|
||||
|
||||
len = 0;
|
||||
/* Encode the sequence number */
|
||||
buf[len++] = (seq >> 8) & 0xFF;
|
||||
buf[len++] = seq & 0xFF;
|
||||
|
||||
/* Encode the primary packet */
|
||||
if (encode_open_type(buf, &len, msg, msg_len) < 0)
|
||||
return -1;
|
||||
|
||||
/* Encode the appropriate type of error recovery information */
|
||||
switch (s->error_correction_scheme) {
|
||||
case UDPTL_ERROR_CORRECTION_NONE:
|
||||
/* Encode the error recovery type */
|
||||
buf[len++] = 0x00;
|
||||
/* The number of entries will always be zero, so it is pointless allowing
|
||||
for the fragmented case here. */
|
||||
if (encode_length(buf, &len, 0) < 0)
|
||||
return -1;
|
||||
break;
|
||||
case UDPTL_ERROR_CORRECTION_REDUNDANCY:
|
||||
/* Encode the error recovery type */
|
||||
buf[len++] = 0x00;
|
||||
if (s->tx_seq_no > s->error_correction_entries)
|
||||
entries = s->error_correction_entries;
|
||||
else
|
||||
entries = s->tx_seq_no;
|
||||
/* The number of entries will always be small, so it is pointless allowing
|
||||
for the fragmented case here. */
|
||||
if (encode_length(buf, &len, entries) < 0)
|
||||
return -1;
|
||||
/* Encode the elements */
|
||||
for (i = 0; i < entries; i++) {
|
||||
j = (entry - i - 1) & UDPTL_BUF_MASK;
|
||||
if (encode_open_type(buf, &len, s->tx[j].buf, s->tx[j].buf_len) < 0)
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case UDPTL_ERROR_CORRECTION_FEC:
|
||||
span = s->error_correction_span;
|
||||
entries = s->error_correction_entries;
|
||||
if (seq < s->error_correction_span * s->error_correction_entries) {
|
||||
/* In the initial stages, wind up the FEC smoothly */
|
||||
entries = seq / s->error_correction_span;
|
||||
if (seq < s->error_correction_span)
|
||||
span = 0;
|
||||
}
|
||||
/* Encode the error recovery type */
|
||||
buf[len++] = 0x80;
|
||||
/* Span is defined as an inconstrained integer, which it dumb. It will only
|
||||
ever be a small value. Treat it as such. */
|
||||
buf[len++] = 1;
|
||||
buf[len++] = span;
|
||||
/* The number of entries is defined as a length, but will only ever be a small
|
||||
value. Treat it as such. */
|
||||
buf[len++] = entries;
|
||||
for (m = 0; m < entries; m++) {
|
||||
/* Make an XOR'ed entry the maximum length */
|
||||
limit = (entry + m) & UDPTL_BUF_MASK;
|
||||
high_tide = 0;
|
||||
for (i = (limit - span * entries) & UDPTL_BUF_MASK; i != limit; i = (i + entries) & UDPTL_BUF_MASK) {
|
||||
if (high_tide < s->tx[i].buf_len) {
|
||||
for (j = 0; j < high_tide; j++)
|
||||
fec[j] ^= s->tx[i].buf[j];
|
||||
for (; j < s->tx[i].buf_len; j++)
|
||||
fec[j] = s->tx[i].buf[j];
|
||||
high_tide = s->tx[i].buf_len;
|
||||
} else {
|
||||
for (j = 0; j < s->tx[i].buf_len; j++)
|
||||
fec[j] ^= s->tx[i].buf[j];
|
||||
}
|
||||
}
|
||||
if (encode_open_type(buf, &len, fec, high_tide) < 0)
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (s->verbose)
|
||||
fprintf(stderr, "\n");
|
||||
s->tx_seq_no++;
|
||||
return len;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int udptl_set_error_correction(udptl_state_t *s, int ec_scheme, int span, int entries)
|
||||
{
|
||||
switch (ec_scheme) {
|
||||
case UDPTL_ERROR_CORRECTION_FEC:
|
||||
case UDPTL_ERROR_CORRECTION_REDUNDANCY:
|
||||
case UDPTL_ERROR_CORRECTION_NONE:
|
||||
s->error_correction_scheme = ec_scheme;
|
||||
break;
|
||||
case -1:
|
||||
/* Just don't change the scheme */
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
if (span >= 0)
|
||||
s->error_correction_span = span;
|
||||
if (entries >= 0)
|
||||
s->error_correction_entries = entries;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int udptl_get_error_correction(udptl_state_t *s, int *ec_scheme, int *span, int *entries)
|
||||
{
|
||||
if (ec_scheme)
|
||||
*ec_scheme = s->error_correction_scheme;
|
||||
if (span)
|
||||
*span = s->error_correction_span;
|
||||
if (entries)
|
||||
*entries = s->error_correction_entries;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int udptl_set_local_max_datagram(udptl_state_t *s, int max_datagram)
|
||||
{
|
||||
s->local_max_datagram_size = max_datagram;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int udptl_get_local_max_datagram(udptl_state_t *s)
|
||||
{
|
||||
return s->local_max_datagram_size;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int udptl_set_far_max_datagram(udptl_state_t *s, int max_datagram)
|
||||
{
|
||||
s->far_max_datagram_size = max_datagram;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int udptl_get_far_max_datagram(udptl_state_t *s)
|
||||
{
|
||||
return s->far_max_datagram_size;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
udptl_state_t *udptl_init(udptl_state_t *s, int ec_scheme, int span, int entries, udptl_rx_packet_handler_t rx_packet_handler, void *user_data)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (rx_packet_handler == NULL)
|
||||
return NULL;
|
||||
|
||||
if (s == NULL) {
|
||||
if ((s = (udptl_state_t *) malloc(sizeof(*s))) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
s->error_correction_scheme = ec_scheme;
|
||||
s->error_correction_span = span;
|
||||
s->error_correction_entries = entries;
|
||||
|
||||
s->far_max_datagram_size = LOCAL_FAX_MAX_DATAGRAM;
|
||||
s->local_max_datagram_size = LOCAL_FAX_MAX_DATAGRAM;
|
||||
|
||||
memset(&s->rx, 0, sizeof(s->rx));
|
||||
memset(&s->tx, 0, sizeof(s->tx));
|
||||
for (i = 0; i <= UDPTL_BUF_MASK; i++) {
|
||||
s->rx[i].buf_len = -1;
|
||||
s->tx[i].buf_len = -1;
|
||||
}
|
||||
|
||||
s->rx_packet_handler = rx_packet_handler;
|
||||
s->user_data = user_data;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int udptl_release(udptl_state_t *s)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
|
@ -1,153 +0,0 @@
|
|||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2009, Steve Underwood <steveu@coppice.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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* udptl.h -- UDPTL handling for T.38
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(FREESWITCH_UDPTL_H)
|
||||
#define FREESWITCH_UDPTL_H
|
||||
|
||||
#define LOCAL_FAX_MAX_DATAGRAM 400
|
||||
#define LOCAL_FAX_MAX_FEC_PACKETS 5
|
||||
|
||||
#define UDPTL_BUF_MASK 15
|
||||
|
||||
typedef int (udptl_rx_packet_handler_t) (void *user_data, const uint8_t msg[], int len, int seq_no);
|
||||
|
||||
typedef struct {
|
||||
int buf_len;
|
||||
uint8_t buf[LOCAL_FAX_MAX_DATAGRAM];
|
||||
} udptl_fec_tx_buffer_t;
|
||||
|
||||
typedef struct {
|
||||
int buf_len;
|
||||
uint8_t buf[LOCAL_FAX_MAX_DATAGRAM];
|
||||
int fec_len[LOCAL_FAX_MAX_FEC_PACKETS];
|
||||
uint8_t fec[LOCAL_FAX_MAX_FEC_PACKETS][LOCAL_FAX_MAX_DATAGRAM];
|
||||
int fec_span;
|
||||
int fec_entries;
|
||||
} udptl_fec_rx_buffer_t;
|
||||
|
||||
struct udptl_state_s {
|
||||
udptl_rx_packet_handler_t *rx_packet_handler;
|
||||
void *user_data;
|
||||
|
||||
/*! This option indicates the error correction scheme used in transmitted UDPTL
|
||||
packets. */
|
||||
int error_correction_scheme;
|
||||
|
||||
/*! This option indicates the number of error correction entries transmitted in
|
||||
UDPTL packets. */
|
||||
int error_correction_entries;
|
||||
|
||||
/*! This option indicates the span of the error correction entries in transmitted
|
||||
UDPTL packets (FEC only). */
|
||||
int error_correction_span;
|
||||
|
||||
/*! This option indicates the maximum size of a datagram that can be accepted by
|
||||
the remote device. */
|
||||
int far_max_datagram_size;
|
||||
|
||||
/*! This option indicates the maximum size of a datagram that we are prepared to
|
||||
accept. */
|
||||
int local_max_datagram_size;
|
||||
|
||||
int verbose;
|
||||
|
||||
int tx_seq_no;
|
||||
int rx_seq_no;
|
||||
int rx_expected_seq_no;
|
||||
|
||||
udptl_fec_tx_buffer_t tx[UDPTL_BUF_MASK + 1];
|
||||
udptl_fec_rx_buffer_t rx[UDPTL_BUF_MASK + 1];
|
||||
};
|
||||
|
||||
enum {
|
||||
UDPTL_ERROR_CORRECTION_NONE,
|
||||
UDPTL_ERROR_CORRECTION_FEC,
|
||||
UDPTL_ERROR_CORRECTION_REDUNDANCY
|
||||
};
|
||||
|
||||
typedef struct udptl_state_s udptl_state_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \brief Process an arriving UDPTL packet.
|
||||
\param s The UDPTL context.
|
||||
\param buf The UDPTL packet buffer.
|
||||
\param len The length of the packet.
|
||||
\return 0 for OK. */
|
||||
int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len);
|
||||
|
||||
/*! \brief Construct a UDPTL packet, ready for transmission.
|
||||
\param s The UDPTL context.
|
||||
\param buf The UDPTL packet buffer.
|
||||
\param msg The primary packet.
|
||||
\param len The length of the primary packet.
|
||||
\return The length of the constructed UDPTL packet. */
|
||||
int udptl_build_packet(udptl_state_t *s, uint8_t buf[], const uint8_t msg[], int msg_len);
|
||||
|
||||
/*! \brief Change the error correction settings of a UDPTL context.
|
||||
\param s The UDPTL context.
|
||||
\param ec_scheme One of the optional error correction schemes.
|
||||
\param span The packet span over which error correction should be applied.
|
||||
\param entries The number of error correction entries to include in packets.
|
||||
\return 0 for OK. */
|
||||
int udptl_set_error_correction(udptl_state_t *s, int ec_scheme, int span, int entries);
|
||||
|
||||
/*! \brief Check the error correction settings of a UDPTL context.
|
||||
\param s The UDPTL context.
|
||||
\param ec_scheme One of the optional error correction schemes.
|
||||
\param span The packet span over which error correction is being applied.
|
||||
\param entries The number of error correction being included in packets.
|
||||
\return 0 for OK. */
|
||||
int udptl_get_error_correction(udptl_state_t *s, int *ec_scheme, int *span, int *entries);
|
||||
|
||||
int udptl_set_local_max_datagram(udptl_state_t *s, int max_datagram);
|
||||
|
||||
int udptl_get_local_max_datagram(udptl_state_t *s);
|
||||
|
||||
int udptl_set_far_max_datagram(udptl_state_t *s, int max_datagram);
|
||||
|
||||
int udptl_get_far_max_datagram(udptl_state_t *s);
|
||||
|
||||
/*! \brief Initialise a UDPTL context.
|
||||
\param s The UDPTL context.
|
||||
\param ec_scheme One of the optional error correction schemes.
|
||||
\param span The packet span over which error correction should be applied.
|
||||
\param entries The number of error correction entries to include in packets.
|
||||
\param rx_packet_handler The callback function, used to report arriving IFP packets.
|
||||
\param user_data An opaque pointer supplied to rx_packet_handler.
|
||||
\return A pointer to the UDPTL context, or NULL if there was a problem. */
|
||||
udptl_state_t *udptl_init(udptl_state_t *s, int ec_scheme, int span, int entries, udptl_rx_packet_handler_t rx_packet_handler, void *user_data);
|
||||
|
||||
/*! \brief Release a UDPTL context.
|
||||
\param s The UDPTL context.
|
||||
\return 0 for OK. */
|
||||
int udptl_release(udptl_state_t *s);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
/*- End of file ------------------------------------------------------------*/
|
Loading…
Reference in New Issue