[Freeswitch-svn] [commit] r13082 - freeswitch/trunk/src/mod/applications/mod_t38gateway

FreeSWITCH SVN coppice at freeswitch.org
Sun Apr 19 04:46:26 PDT 2009


Author: coppice
Date: Sun Apr 19 06:46:26 2009
New Revision: 13082

Log:
Introduction of the skeleton of a media bug implementing a T.38 gateway, so the
related infrastructure work can take place around it.


Added:
   freeswitch/trunk/src/mod/applications/mod_t38gateway/
   freeswitch/trunk/src/mod/applications/mod_t38gateway/Makefile
   freeswitch/trunk/src/mod/applications/mod_t38gateway/mod_t38gateway.2008.vcproj
   freeswitch/trunk/src/mod/applications/mod_t38gateway/mod_t38gateway.c
   freeswitch/trunk/src/mod/applications/mod_t38gateway/udptl.c
   freeswitch/trunk/src/mod/applications/mod_t38gateway/udptl.h

Added: freeswitch/trunk/src/mod/applications/mod_t38gateway/Makefile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/applications/mod_t38gateway/Makefile	Sun Apr 19 06:46:26 2009
@@ -0,0 +1,6 @@
+BASE=../../../..
+
+LOCAL_SOURCES=udptl.c
+LOCAL_OBJS=udptl.o
+
+include $(BASE)/build/modmake.rules

Added: freeswitch/trunk/src/mod/applications/mod_t38gateway/mod_t38gateway.2008.vcproj
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/applications/mod_t38gateway/mod_t38gateway.2008.vcproj	Sun Apr 19 06:46:26 2009
@@ -0,0 +1,291 @@
+<?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="&quot;$(InputDir)..\..\..\..\libs\spandsp\src\msvc&quot;;&quot;$(InputDir)..\..\..\..\libs\spandsp\src&quot;;&quot;$(InputDir)..\..\..\..\libs\tiff-3.8.2\libtiff&quot;"
+				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="&quot;$(InputDir)..\..\..\..\libs\spandsp\src\msvc&quot;;&quot;$(InputDir)..\..\..\..\libs\spandsp\src&quot;;&quot;$(InputDir)..\..\..\..\libs\tiff-3.8.2\libtiff&quot;"
+				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="&quot;$(InputDir)..\..\..\..\libs\spandsp\src\msvc&quot;;&quot;$(InputDir)..\..\..\..\libs\spandsp\src&quot;;&quot;$(InputDir)..\..\..\..\libs\tiff-3.8.2\libtiff&quot;"
+				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="&quot;$(InputDir)..\..\..\..\libs\spandsp\src\msvc&quot;;&quot;$(InputDir)..\..\..\..\libs\spandsp\src&quot;;&quot;$(InputDir)..\..\..\..\libs\tiff-3.8.2\libtiff&quot;"
+				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>

Added: freeswitch/trunk/src/mod/applications/mod_t38gateway/mod_t38gateway.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/applications/mod_t38gateway/mod_t38gateway.c	Sun Apr 19 06:46:26 2009
@@ -0,0 +1,347 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2009, Steve Underwood <steveu at 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 at 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_LOG, 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, t38gateway_callback, t38gateway_info, 0, SMBF_READ_STREAM, &bug);
+
+    if (status != SWITCH_STATUS_SUCCESS) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, 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, 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 expandtab:
+ */

Added: freeswitch/trunk/src/mod/applications/mod_t38gateway/udptl.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/applications/mod_t38gateway/udptl.c	Sun Apr 19 06:46:26 2009
@@ -0,0 +1,596 @@
+//#define UDPTL_DEBUG
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2009, Steve Underwood <steveu at 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 at 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 ------------------------------------------------------------*/

Added: freeswitch/trunk/src/mod/applications/mod_t38gateway/udptl.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/applications/mod_t38gateway/udptl.h	Sun Apr 19 06:46:26 2009
@@ -0,0 +1,170 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2009, Steve Underwood <steveu at 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 at coppice.org>
+ *
+ * udptl.h -- UDPTL handling for T.38
+ *
+ */
+
+#if !defined(_UDPTL_H_)
+#define _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 ------------------------------------------------------------*/



More information about the Freeswitch-svn mailing list