mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-24 13:12:03 +00:00
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:
+3
-3
@@ -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
@@ -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) ||
|
||||
|
||||
@@ -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
|
||||
@@ -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=""$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\";"$(ProjectDir)..\src\include""
|
||||
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=""$(ProjectDir)..\..\..\$(ConfigurationName)";"$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\$(ConfigurationName)""
|
||||
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=""$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\";"$(ProjectDir)..\src\include""
|
||||
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=""$(ProjectDir)..\..\..\$(ConfigurationName)";"$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\$(ConfigurationName)""
|
||||
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=""$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\";"$(ProjectDir)..\src\include""
|
||||
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=""$(ProjectDir)..\..\..\$(PlatformName)\$(ConfigurationName)";"$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\$(PlatformName)\$(ConfigurationName)""
|
||||
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=""$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\";"$(ProjectDir)..\src\include""
|
||||
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=""$(ProjectDir)..\..\..\$(PlatformName)\$(ConfigurationName)";"$(ProjectDir)..\..\..\src\mod\languages\mod_lua\lua\$(PlatformName)\$(ConfigurationName)""
|
||||
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>
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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 */
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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 \
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"]
|
||||
)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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:
|
||||
*/
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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=""C:\Program Files\libsng_isdn\include";"C:\Program Files\libsng_isdn\include\sng_isdn";../../include;"C:\Program Files\Sangoma\include""
|
||||
AdditionalIncludeDirectories=""C:\Program Files\sangoma\sng_isdn\include";../../include;"C:\Program Files\Sangoma\include""
|
||||
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=""$(OutDir)";"C:\Program Files\libsng_isdn\lib";"C:\Program Files\Sangoma\api\lib\x86""
|
||||
AdditionalLibraryDirectories=""$(OutDir)";"C:\Program Files\sangoma\sng_isdn\lib";"C:\Program Files\Sangoma\api\lib\x86""
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
RandomizedBaseAddress="1"
|
||||
@@ -116,10 +117,11 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""C:\Program Files\sangoma\sng_isdn\include";../../include;"C:\Program Files\Sangoma\include""
|
||||
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=""$(OutDir)";"C:\Program Files\sangoma\sng_isdn\lib";"C:\Program Files\Sangoma\api\lib\x86""
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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])
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 >$@
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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 --------------------------------------------------------*/
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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] =
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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 --------------------------------------------------------*/
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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_)
|
||||
|
||||
@@ -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_)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,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 ------------------------------------------------------------*/
|
||||
|
||||
@@ -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 ------------------------------------------------------------*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ------------------------------------------------------------*/
|
||||
@@ -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 ------------------------------------------------------------*/
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 =
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user