Merge branch 'master' into netborder

Conflicts:
	libs/freetdm/src/ftdm_io.c
	libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c
	libs/freetdm/src/include/freetdm.h
This commit is contained in:
Moises Silva
2011-01-05 13:11:37 -05:00
224 changed files with 13786 additions and 6134 deletions
+3 -3
View File
@@ -9,9 +9,9 @@ CXXFLAGS=$(BASE_FLAGS) -Wall -Werror -Wno-unused-variable
MYLIB=libesl.a
LIBS=-lncurses -lpthread -lesl -lm
LDFLAGS=-L.
OBJS=src/esl.o src/esl_event.o src/esl_threadmutex.o src/esl_config.o src/esl_json.o
SRC=src/esl.c src/esl_json.c src/esl_event.c src/esl_threadmutex.c src/esl_config.c src/esl_oop.cpp src/esl_json.c
HEADERS=src/include/esl_config.h src/include/esl_event.h src/include/esl.h src/include/esl_threadmutex.h src/include/esl_oop.h src/include/esl_json.h
OBJS=src/esl.o src/esl_event.o src/esl_threadmutex.o src/esl_config.o src/esl_json.o src/esl_buffer.o
SRC=src/esl.c src/esl_json.c src/esl_event.c src/esl_threadmutex.c src/esl_config.c src/esl_oop.cpp src/esl_json.c src/esl_buffer.c
HEADERS=src/include/esl_config.h src/include/esl_event.h src/include/esl.h src/include/esl_threadmutex.h src/include/esl_oop.h src/include/esl_json.h src/include/esl_buffer.h
SOLINK=-shared -Xlinker -x
# comment the next line to disable c++ (no swig mods for you then)
OBJS += src/esl_oop.o
+2 -2
View File
@@ -656,7 +656,7 @@ static int process_command(esl_handle_t *handle, const char *cmd)
"-----------------------------------------------\n"
"/help \tHelp\n"
"/exit, /quit, /bye, ... \tExit the program.\n"
"/event, /noevent, /nixevent\tEvent commands.\n"
"/event, /noevents, /nixevent\tEvent commands.\n"
"/log, /nolog \tLog commands.\n"
"/uuid \tFilter logs for a single call uuid\n"
"/filter \tFilter commands.\n"
@@ -692,7 +692,7 @@ static int process_command(esl_handle_t *handle, const char *cmd)
} else if (
!strncasecmp(cmd, "event", 5) ||
!strncasecmp(cmd, "noevent", 7) ||
!strncasecmp(cmd, "noevents", 8) ||
!strncasecmp(cmd, "nixevent", 8) ||
!strncasecmp(cmd, "log", 3) ||
!strncasecmp(cmd, "nolog", 5) ||
+26
View File
@@ -0,0 +1,26 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ESL", "esl_lua.2008.vcproj", "{86B6AB99-A261-455A-9CD6-9142A5A1652E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{86B6AB99-A261-455A-9CD6-9142A5A1652E}.Debug|Win32.ActiveCfg = Debug|Win32
{86B6AB99-A261-455A-9CD6-9142A5A1652E}.Debug|Win32.Build.0 = Debug|Win32
{86B6AB99-A261-455A-9CD6-9142A5A1652E}.Debug|x64.ActiveCfg = Debug|x64
{86B6AB99-A261-455A-9CD6-9142A5A1652E}.Debug|x64.Build.0 = Debug|x64
{86B6AB99-A261-455A-9CD6-9142A5A1652E}.Release|Win32.ActiveCfg = Release|Win32
{86B6AB99-A261-455A-9CD6-9142A5A1652E}.Release|Win32.Build.0 = Release|Win32
{86B6AB99-A261-455A-9CD6-9142A5A1652E}.Release|x64.ActiveCfg = Release|x64
{86B6AB99-A261-455A-9CD6-9142A5A1652E}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+351
View File
@@ -0,0 +1,351 @@
<?xml version="1.0" encoding="UTF-8"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="ESL"
ProjectGUID="{86B6AB99-A261-455A-9CD6-9142A5A1652E}"
RootNamespace="esl_lua.2008"
Keyword="Win32Proj"
TargetFrameworkVersion="0"
>
<Platforms>
<Platform
Name="Win32"
/>
<Platform
Name="x64"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\&quot;;&quot;$(ProjectDir)..\src\include&quot;"
PreprocessorDefinitions="ESL_DECLARE_STATIC;WIN32"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="esl.lib lua5.1.lib ws2_32.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;$(ProjectDir)..\..\..\$(ConfigurationName)&quot;;&quot;$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\$(ConfigurationName)&quot;"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="1"
/>
<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"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\&quot;;&quot;$(ProjectDir)..\src\include&quot;"
PreprocessorDefinitions="ESL_DECLARE_STATIC;WIN32"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="esl.lib lua5.1.lib ws2_32.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;$(ProjectDir)..\..\..\$(ConfigurationName)&quot;;&quot;$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\$(ConfigurationName)&quot;"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<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"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\&quot;;&quot;$(ProjectDir)..\src\include&quot;"
PreprocessorDefinitions="ESL_DECLARE_STATIC;WIN32"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="esl.lib lua5.1.lib ws2_32.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;$(ProjectDir)..\..\..\$(PlatformName)\$(ConfigurationName)&quot;;&quot;$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\$(PlatformName)\$(ConfigurationName)&quot;"
GenerateDebugInformation="true"
SubSystem="2"
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|x64"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\&quot;;&quot;$(ProjectDir)..\src\include&quot;"
PreprocessorDefinitions="ESL_DECLARE_STATIC;WIN32"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="esl.lib lua5.1.lib ws2_32.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;$(ProjectDir)..\..\..\$(PlatformName)\$(ConfigurationName)&quot;;&quot;$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\$(PlatformName)\$(ConfigurationName)&quot;"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
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>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\src\esl_oop.cpp"
>
</File>
<File
RelativePath=".\esl_wrap.cpp"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
+3 -2
View File
@@ -40,7 +40,8 @@ sub set_callback($;$$) {
$self->{_callback}->{$event} = shift;
my $subclass = shift;
if($subclass) {
$self->{_custom_subclass} = split(/,/, $subclass);
my @subclasses = split(/,/, $subclass);
$self->{_custom_subclass} = \@subclasses;
}
}
@@ -79,7 +80,7 @@ sub run($;) {
for(;;) {
# Only register for events we have callbacks for.
for my $key ( keys %{$self->{_callback}} ) {
if ($key eq "CUSTOM") {
if ($key =~ m/custom/i) {
foreach $subclass (@{$self->{_custom_subclass}}) {
$self->{_esl}->events("plain", "$key $subclass");
}
+8
View File
@@ -290,6 +290,10 @@
RelativePath=".\esl.c"
>
</File>
<File
RelativePath=".\esl_buffer.c"
>
</File>
<File
RelativePath=".\esl_config.c"
>
@@ -316,6 +320,10 @@
RelativePath=".\include\esl.h"
>
</File>
<File
RelativePath=".\include\esl_buffer.h"
>
</File>
<File
RelativePath=".\include\esl_config.h"
>
+2
View File
@@ -128,6 +128,7 @@
<ClCompile Include="esl_event.c" />
<ClCompile Include="esl_json.c" />
<ClCompile Include="esl_threadmutex.c" />
<ClCompile Include="esl_buffer.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\esl.h" />
@@ -135,6 +136,7 @@
<ClInclude Include="include\esl_event.h" />
<ClInclude Include="include\esl_json.h" />
<ClInclude Include="include\esl_threadmutex.h" />
<ClInclude Include="include\esl_buffer.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
+86 -69
View File
@@ -428,6 +428,10 @@ ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t s
esl_mutex_create(&handle->mutex);
}
if (!handle->packet_buf) {
esl_buffer_create(&handle->packet_buf, BUF_CHUNK, BUF_START, 0);
}
handle->connected = 1;
esl_send_recv(handle, "connect\n\n");
@@ -632,6 +636,10 @@ ESL_DECLARE(esl_status_t) esl_connect_timeout(esl_handle_t *handle, const char *
if (!handle->mutex) {
esl_mutex_create(&handle->mutex);
}
if (!handle->packet_buf) {
esl_buffer_create(&handle->packet_buf, BUF_CHUNK, BUF_START, 0);
}
handle->sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
@@ -805,6 +813,11 @@ ESL_DECLARE(esl_status_t) esl_disconnect(esl_handle_t *handle)
esl_mutex_destroy(&mutex);
}
if (handle->packet_buf) {
esl_buffer_destroy(&handle->packet_buf);
}
return status;
}
@@ -825,7 +838,7 @@ ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms
if (check_q) {
esl_mutex_lock(handle->mutex);
if (handle->race_event) {
if (handle->race_event || esl_buffer_packet_count(handle->packet_buf)) {
esl_mutex_unlock(handle->mutex);
return esl_recv_event(handle, check_q, save_event);
}
@@ -894,12 +907,15 @@ ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms
}
static esl_ssize_t handle_recv(esl_handle_t *handle, void *data, esl_size_t datalen)
{
return recv(handle->sock, data, datalen, 0);
}
ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_event_t **save_event)
{
char *c;
esl_ssize_t rrval;
int crc = 0;
esl_event_t *revent = NULL;
char *beg;
char *hname, *hval;
@@ -907,7 +923,6 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_
char *cl;
esl_ssize_t len;
int zc = 0;
int bread = 0;
if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) {
return ESL_FAIL;
@@ -916,9 +931,7 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_
esl_mutex_lock(handle->mutex);
if (!handle->connected || handle->sock == ESL_SOCK_INVALID) {
handle->connected = 0;
esl_mutex_unlock(handle->mutex);
return ESL_FAIL;
goto fail;
}
esl_event_safe_destroy(&handle->last_event);
@@ -932,76 +945,62 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_
goto parse_event;
}
memset(handle->header_buf, 0, sizeof(handle->header_buf));
while(!revent && handle->connected) {
esl_size_t len1;
if ((len1 = esl_buffer_read_packet(handle->packet_buf, handle->socket_buf, sizeof(handle->socket_buf)))) {
char *data = (char *) handle->socket_buf;
char *p, *e;
esl_event_create(&revent, ESL_EVENT_CLONE);
revent->event_id = ESL_EVENT_SOCKET_DATA;
esl_event_add_header_string(revent, ESL_STACK_BOTTOM, "Event-Name", "SOCKET_DATA");
hname = p = data;
while(p) {
hname = p;
p = NULL;
c = handle->header_buf;
beg = c;
if ((hval = strchr(hname, ':'))) {
*hval++ = '\0';
while(*hval == ' ' || *hval == '\t') hval++;
while(handle->connected) {
if (bread + 2 >= sizeof(handle->header_buf)) {
esl_log(ESL_LOG_CRIT, "OUT OF BUFFER SPACE!\n");
handle->connected = 0;
esl_mutex_unlock(handle->mutex);
return ESL_DISCONNECTED;
if ((e = strchr(hval, '\n'))) {
*e++ = '\0';
while(*e == '\n' || *e == '\r') e++;
if (hname && hval) {
esl_url_decode(hval);
esl_log(ESL_LOG_DEBUG, "RECV HEADER [%s] = [%s]\n", hname, hval);
esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval);
}
p = e;
}
}
}
break;
}
rrval = recv(handle->sock, c, 1, 0);
rrval = handle_recv(handle, handle->socket_buf, sizeof(handle->socket_buf));
if (rrval == 0) {
if (++zc >= 100) {
handle->connected = 0;
esl_mutex_unlock(handle->mutex);
return ESL_DISCONNECTED;
goto fail;
}
continue;
} else if (rrval < 0) {
strerror_r(handle->errnum, handle->err, sizeof(handle->err));
goto fail;
} else {
zc = 0;
if (*c == '\n') {
*(c+1) = '\0';
if (++crc == 2) {
break;
}
if (!revent) {
esl_event_create(&revent, ESL_EVENT_CLONE);
revent->event_id = ESL_EVENT_SOCKET_DATA;
esl_event_add_header_string(revent, ESL_STACK_BOTTOM, "Event-Name", "SOCKET_DATA");
}
hname = beg;
hval = col = NULL;
if (hname && (col = strchr(hname, ':'))) {
hval = col + 1;
*col = '\0';
while(*hval == ' ') hval++;
}
*c = '\0';
if (hname && hval) {
esl_url_decode(hval);
esl_log(ESL_LOG_DEBUG, "RECV HEADER [%s] = [%s]\n", hname, hval);
esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval);
}
c = beg;
bread = 0;
continue;
} else {
crc = 0;
}
c++;
}
}
zc = 0;
esl_buffer_write(handle->packet_buf, handle->socket_buf, rrval);
}
if (!revent) {
goto fail;
}
@@ -1016,12 +1015,28 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_
*(body + len) = '\0';
do {
esl_ssize_t r;
if ((r = recv(handle->sock, body + sofar, len - sofar, 0)) < 0) {
strerror_r(handle->errnum, handle->err, sizeof(handle->err));
goto fail;
esl_ssize_t r,s = esl_buffer_inuse(handle->packet_buf);
if (s >= len) {
sofar = esl_buffer_read(handle->packet_buf, body, len);
} else {
r = handle_recv(handle, handle->socket_buf, sizeof(handle->socket_buf));
if (r < 0) {
strerror_r(handle->errnum, handle->err, sizeof(handle->err));
goto fail;
} else if (r == 0) {
if (++zc >= 100) {
goto fail;
}
continue;
}
zc = 0;
esl_buffer_write(handle->packet_buf, handle->socket_buf, r);
}
sofar += r;
} while (sofar < len);
revent->body = body;
@@ -1123,6 +1138,8 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_
fail:
esl_mutex_unlock(handle->mutex);
handle->connected = 0;
return ESL_FAIL;
+354
View File
@@ -0,0 +1,354 @@
/*
* Copyright (c) 2010, Anthony Minessale II
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "esl_buffer.h"
static unsigned buffer_id = 0;
struct esl_buffer {
unsigned char *data;
unsigned char *head;
esl_size_t used;
esl_size_t actually_used;
esl_size_t datalen;
esl_size_t max_len;
esl_size_t blocksize;
unsigned id;
int loops;
};
ESL_DECLARE(esl_status_t) esl_buffer_create(esl_buffer_t **buffer, esl_size_t blocksize, esl_size_t start_len, esl_size_t max_len)
{
esl_buffer_t *new_buffer;
new_buffer = malloc(sizeof(*new_buffer));
if (new_buffer) {
memset(new_buffer, 0, sizeof(*new_buffer));
if (start_len) {
new_buffer->data = malloc(start_len);
if (!new_buffer->data) {
free(new_buffer);
return ESL_FAIL;
}
memset(new_buffer->data, 0, start_len);
}
new_buffer->max_len = max_len;
new_buffer->datalen = start_len;
new_buffer->id = buffer_id++;
new_buffer->blocksize = blocksize;
new_buffer->head = new_buffer->data;
*buffer = new_buffer;
return ESL_SUCCESS;
}
return ESL_FAIL;
}
ESL_DECLARE(esl_size_t) esl_buffer_len(esl_buffer_t *buffer)
{
assert(buffer != NULL);
return buffer->datalen;
}
ESL_DECLARE(esl_size_t) esl_buffer_freespace(esl_buffer_t *buffer)
{
assert(buffer != NULL);
if (buffer->max_len) {
return (esl_size_t) (buffer->max_len - buffer->used);
}
return 1000000;
}
ESL_DECLARE(esl_size_t) esl_buffer_inuse(esl_buffer_t *buffer)
{
assert(buffer != NULL);
return buffer->used;
}
ESL_DECLARE(esl_size_t) esl_buffer_seek(esl_buffer_t *buffer, esl_size_t datalen)
{
esl_size_t reading = 0;
assert(buffer != NULL);
if (buffer->used < 1) {
buffer->used = 0;
return 0;
} else if (buffer->used >= datalen) {
reading = datalen;
} else {
reading = buffer->used;
}
buffer->used = buffer->actually_used - reading;
buffer->head = buffer->data + reading;
return reading;
}
ESL_DECLARE(esl_size_t) esl_buffer_toss(esl_buffer_t *buffer, esl_size_t datalen)
{
esl_size_t reading = 0;
assert(buffer != NULL);
if (buffer->used < 1) {
buffer->used = 0;
return 0;
} else if (buffer->used >= datalen) {
reading = datalen;
} else {
reading = buffer->used;
}
buffer->used -= reading;
buffer->head += reading;
return buffer->used;
}
ESL_DECLARE(void) esl_buffer_set_loops(esl_buffer_t *buffer, int loops)
{
buffer->loops = loops;
}
ESL_DECLARE(esl_size_t) esl_buffer_read_loop(esl_buffer_t *buffer, void *data, esl_size_t datalen)
{
esl_size_t len;
if ((len = esl_buffer_read(buffer, data, datalen)) < datalen) {
if (buffer->loops == 0) {
return len;
}
buffer->head = buffer->data;
buffer->used = buffer->actually_used;
len = esl_buffer_read(buffer, (char*)data + len, datalen - len);
buffer->loops--;
}
return len;
}
ESL_DECLARE(esl_size_t) esl_buffer_read(esl_buffer_t *buffer, void *data, esl_size_t datalen)
{
esl_size_t reading = 0;
assert(buffer != NULL);
assert(data != NULL);
if (buffer->used < 1) {
buffer->used = 0;
return 0;
} else if (buffer->used >= datalen) {
reading = datalen;
} else {
reading = buffer->used;
}
memcpy(data, buffer->head, reading);
buffer->used -= reading;
buffer->head += reading;
/* if (buffer->id == 4) printf("%u o %d = %d\n", buffer->id, (unsigned)reading, (unsigned)buffer->used); */
return reading;
}
ESL_DECLARE(esl_size_t) esl_buffer_packet_count(esl_buffer_t *buffer)
{
char *pe, *p, *e, *head = (char *) buffer->head;
esl_size_t x = 0;
assert(buffer != NULL);
e = (head + buffer->used);
for (p = head; p && *p && p < e; p++) {
if (*p == '\n') {
pe = p+1;
if (*pe == '\r') pe++;
if (pe <= e && *pe == '\n') {
p = pe++;
x++;
}
}
}
return x;
}
ESL_DECLARE(esl_size_t) esl_buffer_read_packet(esl_buffer_t *buffer, void *data, esl_size_t maxlen)
{
char *pe, *p, *e, *head = (char *) buffer->head;
esl_size_t datalen = 0;
assert(buffer != NULL);
assert(data != NULL);
e = (head + buffer->used);
for (p = head; p && *p && p < e; p++) {
if (*p == '\n') {
pe = p+1;
if (*pe == '\r') pe++;
if (pe <= e && *pe == '\n') {
pe++;
datalen = pe - head;
if (datalen > maxlen) {
datalen = maxlen;
}
break;
}
}
}
return esl_buffer_read(buffer, data, datalen);
}
ESL_DECLARE(esl_size_t) esl_buffer_write(esl_buffer_t *buffer, const void *data, esl_size_t datalen)
{
esl_size_t freespace, actual_freespace;
assert(buffer != NULL);
assert(data != NULL);
assert(buffer->data != NULL);
if (!datalen) {
return buffer->used;
}
actual_freespace = buffer->datalen - buffer->actually_used;
if (actual_freespace < datalen && (!buffer->max_len || (buffer->used + datalen <= buffer->max_len))) {
memmove(buffer->data, buffer->head, buffer->used);
buffer->head = buffer->data;
buffer->actually_used = buffer->used;
}
freespace = buffer->datalen - buffer->used;
/*
if (buffer->data != buffer->head) {
memmove(buffer->data, buffer->head, buffer->used);
buffer->head = buffer->data;
}
*/
if (freespace < datalen) {
esl_size_t new_size, new_block_size;
void *data1;
new_size = buffer->datalen + datalen;
new_block_size = buffer->datalen + buffer->blocksize;
if (new_block_size > new_size) {
new_size = new_block_size;
}
buffer->head = buffer->data;
data1 = realloc(buffer->data, new_size);
if (!data1) {
return 0;
}
buffer->data = data1;
buffer->head = buffer->data;
buffer->datalen = new_size;
}
freespace = buffer->datalen - buffer->used;
if (freespace < datalen) {
return 0;
} else {
memcpy(buffer->head + buffer->used, data, datalen);
buffer->used += datalen;
buffer->actually_used += datalen;
}
/* if (buffer->id == 4) printf("%u i %d = %d\n", buffer->id, (unsigned)datalen, (unsigned)buffer->used); */
return buffer->used;
}
ESL_DECLARE(void) esl_buffer_zero(esl_buffer_t *buffer)
{
assert(buffer != NULL);
assert(buffer->data != NULL);
buffer->used = 0;
buffer->actually_used = 0;
buffer->head = buffer->data;
}
ESL_DECLARE(esl_size_t) esl_buffer_zwrite(esl_buffer_t *buffer, const void *data, esl_size_t datalen)
{
esl_size_t w;
if (!(w = esl_buffer_write(buffer, data, datalen))) {
esl_buffer_zero(buffer);
return esl_buffer_write(buffer, data, datalen);
}
return w;
}
ESL_DECLARE(void) esl_buffer_destroy(esl_buffer_t **buffer)
{
if (*buffer) {
free((*buffer)->data);
free(*buffer);
}
*buffer = NULL;
}
/* 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:
*/
+7 -1
View File
@@ -251,6 +251,7 @@ typedef int esl_filehandle_t;
#include "esl_json.h"
typedef int16_t esl_port_t;
typedef size_t esl_size_t;
typedef enum {
ESL_SUCCESS,
@@ -259,7 +260,11 @@ typedef enum {
ESL_DISCONNECTED
} esl_status_t;
#define BUF_CHUNK 65536 * 50
#define BUF_START 65536 * 100
#include <esl_threadmutex.h>
#include <esl_buffer.h>
/*! \brief A handle that will hold the socket information and
different events received. */
@@ -273,7 +278,8 @@ typedef struct {
/*! The error number reported by the OS */
int errnum;
/*! The inner contents received by the socket. Used only internally. */
char header_buf[4196];
esl_buffer_t *packet_buf;
char socket_buf[65536];
/*! Last command reply */
char last_reply[1024];
/*! Las command reply when called with esl_send_recv */
+146
View File
@@ -0,0 +1,146 @@
/*
* Copyright (c) 2010, Anthony Minessale II
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "esl.h"
#ifndef ESL_BUFFER_H
#define ESL_BUFFER_H
/**
* @defgroup esl_buffer Buffer Routines
* @ingroup buffer
* The purpose of this module is to make a plain buffering interface that can be used for read/write buffers
* throughout the application.
* @{
*/
struct esl_buffer;
typedef struct esl_buffer esl_buffer_t;
/*! \brief Allocate a new dynamic esl_buffer
* \param buffer returned pointer to the new buffer
* \param blocksize length to realloc by as data is added
* \param start_len ammount of memory to reserve initially
* \param max_len length the buffer is allowed to grow to
* \return status
*/
ESL_DECLARE(esl_status_t) esl_buffer_create(esl_buffer_t **buffer, esl_size_t blocksize, esl_size_t start_len, esl_size_t max_len);
/*! \brief Get the length of a esl_buffer_t
* \param buffer any buffer of type esl_buffer_t
* \return int size of the buffer.
*/
ESL_DECLARE(esl_size_t) esl_buffer_len(esl_buffer_t *buffer);
/*! \brief Get the freespace of a esl_buffer_t
* \param buffer any buffer of type esl_buffer_t
* \return int freespace in the buffer.
*/
ESL_DECLARE(esl_size_t) esl_buffer_freespace(esl_buffer_t *buffer);
/*! \brief Get the in use amount of a esl_buffer_t
* \param buffer any buffer of type esl_buffer_t
* \return int ammount of buffer curently in use
*/
ESL_DECLARE(esl_size_t) esl_buffer_inuse(esl_buffer_t *buffer);
/*! \brief Read data from a esl_buffer_t up to the ammount of datalen if it is available. Remove read data from buffer.
* \param buffer any buffer of type esl_buffer_t
* \param data pointer to the read data to be returned
* \param datalen amount of data to be returned
* \return int ammount of data actually read
*/
ESL_DECLARE(esl_size_t) esl_buffer_read(esl_buffer_t *buffer, void *data, esl_size_t datalen);
ESL_DECLARE(esl_size_t) esl_buffer_read_packet(esl_buffer_t *buffer, void *data, esl_size_t maxlen);
ESL_DECLARE(esl_size_t) esl_buffer_packet_count(esl_buffer_t *buffer);
/*! \brief Read data endlessly from a esl_buffer_t
* \param buffer any buffer of type esl_buffer_t
* \param data pointer to the read data to be returned
* \param datalen amount of data to be returned
* \return int ammount of data actually read
* \note Once you have read all the data from the buffer it will loop around.
*/
ESL_DECLARE(esl_size_t) esl_buffer_read_loop(esl_buffer_t *buffer, void *data, esl_size_t datalen);
/*! \brief Assign a number of loops to read
* \param buffer any buffer of type esl_buffer_t
* \param loops the number of loops (-1 for infinite)
*/
ESL_DECLARE(void) esl_buffer_set_loops(esl_buffer_t *buffer, int32_t loops);
/*! \brief Write data into a esl_buffer_t up to the length of datalen
* \param buffer any buffer of type esl_buffer_t
* \param data pointer to the data to be written
* \param datalen amount of data to be written
* \return int amount of buffer used after the write, or 0 if no space available
*/
ESL_DECLARE(esl_size_t) esl_buffer_write(esl_buffer_t *buffer, const void *data, esl_size_t datalen);
/*! \brief Remove data from the buffer
* \param buffer any buffer of type esl_buffer_t
* \param datalen amount of data to be removed
* \return int size of buffer, or 0 if unable to toss that much data
*/
ESL_DECLARE(esl_size_t) esl_buffer_toss(esl_buffer_t *buffer, esl_size_t datalen);
/*! \brief Remove all data from the buffer
* \param buffer any buffer of type esl_buffer_t
*/
ESL_DECLARE(void) esl_buffer_zero(esl_buffer_t *buffer);
/*! \brief Destroy the buffer
* \param buffer buffer to destroy
* \note only neccessary on dynamic buffers (noop on pooled ones)
*/
ESL_DECLARE(void) esl_buffer_destroy(esl_buffer_t **buffer);
/*! \brief Seek to offset from the beginning of the buffer
* \param buffer buffer to seek
* \param datalen offset in bytes
* \return new position
*/
ESL_DECLARE(esl_size_t) esl_buffer_seek(esl_buffer_t *buffer, esl_size_t datalen);
/** @} */
ESL_DECLARE(esl_size_t) esl_buffer_zwrite(esl_buffer_t *buffer, const void *data, esl_size_t datalen);
#endif
/* 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
View File
@@ -73,6 +73,7 @@ libfreetdm_la_SOURCES = \
$(SRC)/hashtable.c \
$(SRC)/hashtable_itr.c \
$(SRC)/ftdm_io.c \
$(SRC)/ftdm_state.c \
$(SRC)/ftdm_queue.c \
$(SRC)/ftdm_sched.c \
$(SRC)/ftdm_call_utils.c \
+57 -6
View File
@@ -12,31 +12,81 @@ with the signaling protocols that you can run on top of your I/O interfaces.
<settings>
<param name="debug" value="0"/>
<!--<param name="hold-music" value="$${moh_uri}"/>-->
<!-- Analog global options (they apply to all spans)
Remember you can only choose between either call-swap
or 3-way, not both!
-->
<!--<param name="enable-analog-option" value="call-swap"/>-->
<!--<param name="enable-analog-option" value="3-way"/>-->
</settings>
<!-- Sample analog configuration -->
<!-- Sample analog configuration (The analog_spans tag is for ftmod_analog) -->
<analog_spans>
<!-- The span name must match the name in your freetdm.conf -->
<span name="myAnalog">
<!--<param name="hold-music" value="$${moh_uri}"/>-->
<!--<param name="enable-analog-option" value="call-swap"/>-->
<!--<param name="enable-analog-option" value="3-way"/>-->
<!--
3-way allows you to flash your FXS line and dial
another number and put all the parties in a conference
call-swap allows you to flash your FXS line and swap
between one call and another
Remember you can only choose between either call-swap
or 3-way, not both!
<param name="enable-analog-option" value="call-swap"/>
<param name="enable-analog-option" value="3-way"/>
-->
<!-- Tones are defined in tones.conf
This setting is very important for analog lines to
work properly
-->
<param name="tonegroup" value="us"/>
<!-- How much time to wait for digits (in FXS lines) -->
<param name="digit-timeout" value="2000"/>
<!-- Maximum number of digits to wait for (in FXS lines) -->
<param name="max-digits" value="11"/>
<param name="dialplan" value="XML"/>
<param name="context" value="default"/>
<!-- whether you want to wait for caller id -->
<param name="enable-callerid" value="true"/>
<!-- whether you want to enable callwaiting feature -->
<!--<param name="callwaiting" value="true"/>-->
<!-- whether you want to answer/hangup on polarity reverse for outgoing calls in FXO devices
and send polarity reverse on answer/hangup for incoming calls in FXS devices -->
<!--<param name="answer-polarity-reverse" value="false"/>-->
<!--<param name="hangup-polarity-reverse" value="false"/>-->
<!--
Minimum delay (in milliseconds) required between an answer polarity reverse
and hangup polarity reverse in order to assume the second polarity reverse is a real hangup
<param name="polarity-delay" value="600"/>
-->
<!-- regex to stop dialing when it matches -->
<!--<param name="dial-regex" value="5555"/>-->
<!-- regex to stop dialing when it does not match -->
<!--<param name="fail-dial-regex" value="^5"/>-->
<!-- FreeSWITCH dialplan type and context to send the calls -->
<param name="dialplan" value="XML"/>
<param name="context" value="default"/>
</span>
</analog_spans>
<!-- openr2 (MFC-R2 signaling) spans
<!--
openr2 (MFC-R2 signaling) spans (ftmod_r2)
In order to use this type of spans your FreeTDM must have been compiled with ftmod_r2 module.
The module is compiled if the openr2 library is present when running the ./configure script
in the FreeTDM source code
MFC-R2 signaling has lots of variants from country to country and even sometimes
minor variants inside the same country. The only mandatory parameters here are:
variant, but typically you also want to set max_ani and max_dnis.
@@ -46,6 +96,7 @@ with the signaling protocols that you can run on top of your I/O interfaces.
best defaults for your country. If you want to contribute your configs for a particular
country send them to the e-mail of the primary OpenR2 developer that you can find in the
AUTHORS file of the OpenR2 package, they will be added to the samples directory of openr2.
-->
<r2_spans>
<span name="wp1" cfgprofile="testr2">
-38
View File
@@ -1,38 +0,0 @@
;M3UA SS7 Links Config
;
;ss7box-m3ua_mode => true
;local_sctp_ip => localhost
;local sctp_port => 30000
;remote_sctp_ip => localhost
;remote_sctp_port => 30001
;opc => 0-0-0
;dpc => 0-0-0
; AP Specific Stuff. This will likely move later.
; CNAM Gateways
cnam1_dpc => 0-0-0
cnam1_ssn => 253
cnam2_dpc => 0-0-0
cnam2_ssn => 253
cnam3_dpc => 0-0-0
cnam3_ssn => 253
;LNP Gateways
lnp1_dpc => 0-0-0
lnp1_ssn => 253
lnp2_dpc => 0-0-0
lnp2_ssn => 253
lnp3_dpc => 0-0-0
lnp3_ssn => 253
;LNP Gateways
sms8001_dpc => 0-0-0
sms8001_ssn => 253
sms8002_dpc => 0-0-0
sms8002_ssn => 253
sms8003_dpc => 0-0-0
sms8003_ssn => 253
+1 -1
View File
@@ -160,7 +160,7 @@ AC_ARG_WITH([pritap],
[AS_HELP_STRING([--with-pritap], [Install ftmod_pritap])],
[case "${withval}" in
no) enable_pritap="no" ;;
*) enable_pritab="yes" ;;
*) enable_pritap="yes" ;;
esac],
[enable_pritap="no"]
)
+125
View File
@@ -0,0 +1,125 @@
Last Updated: Fri 30 Dec, 2010
== Background ==
FreeTDM is a threaded library. As such, locking considerations must be taken when using it and when writing code inside the library.
At the moment locks are not exposed to users. This means API users cannot acquire a lock on a channel or span structure. There is no
need for users to lock channels or spans since all their interactions with those structures should be done thru the FreeTDM API which
can (and in most cases must) internally lock on their behalf.
Internally, locking can be done either by the core or the signaling modules. To better understand the locking considerations we must
understand first the threading model of FreeTDM.
== Threading Model ==
At startup, when the user calls ftdm_global_init(), just one timing thread is created to dispatch internal timers. If you write
a signaling module or any other code using the scheduling API, you can choose to run your schedule in this timing thread or in
a thread of your choice. This is the only thread launched at initialization.
If the application decides to use ftdm_global_configuration(), which reads freetdm.conf to create the spans and channels data
structures, then possibly another thread will be launched for CPU usage monitoring (only if enabled in the configuration cpu_monitor=yes
This thread sole purpose is to check the CPU and raise an alarm if reaches a configurable threshold, the alarm then is checked to avoid
placing or receiving further calls.
At this point FreeTDM has initialized and configured its channels input output configuration.
The user is then supposed to configure the signaling via ftdm_configure_span_signaling() and then start the signaling work
using ftdm_span_start(). This will typically launch at least 1 thread per span. Some signaling modules (actually just the analog one)
launches another thread per channel when receiving a call. The rest of the signaling modules currently launch only one thread per
span and the signaling for all channels within the span is handled in that thread. We call that thread 'the signaling thread'.
At this point the user can start placing calls using the FreeTDM call API ftdm_channel_call_place(). Any of the possible threads in
which the user calls the FreeTDM API is called 'the user thread', depending on the application thread model (the application using FreeTDM)
this user thread may be different each time or the same all the time, we cannot make any assumptions. In the case of FreeSWITCH, the most
common user of FreeTDM, the user thread is most of the cases a thread for each new call leg.
At this point we have identified 4 types of threads.
1. The timing thread (the core thread that triggers timers).
Its responsibility is simply check for timers that were scheduled and trigger them when the time comes. This means that if you decide
to use the scheduling API in freerun mode (where you use the core timer thread) you callbacks will be executed in this global thread
and you MUST not block at all since there might be other events waiting.
2. The CPU thread (we don't really care about this one as it does not interact with channels or spans).
3. The signaling thread.
There is one thread of this per span. This thread takes care of reading signaling specific messages from the network (ISDN network, etc) and
changing the channel call state accordingly and processing state changes caused by user API calls (like ftdm_channel_call_hangup for example).
4. The user thread.
This is a thread in which the user decides to execute FreeTDM APIs, in some cases it might even be the same than the signaling thread (because
most SIGEVENT notifications are delivered by the signaling thread, however we are advicing users to not use FreeTDM unsafe APIs from the
thread where they receive SIGEVENT notifications as some APIs may block for a few milliseconds, effectively blocking the whole signaling thread
that is servicing a span.
== Application Locking ==
Users of the FreeTDM API will typically have locking of their own for their own application-specific data structures (in the case of FreeSWITCH, the
session lock for example). Other application-specific locks may be involved.
== DeadLocks ==
As soon as we think of application locks, and we mix them with the FreeTDM internal locks, the possibility of deadlocks arise.
A typical deadlock scenario when 2 locks are involved is:
- User Thread - - Signaling Thread -
1. Application locks applock. 1. A network message is received for a channel.
2. Aplication invokes a FreeTDM call API (ie: ftdm_channel_call_hangup()). 2. The involved channel is locked.
3. The FreeTDM API attempts to acquire the channel lock and stalls because 3. The message processing results in a notification
the signaling thread just acquired it. to be delivered to the user via the callback function
provided for that purpose. The callback is then called.
4. The thread is now deadlocked because the signaling thread will never 4. The application callback attempts to acquire its application
release the channel lock. lock but deadlocks because the user thread already has it.
To avoid this signaling modules should not deliver signals to the user while holding the channel lock. An easy way to avoid this is
to not deliver signals while processing a state change, but rather defer them until the channel lock is released. Most new signaling modules
accomplish this by setting the span flag FTDM_SPAN_USE_SIGNALS_QUEUE, this flag tells the core to enqueue signals (ie FTDM_SIGEVENT_START)
when ftdm_span_send_signal() is called and not deliver them until ftdm_span_trigger_signals() is called, which is done by the signaling module
in its signaling thread when no channel lock is being held.
== State changes while locking ==
Only 2 types of threads should be performing state changes.
User threads.
The user thread is a random thread that was crated by the API user. We do not know what threading model users of FreeTDM will follow
and therefore cannot make assumptions about it. The user should be free to call FreeTDM APIs from any thread, except threads that
are under our control, like the signaling threads. Although it may work in most situations, is discouraged for users to try
to use FreeTDM APIs from the signaling thread, that is, the thread where the signaling callback provided during configuration
is called (the callback where FTDM_SIGEVENT_XXX signals are delivered).
A user thread may request state changes implicitly through calls to FreeTDM API's. The idea of state changes is internal to freetdm
and should not be exposed to users of the API (except for debugging purposes, like the ftdm_channel_get_state, ftdm_channel_get_state_str etc)
This is an example of the API's that implicitly request a state change.
ftdm_channel_call_answer()
Signaling modules should guarantee that upon releasing a lock on a channel, any state changes will be already processed and
not deferred to other threads, otherwise that leads to a situation where a state change requested by the signaling module is pending
to be serviced by another signaling module thread but a user thread wins the channel lock and attempts to perform a state change which will
fail because another state change is pending (and user threads are not meant to process signaling states).
ONLY one signaling thread per channel should try to perform state changes and processing of the states,
otherwise complexity arises and is not worth it!
At some point before we stablished this policies we could have 3 different threads doing state changes.
1. A user random thread could implcitly try to change the state in response to a call API.
2. The ftmod signaling thread could try to change the state in response to other state changes.
3. The lower level signaling stack threads could try to change the state in response to stack events.
As a result, lower level signaling stack thread could set a state and then let the signaling thread to
process it, but when unlocking the channel, the user thread may win the lock over the signaling thread and
may try to set a state change of its own and fail (due to the unprocessed state change)!
The rule is, the signaling module should never unlock a channel with states pending to process this way the user,
when acquiring a channel lock (inside ftdm_channel_call_answer for example) it will always find a consistent state
for the channel and not in the middle of state processing.
@@ -103,7 +103,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>FreeSwitch.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>FreeSwitchCore.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
@@ -127,7 +127,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>FreeSwitch.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>FreeSwitchCore.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
+62 -23
View File
@@ -421,16 +421,18 @@ static switch_status_t channel_on_routing(switch_core_session_t *session)
private_t *tech_pvt = NULL;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
switch_assert(channel != NULL);
tech_pvt = switch_core_session_get_private(session);
assert(tech_pvt != NULL);
switch_assert(tech_pvt != NULL);
assert(tech_pvt->ftdmchan != NULL);
switch_assert(tech_pvt->ftdmchan != NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel));
ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_PROCEED);
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_PROCEED);
}
return SWITCH_STATUS_SUCCESS;
}
@@ -441,10 +443,10 @@ static switch_status_t channel_on_execute(switch_core_session_t *session)
private_t *tech_pvt = NULL;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
switch_assert(channel != NULL);
tech_pvt = switch_core_session_get_private(session);
assert(tech_pvt != NULL);
switch_assert(tech_pvt != NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel));
@@ -802,7 +804,7 @@ static switch_status_t channel_receive_message_cas(switch_core_session_t *sessio
phy_id = ftdm_channel_get_ph_id(tech_pvt->ftdmchan);
ftdm_log(FTDM_LOG_DEBUG, "Got Freeswitch message in R2 channel %d [%d]\n", phy_id, msg->message_id);
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
return SWITCH_STATUS_SUCCESS;
}
@@ -849,7 +851,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session,
return SWITCH_STATUS_SUCCESS;
}
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
return SWITCH_STATUS_SUCCESS;
}
@@ -892,7 +894,7 @@ static switch_status_t channel_receive_message_fxo(switch_core_session_t *sessio
return SWITCH_STATUS_FALSE;
}
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
return SWITCH_STATUS_SUCCESS;
}
@@ -924,7 +926,7 @@ static switch_status_t channel_receive_message_fxs(switch_core_session_t *sessio
return SWITCH_STATUS_FALSE;
}
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
return SWITCH_STATUS_SUCCESS;
}
@@ -981,7 +983,7 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s
switch (msg->message_id) {
case SWITCH_MESSAGE_INDICATE_PROGRESS:
case SWITCH_MESSAGE_INDICATE_ANSWER:
if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
if ((var = switch_channel_get_variable(channel, "freetdm_pre_buffer_size"))) {
int tmp = atoi(var);
if (tmp > -1) {
@@ -1136,6 +1138,10 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
direction = FTDM_BOTTOM_UP;
} else if (*argv[1] == 'a') {
direction = FTDM_TOP_DOWN;
} else if (*argv[1] == 'r') {
direction = FTDM_RR_DOWN;
} else if (*argv[1] == 'R') {
direction = FTDM_RR_UP;
} else {
chan_id = atoi(argv[1]);
}
@@ -1278,6 +1284,10 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
caller_data.dnis.type = outbound_profile->destination_number_ton;
}
if ((var = channel_get_variable(session, var_event, "freetdm_calling_party_category"))) {
ftdm_set_calling_party_category(var, (uint8_t *)&caller_data.cpc);
}
if ((var = channel_get_variable(session, var_event, "freetdm_custom_call_data"))) {
ftdm_set_string(caller_data.raw_data, var);
caller_data.raw_data_len = (uint32_t)strlen(var);
@@ -1363,7 +1373,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
tech_pvt->caller_profile = caller_profile;
switch_channel_set_flag(channel, CF_OUTBOUND);
switch_channel_set_state(channel, CS_INIT);
if (ftdm_channel_add_token(ftdmchan, switch_core_session_get_uuid(*new_session), ftdm_channel_get_token_count(ftdmchan)) != FTDM_SUCCESS) {
switch_core_session_destroy(new_session);
@@ -1633,6 +1642,14 @@ static FIO_SIGNAL_CB_FUNCTION(on_common_signal)
}
return FTDM_SUCCESS;
}
case FTDM_SIGEVENT_RELEASED:
case FTDM_SIGEVENT_INDICATION_COMPLETED:
{
/* Swallow these events */
return FTDM_BREAK;
}
break;
default:
return FTDM_SUCCESS;
break;
@@ -1723,7 +1740,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
}
}
break;
case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break;
case FTDM_SIGEVENT_SIGSTATUS_CHANGED: { /* twiddle */ } break;
default:
{
@@ -1778,7 +1795,6 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
}
}
break;
case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break;
case FTDM_SIGEVENT_STOP:
{
@@ -1811,7 +1827,9 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
}
if (channel_a && channel_b && !switch_channel_test_flag(channel_a, CF_OUTBOUND) && !switch_channel_test_flag(channel_b, CF_OUTBOUND)) {
if (channel_a && channel_b && switch_channel_direction(channel_a) == SWITCH_CALL_DIRECTION_INBOUND &&
switch_channel_direction(channel_b) == SWITCH_CALL_DIRECTION_INBOUND) {
cause = SWITCH_CAUSE_ATTENDED_TRANSFER;
if (br_a_uuid && br_b_uuid) {
switch_ivr_uuid_bridge(br_a_uuid, br_b_uuid);
@@ -1911,7 +1929,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
case FTDM_SIGEVENT_COLLECTED_DIGIT:
{
int span_id = ftdm_channel_get_span_id(sigmsg->channel);
char *dtmf = sigmsg->raw_data;
char *dtmf = sigmsg->ev_data.collected.digits;
char *regex = SPAN_CONFIG[span_id].dial_regex;
char *fail_regex = SPAN_CONFIG[span_id].fail_dial_regex;
ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(sigmsg->channel);
@@ -2003,8 +2021,6 @@ static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
}
break;
case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break;
/* on DNIS received from the R2 forward side, return status == FTDM_BREAK to stop requesting DNIS */
case FTDM_SIGEVENT_COLLECTED_DIGIT:
{
@@ -2077,13 +2093,14 @@ static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
case FTDM_SIGEVENT_SIGSTATUS_CHANGED:
{
ftdm_signaling_status_t sigstatus = sigmsg->raw_data ? *((ftdm_signaling_status_t*)(sigmsg->raw_data)) : sigmsg->ev_data.sigstatus.status;
ftdm_signaling_status_t sigstatus = sigmsg->ev_data.sigstatus.status;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%d:%d signalling changed to: %s\n",
spanid, chanid, ftdm_signaling_status2str(sigstatus));
}
break;
case FTDM_SIGEVENT_PROCEED:{} break;
case FTDM_SIGEVENT_INDICATION_COMPLETED:{} break;
default:
{
@@ -2122,8 +2139,6 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
}
break;
case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break;
case FTDM_SIGEVENT_STOP:
case FTDM_SIGEVENT_RESTART:
{
@@ -2183,7 +2198,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
break;
case FTDM_SIGEVENT_SIGSTATUS_CHANGED:
{
ftdm_signaling_status_t sigstatus = sigmsg->raw_data ? *((ftdm_signaling_status_t*)(sigmsg->raw_data)) : sigmsg->ev_data.sigstatus.status;
ftdm_signaling_status_t sigstatus = sigmsg->ev_data.sigstatus.status;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%d:%d signalling changed to :%s\n",
spanid, chanid, ftdm_signaling_status2str(sigstatus));
}
@@ -2707,6 +2722,9 @@ static switch_status_t load_config(void)
char *hold_music = NULL;
char *fail_dial_regex = NULL;
const char *enable_callerid = "true";
const char *answer_polarity = "false";
const char *hangup_polarity = "false";
int polarity_delay = 600;
int callwaiting = 1;
uint32_t span_id = 0, to = 0, max = 0;
@@ -2778,6 +2796,12 @@ static switch_status_t load_config(void)
dial_regex = val;
} else if (!strcasecmp(var, "enable-callerid")) {
enable_callerid = val;
} else if (!strcasecmp(var, "answer-polarity-reverse")) {
answer_polarity = val;
} else if (!strcasecmp(var, "hangup-polarity-reverse")) {
hangup_polarity = val;
} else if (!strcasecmp(var, "polarity-delay")) {
polarity_delay = atoi(val);
} else if (!strcasecmp(var, "fail-dial-regex")) {
fail_dial_regex = val;
} else if (!strcasecmp(var, "hold-music")) {
@@ -2838,6 +2862,9 @@ static switch_status_t load_config(void)
"max_dialstr", &max,
"hotline", hotline ? hotline : "",
"enable_callerid", enable_callerid,
"answer_polarity_reverse", answer_polarity,
"hangup_polarity_reverse", hangup_polarity,
"polarity_delay", &polarity_delay,
"callwaiting", &callwaiting,
FTDM_TAG_END) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM analog span %s\n", ftdm_span_get_name(span));
@@ -3526,7 +3553,19 @@ void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *
switch_channel_cause2str(caller_data->hangup_cause));
}
#define FT_SYNTAX "list || dump <span_id> [<chan_id>] || q931_pcap <span_id> on|off [pcapfilename without suffix] || gains <txgain> <rxgain> <span_id> [<chan_id>] || dtmf on|off <span_id> [<chan_id>]"
#define FT_SYNTAX "USAGE:\n" \
"--------------------------------------------------------------------------------\n" \
"ftdm list\n" \
"ftdm start|stop <span_name|span_id>\n" \
"ftdm restart <span_id|span_name> <chan_id>\n" \
"ftdm dump <span_id|span_name> [<chan_id>]\n" \
"ftdm sigstatus get|set [<span_id|span_name>] [<channel>] [<sigstatus>]\n" \
"ftdm trace <path> <span_id|span_name> [<chan_id>]\n" \
"ftdm notrace <span_id|span_name> [<chan_id>]\n" \
"ftdm q931_pcap <span_id> on|off [pcapfilename without suffix]\n" \
"ftdm gains <txgain> <rxgain> <span_id> [<chan_id>]\n" \
"ftdm dtmf on|off <span_id> [<chan_id>]\n" \
"--------------------------------------------------------------------------------\n"
SWITCH_STANDARD_API(ft_function)
{
char *mycmd = NULL, *argv[10] = { 0 };
+80 -72
View File
@@ -94,78 +94,6 @@
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="1"
BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../src/include;../src/include/private;../src/isdn/include"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
RuntimeLibrary="2"
DisableLanguageExtensions="false"
RuntimeTypeInfo="false"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
CompileAs="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
/>
<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"
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
@@ -243,6 +171,78 @@
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="1"
BuildLogFile="$(IntDir)\BuildLog-freetdm.htm"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../src/include;../src/include/private;../src/isdn/include"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS"
RuntimeLibrary="2"
DisableLanguageExtensions="false"
RuntimeTypeInfo="false"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
CompileAs="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
/>
<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"
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
@@ -366,6 +366,10 @@
RelativePath="..\src\include\private\ftdm_sched.h"
>
</File>
<File
RelativePath="..\src\include\private\ftdm_state.h"
>
</File>
<File
RelativePath="..\src\include\ftdm_threadmutex.h"
>
@@ -452,6 +456,10 @@
RelativePath="..\src\ftdm_sched.c"
>
</File>
<File
RelativePath="..\src\ftdm_state.c"
>
</File>
<File
RelativePath="..\src\ftdm_threadmutex.c"
>
+23
View File
@@ -30,6 +30,12 @@
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
*
* Moises Silva <moy@sangoma.com>
* Ricardo Barroetaveña <rbarroetavena@anura.com.ar>
*
*/
#include "private/ftdm_core.h"
@@ -144,3 +150,20 @@ FT_DECLARE(ftdm_status_t) ftdm_is_number(const char *number)
return FTDM_SUCCESS;
}
FT_DECLARE(ftdm_status_t) ftdm_set_calling_party_category(const char *string, uint8_t *target)
{
uint8_t val;
ftdm_status_t status = FTDM_SUCCESS;
val = ftdm_str2ftdm_calling_party_category(string);
if (val == FTDM_CPC_INVALID) {
ftdm_log(FTDM_LOG_WARNING, "Invalid category string (%s)\n", string);
val = FTDM_CPC_ORDINARY;
status = FTDM_FAIL;
}
*target = val;
return status;
}
+491 -517
View File
File diff suppressed because it is too large Load Diff
-692
View File
@@ -1,692 +0,0 @@
/*
* ftdm_m3ua.c
* freetdm
*
* Created by Shane Burrell on 4/3/08.
* Copyright 2008 Shane Burrell. All rights reserved.
*
*
* Copyright (c) 2007, Anthony Minessale II, Nenad Corbic *
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "freetdm.h"
#include "m3ua_client.h"
#include "ftdm_m3ua.h"
#define MAX_REQ_ID MAX_PENDING_CALLS
typedef uint16_t m3ua_request_id_t;
typedef enum {
BST_FREE,
BST_WAITING,
BST_READY,
BST_FAIL
} m3ua_request_status_t;
typedef struct {
m3ua_request_status_t status;
m3uac_event_t event;
ftdm_span_t *span;
ftdm_channel_t *ftdmchan;
} m3ua_request_t;
struct general_config {
uint32_t region;
};
typedef struct general_config general_config_t;
struct m3ua_channel_profile {
char name[80];
int cust_span;
unsigned char opc[3];
unsigned char dpc[3];
int local_ip[4];
int local_port;
int remote_ip[4];
int remote_port;
int m3ua_mode;
};
typedef struct m3ua_channel_profile m3ua_channel_profile_t;
static struct {
ftdm_hash_t *profile_hash;
general_config_t general_config;
} globals;
struct m3ua_span_data {
uint32_t boardno;
uint32_t flags;
};
typedef struct m3ua_span_data m3ua_span_data_t;
struct m3ua_chan_data {
ftdm_buffer_t *digit_buffer;
ftdm_mutex_t *digit_mutex;
ftdm_size_t dtmf_len;
uint32_t flags;
uint32_t hdlc_bytes;
};
typedef struct m3ua_chan_data m3ua_chan_data_t;
static ftdm_mutex_t *request_mutex = NULL;
static ftdm_mutex_t *signal_mutex = NULL;
static uint8_t req_map[MAX_REQ_ID+1] = { 0 };
static void release_request_id(m3ua_request_id_t r)
{
ftdm_mutex_lock(request_mutex);
req_map[r] = 0;
ftdm_mutex_unlock(request_mutex);
}
/*static m3ua_request_id_t next_request_id(void)
{
m3ua_request_id_t r = 0;
int ok = 0;
while(!ok) {
ftdm_mutex_lock(request_mutex);
for (r = 1; r <= MAX_REQ_ID; r++) {
if (!req_map[r]) {
ok = 1;
req_map[r] = 1;
break;
}
}
ftdm_mutex_unlock(request_mutex);
if (!ok) {
ftdm_sleep(5);
}
}
return r;
}
*/
static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
{
m3ua_data_t *m3ua_data = ftdmchan->span->signal_data;
m3uac_connection_t *mcon = &m3ua_data->mcon;
ftdm_sigmsg_t sig;
ftdm_status_t status;
ftdm_log(FTDM_LOG_DEBUG, "%d:%d STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
memset(&sig, 0, sizeof(sig));
sig.chan_id = ftdmchan->chan_id;
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_DOWN:
{
if (ftdmchan->extra_id) {
release_request_id((m3ua_request_id_t)ftdmchan->extra_id);
ftdmchan->extra_id = 0;
}
ftdm_channel_close(&ftdmchan);
}
break;
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_PROGRESS:
{
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
}
} else {
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_START_ACK,
0);
}
}
break;
case FTDM_CHANNEL_STATE_RING:
{
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
sig.event_id = FTDM_SIGEVENT_START;
if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
}
}
}
break;
case FTDM_CHANNEL_STATE_RESTART:
{
if (ftdmchan->last_state != FTDM_CHANNEL_STATE_HANGUP && ftdmchan->last_state != FTDM_CHANNEL_STATE_DOWN) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
} else {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
}
}
break;
case FTDM_CHANNEL_STATE_UP:
{
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
sig.event_id = FTDM_SIGEVENT_UP;
if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
}
} else {
if (!(ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA))) {
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_START_ACK,
0);
}
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_ANSWERED,
0);
}
}
break;
case FTDM_CHANNEL_STATE_DIALING:
{
}
break;
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
{
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
}
break;
case FTDM_CHANNEL_STATE_HANGUP:
{
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_ANSWERED) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA)) {
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_STOPPED,
ftdmchan->caller_data.hangup_cause);
} else {
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_START_NACK,
ftdmchan->caller_data.hangup_cause);
}
}
break;
case FTDM_CHANNEL_STATE_CANCEL:
{
sig.event_id = FTDM_SIGEVENT_STOP;
status = m3ua_data->signal_cb(&sig);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_START_NACK_ACK,
0);
}
break;
case FTDM_CHANNEL_STATE_TERMINATING:
{
sig.event_id = FTDM_SIGEVENT_STOP;
status = m3ua_data->signal_cb(&sig);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
m3uac_exec_command(mcon,
ftdmchan->physical_span_id-1,
ftdmchan->physical_chan_id-1,
0,
SIGBOOST_EVENT_CALL_STOPPED_ACK,
0);
}
break;
default:
break;
}
}
static __inline__ void check_state(ftdm_span_t *span)
{
if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
uint32_t j;
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
for(j = 1; j <= span->chan_count; j++) {
if (ftdm_test_flag((&span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_clear_flag_locked((&span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
state_advance(&span->channels[j]);
ftdm_channel_complete_state(&span->channels[j]);
}
}
}
}
static int parse_ss7_event(ftdm_span_t *span, m3uac_connection_t *mcon, m3uac_event_t *event)
{
ftdm_mutex_lock(signal_mutex);
if (!ftdm_running()) {
ftdm_log(FTDM_LOG_WARNING, "System is shutting down.\n");
goto end;
}
if (ftdm_test_flag(span, FTDM_SPAN_SUSPENDED) &&
event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK && event->event_id != SIGBOOST_EVENT_HEARTBEAT) {
ftdm_log(FTDM_LOG_WARNING,
"INVALID EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
m3uac_event_id_name(event->event_id),
event->event_id,
event->span+1,
event->chan+1,
event->release_cause,
event->call_setup_id,
event->fseqno,
(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
);
goto end;
}
ftdm_log(FTDM_LOG_DEBUG,
"RX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
m3uac_event_id_name(event->event_id),
event->event_id,
event->span+1,
event->chan+1,
event->release_cause,
event->call_setup_id,
event->fseqno,
(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
);
switch(event->event_id) {
case SIGBOOST_EVENT_CALL_START:
//handle_call_start(span, mcon, event);
break;
case SIGBOOST_EVENT_CALL_STOPPED:
//handle_call_stop(span, mcon, event);
break;
case SIGBOOST_EVENT_CALL_START_ACK:
//handle_call_start_ack(mcon, event);
break;
case SIGBOOST_EVENT_CALL_START_NACK:
//handle_call_start_nack(span, mcon, event);
break;
case SIGBOOST_EVENT_CALL_ANSWERED:
//handle_call_answer(span, mcon, event);
break;
case SIGBOOST_EVENT_HEARTBEAT:
//handle_heartbeat(mcon, event);
break;
case SIGBOOST_EVENT_CALL_STOPPED_ACK:
case SIGBOOST_EVENT_CALL_START_NACK_ACK:
//handle_call_done(span, mcon, event);
break;
case SIGBOOST_EVENT_INSERT_CHECK_LOOP:
//handle_call_loop_start(event);
break;
case SIGBOOST_EVENT_REMOVE_CHECK_LOOP:
//handle_call_stop(event);
break;
case SIGBOOST_EVENT_SYSTEM_RESTART_ACK:
//handle_restart_ack(mcon, span, event);
break;
case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE:
//handle_gap_abate(event);
break;
default:
ftdm_log(FTDM_LOG_WARNING, "No handler implemented for [%s]\n", m3uac_event_id_name(event->event_id));
break;
}
end:
ftdm_mutex_unlock(signal_mutex);
return 0;
}
static FIO_CONFIGURE_FUNCTION(m3ua_configure)
{
m3ua_channel_profile_t *profile = NULL;
int ok = 1;
if (!(profile = (m3ua_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
profile = ftdm_malloc(sizeof(*profile));
memset(profile, 0, sizeof(*profile));
ftdm_set_string(profile->name, category);
hashtable_insert(globals.profile_hash, (void *)profile->name, profile);
ftdm_log(FTDM_LOG_INFO, "creating profile [%s]\n", category);
}
// ftdm_set_string(m3ua_data->mcon. cfg.local_ip, local_ip);
if (!strcasecmp(var, "local_sctp_port")) {
profile->local_port = 30000 ;
profile->remote_port = 30000;
profile->cust_span++;
}
ok = 1;
if (ok) {
ftdm_log(FTDM_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
} else {
ftdm_log(FTDM_LOG_ERROR, "unknown param [%s]\n", var);
}
return FTDM_SUCCESS;
}
static FIO_CONFIGURE_SPAN_FUNCTION(m3ua_configure_span)
{
return FTDM_FAIL;
}
static FIO_OPEN_FUNCTION(m3ua_open)
{
return FTDM_FAIL;
}
static FIO_CLOSE_FUNCTION(m3ua_close)
{
return FTDM_FAIL;
}
/*static FIO_SET_INTERVAL_FUNCTION(m3ua_set_interval)
{
return 0;
}*/
static FIO_WAIT_FUNCTION(m3ua_wait)
{
return FTDM_FAIL;
}
static FIO_READ_FUNCTION(m3ua_read)
{
return FTDM_FAIL;
}
static FIO_WRITE_FUNCTION(m3ua_write)
{
return FTDM_FAIL;
}
static FIO_COMMAND_FUNCTION(m3ua_command)
{
return FTDM_FAIL;
}
static FIO_SPAN_POLL_EVENT_FUNCTION(m3ua_poll_event)
{
return FTDM_FAIL;
}
static FIO_SPAN_NEXT_EVENT_FUNCTION(m3ua_next_event)
{
return FTDM_FAIL;
}
static FIO_SPAN_DESTROY_FUNCTION(m3ua_span_destroy)
{
m3ua_span_data_t *span_data = (m3ua_span_data_t *) span->io_data;
if (span_data) {
ftdm_safe_free(span_data);
}
return FTDM_SUCCESS;
}
static FIO_CHANNEL_DESTROY_FUNCTION(m3ua_channel_destroy)
{
m3ua_chan_data_t *chan_data = (m3ua_chan_data_t *) ftdmchan->io_data;
m3ua_span_data_t *span_data = (m3ua_span_data_t *) ftdmchan->span->io_data;
if (!chan_data) {
return FTDM_FAIL;
}
ftdm_mutex_destroy(&chan_data->digit_mutex);
ftdm_buffer_destroy(&chan_data->digit_buffer);
ftdm_safe_free(chan_data);
if (span_data) {
ftdm_safe_free(span_data);
}
return FTDM_SUCCESS;
}
static FIO_GET_ALARMS_FUNCTION(m3ua_get_alarms)
{
return FTDM_FAIL;
}
static ftdm_io_interface_t m3ua_interface;
ftdm_status_t m3ua_init(ftdm_io_interface_t **zint)
{
assert(zint != NULL);
memset(&m3ua_interface, 0, sizeof(m3ua_interface));
m3ua_interface.name = "m3ua";
m3ua_interface.configure = m3ua_configure;
m3ua_interface.configure_span = m3ua_configure_span;
m3ua_interface.open = m3ua_open;
m3ua_interface.close = m3ua_close;
m3ua_interface.wait = m3ua_wait;
m3ua_interface.read = m3ua_read;
m3ua_interface.write = m3ua_write;
m3ua_interface.command = m3ua_command;
m3ua_interface.poll_event = m3ua_poll_event;
m3ua_interface.next_event = m3ua_next_event;
m3ua_interface.channel_destroy = m3ua_channel_destroy;
m3ua_interface.span_destroy = m3ua_span_destroy;
m3ua_interface.get_alarms = m3ua_get_alarms;
*zint = &m3ua_interface;
return FTDM_FAIL;
}
ftdm_status_t m3ua_destroy(void)
{
return FTDM_FAIL;
}
static void *m3ua_run(ftdm_thread_t *me, void *obj)
{
ftdm_span_t *span = (ftdm_span_t *) obj;
m3ua_data_t *m3ua_data = span->signal_data;
m3uac_connection_t *mcon, *pcon;
uint32_t ms = 10, too_long = 60000;
m3ua_data->pcon = m3ua_data->mcon;
if (m3uac_connection_open(&m3ua_data->mcon,
m3ua_data->mcon.cfg.local_ip,
m3ua_data->mcon.cfg.local_port,
m3ua_data->mcon.cfg.remote_ip,
m3ua_data->mcon.cfg.remote_port) < 0) {
ftdm_log(FTDM_LOG_DEBUG, "Error: Opening MCON Socket [%d] %s\n", m3ua_data->mcon.socket, strerror(errno));
goto end;
}
if (m3uac_connection_open(&m3ua_data->pcon,
m3ua_data->pcon.cfg.local_ip,
++m3ua_data->pcon.cfg.local_port,
m3ua_data->pcon.cfg.remote_ip,
m3ua_data->pcon.cfg.remote_port) < 0) {
ftdm_log(FTDM_LOG_DEBUG, "Error: Opening PCON Socket [%d] %s\n", m3ua_data->pcon.socket, strerror(errno));
goto end;
}
mcon = &m3ua_data->mcon;
pcon = &m3ua_data->pcon;
top:
//init_outgoing_array();
m3uac_exec_command(mcon,
0,
0,
-1,
SIGBOOST_EVENT_SYSTEM_RESTART,
0);
while (ftdm_test_flag(m3ua_data, FTDM_M3UA_RUNNING)) {
fd_set rfds, efds;
struct timeval tv = { 0, ms * 1000 };
int max, activity, i = 0;
m3uac_event_t *event = NULL;
if (!ftdm_running()) {
m3uac_exec_command(mcon,
0,
0,
-1,
SIGBOOST_EVENT_SYSTEM_RESTART,
0);
break;
}
FD_ZERO(&rfds);
FD_ZERO(&efds);
FD_SET(mcon->socket, &rfds);
FD_SET(mcon->socket, &efds);
FD_SET(pcon->socket, &rfds);
FD_SET(pcon->socket, &efds);
max = ((pcon->socket > mcon->socket) ? pcon->socket : mcon->socket) + 1;
if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) {
goto error;
}
if (activity) {
if (FD_ISSET(pcon->socket, &efds) || FD_ISSET(mcon->socket, &efds)) {
goto error;
}
if (FD_ISSET(pcon->socket, &rfds)) {
if ((event = m3uac_connection_readp(pcon, i))) {
parse_ss7_event(span, mcon, event);
} else goto top;
}
if (FD_ISSET(mcon->socket, &rfds)) {
if ((event = m3uac_connection_read(mcon, i))) {
parse_ss7_event(span, mcon, event);
} else goto top;
}
}
check_state(span);
mcon->hb_elapsed += ms;
if (mcon->hb_elapsed >= too_long && (mcon->up || !ftdm_test_flag(span, FTDM_SPAN_SUSPENDED))) {
ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED);
mcon->up = 0;
ftdm_log(FTDM_LOG_CRIT, "Lost Heartbeat!\n");
}
}
goto end;
error:
ftdm_log(FTDM_LOG_CRIT, "Socket Error!\n");
end:
m3uac_connection_close(&m3ua_data->mcon);
m3uac_connection_close(&m3ua_data->pcon);
ftdm_clear_flag(m3ua_data, FTDM_M3UA_RUNNING);
ftdm_log(FTDM_LOG_DEBUG, "M3UA thread ended.\n");
return NULL;
}
ftdm_status_t m3ua_start(ftdm_span_t *span)
{
m3ua_data_t *m3ua_data = span->signal_data;
ftdm_set_flag(m3ua_data, FTDM_M3UA_RUNNING);
return ftdm_thread_create_detached(m3ua_run, span);
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
*/
+486
View File
@@ -0,0 +1,486 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* Moises Silva <moy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "private/ftdm_core.h"
FTDM_ENUM_NAMES(CHANNEL_STATE_NAMES, CHANNEL_STATE_STRINGS)
FTDM_STR2ENUM(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t, CHANNEL_STATE_NAMES, FTDM_CHANNEL_STATE_INVALID)
FTDM_ENUM_NAMES(CHANNEL_STATE_STATUS_NAMES, CHANNEL_STATE_STATUS_STRINGS)
FTDM_STR2ENUM(ftdm_str2ftdm_state_status, ftdm_state_status2str, ftdm_state_status_t, CHANNEL_STATE_STATUS_NAMES, FTDM_STATE_STATUS_INVALID)
/* This function is only needed for boost and we should get rid of it at the next refactoring */
FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *fchan)
{
ftdm_channel_lock(fchan);
if (fchan->init_state != FTDM_CHANNEL_STATE_DOWN) {
ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, fchan, fchan->init_state, 1);
fchan->init_state = FTDM_CHANNEL_STATE_DOWN;
}
ftdm_channel_unlock(fchan);
return FTDM_SUCCESS;
}
FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const char *func, int line, ftdm_channel_t *fchan)
{
uint8_t hindex = 0;
ftdm_time_t diff = 0;
ftdm_channel_state_t state = fchan->state;
if (fchan->state_status == FTDM_STATE_STATUS_COMPLETED) {
ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL,
"State change flag set but state is not completed\n");
return FTDM_SUCCESS;
}
ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
if (state == FTDM_CHANNEL_STATE_PROGRESS) {
ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
} else if (state == FTDM_CHANNEL_STATE_UP) {
ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
ftdm_set_flag(fchan, FTDM_CHANNEL_MEDIA);
ftdm_set_flag(fchan, FTDM_CHANNEL_ANSWERED);
} else if (state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
ftdm_set_flag(fchan, FTDM_CHANNEL_MEDIA);
}
/* if there is a pending ack for an indication
* MAINTENANCE WARNING: we're assuming an indication performed
* via state change will involve a single state change
*/
if (ftdm_test_flag(fchan, FTDM_CHANNEL_IND_ACK_PENDING)) {
ftdm_ack_indication(fchan, fchan->indication, FTDM_SUCCESS);
}
hindex = (fchan->hindex == 0) ? (ftdm_array_len(fchan->history) - 1) : (fchan->hindex - 1);
ftdm_assert(!fchan->history[hindex].end_time, "End time should be zero!\n");
fchan->history[hindex].end_time = ftdm_current_time_in_ms();
fchan->state_status = FTDM_STATE_STATUS_COMPLETED;
diff = fchan->history[hindex].end_time - fchan->history[hindex].time;
ftdm_log_chan_ex(fchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Completed state change from %s to %s in %llums\n",
ftdm_channel_state2str(fchan->last_state), ftdm_channel_state2str(state), diff);
if (ftdm_test_flag(fchan, FTDM_CHANNEL_BLOCKING)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_BLOCKING);
ftdm_interrupt_signal(fchan->state_completed_interrupt);
}
return FTDM_SUCCESS;
}
FT_DECLARE(ftdm_status_t) _ftdm_set_state(const char *file, const char *func, int line,
ftdm_channel_t *fchan, ftdm_channel_state_t state)
{
if (fchan->state_status != FTDM_STATE_STATUS_COMPLETED) {
/* the current state is not completed, setting a new state from a signaling module
when the current state is not completed is equivalent to implicitly acknowledging
the current state */
_ftdm_channel_complete_state(file, func, line, fchan);
}
return ftdm_channel_set_state(file, func, line, fchan, state, 0);
}
static int ftdm_parse_state_map(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, ftdm_state_map_t *state_map)
{
int x = 0, ok = 0;
ftdm_state_direction_t direction = ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? ZSD_OUTBOUND : ZSD_INBOUND;
for(x = 0; x < FTDM_MAP_NODE_SIZE; x++) {
int i = 0, proceed = 0;
if (!state_map->nodes[x].type) {
break;
}
if (state_map->nodes[x].direction != direction) {
continue;
}
if (state_map->nodes[x].check_states[0] == FTDM_ANY_STATE) {
proceed = 1;
} else {
for(i = 0; i < FTDM_MAP_MAX; i++) {
if (state_map->nodes[x].check_states[i] == ftdmchan->state) {
proceed = 1;
break;
}
}
}
if (!proceed) {
continue;
}
for(i = 0; i < FTDM_MAP_MAX; i++) {
ok = (state_map->nodes[x].type == ZSM_ACCEPTABLE);
if (state_map->nodes[x].states[i] == FTDM_END) {
break;
}
if (state_map->nodes[x].states[i] == state) {
ok = !ok;
goto end;
}
}
}
end:
return ok;
}
/* this function MUST be called with the channel lock held. If waitrq == 1, the channel will be unlocked/locked (never call it with waitrq == 1 with an lock recursivity > 1) */
#define DEFAULT_WAIT_TIME 1000
FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int waitrq)
{
ftdm_status_t status;
int ok = 1;
int waitms = DEFAULT_WAIT_TIME;
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) {
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR, "Ignored state change request from %s to %s, the channel is not ready\n",
ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
return FTDM_FAIL;
}
if (ftdmchan->state_status != FTDM_STATE_STATUS_COMPLETED) {
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR,
"Ignored state change request from %s to %s, the previous state change has not been processed yet (status = %s)\n",
ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state),
ftdm_state_status2str(ftdmchan->state_status));
return FTDM_FAIL;
}
if (ftdmchan->state == state) {
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "Why bother changing state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
return FTDM_FAIL;
}
if (!ftdmchan->state_completed_interrupt) {
status = ftdm_interrupt_create(&ftdmchan->state_completed_interrupt, FTDM_INVALID_SOCKET);
if (status != FTDM_SUCCESS) {
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_CRIT,
"Failed to create state change interrupt when moving from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
return status;
}
}
if (ftdmchan->span->state_map) {
ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map);
goto end;
}
/* basic core state validation (by-passed if the signaling module provides a state_map) */
switch(ftdmchan->state) {
case FTDM_CHANNEL_STATE_HANGUP:
case FTDM_CHANNEL_STATE_TERMINATING:
{
ok = 0;
switch(state) {
case FTDM_CHANNEL_STATE_DOWN:
case FTDM_CHANNEL_STATE_BUSY:
case FTDM_CHANNEL_STATE_RESTART:
ok = 1;
break;
default:
break;
}
}
break;
case FTDM_CHANNEL_STATE_UP:
{
ok = 1;
switch(state) {
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_RING:
ok = 0;
break;
default:
break;
}
}
break;
case FTDM_CHANNEL_STATE_DOWN:
{
ok = 0;
switch(state) {
case FTDM_CHANNEL_STATE_DIALTONE:
case FTDM_CHANNEL_STATE_COLLECT:
case FTDM_CHANNEL_STATE_DIALING:
case FTDM_CHANNEL_STATE_RING:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_IDLE:
case FTDM_CHANNEL_STATE_GET_CALLERID:
case FTDM_CHANNEL_STATE_GENRING:
ok = 1;
break;
default:
break;
}
}
break;
case FTDM_CHANNEL_STATE_BUSY:
{
switch(state) {
case FTDM_CHANNEL_STATE_UP:
ok = 0;
break;
default:
break;
}
}
break;
case FTDM_CHANNEL_STATE_RING:
{
switch(state) {
case FTDM_CHANNEL_STATE_UP:
ok = 1;
break;
default:
break;
}
}
break;
default:
break;
}
end:
if (!ok) {
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "VETO state change from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
goto done;
}
ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Changed state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
ftdmchan->last_state = ftdmchan->state;
ftdmchan->state = state;
ftdmchan->state_status = FTDM_STATE_STATUS_NEW;
ftdmchan->history[ftdmchan->hindex].file = file;
ftdmchan->history[ftdmchan->hindex].func = func;
ftdmchan->history[ftdmchan->hindex].line = line;
ftdmchan->history[ftdmchan->hindex].state = ftdmchan->state;
ftdmchan->history[ftdmchan->hindex].last_state = ftdmchan->last_state;
ftdmchan->history[ftdmchan->hindex].time = ftdm_current_time_in_ms();
ftdmchan->history[ftdmchan->hindex].end_time = 0;
ftdmchan->hindex++;
if (ftdmchan->hindex == ftdm_array_len(ftdmchan->history)) {
ftdmchan->hindex = 0;
}
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_mutex_lock(ftdmchan->span->mutex);
ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
if (ftdmchan->span->pendingchans) {
ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan);
}
ftdm_mutex_unlock(ftdmchan->span->mutex);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NONBLOCK)) {
/* the channel should not block waiting for state processing */
goto done;
}
if (!waitrq) {
/* no waiting was requested */
goto done;
}
/* let's wait for the state change to be completed by the signaling stack */
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_BLOCKING);
ftdm_mutex_unlock(ftdmchan->mutex);
status = ftdm_interrupt_wait(ftdmchan->state_completed_interrupt, waitms);
ftdm_mutex_lock(ftdmchan->mutex);
if (status != FTDM_SUCCESS) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_BLOCKING);
ftdm_log_chan_ex(ftdmchan, file, func, line,
FTDM_LOG_LEVEL_WARNING, "state change from %s to %s was most likely not completed after aprox %dms\n",
ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(state), DEFAULT_WAIT_TIME);
ok = 0;
goto done;
}
done:
return ok ? FTDM_SUCCESS : FTDM_FAIL;
}
FT_DECLARE(int) ftdm_channel_get_state(const ftdm_channel_t *ftdmchan)
{
int state;
ftdm_channel_lock(ftdmchan);
state = ftdmchan->state;
ftdm_channel_unlock(ftdmchan);
return state;
}
FT_DECLARE(const char *) ftdm_channel_get_state_str(const ftdm_channel_t *ftdmchan)
{
const char *state;
ftdm_channel_lock(ftdmchan);
state = ftdm_channel_state2str(ftdmchan->state);
ftdm_channel_unlock(ftdmchan);
return state;
}
FT_DECLARE(int) ftdm_channel_get_last_state(const ftdm_channel_t *ftdmchan)
{
int last_state;
ftdm_channel_lock(ftdmchan);
last_state = ftdmchan->last_state;
ftdm_channel_unlock(ftdmchan);
return last_state;
}
FT_DECLARE(const char *) ftdm_channel_get_last_state_str(const ftdm_channel_t *ftdmchan)
{
const char *state;
ftdm_channel_lock(ftdmchan);
state = ftdm_channel_state2str(ftdmchan->last_state);
ftdm_channel_unlock(ftdmchan);
return state;
}
static void write_history_entry(const ftdm_channel_t *fchan, ftdm_stream_handle_t *stream, int i, ftdm_time_t *prevtime)
{
char func[255];
char line[255];
char states[255];
const char *filename = NULL;
snprintf(states, sizeof(states), "%-5.15s => %-5.15s", ftdm_channel_state2str(fchan->history[i].last_state), ftdm_channel_state2str(fchan->history[i].state));
snprintf(func, sizeof(func), "[%s]", fchan->history[i].func);
filename = strrchr(fchan->history[i].file, *FTDM_PATH_SEPARATOR);
if (!filename) {
filename = fchan->history[i].file;
} else {
filename++;
}
if (!(*prevtime)) {
*prevtime = fchan->history[i].time;
}
snprintf(line, sizeof(func), "[%s:%d]", filename, fchan->history[i].line);
stream->write_function(stream, "%-30.30s %-30.30s %-30.30s %lums\n", states, func, line, (fchan->history[i].time - *prevtime));
*prevtime = fchan->history[i].time;
}
FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan)
{
uint8_t i = 0;
ftdm_time_t currtime = 0;
ftdm_time_t prevtime = 0;
ftdm_stream_handle_t stream = { 0 };
FTDM_STANDARD_STREAM(stream);
if (!fchan->history[0].file) {
stream.write_function(&stream, "-- No state history --\n");
return stream.data;
}
stream.write_function(&stream, "%-30.30s %-30.30s %-30.30s %s",
"-- States --", "-- Function --", "-- Location --", "-- Time Offset --\n");
for (i = fchan->hindex; i < ftdm_array_len(fchan->history); i++) {
if (!fchan->history[i].file) {
break;
}
write_history_entry(fchan, &stream, i, &prevtime);
}
for (i = 0; i < fchan->hindex; i++) {
write_history_entry(fchan, &stream, i, &prevtime);
}
currtime = ftdm_current_time_in_ms();
stream.write_function(&stream, "\nTime since last state change: %lums\n", (currtime - prevtime));
return stream.data;
}
FT_DECLARE(ftdm_status_t) ftdm_channel_advance_states(ftdm_channel_t *fchan)
{
ftdm_channel_state_t state;
ftdm_assert_return(fchan->span->state_processor, FTDM_FAIL, "Cannot process states without a state processor!\n");
while (fchan->state_status == FTDM_STATE_STATUS_NEW) {
state = fchan->state;
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Executing state processor for %s\n", ftdm_channel_state2str(fchan->state));
fchan->span->state_processor(fchan);
if (state == fchan->state && fchan->state_status == FTDM_STATE_STATUS_NEW) {
/* if the state did not change and is still NEW, the state status must go to PROCESSED
* otherwise we don't touch it since is a new state and the old state was
* already completed implicitly by the state_processor() function via some internal
* call to ftdm_set_state() */
fchan->state_status = FTDM_STATE_STATUS_PROCESSED;
}
}
return FTDM_SUCCESS;
}
FT_DECLARE(int) ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state)
{
uint32_t j;
for(j = 1; j <= span->chan_count; j++) {
if (span->channels[j]->state != state || ftdm_test_flag(span->channels[j], FTDM_CHANNEL_STATE_CHANGE)) {
return 0;
}
}
return 1;
}
/* 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:
*/
+10 -3
View File
@@ -56,7 +56,11 @@ struct ftdm_interrupt {
/* for generic interruption */
HANDLE event;
#else
/* for generic interruption */
/* In theory we could be using thread conditions for generic interruption,
* however, Linux does not have a primitive like Windows WaitForMultipleObjects
* to wait for both thread condition and file descriptors, therefore we decided
* to use a dummy pipe for generic interruption/condition logic
* */
int readfd;
int writefd;
#endif
@@ -243,6 +247,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_mutex_unlock(ftdm_mutex_t *mutex)
FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt, ftdm_socket_t device)
{
ftdm_status_t status = FTDM_SUCCESS;
ftdm_interrupt_t *interrupt = NULL;
#ifndef WIN32
int fds[2];
@@ -253,7 +258,7 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt,
interrupt = ftdm_calloc(1, sizeof(*interrupt));
if (!interrupt) {
ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt memory\n");
return FTDM_FAIL;
return FTDM_ENOMEM;
}
interrupt->device = device;
@@ -261,11 +266,13 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt,
interrupt->event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!interrupt->event) {
ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt event\n");
status = FTDM_ENOMEM;
goto failed;
}
#else
if (pipe(fds)) {
ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt pipe: %s\n", strerror(errno));
status = FTDM_FAIL;
goto failed;
}
interrupt->readfd = fds[0];
@@ -287,7 +294,7 @@ failed:
#endif
ftdm_safe_free(interrupt);
}
return FTDM_FAIL;
return status;
}
#define ONE_BILLION 1000000000
@@ -37,7 +37,9 @@
typedef enum {
FTDM_ANALOG_RUNNING = (1 << 0),
FTDM_ANALOG_CALLERID = (1 << 1)
FTDM_ANALOG_CALLERID = (1 << 1),
FTDM_ANALOG_ANSWER_POLARITY_REVERSE = (1 << 2),
FTDM_ANALOG_HANGUP_POLARITY_REVERSE = (1 << 3)
} ftdm_analog_flag_t;
#define FTDM_MAX_HOTLINE_STR 20
@@ -47,11 +49,13 @@ struct ftdm_analog_data {
uint32_t flags;
uint32_t max_dialstr;
uint32_t wait_dialtone_timeout;
uint32_t polarity_delay;
uint32_t digit_timeout;
char hotline[FTDM_MAX_HOTLINE_STR];
};
/* Analog flags to be set in the sflags (signaling flags) channel memeber */
#define AF_POLARITY_REVERSE (1 << 0)
static void *ftdm_analog_run(ftdm_thread_t *me, void *obj);
typedef struct ftdm_analog_data ftdm_analog_data_t;
@@ -96,6 +96,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_get_channel_sig_status)
{
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) {
*status = FTDM_SIG_STATE_DOWN;
return FTDM_SUCCESS;
}
*status = FTDM_SIG_STATE_UP;
return FTDM_SUCCESS;
}
@@ -109,7 +113,25 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_get_channel_sig_status)
static FIO_SPAN_GET_SIG_STATUS_FUNCTION(analog_get_span_sig_status)
{
*status = FTDM_SIG_STATE_UP;
ftdm_iterator_t *citer = NULL;
ftdm_iterator_t *chaniter = ftdm_span_get_chan_iterator(span, NULL);
if (!chaniter) {
ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
return FTDM_FAIL;
}
/* if ALL channels are in alarm, report DOWN, UP otherwise. */
*status = FTDM_SIG_STATE_DOWN;
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
ftdm_channel_t *fchan = ftdm_iterator_current(citer);
ftdm_channel_lock(fchan);
if (!ftdm_test_flag(fchan, FTDM_CHANNEL_IN_ALARM)) {
*status = FTDM_SIG_STATE_UP;
ftdm_channel_unlock(fchan);
break;
}
ftdm_channel_unlock(fchan);
}
ftdm_iterator_free(chaniter);
return FTDM_SUCCESS;
}
@@ -162,6 +184,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
uint32_t digit_timeout = 10;
uint32_t wait_dialtone_timeout = 30000;
uint32_t max_dialstr = MAX_DTMF;
uint32_t polarity_delay = 600;
const char *var, *val;
int *intval;
uint32_t flags = FTDM_ANALOG_CALLERID;
@@ -214,6 +237,29 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
} else {
flags &= ~FTDM_ANALOG_CALLERID;
}
} else if (!strcasecmp(var, "answer_polarity_reverse")) {
if (!(val = va_arg(ap, char *))) {
break;
}
if (ftdm_true(val)) {
flags |= FTDM_ANALOG_ANSWER_POLARITY_REVERSE;
} else {
flags &= ~FTDM_ANALOG_ANSWER_POLARITY_REVERSE;
}
} else if (!strcasecmp(var, "hangup_polarity_reverse")) {
if (!(val = va_arg(ap, char *))) {
break;
}
if (ftdm_true(val)) {
flags |= FTDM_ANALOG_HANGUP_POLARITY_REVERSE;
} else {
flags &= ~FTDM_ANALOG_HANGUP_POLARITY_REVERSE;
}
} else if (!strcasecmp(var, "polarity_delay")) {
if (!(intval = va_arg(ap, int *))) {
break;
}
polarity_delay = *intval;
} else if (!strcasecmp(var, "callwaiting")) {
if (!(intval = va_arg(ap, int *))) {
break;
@@ -254,6 +300,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
analog_data->flags = flags;
analog_data->digit_timeout = digit_timeout;
analog_data->wait_dialtone_timeout = wait_dialtone_timeout;
analog_data->polarity_delay = polarity_delay;
analog_data->max_dialstr = max_dialstr;
span->signal_cb = sig_cb;
strncpy(analog_data->hotline, hotline, sizeof(analog_data->hotline));
@@ -377,6 +424,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
ftdm_analog_data_t *analog_data = ftdmchan->span->signal_data;
ftdm_channel_t *closed_chan;
uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = analog_data->wait_dialtone_timeout;
uint32_t answer_on_polarity_counter = 0;
ftdm_sigmsg_t sig;
ftdm_status_t status;
@@ -448,7 +496,12 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
if (ftdmchan->needed_tones[FTDM_TONEMAP_DIAL]) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
} else {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
/* do not go up if we're waiting for polarity reversal */
if (ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
} else {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
}
}
}
}
@@ -493,8 +546,10 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS &&
ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) &&
(ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_RING)) {
(ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_RING
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_UP)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
} else {
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
@@ -530,15 +585,37 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
if (done) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
}
}
case FTDM_CHANNEL_STATE_UP:
case FTDM_CHANNEL_STATE_RING:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
{
ftdm_sleep(interval);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) &&
ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA &&
ftdm_test_sflag(ftdmchan, AF_POLARITY_REVERSE)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Answering on polarity reverse\n");
ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
answer_on_polarity_counter = state_counter;
} else if (ftdmchan->state == FTDM_CHANNEL_STATE_UP
&& ftdm_test_sflag(ftdmchan, AF_POLARITY_REVERSE)){
/* if this polarity reverse is close to the answer polarity reverse, ignore it */
if (answer_on_polarity_counter
&& (state_counter - answer_on_polarity_counter) > analog_data->polarity_delay) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Hanging up on polarity reverse\n");
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING,
"Not hanging up on polarity reverse, too close to Answer reverse\n");
}
ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE);
} else {
ftdm_sleep(interval);
}
continue;
}
break;
@@ -551,7 +628,6 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
break;
}
} else {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
indicate = 0;
@@ -591,6 +667,19 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
sig.event_id = FTDM_SIGEVENT_UP;
}
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS &&
!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) &&
ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)) {
ftdm_polarity_t polarity = FTDM_POLARITY_REVERSE;
if (ftdmchan->polarity == FTDM_POLARITY_FORWARD) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Reversing polarity on answer\n");
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_POLARITY, &polarity);
} else {
/* the polarity may be already reversed if this is the second time we
* answer (ie, due to 2 calls being on the same line) */
}
}
ftdm_span_send_signal(ftdmchan->span, &sig);
continue;
}
@@ -615,6 +704,22 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
continue;
}
break;
case FTDM_CHANNEL_STATE_HANGUP:
/* this state is only used when the user hangup, if the device hang up (onhook) we currently
* go straight to DOWN. If we ever change this (as other signaling modules do) by using this
* state for both user and device hangup, we should check here for the type of hangup since
* some actions (polarity reverse) do not make sense if the device hung up */
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS &&
ftdmchan->last_state == FTDM_CHANNEL_STATE_UP &&
ftdm_test_flag(analog_data, FTDM_ANALOG_HANGUP_POLARITY_REVERSE)) {
ftdm_polarity_t polarity = ftdmchan->polarity == FTDM_POLARITY_REVERSE
? FTDM_POLARITY_FORWARD : FTDM_POLARITY_REVERSE;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Reversing polarity on hangup\n");
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_POLARITY, &polarity);
}
break;
case FTDM_CHANNEL_STATE_DOWN:
{
sig.event_id = FTDM_SIGEVENT_STOP;
@@ -717,7 +822,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
dtmf_offset = strlen(dtmf);
last_digit = elapsed;
sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
sig.raw_data = dtmf;
ftdm_set_string(sig.ev_data.collected.digits, dtmf);
if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
collecting = 0;
}
@@ -823,6 +928,9 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
done:
closed_chan = ftdmchan;
ftdm_channel_lock(closed_chan);
if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
@@ -833,7 +941,8 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
}
closed_chan = ftdmchan;
ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE);
ftdm_channel_close(&ftdmchan);
ftdm_channel_command(closed_chan, FTDM_COMMAND_SET_NATIVE_CODEC, NULL);
@@ -851,8 +960,11 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
}
ftdm_log_chan(closed_chan, FTDM_LOG_DEBUG, "ANALOG CHANNEL %d:%d thread ended.\n", closed_chan->span_id, closed_chan->chan_id);
ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD);
ftdm_channel_unlock(closed_chan);
return NULL;
}
@@ -879,19 +991,32 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
ftdm_mutex_lock(event->channel->mutex);
locked++;
/* MAINTENANCE WARNING:
* 1. Be aware you are working on the locked channel
* 2. We should not be calling ftdm_span_send_signal or ftdm_set_state when there is already a channel thread running
* however, since this is old code I am not changing it now, but new code should adhere to that convention
* otherwise, we have possible races where we compete with the user for state changes, ie, the user requests
* a state change and then we process an event, the state change from the user is pending so our ftdm_set_state
* operation will fail. In cases where we win the race, our state change will be accepted but if a user requests
* a state change before the state change we requested here is processed by the channel thread, we'll end up
* rejecting the user request.
*
* See docs/locking.txt for further information about what guarantees should signaling modules provide when
* locking/unlocking a channel
* */
switch(event->enum_id) {
case FTDM_OOB_RING_START:
{
if (event->channel->type != FTDM_CHAN_TYPE_FXO) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_ERROR, "Cannot get a RING_START event on a non-fxo channel, please check your config.\n");
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN);
goto end;
}
if (!event->channel->ring_count && (event->channel->state == FTDM_CHANNEL_STATE_DOWN && !ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD))) {
if (ftdm_test_flag(analog_data, FTDM_ANALOG_CALLERID)) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
} else {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RING);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_RING);
}
event->channel->ring_count = 1;
ftdm_mutex_unlock(event->channel->mutex);
@@ -909,24 +1034,33 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
}
if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
if (event->channel->state == FTDM_CHANNEL_STATE_HANGUP &&
ftdm_test_flag(event->channel, FTDM_CHANNEL_STATE_CHANGE)) {
/* we do not need to process HANGUP since the device also hangup already */
ftdm_channel_complete_state(event->channel);
}
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN);
}
if (event->channel->type == FTDM_CHAN_TYPE_FXS) {
/* we always return to forward when the device goes onhook */
ftdm_polarity_t forward_polarity = FTDM_POLARITY_FORWARD;
ftdm_channel_command(event->channel, FTDM_COMMAND_SET_POLARITY, &forward_polarity);
}
}
break;
case FTDM_OOB_FLASH:
{
if (event->channel->state == FTDM_CHANNEL_STATE_CALLWAITING) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
ftdm_clear_flag_locked(event->channel, FTDM_CHANNEL_STATE_CHANGE);
ftdm_clear_flag_locked(event->channel->span, FTDM_SPAN_STATE_CHANGE);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP);
ftdm_clear_flag(event->channel->span, FTDM_SPAN_STATE_CHANGE);
ftdm_channel_complete_state(event->channel);
event->channel->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
}
ftdm_channel_rotate_tokens(event->channel);
if (ftdm_test_flag(event->channel, FTDM_CHANNEL_HOLD) && event->channel->token_count != 1) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP);
} else {
sig.event_id = FTDM_SIGEVENT_FLASH;
ftdm_span_send_signal(span, &sig);
@@ -940,12 +1074,12 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
if (ftdm_test_flag(event->channel, FTDM_CHANNEL_RINGING)) {
ftdm_channel_command(event->channel, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
}
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP);
} else {
if(!analog_data->max_dialstr) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_COLLECT);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_COLLECT);
} else {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
}
ftdm_mutex_unlock(event->channel->mutex);
locked = 0;
@@ -957,9 +1091,53 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL);
}
}
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN);
}
}
break;
case FTDM_OOB_ALARM_TRAP:
{
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN;
ftdm_span_send_signal(span, &sig);
}
break;
case FTDM_OOB_ALARM_CLEAR:
{
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.ev_data.sigstatus.status = FTDM_SIG_STATE_UP;
ftdm_span_send_signal(span, &sig);
}
break;
case FTDM_OOB_POLARITY_REVERSE:
{
if (event->channel->type != FTDM_CHAN_TYPE_FXO) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING,
"Ignoring polarity reversal, this should not happen in non-FXO channels!\n");
break;
}
if (!ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD) &&
ftdm_test_flag(event->channel, FTDM_CHANNEL_OFFHOOK)) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING,
"Forcing onhook in channel not in thread after polarity reversal\n");
ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL);
break;
}
if (!ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)
&& !ftdm_test_flag(analog_data, FTDM_ANALOG_HANGUP_POLARITY_REVERSE)) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG,
"Ignoring polarity reversal because this channel is not configured for it\n");
break;
}
if (event->channel->state == FTDM_CHANNEL_STATE_DOWN) {
ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG,
"Ignoring polarity reversal because this channel is down\n");
break;
}
/* we have a good channel, set the polarity flag and let the channel thread deal with it */
ftdm_set_sflag(event->channel, AF_POLARITY_REVERSE);
}
break;
default:
{
ftdm_log_chan(event->channel, FTDM_LOG_DEBUG, "Ignoring event [%s] in state [%s]\n", ftdm_oob_event2str(event->enum_id), ftdm_channel_state2str(event->channel->state));
@@ -355,7 +355,6 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
break;
}
} else {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
indicate = 0;
@@ -467,7 +466,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
dtmf_offset = strlen(dtmf);
last_digit = elapsed;
sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
sig.raw_data = dtmf;
ftdm_set_string(sig.ev_data.collected.digits, dtmf);
if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
collecting = 0;
}
@@ -497,7 +497,7 @@ static ftdm_state_map_t isdn_state_map = {
* \param ftdmchan Channel to handle
* \note This function MUST be called with the channel locked
*/
static __inline__ void state_advance(ftdm_channel_t *chan)
static ftdm_status_t state_advance(ftdm_channel_t *chan)
{
ftdm_libpri_data_t *isdn_data = chan->span->signal_data;
q931_call *call = (q931_call *)chan->call_data;
@@ -511,27 +511,23 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
sig.chan_id = ftdm_channel_get_id(chan);
sig.span_id = ftdm_channel_get_span_id(chan);
sig.channel = chan;
ftdm_channel_complete_state(chan);
switch (ftdm_channel_get_state(chan)) {
case FTDM_CHANNEL_STATE_DOWN:
{
ftdm_channel_t *chtmp = chan;
chan->call_data = NULL;
ftdm_channel_done(chan);
/*
* Close channel completely, BRI PTMP will thank us
*/
if (ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) {
ftdm_channel_t *chtmp = chan;
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
} else {
ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
}
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
} else {
ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n",
ftdm_channel_get_span_id(chan),
ftdm_channel_get_id(chan));
}
}
break;
@@ -631,7 +627,7 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan));
/* TODO: set hangup cause? */
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
return;
return FTDM_SUCCESS;
}
ton = caller_data->dnis.type;
@@ -714,6 +710,7 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
default:
break;
}
return FTDM_SUCCESS;
}
/**
@@ -729,13 +726,8 @@ static __inline__ void check_state(ftdm_span_t *span)
for (j = 1; j <= ftdm_span_get_chan_count(span); j++) {
ftdm_channel_t *chan = ftdm_span_get_channel(span, j);
ftdm_channel_lock(chan);
while (ftdm_test_flag(chan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_clear_flag(chan, FTDM_CHANNEL_STATE_CHANGE);
state_advance(chan);
ftdm_channel_complete_state(chan);
}
ftdm_channel_advance_states(chan);
ftdm_channel_unlock(chan);
}
}
@@ -1403,8 +1395,7 @@ static int on_dchan_up(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_ev
sig.chan_id = ftdm_channel_get_id(chan);
sig.channel = chan;
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.raw_data = &status;
sig.ev_data.sigstatus.status = status;
ftdm_span_send_signal(span, &sig);
}
}
@@ -1440,7 +1431,7 @@ static int on_dchan_down(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_
sig.chan_id = ftdm_channel_get_id(chan);
sig.channel = chan;
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.raw_data = &status;
sig.ev_data.sigstatus.status = status;
ftdm_span_send_signal(span, &sig);
}
@@ -1917,6 +1908,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
span->outgoing_call = isdn_outgoing_call;
span->state_map = &isdn_state_map;
span->state_processor = state_advance;
span->get_channel_sig_status = isdn_get_channel_sig_status;
span->get_span_sig_status = isdn_get_span_sig_status;
@@ -127,9 +127,8 @@ static int __pri_lpwrap_read(struct pri *pri, void *buf, int buflen)
} else {
ftdm_log(FTDM_LOG_CRIT, "span %d D-READ TIMEOUT\n", spri->span->span_id);
}
ftdm_clear_flag(spri, LPWRAP_PRI_READY);
return -1;
/* we cannot return -1, libpri seems to expect values >= 0 */
return 0;
}
spri->errs = 0;
res = (int)len;
@@ -156,8 +155,8 @@ static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen)
if (ftdm_channel_write(spri->dchan, buf, buflen, &len) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "span %d D-WRITE FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
ftdm_clear_flag(spri, LPWRAP_PRI_READY);
return -1;
/* we cannot return -1, libpri seems to expect values >= 0 */
return 0;
}
#ifdef IODEBUG
@@ -265,7 +265,7 @@ static ftdm_state_map_t pritap_state_map = {
}
};
static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
{
ftdm_status_t status;
ftdm_sigmsg_t sig;
@@ -278,6 +278,8 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
ftdm_channel_complete_state(ftdmchan);
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_DOWN:
{
@@ -321,24 +323,20 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
break;
}
return;
return FTDM_SUCCESS;
}
static __inline__ void pritap_check_state(ftdm_span_t *span)
{
if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
uint32_t j;
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
for(j = 1; j <= span->chan_count; j++) {
if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_mutex_lock(span->channels[j]->mutex);
ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
state_advance(span->channels[j]);
ftdm_channel_complete_state(span->channels[j]);
ftdm_mutex_unlock(span->channels[j]->mutex);
}
}
}
if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
uint32_t j;
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
for(j = 1; j <= span->chan_count; j++) {
ftdm_mutex_lock(span->channels[j]->mutex);
ftdm_channel_advance_states(span->channels[j]);
ftdm_mutex_unlock(span->channels[j]->mutex);
}
}
}
static int pri_io_read(struct pri *pri, void *buf, int buflen)
@@ -896,6 +894,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_pritap_configure_span)
span->get_span_sig_status = pritap_get_span_sig_status;
span->state_map = &pritap_state_map;
span->state_processor = state_advance;
return FTDM_SUCCESS;
}
+325 -237
View File
@@ -33,6 +33,7 @@
* Contributors:
*
* Arnaldo Pereira <arnaldo@sangoma.com>
* Ricardo Barroetaveña <rbarroetavena@anura.com.ar>
*
*/
@@ -49,10 +50,6 @@
#include "freetdm.h"
#include "private/ftdm_core.h"
/* debug thread count for r2 legs */
static ftdm_mutex_t* g_thread_count_mutex;
static int32_t g_thread_count = 0;
typedef int openr2_call_status_t;
/* when the user stops a span, we clear FTDM_R2_SPAN_STARTED, so that the signaling thread
@@ -76,7 +73,6 @@ typedef struct ftdm_r2_call_t {
int disconnect_rcvd:1;
int ftdm_call_started:1;
int protocol_error:1;
ftdm_channel_state_t chanstate;
ftdm_size_t dnis_index;
ftdm_size_t ani_index;
char logname[255];
@@ -171,8 +167,7 @@ static ftdm_hash_t *g_mod_data_hash;
/* IO interface for the command API */
static ftdm_io_interface_t g_ftdm_r2_interface;
static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan);
static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan);
static ftdm_status_t ftdm_r2_state_advance(ftdm_channel_t *ftdmchan);
/* whether R2 call accept process is pending */
#define IS_ACCEPTING_PENDING(ftdmchan) \
@@ -352,7 +347,6 @@ static void ft_r2_clean_call(ftdm_r2_call_t *call)
call->disconnect_rcvd = 0;
call->ftdm_call_started = 0;
call->protocol_error = 0;
call->chanstate = FTDM_CHANNEL_STATE_DOWN;
call->dnis_index = 0;
call->ani_index = 0;
call->name[0] = 0;
@@ -380,11 +374,72 @@ static void ft_r2_answer_call(ftdm_channel_t *ftdmchan)
R2CALL(ftdmchan)->answer_pending = 0;
}
static __inline__ ftdm_calling_party_category_t ftdm_openr2_cpc_to_r2_ftdm_cpc(openr2_calling_party_category_t cpc)
{
switch (cpc) {
case OR2_CALLING_PARTY_CATEGORY_UNKNOWN:
return FTDM_CPC_UNKNOWN;
case OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER:
return FTDM_CPC_ORDINARY;
case OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER:
return FTDM_CPC_PRIORITY;
case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_SUBSCRIBER:
return FTDM_CPC_UNKNOWN;
case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_PRIORITY_SUBSCRIBER:
return FTDM_CPC_UNKNOWN;
case OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT:
return FTDM_CPC_TEST;
case OR2_CALLING_PARTY_CATEGORY_PAY_PHONE:
return FTDM_CPC_PAYPHONE;
case OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL:
return FTDM_CPC_OPERATOR;
}
return FTDM_CPC_INVALID;
}
static __inline openr2_calling_party_category_t ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdm_calling_party_category_t cpc)
{
switch (cpc) {
case FTDM_CPC_UNKNOWN:
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
case FTDM_CPC_OPERATOR:
return OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL;
case FTDM_CPC_ORDINARY:
return OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
case FTDM_CPC_PRIORITY:
return OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER;
case FTDM_CPC_DATA:
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
case FTDM_CPC_TEST:
return OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT;
case FTDM_CPC_PAYPHONE:
return OR2_CALLING_PARTY_CATEGORY_PAY_PHONE;
case FTDM_CPC_INVALID:
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
}
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
}
/* this function must be called with the chan mutex held! */
static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
{
openr2_call_status_t callstatus;
ftdm_r2_data_t *r2data;
openr2_calling_party_category_t category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
r2data = ftdmchan->span->signal_data;
@@ -397,6 +452,12 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
ft_r2_clean_call(ftdmchan->call_data);
if (ftdmchan->caller_data.cpc == FTDM_CPC_INVALID || ftdmchan->caller_data.cpc == FTDM_CPC_UNKNOWN) {
category = r2data->category;
} else {
category = ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdmchan->caller_data.cpc);
}
/* start io dump */
if (r2data->mf_dump_size) {
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_INPUT_DUMP, &r2data->mf_dump_size);
@@ -404,9 +465,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
}
callstatus = openr2_chan_make_call(R2CALL(ftdmchan)->r2chan,
ftdmchan->caller_data.cid_num.digits,
ftdmchan->caller_data.cid_num.digits,
ftdmchan->caller_data.dnis.digits,
r2data->category);
category,
ftdmchan->caller_data.pres == FTDM_PRES_ALLOWED ? 0 : 1);
if (callstatus) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to make call in R2 channel, openr2_chan_make_call failed\n");
@@ -414,7 +476,6 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
}
R2CALL(ftdmchan)->ftdm_call_started = 1;
R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
@@ -456,19 +517,40 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_channel_sig_status)
static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_channel_sig_status)
{
openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
openr2_cas_signal_t rxcas, txcas;
/* get the current rx and tx cas bits */
openr2_chan_get_cas(r2chan, &rxcas, &txcas);
/* if we're already in the state the user asks us to be, we have nothing to do */
if (status == FTDM_SIG_STATE_SUSPENDED && txcas == OR2_CAS_BLOCK) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in BLOCK state\n");
return FTDM_SUCCESS;
}
if (status == FTDM_SIG_STATE_UP && txcas == OR2_CAS_IDLE) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in IDLE state\n");
return FTDM_SUCCESS;
}
/* set the signaling as requested and send SIGEVENT_SIGSTATUS_CHANGED, if applicable.
* see docs/sigstatus.txt for details */
switch(status) {
case FTDM_SIG_STATE_DOWN:
case FTDM_SIG_STATE_SUSPENDED:
openr2_chan_set_blocked(r2chan);
if (rxcas == OR2_CAS_IDLE) {
ftdm_r2_set_chan_sig_status(ftdmchan, status);
}
break;
case FTDM_SIG_STATE_UP:
openr2_chan_set_idle(r2chan);
if (rxcas == OR2_CAS_IDLE) {
ftdm_r2_set_chan_sig_status(ftdmchan, status);
}
break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status);
return FTDM_FAIL;
}
ftdm_r2_set_chan_sig_status(ftdmchan, status);
return FTDM_SUCCESS;
}
@@ -484,10 +566,13 @@ static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_span_sig_status)
*status = FTDM_SIG_STATE_SUSPENDED;
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
ftdm_channel_t *fchan = ftdm_iterator_current(citer);
ftdm_channel_lock(fchan);
if (ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP)) {
*status = FTDM_SIG_STATE_UP;
ftdm_channel_unlock(fchan);
break;
}
ftdm_channel_unlock(fchan);
}
ftdm_iterator_free(chaniter);
return FTDM_SUCCESS;
@@ -497,21 +582,6 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status)
{
ftdm_iterator_t *chaniter = NULL;
ftdm_iterator_t *citer = NULL;
uint32_t span_opr = -1;
/* we either set the channels to BLOCK or IDLE */
switch(status) {
case FTDM_SIG_STATE_DOWN:
case FTDM_SIG_STATE_SUSPENDED:
span_opr = 0;
break;
case FTDM_SIG_STATE_UP:
span_opr = 1;
break;
default:
ftdm_log(FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status);
return FTDM_FAIL;
}
chaniter = ftdm_span_get_chan_iterator(span, NULL);
if (!chaniter) {
@@ -521,15 +591,13 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status)
/* iterate over all channels, setting them to the requested state */
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
ftdm_channel_t *fchan = ftdm_iterator_current(citer);
openr2_chan_t *r2chan = R2CALL(fchan)->r2chan;
if (span_opr == 0) {
openr2_chan_set_blocked(r2chan);
ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel blocked\n");
} else {
openr2_chan_set_idle(r2chan);
ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel idle\n");
/* we set channel's state through ftdm_r2_set_channel_sig_status(), since it already takes
* care of notifying the user when appropriate */
ftdm_channel_lock(fchan);
if ((ftdm_r2_set_channel_sig_status(fchan, status)) != FTDM_SUCCESS) {
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to set signaling status to %s\n", ftdm_signaling_status2str(status));
}
ftdm_r2_set_chan_sig_status(fchan, status);
ftdm_channel_unlock(fchan);
}
ftdm_iterator_free(chaniter);
return FTDM_SUCCESS;
@@ -552,7 +620,7 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
ftdm_sched_cancel_timer(r2data->sched, r2call->protocol_error_recovery_timer);
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Cancelled protocol error recovery timer\n");
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
}
}
@@ -586,7 +654,6 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_OUTPUT_DUMP, &r2data->mf_dump_size);
}
R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLUSH_TX_BUFFERS, NULL);
@@ -595,12 +662,14 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
static void dump_mf(openr2_chan_t *r2chan);
/* only called for incoming calls when the ANI, DNIS etc is complete and the user has to decide either to accept or reject the call */
static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis,
openr2_calling_party_category_t category, int ani_restricted)
{
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = (%d)\n", ani, dnis, category);
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = %d, ANI restricted = %s\n",
ani, dnis, category, ani_restricted ? "Yes" : "No");
/* nothing went wrong during call setup, MF has ended, we can and must disable the MF dump */
if (r2data->mf_dump_size) {
@@ -615,6 +684,8 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons
} else {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
}
ftdmchan->caller_data.cpc = ftdm_openr2_cpc_to_r2_ftdm_cpc(category);
ftdmchan->caller_data.pres = ani_restricted ? FTDM_PRES_RESTRICTED : FTDM_PRES_ALLOWED;
}
/*
@@ -632,12 +703,10 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons
static void clear_accept_pending(ftdm_channel_t *fchan)
{
if (IS_ACCEPTING_PENDING(fchan)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(fchan);
} else if (ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_log_chan(fchan, FTDM_LOG_CRIT, "State change flag set in state %s, last state = %s\n",
ftdm_channel_state2str(fchan->state), ftdm_channel_state2str(fchan->last_state));
ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(fchan);
}
}
@@ -745,7 +814,7 @@ static void ftdm_r2_on_call_end(openr2_chan_t *r2chan)
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
/* in some circumstances openr2 can call on_call_init right after this, so let's advance the state right here */
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
}
static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
@@ -777,7 +846,7 @@ static void ftdm_r2_recover_from_protocol_error(void *data)
goto done;
}
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
done:
ftdm_channel_unlock(ftdmchan);
}
@@ -1158,6 +1227,18 @@ static openr2_log_level_t ftdm_r2_loglevel_from_string(const char *level)
static ftdm_state_map_t r2_state_map = {
{
{
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
{FTDM_ANY_STATE, FTDM_END},
{FTDM_CHANNEL_STATE_RESET, FTDM_END}
},
{
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_RESET, FTDM_END},
{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
},
{
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
@@ -1209,6 +1290,20 @@ static ftdm_state_map_t r2_state_map = {
/* Outbound states */
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
{FTDM_ANY_STATE, FTDM_END},
{FTDM_CHANNEL_STATE_RESET, FTDM_END}
},
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_RESET, FTDM_END},
{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
},
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
@@ -1515,10 +1610,14 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
span->set_channel_sig_status = ftdm_r2_set_channel_sig_status;
span->state_map = &r2_state_map;
span->state_processor = ftdm_r2_state_advance;
/* use signals queue */
ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
/* we can skip states (going straight from RING to UP) */
ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);
/* setup the scheduler */
snprintf(schedname, sizeof(schedname), "ftmod_r2_%s", span->name);
ftdm_assert(ftdm_sched_create(&r2data->sched, schedname) == FTDM_SUCCESS, "Failed to create schedule!\n");
@@ -1541,10 +1640,10 @@ fail:
}
/* the channel must be locked when calling this function */
static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
static ftdm_status_t ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
{
ftdm_sigmsg_t sigev;
int ret;
ftdm_status_t ret;
ftdm_r2_call_t *r2call = R2CALL(ftdmchan);
openr2_chan_t *r2chan = r2call->r2chan;
ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
@@ -1554,172 +1653,173 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
sigev.span_id = ftdmchan->span_id;
sigev.channel = ftdmchan;
ret = 0;
ret = FTDM_SUCCESS;
/* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept
* procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this
* function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting
* to complete (the processing is media-bound)
* */
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)
&& (r2call->chanstate != ftdmchan->state)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
r2call->chanstate = ftdmchan->state;
if (IS_ACCEPTING_PENDING(ftdmchan)) {
/*
Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting
the call in R2 means sending a tone, then waiting for the acknowledge from the other end,
since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100)
which means during that time the user should not try to perform any operations like answer, hangup or anything
else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block
the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag,
otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first,
if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state));
} else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
}
switch (ftdmchan->state) {
/* starting an incoming call */
case FTDM_CHANNEL_STATE_COLLECT:
{
uint32_t interval = 0;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval);
openr2_chan_enable_read(r2chan);
}
break;
/* starting an outgoing call */
case FTDM_CHANNEL_STATE_DIALING:
{
uint32_t interval = 0;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan,
FTDM_LOG_DEBUG, "Starting processing of outgoing call in channel with interval %d\n", interval);
openr2_chan_enable_read(r2chan);
}
break;
/* incoming call was offered */
case FTDM_CHANNEL_STATE_RING:
/* notify the user about the new call */
sigev.event_id = FTDM_SIGEVENT_START;
ftdm_span_send_signal(ftdmchan->span, &sigev);
r2call->ftdm_call_started = 1;
break;
/* the call is making progress */
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
{
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (!r2call->accepted) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n");
ft_r2_accept_call(ftdmchan);
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n");
sigev.event_id = FTDM_SIGEVENT_PROCEED;
ftdm_span_send_signal(ftdmchan->span, &sigev);
sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* the call was answered */
case FTDM_CHANNEL_STATE_UP:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n");
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (!r2call->accepted) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n");
// the answering will be done in the on_call_accepted handler
ft_r2_accept_call(ftdmchan);
r2call->answer_pending = 1;
} else {
ft_r2_answer_call(ftdmchan);
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n");
sigev.event_id = FTDM_SIGEVENT_UP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* just got hangup */
case FTDM_CHANNEL_STATE_HANGUP:
{
if (!r2call->disconnect_rcvd) {
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
openr2_chan_disconnect_call(r2chan, disconnect_cause);
} else if (!r2call->protocol_error) {
/* just ack the hangup, on_call_end will be called by openr2 right after */
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n");
/* do not set to down yet, give some time for recovery */
ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100,
ftdm_r2_recover_from_protocol_error, r2chan, &r2call->protocol_error_recovery_timer);
}
}
break;
case FTDM_CHANNEL_STATE_TERMINATING:
{
/* if the call has not been started yet we must go to HANGUP right here */
if (!r2call->ftdm_call_started) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
} else {
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* notify the user of the call terminating and we wait for the user to move us to hangup */
sigev.event_id = FTDM_SIGEVENT_STOP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* finished call for good */
case FTDM_CHANNEL_STATE_DOWN:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n");
ret = 1;
}
break;
/* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */
case FTDM_CHANNEL_STATE_RINGING:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n");
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
}
break;
}
if (IS_ACCEPTING_PENDING(ftdmchan)) {
/*
Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting
the call in R2 means sending a tone, then waiting for the acknowledge from the other end,
since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100)
which means during that time the user should not try to perform any operations like answer, hangup or anything
else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block
the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag,
otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first,
if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state));
} else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
ftdm_channel_complete_state(ftdmchan);
}
if (ret) {
switch (ftdmchan->state) {
/* starting an incoming call */
case FTDM_CHANNEL_STATE_COLLECT:
{
uint32_t interval = 0;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval);
openr2_chan_enable_read(r2chan);
}
break;
/* starting an outgoing call */
case FTDM_CHANNEL_STATE_DIALING:
{
uint32_t interval = 0;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan,
FTDM_LOG_DEBUG, "Starting processing of outgoing call in channel with interval %d\n", interval);
openr2_chan_enable_read(r2chan);
}
break;
/* incoming call was offered */
case FTDM_CHANNEL_STATE_RING:
/* notify the user about the new call */
sigev.event_id = FTDM_SIGEVENT_START;
ftdm_span_send_signal(ftdmchan->span, &sigev);
r2call->ftdm_call_started = 1;
break;
/* the call is making progress */
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
{
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (!r2call->accepted) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n");
ft_r2_accept_call(ftdmchan);
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n");
sigev.event_id = FTDM_SIGEVENT_PROCEED;
ftdm_span_send_signal(ftdmchan->span, &sigev);
sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* the call was answered */
case FTDM_CHANNEL_STATE_UP:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n");
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
if (!r2call->accepted) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n");
// the answering will be done in the on_call_accepted handler
ft_r2_accept_call(ftdmchan);
r2call->answer_pending = 1;
} else {
ft_r2_answer_call(ftdmchan);
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n");
sigev.event_id = FTDM_SIGEVENT_UP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* just got hangup */
case FTDM_CHANNEL_STATE_HANGUP:
{
if (!r2call->disconnect_rcvd) {
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
openr2_chan_disconnect_call(r2chan, disconnect_cause);
} else if (!r2call->protocol_error) {
/* just ack the hangup, on_call_end will be called by openr2 right after */
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n");
/* do not set to down yet, give some time for recovery */
ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100,
ftdm_r2_recover_from_protocol_error, r2chan, &r2call->protocol_error_recovery_timer);
}
}
break;
case FTDM_CHANNEL_STATE_TERMINATING:
{
/* if the call has not been started yet we must go to HANGUP right here */
if (!r2call->ftdm_call_started) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
} else {
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* notify the user of the call terminating and we wait for the user to move us to hangup */
sigev.event_id = FTDM_SIGEVENT_STOP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* finished call for good */
case FTDM_CHANNEL_STATE_DOWN:
{
if (ftdmchan->last_state != FTDM_CHANNEL_STATE_RESET) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n");
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Reset Complete\n");
}
ret = FTDM_BREAK;
}
break;
/* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */
case FTDM_CHANNEL_STATE_RINGING:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n");
}
break;
/* put the r2 channel back to IDLE, close ftdmchan and set it's state as DOWN */
case FTDM_CHANNEL_STATE_RESET:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RESET indicated, putting the R2 channel back to IDLE\n");
openr2_chan_set_idle(r2chan);
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
}
break;
}
if (ret == FTDM_BREAK) {
ftdm_channel_t *closed_chan;
closed_chan = ftdmchan;
ftdm_channel_close(&closed_chan);
@@ -1728,20 +1828,6 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
return ret;
}
/* the channel must be locked when calling this function */
static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan)
{
/* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept
* procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this
* function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting
* to complete (the processing is media-bound)
* */
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)
&& (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) {
ftdm_r2_state_advance(ftdmchan);
}
}
static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
{
openr2_chan_t *r2chan = NULL;
@@ -1776,10 +1862,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
}
for (i = 1, citer = chaniter; citer; citer = ftdm_iterator_next(citer), i++) {
ftdmchan = ftdm_iterator_current(citer);
ftdm_channel_lock(ftdmchan);
r2chan = R2CALL(ftdmchan)->r2chan;
openr2_chan_set_span_id(r2chan, span->span_id);
openr2_chan_set_idle(r2chan);
openr2_chan_process_cas_signaling(r2chan);
ftdm_channel_unlock(ftdmchan);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &txqueue_size);
}
@@ -1861,7 +1949,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
for ( ; citer; citer = ftdm_iterator_next(citer)) {
ftdmchan = ftdm_iterator_current(citer);
ftdm_mutex_lock(ftdmchan->mutex);
ftdm_channel_lock(ftdmchan);
call = R2CALL(ftdmchan);
@@ -1870,12 +1958,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED);
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
r2chan = call->r2chan;
openr2_chan_process_signaling(r2chan);
ftdm_r2_state_advance_all(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
if (!call->accepted) {
/* if the call is not accepted we do not want users reading */
@@ -1883,7 +1971,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED);
}
ftdm_mutex_unlock(ftdmchan->mutex);
ftdm_channel_unlock(ftdmchan);
}
}
@@ -1891,8 +1979,10 @@ done:
citer = ftdm_span_get_chan_iterator(span, chaniter);
for ( ; citer; citer = ftdm_iterator_next(citer)) {
ftdmchan = ftdm_iterator_current(citer);
ftdm_channel_lock(ftdmchan);
r2chan = R2CALL(ftdmchan)->r2chan;
openr2_chan_set_blocked(r2chan);
ftdm_channel_unlock(ftdmchan);
}
ftdm_iterator_free(chaniter);
@@ -1947,6 +2037,14 @@ static void __inline__ unblock_channel(ftdm_channel_t *fchan, ftdm_stream_handle
ftdm_mutex_unlock(fchan->mutex);
}
#define FT_SYNTAX "USAGE:\n" \
"--------------------------------------------------------------------------------\n" \
"ftdm r2 status <span_id|span_name>\n" \
"ftdm r2 loopstats <span_id|span_name>\n" \
"ftdm r2 block|unblock <span_id|span_name> [<chan_id>]\n" \
"ftdm r2 version\n" \
"ftdm r2 variants\n" \
"--------------------------------------------------------------------------------\n"
static FIO_API_FUNCTION(ftdm_r2_api)
{
ftdm_span_t *span = NULL;
@@ -2130,14 +2228,6 @@ static FIO_API_FUNCTION(ftdm_r2_api)
}
if (argc == 1) {
if (!strcasecmp(argv[0], "threads")) {
ftdm_mutex_lock(g_thread_count_mutex);
stream->write_function(stream, "%d R2 channel threads up\n", g_thread_count);
ftdm_mutex_unlock(g_thread_count_mutex);
stream->write_function(stream, "+OK.\n");
goto done;
}
if (!strcasecmp(argv[0], "version")) {
stream->write_function(stream, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
stream->write_function(stream, "+OK.\n");
@@ -2163,7 +2253,7 @@ static FIO_API_FUNCTION(ftdm_r2_api)
}
}
stream->write_function(stream, "-ERR invalid command.\n");
stream->write_function(stream, "%s", FT_SYNTAX);
done:
@@ -2192,7 +2282,6 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_r2_init)
if (!g_mod_data_hash) {
return FTDM_FAIL;
}
ftdm_mutex_create(&g_thread_count_mutex);
return FTDM_SUCCESS;
}
@@ -2212,7 +2301,6 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy)
}
}
hashtable_destroy(g_mod_data_hash);
ftdm_mutex_destroy(&g_thread_count_mutex);
return FTDM_SUCCESS;
}
@@ -951,7 +951,6 @@ static void handle_call_answer(ftdm_span_t *span, sangomabc_connection_t *mcon,
}
}
static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan);
static __inline__ void stop_loop(ftdm_channel_t *ftdmchan);
/**
@@ -1002,7 +1001,7 @@ tryagain:
} else if (ftdmchan->state == FTDM_CHANNEL_STATE_IN_LOOP && retry) {
retry = 0;
stop_loop(ftdmchan);
advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
goto tryagain;
} else {
ftdm_log(FTDM_LOG_ERROR, "s%dc%d: rejecting incoming call in channel state %s\n",
@@ -1267,7 +1266,7 @@ static ftdm_channel_t* event_process_states(ftdm_span_t *span, sangomabc_short_e
}
ftdm_mutex_lock(ftdmchan->mutex);
advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
return ftdmchan;
}
@@ -1354,11 +1353,11 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon,
}
if(ftdmchan != NULL) {
advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
ftdm_mutex_unlock(ftdmchan->mutex);
}
return 0;
return 0;
}
@@ -1366,7 +1365,7 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon,
* \brief Handler for channel state change
* \param ftdmchan Channel to handle
*/
static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
{
ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
sangomabc_connection_t *mcon = &sangoma_boost_data->mcon;
@@ -1374,12 +1373,6 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
ftdm_status_t status;
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
} else {
return FTDM_SUCCESS;
}
ftdm_assert_return(ftdmchan->last_state != ftdmchan->state, FTDM_FAIL, "Channel state already processed\n");
ftdm_log(FTDM_LOG_DEBUG, "%d:%d PROCESSING STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
@@ -1389,6 +1382,8 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
ftdm_channel_complete_state(ftdmchan);
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_DOWN:
{
@@ -1640,24 +1635,15 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
default:
break;
}
ftdm_channel_complete_state(ftdmchan);
return FTDM_SUCCESS;
}
static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan)
{
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
state_advance(ftdmchan);
}
}
/**
* \brief Initialises outgoing requests array
*/
static __inline__ void init_outgoing_array(void)
{
memset(&OUTBOUND_REQUESTS, 0, sizeof(OUTBOUND_REQUESTS));
}
/**
@@ -1685,7 +1671,7 @@ static __inline__ void check_state(ftdm_span_t *span)
if (susp && span->channels[j]->state != FTDM_CHANNEL_STATE_DOWN) {
ftdm_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART);
}
state_advance(span->channels[j]);
ftdm_channel_advance_states(span->channels[j]);
ftdm_mutex_unlock(span->channels[j]->mutex);
}
}
@@ -1695,7 +1681,7 @@ static __inline__ void check_state(ftdm_span_t *span)
* but without taking the chan out of the queue, so check th
* flag before advancing the state */
ftdm_mutex_lock(ftdmchan->mutex);
state_advance(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
ftdm_mutex_unlock(ftdmchan->mutex);
}
}
@@ -2478,7 +2464,7 @@ static BOOST_SIG_STATUS_CB_FUNCTION(ftdm_boost_sig_status_change)
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
sig.raw_data = &status;
sig.ev_data.sigstatus.status = status;
ftdm_span_send_signal(ftdmchan->span, &sig);
return;
}
@@ -2687,6 +2673,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
span->get_span_sig_status = sangoma_boost_get_span_sig_status;
span->set_span_sig_status = sangoma_boost_set_span_sig_status;
span->state_map = &boost_state_map;
span->state_processor = state_advance;
sangoma_boost_data->mcon.debuglevel = FTDM_LOG_LEVEL_DEBUG;
sangoma_boost_data->pcon.debuglevel = FTDM_LOG_LEVEL_DEBUG;
ftdm_clear_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
@@ -31,6 +31,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define _GNU_SOURCE
#if HAVE_NETDB_H
#include <netdb.h>
#endif
@@ -40,11 +40,12 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;C:\Program Files\libsng_isdn\include&quot;;&quot;C:\Program Files\libsng_isdn\include\sng_isdn&quot;;../../include;&quot;C:\Program Files\Sangoma\include&quot;"
AdditionalIncludeDirectories="&quot;C:\Program Files\sangoma\sng_isdn\include&quot;;../../include;&quot;C:\Program Files\Sangoma\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
MinimalRebuild="true"
ExceptionHandling="0"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
@@ -63,7 +64,7 @@
Name="VCLinkerTool"
AdditionalDependencies="freetdm.lib libsng_isdn.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;&quot;C:\Program Files\libsng_isdn\lib&quot;;&quot;C:\Program Files\Sangoma\api\lib\x86&quot;"
AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;&quot;C:\Program Files\sangoma\sng_isdn\lib&quot;;&quot;C:\Program Files\Sangoma\api\lib\x86&quot;"
GenerateDebugInformation="true"
SubSystem="1"
RandomizedBaseAddress="1"
@@ -116,10 +117,11 @@
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;C:\Program Files\sangoma\sng_isdn\include&quot;;../../include;&quot;C:\Program Files\Sangoma\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
@@ -136,7 +138,9 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="freetdm.lib libsng_isdn.lib"
LinkIncremental="2"
AdditionalLibraryDirectories="&quot;$(OutDir)&quot;;&quot;C:\Program Files\sangoma\sng_isdn\lib&quot;;&quot;C:\Program Files\Sangoma\api\lib\x86&quot;"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
@@ -85,7 +85,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<ExceptionHandling>
@@ -95,10 +95,11 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\libsng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\sangoma\sng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
@@ -110,7 +111,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>
</ExceptionHandling>
@@ -119,6 +120,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -135,11 +137,13 @@
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -147,23 +151,27 @@
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\sangoma\sng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@@ -46,10 +46,9 @@ static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span);
static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span);
ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
static void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftdmchan);
static void ftdm_sangoma_isdn_poll_events(ftdm_span_t *span);
static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event);
static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan);
static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan);
static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
static void ftdm_sangoma_isdn_wakeup_phy(ftdm_channel_t *dchan);
static void ftdm_sangoma_isdn_dchan_set_queue_size(ftdm_channel_t *ftdmchan);
@@ -270,13 +269,6 @@ ftdm_state_map_t sangoma_isdn_state_map = {
}
};
static __inline__ void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftdmchan)
{
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_sangoma_isdn_process_state_change(ftdmchan);
}
}
static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event)
{
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
@@ -457,7 +449,7 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj)
while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
/* double check that this channel has a state change pending */
ftdm_channel_lock(ftdmchan);
ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
ftdm_channel_unlock(ftdmchan);
}
@@ -470,11 +462,11 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj)
/* twiddle */
break;
case FTDM_FAIL:
ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned error!\n", span->name);
ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned error!\n", span->name);
break;
default:
ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned with unknown code\n", span->name);
ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned with unknown code\n", span->name);
break;
}
@@ -536,7 +528,7 @@ ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisd
break;
}
ftdm_channel_lock(ftdmchan);
ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
ftdm_channel_advance_states(ftdmchan);
return ftdmchan;
}
@@ -600,13 +592,14 @@ static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_ev
sngisdn_process_rst_ind(sngisdn_event);
break;
}
if(ftdmchan != NULL) {
ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
if (ftdmchan != NULL) {
ftdm_channel_advance_states(ftdmchan);
ftdm_channel_unlock(ftdmchan);
}
}
static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
/* this function is called with the channel already locked by the core */
static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
{
ftdm_sigmsg_t sigev;
ftdm_channel_state_t initial_state;
@@ -618,13 +611,12 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
sigev.span_id = ftdmchan->span_id;
sigev.channel = ftdmchan;
/*first lock the channel*/
ftdm_channel_lock(ftdmchan);
/*clear the state change flag...since we might be setting a new state*/
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
/* Acknowledge the state change */
ftdm_channel_complete_state(ftdmchan);
#ifdef FTDM_DEBUG_CHAN_MEMORY
if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ)==0, "Failed to mprotect");
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ) == 0, "Failed to mprotect");
}
#endif
@@ -879,11 +871,10 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
}
#ifdef FTDM_DEBUG_CHAN_MEMORY
if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE)==0, "Failed to mprotect");
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE) == 0, "Failed to mprotect");
}
#endif
ftdm_channel_unlock(ftdmchan);
return;
return FTDM_SUCCESS;
}
static FIO_CHANNEL_SEND_MSG_FUNCTION(ftdm_sangoma_isdn_send_msg)
@@ -1098,6 +1089,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
span->get_span_sig_status = ftdm_sangoma_isdn_get_span_sig_status;
span->set_span_sig_status = ftdm_sangoma_isdn_set_span_sig_status;
span->state_map = &sangoma_isdn_state_map;
span->state_processor = ftdm_sangoma_isdn_process_state_change;
ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
ftdm_set_flag(span, FTDM_SPAN_USE_PROCEED_STATE);
@@ -137,8 +137,9 @@ void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d
ftdm_assert(raw_data, "Failed to malloc");
memcpy(raw_data, data, data_len);
sigev.raw_data = raw_data;
sigev.raw_data_len = data_len;
sigev.raw.data = raw_data;
sigev.raw.len = data_len;
sigev.raw.autofree = 1;
ftdm_span_send_signal(signal_data->ftdm_span, &sigev);
}
@@ -250,8 +251,9 @@ void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d
ftdm_assert(raw_data, "Failed to malloc");
memcpy(raw_data, data, data_len);
sigev.raw_data = raw_data;
sigev.raw_data_len = data_len;
sigev.raw.data = raw_data;
sigev.raw.len = data_len;
sigev.raw.autofree = 1;
ftdm_span_send_signal(signal_data->ftdm_span, &sigev);
}
}
@@ -46,7 +46,6 @@ ftdm_sngss7_data_t g_ftdm_sngss7_data;
/* PROTOTYPES *****************************************************************/
static void *ftdm_sangoma_ss7_run (ftdm_thread_t * me, void *obj);
void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan);
static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_event);
static ftdm_status_t ftdm_sangoma_ss7_stop (ftdm_span_t * span);
@@ -308,9 +307,7 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
ftdm_mutex_lock(ftdmchan->mutex);
/* process state changes for this channel until they are all done */
while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_sangoma_ss7_process_state_change (ftdmchan);
}
ftdm_channel_advance_states(ftdmchan);
/* unlock the channel */
ftdm_mutex_unlock (ftdmchan->mutex);
@@ -403,9 +400,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
ftdm_mutex_lock(ftdmchan->mutex);
/* while there's a state change present on this channel process it */
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_sangoma_ss7_process_state_change(ftdmchan);
}
ftdm_channel_advance_states(ftdmchan);
/* figure out the type of event and send it to the right handler */
switch (sngss7_event->event_id) {
@@ -468,9 +463,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
} /* switch (sngss7_event->event_id) */
/* while there's a state change present on this channel process it */
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
ftdm_sangoma_ss7_process_state_change(ftdmchan);
}
ftdm_channel_advance_states(ftdmchan);
/* unlock the channel */
ftdm_mutex_unlock(ftdmchan->mutex);
@@ -479,7 +472,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
}
/******************************************************************************/
void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
{
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
sng_isup_inf_t *isup_intf = NULL;
@@ -495,7 +488,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
SS7_DEBUG_CHAN(ftdmchan, "ftmod_sangoma_ss7 processing state %s\n", ftdm_channel_state2str (ftdmchan->state));
/* clear the state change flag...since we might be setting a new state */
ftdm_clear_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
ftdm_channel_complete_state(ftdmchan);
/*check what state we are supposed to be in */
switch (ftdmchan->state) {
@@ -1212,7 +1205,7 @@ suspend_goto_restart:
/**************************************************************************/
}/*switch (ftdmchan->state) */
return;
return FTDM_SUCCESS;
}
/******************************************************************************/
@@ -1476,6 +1469,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config)
span->get_channel_sig_status = ftdm_sangoma_ss7_get_sig_status;
span->set_channel_sig_status = ftdm_sangoma_ss7_set_sig_status;
span->state_map = &sangoma_ss7_state_map;
span->state_processor = ftdm_sangoma_ss7_process_state_change;
span->signal_data = ss7_span_info;
/* set the flag to indicate that this span uses channel state change queues */
@@ -452,7 +452,7 @@ extern int cmbLinkSetId;
/* PROTOTYPES *****************************************************************/
/* in ftmod_sangoma_ss7_main.c */
void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan);
ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan);
/* in ftmod_sangoma_ss7_logger.c */
void handle_sng_log(uint8_t level, char *fmt,...);
@@ -100,7 +100,7 @@
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -127,7 +127,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -148,7 +148,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -174,7 +174,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -784,17 +784,27 @@ static FIO_COMMAND_FUNCTION(wanpipe_command)
err = sangoma_set_tx_queue_sz(ftdmchan->sockfd, &tdm_api, queue_size);
}
break;
case FTDM_COMMAND_SET_POLARITY:
{
ftdm_polarity_t polarity = FTDM_COMMAND_OBJ_INT;
err = sangoma_tdm_set_polarity(ftdmchan->sockfd, &tdm_api, polarity);
if (!err) {
ftdmchan->polarity = polarity;
}
}
break;
default:
err = FTDM_NOTIMPL;
break;
};
if (err) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
int myerrno = errno;
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Wanpipe failed to execute command %d: %s\n", command, strerror(myerrno));
errno = myerrno;
return err;
}
return FTDM_SUCCESS;
}
@@ -1224,6 +1234,131 @@ static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
return FTDM_SUCCESS;
}
/**
* \brief Process an event in a channel and set it's OOB event id. The channel must be locked.
* \param fchan Channel in which event occured
* \param event_id Pointer where we save the OOB event id
* \param tdm_api Wanpipe tdm struct that contain the event
* \return FTDM_SUCCESS or FTDM_FAIL
*/
static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, wanpipe_tdm_api_t *tdm_api)
{
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type) {
case WP_API_EVENT_LINK_STATUS:
{
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
*event_id = FTDM_OOB_ALARM_CLEAR;
break;
default:
*event_id = FTDM_OOB_ALARM_TRAP;
break;
};
}
break;
case WP_API_EVENT_RXHOOK:
{
if (fchan->type == FTDM_CHAN_TYPE_FXS) {
*event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
if (*event_id == FTDM_OOB_OFFHOOK) {
if (ftdm_test_flag(fchan, FTDM_CHANNEL_FLASH)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_FLASH);
ftdm_clear_flag(fchan, FTDM_CHANNEL_WINK);
*event_id = FTDM_OOB_FLASH;
goto event;
} else {
ftdm_set_flag(fchan, FTDM_CHANNEL_WINK);
}
} else {
if (ftdm_test_flag(fchan, FTDM_CHANNEL_WINK)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_WINK);
ftdm_clear_flag(fchan, FTDM_CHANNEL_FLASH);
*event_id = FTDM_OOB_WINK;
goto event;
} else {
ftdm_set_flag(fchan, FTDM_CHANNEL_FLASH);
}
}
break;
} else {
ftdm_status_t status;
wanpipe_tdm_api_t onhook_tdm_api;
memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api));
status = sangoma_tdm_txsig_onhook(fchan->sockfd, &onhook_tdm_api);
if (status) {
snprintf(fchan->last_error, sizeof(fchan->last_error), "ONHOOK Failed");
return FTDM_FAIL;
}
*event_id = onhook_tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
}
}
break;
case WP_API_EVENT_RING_DETECT:
{
*event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
}
break;
/*
disabled this ones when configuring, we don't need them, do we?
case WP_API_EVENT_RING_TRIP_DETECT:
{
*event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
}
break;
*/
case WP_API_EVENT_RBS:
{
*event_id = FTDM_OOB_CAS_BITS_CHANGE;
fchan->rx_cas_bits = wanpipe_swap_bits(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
}
break;
case WP_API_EVENT_DTMF:
{
char tmp_dtmf[2] = { tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
*event_id = FTDM_OOB_NOOP;
if (tmp_dtmf[0] == 'f') {
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
break;
}
if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
ftdm_set_flag(fchan, FTDM_CHANNEL_MUTE);
}
if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_MUTE);
if (ftdm_test_flag(fchan, FTDM_CHANNEL_INUSE)) {
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
ftdm_channel_queue_dtmf(fchan, tmp_dtmf);
}
}
}
break;
case WP_API_EVENT_ALARM:
{
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api->wp_tdm_cmd.event.wp_api_event_alarm);
*event_id = FTDM_OOB_ALARM_TRAP;
}
break;
case WP_API_EVENT_POLARITY_REVERSE:
{
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Got polarity reverse\n");
*event_id = FTDM_OOB_POLARITY_REVERSE;
}
break;
default:
{
ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type);
*event_id = FTDM_OOB_INVALID;
}
break;
}
event:
return FTDM_SUCCESS;
}
/**
* \brief Retrieves an event from a wanpipe channel
* \param channel Channel to retrieve event from
@@ -1237,8 +1372,9 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
wanpipe_tdm_api_t tdm_api;
ftdm_span_t *span = ftdmchan->span;
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT))
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
}
memset(&tdm_api, 0, sizeof(tdm_api));
status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
@@ -1249,115 +1385,11 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
}
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
case WP_TDMAPI_EVENT_LINK_STATUS:
{
switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
event_id = FTDM_OOB_ALARM_CLEAR;
break;
default:
event_id = FTDM_OOB_ALARM_TRAP;
break;
};
}
break;
case WP_TDMAPI_EVENT_RXHOOK:
{
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS) {
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
if (event_id == FTDM_OOB_OFFHOOK) {
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
event_id = FTDM_OOB_FLASH;
goto event;
} else {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
}
} else {
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
event_id = FTDM_OOB_WINK;
goto event;
} else {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
}
}
break;
} else {
wanpipe_tdm_api_t onhook_tdm_api;
memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api));
status = sangoma_tdm_txsig_onhook(ftdmchan->sockfd, &onhook_tdm_api);
if (status) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
return FTDM_FAIL;
}
event_id = onhook_tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
}
}
break;
case WP_TDMAPI_EVENT_RING_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
}
break;
/*
disabled this ones when configuring, we don't need them, do we?
case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
}
break;
*/
case WP_TDMAPI_EVENT_RBS:
{
event_id = FTDM_OOB_CAS_BITS_CHANGE;
ftdmchan->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
}
break;
case WP_TDMAPI_EVENT_DTMF:
{
char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
event_id = FTDM_OOB_NOOP;
if (tmp_dtmf[0] == 'f') {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
break;
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf);
}
}
}
break;
case WP_TDMAPI_EVENT_ALARM:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
event_id = FTDM_OOB_ALARM_TRAP;
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
event_id = FTDM_OOB_INVALID;
}
break;
if ((wanpipe_channel_process_event(ftdmchan, &event_id, &tdm_api)) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
return FTDM_FAIL;
}
event:
ftdmchan->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
@@ -1419,114 +1451,15 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL;
}
ftdm_log_chan(span->channels[i], FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
case WP_TDMAPI_EVENT_LINK_STATUS:
{
switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
event_id = FTDM_OOB_ALARM_CLEAR;
break;
default:
event_id = FTDM_OOB_ALARM_TRAP;
break;
};
}
break;
case WP_TDMAPI_EVENT_RXHOOK:
{
if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS) {
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
if (event_id == FTDM_OOB_OFFHOOK) {
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) {
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
event_id = FTDM_OOB_FLASH;
goto event;
} else {
ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
}
} else {
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
event_id = FTDM_OOB_WINK;
goto event;
} else {
ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
}
}
continue;
} else {
int err;
ftdm_channel_t *ftdmchan = span->channels[i];
err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
if (err) {
snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "ONHOOK Failed");
return FTDM_FAIL;
}
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
}
}
break;
case WP_TDMAPI_EVENT_RING_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
}
break;
/*
disabled this ones when configuring, we don't need them, do we?
case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
}
break;
*/
case WP_TDMAPI_EVENT_RBS:
{
event_id = FTDM_OOB_CAS_BITS_CHANGE;
span->channels[i]->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
}
break;
case WP_TDMAPI_EVENT_DTMF:
{
char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
event_id = FTDM_OOB_NOOP;
if (tmp_dtmf[0] == 'f') {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
break;
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf);
}
}
}
break;
case WP_TDMAPI_EVENT_ALARM:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
event_id = FTDM_OOB_ALARM_TRAP;
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
event_id = FTDM_OOB_INVALID;
}
break;
ftdm_channel_lock(ftdmchan);
if ((wanpipe_channel_process_event(ftdmchan, &event_id, &tdm_api)) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process events from channel\n");
ftdm_channel_unlock(ftdmchan);
return FTDM_FAIL;
}
ftdm_channel_unlock(ftdmchan);
event:
@@ -1538,9 +1471,7 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
return FTDM_SUCCESS;
}
}
return FTDM_FAIL;
}
/**
+191 -116
View File
@@ -52,42 +52,48 @@ static struct {
float txgain;
} zt_globals;
#if defined(__FreeBSD__)
typedef unsigned long ioctlcmd;
#else
typedef int ioctlcmd;
#endif
/**
* \brief General IOCTL codes
*/
struct ioctl_codes {
int GET_BLOCKSIZE;
int SET_BLOCKSIZE;
int FLUSH;
int SYNC;
int GET_PARAMS;
int SET_PARAMS;
int HOOK;
int GETEVENT;
int IOMUX;
int SPANSTAT;
int MAINT;
int GETCONF;
int SETCONF;
int CONFLINK;
int CONFDIAG;
int GETGAINS;
int SETGAINS;
int SPANCONFIG;
int CHANCONFIG;
int SET_BUFINFO;
int GET_BUFINFO;
int AUDIOMODE;
int ECHOCANCEL;
int HDLCRAWMODE;
int HDLCFCSMODE;
int SPECIFY;
int SETLAW;
int SETLINEAR;
int GETCONFMUTE;
int ECHOTRAIN;
int SETTXBITS;
int GETRXBITS;
ioctlcmd GET_BLOCKSIZE;
ioctlcmd SET_BLOCKSIZE;
ioctlcmd FLUSH;
ioctlcmd SYNC;
ioctlcmd GET_PARAMS;
ioctlcmd SET_PARAMS;
ioctlcmd HOOK;
ioctlcmd GETEVENT;
ioctlcmd IOMUX;
ioctlcmd SPANSTAT;
ioctlcmd MAINT;
ioctlcmd GETCONF;
ioctlcmd SETCONF;
ioctlcmd CONFLINK;
ioctlcmd CONFDIAG;
ioctlcmd GETGAINS;
ioctlcmd SETGAINS;
ioctlcmd SPANCONFIG;
ioctlcmd CHANCONFIG;
ioctlcmd SET_BUFINFO;
ioctlcmd GET_BUFINFO;
ioctlcmd AUDIOMODE;
ioctlcmd ECHOCANCEL;
ioctlcmd HDLCRAWMODE;
ioctlcmd HDLCFCSMODE;
ioctlcmd SPECIFY;
ioctlcmd SETLAW;
ioctlcmd SETLINEAR;
ioctlcmd GETCONFMUTE;
ioctlcmd ECHOTRAIN;
ioctlcmd SETTXBITS;
ioctlcmd GETRXBITS;
};
/**
@@ -181,6 +187,7 @@ static ftdm_socket_t CONTROL_FD = ZT_INVALID_SOCKET;
FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event);
FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event);
FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event);
/**
* \brief Initialises codec, and rx/tx gains
@@ -985,6 +992,124 @@ FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
return k ? FTDM_SUCCESS : FTDM_FAIL;
}
/**
* \brief Process an event from a ftdmchan and set the proper OOB event_id. The channel must be locked.
* \param fchan Channel to retrieve event from
* \param event_id Pointer to OOB event id
* \param zt_event_id Zaptel event id
* \return FTDM_SUCCESS or FTDM_FAIL
*/
static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, zt_event_t zt_event_id)
{
switch(zt_event_id) {
case ZT_EVENT_RINGEROFF:
{
return FTDM_FAIL;
}
break;
case ZT_EVENT_RINGERON:
{
return FTDM_FAIL;
}
break;
case ZT_EVENT_RINGBEGIN:
{
*event_id = FTDM_OOB_RING_START;
}
break;
case ZT_EVENT_ONHOOK:
{
*event_id = FTDM_OOB_ONHOOK;
}
break;
case ZT_EVENT_WINKFLASH:
{
if (fchan->state == FTDM_CHANNEL_STATE_DOWN || fchan->state == FTDM_CHANNEL_STATE_DIALING) {
*event_id = FTDM_OOB_WINK;
} else {
*event_id = FTDM_OOB_FLASH;
}
}
break;
case ZT_EVENT_RINGOFFHOOK:
{
if (fchan->type == FTDM_CHAN_TYPE_FXS || (fchan->type == FTDM_CHAN_TYPE_EM && fchan->state != FTDM_CHANNEL_STATE_UP)) {
ftdm_set_flag_locked(fchan, FTDM_CHANNEL_OFFHOOK);
*event_id = FTDM_OOB_OFFHOOK;
} else if (fchan->type == FTDM_CHAN_TYPE_FXO) {
*event_id = FTDM_OOB_RING_START;
} else {
*event_id = FTDM_OOB_NOOP;
}
}
break;
case ZT_EVENT_ALARM:
{
*event_id = FTDM_OOB_ALARM_TRAP;
}
break;
case ZT_EVENT_NOALARM:
{
*event_id = FTDM_OOB_ALARM_CLEAR;
}
break;
case ZT_EVENT_BITSCHANGED:
{
*event_id = FTDM_OOB_CAS_BITS_CHANGE;
int bits = 0;
int err = ioctl(fchan->sockfd, codes.GETRXBITS, &bits);
if (err) {
return FTDM_FAIL;
}
fchan->rx_cas_bits = bits;
}
break;
default:
{
ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled event %d\n", zt_event_id);
*event_id = FTDM_OOB_INVALID;
}
break;
}
return FTDM_SUCCESS;
}
/**
* \brief Retrieves an event from a ftdm channel
* \param ftdmchan Channel to retrieve event from
* \param event FreeTDM event to return
* \return Success or failure
*/
FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event)
{
uint32_t event_id = FTDM_OOB_INVALID;
zt_event_t zt_event_id = 0;
ftdm_span_t *span = ftdmchan->span;
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
}
if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event from channel: %s\n",
strerror(errno));
return FTDM_FAIL;
}
/* the core already locked the channel for us, so it's safe to call zt_channel_process_event() here */
if ((zt_channel_process_event(ftdmchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
return FTDM_FAIL;
}
ftdmchan->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
span->event_header.channel = ftdmchan;
*event = &span->event_header;
return FTDM_SUCCESS;
}
/**
* \brief Retrieves an event from a ftdmtel span
* \param span Span to retrieve event from
@@ -997,91 +1122,29 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
zt_event_t zt_event_id = 0;
for(i = 1; i <= span->chan_count; i++) {
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
if (ioctl(span->channels[i]->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL;
}
switch(zt_event_id) {
case ZT_EVENT_RINGEROFF:
{
return FTDM_FAIL;
}
break;
case ZT_EVENT_RINGERON:
{
return FTDM_FAIL;
}
break;
case ZT_EVENT_RINGBEGIN:
{
event_id = FTDM_OOB_RING_START;
}
break;
case ZT_EVENT_ONHOOK:
{
event_id = FTDM_OOB_ONHOOK;
}
break;
case ZT_EVENT_WINKFLASH:
{
if (span->channels[i]->state == FTDM_CHANNEL_STATE_DOWN || span->channels[i]->state == FTDM_CHANNEL_STATE_DIALING) {
event_id = FTDM_OOB_WINK;
} else {
event_id = FTDM_OOB_FLASH;
}
}
break;
case ZT_EVENT_RINGOFFHOOK:
{
if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS || (span->channels[i]->type == FTDM_CHAN_TYPE_EM && span->channels[i]->state != FTDM_CHANNEL_STATE_UP)) {
ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
event_id = FTDM_OOB_OFFHOOK;
} else if (span->channels[i]->type == FTDM_CHAN_TYPE_FXO) {
event_id = FTDM_OOB_RING_START;
} else {
event_id = FTDM_OOB_NOOP;
}
}
break;
case ZT_EVENT_ALARM:
{
event_id = FTDM_OOB_ALARM_TRAP;
}
break;
case ZT_EVENT_NOALARM:
{
event_id = FTDM_OOB_ALARM_CLEAR;
}
break;
case ZT_EVENT_BITSCHANGED:
{
event_id = FTDM_OOB_CAS_BITS_CHANGE;
int bits = 0;
int err = ioctl(span->channels[i]->sockfd, codes.GETRXBITS, &bits);
if (err) {
return FTDM_FAIL;
}
span->channels[i]->rx_cas_bits = bits;
}
break;
default:
{
ftdm_log(FTDM_LOG_WARNING, "Unhandled event %d for %d:%d\n", zt_event_id, span->span_id, i);
event_id = FTDM_OOB_INVALID;
}
break;
}
span->channels[i]->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
span->event_header.channel = span->channels[i];
*event = &span->event_header;
return FTDM_SUCCESS;
ftdm_channel_t *fchan = span->channels[i];
if (ftdm_test_flag(fchan, FTDM_CHANNEL_EVENT)) {
ftdm_clear_flag(fchan, FTDM_CHANNEL_EVENT);
}
if (ioctl(fchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
return FTDM_FAIL;
}
ftdm_channel_lock(fchan);
if ((zt_channel_process_event(fchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
ftdm_channel_unlock(fchan);
return FTDM_FAIL;
}
ftdm_channel_unlock(fchan);
fchan->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
span->event_header.channel = fchan;
*event = &span->event_header;
return FTDM_SUCCESS;
}
return FTDM_FAIL;
@@ -1146,6 +1209,7 @@ static FIO_WRITE_FUNCTION(zt_write)
bytes += 2;
}
tryagain:
w = write(ftdmchan->sockfd, data, bytes);
if (w >= 0) {
@@ -1153,6 +1217,17 @@ static FIO_WRITE_FUNCTION(zt_write)
return FTDM_SUCCESS;
}
if (errno == ELAST) {
zt_event_t zt_event_id = 0;
if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event after ELAST on write: %s\n", strerror(errno));
return FTDM_FAIL;
}
/* we should enqueue this event somewhere so it can be retrieved by the user, for now, dropping it to see what it is! */
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dropping event %d to be able to write data\n", zt_event_id);
goto tryagain;
}
return FTDM_FAIL;
}
+114 -26
View File
@@ -144,7 +144,9 @@ typedef enum {
/*! \brief Hunting direction (when hunting for free channels) */
typedef enum {
FTDM_TOP_DOWN,
FTDM_BOTTOM_UP
FTDM_BOTTOM_UP,
FTDM_RR_DOWN,
FTDM_RR_UP,
} ftdm_direction_t;
/*! \brief I/O channel type */
@@ -265,15 +267,32 @@ typedef enum {
#define USER_LAYER1_PROT_STRINGS "V.110", "u-law", "a-law", "Invalid"
FTDM_STR2ENUM_P(ftdm_str2ftdm_usr_layer1_prot, ftdm_user_layer1_prot2str, ftdm_user_layer1_prot_t)
/*! Calling Party Category */
typedef enum {
FTDM_CPC_UNKNOWN,
FTDM_CPC_OPERATOR,
FTDM_CPC_ORDINARY,
FTDM_CPC_PRIORITY,
FTDM_CPC_DATA,
FTDM_CPC_TEST,
FTDM_CPC_PAYPHONE,
FTDM_CPC_INVALID
} ftdm_calling_party_category_t;
#define CALLING_PARTY_CATEGORY_STRINGS "unknown", "operator", "ordinary", "priority", "data-call", "test-call", "payphone", "invalid"
FTDM_STR2ENUM_P(ftdm_str2ftdm_calling_party_category, ftdm_calling_party_category2str, ftdm_calling_party_category_t)
/*! \brief Digit limit used in DNIS/ANI */
#define FTDM_DIGITS_LIMIT 25
/*! \brief Number abstraction */
typedef struct {
char digits[25];
char digits[FTDM_DIGITS_LIMIT];
uint8_t type;
uint8_t plan;
} ftdm_number_t;
typedef void * ftdm_variable_container_t;
/*! \brief Caller information */
typedef struct ftdm_caller_data {
char cid_date[8]; /*!< Caller ID date */
@@ -282,10 +301,10 @@ typedef struct ftdm_caller_data {
ftdm_number_t ani; /*!< ANI (Automatic Number Identification) */
ftdm_number_t dnis; /*!< DNIS (Dialed Number Identification Service) */
ftdm_number_t rdnis; /*!< RDNIS (Redirected Dialed Number Identification Service) */
char aniII[25]; /*! ANI II */
char aniII[FTDM_DIGITS_LIMIT]; /*! ANI II */
uint8_t screen; /*!< Screening */
uint8_t pres; /*!< Presentation*/
char collected[25]; /*!< Collected digits so far */
char collected[FTDM_DIGITS_LIMIT]; /*!< Collected digits so far */
int hangup_cause; /*!< Hangup cause */
char raw_data[1024]; /*!< Protocol specific raw caller data */
uint32_t raw_data_len; /*!< Raw data length */
@@ -294,12 +313,14 @@ typedef struct ftdm_caller_data {
ftdm_bearer_cap_t bearer_capability;
/* user information layer 1 protocol */
ftdm_user_layer1_prot_t bearer_layer1;
ftdm_variable_container_t variables; /*!<variables attached to this call */
ftdm_calling_party_category_t cpc; /*!< Calling party category */
ftdm_variable_container_t variables; /*!< Variables attached to this call */
/* We need call_id inside caller_data for the user to be able to retrieve
* the call_id when ftdm_channel_call_place is called. This is the only time
* that the user can use caller_data.call_id to obtain the call_id. The user
* should use the call_id from sigmsg otherwise */
uint32_t call_id; /*!< Unique call ID for this call */
ftdm_channel_t *fchan; /*!< FreeTDM channel associated (can be NULL) */
} ftdm_caller_data_t;
/*! \brief Tone type */
@@ -328,12 +349,13 @@ typedef enum {
FTDM_SIGEVENT_FACILITY, /*!< In call facility event */
FTDM_SIGEVENT_TRACE, /*!<Interpreted trace event */
FTDM_SIGEVENT_TRACE_RAW, /*!<Raw trace event */
FTDM_SIGEVENT_INDICATION_COMPLETED, /*!< Last requested indication was completed */
FTDM_SIGEVENT_INVALID, /*!<Invalid */
} ftdm_signal_event_t;
#define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROCEED", "RINGING", "PROGRESS", \
"PROGRESS_MEDIA", "ALARM_TRAP", "ALARM_CLEAR", \
"COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "COLLISION", "FACILITY", "TRACE", "TRACE_RAW", "INVALID"
"COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "COLLISION", "FACILITY", \
"TRACE", "TRACE_RAW", "INDICATION_COMPLETED", "INVALID"
/*! \brief Move from string to ftdm_signal_event_t and viceversa */
FTDM_STR2ENUM_P(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t)
@@ -418,19 +440,55 @@ typedef struct {
ftdm_trace_type_t type;
} ftdm_event_trace_t;
typedef struct {
/* Digits collected */
char digits[FTDM_DIGITS_LIMIT];
} ftdm_event_collected_t;
/*! \brief FreeTDM supported indications.
* This is used during incoming calls when you want to request the signaling stack
* to notify about indications occurring locally. See ftdm_channel_call_indicate for more info */
typedef enum {
FTDM_CHANNEL_INDICATE_NONE,
FTDM_CHANNEL_INDICATE_RINGING,
FTDM_CHANNEL_INDICATE_PROCEED,
FTDM_CHANNEL_INDICATE_PROGRESS,
FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA,
FTDM_CHANNEL_INDICATE_BUSY,
/* Using this indication is equivalent to call ftdm_channel_call_answer API */
FTDM_CHANNEL_INDICATE_ANSWER,
FTDM_CHANNEL_INDICATE_INVALID,
} ftdm_channel_indication_t;
#define INDICATION_STRINGS "NONE", "RINGING", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "BUSY", "ANSWER", "INVALID"
/*! \brief Move from string to ftdm_channel_indication_t and viceversa */
FTDM_STR2ENUM_P(ftdm_str2channel_indication, ftdm_channel_indication2str, ftdm_channel_indication_t)
typedef struct {
/* The indication that was completed */
ftdm_channel_indication_t indication;
/* Completion status of the indication */
ftdm_status_t status;
} ftdm_event_indication_completed_t;
/*! \brief Generic signaling message */
struct ftdm_sigmsg {
ftdm_signal_event_t event_id; /*!< The type of message */
ftdm_channel_t *channel; /*!< Related channel */
uint32_t chan_id; /*!< easy access to chan id */
uint32_t span_id; /*!< easy access to span_id */
void *raw_data; /*!< Message specific data if any */
uint32_t raw_data_len; /*!< Data len in case is needed */
uint32_t call_id; /*!< unique call id for this call */
union {
ftdm_event_sigstatus_t sigstatus; /*!< valid if event_id is FTDM_SIGEVENT_SIGSTATUS_CHANGED */
ftdm_event_trace_t trace; /*!< valid if event_id is FTDM_SIGEVENT_TRACE or FTDM_SIGEVENT_TRACE_RAW */
}ev_data;
ftdm_event_collected_t collected; /*!< valid if event_id is FTDM_SIGEVENT_COLLECTED_DIGIT */
ftdm_event_indication_completed_t indication_completed; /*!< valid if the event_id is FTDM_SIGEVENT_INDICATION_COMPLETED */
} ev_data;
struct {
uint8_t autofree; /*!< Whether the freetdm core will free it after message delivery */
uint32_t len; /*!< Data len */
void *data; /*!< Signaling module specific data */
} raw;
};
/*! \brief Crash policy
@@ -535,11 +593,17 @@ typedef enum {
FTDM_COMMAND_GET_LINK_STATUS,
FTDM_COMMAND_ENABLE_LOOP,
FTDM_COMMAND_DISABLE_LOOP,
FTDM_COMMAND_COUNT,
FTDM_COMMAND_SET_RX_QUEUE_SIZE,
FTDM_COMMAND_SET_TX_QUEUE_SIZE,
FTDM_COMMAND_SET_POLARITY,
FTDM_COMMAND_COUNT,
} ftdm_command_t;
typedef enum {
FTDM_POLARITY_FORWARD = 0,
FTDM_POLARITY_REVERSE = 1
} ftdm_polarity_t;
/*! \brief Custom memory handler hooks. Not recommended to use unless you need memory allocation customizations */
typedef void *(*ftdm_malloc_func_t)(void *pool, ftdm_size_t len);
typedef void *(*ftdm_calloc_func_t)(void *pool, ftdm_size_t elements, ftdm_size_t len);
@@ -598,7 +662,20 @@ typedef ftdm_status_t (*fio_span_get_sig_status_t) FIO_SPAN_GET_SIG_STATUS_ARGS;
typedef ftdm_status_t (*fio_span_poll_event_t) FIO_SPAN_POLL_EVENT_ARGS ;
typedef ftdm_status_t (*fio_span_next_event_t) FIO_SPAN_NEXT_EVENT_ARGS ;
typedef ftdm_status_t (*fio_channel_next_event_t) FIO_CHANNEL_NEXT_EVENT_ARGS ;
/*! \brief Callback for signal delivery (FTDM_SIGEVENT_START and friends)
* \note This callback is provided by the user during ftdm_configure_span_signaling
*
* \note You must NOT do any blocking during this callback since this function is
* most likely called in an internal signaling thread that can potentially be
* shared for all the channels in a span and blocking will delay processing
* (sometimes even audio processing) for other channels
*
* \note Although some simple FreeTDM APIs can work (ie: ftdm_span_get_id etc), the
* use of any FreeTDM call API (ie ftdm_channel_call_answer) is discouraged
*/
typedef ftdm_status_t (*fio_signal_cb_t) FIO_SIGNAL_CB_ARGS ;
typedef ftdm_status_t (*fio_event_cb_t) FIO_EVENT_CB_ARGS ;
typedef ftdm_status_t (*fio_configure_span_t) FIO_CONFIGURE_SPAN_ARGS ;
typedef ftdm_status_t (*fio_configure_t) FIO_CONFIGURE_ARGS ;
@@ -682,17 +759,6 @@ typedef enum {
FTDM_CODEC_NONE = (1 << 30)
} ftdm_codec_t;
/*! \brief FreeTDM supported indications.
* This is used during incoming calls when you want to request the signaling stack
* to notify about indications occurring locally */
typedef enum {
FTDM_CHANNEL_INDICATE_RINGING,
FTDM_CHANNEL_INDICATE_PROCEED,
FTDM_CHANNEL_INDICATE_PROGRESS,
FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA,
FTDM_CHANNEL_INDICATE_BUSY,
} ftdm_channel_indication_t;
/*! \brief FreeTDM supported hardware alarms. */
typedef enum {
FTDM_ALARM_NONE = 0,
@@ -715,7 +781,12 @@ FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *ha
*/
FT_DECLARE(int) ftdm_channel_get_availability(ftdm_channel_t *ftdmchan);
/*! \brief Answer call */
/*! \brief Answer call. This can also be accomplished by ftdm_channel_call_indicate with FTDM_CHANNEL_INDICATE_ANSWER, in both
* cases you will get a FTDM_SIGEVENT_INDICATION_COMPLETED when the indication is sent (or an error occurs)
* \note Although this API will result in FTDM_SIGEVENT_INDICATION_COMPLETED event being delivered,
* there is no guarantee of whether the event will arrive after or before your execution thread returns
* from ftdm_channel_call_answer
*/
#define ftdm_channel_call_answer(ftdmchan) _ftdm_channel_call_answer(__FILE__, __FUNCTION__, __LINE__, (ftdmchan))
/*! \brief Answer call recording the source code point where the it was called (see ftdm_channel_call_answer for an easy to use macro) */
@@ -727,7 +798,19 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
/*! \brief Place an outgoing call recording the source code point where it was called (see ftdm_channel_call_place for an easy to use macro) */
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan);
/*! \brief Indicate a new condition in an incoming call */
/*! \brief Indicate a new condition in an incoming call
*
* \note Every indication request will result in FTDM_SIGEVENT_INDICATION_COMPLETED event being delivered with
* the proper status that will inform you if the request was successful or not. The exception is if this
* function returns something different to FTDM_SUCCESS, in which case the request failed right away and no
* further FTDM_SIGEVENT_INDICATION_COMPLETED will be delivered
* Be aware there is no guarantee of whether the completion event will arrive after or before your execution
* thread returns from ftdm_channel_call_indicate. This means you could get FTDM_SIGEVENT_INDICATION_COMPLETED
* even before your execution thread returns from the ftdm_channel_call_indicate() API
*
* \note You cannot send more than one indication at the time. You must wait for the completed event before
* calling this function again (unless the return code was different than FTDM_SUCCESS)
*/
#define ftdm_channel_call_indicate(ftdmchan, indication) _ftdm_channel_call_indicate(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), (indication))
/*! \brief Indicate a new condition in an incoming call recording the source code point where it was called (see ftdm_channel_call_indicate for an easy to use macro) */
@@ -1468,9 +1551,14 @@ FT_DECLARE(const char *) ftdm_channel_get_last_state_str(const ftdm_channel_t *c
*/
FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *channel);
/*! \brief Initialize channel state for an outgoing call */
/*! \brief Initialize channel state for an outgoing call
* \note This API will eventually be deprecated, is only needed if you use boost signaling
*/
FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan);
/*! \brief Enable/disable blocking mode in the channels for this span */
FT_DECLARE(ftdm_status_t) ftdm_span_set_blocking_mode(const ftdm_span_t *span, ftdm_bool_t enabled);
/*! \brief Initialize the library */
FT_DECLARE(ftdm_status_t) ftdm_global_init(void);
@@ -30,6 +30,12 @@
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
*
* Moises Silva <moy@sangoma.com>
* Ricardo Barroetaveña <rbarroetavena@anura.com.ar>
*
*/
#ifndef __FTDM_CALL_UTILS_H__
@@ -114,5 +120,16 @@ FT_DECLARE(ftdm_status_t) ftdm_set_presentation_ind(const char *string, uint8_t
*/
FT_DECLARE(ftdm_status_t) ftdm_is_number(const char *number);
/*!
* \brief Set the Calling Party Category from an enum
*
* \param cpc_string string value
* \param target the target to set value to
*
* \retval FTDM_SUCCESS success
* \retval FTDM_FAIL failure
*/
FT_DECLARE(ftdm_status_t) ftdm_set_calling_party_category(const char *string, uint8_t *target);
#endif /* __FTDM_CALL_UTILS_H__ */
+10 -1
View File
@@ -183,7 +183,16 @@ typedef enum {
FTDM_TIMEOUT, /*!< Operation timed out (ie: polling on a device)*/
FTDM_NOTIMPL, /*!< Operation not implemented */
FTDM_BREAK, /*!< Request the caller to perform a break (context-dependant, ie: stop getting DNIS/ANI) */
FTDM_EINVAL /*!< Invalid argument */
/*!< Any new return codes should try to mimc unix style error codes, no need to reinvent */
/* Remapping some of the codes that were before */
FTDM_ENOMEM = FTDM_MEMERR, /*!< Memory error */
FTDM_ETIMEDOUT = FTDM_TIMEOUT, /*!< Operation timedout */
FTDM_ENOSYS = FTDM_NOTIMPL, /*!< The function is not implemented */
FTDM_EINVAL, /*!< Invalid argument */
FTDM_ECANCELED, /*!< Operation cancelled */
FTDM_EBUSY, /*!< Device busy */
} ftdm_status_t;
/*! \brief FreeTDM bool type. */
+5
View File
@@ -51,6 +51,9 @@ extern "C" {
#include <unistd.h>
#endif
/*! \brief time data type */
typedef uint64_t ftdm_time_t;
/*! \brief sleep x amount of milliseconds */
#ifdef __WINDOWS__
#define ftdm_sleep(x) Sleep(x)
@@ -114,6 +117,8 @@ FT_DECLARE(char *) ftdm_strdup(const char *str);
/*! \brief Duplicate string with limit */
FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen);
/*! \brief Get the current time in milliseconds */
FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void);
#ifdef __cplusplus
} /* extern C */
+14 -76
View File
@@ -143,7 +143,9 @@ extern "C" {
\return true value if the object has the flags defined
*/
#define ftdm_test_flag(obj, flag) ((obj)->flags & flag)
/*!< Physical (IO) module specific flags */
#define ftdm_test_pflag(obj, flag) ((obj)->pflags & flag)
/*!< signaling module specific flags */
#define ftdm_test_sflag(obj, flag) ((obj)->sflags & flag)
#define ftdm_set_alarm_flag(obj, flag) (obj)->alarm_flags |= (flag)
@@ -190,17 +192,6 @@ extern "C" {
#define ftdm_clear_sflag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->sflags &= ~(flag); ftdm_mutex_unlock(obj->mutex);
#define ftdm_set_state(obj, s) ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); \
#define ftdm_set_state_locked(obj, s) \
do { \
ftdm_channel_lock(obj); \
ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); \
ftdm_channel_unlock(obj); \
} while(0);
#define ftdm_set_state_r(obj, s, r) r = ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0);
#ifdef _MSC_VER
/* The while(0) below throws a conditional expression is constant warning */
#pragma warning(disable:4127)
@@ -361,15 +352,6 @@ typedef struct {
ftdm_mutex_t *mutex;
} ftdm_dtmf_debug_t;
typedef struct {
const char *file;
const char *func;
int line;
ftdm_channel_state_t state;
ftdm_channel_state_t last_state;
ftdm_time_t time;
} ftdm_channel_history_entry_t;
typedef enum {
FTDM_IOSTATS_ERROR_CRC = (1 << 0),
FTDM_IOSTATS_ERROR_FRAME = (1 << 1),
@@ -411,7 +393,7 @@ struct ftdm_channel {
uint32_t extra_id;
ftdm_chan_type_t type;
ftdm_socket_t sockfd;
uint32_t flags;
uint64_t flags;
uint32_t pflags;
uint32_t sflags;
ftdm_alarm_flag_t alarm_flags;
@@ -422,9 +404,11 @@ struct ftdm_channel {
uint32_t native_interval;
uint32_t packet_len;
ftdm_channel_state_t state;
ftdm_state_status_t state_status;
ftdm_channel_state_t last_state;
ftdm_channel_state_t init_state;
ftdm_channel_history_entry_t history[10];
ftdm_channel_indication_t indication;
ftdm_state_history_entry_t history[10];
uint8_t hindex;
ftdm_mutex_t *mutex;
teletone_dtmf_detect_state_t dtmf_detect;
@@ -456,6 +440,7 @@ struct ftdm_channel {
ftdm_fsk_data_state_t fsk;
uint8_t fsk_buf[80];
uint32_t ring_count;
ftdm_polarity_t polarity;
/* Private I/O data. Do not touch unless you are an I/O module */
void *io_data;
/* Private signaling data. Do not touch unless you are a signaling module */
@@ -477,6 +462,7 @@ struct ftdm_channel {
ftdm_dtmf_debug_t dtmfdbg;
ftdm_io_dump_t rxdump;
ftdm_io_dump_t txdump;
ftdm_interrupt_t *state_completed_interrupt; /*!< Notify when a state change is completed */
int32_t txdrops;
int32_t rxdrops;
};
@@ -493,6 +479,7 @@ struct ftdm_span {
ftdm_trunk_type_t trunk_type;
ftdm_analog_start_type_t start_type;
ftdm_signal_type_t signal_type;
uint32_t last_used_index;
/* Private signaling data. Do not touch unless you are a signaling module */
void *signal_data;
fio_signal_cb_t signal_cb;
@@ -513,15 +500,15 @@ struct ftdm_span {
ftdm_span_stop_t stop;
ftdm_channel_sig_read_t sig_read;
ftdm_channel_sig_write_t sig_write;
/* Private I/O data per span. Do not touch unless you are an I/O module */
void *io_data;
ftdm_channel_state_processor_t state_processor; /*!< This guy is called whenever state processing is required */
void *io_data; /*!< Private I/O data per span. Do not touch unless you are an I/O module */
char *type;
char *dtmf_hangup;
size_t dtmf_hangup_len;
ftdm_state_map_t *state_map;
ftdm_caller_data_t default_caller_data;
ftdm_queue_t *pendingchans;
ftdm_queue_t *pendingsignals;
ftdm_queue_t *pendingchans; /*!< Channels pending of state processing */
ftdm_queue_t *pendingsignals; /*!< Signals pending from being delivered to the user */
struct ftdm_span *next;
};
@@ -568,11 +555,7 @@ FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_checksum(ftdm_fsk_data_state_t *stat
FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_sdmf(ftdm_fsk_data_state_t *state, const char *date, char *number);
FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, ftdm_fsk_data_state_t *fsk_data, float db_level);
FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line,
ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int wait);
FT_DECLARE(ftdm_status_t) ftdm_span_load_tones(ftdm_span_t *span, const char *mapname);
FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void);
FT_DECLARE(ftdm_status_t) ftdm_channel_use(ftdm_channel_t *ftdmchan);
@@ -585,8 +568,6 @@ FT_DECLARE(void) print_hex_bytes(uint8_t *data, ftdm_size_t dlen, char *buf, ftd
FT_DECLARE_NONSTD(int) ftdm_hash_equalkeys(void *k1, void *k2);
FT_DECLARE_NONSTD(uint32_t) ftdm_hash_hashfromstring(void *ky);
FT_DECLARE(ftdm_status_t) ftdm_channel_complete_state(ftdm_channel_t *ftdmchan);
FT_DECLARE(int) ftdm_load_modules(void);
FT_DECLARE(ftdm_status_t) ftdm_unload_modules(void);
@@ -602,6 +583,7 @@ FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap);
FT_DECLARE(ftdm_status_t) ftdm_span_close_all(void);
FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan);
FT_DECLARE(void) ftdm_ack_indication(ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication, ftdm_status_t status);
/*!
* \brief Retrieves an event from the span
@@ -702,50 +684,6 @@ static __inline__ void ftdm_abort(void)
#endif
}
static __inline__ void ftdm_set_state_all(ftdm_span_t *span, ftdm_channel_state_t state)
{
uint32_t j;
ftdm_mutex_lock(span->mutex);
for(j = 1; j <= span->chan_count; j++) {
if (!FTDM_IS_DCHAN(span->channels[j])) {
ftdm_set_state_locked((span->channels[j]), state);
}
}
ftdm_mutex_unlock(span->mutex);
}
static __inline__ int ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state)
{
uint32_t j;
for(j = 1; j <= span->chan_count; j++) {
if (span->channels[j]->state != state || ftdm_test_flag(span->channels[j], FTDM_CHANNEL_STATE_CHANGE)) {
return 0;
}
}
return 1;
}
static __inline__ void ftdm_set_flag_all(ftdm_span_t *span, uint32_t flag)
{
uint32_t j;
ftdm_mutex_lock(span->mutex);
for(j = 1; j <= span->chan_count; j++) {
ftdm_set_flag_locked((span->channels[j]), flag);
}
ftdm_mutex_unlock(span->mutex);
}
static __inline__ void ftdm_clear_flag_all(ftdm_span_t *span, uint32_t flag)
{
uint32_t j;
ftdm_mutex_lock(span->mutex);
for(j = 1; j <= span->chan_count; j++) {
ftdm_clear_flag_locked((span->channels[j]), flag);
}
ftdm_mutex_unlock(span->mutex);
}
static __inline__ int16_t ftdm_saturated_add(int16_t sample1, int16_t sample2)
{
int addres;
@@ -1,134 +0,0 @@
/*
* ftdm_m3ua.h
* freetdm
*
* Created by Shane Burrell on 4/3/08.
* Copyright 2008 Shane Burrell. All rights reserved.
*
* Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//#include "m3ua_client.h"
#include "freetdm.h"
#ifdef __cplusplus
extern "C" {
#endif
enum e_sigboost_event_id_values
{
SIGBOOST_EVENT_CALL_START = 0x80, /*128*/
SIGBOOST_EVENT_CALL_START_ACK = 0x81, /*129*/
SIGBOOST_EVENT_CALL_START_NACK = 0x82, /*130*/
SIGBOOST_EVENT_CALL_START_NACK_ACK = 0x83, /*131*/
SIGBOOST_EVENT_CALL_ANSWERED = 0x84, /*132*/
SIGBOOST_EVENT_CALL_STOPPED = 0x85, /*133*/
SIGBOOST_EVENT_CALL_STOPPED_ACK = 0x86, /*134*/
SIGBOOST_EVENT_SYSTEM_RESTART = 0x87, /*135*/
SIGBOOST_EVENT_SYSTEM_RESTART_ACK = 0x88, /*136*/
/* Following IDs are ss7boost to sangoma_mgd only. */
SIGBOOST_EVENT_HEARTBEAT = 0x89, /*137*/
SIGBOOST_EVENT_INSERT_CHECK_LOOP = 0x8a, /*138*/
SIGBOOST_EVENT_REMOVE_CHECK_LOOP = 0x8b, /*139*/
SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE = 0x8c, /*140*/
};
enum e_sigboost_release_cause_values
{
SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0,
SIGBOOST_RELEASE_CAUSE_NORMAL = 16,
SIGBOOST_RELEASE_CAUSE_BUSY = 17,
/* probable elimination */
//SIGBOOST_RELEASE_CAUSE_BUSY = 0x91, /* 145 */
//SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST = 0x92, /* 146 */
//SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET = 0x93, /* 147 */
//SIGBOOST_RELEASE_CAUSE_NOANSWER = 0x94, /* 148 */
};
enum e_sigboost_call_setup_ack_nack_cause_values
{
SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 117, /* unused Q.850 value */
SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY = 118, /* unused Q.850 value */
SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER = 28,
/* probable elimination */
//SIGBOOST_CALL_SETUP_RESERVED = 0x00,
//SIGBOOST_CALL_SETUP_CIRCUIT_RESET = 0x10,
//SIGBOOST_CALL_SETUP_NACK_CKT_START_TIMEOUT = 0x11,
//SIGBOOST_CALL_SETUP_NACK_AUTO_CALL_GAP = 0x17,
};
typedef enum {
M3UA_SPAN_SIGNALING_M3UA,
M3UA_SPAN_SIGNALING_SS7BOX,
} M3UA_TSpanSignaling;
#define M3UA_SPAN_STRINGS "M3UA", "SS7BOX"
FTDM_STR2ENUM_P(m3ua_str2span, m3ua_span2str, M3UA_TSpanSignaling)
typedef enum {
FTDM_M3UA_RUNNING = (1 << 0)
} ftdm_m3uat_flag_t;
/*typedef struct m3ua_data {
m3uac_connection_t mcon;
m3uac_connection_t pcon;
fio_signal_cb_t signal_cb;
uint32_t flags;
} m3ua_data_t;
*/
/*typedef struct mu3a_link {
ss7bc_connection_t mcon;
ss7bc_connection_t pcon;
fio_signal_cb_t signal_cb;
uint32_t flags;
} ftdm_m3ua_data_t;
*/
ftdm_status_t m3ua_init(ftdm_io_interface_t **zint);
ftdm_status_t m3ua_destroy(void);
ftdm_status_t m3ua_start(ftdm_span_t *span);
#ifdef __cplusplus
}
#endif
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
@@ -0,0 +1,237 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* Moises Silva <moy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __FTDM_STATE_H__
#define __FTDM_STATE_H__
/*! \file
* \brief State handling definitions
* \note Most, if not all of the state handling functions assume you have a lock acquired. Touching the channel
* state is a sensitive matter that requires checks and careful thought and is typically a process that
* is not encapsulated within a single function, therefore the lock must be explicitly acquired by the
* caller (most of the time, signaling modules), process states, set a new state and process it, and
* finally unlock the channel. See docs/locking.txt fore more info
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
FTDM_CHANNEL_STATE_DOWN,
FTDM_CHANNEL_STATE_HOLD,
FTDM_CHANNEL_STATE_SUSPENDED,
FTDM_CHANNEL_STATE_DIALTONE,
FTDM_CHANNEL_STATE_COLLECT,
FTDM_CHANNEL_STATE_RING,
FTDM_CHANNEL_STATE_RINGING,
FTDM_CHANNEL_STATE_BUSY,
FTDM_CHANNEL_STATE_ATTN,
FTDM_CHANNEL_STATE_GENRING,
FTDM_CHANNEL_STATE_DIALING,
FTDM_CHANNEL_STATE_GET_CALLERID,
FTDM_CHANNEL_STATE_CALLWAITING,
FTDM_CHANNEL_STATE_RESTART,
FTDM_CHANNEL_STATE_PROCEED,
FTDM_CHANNEL_STATE_PROGRESS,
FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
FTDM_CHANNEL_STATE_UP,
FTDM_CHANNEL_STATE_IDLE,
FTDM_CHANNEL_STATE_TERMINATING,
FTDM_CHANNEL_STATE_CANCEL,
FTDM_CHANNEL_STATE_HANGUP,
FTDM_CHANNEL_STATE_HANGUP_COMPLETE,
FTDM_CHANNEL_STATE_IN_LOOP,
FTDM_CHANNEL_STATE_RESET,
FTDM_CHANNEL_STATE_INVALID
} ftdm_channel_state_t;
#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
"RING", "RINGING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
"RESTART", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \
"HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "RESET", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t)
typedef struct {
const char *file;
const char *func;
int line;
ftdm_channel_state_t state; /*!< Current state (processed or not) */
ftdm_channel_state_t last_state; /*!< Previous state */
ftdm_time_t time; /*!< Time the state was set */
ftdm_time_t end_time; /*!< Time the state processing was completed */
} ftdm_state_history_entry_t;
typedef ftdm_status_t (*ftdm_channel_state_processor_t)(ftdm_channel_t *fchan);
/*!
* \brief Process channel states by invoking the channel state processing routine
* it will keep calling the processing routine while the state status
* is FTDM_STATE_STATUS_NEW, it will not do anything otherwise
*/
FT_DECLARE(ftdm_status_t) ftdm_channel_advance_states(ftdm_channel_t *fchan);
FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const char *function, int line, ftdm_channel_t *fchan);
#define ftdm_channel_complete_state(obj) _ftdm_channel_complete_state(__FILE__, __FUNCTION__, __LINE__, obj)
FT_DECLARE(int) ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state);
/*!
* \brief Status of the current channel state
* \note A given state goes thru several status (yes, states for the state!)
* The order is always FTDM_STATE_STATUS_NEW -> FTDM_STATE_STATUS_PROCESSED -> FTDM_STATUS_COMPLETED
* However, is possible to go from NEW -> COMPLETED directly when the signaling module explicitly changes
* the state of the channel in the middle of processing the current state by calling the ftdm_set_state() API
*
* FTDM_STATE_STATUS_NEW -
* Someone just set the state of the channel, either the signaling module or the user (implicitly through a call API).
* This is accomplished by calling ftdm_channel_set_state() which changes the 'state' and 'last_state' memebers of
* the ftdm_channel_t structure.
*
* FTDM_STATE_STATUS_PROCESSED -
* The signaling module did something based on the new state.
*
* This is accomplished via ftdm_channel_advance_states()
*
* When ftdm_channel_advance_states(), at the very least, if the channel has its state in FTDM_STATE_STATUS_NEW, it
* will move to FTDM_STATE_STATUS_PROCESSED, depending on what the signaling module does during the processing
* the state may move to FTDM_STATE_STATUS_COMPLETED right after or wait for a signaling specific event to complete it.
* It is also possible that more state transitions occur during the execution of ftdm_channel_advance_states() if one
* state processing/completion leads to another state change, the function will not return until the chain of events
* lead to a state that is not in FTDM_STATE_STATUS_NEW
*
* FTDM_STATE_STATUS_COMPLETED -
* The signaling module completed the processing of the state and there is nothing further to be done for this state.
*
* This is accomplished either explicitly by the signaling module by calling ftdm_channel_complete_state() or by
* the signaling module implicitly by trying to set the state of the channel to a new state via ftdm_set_state()
*
* When working with blocking channels (FTDM_CHANNEL_NONBLOCK flag not set), the user thread is signaled and unblocked
* so it can continue.
*
* When a state moves to this status is also possible for a signal FTDM_SIGEVENT_INDICATION_COMPLETED to be delivered
* by the core if the state change was associated to an indication requested by the user,
*/
typedef enum {
FTDM_STATE_STATUS_NEW,
FTDM_STATE_STATUS_PROCESSED,
FTDM_STATE_STATUS_COMPLETED,
FTDM_STATE_STATUS_INVALID
} ftdm_state_status_t;
#define CHANNEL_STATE_STATUS_STRINGS "NEW", "PROCESSED", "COMPLETED", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_state_status, ftdm_state_status2str, ftdm_state_status_t)
typedef enum {
ZSM_NONE,
ZSM_UNACCEPTABLE,
ZSM_ACCEPTABLE
} ftdm_state_map_type_t;
typedef enum {
ZSD_INBOUND,
ZSD_OUTBOUND,
} ftdm_state_direction_t;
#define FTDM_MAP_NODE_SIZE 512
#define FTDM_MAP_MAX FTDM_CHANNEL_STATE_INVALID+2
struct ftdm_state_map_node {
ftdm_state_direction_t direction;
ftdm_state_map_type_t type;
ftdm_channel_state_t check_states[FTDM_MAP_MAX];
ftdm_channel_state_t states[FTDM_MAP_MAX];
};
typedef struct ftdm_state_map_node ftdm_state_map_node_t;
struct ftdm_state_map {
ftdm_state_map_node_t nodes[FTDM_MAP_NODE_SIZE];
};
typedef struct ftdm_state_map ftdm_state_map_t;
/*!\brief Set the state for a channel (the channel must be locked when calling this function)
* \note Signaling modules should use ftdm_set_state macro instead
* \note If this function is called with the wait parameter set to a non-zero value, the recursivity
* of the channel lock must be == 1 because the channel will be unlocked/locked when waiting */
FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line,
ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int wait);
/*!\brief Set the state of a channel immediately and implicitly complete the previous state if needed
* \note FTDM_SIGEVENT_INDICATION_COMPLETED will be sent if the state change
* is associated to some indication (ie FTDM_CHANNEL_INDICATE_PROCEED)
* \note The channel must be locked when calling this function
* */
FT_DECLARE(ftdm_status_t) _ftdm_set_state(const char *file, const char *func, int line,
ftdm_channel_t *fchan, ftdm_channel_state_t state);
#define ftdm_set_state(obj, s) _ftdm_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s); \
/*!\brief This macro is deprecated, signaling modules should always lock the channel themselves anyways since they must
* process first the user pending state changes then set a new state before releasing the lock
* this macro is here for backwards compatibility, DO NOT USE IT in new code since it is *always* wrong to set
* a state in a signaling module without checking and processing the current state first (and for that you must lock the channel)
*/
#define ftdm_set_state_locked(obj, s) \
do { \
ftdm_channel_lock(obj); \
ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); \
ftdm_channel_unlock(obj); \
} while(0);
#define ftdm_set_state_r(obj, s, r) r = ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0);
#define ftdm_set_state_all(span, state) \
do { \
uint32_t _j; \
ftdm_mutex_lock((span)->mutex); \
for(_j = 1; _j <= (span)->chan_count; _j++) { \
if (!FTDM_IS_DCHAN(span->channels[_j])) { \
ftdm_set_state_locked((span->channels[_j]), state); \
} \
} \
ftdm_mutex_unlock((span)->mutex); \
} while (0);
#ifdef __cplusplus
}
#endif
#endif
/* 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:
*/
+51 -109
View File
@@ -69,8 +69,6 @@ extern "C" {
#define FTDM_END -1
#define FTDM_ANY_STATE -1
typedef uint64_t ftdm_time_t;
typedef enum {
FTDM_ENDIAN_BIG = 1,
FTDM_ENDIAN_LITTLE = -1
@@ -123,6 +121,7 @@ typedef enum {
FTDM_STR2ENUM_P(ftdm_str2ftdm_analog_start_type, ftdm_analog_start_type2str, ftdm_analog_start_type_t)
typedef enum {
FTDM_OOB_NOOP,
FTDM_OOB_ONHOOK,
FTDM_OOB_OFFHOOK,
FTDM_OOB_WINK,
@@ -131,11 +130,11 @@ typedef enum {
FTDM_OOB_RING_STOP,
FTDM_OOB_ALARM_TRAP,
FTDM_OOB_ALARM_CLEAR,
FTDM_OOB_NOOP,
FTDM_OOB_CAS_BITS_CHANGE,
FTDM_OOB_POLARITY_REVERSE,
FTDM_OOB_INVALID
} ftdm_oob_event_t;
#define OOB_STRINGS "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "NOOP", "CAS_BITS_CHANGE", "INVALID"
#define OOB_STRINGS "NOOP", "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "CAS_BITS_CHANGE", "POLARITY_REVERSE", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_oob_event, ftdm_oob_event2str, ftdm_oob_event_t)
/*! \brief Event types */
@@ -169,7 +168,7 @@ typedef enum {
typedef enum {
FTDM_SPAN_CONFIGURED = (1 << 0),
FTDM_SPAN_READY = (1 << 1),
FTDM_SPAN_STARTED = (1 << 1),
FTDM_SPAN_STATE_CHANGE = (1 << 2),
FTDM_SPAN_SUSPENDED = (1 << 3),
FTDM_SPAN_IN_THREAD = (1 << 4),
@@ -203,113 +202,56 @@ typedef enum {
FTDM_CHANNEL_FEATURE_IO_STATS = (1<<9), /*!< Channel supports IO statistics (HDLC channels only) */
} ftdm_channel_feature_t;
typedef enum {
FTDM_CHANNEL_STATE_DOWN,
FTDM_CHANNEL_STATE_HOLD,
FTDM_CHANNEL_STATE_SUSPENDED,
FTDM_CHANNEL_STATE_DIALTONE,
FTDM_CHANNEL_STATE_COLLECT,
FTDM_CHANNEL_STATE_RING,
FTDM_CHANNEL_STATE_RINGING,
FTDM_CHANNEL_STATE_BUSY,
FTDM_CHANNEL_STATE_ATTN,
FTDM_CHANNEL_STATE_GENRING,
FTDM_CHANNEL_STATE_DIALING,
FTDM_CHANNEL_STATE_GET_CALLERID,
FTDM_CHANNEL_STATE_CALLWAITING,
FTDM_CHANNEL_STATE_RESTART,
FTDM_CHANNEL_STATE_PROCEED,
FTDM_CHANNEL_STATE_PROGRESS,
FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
FTDM_CHANNEL_STATE_UP,
FTDM_CHANNEL_STATE_IDLE,
FTDM_CHANNEL_STATE_TERMINATING,
FTDM_CHANNEL_STATE_CANCEL,
FTDM_CHANNEL_STATE_HANGUP,
FTDM_CHANNEL_STATE_HANGUP_COMPLETE,
FTDM_CHANNEL_STATE_IN_LOOP,
FTDM_CHANNEL_STATE_RESET,
FTDM_CHANNEL_STATE_INVALID
} ftdm_channel_state_t;
#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
"RING", "RINGING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
"RESTART", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \
"HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "RESET", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t)
/*!< Channel flags. This used to be an enum but we reached the 32bit limit for enums, is safer this way */
#define FTDM_CHANNEL_CONFIGURED (1ULL << 0)
#define FTDM_CHANNEL_READY (1ULL << 1)
#define FTDM_CHANNEL_OPEN (1ULL << 2)
#define FTDM_CHANNEL_DTMF_DETECT (1ULL << 3)
#define FTDM_CHANNEL_SUPRESS_DTMF (1ULL << 4)
#define FTDM_CHANNEL_TRANSCODE (1ULL << 5)
#define FTDM_CHANNEL_BUFFER (1ULL << 6)
#define FTDM_CHANNEL_EVENT (1ULL << 7)
#define FTDM_CHANNEL_INTHREAD (1ULL << 8)
#define FTDM_CHANNEL_WINK (1ULL << 9)
#define FTDM_CHANNEL_FLASH (1ULL << 10)
#define FTDM_CHANNEL_STATE_CHANGE (1ULL << 11)
#define FTDM_CHANNEL_HOLD (1ULL << 12)
#define FTDM_CHANNEL_INUSE (1ULL << 13)
#define FTDM_CHANNEL_OFFHOOK (1ULL << 14)
#define FTDM_CHANNEL_RINGING (1ULL << 15)
#define FTDM_CHANNEL_PROGRESS_DETECT (1ULL << 16)
#define FTDM_CHANNEL_CALLERID_DETECT (1ULL << 17)
#define FTDM_CHANNEL_OUTBOUND (1ULL << 18)
#define FTDM_CHANNEL_SUSPENDED (1ULL << 19)
#define FTDM_CHANNEL_3WAY (1ULL << 20)
typedef enum {
FTDM_CHANNEL_CONFIGURED = (1 << 0),
FTDM_CHANNEL_READY = (1 << 1),
FTDM_CHANNEL_OPEN = (1 << 2),
FTDM_CHANNEL_DTMF_DETECT = (1 << 3),
FTDM_CHANNEL_SUPRESS_DTMF = (1 << 4),
FTDM_CHANNEL_TRANSCODE = (1 << 5),
FTDM_CHANNEL_BUFFER = (1 << 6),
FTDM_CHANNEL_EVENT = (1 << 7),
FTDM_CHANNEL_INTHREAD = (1 << 8),
FTDM_CHANNEL_WINK = (1 << 9),
FTDM_CHANNEL_FLASH = (1 << 10),
FTDM_CHANNEL_STATE_CHANGE = (1 << 11),
FTDM_CHANNEL_HOLD = (1 << 12),
FTDM_CHANNEL_INUSE = (1 << 13),
FTDM_CHANNEL_OFFHOOK = (1 << 14),
FTDM_CHANNEL_RINGING = (1 << 15),
FTDM_CHANNEL_PROGRESS_DETECT = (1 << 16),
FTDM_CHANNEL_CALLERID_DETECT = (1 << 17),
FTDM_CHANNEL_OUTBOUND = (1 << 18),
FTDM_CHANNEL_SUSPENDED = (1 << 19),
FTDM_CHANNEL_3WAY = (1 << 20),
FTDM_CHANNEL_PROGRESS = (1 << 21),
FTDM_CHANNEL_MEDIA = (1 << 22),
FTDM_CHANNEL_ANSWERED = (1 << 23),
FTDM_CHANNEL_MUTE = (1 << 24),
FTDM_CHANNEL_USE_RX_GAIN = (1 << 25),
FTDM_CHANNEL_USE_TX_GAIN = (1 << 26),
FTDM_CHANNEL_IN_ALARM = (1 << 27),
FTDM_CHANNEL_SIG_UP = (1 << 28),
FTDM_CHANNEL_USER_HANGUP = (1 << 29),
FTDM_CHANNEL_RX_DISABLED = (1 << 30),
FTDM_CHANNEL_TX_DISABLED = (1 << 31),
/* ok, when we reach 32, we need to move to uint64_t all the flag stuff */
} ftdm_channel_flag_t;
#if defined(__cplusplus) && defined(WIN32)
// fix C2676
__inline__ ftdm_channel_flag_t operator|=(ftdm_channel_flag_t a, int32_t b) {
a = (ftdm_channel_flag_t)(a | b);
return a;
}
__inline__ ftdm_channel_flag_t operator&=(ftdm_channel_flag_t a, int32_t b) {
a = (ftdm_channel_flag_t)(a & b);
return a;
}
#endif
/* this 3 flags are really nonsense used by boost module only, as soon
* as we deprecate/delete boost module we can get rid of them
* ==================
* */
#define FTDM_CHANNEL_PROGRESS (1ULL << 21)
#define FTDM_CHANNEL_MEDIA (1ULL << 22)
#define FTDM_CHANNEL_ANSWERED (1ULL << 23)
/* ================== */
typedef enum {
ZSM_NONE,
ZSM_UNACCEPTABLE,
ZSM_ACCEPTABLE
} ftdm_state_map_type_t;
#define FTDM_CHANNEL_MUTE (1ULL << 24)
#define FTDM_CHANNEL_USE_RX_GAIN (1ULL << 25)
#define FTDM_CHANNEL_USE_TX_GAIN (1ULL << 26)
#define FTDM_CHANNEL_IN_ALARM (1ULL << 27)
#define FTDM_CHANNEL_SIG_UP (1ULL << 28)
#define FTDM_CHANNEL_USER_HANGUP (1ULL << 29)
#define FTDM_CHANNEL_RX_DISABLED (1ULL << 30)
#define FTDM_CHANNEL_TX_DISABLED (1ULL << 31)
/*!< The user knows about a call in this channel */
#define FTDM_CHANNEL_CALL_STARTED (1ULL << 32)
/*!< The user wants non-blocking operations in the channel */
#define FTDM_CHANNEL_NONBLOCK (1ULL << 33)
/*!< There is a pending acknowledge for an indication */
#define FTDM_CHANNEL_IND_ACK_PENDING (1ULL << 34)
/*!< There is someone blocking in the channel waiting for state completion */
#define FTDM_CHANNEL_BLOCKING (1ULL << 35)
typedef enum {
ZSD_INBOUND,
ZSD_OUTBOUND,
} ftdm_state_direction_t;
#define FTDM_MAP_NODE_SIZE 512
#define FTDM_MAP_MAX FTDM_CHANNEL_STATE_INVALID+2
struct ftdm_state_map_node {
ftdm_state_direction_t direction;
ftdm_state_map_type_t type;
ftdm_channel_state_t check_states[FTDM_MAP_MAX];
ftdm_channel_state_t states[FTDM_MAP_MAX];
};
typedef struct ftdm_state_map_node ftdm_state_map_node_t;
struct ftdm_state_map {
ftdm_state_map_node_t nodes[FTDM_MAP_NODE_SIZE];
};
typedef struct ftdm_state_map ftdm_state_map_t;
#include "ftdm_state.h"
typedef enum ftdm_channel_hw_link_status {
FTDM_HW_LINK_DISCONNECTED = 0,
-62
View File
@@ -1,62 +0,0 @@
/* WARNING WORK IN PROGRESS
* mstm3ua.c
* mstss7d port
*
* Created by Shane Burrell on 2/2/08.
* Copyright 2008 Shane Burrell. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "mstm3ua.h"
int build_m3ua_hdr(unsigned char len,unsigned char *bytemsg)
{
*bytemsg++ = M_VERSION_REL1; // 1 Verison
//bytemsg[1] = 0x00; // 2 RESERVED
//bytemsg[2] = M_CLASS_XFER; // 3 Msg Class
//SS7 BOX Kludge
*bytemsg++ = 0x01; // 2 RESERVED
*bytemsg++ = 0x00; // 2 RESERVED
*bytemsg++ = M_TYPE_DATA ; // 4 Msg Type
*bytemsg++ = len; // 5 Msg LENGTH 81 32bit field
*bytemsg++ = 0x00; // 6
*bytemsg++ = 0x00; // 7
*bytemsg++ = 0x00; // 8
return(0);
};
-96
View File
@@ -1,96 +0,0 @@
/*
* mstm3ua.h
* mstss7d
*
* Created by Shane Burrell on 3/2/08.
* Copyright 2008 Shane Burrell. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
typedef unsigned long m3ua_ulong;
typedef unsigned short m3ua_ushort;
typedef unsigned char m3ua_uchar;
typedef unsigned char u8;
typedef unsigned short u16; /* Note: multi-byte values are little-endian */
typedef unsigned long u32;
#define M_TAG_NETWORK_APPEARANCE 1
#define M_TAG_PROTOCOL_DATA 3
#define M_TAG_INFO_STRING 4
#define M_TAG_AFFECTED_DPC 5
#define M_TAG_ROUTING_CONTEXT 6
#define M_TAG_DIAGNOSTIC_INFORMATION 7
#define M_TAG_HEARTBEAT_DATA 8
#define M_TAG_UNAVAILABILITY_CAUSE 9
#define M_TAG_REASON 10
#define M_TAG_TRAFFIC_MODE_TYPE 11
#define M_TAG_ERROR_CODE 12
#define M_TAG_STATUS_TYPE 13
#define M_TAG_CONGESTED_INDICATIONS 14
#define M_VERSION_REL1 1
#define M_CLASS_MGMT 0x00
#define M_CLASS_XFER 0x01
#define M_CLASS_SSNM 0x02
#define M_CLASS_ASPSM 0x03
#define M_CLASS_ASPTM 0x04
#define M_CLASS_RKM 0x09
#define M_TYPE_ERR (0|M_CLASS_MGMT
#define M_TYPE_NTFY (1|M_CLASS_XFER)
#define M_TYPE_DATA (1|M_CLASS_XFER)
#define M_TYPE_DUNA (1|M_CLASS_SSNM)
#define M_TYPE_DAVA (2|M_CLASS_SSNM)
#define M_TYPE_DUAD (3|M_CLASS_SSNM)
#define M_TYPE_SCON (4|M_CLASS_SSNM)
#define M_TYPE_DUPU (5|M_CLASS_SSNM)
#define M_TYPE_UP (1|M_CLASS_ASPSM)
#define M_TYPE_DOWN (2|M_CLASS_ASPSM)
#define M_TYPE_BEAT (3|M_CLASS_ASPSM)
#define M_TYPE_UP_ACK (4|M_CLASS_ASPSM)
#define M_TYPE_DOWN_ACK (5|M_CLASS_ASPSM)
#define M_TYPE_BEAT_ACK (6|M_CLASS_ASPSM)
#define M_TYPE_ACTIVE (1|M_CLASS_ASPTM)
#define M_TYPE_INACTIVE (2|M_CLASS_ASPTM)
#define M_TYPE_ACTIVE_ACK (3|M_CLASS_ASPTM)
#define M_TYPE_INACTIVE_ACK (4|M_CLASS_ASPTM)
#define M_CLASS_MASK 0xff00
#define M_TYPE_MASK 0x00ff
-333
View File
@@ -1,333 +0,0 @@
/*
* m3ua_client.c
* freetdm
*
* Created by Shane Burrell on 4/3/08.
* Copyright 2008 Shane Burrell. All rights reserved.
*
*
* Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NETDB_H
#include <netdb.h>
#endif
#include "freetdm.h"
#include <m3ua_client.h>
#ifndef HAVE_GETHOSTBYNAME_R
extern int gethostbyname_r (const char *__name,
struct hostent *__result_buf,
char *__buf, size_t __buflen,
struct hostent **__result,
int *__h_errnop);
#endif
struct m3uac_map {
uint32_t event_id;
const char *name;
};
static struct m3uac_map m3uac_table[] = {
{M3UA_EVENT_CALL_START, "CALL_START"},
{M3UA_EVENT_CALL_START_ACK, "CALL_START_ACK"},
{M3UA_EVENT_CALL_START_NACK, "CALL_START_NACK"},
{M3UA_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"},
{M3UA_EVENT_CALL_ANSWERED, "CALL_ANSWERED"},
{M3UA_EVENT_CALL_STOPPED, "CALL_STOPPED"},
{M3UA_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"},
{M3UA_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"},
{M3UA_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"},
{M3UA_EVENT_HEARTBEAT, "HEARTBEAT"},
{M3UA_EVENT_INSERT_CHECK_LOOP, "LOOP START"},
{M3UA_EVENT_REMOVE_CHECK_LOOP, "LOOP STOP"}
};
static int create_conn_socket(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
{
int rc;
struct hostent *result, *local_result;
char buf[512], local_buf[512];
int err = 0;
memset(&mcon->remote_hp, 0, sizeof(mcon->remote_hp));
memset(&mcon->local_hp, 0, sizeof(mcon->local_hp));
mcon->socket = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
ftdm_log(FTDM_LOG_DEBUG, "Creating L=%s:%d R=%s:%d\n",
local_ip,local_port,ip,port);
if (mcon->socket >= 0) {
int flag;
flag = 1;
gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &result, &err);
gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_result, &err);
if (result && local_result) {
mcon->remote_addr.sin_family = mcon->remote_hp.h_addrtype;
memcpy((char *) &mcon->remote_addr.sin_addr.s_addr, mcon->remote_hp.h_addr_list[0], mcon->remote_hp.h_length);
mcon->remote_addr.sin_port = htons(port);
mcon->local_addr.sin_family = mcon->local_hp.h_addrtype;
memcpy((char *) &mcon->local_addr.sin_addr.s_addr, mcon->local_hp.h_addr_list[0], mcon->local_hp.h_length);
mcon->local_addr.sin_port = htons(local_port);
setsockopt(mcon->socket, IPPROTO_SCTP, SCTP_NODELAY, (char *)&flag, sizeof(int));
rc=listen(mcon->socket,100);
if (rc) {
close(mcon->socket);
mcon->socket = -1;
}
}
}
ftdm_mutex_create(&mcon->mutex);
return mcon->socket;
}
int m3uac_connection_close(m3uac_connection_t *mcon)
{
if (mcon->socket > -1) {
close(mcon->socket);
}
ftdm_mutex_lock(mcon->mutex);
ftdm_mutex_unlock(mcon->mutex);
ftdm_mutex_destroy(&mcon->mutex);
memset(mcon, 0, sizeof(*mcon));
mcon->socket = -1;
return 0;
}
int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port)
{
create_conn_socket(mcon, local_ip, local_port, ip, port);
return mcon->socket;
}
int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause)
{
m3uac_event_t oevent;
int retry = 5;
m3uac_event_init(&oevent, cmd, chan, span);
oevent.release_cause = cause;
if (cmd == SIGBOOST_EVENT_SYSTEM_RESTART) {
mcon->rxseq_reset = 1;
mcon->txseq = 0;
mcon->rxseq = 0;
mcon->txwindow = 0;
}
if (id >= 0) {
oevent.call_setup_id = id;
}
while (m3uac_connection_write(mcon, &oevent) <= 0) {
if (--retry <= 0) {
ftdm_log(FTDM_LOG_CRIT, "Failed to tx on M3UA socket: %s\n", strerror(errno));
return -1;
} else {
ftdm_log(FTDM_LOG_WARNING, "Failed to tx on M3UA socket: %s :retry %i\n", strerror(errno), retry);
ftdm_sleep(1);
}
}
return 0;
}
m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration)
{
unsigned int fromlen = sizeof(struct sockaddr_in);
int bytes = 0;
bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT,
(struct sockaddr *) &mcon->local_addr, &fromlen);
if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) {
if (mcon->rxseq_reset) {
if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) {
ftdm_log(FTDM_LOG_DEBUG, "Rx sync ok\n");
mcon->rxseq = mcon->event.fseqno;
return &mcon->event;
}
errno=EAGAIN;
ftdm_log(FTDM_LOG_DEBUG, "Waiting for rx sync...\n");
return NULL;
}
mcon->txwindow = mcon->txseq - mcon->event.bseqno;
mcon->rxseq++;
if (mcon->rxseq != mcon->event.fseqno) {
ftdm_log(FTDM_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno);
return NULL;
}
return &mcon->event;
} else {
if (iteration == 0) {
ftdm_log(FTDM_LOG_CRIT, "Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
return NULL;
}
}
return NULL;
}
m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration)
{
unsigned int fromlen = sizeof(struct sockaddr_in);
int bytes = 0;
bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen);
if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) {
return &mcon->event;
} else {
if (iteration == 0) {
ftdm_log(FTDM_LOG_CRIT, "Critical Error: PQ Invalid Event lenght from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event));
return NULL;
}
}
return NULL;
}
int m3uac_connection_write(m3uac_connection_t *mcon, ss7bc_event_t *event)
{
int err;
if (!event || mcon->socket < 0 || !mcon->mutex) {
ftdm_log(FTDM_LOG_DEBUG, "Critical Error: No Event Device\n");
return -EINVAL;
}
if (event->span > 16 || event->chan > 31) {
ftdm_log(FTDM_LOG_CRIT, "Critical Error: TX Cmd=%s Invalid Span=%i Chan=%i\n", m3uac_event_id_name(event->event_id), event->span,event->chan);
return -1;
}
gettimeofday(&event->tv,NULL);
ftdm_mutex_lock(mcon->mutex);
event->fseqno = mcon->txseq++;
event->bseqno = mcon->rxseq;
err = sendto(mcon->socket, event, sizeof(m3uac_event_t), 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr));
ftdm_mutex_unlock(mcon->mutex);
if (err != sizeof(m3uac_event_t)) {
err = -1;
}
ftdm_log(FTDM_LOG_DEBUG, "TX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n",
m3uac_event_id_name(event->event_id),
event->event_id,
event->span+1,
event->chan+1,
event->release_cause,
event->call_setup_id,
event->fseqno,
(event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"),
(event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A")
);
return err;
}
void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id)
{
memset(event, 0, sizeof(m3uac_event_t));
event->event_id = M3UA_EVENT_CALL_START;
if (calling) {
strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1);
event->calling_number_digits_count = strlen(calling);
}
if (called) {
strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1);
event->called_number_digits_count = strlen(called);
}
event->call_setup_id = setup_id;
}
void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span)
{
memset(event, 0, sizeof(ss7bc_event_t));
event->event_id = event_id;
event->chan = chan;
event->span = span;
}
const char *m3uac_event_id_name(uint32_t event_id)
{
unsigned int x;
const char *ret = NULL;
for (x = 0 ; x < sizeof(m3uac_table)/sizeof(struct m3uac_map); x++) {
if (m3uac_table[x].event_id == event_id) {
ret = m3uac_table[x].name;
break;
}
}
return ret;
}
/* 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:
*/
-164
View File
@@ -1,164 +0,0 @@
/*
* m3ua_client.h
* freetdm
*
* Created by Shane Burrell on 4/3/08.
* Copyright 2008 Shane Burrell. All rights reserved.
*
* Copyright (c) 2007, Anthony Minessale II, Nenad Corbic
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
// Fix this for portability
#include <sctp.h>
//#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <stdarg.h>
#include <netdb.h>
//#include <sigboost.h>
#include <sys/time.h>
#define MAX_DIALED_DIGITS 31
#define MAX_CALLING_NAME 31
/* Next two defines are used to create the range of values for call_setup_id
* in the t_sigboost structure.
* 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */
#define CORE_MAX_SPANS 200
#define CORE_MAX_CHAN_PER_SPAN 30
#define MAX_PENDING_CALLS CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN
/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */
#define SIZE_RDNIS 80
//#undef MSGWINDOW
#define MSGWINDOW
typedef struct
{
uint32_t event_id;
uint32_t fseqno;
#ifdef MSGWINDOW
uint32_t bseqno;
#endif
uint16_t call_setup_id;
uint32_t trunk_group;
uint32_t span;
uint32_t chan;
uint8_t called_number_digits_count;
char called_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
uint8_t calling_number_digits_count; /* it's an array */
char calling_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */
uint8_t release_cause;
struct timeval tv;
/* ref. Q.931 Table 4-11 and Q.951 Section 3 */
uint8_t calling_number_screening_ind;
uint8_t calling_number_presentation;
char redirection_string [SIZE_RDNIS]; /* it's a null terminated string */
} t_m3ua;
typedef t_m3ua m3uac_event_t;
typedef uint32_t m3uac_event_id_t;
typedef struct m3uac_ip_cfg
{
char local_ip[25];
int local_port;
char remote_ip[25];
int remote_port;
}m3uac_ip_cfg_t;
struct m3uac_connection {
ftdm_socket_t socket;
struct sockaddr_in local_addr;
struct sockaddr_in remote_addr;
m3uac_event_t event;
struct hostent remote_hp;
struct hostent local_hp;
unsigned int flags;
ftdm_mutex_t *mutex;
FILE *log;
unsigned int txseq;
unsigned int rxseq;
unsigned int txwindow;
unsigned int rxseq_reset;
m3uac_ip_cfg_t cfg;
uint32_t hb_elapsed;
int up;
};
typedef enum {
MSU_FLAG_EVENT = (1 << 0)
} m3uac_flag_t;
typedef struct m3uac_connection m3uac_connection_t;
static inline void sctp_no_nagle(int socket)
{
//int flag = 1;
//setsockopt(socket, IPPROTO_SCTP, SCTP_NODELAY, (char *) &flag, sizeof(int));
}
int m3uac_connection_close(m3uac_connection_t *mcon);
int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port);
m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration);
m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration);
int m3uac_connection_write(m3uac_connection_t *mcon, m3uac_event_t *event);
void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span);
void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id);
const char *m3uac_event_id_name(uint32_t event_id);
int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause);
/* 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:
*/
-60
View File
@@ -1,60 +0,0 @@
/*
* testm3ua.c
* freetdm
*
* Created by Shane Burrell on 4/8/08.
* Copyright 2008 __MyCompanyName__. All rights reserved.
*
*/
#include "testm3ua.h"
#include "freetdm.h"
#include "ftdm_m3ua.h"
static FIO_SIGNAL_CB_FUNCTION(on_signal)
{
return FTDM_FAIL;
}
int main(int argc, char *argv[])
{
ftdm_span_t *span;
//m3ua_data_t *data;
ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
if (argc < 5) {
printf("more args needed\n");
exit(-1);
}
if (ftdm_global_init() != FTDM_SUCCESS) {
fprintf(stderr, "Error loading FreeTDM\n");
exit(-1);
}
printf("FreeTDM loaded\n");
if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
fprintf(stderr, "Error finding FreeTDM span\n");
goto done;
}
if (ftdm_m3ua_configure_span(span) == FTDM_SUCCESS) {
//data = span->signal_data;
ftdm_m3ua_start(span);
} else {
fprintf(stderr, "Error starting M3UA\n");
goto done;
}
//while(ftdm_test_flag(data, FTDM_M3UA_RUNNING)) {
// ftdm_sleep(1 * 1000);
//}
done:
ftdm_global_destroy();
}
+112 -32
View File
@@ -2,78 +2,158 @@
#include <signal.h>
#include <stdlib.h>
static int R = 0;
static ftdm_mutex_t *mutex = NULL;
static volatile int running = 0;
static ftdm_mutex_t *the_mutex = NULL;
static ftdm_channel_t *fchan = NULL;
static ftdm_channel_indication_t indication = FTDM_CHANNEL_INDICATE_NONE;
static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
{
int chanid = ftdm_channel_get_ph_id(sigmsg->channel);
ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), chanid);
return FTDM_SUCCESS;
ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), chanid);
switch (sigmsg->event_id) {
case FTDM_SIGEVENT_START:
{
ftdm_mutex_lock(the_mutex);
if (!fchan) {
fchan = sigmsg->channel;
indication = FTDM_CHANNEL_INDICATE_PROCEED;
}
ftdm_mutex_unlock(the_mutex);
}
break;
case FTDM_SIGEVENT_INDICATION_COMPLETED:
{
ftdm_channel_indication_t ind = FTDM_CHANNEL_INDICATE_NONE;
if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROCEED) {
ftdm_log(FTDM_LOG_DEBUG, "Proceed indication result = %d\n", sigmsg->ev_data.indication_completed.status);
ind = FTDM_CHANNEL_INDICATE_PROGRESS;
} else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROGRESS) {
ftdm_log(FTDM_LOG_DEBUG, "Progress indication result = %d\n", sigmsg->ev_data.indication_completed.status);
ind = FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA;
} else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA) {
ftdm_log(FTDM_LOG_DEBUG, "Progress media indication result = %d\n", sigmsg->ev_data.indication_completed.status);
ind = FTDM_CHANNEL_INDICATE_ANSWER;
} else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_ANSWER) {
ftdm_log(FTDM_LOG_DEBUG, "Answer indication result = %d\n", sigmsg->ev_data.indication_completed.status);
} else {
ftdm_log(FTDM_LOG_DEBUG, "Unexpected indication, result = %d\n", sigmsg->ev_data.indication_completed.status);
exit(1);
}
ftdm_mutex_lock(the_mutex);
if (fchan) {
indication = ind;
}
ftdm_mutex_unlock(the_mutex);
}
break;
case FTDM_SIGEVENT_STOP:
{
ftdm_channel_call_hangup(sigmsg->channel);
}
break;
case FTDM_SIGEVENT_RELEASED:
{
ftdm_mutex_lock(the_mutex);
if (fchan && fchan == sigmsg->channel) {
fchan = NULL;
}
ftdm_mutex_unlock(the_mutex);
}
break;
default:
break;
}
return FTDM_SUCCESS;
}
static void handle_SIGINT(int sig)
static void stop_test(int sig)
{
ftdm_mutex_lock(mutex);
R = 0;
ftdm_mutex_unlock(mutex);
return;
running = 0;
}
int main(int argc, char *argv[])
{
ftdm_span_t *span;
ftdm_mutex_create(&mutex);
ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
ftdm_conf_parameter_t parameters[20];
ftdm_mutex_create(&the_mutex);
if (argc < 2) {
printf("umm no\n");
exit(-1);
exit(1);
}
ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
if (ftdm_global_init() != FTDM_SUCCESS) {
fprintf(stderr, "Error loading FreeTDM\n");
exit(-1);
exit(1);
}
ftdm_global_configuration();
printf("FreeTDM loaded\n");
if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
fprintf(stderr, "Error finding FreeTDM span\n");
if (ftdm_span_find_by_name(argv[1], &span) != FTDM_SUCCESS) {
fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]);
goto done;
}
/* testing non-blocking operation */
//ftdm_span_set_blocking_mode(span, FTDM_FALSE);
parameters[0].var = "variant";
parameters[0].val = "br";
if (ftdm_configure_span(span, "r2", on_r2_signal,
"variant", "mx",
"max_ani", 10,
"max_dnis", 4,
"logging", "all",
FTDM_TAG_END) == FTDM_SUCCESS) {
parameters[1].var = "max_ani";
parameters[1].val = "4";
parameters[2].var = "max_dnis";
parameters[2].val = "4";
parameters[3].var = "logging";
parameters[3].val = "all";
parameters[4].var = NULL;
parameters[4].val = NULL;
if (ftdm_configure_span_signaling(span, "r2", on_r2_signal, parameters) == FTDM_SUCCESS) {
ftdm_span_start(span);
} else {
fprintf(stderr, "Error starting R2 span\n");
goto done;
}
signal(SIGINT, handle_SIGINT);
ftdm_mutex_lock(mutex);
R = 1;
ftdm_mutex_unlock(mutex);
while(R) {
ftdm_sleep(1 * 1000);
running = 1;
signal(SIGINT, stop_test);
while(running) {
ftdm_sleep(20);
if (fchan && indication != FTDM_CHANNEL_INDICATE_NONE) {
ftdm_channel_t *lchan = NULL;
ftdm_channel_indication_t ind = FTDM_CHANNEL_INDICATE_NONE;
ftdm_time_t start, stop, diff;
ftdm_mutex_lock(the_mutex);
ind = indication;
indication = FTDM_CHANNEL_INDICATE_NONE;
lchan = fchan;
ftdm_mutex_unlock(the_mutex);
start = ftdm_current_time_in_ms();
ftdm_channel_call_indicate(lchan, ind);
stop = ftdm_current_time_in_ms();
diff = stop - start;
ftdm_log(FTDM_LOG_DEBUG, "Setting indication %s took %llums\n",
ftdm_channel_indication2str(ind), diff);
}
}
done:
done:
ftdm_global_destroy();
return 1;
return 0;
}
/* For Emacs:
+1 -1
View File
@@ -84,7 +84,7 @@ AC_ARG_ENABLE(64,
if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then
if test "${enable_64}" = "yes"; then
CFLAGS="$CFLAGS -m64"
CXXFLAGS="$CXXFLAGS -m64"
CXXFLAGS="$CXXFLAGS -m64 -lgpg-error"
fi
fi
+4 -2
View File
@@ -15,8 +15,6 @@
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
## $Id: Makefile.am,v 1.6 2008/09/30 14:06:39 steveu Exp $
AM_CFLAGS = $(COMP_VENDOR_CFLAGS)
AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS)
@@ -26,6 +24,7 @@ noinst_SCRIPTS = g722_1.spec
MAINTAINERCLEANFILES = Makefile.in
EXTRA_DIST = autogen.sh \
g722_1.pc \
g722_1.spec \
unpack_g722_1_data.sh \
wrapper.xsl \
@@ -50,6 +49,9 @@ SUBDIRS = src $(MAYBE_DOC) $(MAYBE_TESTS)
DIST_SUBDIRS = src doc tests test-data
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = g722_1.pc
faq: faq.xml
cd faq ; xsltproc ../wrapper.xsl ../faq.xml
-5
View File
@@ -16,11 +16,6 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id: autogen.sh,v 1.1.1.1 2008/09/20 09:47:17 steveu Exp $
#
UNAME=`uname`
if [ "x$UNAME" = "xFreeBSD" ]; then
echo ""
+21 -15
View File
@@ -15,17 +15,11 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id: configure.ac,v 1.9 2008/10/09 14:17:12 steveu Exp $
# @start 1
AC_INIT
CFLAGS="$CFLAGS $CONFIGURE_CFLAGS"
CXXFLAGS="$CXXFLAGS $CONFIGURE_CXXFLAGS"
LDFLAGS="$LDFLAGS $CONFIGURE_LDFLAGS"
m4_include(config/ax_compiler_vendor.m4)
m4_include(config/ax_check_real_file.m4)
m4_include(config/ax_fixed_point_machine.m4)
@@ -111,6 +105,22 @@ else
CXXFLAGS=${CXXFLAGS-"-g -O2"}
fi
AC_DEFUN([REMOVE_FROM_VAR],[
new_val=""
removed=0
for i in $$1; do
if test "x$i" != "x$2"; then
new_val="$new_val $i"
else
removed=1
fi
done
if test $removed = "1"; then
echo " removed \"$2\" from $1"
$1=$new_val
fi
])
AC_C_CONST
AC_C_INLINE
AC_C_VOLATILE
@@ -190,7 +200,7 @@ AC_CHECK_HEADERS([audiofile.h])
AC_LANG([C])
if test "${build}" = "${host}"
if test "${build}" == "${host}"
then
case "${host}" in
x86_64-*)
@@ -270,6 +280,7 @@ sun)
COMP_VENDOR_CFLAGS="-native -fast $COMP_VENDOR_CFLAGS"
fi
COMP_VENDOR_LDFLAGS=
REMOVE_FROM_VAR(CFLAGS, -Xc)
;;
*)
COMP_VENDOR_CFLAGS="-std=c99 -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes"
@@ -293,20 +304,14 @@ AM_CONDITIONAL([COND_SSE5], [test "$enable_sse5" = yes])
if test "$enable_fixed_point" = "yes" ; then
AC_DEFINE([G722_1_USE_FIXED_POINT], [1], [Enable fixed point processing, where possible, instead of floating point])
G722_1_USE_FIXED_POINT="#define G722_1_USE_FIXED_POINT 1"
fixed = "yes"
G722_1_VECTORS_FOR_TESTS="fixed"
else
AX_FIXED_POINT_MACHINE([$host],
[
AC_DEFINE([G722_1_USE_FIXED_POINT], [1], [Enable fixed point processing, where possible, instead of floating point])
G722_1_USE_FIXED_POINT="#define G722_1_USE_FIXED_POINT 1"
fixed = "yes"
],
[AC_DEFINE([G722_1_USE_FIXED_POINT], [1], [Enable fixed point processing, where possible, instead of floating point])
G722_1_USE_FIXED_POINT="#define G722_1_USE_FIXED_POINT 1"],
[G722_1_USE_FIXED_POINT="#undef G722_1_USE_FIXED_POINT"])
G722_1_VECTORS_FOR_TESTS="floating"
fi
AM_CONDITIONAL([COND_FIXED], [test "$fixed" = "yes"])
AX_MISALIGNED_ACCESS_FAILS([$host],
[AC_DEFINE([G722_1_MISALIGNED_ACCESS_FAILS], [1], [Do not expect a misaligned memory access to work correctly])
G722_1_MISALIGNED_ACCESS_FAILS="#define G722_1_MISALIGNED_ACCESS_FAILS 1"],
@@ -363,6 +368,7 @@ AC_CONFIG_FILES([Makefile
src/Makefile
src/g722_1.h
tests/Makefile
g722_1.pc
g722_1.spec])
AC_CONFIG_FILES([tests/regression_tests.sh], [chmod +x tests/regression_tests.sh])
-2
View File
@@ -15,8 +15,6 @@
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
## $Id: Makefile.am,v 1.1.1.1 2008/09/20 09:47:17 steveu Exp $
MAINTAINERCLEANFILES = Makefile.in
+11
View File
@@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: spandsp
Description: A library for the ITU G.722.1 and G.722.1C audio codecs.
Requires:
Version: @VERSION@
Libs: -L${libdir} -lg722_1 -lm
Cflags: -I${includedir}
+1 -2
View File
@@ -47,14 +47,13 @@ rm -rf %{buildroot}
%{_libdir}/libg722_1.so.*
%{_datadir}/libg722_1
%files devel
%defattr(-,root,root,-)
%doc doc/api
%{_includedir}/g722_1.h
%{_includedir}/g722_1
%{_libdir}/libg722_1.so
%{_libdir}/pkgconfig/g722_1.pc
%post -p /sbin/ldconfig
+49 -30
View File
@@ -15,18 +15,19 @@
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
## $Id: Makefile.am,v 1.10 2008/10/16 15:46:12 steveu Exp $
AM_CFLAGS = $(COMP_VENDOR_CFLAGS)
AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS)
MAINTAINERCLEANFILES = Makefile.in
EXTRA_DIST = g722_1/version.h.in \
EXTRA_DIST = make_tables.c \
g722_1/version.h.in \
libg722_1.dsp \
libg722_1.sln \
libg722_1.vcproj \
libg722_1.2005.sln \
libg722_1.2008.sln \
libg722_1.2005.vcproj \
libg722_1.2008.vcproj \
msvc/gettimeofday.c \
msvc/inttypes.h \
msvc/tgmath.h \
@@ -36,13 +37,16 @@ EXTRA_DIST = g722_1/version.h.in \
msvc/msvcproj.head \
msvc/msvcproj.foot \
msvc/vc8proj.head \
msvc/vc8proj.foot
msvc/vc8proj.foot \
msvc/vc9proj.head \
msvc/vc9proj.foot
INCLUDES = -I$(top_builddir)
lib_LTLIBRARIES = libg722_1.la
libg722_1_la_SOURCES = bitstream.c \
libg722_1_la_SOURCES = basop32.c \
bitstream.c \
coef2sam.c \
common.c \
commonf.c \
@@ -55,11 +59,9 @@ libg722_1_la_SOURCES = bitstream.c \
encoderf.c \
huff_tab.c \
sam2coef.c \
tables.c
tables.c \
utilities.c
if COND_FIXED
libg722_1_la_SOURCES += basop32.c
endif
libg722_1_la_LDFLAGS = -version-info @G722_1_LT_CURRENT@:@G722_1_LT_REVISION@:@G722_1_LT_AGE@ $(COMP_VENDOR_LDFLAGS)
nobase_include_HEADERS = g722_1/g722_1.h \
@@ -76,10 +78,10 @@ noinst_HEADERS = basop32.h \
defs.h \
huff_tab.h \
sam2coef.h \
tables.h
tables.h \
utilities.h
noinst_PROGRAMS = make_dct4_tables \
make_tables
noinst_PROGRAMS = make_dct4_tables
dct4.$(OBJEXT): dct4.h
@@ -88,6 +90,9 @@ dct4.lo: dct4.h
dct4.h: make_dct4_tables$(EXEEXT)
./make_dct4_tables$(EXEEXT) >dct4.h
make_dct4_tables$(EXEEXT): $(top_srcdir)/src/make_dct4_tables.c
$(CC_FOR_BUILD) -o make_dct4_tables$(EXEEXT) $(top_srcdir)/src/make_dct4_tables.c -DHAVE_CONFIG_H -I$(top_builddir)/src -lm
#coef2sam.h: make_tables$(EXEEXT)
# ./make_tables$(EXEEXT) coef2sam >coef2samx.h
@@ -95,13 +100,15 @@ dct4.h: make_dct4_tables$(EXEEXT)
# ./make_tables$(EXEEXT) sam2coef >sam2coefx.h
DSP = libg722_1.dsp
VCPROJ = libg722_1.vcproj
VCPROJ8 = libg722_1.2005.vcproj
VCPROJ9 = libg722_1.2008.vcproj
WIN32SOURCES = $(libg722_1_la_SOURCES) msvc/gettimeofday.c
WIN32HEADERS = $(nobase_include_HEADERS) g722_1.h
DSPOUT = | awk '{printf("%s\r\n", $$0)}' >> $(DSP)
VCPROJOUT = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ)
VCPROJOUT8 = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ8)
VCPROJOUT9 = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ9)
$(DSP): msvc/msvcproj.head msvc/msvcproj.foot Makefile.am
echo "creating $(DSP)"
@@ -124,26 +131,38 @@ $(DSP): msvc/msvcproj.head msvc/msvcproj.foot Makefile.am
echo "# End Group" $(DSPOUT); \
cat $(srcdir)/msvc/msvcproj.foot $(DSPOUT) )
$(VCPROJ): msvc/vc8proj.head msvc/vc8proj.foot Makefile.am
echo "creating $(VCPROJ)"
@(cp $(srcdir)/msvc/vc8proj.head $(VCPROJ); \
$(VCPROJ8): msvc/vc8proj.head msvc/vc8proj.foot Makefile.am
echo "creating $(VCPROJ8)"
@(cp $(srcdir)/msvc/vc8proj.head $(VCPROJ8); \
for file in $(WIN32SOURCES); do \
echo "<File RelativePath=\""$$file"\"></File>" $(VCPROJOUT); \
myfile=`echo $$file | sed -e 's|/|\\\\|g'`; \
echo "<File RelativePath=\""$$myfile"\"></File>" $(VCPROJOUT8); \
done; \
echo "</Filter><Filter Name=\"Header Files\">" $(VCPROJOUT); \
echo "</Filter><Filter Name=\"Header Files\">" $(VCPROJOUT8); \
for file in $(WIN32HEADERS); do \
echo "<File RelativePath=\""$$file"\"></File>" $(VCPROJOUT); \
myfile=`echo $$file | sed -e 's|/|\\\\|g'`; \
echo "<File RelativePath=\""$$myfile"\"></File>" $(VCPROJOUT8); \
done; \
cat $(srcdir)/msvc/vc8proj.foot $(VCPROJOUT) )
cat $(srcdir)/msvc/vc8proj.foot $(VCPROJOUT8) )
$(VCPROJ9): msvc/vc9proj.head msvc/vc9proj.foot Makefile.am
echo "creating $(VCPROJ9)"
@(cp $(srcdir)/msvc/vc9proj.head $(VCPROJ9); \
for file in $(WIN32SOURCES); do \
myfile=`echo $$file | sed -e 's|/|\\\\|g'`; \
echo "<File RelativePath=\""$$myfile"\"></File>" $(VCPROJOUT9); \
done; \
echo "</Filter><Filter Name=\"Header Files\">" $(VCPROJOUT9); \
for file in $(WIN32HEADERS); do \
myfile=`echo $$file | sed -e 's|/|\\\\|g'`; \
echo "<File RelativePath=\""$$myfile"\"></File>" $(VCPROJOUT9); \
done; \
cat $(srcdir)/msvc/vc9proj.foot $(VCPROJOUT9) )
dist-hook: g722_1/version.h
g722_1/version.h:
NOWDATE=`date --utc +"%Y%m%d"` ; \
NOWTIME=`date --utc +"%H%M%S"` ; \
sed 's/$$G722_1_RELEASE_DATE/'$$NOWDATE'/;s/$$G722_1_RELEASE_TIME/'$$NOWTIME'/' \
<g722_1/version.h.in >g722_1/version.h
dist-hook:
NOWDATE=`date --utc +"%Y%m%d"` ; \
NOWTIME=`date --utc +"%H%M%S"` ; \
sed 's/$$G722_1_RELEASE_DATE/'$$NOWDATE'/;s/$$G722_1_RELEASE_TIME/'$$NOWTIME'/' \
<g722_1/version.h.in >g722_1/version.h
<$(srcdir)/g722_1/version.h.in >$@
+2 -3
View File
@@ -9,8 +9,6 @@
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: basop32.c,v 1.5 2008/09/22 13:08:31 steveu Exp $
*/
/*! \file */
@@ -19,9 +17,10 @@
#include <config.h>
#endif
#include <inttypes.h>
#if defined(G722_1_USE_FIXED_POINT)
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
+9 -11
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: basop32.h,v 1.3 2008/09/22 13:08:31 steveu Exp $
*/
#if !defined(BASOP32_H_DEFINED)
@@ -104,14 +102,14 @@ static __inline__ int32_t L_mac(int32_t L_var3, int16_t var1, int16_t var2)
}
/*- End of function --------------------------------------------------------*/
int16_t shl(int16_t var1, int16_t var2); /* Short shift left, 1 */
int16_t shr(int16_t var1, int16_t var2); /* Short shift right, 1 */
int32_t L_sub(int32_t L_var1, int32_t L_var2); /* Long sub, 2 */
int32_t L_shl(int32_t L_var1, int16_t var2); /* Long shift left, 2 */
int32_t L_shr(int32_t L_var1, int16_t var2); /* Long shift right, 2*/
int16_t norm_s(int16_t var1); /* Short norm, 15 */
int16_t div_s(int16_t var1, int16_t var2); /* Short division, 18 */
int16_t norm_l(int32_t L_var1); /* Long norm, 30 */
int16_t shl(int16_t var1, int16_t var2); /* Short shift left, 1 */
int16_t shr(int16_t var1, int16_t var2); /* Short shift right, 1 */
int32_t L_sub(int32_t L_var1, int32_t L_var2); /* Long sub, 2 */
int32_t L_shl(int32_t L_var1, int16_t var2); /* Long shift left, 2 */
int32_t L_shr(int32_t L_var1, int16_t var2); /* Long shift right, 2 */
int16_t norm_s(int16_t var1); /* Short norm, 15 */
int16_t div_s(int16_t var1, int16_t var2); /* Short division, 18 */
int16_t norm_l(int32_t L_var1); /* Long norm, 30 */
#endif
-2
View File
@@ -8,8 +8,6 @@
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: bitstream.c,v 1.2 2008/10/17 13:18:21 steveu Exp $
*/
/*! \file */
-2
View File
@@ -8,8 +8,6 @@
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: bitstream.h,v 1.2 2008/10/17 13:18:21 steveu Exp $
*/
/*! \file */
+15 -29
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: coef2sam.c,v 1.10 2008/10/02 11:43:54 steveu Exp $
*/
/*! \file */
@@ -29,18 +27,16 @@
#include "defs.h"
#include "coef2sam.h"
#include "utilities.h"
/*************************************************************************************
/* Convert Reversed MLT (Modulated Lapped Transform) Coefficients to Samples
Purpose: Convert Reversed MLT (Modulated Lapped Transform) Coefficients to Samples
The "Reversed MLT" is an overlapped block transform which uses even symmetry
on the left, odd symmetry on the right and a Type IV DCT as the block transform.
It is thus similar to a MLT which uses odd symmetry on the left, even symmetry
on the right and a Type IV DST as the block transform. In fact, it is equivalent
to reversing the order of the samples, performing an MLT and then negating all
the even-numbered coefficients.
***************************************************************************/
The "Reversed MLT" is an overlapped block transform which uses even symmetry
on the left, odd symmetry on the right and a Type IV DCT as the block transform.
It is thus similar to a MLT which uses odd symmetry on the left, even symmetry
on the right and a Type IV DST as the block transform. In fact, it is equivalent
to reversing the order of the samples, performing an MLT and then negating all
the even-numbered coefficients. */
#if defined(G722_1_USE_FIXED_POINT)
void rmlt_coefs_to_samples(int16_t coefs[],
@@ -73,29 +69,23 @@ void rmlt_coefs_to_samples(int16_t coefs[],
new_samples[i] = shl(new_samples[i], mag_shift);
}
if (dct_length == DCT_LENGTH)
win = rmlt_to_samples_window;
else
win = max_rmlt_to_samples_window;
win = (dct_length == DCT_LENGTH) ? rmlt_to_samples_window : max_rmlt_to_samples_window;
last = half_dct_length - 1;
for (i = 0; i < half_dct_length; i++)
{
/* Get the first half of the windowed samples */
sum = 0L;
sum = L_mac(sum, win[i], new_samples[last - i]);
sum = L_mult(win[i], new_samples[last - i]);
sum = L_mac(sum, win[dct_length - i - 1], old_samples[i]);
out_samples[i] = xround(L_shl(sum, 2));
/* Get the second half of the windowed samples */
sum = 0L;
sum = L_mac(sum, win[half_dct_length + i], new_samples[i]);
sum = L_mult(win[half_dct_length + i], new_samples[i]);
sum = L_mac(sum, negate(win[last - i]), old_samples[last - i]);
out_samples[half_dct_length + i] = xround(L_shl(sum, 2));
}
/* Save the second half of the new samples for
next time, when they will be the old samples. */
for (i = 0; i < half_dct_length; i++)
old_samples[i] = new_samples[half_dct_length + i];
vec_copyi16(old_samples, &new_samples[half_dct_length], half_dct_length);
}
/*- End of function --------------------------------------------------------*/
#else
@@ -116,10 +106,7 @@ void rmlt_coefs_to_samples(float coefs[],
/* Perform a Type IV (inverse) DCT on the coefficients */
dct_type_iv(coefs, new_samples, dct_length);
if (dct_length == DCT_LENGTH)
win = rmlt_to_samples_window;
else
win = max_rmlt_to_samples_window;
win = (dct_length == DCT_LENGTH) ? rmlt_to_samples_window : max_rmlt_to_samples_window;
last = half_dct_length - 1;
for (i = 0; i < half_dct_length; i++)
{
@@ -135,8 +122,7 @@ void rmlt_coefs_to_samples(float coefs[],
/* Save the second half of the new samples for next time, when they will
be the old samples. */
for (i = 0; i < half_dct_length; i++)
old_samples[i] = new_samples[half_dct_length + i];
vec_copyf(old_samples, &new_samples[half_dct_length], half_dct_length);
}
/*- End of function --------------------------------------------------------*/
#endif
+1 -3
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: coef2sam.h,v 1.2 2008/10/02 11:43:54 steveu Exp $
*/
#if defined(G722_1_USE_FIXED_POINT)
+13 -149
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: common.c,v 1.6 2008/09/30 14:06:39 steveu Exp $
*/
/*! \file */
@@ -38,41 +36,7 @@ static void compute_raw_pow_categories(int16_t *power_categories,
int16_t number_of_regions,
int16_t offset);
/****************************************************************************************
Function: categorize
Syntax: void categorize(int16_t number_of_available_bits,
int16_t number_of_regions,
int16_t num_categorization_control_possibilities,
int16_t rms_index,
int16_t power_categories,
int16_t category_balances)
inputs: number_of_regions
num_categorization_control_possibilities
number_of_available_bits
rms_index[MAX_NUMBER_OF_REGIONS]
outputs: power_categories[MAX_NUMBER_OF_REGIONS]
category_balances[MAX_NUM_CATEGORIZATION_CONTROL_POSSIBILITIES-1]
Description: Computes a series of categorizations
WMOPS: 7kHz | 24kbit | 32kbit
-------|--------------|----------------
AVG | 0.14 | 0.14
-------|--------------|----------------
MAX | 0.15 | 0.15
-------|--------------|----------------
14kHz | 24kbit | 32kbit | 48kbit
-------|--------------|----------------|----------------
AVG | 0.42 | 0.45 | 0.48
-------|--------------|----------------|----------------
MAX | 0.47 | 0.52 | 0.52
-------|--------------|----------------|----------------
****************************************************************************************/
/* Compute a series of categorizations */
void categorize(int16_t number_of_available_bits,
int16_t number_of_regions,
int16_t num_categorization_control_possibilities,
@@ -88,10 +52,7 @@ void categorize(int16_t number_of_available_bits,
/* At higher bit rates, there is an increase for most categories in average bit
consumption per region. We compensate for this by pretending we have fewer
available bits. */
if (number_of_regions == NUMBER_OF_REGIONS)
frame_size = DCT_LENGTH;
else
frame_size = MAX_DCT_LENGTH;
frame_size = (number_of_regions == NUMBER_OF_REGIONS) ? DCT_LENGTH : MAX_DCT_LENGTH;
temp = sub(number_of_available_bits, frame_size);
if (temp > 0)
@@ -114,45 +75,7 @@ void categorize(int16_t number_of_available_bits,
}
/*- End of function --------------------------------------------------------*/
/***************************************************************************
Function: comp_powercat_and_catbalance
Syntax: void comp_powercat_and_catbalance(int16_t *power_categories,
int16_t *category_balances,
int16_t *rms_index,
int16_t number_of_available_bits,
int16_t number_of_regions,
int16_t num_categorization_control_possibilities,
int16_t offset)
inputs: *rms_index
number_of_available_bits
number_of_regions
num_categorization_control_possibilities
offset
outputs: *power_categories
*category_balances
Description: Computes the power_categories and the category balances
WMOPS: 7kHz | 24kbit | 32kbit
-------|--------------|----------------
AVG | 0.10 | 0.10
-------|--------------|----------------
MAX | 0.11 | 0.11
-------|--------------|----------------
14kHz | 24kbit | 32kbit | 48kbit
-------|--------------|----------------|----------------
AVG | 0.32 | 0.35 | 0.38
-------|--------------|----------------|----------------
MAX | 0.38 | 0.42 | 0.43
-------|--------------|----------------|----------------
***************************************************************************/
/* Compute the power_categories and the category balances */
void comp_powercat_and_catbalance(int16_t *power_categories,
int16_t *category_balances,
int16_t *rms_index,
@@ -161,7 +84,6 @@ void comp_powercat_and_catbalance(int16_t *power_categories,
int16_t num_categorization_control_possibilities,
int16_t offset)
{
int16_t expected_number_of_code_bits;
int16_t region;
int16_t max_region;
@@ -190,7 +112,6 @@ void comp_powercat_and_catbalance(int16_t *power_categories,
for (region = 0; region < number_of_regions; region++)
expected_number_of_code_bits = add(expected_number_of_code_bits, expected_bits_table[power_categories[region]]);
for (region = 0; region < number_of_regions; region++)
{
max_rate_categories[region] = power_categories[region];
@@ -277,42 +198,16 @@ void comp_powercat_and_catbalance(int16_t *power_categories,
}
/*- End of function --------------------------------------------------------*/
/***************************************************************************
Function: calc_offset
Syntax: offset=calc_offset(int16_t *rms_index,int16_t number_of_regions,int16_t available_bits)
input: int16_t *rms_index
int16_t number_of_regions
int16_t available_bits
output: int16_t offset
Description: Calculates the the category offset. This is the shift required
To get the most out of the number of available bits. A binary
type search is used to find the offset.
WMOPS: 7kHz | 24kbit | 32kbit
-------|--------------|----------------
AVG | 0.04 | 0.04
-------|--------------|----------------
MAX | 0.04 | 0.04
-------|--------------|----------------
14kHz | 24kbit | 32kbit | 48kbit
-------|--------------|----------------|----------------
AVG | 0.08 | 0.08 | 0.08
-------|--------------|----------------|----------------
MAX | 0.09 | 0.09 | 0.09
-------|--------------|----------------|----------------
***************************************************************************/
int16_t calc_offset(int16_t *rms_index,int16_t number_of_regions,int16_t available_bits)
/* Calculate the the category offset. This is the shift required
To get the most out of the number of available bits. A binary
type search is used to find the offset. */
int16_t calc_offset(int16_t *rms_index, int16_t number_of_regions, int16_t available_bits)
{
int16_t answer;
int16_t delta;
int16_t test_offset;
int16_t region,j;
int16_t region;
int16_t j;
int16_t power_cats[MAX_NUMBER_OF_REGIONS];
int16_t bits;
int16_t offset;
@@ -360,40 +255,9 @@ int16_t calc_offset(int16_t *rms_index,int16_t number_of_regions,int16_t availab
}
/*- End of function --------------------------------------------------------*/
/***************************************************************************
Function: compute_raw_pow_categories
Syntax: void compute_raw_pow_categories(int16_t *power_categories,
int16_t *rms_index,
int16_t number_of_regions,
int16_t offset)
inputs: *rms_index
number_of_regions
offset
outputs: *power_categories
Description: This function computes the power categories given the offset
This is kind of redundant since they were already computed
in calc_offset to determine the offset.
WMOPS: | 24kbit | 32kbit
-------|--------------|----------------
AVG | 0.01 | 0.01
-------|--------------|----------------
MAX | 0.01 | 0.01
-------|--------------|----------------
14kHz | 24kbit | 32kbit | 48kbit
-------|--------------|----------------|----------------
AVG | 0.01 | 0.01 | 0.01
-------|--------------|----------------|----------------
MAX | 0.01 | 0.01 | 0.01
-------|--------------|----------------|----------------
***************************************************************************/
/* Compute the power categories given the offset
This is kind of redundant since they were already computed
in calc_offset to determine the offset. */
static void compute_raw_pow_categories(int16_t *power_categories, int16_t *rms_index, int16_t number_of_regions, int16_t offset)
{
int16_t region;
+2 -6
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: commonf.c,v 1.11 2008/09/30 14:06:39 steveu Exp $
*/
/*! \file */
@@ -34,9 +32,7 @@
#if !defined(G722_1_USE_FIXED_POINT)
/****************************************************************************************
Description: Computes a series of categorizations
****************************************************************************************/
/* Compute a series of categorizations */
void categorize(int number_of_regions,
int number_of_available_bits,
int rms_index[MAX_NUMBER_OF_REGIONS],
+26 -46
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C)2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: dct4.c,v 1.8 2008/09/29 16:09:26 steveu Exp $
*/
#if defined(HAVE_CONFIG_H)
@@ -29,6 +27,7 @@
#include "g722_1/g722_1.h"
#include "defs.h"
#include "utilities.h"
#if !defined(G722_1_USE_FIXED_POINT)
@@ -52,9 +51,7 @@ static const cos_msin_t *cos_msin_table[] =
cos_msin_640
};
/*********************************************************************************
Description: Discrete Cosine Transform, Type IV
*********************************************************************************/
/* Discrete Cosine Transform, Type IV */
void dct_type_iv(float input[], float output[], int dct_length)
{
float buffer_a[MAX_DCT_LENGTH];
@@ -64,22 +61,20 @@ void dct_type_iv(float input[], float output[], int dct_length)
float *in_ptr_low;
float *in_ptr_high;
float *next_in_base;
float *out_ptr_low;
float *out_ptr_high;
float *out_ptr;
float *next_out_base;
float *out_buffer;
float *in_buffer;
float *buffer_swap;
float *fptr0;
const float *fptr2;
const float *core_a;
float in_val_low;
float in_val_high;
float cos_even;
float cos_odd;
float msin_even;
float msin_odd;
float sum;
const float *fptr2;
const float *core_a;
const cos_msin_t **table_ptr_ptr;
const cos_msin_t *cos_msin_ptr;
int set_span;
@@ -120,29 +115,24 @@ void dct_type_iv(float input[], float output[], int dct_length)
for (sets_left = set_count; sets_left > 0; sets_left--)
{
/* Set up output pointers for the current set */
out_ptr_low = next_out_base;
out_ptr = next_out_base;
next_out_base += set_span;
out_ptr_high = next_out_base;
/* Loop over all the butterflies in the current set */
do
for (i = 0; i < (set_span >> 1); i++)
{
in_val_low = *in_ptr++;
in_val_high = *in_ptr++;
*out_ptr_low++ = in_val_low + in_val_high;
*--out_ptr_high = in_val_low - in_val_high;
out_ptr[i] = in_val_low + in_val_high;
out_ptr[set_span - 1 - i] = in_val_low - in_val_high;
}
while (out_ptr_low < out_ptr_high);
}
/* Decide which buffers to use as input and output next time.
Except for the first time (when the input buffer is the
subroutine input) we just alternate the local buffers. */
in_buffer = out_buffer;
if (out_buffer == buffer_a)
out_buffer = buffer_b;
else
out_buffer = buffer_a;
out_buffer = (out_buffer == buffer_a) ? buffer_b : buffer_a;
}
/* Do dct_size/10 ten-point transforms */
@@ -153,11 +143,8 @@ void dct_type_iv(float input[], float output[], int dct_length)
fptr2 = core_a;
for (k = 0; k < CORE_SIZE; k++)
{
sum = 0;
for (i = 0; i < CORE_SIZE; i++)
sum += fptr0[i]*fptr2[i];
buffer_swap[k] = vec_dot_prodf(fptr0, fptr2, CORE_SIZE);
fptr2 += CORE_SIZE;
buffer_swap[k] = sum;
}
fptr0 += CORE_SIZE;
buffer_swap += CORE_SIZE;
@@ -172,14 +159,10 @@ void dct_type_iv(float input[], float output[], int dct_length)
{
/* Initialization for the loop over sets at the current size */
set_span = dct_length >> set_count_log;
set_count = 1 << set_count_log;
next_in_base = in_buffer;
if (set_count_log == 0)
next_out_base = output;
else
next_out_base = out_buffer;
++table_ptr_ptr;
next_out_base = (set_count_log == 0) ? output : out_buffer;
table_ptr_ptr++;
/* Loop over all the sets of this size */
for (sets_left = set_count; sets_left > 0; sets_left--)
@@ -187,26 +170,23 @@ void dct_type_iv(float input[], float output[], int dct_length)
/* Set up the pointers for the current set */
in_ptr_low = next_in_base;
in_ptr_high = in_ptr_low + (set_span >> 1);
next_in_base += set_span;
out_ptr_low = next_out_base;
next_out_base += set_span;
out_ptr_high = next_out_base;
out_ptr = next_out_base;
cos_msin_ptr = *table_ptr_ptr;
/* Loop over all the butterfly pairs in the current set */
do
for (i = 0; i < (set_span >> 1); i += 2)
{
cos_even = (*cos_msin_ptr).cosine;
msin_even = (*cos_msin_ptr++).minus_sine;
*out_ptr_low++ = cos_even * *in_ptr_low - msin_even * *in_ptr_high;
*--out_ptr_high = msin_even * *in_ptr_low++ + cos_even * *in_ptr_high++;
cos_odd = (*cos_msin_ptr).cosine;
msin_odd = (*cos_msin_ptr++).minus_sine;
*out_ptr_low++ = cos_odd * *in_ptr_low + msin_odd * *in_ptr_high;
*--out_ptr_high = msin_odd * *in_ptr_low++ - cos_odd * *in_ptr_high++;
cos_even = cos_msin_ptr[i].cosine;
msin_even = cos_msin_ptr[i].minus_sine;
cos_odd = cos_msin_ptr[i + 1].cosine;
msin_odd = cos_msin_ptr[i + 1].minus_sine;
out_ptr[i] = cos_even*in_ptr_low[i] - msin_even*in_ptr_high[i];
out_ptr[set_span - 1 - i] = msin_even*in_ptr_low[i] + cos_even*in_ptr_high[i];
out_ptr[i + 1] = cos_odd*in_ptr_low[i + 1] + msin_odd*in_ptr_high[i + 1];
out_ptr[set_span - 2 - i] = msin_odd*in_ptr_low[i + 1] - cos_odd*in_ptr_high[i + 1];
}
while (out_ptr_low < out_ptr_high);
next_in_base += set_span;
next_out_base += set_span;
}
/* Swap input and output buffers for next time */
+68 -136
View File
@@ -6,29 +6,23 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: dct4_a.c,v 1.8 2008/09/30 14:06:39 steveu Exp $
*/
/*********************************************************************************
* Filename: dct_type_iv_a.c
*
* Purpose: Discrete Cosine Transform, Type IV used for MLT
*
* The basis functions are
*
* cos(PI*(t+0.5)*(k+0.5)/block_length)
*
* for time t and basis function number k. Due to the symmetry of the expression
* in t and k, it is clear that the forward and inverse transforms are the same.
*
*********************************************************************************/
/* Discrete Cosine Transform, Type IV used for MLT
The basis functions are
cos(PI*(t+0.5)*(k+0.5)/block_length)
for time t and basis function number k. Due to the symmetry of the
expression in t and k, it is clear that the forward and inverse transforms
are the same. */
/*! \file */
@@ -47,51 +41,31 @@
#include "dct4_a.h"
/*********************************************************************************
Function: dct_type_iv_a
Syntax: void dct_type_iv_a (input, output, dct_length)
int16_t input[], output[], dct_length;
Description: Discrete Cosine Transform, Type IV used for MLT
*********************************************************************************/
/* Discrete Cosine Transform, Type IV used for MLT */
void dct_type_iv_a(int16_t input[], int16_t output[], int dct_length)
{
int16_t buffer_a[MAX_DCT_LENGTH];
int16_t buffer_b[MAX_DCT_LENGTH];
int16_t buffer_c[MAX_DCT_LENGTH];
int16_t *in_ptr;
int16_t *in_ptr_low;
int16_t *in_ptr_high;
int16_t *next_in_base;
int16_t *out_ptr_low;
int16_t *out_ptr_high;
int16_t *next_out_base;
int16_t *out_buffer;
int16_t *out_ptr;
int16_t *in_buffer;
int16_t *out_buffer;
int16_t *buffer_swap;
int16_t in_val_low;
int16_t in_val_high;
int16_t out_val_low;
int16_t out_val_high;
int16_t in_low_even;
int16_t in_low_odd;
int16_t in_high_even;
int16_t in_high_odd;
int16_t out_low_even;
int16_t out_low_odd;
int16_t out_high_even;
int16_t out_high_odd;
int16_t *pair_ptr;
int16_t cos_even;
int16_t cos_odd;
int16_t msin_even;
int16_t msin_odd;
int16_t neg_cos_odd;
int16_t neg_msin_even;
int32_t sum;
int16_t set_span;
int16_t half_span;
int16_t set_count;
int16_t set_count_log;
int16_t pairs_left;
@@ -99,15 +73,15 @@ void dct_type_iv_a(int16_t input[], int16_t output[], int dct_length)
int16_t i;
int16_t k;
int16_t index;
const cos_msin_t **table_ptr_ptr;
const cos_msin_t *cos_msin_ptr;
int16_t temp;
int32_t acca;
int16_t dct_length_log;
const cos_msin_t **table_ptr_ptr;
const cos_msin_t *cos_msin_ptr;
/* Do the sum/difference butterflies, the first part of */
/* converting one N-point transform into N/2 two-point */
/* transforms, where N = 1 << DCT_LENGTH_LOG. = 64/128 */
/* Do the sum/difference butterflies, the first part of
converting one N-point transform into N/2 two-point
transforms, where N = 1 << DCT_LENGTH_LOG. = 64/128 */
if (dct_length == DCT_LENGTH)
{
dct_length_log = DCT_LENGTH_LOG;
@@ -123,62 +97,45 @@ void dct_type_iv_a(int16_t input[], int16_t output[], int dct_length)
index = 0L;
in_buffer = input;
out_buffer = buffer_a;
temp = sub(dct_length_log, 2);
temp = dct_length_log - 2;
for (set_count_log = 0; set_count_log <= temp; set_count_log++)
{
/* Initialization for the loop over sets at the current size */
/* set_span = 1 << (DCT_LENGTH_LOG - set_count_log); */
set_span = shr(dct_length, set_count_log);
set_count = shl(1, set_count_log);
/* Loop over all the sets at the current size */
set_span = dct_length >> set_count_log;
set_count = 1 << set_count_log;
half_span = set_span >> 1;
in_ptr = in_buffer;
next_out_base = out_buffer;
out_ptr = out_buffer;
/* Loop over all the sets of this size */
for (sets_left = set_count; sets_left > 0; sets_left--)
{
/* Set up output pointers for the current set */
out_ptr_low = next_out_base;
next_out_base = next_out_base + set_span;
out_ptr_high = next_out_base;
/* Loop over all the butterflies in the current set */
do
for (i = 0; i < half_span; i++)
{
in_val_low = *in_ptr++;
in_val_high = *in_ptr++;
acca = L_add(in_val_low, in_val_high);
acca = L_shr(acca, 1);
out_val_low = (int16_t) acca;
in_val_low = *in_ptr++;
in_val_high = *in_ptr++;
acca = L_sub(in_val_low, in_val_high);
acca = L_shr(acca, 1);
out_val_high = (int16_t) acca;
acca = L_add(in_val_low, in_val_high);
out_ptr[i] = (int16_t) L_shr(acca, 1);
*out_ptr_low++ = out_val_low;
*--out_ptr_high = out_val_high;
acca = L_sub(in_val_low, in_val_high);
out_ptr[set_span - 1 - i] = (int16_t) L_shr(acca, 1);
}
while (out_ptr_low < out_ptr_high);
out_ptr += set_span;
}
/* Decide which buffers to use as input and output next time. */
/* Except for the first time (when the input buffer is the */
/* subroutine input) we just alternate the local buffers. */
/* Decide which buffers to use as input and output next time.
Except for the first time (when the input buffer is the
subroutine input) we just alternate the local buffers. */
in_buffer = out_buffer;
if (out_buffer == buffer_a)
out_buffer = buffer_b;
else
out_buffer = buffer_a;
out_buffer = (out_buffer == buffer_a) ? buffer_b : buffer_a;
index = add(index, 1);
}
/* Do N/2 two-point transforms, */
/* where N = 1 << DCT_LENGTH_LOG */
/* Do N/2 two-point transforms, where N = 1 << DCT_LENGTH_LOG */
pair_ptr = in_buffer;
buffer_swap = buffer_c;
temp = sub(dct_length_log, 1);
temp = shl(1, temp);
temp = 1 << (dct_length_log - 1);
for (pairs_left = temp; pairs_left > 0; pairs_left--)
{
for (k = 0; k < CORE_SIZE; k++)
@@ -188,7 +145,6 @@ void dct_type_iv_a(int16_t input[], int16_t output[], int dct_length)
sum = L_mac(sum, pair_ptr[i], dct_core_a[i][k]);
buffer_swap[k] = xround(sum);
}
/* Address arithmetic */
pair_ptr += CORE_SIZE;
buffer_swap += CORE_SIZE;
}
@@ -202,77 +158,53 @@ void dct_type_iv_a(int16_t input[], int16_t output[], int dct_length)
temp = sub(dct_length_log, 2);
for (set_count_log = temp; set_count_log >= 0; set_count_log--)
{
/* Initialization for the loop over sets at the current size */
/* set_span = 1 << (DCT_LENGTH_LOG - set_count_log); */
set_span = shr(dct_length, set_count_log);
set_count = shl(1, set_count_log);
next_in_base = in_buffer;
next_out_base = (set_count_log == 0) ? output : out_buffer;
/* Loop over all the sets at the current size */
set_span = dct_length >> set_count_log;
set_count = 1 << set_count_log;
half_span = set_span >> 1;
in_ptr = in_buffer;
out_ptr = (set_count_log == 0) ? output : out_buffer;
cos_msin_ptr = *table_ptr_ptr++;
/* Loop over all the sets of this size */
for (sets_left = set_count; sets_left > 0; sets_left--)
{
/* Set up the pointers for the current set */
in_ptr_low = next_in_base;
temp = shr(set_span, 1);
/* Address arithmetic */
in_ptr_high = in_ptr_low + temp;
next_in_base += set_span;
out_ptr_low = next_out_base;
next_out_base += set_span;
out_ptr_high = next_out_base;
cos_msin_ptr = *table_ptr_ptr;
/* Loop over all the butterfly pairs in the current set */
do
for (i = 0; i < half_span; i += 2)
{
/* Address arithmetic */
in_low_even = *in_ptr_low++;
in_low_odd = *in_ptr_low++;
in_high_even = *in_ptr_high++;
in_high_odd = *in_ptr_high++;
cos_even = cos_msin_ptr[0].cosine;
msin_even = cos_msin_ptr[0].minus_sine;
cos_odd = cos_msin_ptr[1].cosine;
msin_odd = cos_msin_ptr[1].minus_sine;
cos_msin_ptr += 2;
in_low_even = in_ptr[i];
in_low_odd = in_ptr[i + 1];
in_high_even = in_ptr[half_span + i];
in_high_odd = in_ptr[half_span + i + 1];
sum = 0L;
sum = L_mac(sum, cos_even, in_low_even);
neg_msin_even = negate(msin_even);
sum = L_mac(sum, neg_msin_even, in_high_even);
out_low_even = xround(sum);
cos_even = cos_msin_ptr[i].cosine;
msin_even = cos_msin_ptr[i].minus_sine;
cos_odd = cos_msin_ptr[i + 1].cosine;
msin_odd = cos_msin_ptr[i + 1].minus_sine;
sum = 0L;
sum = L_mac(sum, msin_even,in_low_even);
sum = L_mult(cos_even, in_low_even);
sum = L_mac(sum, -msin_even, in_high_even);
out_ptr[i] = xround(sum);
sum = L_mult(msin_even,in_low_even);
sum = L_mac(sum, cos_even, in_high_even);
out_high_even = xround(sum);
out_ptr[set_span - 1 - i] = xround(sum);
sum = 0L;
sum = L_mac(sum, cos_odd, in_low_odd);
sum = L_mult(cos_odd, in_low_odd);
sum = L_mac(sum, msin_odd, in_high_odd);
out_low_odd = xround(sum);
out_ptr[i + 1] = xround(sum);
sum = 0L;
sum = L_mac(sum, msin_odd, in_low_odd);
neg_cos_odd = negate(cos_odd);
sum = L_mac(sum, neg_cos_odd, in_high_odd);
out_high_odd = xround(sum);
*out_ptr_low++ = out_low_even;
*--out_ptr_high = out_high_even;
*out_ptr_low++ = out_low_odd;
*--out_ptr_high = out_high_odd;
sum = L_mult(msin_odd, in_low_odd);
sum = L_mac(sum, -cos_odd, in_high_odd);
out_ptr[set_span - 2 - i] = xround(sum);
}
while (out_ptr_low < out_ptr_high);
in_ptr += set_span;
out_ptr += set_span;
}
/* Swap input and output buffers for next time */
buffer_swap = in_buffer;
in_buffer = out_buffer;
out_buffer = buffer_swap;
table_ptr_ptr++;
}
}
/*- End of function --------------------------------------------------------*/
+1 -3
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: dct4_a.h,v 1.4 2008/09/25 15:56:31 steveu Exp $
*/
typedef struct
+77 -160
View File
@@ -6,29 +6,23 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: dct4_s.c,v 1.8 2008/09/30 14:06:39 steveu Exp $
*/
/********************************************************************************
* Filename: dct_type_iv_s.c
*
* Purpose: Discrete Cosine Transform, Type IV used for inverse MLT
*
* The basis functions are
*
* cos(PI*(t+0.5)*(k+0.5)/block_length)
*
* for time t and basis function number k. Due to the symmetry of the expression
* in t and k, it is clear that the forward and inverse transforms are the same.
*
*********************************************************************************/
/* Discrete Cosine Transform, Type IV used for inverse MLT
The basis functions are
cos(PI*(t+0.5)*(k+0.5)/block_length)
for time t and basis function number k. Due to the symmetry of the
expression in t and k, it is clear that the forward and inverse transforms
are the same. */
/*! \file */
@@ -45,67 +39,51 @@
#if defined(G722_1_USE_FIXED_POINT)
#include "dct4_s.h"
#include "utilities.h"
/********************************************************************************
Function: dct_type_iv_s
Syntax: void dct_type_iv_s (int16_t *input,int16_t *output,int16_t dct_length)
Description: Discrete Cosine Transform, Type IV used for inverse MLT
********************************************************************************/
/* Discrete Cosine Transform, Type IV used for inverse MLT */
void dct_type_iv_s(int16_t input[], int16_t output[], int dct_length)
{
int16_t buffer_a[MAX_DCT_LENGTH];
int16_t buffer_b[MAX_DCT_LENGTH];
int16_t buffer_c[MAX_DCT_LENGTH];
int16_t *in_ptr;
int16_t *in_ptr_low;
int16_t *in_ptr_high;
int16_t *next_in_base;
int16_t *out_ptr_low;
int16_t *out_ptr_high;
int16_t *next_out_base;
int16_t *out_buffer;
int16_t *out_ptr;
int16_t *in_buffer;
int16_t *out_buffer;
int16_t *buffer_swap;
int16_t in_val_low;
int16_t in_val_high;
int16_t out_val_low;
int16_t out_val_high;
int16_t in_low_even;
int16_t in_low_odd;
int16_t in_high_even;
int16_t in_high_odd;
int16_t out_low_even;
int16_t out_low_odd;
int16_t out_high_even;
int16_t out_high_odd;
int16_t *pair_ptr;
int16_t cos_even;
int16_t cos_odd;
int16_t msin_even;
int16_t msin_odd;
int16_t set_span;
int16_t half_span;
int16_t set_count;
int16_t set_count_log;
int16_t pairs_left;
int16_t sets_left;
int16_t i;
int16_t j;
int16_t k;
int16_t index;
int16_t dummy;
int16_t dct_length_log;
int32_t sum;
int32_t acca;
const cos_msin_t **table_ptr_ptr;
const cos_msin_t *cos_msin_ptr;
int32_t acca;
int16_t temp;
int16_t dct_length_log;
const int16_t *dither_ptr;
/* Do the sum/difference butterflies, the first part of */
/* converting one N-point transform into 32 - 10 point transforms */
/* transforms, where N = 1 << DCT_LENGTH_LOG. */
/* Do the sum/difference butterflies, the first part of
converting one N-point transform into 32 - 10 point transforms
transforms, where N = 1 << DCT_LENGTH_LOG. */
if (dct_length == DCT_LENGTH)
{
dct_length_log = DCT_LENGTH_LOG;
@@ -122,92 +100,61 @@ void dct_type_iv_s(int16_t input[], int16_t output[], int dct_length)
index = 0;
i = 0;
j = 0;
for (set_count_log = 0; set_count_log <= dct_length_log - 2; set_count_log++)
{
/* Initialization for the loop over sets at the current size */
/* set_span = 1 << (DCT_LENGTH_LOG - set_count_log); */
set_span = shr(dct_length, set_count_log);
set_count = shl(1, set_count_log);
/* Loop over all the sets at the current size */
set_span = dct_length >> set_count_log;
set_count = 1 << set_count_log;
half_span = set_span >> 1;
in_ptr = in_buffer;
next_out_base = out_buffer;
out_ptr = out_buffer;
/* Loop over all the sets of this size */
temp = sub(index, 1);
if (temp < 0)
if (index < 1)
{
for (sets_left = set_count; sets_left > 0; sets_left--)
{
/* Set up output pointers for the current set */
/* pointer arithmetic */
out_ptr_low = next_out_base;
next_out_base += set_span;
out_ptr_high = next_out_base;
/* Loop over all the butterflies in the current set */
do
for (i = 0; i < half_span; i++)
{
in_val_low = *in_ptr++;
in_val_high = *in_ptr++;
/* BEST METHOD OF GETTING RID OF BIAS, BUT COMPUTATIONALLY UNPLEASANT */
/* ALTERNATIVE METHOD, SMEARS BIAS OVER THE ENTIRE FRAME, COMPUTATIONALLY SIMPLEST. */
/* IF THIS WORKS, IT'S PREFERABLE */
dummy = add(in_val_low, dither_ptr[i++]);
dummy = add(in_val_low, dither_ptr[j++]);
acca = L_add(dummy, in_val_high);
out_val_low = (int16_t) L_shr(acca, 1);
out_ptr[i] = (int16_t) L_shr(acca, 1);
dummy = add(in_val_low, dither_ptr[i++]);
acca = L_add(dummy, -in_val_high);
out_val_high = (int16_t) L_shr(acca, 1);
*out_ptr_low++ = out_val_low;
*--out_ptr_high = out_val_high;
/* this involves comparison of pointers */
/* pointer arithmetic */
dummy = add(in_val_low, dither_ptr[j++]);
acca = L_sub(dummy, in_val_high);
out_ptr[set_span - 1 - i] = (int16_t) L_shr(acca, 1);
}
while (out_ptr_low < out_ptr_high);
out_ptr += set_span;
}
}
else
{
for (sets_left = set_count; sets_left > 0; sets_left--)
{
/* Set up output pointers for the current set */
out_ptr_low = next_out_base;
next_out_base += set_span;
out_ptr_high = next_out_base;
/* Loop over all the butterflies in the current set */
do
for (i = 0; i < half_span; i++)
{
in_val_low = *in_ptr++;
in_val_high = *in_ptr++;
out_val_low = add(in_val_low, in_val_high);
out_val_high = add(in_val_low, negate(in_val_high));
*out_ptr_low++ = out_val_low;
*--out_ptr_high = out_val_high;
out_ptr[i] = add(in_val_low, in_val_high);
out_ptr[set_span - 1 - i] = sub(in_val_low, in_val_high);
}
while (out_ptr_low < out_ptr_high);
out_ptr += set_span;
}
}
/* Decide which buffers to use as input and output next time. */
/* Except for the first time (when the input buffer is the */
/* subroutine input) we just alternate the local buffers. */
/* Decide which buffers to use as input and output next time.
Except for the first time (when the input buffer is the
subroutine input) we just alternate the local buffers. */
in_buffer = out_buffer;
if (out_buffer == buffer_a)
out_buffer = buffer_b;
else
out_buffer = buffer_a;
index = add(index, 1);
out_buffer = (out_buffer == buffer_a) ? buffer_b : buffer_a;
index++;
}
/* Do 32 - 10 point transforms */
@@ -228,8 +175,7 @@ void dct_type_iv_s(int16_t input[], int16_t output[], int dct_length)
buffer_swap += CORE_SIZE;
}
for (i = 0; i < dct_length; i++)
in_buffer[i] = buffer_c[i];
vec_copyi16(in_buffer, buffer_c, dct_length);
table_ptr_ptr = s_cos_msin_table;
@@ -238,90 +184,61 @@ void dct_type_iv_s(int16_t input[], int16_t output[], int dct_length)
for (set_count_log = dct_length_log - 2; set_count_log >= 0; set_count_log--)
{
/* Initialization for the loop over sets at the current size */
/* set_span = 1 << (DCT_LENGTH_LOG - set_count_log); */
set_span = shr(dct_length, set_count_log);
set_count = shl(1, set_count_log);
next_in_base = in_buffer;
if (set_count_log == 0)
next_out_base = output;
else
next_out_base = out_buffer;
set_span = dct_length >> set_count_log;
set_count = 1 << set_count_log;
half_span = set_span >> 1;
in_ptr = in_buffer;
out_ptr = (set_count_log == 0) ? output : out_buffer;
cos_msin_ptr = *table_ptr_ptr++;
/* Loop over all the sets of this size */
for (sets_left = set_count; sets_left > 0; sets_left--)
{
/* Set up the pointers for the current set */
in_ptr_low = next_in_base;
temp = shr(set_span, 1);
in_ptr_high = in_ptr_low + temp;
next_in_base += set_span;
out_ptr_low = next_out_base;
next_out_base += set_span;
out_ptr_high = next_out_base;
cos_msin_ptr = *table_ptr_ptr;
/* Loop over all the butterfly pairs in the current set */
do
for (i = 0; i < half_span; i += 2)
{
in_low_even = *in_ptr_low++;
in_low_odd = *in_ptr_low++;
in_high_even = *in_ptr_high++;
in_high_odd = *in_ptr_high++;
cos_even = cos_msin_ptr[0].cosine;
msin_even = cos_msin_ptr[0].minus_sine;
cos_odd = cos_msin_ptr[1].cosine;
msin_odd = cos_msin_ptr[1].minus_sine;
cos_msin_ptr += 2;
in_low_even = in_ptr[i];
in_low_odd = in_ptr[i + 1];
in_high_even = in_ptr[half_span + i];
in_high_odd = in_ptr[half_span + i + 1];
sum = 0L;
sum = L_mac(sum, cos_even, in_low_even);
sum = L_mac(sum, negate(msin_even), in_high_even);
out_low_even = xround(L_shl(sum, 1));
cos_even = cos_msin_ptr[i].cosine;
msin_even = cos_msin_ptr[i].minus_sine;
cos_odd = cos_msin_ptr[i + 1].cosine;
msin_odd = cos_msin_ptr[i + 1].minus_sine;
sum = 0L;
sum = L_mac(sum, msin_even, in_low_even);
sum = L_mult(cos_even, in_low_even);
sum = L_mac(sum, -msin_even, in_high_even);
out_ptr[i] = xround(L_shl(sum, 1));
sum = L_mult(msin_even, in_low_even);
sum = L_mac(sum, cos_even, in_high_even);
out_high_even = xround(L_shl(sum, 1));
out_ptr[set_span - 1 - i] = xround(L_shl(sum, 1));
sum = 0L;
sum = L_mac(sum, cos_odd, in_low_odd);
sum = L_mult(cos_odd, in_low_odd);
sum = L_mac(sum, msin_odd, in_high_odd);
out_low_odd = xround(L_shl(sum, 1));
out_ptr[i + 1] = xround(L_shl(sum, 1));
sum = 0L;
sum = L_mac(sum, msin_odd, in_low_odd);
sum = L_mac(sum, negate(cos_odd), in_high_odd);
out_high_odd = xround(L_shl(sum, 1));
*out_ptr_low++ = out_low_even;
*--out_ptr_high = out_high_even;
*out_ptr_low++ = out_low_odd;
*--out_ptr_high = out_high_odd;
sum = L_mult(msin_odd, in_low_odd);
sum = L_mac(sum, -cos_odd, in_high_odd);
out_ptr[set_span - 2 - i] = xround(L_shl(sum, 1));
}
while (out_ptr_low < out_ptr_high);
in_ptr += set_span;
out_ptr += set_span;
}
/* Swap input and output buffers for next time */
buffer_swap = in_buffer;
in_buffer = out_buffer;
out_buffer = buffer_swap;
index = add(index, 1);
table_ptr_ptr++;
index++;
}
/* ADD IN BIAS FOR OUTPUT */
/* Add in bias for output */
if (dct_length == DCT_LENGTH)
{
for (i = 0; i < 320; i++)
for (i = 0; i < DCT_LENGTH; i++)
{
sum = L_add(output[i], syn_bias_7khz[i]);
acca = L_sub(sum, 32767);
if (acca > 0)
sum = 32767L;
acca = L_add(sum, 32768L);
if (acca < 0)
sum = -32768L;
output[i] = (int16_t) sum;
output[i] = saturate(sum);
}
}
}
+3 -7
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: dct4_s.h,v 1.4 2008/09/25 15:56:31 steveu Exp $
*/
typedef struct
@@ -196,11 +194,9 @@ static const int16_t max_dither[MAX_DCT_LENGTH] =
for (index = 0;index < length;index++)
{
angle = scale * ((double)index + 0.5);
table[index].cosine = (short) (FTOI((18427)* cos(angle)));
table[index].minus_sine = (short) (FTOI((18427)*(-sin(angle))));
table[index].cosine = (int16_t) (FTOI((18427)* cos(angle)));
table[index].minus_sine = (int16_t) (FTOI((18427)*(-sin(angle))));
}
********************************************************************************/
static const cos_msin_t s_cos_msin_2[DCT_LENGTH_DIV_32] =
+10 -16
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C)2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: decoder.c,v 1.21 2008/11/21 15:30:22 steveu Exp $
*/
/*! \file */
@@ -94,9 +92,7 @@ static void decoder(g722_1_decode_state_t *s,
int16_t old_decoder_mlt_coefs[],
int frame_error_flag);
/***************************************************************************
Description: Decodes the out_words into mlt coefs using G.722.1 Annex C
***************************************************************************/
/* Decodes the out_words into MLT coefs using G.722.1 Annex C */
void decoder(g722_1_decode_state_t *s,
int16_t number_of_regions,
int16_t decoder_mlt_coefs[],
@@ -109,11 +105,11 @@ void decoder(g722_1_decode_state_t *s,
int16_t absolute_region_power_index[MAX_NUMBER_OF_REGIONS];
int16_t decoder_power_categories[MAX_NUMBER_OF_REGIONS];
int16_t decoder_category_balances[MAX_NUM_CATEGORIZATION_CONTROL_POSSIBILITIES - 1];
uint16_t categorization_control;
int16_t num_categorization_control_bits;
int16_t num_categorization_control_possibilities;
int16_t number_of_coefs;
int16_t number_of_valid_coefs;
uint16_t categorization_control;
number_of_valid_coefs = number_of_regions*REGION_SIZE;
@@ -184,9 +180,7 @@ void decoder(g722_1_decode_state_t *s,
}
/*- End of function --------------------------------------------------------*/
/***************************************************************************
Description: Recover differential_region_power_index from code bits
***************************************************************************/
/* Recover differential_region_power_index from code bits */
static void decode_envelope(g722_1_decode_state_t *s,
int16_t number_of_regions,
int16_t *decoder_region_standard_deviation,
@@ -262,7 +256,7 @@ static void decode_envelope(g722_1_decode_state_t *s,
while ((i >= 0) && ((temp1 >= 0) || (temp2 > 0)))
{
i = sub(i, 1);
temp = shr(temp, 1);
temp >>= 1;
max_index = sub(max_index, 2);
temp1 = sub(temp, 8);
temp2 = sub(max_index, 28);
@@ -365,12 +359,12 @@ static void decode_vector_quantized_mlt_indices(g722_1_decode_state_t *s,
if (g722_1_bitstream_get(&s->bitstream, &(s->code_ptr), 1) == 0)
{
temp = shl(index, 1);
index = (int16_t) *(decoder_table_ptr + temp);
index = decoder_table_ptr[temp];
}
else
{
temp = shl(index, 1);
index = (int16_t) *(decoder_table_ptr + temp + 1);
index = decoder_table_ptr[temp + 1];
}
s->number_of_bits_left--;
}
@@ -406,7 +400,7 @@ static void decode_vector_quantized_mlt_indices(g722_1_decode_state_t *s,
{
if ((signs_index & bit) == 0)
decoder_mlt_value = negate(decoder_mlt_value);
bit = shr(bit, 1);
bit >>= 1;
}
*decoder_mlt_ptr++ = decoder_mlt_value;
}
@@ -440,7 +434,7 @@ static void decode_vector_quantized_mlt_indices(g722_1_decode_state_t *s,
if (*decoder_mlt_ptr == 0)
{
*decoder_mlt_ptr = ((random_word & 1) == 0) ? noifillneg : noifillpos;
random_word = shr(random_word, 1);
random_word >>= 1;
}
/* pointer arithmetic */
decoder_mlt_ptr++;
@@ -451,7 +445,7 @@ static void decode_vector_quantized_mlt_indices(g722_1_decode_state_t *s,
if (*decoder_mlt_ptr == 0)
{
*decoder_mlt_ptr = ((random_word & 1) == 0) ? noifillneg : noifillpos;
random_word = shr(random_word,1);
random_word >>= 1;
}
/* pointer arithmetic */
decoder_mlt_ptr++;
+8 -15
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: decoderf.c,v 1.22 2008/11/21 15:30:22 steveu Exp $
*/
/*! \file */
@@ -33,6 +31,7 @@
#include "huff_tab.h"
#include "tables.h"
#include "bitstream.h"
#include "utilities.h"
#if !defined(G722_1_USE_FIXED_POINT)
@@ -84,12 +83,12 @@ static void decoder(g722_1_decode_state_t *s,
int absolute_region_power_index[MAX_NUMBER_OF_REGIONS];
int decoder_power_categories[MAX_NUMBER_OF_REGIONS];
int decoder_category_balances[MAX_NUM_CATEGORIZATION_CONTROL_POSSIBILITIES - 1];
int rate_control;
int num_categorization_control_bits;
int num_categorization_control_possibilities;
int number_of_coefs;
int number_of_valid_coefs;
int rmlt_scale_factor;
int rate_control;
number_of_valid_coefs = s->number_of_regions*REGION_SIZE;
@@ -451,7 +450,7 @@ static void decode_vector_quantized_mlt_indices(g722_1_decode_state_t *s,
if (category == NUM_CATEGORIES - 1)
{
noifillpos = standard_deviation*0.70711f;
noifillpos = standard_deviation*0.70711;
noifillneg = -noifillpos;
/* This assumes region_size = 20 */
@@ -555,27 +554,21 @@ static void error_handling(int number_of_coefs,
float *decoder_mlt_coefs,
float *old_decoder_mlt_coefs)
{
int i;
/* If both the current and previous frames are errored,
set the mlt coefficients to 0. If only the current frame
is errored, repeat the previous frame's MLT coefficients. */
if (*frame_error_flag)
{
for (i = 0; i < number_of_valid_coefs; i++)
decoder_mlt_coefs[i] = old_decoder_mlt_coefs[i];
for (i = 0; i < number_of_valid_coefs; i++)
old_decoder_mlt_coefs[i] = 0.0f;
vec_copyf(decoder_mlt_coefs, old_decoder_mlt_coefs, number_of_valid_coefs);
vec_zerof(old_decoder_mlt_coefs, number_of_valid_coefs);
}
else
{
/* Store in case the next frame has errors. */
for (i = 0; i < number_of_valid_coefs; i++)
old_decoder_mlt_coefs[i] = decoder_mlt_coefs[i];
vec_copyf(old_decoder_mlt_coefs, decoder_mlt_coefs, number_of_valid_coefs);
}
/* Zero out the upper 1/8 of the spectrum. */
for (i = number_of_valid_coefs; i < number_of_coefs; i++)
decoder_mlt_coefs[i] = 0.0f;
vec_zerof(&decoder_mlt_coefs[number_of_valid_coefs], number_of_coefs - number_of_valid_coefs);
}
/*- End of function --------------------------------------------------------*/
+1 -3
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: defs.h,v 1.16 2008/10/01 15:31:10 steveu Exp $
*/
#define MAX(a,b) (a > b ? a : b)
+10 -20
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: encoder.c,v 1.26 2008/11/21 15:30:22 steveu Exp $
*/
/*! \file */
@@ -32,6 +30,7 @@
#include "huff_tab.h"
#include "tables.h"
#include "bitstream.h"
#include "utilities.h"
#if defined(G722_1_USE_FIXED_POINT)
@@ -99,9 +98,8 @@ static void bits_to_words(g722_1_encode_state_t *s,
drp_num_bits[number_of_regions] = num_categorization_control_bits;
drp_code_bits[number_of_regions] = categorization_control;
bit_count = 0;
/* These code bits are right justified. */
for (region = 0; region <= number_of_regions; region++)
for (bit_count = 0, region = 0; region <= number_of_regions; region++)
{
g722_1_bitstream_put(&s->bitstream, &out_code, drp_code_bits[region], drp_num_bits[region]);
bit_count += drp_num_bits[region];
@@ -247,14 +245,11 @@ void adjust_abs_region_power_index(int16_t *absolute_region_power_index,
for (region = 0; region < number_of_regions; region++)
{
n = sub(absolute_region_power_index[region], 39);
n = shr(n, 1);
n = sub(absolute_region_power_index[region], 39) >> 1;
if (n > 0)
{
temp = (int16_t) L_mult0(region, REGION_SIZE);
raw_mlt_ptr = &mlt_coefs[temp];
for (i = 0; i < REGION_SIZE; i++)
{
acca = L_shl(*raw_mlt_ptr, 16);
@@ -264,8 +259,7 @@ void adjust_abs_region_power_index(int16_t *absolute_region_power_index,
*raw_mlt_ptr++ = (int16_t) acca;
}
temp = sub(absolute_region_power_index[region], shl(n, 1));
absolute_region_power_index[region] = temp;
absolute_region_power_index[region] = sub(absolute_region_power_index[region], shl(n, 1));
}
}
}
@@ -281,7 +275,6 @@ static int16_t compute_region_powers(int16_t *mlt_coefs,
{
int16_t *input_ptr;
int32_t long_accumulator;
int16_t itemp1;
int16_t power_shift;
int16_t region;
int16_t j;
@@ -295,12 +288,8 @@ static int16_t compute_region_powers(int16_t *mlt_coefs,
input_ptr = mlt_coefs;
for (region = 0; region < number_of_regions; region++)
{
long_accumulator = 0;
for (j = 0; j < REGION_SIZE; j++)
{
itemp1 = *input_ptr++;
long_accumulator = L_mac0(long_accumulator, itemp1, itemp1);
}
long_accumulator = vec_dot_prodi16(input_ptr, input_ptr, REGION_SIZE);
input_ptr += REGION_SIZE;
power_shift = 0;
acca = long_accumulator & 0x7FFF0000L;
@@ -348,7 +337,7 @@ static int16_t compute_region_powers(int16_t *mlt_coefs,
}
/* The MLT is currently scaled too low by the factor
ENCODER_SCALE_FACTOR(=18318)/32768 * (1./sqrt(160).
ENCODER_SCALE_FACTOR(=18318)/32768 * (1.0/sqrt(160).
This is the ninth power of 1 over the square root of 2.
So later we will add ESF_ADJUSTMENT_TO_RMS_INDEX (now 9)
to drp_code_bits[0]. */
@@ -520,7 +509,8 @@ static int16_t vector_huffman(int16_t category,
int16_t num_vecs;
int16_t kmax;
int16_t kmax_plus_one;
int16_t index,signs_index;
int16_t index;
int16_t signs_index;
const int16_t *bitcount_table_ptr;
const uint16_t *code_table_ptr;
int32_t code_bits;
+9 -15
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: encoderf.c,v 1.22 2008/11/21 15:30:22 steveu Exp $
*/
/*! \file */
@@ -33,6 +31,7 @@
#include "huff_tab.h"
#include "tables.h"
#include "bitstream.h"
#include "utilities.h"
#if !defined(G722_1_USE_FIXED_POINT)
@@ -218,7 +217,6 @@ static int compute_region_powers(int number_of_regions,
float *input_ptr;
int iterations;
float ftemp0;
float ftemp1;
int index;
int index_min;
int index_max;
@@ -230,13 +228,9 @@ static int compute_region_powers(int number_of_regions,
input_ptr = mlt_coefs;
for (region = 0; region < number_of_regions; region++)
{
ftemp0 = 0.0f;
for (j = 0; j < REGION_SIZE; j++)
{
ftemp1 = *input_ptr++;
ftemp0 += ftemp1*ftemp1;
}
ftemp0 = vec_dot_prodf(input_ptr, input_ptr, REGION_SIZE);
ftemp0 *= REGION_SIZE_INVERSE;
input_ptr += REGION_SIZE;
index_min = 0;
index_max = REGION_POWER_TABLE_SIZE;
@@ -260,7 +254,7 @@ static int compute_region_powers(int number_of_regions,
}
/* The MLT is currently scaled too low by the factor
ENCODER_SCALE_FACTOR(=18318)/32768 * (1./sqrt(160).
ENCODER_SCALE_FACTOR(=18318)/32768 * (1.0/sqrt(160).
This is the ninth power of 1 over the square root of 2.
So later we will add ESF_ADJUSTMENT_TO_RMS_INDEX (now 9)
to drp_code_bits[0]. */
@@ -448,7 +442,7 @@ static int vector_huffman(int category,
number_of_non_zero = 0;
for (j = 0; j < vec_dim; j++)
{
k = (int) (fabs(*raw_mlt_ptr) * inv_of_step_size_times_std_dev + dead_zone[category]);
k = (int) (fabs(*raw_mlt_ptr)*inv_of_step_size_times_std_dev + dead_zone[category]);
if (k != 0)
{
number_of_non_zero++;
@@ -458,12 +452,12 @@ static int vector_huffman(int category,
if (k > kmax)
k = kmax;
}
index = index*(kmax_plus_one) + k;
index = index*kmax_plus_one + k;
raw_mlt_ptr++;
}
code_bits = *(code_table_ptr + index);
number_of_code_bits = *(bitcount_table_ptr + index) + number_of_non_zero;
code_bits = code_table_ptr[index];
number_of_code_bits = bitcount_table_ptr[index] + number_of_non_zero;
number_of_region_bits += number_of_code_bits;
code_bits = (code_bits << number_of_non_zero) + signs_index;
-2
View File
@@ -7,8 +7,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* $Id: g722_1.h.in,v 1.1.1.1 2008/09/20 09:47:17 steveu Exp $
*/
/*! \file */
+1 -3
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: g722_1.h,v 1.14 2008/10/17 13:18:21 steveu Exp $
*/
#if !defined(_G722_1_G722_1_H_)
-2
View File
@@ -9,8 +9,6 @@
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: version.h.in,v 1.2 2008/09/20 16:52:51 steveu Exp $
*/
#if !defined(_G722_1_VERSION_H_)
+1 -3
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: huff_tab.c,v 1.7 2008/09/30 14:06:40 steveu Exp $
*/
/*! \file */
+1 -3
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: huff_tab.h,v 1.4 2008/09/30 14:06:40 steveu Exp $
*/
#define REGION_POWER_STEPSIZE_DB 3.010299957
+6 -3
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: make_dct4_tables.c,v 1.2 2008/10/02 11:43:54 steveu Exp $
*/
/*! \file */
@@ -29,7 +27,11 @@
#include "g722_1/g722_1.h"
#if defined(PI)
#undef PI
#endif
#define PI 3.141592653589793238462
#include "defs.h"
static void set_up_one_table(int length)
@@ -99,6 +101,7 @@ int main(int argc, char *argv[])
for (i = 0; i <= length_log; i++)
set_up_one_table(dct_size << i);
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/
+13 -13
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: make_tables.c,v 1.5 2008/11/21 15:30:22 steveu Exp $
*/
/*! \file */
@@ -37,6 +35,7 @@
#undef PI
#endif
#define PI 3.141592653589793238462
/* These may have been defined in the main header for the codec, so we clear out
any pre-existing definitions here. */
#if defined(ENCODER_SCALE_FACTOR)
@@ -124,7 +123,7 @@ static void generate_sam2coef_tables(void)
for (i = 0; i < DCT_LENGTH; i++)
{
angle = (PI/2.0)*((double) i + 0.5)/(double) DCT_LENGTH;
printf(" %.15e,\n", sin(angle));
printf(" %.15ef,\n", sin(angle));
}
printf("};\n\n");
@@ -132,7 +131,7 @@ static void generate_sam2coef_tables(void)
for (i = 0; i < MAX_DCT_LENGTH; i++)
{
angle = (PI/2.0)*((double) i + 0.5)/(double) MAX_DCT_LENGTH;
printf(" %.15le,\n", sin(angle));
printf(" %.15ef,\n", sin(angle));
}
printf("};\n\n");
@@ -180,7 +179,7 @@ static void generate_coef2sam_tables(void)
for (i = 0; i < DCT_LENGTH; i++)
{
angle = (PI/2.0)*((double) i + 0.5)/(double) DCT_LENGTH;
printf(" %.15e,\n", sin(angle));
printf(" %.15ef,\n", sin(angle));
}
printf("};\n\n");
@@ -188,7 +187,7 @@ static void generate_coef2sam_tables(void)
for (i = 0; i < MAX_DCT_LENGTH; i++)
{
angle = (PI/2.0)*((double) i + 0.5)/(double) MAX_DCT_LENGTH;
printf(" %.15e,\n", sin(angle));
printf(" %.15ef,\n", sin(angle));
}
printf("};\n\n");
@@ -218,7 +217,7 @@ int main(int argc, char *argv[])
for (i = 0; i < REGION_POWER_TABLE_SIZE; i++)
{
value = pow(10.0, 0.10*REGION_POWER_STEPSIZE_DB*(i - REGION_POWER_TABLE_NUM_NEGATIVES));
printf(" %.15e,\n", sqrt(value));
printf(" %.15ef,\n", sqrt(value));
}
printf("};\n\n");
@@ -226,7 +225,7 @@ int main(int argc, char *argv[])
for (i = 0; i < REGION_POWER_TABLE_SIZE; i++)
{
value = pow(10.0, 0.10*REGION_POWER_STEPSIZE_DB*(i - REGION_POWER_TABLE_NUM_NEGATIVES));
printf(" %.15e,\n", 1.0/sqrt(value));
printf(" %.15ef,\n", 1.0/sqrt(value));
}
printf("};\n\n");
@@ -259,14 +258,14 @@ int main(int argc, char *argv[])
printf("const float step_size[NUM_CATEGORIES] =\n{\n");
for (i = 0; i < NUM_CATEGORIES; i++)
{
printf(" %.15e,\n", step_size[i]);
printf(" %.15ef,\n", step_size[i]);
}
printf("};\n\n");
printf("const float step_size_inverse_table[NUM_CATEGORIES] =\n{\n");
for (i = 0; i < NUM_CATEGORIES; i++)
{
printf(" %.15e,\n", 1.0/step_size[i]);
printf(" %.15ef,\n", 1.0/step_size[i]);
}
printf("};\n\n");
@@ -275,7 +274,7 @@ int main(int argc, char *argv[])
for (i = 0; i < REGION_POWER_TABLE_SIZE; i++)
{
value = pow(10.0, 0.10*REGION_POWER_STEPSIZE_DB*(i - REGION_POWER_TABLE_NUM_NEGATIVES));
printf(" %.15e,\n", value);
printf(" %.15ef,\n", value);
}
printf("};\n\n");
@@ -283,9 +282,10 @@ int main(int argc, char *argv[])
for (i = 0; i < REGION_POWER_TABLE_SIZE - 1; i++)
{
value = (float) pow(10.0, 0.10*REGION_POWER_STEPSIZE_DB*(0.5 + (i - REGION_POWER_TABLE_NUM_NEGATIVES)));
printf(" %.15e,\n", value);
printf(" %.15ef,\n", value);
}
printf("};\n\n");
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/
+17 -32
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: sam2coef.c,v 1.12 2008/10/02 11:43:54 steveu Exp $
*/
/*! \file */
@@ -29,17 +27,16 @@
#include "defs.h"
#include "sam2coef.h"
#include "utilities.h"
/************************************************************************************
Purpose: Convert Samples to Reversed MLT (Modulated Lapped Transform) Coefficients
/* Convert Samples to Reversed MLT (Modulated Lapped Transform) Coefficients
The "Reversed MLT" is an overlapped block transform which uses even symmetry
on the left, odd symmetry on the right and a Type IV DCT as the block transform.
It is thus similar to a MLT which uses odd symmetry on the left, even symmetry
on the right and a Type IV DST as the block transform. In fact, it is equivalent
to reversing the order of the samples, performing an MLT and then negating all
the even-numbered coefficients.
***************************************************************************/
The "Reversed MLT" is an overlapped block transform which uses even symmetry
on the left, odd symmetry on the right and a Type IV DCT as the block transform.
It is thus similar to a MLT which uses odd symmetry on the left, even symmetry
on the right and a Type IV DST as the block transform. In fact, it is equivalent
to reversing the order of the samples, performing an MLT and then negating all
the even-numbered coefficients. */
#if defined(G722_1_USE_FIXED_POINT)
int16_t samples_to_rmlt_coefs(const int16_t new_samples[],
@@ -62,34 +59,26 @@ int16_t samples_to_rmlt_coefs(const int16_t new_samples[],
half_dct_length = dct_length >> 1;
if (dct_length == DCT_LENGTH)
win = samples_to_rmlt_window;
else
win = max_samples_to_rmlt_window;
win = (dct_length == DCT_LENGTH) ? samples_to_rmlt_window : max_samples_to_rmlt_window;
/* Get the first half of the windowed samples */
last = half_dct_length - 1;
for (i = 0; i < half_dct_length; i++)
{
acca = 0L;
acca = L_mac(acca, win[last - i], old_samples[last - i]);
acca = L_mult(win[last - i], old_samples[last - i]);
acca = L_mac(acca, win[half_dct_length + i], old_samples[half_dct_length + i]);
temp = xround(acca);
windowed_data[i] = temp;
windowed_data[i] = xround(acca);
}
/* Get the second half of the windowed samples */
last = dct_length - 1;
for (i = 0; i < half_dct_length; i++)
{
acca = 0L;
acca = L_mac(acca, win[last - i], new_samples[i]);
acca = L_mult(win[last - i], new_samples[i]);
acca = L_mac(acca, negate(win[i]), new_samples[last - i]);
temp = xround(acca);
windowed_data[half_dct_length + i] = temp;
windowed_data[half_dct_length + i] = xround(acca);
}
/* Save the new samples for next time, when they will be the old samples. */
for (i = 0; i < dct_length; i++)
old_samples[i] = new_samples[i];
vec_copyi16(old_samples, new_samples, dct_length);
/* Calculate how many bits to shift up the input to the DCT. */
temp1 = 0;
@@ -156,10 +145,7 @@ void samples_to_rmlt_coefs(const float new_samples[],
half_dct_length = dct_length >> 1;
if (dct_length == DCT_LENGTH)
win = samples_to_rmlt_window;
else
win = max_samples_to_rmlt_window;
win = (dct_length == DCT_LENGTH) ? samples_to_rmlt_window : max_samples_to_rmlt_window;
/* Get the first half of the windowed samples. */
last = half_dct_length - 1;
for (i = 0; i < half_dct_length; i++)
@@ -177,8 +163,7 @@ void samples_to_rmlt_coefs(const float new_samples[],
windowed_data[half_dct_length + i] = sum;
}
/* Save the new samples for next time, when they will be the old samples. */
for (i = 0; i < dct_length; i++)
old_samples[i] = new_samples[i];
vec_copyf(old_samples, new_samples, dct_length);
/* Perform a Type IV DCT on the windowed data to get the coefficients. */
dct_type_iv(windowed_data, coefs, dct_length);
+1 -3
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: sam2coef.h,v 1.2 2008/10/02 11:43:54 steveu Exp $
*/
#if defined(G722_1_USE_FIXED_POINT)
+264 -266
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: tables.c,v 1.11 2008/09/30 14:06:40 steveu Exp $
*/
/*! \file */
@@ -65,70 +63,70 @@ const int16_t int_region_standard_deviation_table[REGION_POWER_TABLE_SIZE] =
#else
const float region_standard_deviation_table[REGION_POWER_TABLE_SIZE] =
{
2.441406247570224e-04f,
3.452669826719395e-04f,
4.882812495545411e-04f,
6.905339654011486e-04f,
9.765624991900746e-04f,
1.381067930916839e-03f,
1.953124998542134e-03f,
2.762135862062757e-03f,
3.906249997408239e-03f,
5.524271724583683e-03f,
7.812499995464418e-03f,
1.104854345008369e-02f,
1.562499999222472e-02f,
2.209708690200003e-02f,
3.124999998704119e-02f,
4.419417380766535e-02f,
6.249999997926591e-02f,
8.838834762266132e-02f,
1.249999999688989e-01f,
1.767766952599839e-01f,
2.499999999585318e-01f,
3.535533905492901e-01f,
4.999999999585318e-01f,
7.071067811572251e-01f,
1.000000000000000e+00f,
1.414213562431740e+00f,
2.000000000165873e+00f,
2.828427125098059e+00f,
4.000000000663491e+00f,
5.656854250665278e+00f,
8.000000001990472e+00f,
1.131370850226887e+01f,
1.600000000530792e+01f,
2.262741700641438e+01f,
3.200000001326981e+01f,
4.525483401658204e+01f,
6.400000003184756e+01f,
9.050966804067060e+01f,
1.280000000743110e+02f,
1.810193360963542e+02f,
2.560000001698536e+02f,
3.620386722227349e+02f,
5.120000003821707e+02f,
7.240773445055215e+02f,
1.024000000849268e+03f,
1.448154689131149e+03f,
2.048000001868390e+03f,
2.896309378502505e+03f,
4.096000004076487e+03f,
5.792618757485434e+03f,
8.192000008832390e+03f,
1.158523751593169e+04f,
1.638400001902361e+04f,
2.317047503378509e+04f,
3.276800004076484e+04f,
4.634095007141347e+04f,
6.553600008696507e+04f,
9.268190015051374e+04f,
1.310720001848009e+05f,
1.853638003164007e+05f,
2.621440003913428e+05f,
3.707276006635486e+05f,
5.242880008261676e+05f,
7.414552013885899e+05f
2.441406247570224e-04,
3.452669826719395e-04,
4.882812495545411e-04,
6.905339654011486e-04,
9.765624991900746e-04,
1.381067930916839e-03,
1.953124998542134e-03,
2.762135862062757e-03,
3.906249997408239e-03,
5.524271724583683e-03,
7.812499995464418e-03,
1.104854345008369e-02,
1.562499999222472e-02,
2.209708690200003e-02,
3.124999998704119e-02,
4.419417380766535e-02,
6.249999997926591e-02,
8.838834762266132e-02,
1.249999999688989e-01,
1.767766952599839e-01,
2.499999999585318e-01,
3.535533905492901e-01,
4.999999999585318e-01,
7.071067811572251e-01,
1.000000000000000e+00,
1.414213562431740e+00,
2.000000000165873e+00,
2.828427125098059e+00,
4.000000000663491e+00,
5.656854250665278e+00,
8.000000001990472e+00,
1.131370850226887e+01,
1.600000000530792e+01,
2.262741700641438e+01,
3.200000001326981e+01,
4.525483401658204e+01,
6.400000003184756e+01,
9.050966804067060e+01,
1.280000000743110e+02,
1.810193360963542e+02,
2.560000001698536e+02,
3.620386722227349e+02,
5.120000003821707e+02,
7.240773445055215e+02,
1.024000000849268e+03,
1.448154689131149e+03,
2.048000001868390e+03,
2.896309378502505e+03,
4.096000004076487e+03,
5.792618757485434e+03,
8.192000008832390e+03,
1.158523751593169e+04,
1.638400001902361e+04,
2.317047503378509e+04,
3.276800004076484e+04,
4.634095007141347e+04,
6.553600008696507e+04,
9.268190015051374e+04,
1.310720001848009e+05,
1.853638003164007e+05,
2.621440003913428e+05,
3.707276006635486e+05,
5.242880008261676e+05,
7.414552013885899e+05
};
#endif
@@ -146,70 +144,70 @@ const int16_t standard_deviation_inverse_table[REGION_POWER_TABLE_SIZE] =
#else
const float standard_deviation_inverse_table[REGION_POWER_TABLE_SIZE] =
{
4.096000004076488e+03f,
2.896309378502504e+03f,
2.048000001868390e+03f,
1.448154689131149e+03f,
1.024000000849268e+03f,
7.240773445055215e+02f,
5.120000003821708e+02f,
3.620386722227349e+02f,
2.560000001698537e+02f,
1.810193360963542e+02f,
1.280000000743110e+02f,
9.050966804067060e+01f,
6.400000003184756e+01f,
4.525483401658203e+01f,
3.200000001326982e+01f,
2.262741700641438e+01f,
1.600000000530793e+01f,
1.131370850226887e+01f,
8.000000001990474e+00f,
5.656854250665277e+00f,
4.000000000663491e+00f,
2.828427125098059e+00f,
2.000000000165873e+00f,
1.414213562431740e+00f,
1.000000000000000e+00f,
7.071067811572251e-01f,
4.999999999585318e-01f,
3.535533905492901e-01f,
2.499999999585318e-01f,
1.767766952599838e-01f,
1.249999999688989e-01f,
8.838834762266132e-02f,
6.249999997926592e-02f,
4.419417380766535e-02f,
3.124999998704120e-02f,
2.209708690200002e-02f,
1.562499999222472e-02f,
1.104854345008369e-02f,
7.812499995464418e-03f,
5.524271724583683e-03f,
3.906249997408239e-03f,
2.762135862062757e-03f,
1.953124998542134e-03f,
1.381067930916839e-03f,
9.765624991900747e-04f,
6.905339654011486e-04f,
4.882812495545411e-04f,
3.452669826719394e-04f,
2.441406247570224e-04f,
1.726334913216520e-04f,
1.220703123683871e-04f,
8.631674565366727e-05f,
6.103515617913153e-05f,
4.315837282325419e-05f,
3.051757808703478e-05f,
2.157918640983742e-05f,
1.525878904225187e-05f,
1.078959320402385e-05f,
7.629394520493171e-06f,
5.394796601564505e-06f,
3.814697259930213e-06f,
2.697398300558537e-06f,
1.907348629806920e-06f,
1.348699150167414e-06f
4.096000004076488e+03,
2.896309378502504e+03,
2.048000001868390e+03,
1.448154689131149e+03,
1.024000000849268e+03,
7.240773445055215e+02,
5.120000003821708e+02,
3.620386722227349e+02,
2.560000001698537e+02,
1.810193360963542e+02,
1.280000000743110e+02,
9.050966804067060e+01,
6.400000003184756e+01,
4.525483401658203e+01,
3.200000001326982e+01,
2.262741700641438e+01,
1.600000000530793e+01,
1.131370850226887e+01,
8.000000001990474e+00,
5.656854250665277e+00,
4.000000000663491e+00,
2.828427125098059e+00,
2.000000000165873e+00,
1.414213562431740e+00,
1.000000000000000e+00,
7.071067811572251e-01,
4.999999999585318e-01,
3.535533905492901e-01,
2.499999999585318e-01,
1.767766952599838e-01,
1.249999999688989e-01,
8.838834762266132e-02,
6.249999997926592e-02,
4.419417380766535e-02,
3.124999998704120e-02,
2.209708690200002e-02,
1.562499999222472e-02,
1.104854345008369e-02,
7.812499995464418e-03,
5.524271724583683e-03,
3.906249997408239e-03,
2.762135862062757e-03,
1.953124998542134e-03,
1.381067930916839e-03,
9.765624991900747e-04,
6.905339654011486e-04,
4.882812495545411e-04,
3.452669826719394e-04,
2.441406247570224e-04,
1.726334913216520e-04,
1.220703123683871e-04,
8.631674565366727e-05,
6.103515617913153e-05,
4.315837282325419e-05,
3.051757808703478e-05,
2.157918640983742e-05,
1.525878904225187e-05,
1.078959320402385e-05,
7.629394520493171e-06,
5.394796601564505e-06,
3.814697259930213e-06,
2.697398300558537e-06,
1.907348629806920e-06,
1.348699150167414e-06
};
#endif
@@ -241,14 +239,14 @@ const float step_size[NUM_CATEGORIES] =
const float step_size_inverse_table[NUM_CATEGORIES] =
{
2.82805443e+00f,
2.00000000e+00f,
1.41422713e+00f,
1.00000000e+00f,
7.07113564e-01f,
5.00000000e-01f,
3.53556782e-01f,
3.53556782e-01f
2.82805443e+00,
2.00000000e+00,
1.41422713e+00,
1.00000000e+00,
7.07113564e-01,
5.00000000e-01,
3.53556782e-01,
3.53556782e-01
};
#endif
@@ -279,137 +277,137 @@ const float dead_zone[NUM_CATEGORIES] =
#if !defined(G722_1_USE_FIXED_POINT)
const float region_power_table[REGION_POWER_TABLE_SIZE] =
{
5.96046448e-08f,
1.19209290e-07f,
2.38418579e-07f,
4.76837158e-07f,
9.53674316e-07f,
1.90734863e-06f,
3.81469727e-06f,
7.62939453e-06f,
1.52587891e-05f,
3.05175781e-05f,
6.10351562e-05f,
1.22070312e-04f,
2.44140625e-04f,
4.88281250e-04f,
9.76562500e-04f,
1.95312500e-03f,
3.90625000e-03f,
7.81250000e-03f,
1.56250000e-02f,
3.12500000e-02f,
6.25000000e-02f,
1.25000000e-01f,
2.50000000e-01f,
5.00000000e-01f,
1.00000000e+00f,
2.00000000e+00f,
4.00000000e+00f,
8.00000000e+00f,
1.60000000e+01f,
3.20000000e+01f,
6.40000000e+01f,
1.28000000e+02f,
2.56000000e+02f,
5.12000000e+02f,
1.02400000e+03f,
2.04800000e+03f,
4.09600000e+03f,
8.19200000e+03f,
1.63840000e+04f,
3.27680000e+04f,
6.55360000e+04f,
1.31072000e+05f,
2.62144000e+05f,
5.24288000e+05f,
1.04857600e+06f,
2.09715200e+06f,
4.19430400e+06f,
8.38860800e+06f,
1.67772160e+07f,
3.35544320e+07f,
6.71088640e+07f,
1.34217728e+08f,
2.68435456e+08f,
5.36870912e+08f,
1.07374182e+09f,
2.14748365e+09f,
4.29496730e+09f,
8.58993459e+09f,
1.71798692e+10f,
3.43597384e+10f,
6.87194767e+10f,
1.37438953e+11f,
2.74877907e+11f,
5.49755814e+11f
5.96046448e-08,
1.19209290e-07,
2.38418579e-07,
4.76837158e-07,
9.53674316e-07,
1.90734863e-06,
3.81469727e-06,
7.62939453e-06,
1.52587891e-05,
3.05175781e-05,
6.10351562e-05,
1.22070312e-04,
2.44140625e-04,
4.88281250e-04,
9.76562500e-04,
1.95312500e-03,
3.90625000e-03,
7.81250000e-03,
1.56250000e-02,
3.12500000e-02,
6.25000000e-02,
1.25000000e-01,
2.50000000e-01,
5.00000000e-01,
1.00000000e+00,
2.00000000e+00,
4.00000000e+00,
8.00000000e+00,
1.60000000e+01,
3.20000000e+01,
6.40000000e+01,
1.28000000e+02,
2.56000000e+02,
5.12000000e+02,
1.02400000e+03,
2.04800000e+03,
4.09600000e+03,
8.19200000e+03,
1.63840000e+04,
3.27680000e+04,
6.55360000e+04,
1.31072000e+05,
2.62144000e+05,
5.24288000e+05,
1.04857600e+06,
2.09715200e+06,
4.19430400e+06,
8.38860800e+06,
1.67772160e+07,
3.35544320e+07,
6.71088640e+07,
1.34217728e+08,
2.68435456e+08,
5.36870912e+08,
1.07374182e+09,
2.14748365e+09,
4.29496730e+09,
8.58993459e+09,
1.71798692e+10,
3.43597384e+10,
6.87194767e+10,
1.37438953e+11,
2.74877907e+11,
5.49755814e+11
};
const float region_power_table_boundary[REGION_POWER_TABLE_SIZE - 1] =
{
8.42936956e-08f,
1.68587391e-07f,
3.37174782e-07f,
6.74349565e-07f,
1.34869913e-06f,
2.69739826e-06f,
5.39479652e-06f,
1.07895930e-05f,
2.15791861e-05f,
4.31583721e-05f,
8.63167443e-05f,
1.72633489e-04f,
3.45266977e-04f,
6.90533954e-04f,
1.38106791e-03f,
2.76213582e-03f,
5.52427163e-03f,
1.10485433e-02f,
2.20970865e-02f,
4.41941731e-02f,
8.83883461e-02f,
1.76776692e-01f,
3.53553385e-01f,
7.07106769e-01f,
1.41421354e+00f,
2.82842708e+00f,
5.65685415e+00f,
1.13137083e+01f,
2.26274166e+01f,
4.52548332e+01f,
9.05096664e+01f,
1.81019333e+02f,
3.62038666e+02f,
7.24077332e+02f,
1.44815466e+03f,
2.89630933e+03f,
5.79261865e+03f,
1.15852373e+04f,
2.31704746e+04f,
4.63409492e+04f,
9.26818984e+04f,
1.85363797e+05f,
3.70727594e+05f,
7.41455188e+05f,
1.48291038e+06f,
2.96582075e+06f,
5.93164150e+06f,
1.18632830e+07f,
2.37265660e+07f,
4.74531320e+07f,
9.49062640e+07f,
1.89812528e+08f,
3.79625056e+08f,
7.59250112e+08f,
1.51850022e+09f,
3.03700045e+09f,
6.07400090e+09f,
1.21480018e+10f,
2.42960036e+10f,
4.85920072e+10f,
9.71840143e+10f,
1.94368029e+11f,
3.88736057e+11f
8.42936956e-08,
1.68587391e-07,
3.37174782e-07,
6.74349565e-07,
1.34869913e-06,
2.69739826e-06,
5.39479652e-06,
1.07895930e-05,
2.15791861e-05,
4.31583721e-05,
8.63167443e-05,
1.72633489e-04,
3.45266977e-04,
6.90533954e-04,
1.38106791e-03,
2.76213582e-03,
5.52427163e-03,
1.10485433e-02,
2.20970865e-02,
4.41941731e-02,
8.83883461e-02,
1.76776692e-01,
3.53553385e-01,
7.07106769e-01,
1.41421354e+00,
2.82842708e+00,
5.65685415e+00,
1.13137083e+01,
2.26274166e+01,
4.52548332e+01,
9.05096664e+01,
1.81019333e+02,
3.62038666e+02,
7.24077332e+02,
1.44815466e+03,
2.89630933e+03,
5.79261865e+03,
1.15852373e+04,
2.31704746e+04,
4.63409492e+04,
9.26818984e+04,
1.85363797e+05,
3.70727594e+05,
7.41455188e+05,
1.48291038e+06,
2.96582075e+06,
5.93164150e+06,
1.18632830e+07,
2.37265660e+07,
4.74531320e+07,
9.49062640e+07,
1.89812528e+08,
3.79625056e+08,
7.59250112e+08,
1.51850022e+09,
3.03700045e+09,
6.07400090e+09,
1.21480018e+10,
2.42960036e+10,
4.85920072e+10,
9.71840143e+10,
1.94368029e+11,
3.88736057e+11
};
#endif
+1 -3
View File
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood <steveu@coppice.org> from the reference
* code supplied with ITU G.722.1, which is:
*
* © 2004 Polycom, Inc.
* (C) 2004 Polycom, Inc.
* All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: tables.h,v 1.7 2008/09/26 17:37:31 steveu Exp $
*/
#define REGION_POWER_TABLE_SIZE 64
+467
View File
@@ -0,0 +1,467 @@
/*
* g722_1 - a library for the G.722.1 and Annex C codecs
*
* utilities.c
*
* Copyright (C) 2006 Steve Underwood
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#if defined(HAVE_CONFIG_H)
#include <config.h>
#endif
#include <inttypes.h>
#if defined(G722_1_USE_MMX)
#include <mmintrin.h>
#endif
#if defined(G722_1_USE_SSE)
#include <xmmintrin.h>
#endif
#if defined(G722_1_USE_SSE2)
#include <emmintrin.h>
#endif
#if defined(G722_1_USE_SSE3)
#include <pmmintrin.h>
#include <tmmintrin.h>
#endif
#if defined(G722_1_USE_SSE4_1)
#include <smmintrin.h>
#endif
#if defined(G722_1_USE_SSE4_2)
#include <nmmintrin.h>
#endif
#if defined(G722_1_USE_SSE4A)
#include <ammintrin.h>
#endif
#if defined(G722_1_USE_SSE5)
#include <bmmintrin.h>
#endif
#include "utilities.h"
#if defined(G722_1_USE_FIXED_POINT)
void vec_copyi16(int16_t z[], const int16_t x[], int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x[i];
}
/*- End of function --------------------------------------------------------*/
int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n)
{
int32_t z;
#if defined(__GNUC__) && defined(G722_1_USE_MMX)
#if defined(__x86_64__)
__asm__ __volatile__(
" emms;\n"
" pxor %%mm0,%%mm0;\n"
" leal -32(%%rsi,%%eax,2),%%edx;\n" /* edx = top - 32 */
" cmpl %%rdx,%%rsi;\n"
" ja 1f;\n"
/* Work in blocks of 16 int16_t's until we are near the end */
" .p2align 2;\n"
"2:\n"
" movq (%%rdi),%%mm1;\n"
" movq (%%rsi),%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" movq 8(%%rdi),%%mm1;\n"
" movq 8(%%rsi),%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" movq 16(%%rdi),%%mm1;\n"
" movq 16(%%rsi),%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" movq 24(%%rdi),%%mm1;\n"
" movq 24(%%rsi),%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" addl $32,%%rsi;\n"
" addl $32,%%rdi;\n"
" cmpl %%rdx,%%rsi;\n"
" jbe 2b;\n"
" .p2align 2;\n"
"1:\n"
" addl $24,%%rdx;\n" /* Now edx = top - 8 */
" cmpl %%rdx,%%rsi;\n"
" ja 3f;\n"
/* Work in blocks of 4 int16_t's until we are near the end */
" .p2align 2;\n"
"4:\n"
" movq (%%rdi),%%mm1;\n"
" movq (%%rsi),%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" addl $8,%%rsi;\n"
" addl $8,%%rdi;\n"
" cmpl %%rdx,%%rsi;"
" jbe 4b;\n"
" .p2align 2;\n"
"3:\n"
" addl $4,%%rdx;\n" /* Now edx = top - 4 */
" cmpl %%rdx,%%rsi;\n"
" ja 5f;\n"
/* Work in a block of 2 int16_t's */
" movd (%%rdi),%%mm1;\n"
" movd (%%rsi),%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" addl $4,%%rsi;\n"
" addl $4,%%rdi;\n"
" .p2align 2;\n"
"5:\n"
" addl $2,%%rdx;\n" /* Now edx = top - 2 */
" cmpl %%rdx,%%rsi;\n"
" ja 6f;\n"
/* Deal with the very last int16_t, when n is odd */
" movswl (%%rdi),%%eax;\n"
" andl $65535,%%eax;\n"
" movd %%eax,%%mm1;\n"
" movswl (%%rsi),%%eax;\n"
" andl $65535,%%eax;\n"
" movd %%eax,%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" .p2align 2;\n"
"6:\n"
/* Merge the pieces of the answer */
" movq %%mm0,%%mm1;\n"
" punpckhdq %%mm0,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
/* Et voila, eax has the final result */
" movd %%mm0,%%eax;\n"
" emms;\n"
: "=a" (z)
: "S" (x), "D" (y), "a" (n)
: "cc"
);
#else
__asm__ __volatile__(
" emms;\n"
" pxor %%mm0,%%mm0;\n"
" leal -32(%%esi,%%eax,2),%%edx;\n" /* edx = top - 32 */
" cmpl %%edx,%%esi;\n"
" ja 1f;\n"
/* Work in blocks of 16 int16_t's until we are near the end */
" .p2align 2;\n"
"2:\n"
" movq (%%edi),%%mm1;\n"
" movq (%%esi),%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" movq 8(%%edi),%%mm1;\n"
" movq 8(%%esi),%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" movq 16(%%edi),%%mm1;\n"
" movq 16(%%esi),%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" movq 24(%%edi),%%mm1;\n"
" movq 24(%%esi),%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" addl $32,%%esi;\n"
" addl $32,%%edi;\n"
" cmpl %%edx,%%esi;\n"
" jbe 2b;\n"
" .p2align 2;\n"
"1:\n"
" addl $24,%%edx;\n" /* Now edx = top - 8 */
" cmpl %%edx,%%esi;\n"
" ja 3f;\n"
/* Work in blocks of 4 int16_t's until we are near the end */
" .p2align 2;\n"
"4:\n"
" movq (%%edi),%%mm1;\n"
" movq (%%esi),%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" addl $8,%%esi;\n"
" addl $8,%%edi;\n"
" cmpl %%edx,%%esi;"
" jbe 4b;\n"
" .p2align 2;\n"
"3:\n"
" addl $4,%%edx;\n" /* Now edx = top - 4 */
" cmpl %%edx,%%esi;\n"
" ja 5f;\n"
/* Work in a block of 2 int16_t's */
" movd (%%edi),%%mm1;\n"
" movd (%%esi),%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" addl $4,%%esi;\n"
" addl $4,%%edi;\n"
" .p2align 2;\n"
"5:\n"
" addl $2,%%edx;\n" /* Now edx = top - 2 */
" cmpl %%edx,%%esi;\n"
" ja 6f;\n"
/* Deal with the very last int16_t, when n is odd */
" movswl (%%edi),%%eax;\n"
" andl $65535,%%eax;\n"
" movd %%eax,%%mm1;\n"
" movswl (%%esi),%%eax;\n"
" andl $65535,%%eax;\n"
" movd %%eax,%%mm2;\n"
" pmaddwd %%mm2,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
" .p2align 2;\n"
"6:\n"
/* Merge the pieces of the answer */
" movq %%mm0,%%mm1;\n"
" punpckhdq %%mm0,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
/* Et voila, eax has the final result */
" movd %%mm0,%%eax;\n"
" emms;\n"
: "=a" (z)
: "S" (x), "D" (y), "a" (n)
: "cc"
);
#endif
#else
int i;
z = 0;
for (i = 0; i < n; i++)
z += (int32_t) x[i]*(int32_t) y[i];
#endif
return z;
}
/*- End of function --------------------------------------------------------*/
#else
#if defined(__GNUC__) && defined(G722_1_USE_SSE2)
void vec_copyf(float z[], const float x[], int n)
{
int i;
__m128 n1;
if ((i = n & ~3))
{
for (i -= 4; i >= 0; i -= 4)
{
n1 = _mm_loadu_ps(x + i);
_mm_storeu_ps(z + i, n1);
}
}
/* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */
switch (n & 3)
{
case 3:
z[n - 3] = x[n - 3];
case 2:
z[n - 2] = x[n - 2];
case 1:
z[n - 1] = x[n - 1];
}
}
#else
void vec_copyf(float z[], const float x[], int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x[i];
}
#endif
/*- End of function --------------------------------------------------------*/
#if defined(__GNUC__) && defined(G722_1_USE_SSE2)
void vec_zerof(float z[], int n)
{
int i;
__m128 n1;
if ((i = n & ~3))
{
n1 = _mm_setzero_ps();
for (i -= 4; i >= 0; i -= 4)
_mm_storeu_ps(z + i, n1);
}
/* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */
switch (n & 3)
{
case 3:
z[n - 3] = 0;
case 2:
z[n - 2] = 0;
case 1:
z[n - 1] = 0;
}
}
#else
void vec_zerof(float z[], int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = 0.0f;
}
#endif
/*- End of function --------------------------------------------------------*/
void vec_subf(float z[], const float x[], const float y[], int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x[i] - y[i];
}
/*- End of function --------------------------------------------------------*/
#if defined(__GNUC__) && defined(G722_1_USE_SSE2)
void vec_mulf(float z[], const float x[], const float y[], int n)
{
int i;
__m128 n1;
__m128 n2;
__m128 n3;
if ((i = n & ~3))
{
for (i -= 4; i >= 0; i -= 4)
{
n1 = _mm_loadu_ps(x + i);
n2 = _mm_loadu_ps(y + i);
n3 = _mm_mul_ps(n1, n2);
_mm_storeu_ps(z + i, n3);
}
}
/* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */
switch (n & 3)
{
case 3:
z[n - 3] = x[n - 3]*y[n - 3];
case 2:
z[n - 2] = x[n - 2]*y[n - 2];
case 1:
z[n - 1] = x[n - 1]*y[n - 1];
}
}
#else
void vec_mulf(float z[], const float x[], const float y[], int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x[i]*y[i];
}
#endif
/*- End of function --------------------------------------------------------*/
#if defined(__GNUC__) && defined(G722_1_USE_SSE2)
float vec_dot_prodf(const float x[], const float y[], int n)
{
int i;
float z;
__m128 n1;
__m128 n2;
__m128 n3;
__m128 n4;
z = 0.0f;
if ((i = n & ~3))
{
n4 = _mm_setzero_ps(); //sets sum to zero
for (i -= 4; i >= 0; i -= 4)
{
n1 = _mm_loadu_ps(x + i);
n2 = _mm_loadu_ps(y + i);
n3 = _mm_mul_ps(n1, n2);
n4 = _mm_add_ps(n4, n3);
}
n4 = _mm_add_ps(_mm_movehl_ps(n4, n4), n4);
n4 = _mm_add_ss(_mm_shuffle_ps(n4, n4, 1), n4);
_mm_store_ss(&z, n4);
}
/* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */
switch (n & 3)
{
case 3:
z += x[n - 3]*y[n - 3];
case 2:
z += x[n - 2]*y[n - 2];
case 1:
z += x[n - 1]*y[n - 1];
}
return z;
}
#else
float vec_dot_prodf(const float x[], const float y[], int n)
{
int i;
float z;
z = 0.0f;
for (i = 0; i < n; i++)
z += x[i]*y[i];
return z;
}
/*- End of function --------------------------------------------------------*/
#endif
void vec_scalar_mulf(float z[], const float x[], float y, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x[i]*y;
}
/*- End of function --------------------------------------------------------*/
void vec_scaled_addf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x[i]*x_scale + y[i]*y_scale;
}
/*- End of function --------------------------------------------------------*/
void vec_scaled_subf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x[i]*x_scale - y[i]*y_scale;
}
/*- End of function --------------------------------------------------------*/
#endif
/*- End of file ------------------------------------------------------------*/
+32
View File
@@ -0,0 +1,32 @@
/*
* g722_1 - a library for the G.722.1 and Annex C codecs
*
* utilities.h
*
* Copyright (C) 2006 Steve Underwood
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#if !defined(__UTILITIES_H__)
#define __UTILITIES_H__
/* Prototypes for some general purpose signal and vector functions */
#if defined(G722_1_USE_FIXED_POINT)
void vec_copyi16(int16_t z[], const int16_t x[], int n);
int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n);
#else
void vec_copyf(float z[], const float x[], int n);
void vec_zerof(float z[], int n);
void vec_subf(float z[], const float x[], const float y[], int n);
void vec_scalar_mulf(float z[], const float x[], float y, int n);
void vec_mulf(float z[], const float x[], const float y[], int n);
float vec_dot_prodf(const float x[], const float y[], int n);
void vec_scaled_addf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n);
void vec_scaled_subf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n);
#endif
#endif
/*- End of file ------------------------------------------------------------*/
-2
View File
@@ -15,8 +15,6 @@
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
## $Id: Makefile.am,v 1.2 2008/09/20 16:31:19 steveu Exp $
SUBDIRS = itu local
-2
View File
@@ -15,8 +15,6 @@
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
## $Id: Makefile.am,v 1.3 2008/09/23 16:03:04 steveu Exp $
SUBDIRS =
@@ -15,8 +15,6 @@
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
## $Id: Makefile.am,v 1.3 2008/09/24 16:12:52 steveu Exp $
SUBDIRS =
+2 -4
View File
@@ -15,8 +15,6 @@
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
## $Id: Makefile.am,v 1.4 2008/10/19 04:05:02 steveu Exp $
AM_CFLAGS = $(COMP_VENDOR_CFLAGS)
AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS)
@@ -33,8 +31,8 @@ LIBDIR = -L$(top_builddir)/src
noinst_PROGRAMS = g722_1_tests
noinst_HEADERS = itu_bit_stream.c \
noinst_HEADERS = g192_bit_stream.h \
timing.h
g722_1_tests_SOURCES = g722_1_tests.c itu_bit_stream.c
g722_1_tests_SOURCES = g722_1_tests.c g192_bit_stream.c
g722_1_tests_LDADD = $(LIBDIR) -lg722_1
+177
View File
@@ -0,0 +1,177 @@
/*
* broadvoice - a library for the BroadVoice 16 and 32 codecs
*
* g192_bit_stream.c
*
* Copyright 2008-2009 Steve Underwood <steveu@coppice.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*! \file */
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <audiofile.h>
#include "g192_bit_stream.h"
#if !defined(FALSE)
#define FALSE 0
#endif
#if !defined(TRUE)
#define TRUE (!FALSE)
#endif
enum
{
G192_FRAME_ERASURE = 0x6B20,
G192_FRAME_SYNC_1 = 0x6B21,
G192_FRAME_SYNC_2 = 0x6B22,
G192_FRAME_SYNC_3 = 0x6B23,
G192_FRAME_SYNC_4 = 0x6B24,
G192_FRAME_SYNC_5 = 0x6B25,
G192_FRAME_SYNC_6 = 0x6B26,
G192_FRAME_SYNC_7 = 0x6B27,
G192_FRAME_SYNC_8 = 0x6B28,
G192_FRAME_SYNC_9 = 0x6B29,
G192_FRAME_SYNC_10 = 0x6B2A,
G192_FRAME_SYNC_11 = 0x6B2B,
G192_FRAME_SYNC_12 = 0x6B2C,
G192_FRAME_SYNC_13 = 0x6B2D,
G192_FRAME_SYNC_14 = 0x6B2E,
G192_FRAME_SYNC_15 = 0x6B2F,
G192_HARD_ZERO = 0x7F,
G192_INDETERMINATE = 0x00,
G192_HARD_ONE = 0x81
};
int itu_codec_bitstream_write(const uint8_t out_data[],
int number_of_bits,
int mode,
FILE *fp_bitstream)
{
int i;
int j;
int bit_count;
int number_of_bytes;
uint8_t packed_word;
int16_t out_array[2 + number_of_bits + 7];
number_of_bytes = (number_of_bits + 7)/8;
if (mode == ITU_CODEC_BITSTREAM_PACKED)
{
return fwrite(out_data, 1, number_of_bytes, fp_bitstream);
}
j = 0;
out_array[j++] = G192_FRAME_SYNC_1;
out_array[j++] = number_of_bits;
for (i = 0; i < number_of_bytes; i++)
{
packed_word = out_data[i];
for (bit_count = 7; bit_count >= 0; bit_count--)
out_array[j++] = ((packed_word >> bit_count) & 1) ? G192_HARD_ONE : G192_HARD_ZERO;
}
return fwrite(out_array, sizeof(int16_t), number_of_bits + 2, fp_bitstream);
}
/*- End of function --------------------------------------------------------*/
int itu_codec_bitstream_read(uint8_t in_data[],
int16_t *erasure,
int number_of_bits,
int mode,
FILE *fp_bitstream)
{
int i;
int j;
int bit_pos;
int nsamp;
int limit;
int rem;
int len;
int erased_frame;
int16_t packed_word;
int16_t bit;
int16_t in_array[2 + number_of_bits];
*erasure = FALSE;
if (mode == ITU_CODEC_BITSTREAM_PACKED)
{
nsamp = fread(in_data, 1, number_of_bits/8, fp_bitstream);
if (nsamp <= 0)
return -1;
return nsamp*8;
}
nsamp = fread(in_array, sizeof(int16_t), 2, fp_bitstream);
if (nsamp < 2)
return -1;
if (in_array[0] < G192_FRAME_ERASURE || in_array[0] > G192_FRAME_SYNC_15)
{
*erasure = TRUE;
return 0;
}
erased_frame = (in_array[0] == G192_FRAME_ERASURE);
len = in_array[1];
if (len > number_of_bits)
{
*erasure = TRUE;
return 0;
}
nsamp = fread(in_array, sizeof(int16_t), len, fp_bitstream);
if (nsamp != len)
{
*erasure = TRUE;
return nsamp;
}
limit = (nsamp + 7)/8;
for (i = 0, j = 0; i < limit; i++)
{
packed_word = 0;
rem = (i == (limit - 1)) ? (limit*8 - nsamp) : 0;
for (bit_pos = 7; bit_pos >= rem; bit_pos--)
{
bit = in_array[j++];
if (bit >= 0x0001 && bit <= G192_HARD_ZERO)
{
/* Its a zero */
}
else if (bit >= G192_HARD_ONE && bit <= 0x00FF)
{
/* Its a one */
packed_word |= (1 << bit_pos);
}
else
{
/* Bad bit */
*erasure = 1;
}
}
in_data[i] = packed_word;
}
if (erased_frame)
*erasure = TRUE;
return nsamp;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

Some files were not shown because too many files have changed in this diff Show More