diff --git a/Freeswitch.2008.express.sln b/Freeswitch.2008.express.sln
index 672406bda2..d9cb441e2f 100644
--- a/Freeswitch.2008.express.sln
+++ b/Freeswitch.2008.express.sln
@@ -1,6 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
+# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchConsole", "w32\Console\FreeSwitchConsole.2008.vcproj", "{1AF3A893-F7BE-43DD-B697-8AB2397C0D67}"
ProjectSection(ProjectDependencies) = postProject
{202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
@@ -11,6 +11,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchCoreLib", "w32\Li
ProjectSection(ProjectDependencies) = postProject
{8D04B550-D240-4A44-8A18-35DA3F7038D9} = {8D04B550-D240-4A44-8A18-35DA3F7038D9}
{89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C}
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}
{F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3}
{03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD}
{F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
@@ -1641,6 +1642,7 @@ Global
{D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|Win32.Build.0 = Release|Win32
{D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x64.ActiveCfg = Release|Win32
{D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|Win32.Build.0 = Debug|Win32
{D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64.ActiveCfg = Debug|Win32
{D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64.Build.0 = Debug|Win32
{D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|Win32.ActiveCfg = Release|Win32
@@ -2046,6 +2048,7 @@ Global
{B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|Win32.Build.0 = Debug|Win32
{B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|x64.ActiveCfg = Debug|Win32
{B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|Win32.ActiveCfg = Release|Win32
+ {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|Win32.Build.0 = Release|Win32
{B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|x64.ActiveCfg = Release|Win32
{9778F1C0-09BC-4698-8EBC-BD982247209A}.All|Win32.ActiveCfg = Release|Win32
{9778F1C0-09BC-4698-8EBC-BD982247209A}.All|x64.ActiveCfg = Release|x64
diff --git a/Freeswitch.2008.sln b/Freeswitch.2008.sln
index 01a4cf43c1..e171ffe418 100644
--- a/Freeswitch.2008.sln
+++ b/Freeswitch.2008.sln
@@ -381,6 +381,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchCoreLib", "w32\Li
ProjectSection(ProjectDependencies) = postProject
{8D04B550-D240-4A44-8A18-35DA3F7038D9} = {8D04B550-D240-4A44-8A18-35DA3F7038D9}
{89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C}
+ {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}
{F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3}
{03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD}
{F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF}
diff --git a/Freeswitch.2010.sln b/Freeswitch.2010.sln
index 186969891a..edee701d51 100644
--- a/Freeswitch.2010.sln
+++ b/Freeswitch.2010.sln
@@ -707,6 +707,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_distributor", "src\mod\
EndProject
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Setup", "w32\Setup\Setup.wixproj", "{47213370-B933-487D-9F45-BCA26D7E2B6F}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_pt", "src\mod\say\mod_say_pt\mod_say_pt.2010.vcxproj", "{7C22BDFF-CC09-400C-8A09-660733980028}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
All|Win32 = All|Win32
@@ -3619,6 +3621,23 @@ Global
{47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x64 Setup.Build.0 = Release|x64
{47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x86 Setup.ActiveCfg = Release|x86
{47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x86 Setup.Build.0 = Release|x86
+ {7C22BDFF-CC09-400C-8A09-660733980028}.All|Win32.ActiveCfg = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.All|x64.ActiveCfg = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.All|x64.Build.0 = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.All|x64 Setup.ActiveCfg = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.All|x86 Setup.ActiveCfg = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|Win32.Build.0 = Debug|Win32
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x64.ActiveCfg = Debug|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x64.Build.0 = Debug|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x64 Setup.ActiveCfg = Debug|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x86 Setup.ActiveCfg = Debug|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Release|Win32.ActiveCfg = Release|Win32
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Release|Win32.Build.0 = Release|Win32
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x64.ActiveCfg = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x64.Build.0 = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x64 Setup.ActiveCfg = Release|x64
+ {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x86 Setup.ActiveCfg = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -3769,6 +3788,7 @@ Global
{A4B122CF-5196-476B-8C0E-D8BD59AC3C14} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
{B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
{0382E8FD-CFDC-41C0-8B03-792C7C84FC31} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
+ {7C22BDFF-CC09-400C-8A09-660733980028} = {6CD61A1D-797C-470A-BE08-8C31B68BB336}
{3B08FEFD-4D3D-4C16-BA94-EE83509E32A0} = {57D119DC-484F-420F-B9E9-8589FD9A8DF8}
{7BFD517E-7F8F-4A40-A78E-8D3632738227} = {57D119DC-484F-420F-B9E9-8589FD9A8DF8}
{6374D55C-FABE-4A02-9CF1-4145308A56C5} = {57D119DC-484F-420F-B9E9-8589FD9A8DF8}
diff --git a/Makefile.am b/Makefile.am
index e701494a2e..df1ee2e0d0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -102,6 +102,7 @@ CORE_CFLAGS += -I$(switch_srcdir)/libs/pcre
CORE_CFLAGS += -I$(switch_srcdir)/libs/speex/include -Ilibs/speex/include
CORE_CFLAGS += -I$(switch_srcdir)/libs/srtp/include
CORE_CFLAGS += -I$(switch_srcdir)/libs/srtp/crypto/include -Ilibs/srtp/crypto/include
+CORE_CFLAGS += -I$(switch_srcdir)/libs/spandsp/src -I$(switch_srcdir)/libs/tiff-3.8.2/libtiff
CORE_LIBS = libs/apr-util/libaprutil-1.la libs/apr/libapr-1.la
CORE_LIBS += libs/sqlite/libsqlite3.la libs/pcre/libpcre.la libs/speex/libspeex/libspeexdsp.la
@@ -249,7 +250,8 @@ libfreeswitch_la_SOURCES = \
libs/miniupnpc/minissdpc.c \
libs/miniupnpc/upnperrors.c \
libs/libnatpmp/natpmp.c \
- libs/libnatpmp/getgateway.c
+ libs/libnatpmp/getgateway.c\
+ libs/spandsp/src/plc.c
if ENABLE_CPP
libfreeswitch_la_SOURCES += src/switch_cpp.cpp
@@ -274,7 +276,8 @@ bin_PROGRAMS = freeswitch fs_cli fs_ivrd tone2wav fs_encode
##
## fs_cli ()
##
-fs_cli_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c libs/esl/src/esl_threadmutex.c libs/esl/fs_cli.c libs/esl/src/esl_json.c
+fs_cli_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c \
+ libs/esl/src/esl_threadmutex.c libs/esl/fs_cli.c libs/esl/src/esl_json.c libs/esl/src/esl_buffer.c
fs_cli_CFLAGS = $(AM_CFLAGS) -I$(switch_srcdir)/libs/esl/src/include
fs_cli_LDFLAGS = $(AM_LDFLAGS) -lpthread $(ESL_LDFLAGS) -lm
@@ -302,7 +305,8 @@ tone2wav_LDADD = libfreeswitch.la
##
## fs_ivrd ()
##
-fs_ivrd_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c libs/esl/src/esl_threadmutex.c libs/esl/ivrd.c libs/esl/src/esl_json.c
+fs_ivrd_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c \
+ libs/esl/src/esl_threadmutex.c libs/esl/ivrd.c libs/esl/src/esl_json.c libs/esl/src/esl_buffer.c
fs_ivrd_CFLAGS = $(AM_CFLAGS) -I$(switch_srcdir)/libs/esl/src/include
fs_ivrd_LDFLAGS = $(AM_LDFLAGS) -lpthread $(ESL_LDFLAGS) -lm
diff --git a/build/modules.conf.in b/build/modules.conf.in
index 13e655672c..69d90a8dd4 100644
--- a/build/modules.conf.in
+++ b/build/modules.conf.in
@@ -73,6 +73,8 @@ endpoints/mod_loopback
#event_handlers/mod_event_multicast
event_handlers/mod_event_socket
event_handlers/mod_cdr_csv
+event_handlers/mod_cdr_sqlite
+#event_handlers/mod_cdr_pg_csv
#event_handlers/mod_radius_cdr
#event_handlers/mod_erlang_event
formats/mod_native_file
@@ -100,6 +102,7 @@ say/mod_say_en
#say/mod_say_fr
#say/mod_say_it
#say/mod_say_nl
+#say/mod_say_pt
say/mod_say_ru
#say/mod_say_zh
#say/mod_say_hu
diff --git a/conf/autoload_configs/cdr_pg_csv.conf.xml b/conf/autoload_configs/cdr_pg_csv.conf.xml
index ec62053190..2f2efa9b26 100644
--- a/conf/autoload_configs/cdr_pg_csv.conf.xml
+++ b/conf/autoload_configs/cdr_pg_csv.conf.xml
@@ -1,23 +1,21 @@
+
+
+
+
+
+
+
-
+
+
+
-
-
-
-
-
-
- INSERT INTO cdr VALUES ("${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}", "${accountcode}");
"${local_ip_v4}","${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}","${accountcode}","${read_codec}","${write_codec}","${sip_hangup_disposition}","${ani}"
- "${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}", "${accountcode}","${read_codec}","${write_codec}","${sip_user_agent}","${call_clientcode}","${sip_rtp_rxstat}","${sip_rtp_txstat}","${sofia_record_file}"
- "${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}","${accountcode}","${read_codec}","${write_codec}","${sip_user_agent}","${sip_p_rtp_stat}"
- "${accountcode}","${caller_id_number}","${destination_number}","${context}","${caller_id}","${channel_name}","${bridge_channel}","${last_app}","${last_arg}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}","${billsec}","${hangup_cause}","${amaflags}","${uuid}","${userfield}"
-
diff --git a/conf/autoload_configs/cdr_sqlite.conf.xml b/conf/autoload_configs/cdr_sqlite.conf.xml
new file mode 100644
index 0000000000..872c04c4fb
--- /dev/null
+++ b/conf/autoload_configs/cdr_sqlite.conf.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}",${duration},${billsec},"${hangup_cause}","${uuid}","${bleg_uuid}","${accountcode}"
+
+
diff --git a/conf/autoload_configs/modules.conf.xml b/conf/autoload_configs/modules.conf.xml
index 118d7c4d81..51c62f2059 100644
--- a/conf/autoload_configs/modules.conf.xml
+++ b/conf/autoload_configs/modules.conf.xml
@@ -19,6 +19,7 @@
+
diff --git a/conf/autoload_configs/switch.conf.xml b/conf/autoload_configs/switch.conf.xml
index 896dd0e712..fba809ba2c 100644
--- a/conf/autoload_configs/switch.conf.xml
+++ b/conf/autoload_configs/switch.conf.xml
@@ -23,7 +23,13 @@
-
+
diff --git a/conf/directory/default/default.xml b/conf/directory/default/default.xml
index 5db60112dc..aa138f18d9 100644
--- a/conf/directory/default/default.xml
+++ b/conf/directory/default/default.xml
@@ -1,7 +1,7 @@
@@ -390,15 +397,10 @@
-
-
-
-
-
@@ -409,10 +411,7 @@
-
-
-
@@ -425,20 +424,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/docs/phrase/phrase_es_ES.xml b/docs/phrase/phrase_es_ES.xml
new file mode 100644
index 0000000000..ad99c1bf73
--- /dev/null
+++ b/docs/phrase/phrase_es_ES.xml
@@ -0,0 +1,994 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/phrase/phrase_es_MX.xml b/docs/phrase/phrase_es_MX.xml
new file mode 100644
index 0000000000..527f8c3c89
--- /dev/null
+++ b/docs/phrase/phrase_es_MX.xml
@@ -0,0 +1,993 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/phrase/phrase_pt_BR.xml b/docs/phrase/phrase_pt_BR.xml
new file mode 100644
index 0000000000..9cc400c76b
--- /dev/null
+++ b/docs/phrase/phrase_pt_BR.xml
@@ -0,0 +1,987 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/phrase/phrase_pt_PT.xml b/docs/phrase/phrase_pt_PT.xml
new file mode 100644
index 0000000000..a0e59deb85
--- /dev/null
+++ b/docs/phrase/phrase_pt_PT.xml
@@ -0,0 +1,987 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/freeswitch.spec b/freeswitch.spec
index ceacfbafb2..05401b8e8a 100644
--- a/freeswitch.spec
+++ b/freeswitch.spec
@@ -379,7 +379,7 @@ ENDPOINTS_MODULES="endpoints/mod_dingaling endpoints/mod_loopback ../../libs/fre
# Event Handlers
#
######################################################################################################################
-EVENT_HANDLERS_MODULES="event_handlers/mod_cdr_csv event_handlers/mod_event_socket event_handlers/mod_event_multicast"
+EVENT_HANDLERS_MODULES="event_handlers/mod_cdr_csv event_handlers/mod_cdr_sqlite event_handlers/mod_event_socket event_handlers/mod_event_multicast"
######################################################################################################################
#
# File and Audio Format Handlers
@@ -620,6 +620,7 @@ fi
%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/callcenter.conf.xml
%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/cdr_csv.conf.xml
%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/cdr_pg_csv.conf.xml
+%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/cdr_sqlite.conf.xml
%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/cidlookup.conf.xml
%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/conference.conf.xml
%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/console.conf.xml
@@ -746,6 +747,7 @@ fi
%{prefix}/mod/mod_bv.so*
%{prefix}/mod/mod_callcenter.so*
%{prefix}/mod/mod_cdr_csv.so*
+%{prefix}/mod/mod_cdr_sqlite.so*
%{prefix}/mod/mod_celt.so*
%{prefix}/mod/mod_cidlookup.so*
%{prefix}/mod/mod_cluechoo.so*
diff --git a/libs/esl/Makefile b/libs/esl/Makefile
index a180406bda..ab50bac4d9 100644
--- a/libs/esl/Makefile
+++ b/libs/esl/Makefile
@@ -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
diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c
index 73bee7ab5e..254365b3c9 100644
--- a/libs/esl/fs_cli.c
+++ b/libs/esl/fs_cli.c
@@ -657,7 +657,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"
@@ -693,7 +693,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) ||
diff --git a/libs/esl/lua/esl_lua.2008.sln b/libs/esl/lua/esl_lua.2008.sln
new file mode 100644
index 0000000000..cdfbd44ab7
--- /dev/null
+++ b/libs/esl/lua/esl_lua.2008.sln
@@ -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
diff --git a/libs/esl/lua/esl_lua.2008.vcproj b/libs/esl/lua/esl_lua.2008.vcproj
new file mode 100644
index 0000000000..38111c8580
--- /dev/null
+++ b/libs/esl/lua/esl_lua.2008.vcproj
@@ -0,0 +1,351 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/esl/perl/ESL/Dispatch.pm b/libs/esl/perl/ESL/Dispatch.pm
index 1d21934046..d1712d1cfc 100644
--- a/libs/esl/perl/ESL/Dispatch.pm
+++ b/libs/esl/perl/ESL/Dispatch.pm
@@ -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");
}
diff --git a/libs/esl/src/esl.2008.vcproj b/libs/esl/src/esl.2008.vcproj
index 101348dd59..89daa17d9e 100644
--- a/libs/esl/src/esl.2008.vcproj
+++ b/libs/esl/src/esl.2008.vcproj
@@ -290,6 +290,10 @@
RelativePath=".\esl.c"
>
+
+
@@ -316,6 +320,10 @@
RelativePath=".\include\esl.h"
>
+
+
diff --git a/libs/esl/src/esl.2010.vcxproj b/libs/esl/src/esl.2010.vcxproj
index b215fe4bc8..fd5e3a8353 100644
--- a/libs/esl/src/esl.2010.vcxproj
+++ b/libs/esl/src/esl.2010.vcxproj
@@ -128,6 +128,7 @@
+
@@ -135,6 +136,7 @@
+
diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c
index 4a02a8fe38..f5bab62fcb 100644
--- a/libs/esl/src/esl.c
+++ b/libs/esl/src/esl.c
@@ -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;
@@ -1177,7 +1194,6 @@ ESL_DECLARE(esl_status_t) esl_send_recv_timed(esl_handle_t *handle, const char *
return ESL_FAIL;
}
- esl_event_safe_destroy(&handle->last_event);
esl_event_safe_destroy(&handle->last_sr_event);
*handle->last_sr_reply = '\0';
diff --git a/libs/esl/src/esl_buffer.c b/libs/esl/src/esl_buffer.c
new file mode 100644
index 0000000000..8032169fe3
--- /dev/null
+++ b/libs/esl/src/esl_buffer.c
@@ -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:
+ */
diff --git a/libs/esl/src/include/esl.h b/libs/esl/src/include/esl.h
index 9f28c3d925..99ab53ae95 100644
--- a/libs/esl/src/include/esl.h
+++ b/libs/esl/src/include/esl.h
@@ -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
+#include
/*! \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 */
diff --git a/libs/esl/src/include/esl_buffer.h b/libs/esl/src/include/esl_buffer.h
new file mode 100644
index 0000000000..c7901e4ede
--- /dev/null
+++ b/libs/esl/src/include/esl_buffer.h
@@ -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:
+ */
diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am
index af26f7f2af..2ab5c29e18 100644
--- a/libs/freetdm/Makefile.am
+++ b/libs/freetdm/Makefile.am
@@ -49,6 +49,7 @@ if HAVE_SNG_ISDN
INCS += -I/usr/include/sng_isdn
endif
+# we needed to separate CFLAGS in FTDM_COMPAT_CFLAGS and FTDM_CFLAGS due to -c99 which causes problems with wanpipe headers
FTDM_COMPAT_CFLAGS = $(INCS) -DFTDM_CONFIG_DIR=\"@confdir@\" -DFTDM_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_COMPAT_CFLAGS@ @DEFS@
FTDM_CFLAGS = $(INCS) -DFTDM_CONFIG_DIR=\"@confdir@\" -DFTDM_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_CFLAGS@ @DEFS@
COMPILE = $(CC) $(FTDM_CFLAGS)
@@ -72,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 \
@@ -183,8 +185,8 @@ ftmod_analog_em_la_LIBADD = libfreetdm.la
if HAVE_LIBSANGOMA
mod_LTLIBRARIES += ftmod_wanpipe.la
ftmod_wanpipe_la_SOURCES = $(SRC)/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
-#some structures within Wanpipe drivers are not c99 compatible, so we need to compile ftmod_wanpipe
-#without c99 flags
+# some structures within Wanpipe drivers are not c99 compatible, so we need to compile ftmod_wanpipe
+# without c99 flags, use FTDM_COMPAT_CFLAGS instead
ftmod_wanpipe_la_CFLAGS = $(AM_CFLAGS) $(FTDM_COMPAT_CFLAGS) -D__LINUX__ -I/usr/include/wanpipe
ftmod_wanpipe_la_LDFLAGS = -shared -module -avoid-version -lsangoma
ftmod_wanpipe_la_LIBADD = libfreetdm.la
diff --git a/libs/freetdm/conf/freetdm.conf.xml b/libs/freetdm/conf/freetdm.conf.xml
index 63a3ea62cd..43197af4bc 100644
--- a/libs/freetdm/conf/freetdm.conf.xml
+++ b/libs/freetdm/conf/freetdm.conf.xml
@@ -12,31 +12,81 @@ with the signaling protocols that you can run on top of your I/O interfaces.
+
-
+
-
-
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/libs/freetdm/conf/m3ua.conf b/libs/freetdm/conf/m3ua.conf
deleted file mode 100644
index e3eeed3a4a..0000000000
--- a/libs/freetdm/conf/m3ua.conf
+++ /dev/null
@@ -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
-
-
diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac
index 592dfd82a3..a070e994a3 100644
--- a/libs/freetdm/configure.ac
+++ b/libs/freetdm/configure.ac
@@ -82,7 +82,7 @@ sun)
fi
;;
*)
- COMP_VENDOR_COMPAT_CFLAGS="-Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes"
+ COMP_VENDOR_COMPAT_CFLAGS="-Wall -Werror -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes"
COMP_VENDOR_CFLAGS="-std=c99 $COMP_VENDOR_COMPAT_CFLAGS"
;;
esac
@@ -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"]
)
diff --git a/libs/freetdm/configure.gnu b/libs/freetdm/configure.gnu
index 5785ffc0e7..d00cd18473 100755
--- a/libs/freetdm/configure.gnu
+++ b/libs/freetdm/configure.gnu
@@ -1,3 +1,3 @@
#! /bin/sh
-./configure "$@" --with-pic
-
+srcpath=$(dirname $0 2>/dev/null ) || srcpath="."
+$srcpath/configure "$@" --with-pic
diff --git a/libs/freetdm/docs/locking.txt b/libs/freetdm/docs/locking.txt
new file mode 100644
index 0000000000..851d045b41
--- /dev/null
+++ b/libs/freetdm/docs/locking.txt
@@ -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.
+
+
diff --git a/libs/freetdm/docs/sigstatus.txt b/libs/freetdm/docs/sigstatus.txt
new file mode 100644
index 0000000000..10561bfb5b
--- /dev/null
+++ b/libs/freetdm/docs/sigstatus.txt
@@ -0,0 +1,59 @@
+FreeTDM can both notify and set signaling status changes in the different protocols thru a unified interface. More
+specific details on the C data types and function prototypes are found in freetdm.h
+
+The API provides the following functions and data types to do it:
+
+The signaling status in any channel/span is represented thru ftdm_signaling_status_t
+
+ /* The signaling link is down (no d-chans up in the span/group, MFC-R2 bit pattern unidentified) */
+ FTDM_SIG_STATE_DOWN,
+ /* The signaling link is suspended (MFC-R2 bit pattern blocked, PRI maintenance, ss7 blocked?) */
+ FTDM_SIG_STATE_SUSPENDED,
+ /* The signaling link is ready and calls can be placed (ie: d-chan up, MFC-R2 both rx and tx in IDLE) */
+ FTDM_SIG_STATE_UP,
+ /* Invalid status */
+ FTDM_SIG_STATE_INVALID
+
+Changes in the signaling status are notified to the user using the standard callback notification function provided
+during configuration using the sigevent type FTDM_SIGEVENT_SIGSTATUS_CHANGED which is sent when the line status changes.
+
+On startup the signalling status default is FTDM_SIG_STATE_DOWN, and no notification is provided until the state change,
+so applications must assume the status is down unless told otherwise.
+
+When ftdm_span_start is called, the signaling stack takes care of attempting to bring the status to UP
+but it will ultimately depend on the other side too.
+
+== Setting the signaling status ==
+
+Users can set the signaling status on a given channel/span thru FreeTDM the following API functions:
+
+ftdm_channel_set_sig_status
+ftdm_span_set_sig_status
+
+If the user calls ftdm_channel_set_sig_status(chan, FTDM_SIG_STATE_SUSPENDED), the signaling stack will try to set
+the status of the line to the one requested, if successful, it will result in a SIGEVENT_SIGSTATUS_CHANGED notification
+being sent with status FTDM_SIG_STATE_SUSPENDED.
+
+** MFC-R2 Signaling Notes **
+For MFC-R2, calling ftdm_span_start() results in setting the tx CAS bits to IDLE. However, if the rx bits are in BLOCKED state
+the signaling status will be reported as SUSPENDED.
+
+If the user calls ftdm_channel_set_sig_status(chan, SUSPENDED), the tx CAS bits will be set to BLOCKED and, if, the current rx bits
+are IDLE then a SIGEVENT_SIGSTATUS_CHANGED with state SUSPENDED will be sent. If the rx bits are already in blocked then no further
+SIGEVENT_SIGSTATUS_CHANGED notification is needed (because it was already sent when the rx bits were initially detected as BLOCKED).
+
+If the user calls ftdm_channel_set_sig_status(chan, UP), the tx CAS bits will be set to IDLE and, if, the current rx bits
+are IDLE, then SIGEVENT_SIGSTATUS_CHANGED with state UP will be sent. If the rx bits are BLOCKED, then no notification is
+sent at all until the rx bits change.
+
+Bottom line is, for MFC-R2, SIGEVENT_SIGSTATUS_CHANGED UP is only sent to the user when both the rx and tx bits are in IDLE, and
+SIGEVENT_SIGSTATUS_CHANGED SUSPENDED is only sent to the user when any of the rx or tx bits are in BLOCKED.
+
+== Getting the signaling status ==
+Users can get the signaling status on a given channel/span thru FreeTDM the following API functions:
+
+ftdm_channel_get_sig_status
+ftdm_span_get_sig_status
+
+The line status returned should be the same as the last time a SIGEVENT_SIGSTATUS_CHANGED was reported.
+
diff --git a/libs/freetdm/freetdm.2010.sln b/libs/freetdm/freetdm.2010.sln
index f4bd907a6d..44431d675a 100644
--- a/libs/freetdm/freetdm.2010.sln
+++ b/libs/freetdm/freetdm.2010.sln
@@ -119,10 +119,8 @@ Global
{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.ActiveCfg = Release|x64
{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.Build.0 = Release|x64
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.ActiveCfg = Debug|Win32
- {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.Build.0 = Debug|Win32
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|x64.ActiveCfg = Debug|x64
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.ActiveCfg = Release|Win32
- {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.Build.0 = Release|Win32
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|x64.ActiveCfg = Release|x64
{08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.ActiveCfg = Debug|Win32
{08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|x64.ActiveCfg = Debug|x64
diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c
index 38197bb2f0..7bbdef6dae 100755
--- a/libs/freetdm/mod_freetdm/mod_freetdm.c
+++ b/libs/freetdm/mod_freetdm/mod_freetdm.c
@@ -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->sigstatus;
+ 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:
{
@@ -2167,6 +2182,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
}
break;
case FTDM_SIGEVENT_PROGRESS:
+ case FTDM_SIGEVENT_RINGING:
{
if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) {
channel = switch_core_session_get_channel(session);
@@ -2182,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->sigstatus;
+ 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));
}
@@ -2706,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;
@@ -2777,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")) {
@@ -2837,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));
@@ -3525,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 [] || q931_pcap on|off [pcapfilename without suffix] || gains [] || dtmf on|off []"
+#define FT_SYNTAX "USAGE:\n" \
+"--------------------------------------------------------------------------------\n" \
+"ftdm list\n" \
+"ftdm start|stop \n" \
+"ftdm restart \n" \
+"ftdm dump []\n" \
+"ftdm sigstatus get|set [] [] []\n" \
+"ftdm trace []\n" \
+"ftdm notrace []\n" \
+"ftdm q931_pcap on|off [pcapfilename without suffix]\n" \
+"ftdm gains []\n" \
+"ftdm dtmf on|off []\n" \
+"--------------------------------------------------------------------------------\n"
SWITCH_STANDARD_API(ft_function)
{
char *mycmd = NULL, *argv[10] = { 0 };
@@ -3542,7 +3582,83 @@ SWITCH_STANDARD_API(ft_function)
goto end;
}
- if (!strcasecmp(argv[0], "dump")) {
+ if (!strcasecmp(argv[0], "sigstatus")) {
+ ftdm_span_t *span = NULL;
+ ftdm_signaling_status_t sigstatus;
+
+ if (argc < 3) {
+ stream->write_function(stream, "-ERR Usage: ftdm sigstatus get|set [] [] []\n");
+ goto end;
+ }
+ if (!strcasecmp(argv[1], "get") && argc < 3) {
+ stream->write_function(stream, "-ERR sigstatus get usage: get \n");
+ goto end;
+ }
+ if (!strcasecmp(argv[1], "set") && argc != 5) {
+ stream->write_function(stream, "-ERR sigstatus set usage: set |all \n");
+ goto end;
+ }
+
+ ftdm_span_find_by_name(argv[2], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+
+ if (!strcasecmp(argv[1], "get")) {
+ if (argc == 4) {
+ uint32_t chan_id = atol(argv[3]);
+ ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id);
+ if (!fchan) {
+ stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id);
+ goto end;
+ }
+
+ if ((FTDM_SUCCESS == ftdm_channel_get_sig_status(fchan, &sigstatus))) {
+ stream->write_function(stream, "channel %d signaling status: %s\n", chan_id, ftdm_signaling_status2str(sigstatus));
+ } else {
+ stream->write_function(stream, "-ERR failed to get channel sigstatus\n");
+ }
+ goto end;
+ } else {
+ if ((FTDM_SUCCESS == ftdm_span_get_sig_status(span, &sigstatus))) {
+ stream->write_function(stream, "signaling_status: %s\n", ftdm_signaling_status2str(sigstatus));
+ } else {
+ stream->write_function(stream, "-ERR failed to read span status: %s\n", ftdm_span_get_last_error(span));
+ }
+ }
+ goto end;
+ }
+ if (!strcasecmp(argv[1], "set")) {
+ sigstatus = ftdm_str2ftdm_signaling_status(argv[4]);
+
+ if (!strcasecmp(argv[3], "all")) {
+ if ((FTDM_SUCCESS == ftdm_span_set_sig_status(span, sigstatus))) {
+ stream->write_function(stream, "Signaling status of all channels from span %s set to %s\n",
+ ftdm_span_get_name(span), ftdm_signaling_status2str(sigstatus));
+ } else {
+ stream->write_function(stream, "-ERR failed to set span sigstatus to '%s'\n", ftdm_signaling_status2str(sigstatus));
+ }
+ goto end;
+ } else {
+ uint32_t chan_id = atol(argv[3]);
+ ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id);
+ if (!fchan) {
+ stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id);
+ goto end;
+ }
+
+ if ((FTDM_SUCCESS == ftdm_channel_set_sig_status(fchan, sigstatus))) {
+ stream->write_function(stream, "Signaling status of channel %d set to %s\n", chan_id,
+ ftdm_signaling_status2str(sigstatus));
+ } else {
+ stream->write_function(stream, "-ERR failed to set span sigstatus to '%s'\n", ftdm_signaling_status2str(sigstatus));
+ }
+ goto end;
+ }
+ }
+
+ } else if (!strcasecmp(argv[0], "dump")) {
if (argc < 2) {
stream->write_function(stream, "-ERR Usage: ftdm dump []\n");
goto end;
@@ -3922,6 +4038,28 @@ SWITCH_STANDARD_API(ft_function)
}
}
stream->write_function(stream, "+OK gains set to Rx %f and Tx %f\n", rxgain, txgain);
+ } else if (!strcasecmp(argv[0], "restart")) {
+ uint32_t chan_id = 0;
+ ftdm_channel_t *chan;
+ ftdm_span_t *span = NULL;
+ if (argc < 3) {
+ stream->write_function(stream, "-ERR Usage: ftdm restart \n");
+ goto end;
+ }
+ ftdm_span_find_by_name(argv[1], &span);
+ if (!span) {
+ stream->write_function(stream, "-ERR invalid span\n");
+ goto end;
+ }
+
+ chan_id = atoi(argv[2]);
+ chan = ftdm_span_get_channel(span, chan_id);
+ if (!chan) {
+ stream->write_function(stream, "-ERR Could not find chan\n");
+ goto end;
+ }
+ stream->write_function(stream, "Resetting channel %s:%s\n", argv[2], argv[3]);
+ ftdm_channel_reset(chan);
} else {
char *rply = ftdm_api_execute(cmd);
diff --git a/libs/freetdm/msvc/freetdm.2008.vcproj b/libs/freetdm/msvc/freetdm.2008.vcproj
index c72891e525..0539ff3f42 100644
--- a/libs/freetdm/msvc/freetdm.2008.vcproj
+++ b/libs/freetdm/msvc/freetdm.2008.vcproj
@@ -94,78 +94,6 @@
Name="VCPostBuildEventTool"
/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -452,6 +456,10 @@
RelativePath="..\src\ftdm_sched.c"
>
+
+
diff --git a/libs/freetdm/src/ftdm_call_utils.c b/libs/freetdm/src/ftdm_call_utils.c
index 69f2fb4fff..2b72f05b77 100644
--- a/libs/freetdm/src/ftdm_call_utils.c
+++ b/libs/freetdm/src/ftdm_call_utils.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
+ * Ricardo Barroetaveña
+ *
*/
#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;
+}
+
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index eaa25e3da5..21354c4442 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -57,11 +57,16 @@ struct tm *localtime_r(const time_t *clock, struct tm *result);
#define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000
#define FTDM_READ_TRACE_INDEX 0
#define FTDM_WRITE_TRACE_INDEX 1
+#define MAX_CALLIDS 6000
ftdm_time_t time_last_throttle_log = 0;
ftdm_time_t time_current_throttle_log = 0;
static ftdm_iterator_t *get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter);
+static ftdm_status_t ftdm_call_set_call_id(ftdm_channel_t *fchan, ftdm_caller_data_t *caller_data);
+static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data);
+static ftdm_status_t ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan);
+static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan);
static int time_is_init = 0;
@@ -235,6 +240,10 @@ static struct {
ftdm_span_t *spans;
ftdm_group_t *groups;
cpu_monitor_t cpu_monitor;
+
+ ftdm_caller_data_t *call_ids[MAX_CALLIDS+1];
+ ftdm_mutex_t *call_id_mutex;
+ uint32_t last_call_id;
} globals;
enum ftdm_enum_cpu_alarm_action_flags
@@ -259,9 +268,6 @@ FTDM_STR2ENUM(ftdm_str2ftdm_analog_start_type, ftdm_analog_start_type2str, ftdm_
FTDM_ENUM_NAMES(SIGNAL_NAMES, SIGNAL_STRINGS)
FTDM_STR2ENUM(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t, SIGNAL_NAMES, FTDM_SIGEVENT_INVALID)
-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(MDMF_TYPE_NAMES, MDMF_STRINGS)
FTDM_STR2ENUM(ftdm_str2ftdm_mdmf_type, ftdm_mdmf_type2str, ftdm_mdmf_type_t, MDMF_TYPE_NAMES, MDMF_INVALID)
@@ -271,6 +277,9 @@ FTDM_STR2ENUM(ftdm_str2ftdm_chan_type, ftdm_chan_type2str, ftdm_chan_type_t, CHA
FTDM_ENUM_NAMES(SIGNALING_STATUS_NAMES, SIGSTATUS_STRINGS)
FTDM_STR2ENUM(ftdm_str2ftdm_signaling_status, ftdm_signaling_status2str, ftdm_signaling_status_t, SIGNALING_STATUS_NAMES, FTDM_SIG_STATE_INVALID)
+FTDM_ENUM_NAMES(TRACE_DIR_NAMES, TRACE_DIR_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_trace_dir, ftdm_trace_dir2str, ftdm_trace_dir_t, TRACE_DIR_NAMES, FTDM_TRACE_INVALID)
+
FTDM_ENUM_NAMES(TON_NAMES, TON_STRINGS)
FTDM_STR2ENUM(ftdm_str2ftdm_ton, ftdm_ton2str, ftdm_ton_t, TON_NAMES, FTDM_TON_INVALID)
@@ -289,6 +298,12 @@ FTDM_STR2ENUM(ftdm_str2ftdm_bearer_cap, ftdm_bearer_cap2str, ftdm_bearer_cap_t,
FTDM_ENUM_NAMES(USER_LAYER1_PROT_NAMES, USER_LAYER1_PROT_STRINGS)
FTDM_STR2ENUM(ftdm_str2ftdm_usr_layer1_prot, ftdm_user_layer1_prot2str, ftdm_user_layer1_prot_t, USER_LAYER1_PROT_NAMES, FTDM_USER_LAYER1_PROT_INVALID)
+FTDM_ENUM_NAMES(CALLING_PARTY_CATEGORY_NAMES, CALLING_PARTY_CATEGORY_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_calling_party_category, ftdm_calling_party_category2str, ftdm_calling_party_category_t, CALLING_PARTY_CATEGORY_NAMES, FTDM_CPC_INVALID)
+
+FTDM_ENUM_NAMES(INDICATION_NAMES, INDICATION_STRINGS)
+FTDM_STR2ENUM(ftdm_str2channel_indication, ftdm_channel_indication2str, ftdm_channel_indication_t, INDICATION_NAMES, FTDM_CHANNEL_INDICATE_INVALID)
+
static ftdm_status_t ftdm_group_add_channels(ftdm_span_t* span, int currindex, const char* name);
static const char *cut_path(const char *in)
@@ -600,6 +615,9 @@ static ftdm_status_t ftdm_channel_destroy(ftdm_channel_t *ftdmchan)
ftdm_mutex_destroy(&ftdmchan->mutex);
ftdm_mutex_destroy(&ftdmchan->pre_buffer_mutex);
+ if (ftdmchan->state_completed_interrupt) {
+ ftdm_interrupt_destroy(&ftdmchan->state_completed_interrupt);
+ }
}
return FTDM_SUCCESS;
@@ -715,11 +733,28 @@ static void ftdm_span_add(ftdm_span_t *span)
FT_DECLARE(ftdm_status_t) ftdm_span_stop(ftdm_span_t *span)
{
- ftdm_status_t status = FTDM_FAIL;
- if (span->stop) {
- status = span->stop(span);
- span->stop = NULL;
+ ftdm_status_t status = FTDM_SUCCESS;
+
+ ftdm_mutex_lock(span->mutex);
+
+ if (!ftdm_test_flag(span, FTDM_SPAN_STARTED)) {
+ status = FTDM_EINVAL;
+ goto done;
}
+
+ if (!span->stop) {
+ status = FTDM_ENOSYS;
+ goto done;
+ }
+
+ status = span->stop(span);
+ if (FTDM_SUCCESS == status) {
+ ftdm_clear_flag(span, FTDM_SPAN_STARTED);
+ }
+
+done:
+ ftdm_mutex_unlock(span->mutex);
+
return status;
}
@@ -1007,6 +1042,8 @@ FT_DECLARE(ftdm_status_t) ftdm_span_add_channel(ftdm_span_t *span, ftdm_socket_t
}
ftdm_set_flag(new_chan, FTDM_CHANNEL_CONFIGURED | FTDM_CHANNEL_READY);
+ new_chan->state = FTDM_CHANNEL_STATE_DOWN;
+ new_chan->state_status = FTDM_STATE_STATUS_COMPLETED;
*chan = new_chan;
return FTDM_SUCCESS;
}
@@ -1076,10 +1113,43 @@ FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms, s
return FTDM_NOTIMPL;
}
+/* handle oob events and send the proper SIGEVENT signal to user, when applicable */
+static __inline__ ftdm_status_t ftdm_event_handle_oob(ftdm_event_t *event)
+{
+ ftdm_sigmsg_t sigmsg;
+ ftdm_status_t status = FTDM_SUCCESS;
+ ftdm_channel_t *fchan = event->channel;
+ ftdm_span_t *span = fchan->span;
+
+ memset(&sigmsg, 0, sizeof(sigmsg));
+ sigmsg.span_id = span->span_id;
+ sigmsg.chan_id = fchan->chan_id;
+ sigmsg.channel = fchan;
+ switch (event->enum_id) {
+ case FTDM_OOB_ALARM_CLEAR:
+ {
+ sigmsg.event_id = FTDM_SIGEVENT_ALARM_CLEAR;
+ ftdm_clear_flag_locked(fchan, FTDM_CHANNEL_IN_ALARM);
+ status = ftdm_span_send_signal(span, &sigmsg);
+ }
+ break;
+ case FTDM_OOB_ALARM_TRAP:
+ {
+ sigmsg.event_id = FTDM_SIGEVENT_ALARM_TRAP;
+ ftdm_set_flag_locked(fchan, FTDM_CHANNEL_IN_ALARM);
+ status = ftdm_span_send_signal(span, &sigmsg);
+ }
+ break;
+ default:
+ /* NOOP */
+ break;
+ }
+ return status;
+}
+
FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t **event)
{
ftdm_status_t status = FTDM_FAIL;
- ftdm_sigmsg_t sigmsg;
ftdm_assert_return(span->fio != NULL, FTDM_FAIL, "No I/O module attached to this span!\n");
if (!span->fio->next_event) {
@@ -1092,76 +1162,39 @@ FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t *
return status;
}
- /* before returning the event to the user we do some core operations with certain OOB events */
- memset(&sigmsg, 0, sizeof(sigmsg));
- sigmsg.span_id = span->span_id;
- sigmsg.chan_id = (*event)->channel->chan_id;
- sigmsg.channel = (*event)->channel;
- switch ((*event)->enum_id) {
- case FTDM_OOB_ALARM_CLEAR:
- {
- sigmsg.event_id = FTDM_SIGEVENT_ALARM_CLEAR;
- ftdm_clear_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM);
- ftdm_span_send_signal(span, &sigmsg);
- }
- break;
- case FTDM_OOB_ALARM_TRAP:
- {
- sigmsg.event_id = FTDM_SIGEVENT_ALARM_TRAP;
- ftdm_set_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM);
- ftdm_span_send_signal(span, &sigmsg);
- }
- break;
- default:
- /* NOOP */
- break;
+ status = ftdm_event_handle_oob(*event);
+ if (status != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "failed to handle event %d\n", **event);
}
-
return status;
}
FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm_event_t **event)
{
ftdm_status_t status = FTDM_FAIL;
- ftdm_sigmsg_t sigmsg;
ftdm_span_t *span = ftdmchan->span;
ftdm_assert_return(span->fio != NULL, FTDM_FAIL, "No I/O module attached to this span!\n");
+ ftdm_channel_lock(ftdmchan);
+
if (!span->fio->channel_next_event) {
ftdm_log(FTDM_LOG_ERROR, "channel_next_event method not implemented in module %s!", span->fio->name);
- return FTDM_NOTIMPL;
+ status = FTDM_NOTIMPL;
+ goto done;
}
status = span->fio->channel_next_event(ftdmchan, event);
if (status != FTDM_SUCCESS) {
- return status;
+ goto done;
}
- /* before returning the event to the user we do some core operations with certain OOB events */
- memset(&sigmsg, 0, sizeof(sigmsg));
- sigmsg.span_id = span->span_id;
- sigmsg.chan_id = (*event)->channel->chan_id;
- sigmsg.channel = (*event)->channel;
- switch ((*event)->enum_id) {
- case FTDM_OOB_ALARM_CLEAR:
- {
- sigmsg.event_id = FTDM_SIGEVENT_ALARM_CLEAR;
- ftdm_clear_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM);
- ftdm_span_send_signal(span, &sigmsg);
- }
- break;
- case FTDM_OOB_ALARM_TRAP:
- {
- sigmsg.event_id = FTDM_SIGEVENT_ALARM_TRAP;
- ftdm_set_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM);
- ftdm_span_send_signal(span, &sigmsg);
- }
- break;
- default:
- /* NOOP */
- break;
+ status = ftdm_event_handle_oob(*event);
+ if (status != FTDM_SUCCESS) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "failed to handle event %d\n", **event);
}
+done:
+ ftdm_channel_unlock(ftdmchan);
return status;
}
@@ -1329,236 +1362,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_add_token(ftdm_channel_t *ftdmchan, char
}
-FT_DECLARE(ftdm_status_t) ftdm_channel_complete_state(ftdm_channel_t *ftdmchan)
-{
- ftdm_channel_state_t state = ftdmchan->state;
-
- if (state == FTDM_CHANNEL_STATE_PROGRESS) {
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
- } else if (state == FTDM_CHANNEL_STATE_UP) {
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_ANSWERED);
- } else if (state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
- }
-
- return FTDM_SUCCESS;
-}
-
-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)
-{
- 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 (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
- 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\n",
- ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state));
- 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->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_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->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->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);
- } else {
- 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));
- }
-
- /* there is an inherent race here between set and check of the change flag but we do not care because
- * the flag should never last raised for more than a few ms for any state change */
- while (waitrq && waitms > 0) {
- /* give a chance to the signaling stack to process it */
- ftdm_mutex_unlock(ftdmchan->mutex);
-
- ftdm_sleep(10);
- waitms -= 10;
-
- ftdm_mutex_lock(ftdmchan->mutex);
-
- /* if the flag is no longer set, the state change was processed (or is being processed) */
- if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
- break;
- }
-
- /* if the state is no longer what we set, the state change was
- * obviously processed (and the current state change flag is for other state change) */
- if (ftdmchan->state != state) {
- break;
- }
- }
-
- if (waitms <= 0) {
- ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "state change from %s to %s was most likely not processed after aprox %dms\n",
- ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(state), DEFAULT_WAIT_TIME);
- }
-
- return ok ? FTDM_SUCCESS : FTDM_FAIL;
-}
-
FT_DECLARE(uint32_t) ftdm_group_get_id(const ftdm_group_t *group)
{
return group->group_id;
@@ -1690,6 +1493,33 @@ static ftdm_status_t __inline__ get_best_rated(ftdm_channel_t **fchan, ftdm_chan
return FTDM_SUCCESS;
}
+
+static uint32_t __inline__ rr_next(uint32_t last, uint32_t min, uint32_t max, ftdm_direction_t direction)
+{
+ uint32_t next = min;
+
+ ftdm_log(FTDM_LOG_DEBUG, "last = %d, min = %d, max = %d\n", last, min, max);
+
+ if (direction == FTDM_RR_DOWN) {
+ next = (last >= max) ? min : ++last;
+ } else {
+ next = (last <= min) ? max : --last;
+ }
+ return next;
+}
+
+
+FT_DECLARE(int) ftdm_channel_get_availability(ftdm_channel_t *ftdmchan)
+{
+ int availability = -1;
+ ftdm_channel_lock(ftdmchan);
+ if (ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_AV_RATE)) {
+ availability = ftdmchan->availability_rate;
+ }
+ ftdm_channel_unlock(ftdmchan);
+ return availability;
+}
+
FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
{
ftdm_status_t status = FTDM_FAIL;
@@ -1721,6 +1551,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_dir
if (direction == FTDM_TOP_DOWN) {
i = 0;
+ } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) {
+ i = rr_next(group->last_used_index, 0, group->chan_count - 1, direction);
} else {
i = group->chan_count-1;
}
@@ -1735,16 +1567,24 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_dir
if (request_voice_channel(check, ftdmchan, caller_data, direction)) {
status = FTDM_SUCCESS;
+ if (direction == FTDM_RR_UP || direction == FTDM_RR_DOWN) {
+ group->last_used_index = i;
+ }
break;
}
calculate_best_rate(check, &best_rated, &best_rate);
if (direction == FTDM_TOP_DOWN) {
- if (i >= group->chan_count) {
+ if (i >= (group->chan_count - 1)) {
break;
}
i++;
+ } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) {
+ if (check == best_rated) {
+ group->last_used_index = i;
+ }
+ i = rr_next(i, 0, group->chan_count - 1, direction);
} else {
if (i == 0) {
break;
@@ -1823,6 +1663,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc
if (direction == FTDM_TOP_DOWN) {
i = 1;
+ } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) {
+ i = rr_next(span->last_used_index, 1, span->chan_count, direction);
} else {
i = span->chan_count;
}
@@ -1833,6 +1675,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc
if (i > span->chan_count) {
break;
}
+ } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) {
+ if (i == span->last_used_index) {
+ break;
+ }
} else {
if (i == 0) {
break;
@@ -1846,6 +1692,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc
if (request_voice_channel(check, ftdmchan, caller_data, direction)) {
status = FTDM_SUCCESS;
+ if (direction == FTDM_RR_UP || direction == FTDM_RR_DOWN) {
+ span->last_used_index = i;
+ }
break;
}
@@ -1853,6 +1702,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc
if (direction == FTDM_TOP_DOWN) {
i++;
+ } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) {
+ if (check == best_rated) {
+ span->last_used_index = i;
+ }
+ i = rr_next(i, 1, span->chan_count, direction);
} else {
i--;
}
@@ -1867,58 +1721,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc
return status;
}
-static ftdm_status_t ftdm_channel_reset(ftdm_channel_t *ftdmchan)
-{
- ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OPEN);
- ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT);
- ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF);
- ftdm_channel_done(ftdmchan);
- ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_HOLD);
-
- memset(ftdmchan->tokens, 0, sizeof(ftdmchan->tokens));
- ftdmchan->token_count = 0;
-
- ftdm_channel_flush_dtmf(ftdmchan);
-
- if (ftdmchan->gen_dtmf_buffer) {
- ftdm_buffer_zero(ftdmchan->gen_dtmf_buffer);
- }
-
- if (ftdmchan->digit_buffer) {
- ftdm_buffer_zero(ftdmchan->digit_buffer);
- }
-
- if (!ftdmchan->dtmf_on) {
- ftdmchan->dtmf_on = FTDM_DEFAULT_DTMF_ON;
- }
-
- if (!ftdmchan->dtmf_off) {
- ftdmchan->dtmf_off = FTDM_DEFAULT_DTMF_OFF;
- }
-
- ftdm_call_clear_vars(&ftdmchan->caller_data);
-
- memset(ftdmchan->dtmf_hangup_buf, '\0', ftdmchan->span->dtmf_hangup_len);
-
- if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE)) {
- ftdmchan->effective_codec = ftdmchan->native_codec;
- ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
- ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE);
- }
-
- return FTDM_SUCCESS;
-}
-
-FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan)
-{
- if (ftdmchan->init_state != FTDM_CHANNEL_STATE_DOWN) {
- ftdm_set_state(ftdmchan, ftdmchan->init_state);
- ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN;
- }
-
- return FTDM_SUCCESS;
-}
-
FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan)
{
ftdm_status_t status = FTDM_FAIL;
@@ -2093,6 +1895,28 @@ FT_DECLARE(void) ftdm_span_set_trunk_type(ftdm_span_t *span, ftdm_trunk_type_t t
span->trunk_type = type;
}
+FT_DECLARE(ftdm_status_t) ftdm_span_set_blocking_mode(const ftdm_span_t *span, ftdm_bool_t enabled)
+{
+ ftdm_channel_t *fchan = NULL;
+ ftdm_iterator_t *citer = NULL;
+ ftdm_iterator_t *curr = NULL;
+
+ citer = ftdm_span_get_chan_iterator(span, NULL);
+ if (!citer) {
+ return FTDM_ENOMEM;
+ }
+ for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) {
+ fchan = ftdm_iterator_current(curr);
+ if (enabled) {
+ ftdm_clear_flag_locked(fchan, FTDM_CHANNEL_NONBLOCK);
+ } else {
+ ftdm_set_flag_locked(fchan, FTDM_CHANNEL_NONBLOCK);
+ }
+ }
+ ftdm_iterator_free(citer);
+ return FTDM_SUCCESS;
+}
+
FT_DECLARE(ftdm_trunk_type_t) ftdm_span_get_trunk_type(const ftdm_span_t *span)
{
return span->trunk_type;
@@ -2179,19 +2003,107 @@ FT_DECLARE(ftdm_bool_t) ftdm_channel_call_check_done(const ftdm_channel_t *ftdmc
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hold(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
+ ftdm_status_t status;
ftdm_channel_lock(ftdmchan);
+
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_HOLD);
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_DIALTONE, 0);
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_DIALTONE, 0);
ftdm_channel_unlock(ftdmchan);
- return FTDM_SUCCESS;
+
+ return status;
}
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_unhold(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
+ ftdm_status_t status;
+
ftdm_channel_lock(ftdmchan);
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 0);
+
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 0);
+
ftdm_channel_unlock(ftdmchan);
- return FTDM_SUCCESS;
+
+ return status;
+}
+
+FT_DECLARE(void) ftdm_ack_indication(ftdm_channel_t *fchan, ftdm_channel_indication_t indication, ftdm_status_t status)
+{
+ ftdm_sigmsg_t msg;
+ ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Acknowledging indication %s in state %s (rc = %d)\n",
+ ftdm_channel_indication2str(indication), ftdm_channel_state2str(fchan->state), status);
+ ftdm_clear_flag(fchan, FTDM_CHANNEL_IND_ACK_PENDING);
+ memset(&msg, 0, sizeof(msg));
+ msg.channel = fchan;
+ msg.event_id = FTDM_SIGEVENT_INDICATION_COMPLETED;
+ msg.ev_data.indication_completed.indication = indication;
+ msg.ev_data.indication_completed.status = status;
+ ftdm_span_send_signal(fchan->span, &msg);
+}
+
+/*! \brief Answer call without locking the channel. The caller must have locked first
+ * \note This function was added because ftdm_channel_call_indicate needs to answer the call
+ * when its already locking the channel, ftdm_channel_set_state cannot be called with the same
+ * lock locked once or more (recursive lock) and wait for the result */
+static ftdm_status_t _ftdm_channel_call_answer_nl(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
+{
+ ftdm_status_t status = FTDM_SUCCESS;
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ status = FTDM_EINVAL;
+ goto done;
+ }
+
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call is already TERMINATING\n");
+ status = FTDM_ECANCELED;
+ goto done;
+ }
+
+ if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) {
+ /* We will fail RFC's if we not skip states, but some modules apart from ftmod_sangoma_isdn
+ * expect the call to always to go PROGRESS and PROGRESS MEDIA state before going to UP, so
+ * use FTDM_SPAN_USE_SKIP_STATES for now while we update the sig modules */
+
+ if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
+ if (status != FTDM_SUCCESS) {
+ status = FTDM_ECANCELED;
+ goto done;
+ }
+ }
+
+ /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n");
+ status = FTDM_ECANCELED;
+ goto done;
+ }
+
+ if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
+ if (status != FTDM_SUCCESS) {
+ status = FTDM_ECANCELED;
+ goto done;
+ }
+ }
+
+ /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to UP\n");
+ status = FTDM_ECANCELED;
+ goto done;
+ }
+ }
+
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1);
+ if (status != FTDM_SUCCESS) {
+ status = FTDM_ECANCELED;
+ goto done;
+ }
+
+done:
+
+ return status;
}
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
@@ -2200,55 +2112,17 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
ftdm_channel_lock(ftdmchan);
- if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call is already TERMINATING\n");
- goto done;
- }
-
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_ANSWERED);
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
-
- if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
- goto done;
- }
-
- if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) {
- /* We will fail RFC's if we not skip states, but some modules apart from ftmod_sangoma_isdn
- * expect the call to always to go PROGRESS and PROGRESS MEDIA state before going to UP, so
- * use FTDM_SPAN_USE_SKIP_STATESfor now while we update the sig modules */
-
- if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
- }
-
- /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
- if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n");
- goto done;
- }
-
- if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
- }
-
- /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
- if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to UP\n");
- goto done;
- }
- }
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1);
-
-done:
+ status = _ftdm_channel_call_answer_nl(file, func, line, ftdmchan);
ftdm_channel_unlock(ftdmchan);
return status;
}
/* lock must be acquired by the caller! */
-static ftdm_status_t call_hangup(ftdm_channel_t *chan, const char *file, const char *func, int line)
+static ftdm_status_t _ftdm_channel_call_hangup_nl(ftdm_channel_t *chan, const char *file, const char *func, int line)
{
+ ftdm_status_t status = FTDM_SUCCESS;
+
ftdm_set_flag(chan, FTDM_CHANNEL_USER_HANGUP);
ftdm_set_echocancel_call_end(chan);
@@ -2261,34 +2135,47 @@ static ftdm_status_t call_hangup(ftdm_channel_t *chan, const char *file, const c
if (chan->hangup_timer) {
ftdm_sched_cancel_timer(globals.timingsched, chan->hangup_timer);
}
- ftdm_channel_set_state(file, func, line, chan, FTDM_CHANNEL_STATE_HANGUP, 1);
+ status = ftdm_channel_set_state(file, func, line, chan, FTDM_CHANNEL_STATE_HANGUP, 1);
} else {
/* the signaling stack did not touch the state,
- * core is responsible from clearing flags and stuff */
- ftdm_channel_close(&chan);
+ * core is responsible from clearing flags and stuff, however, because ftmod_analog
+ * is a bitch in a serious need of refactoring, we also check whether the channel is open
+ * to avoid an spurious warning about the channel not being open. This is because ftmod_analog
+ * does not follow our convention of sending SIGEVENT_STOP and waiting for the user to move
+ * to HANGUP (implicitly through ftdm_channel_call_hangup(), as soon as ftmod_analog is fixed
+ * this check can be removed */
+ if (ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) {
+ ftdm_channel_close(&chan);
+ }
}
- return FTDM_SUCCESS;
+ return status;
}
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup_with_cause(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_call_cause_t cause)
{
+ ftdm_status_t status = FTDM_SUCCESS;
ftdm_channel_lock(ftdmchan);
ftdmchan->caller_data.hangup_cause = cause;
- call_hangup(ftdmchan, file, func, line);
+ status = _ftdm_channel_call_hangup_nl(ftdmchan, file, func, line);
ftdm_channel_unlock(ftdmchan);
- return FTDM_SUCCESS;
+ return status;
}
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
+ ftdm_status_t status = FTDM_SUCCESS;
+
ftdm_channel_lock(ftdmchan);
+
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
- call_hangup(ftdmchan, file, func, line);
+
+ status = _ftdm_channel_call_hangup_nl(ftdmchan, file, func, line);
+
ftdm_channel_unlock(ftdmchan);
- return FTDM_SUCCESS;
+ return status;
}
FT_DECLARE(const char *) ftdm_channel_get_last_error(const ftdm_channel_t *ftdmchan)
@@ -2306,42 +2193,6 @@ FT_DECLARE(ftdm_caller_data_t *) ftdm_channel_get_caller_data(ftdm_channel_t *ft
return &ftdmchan->caller_data;
}
-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;
-}
-
FT_DECLARE(ftdm_channel_t *) ftdm_span_get_channel(const ftdm_span_t *span, uint32_t chanid)
{
ftdm_channel_t *chan;
@@ -2373,13 +2224,48 @@ FT_DECLARE(uint32_t) ftdm_channel_get_ph_span_id(const ftdm_channel_t *ftdmchan)
return id;
}
+/*
+ * Every user requested indication *MUST* be acknowledged with the proper status (ftdm_status_t)
+ * However, if the indication fails before we notify the signaling stack, we don't need to ack
+ * but if we already notified the signaling stack about the indication, the signaling stack is
+ * responsible for the acknowledge. Bottom line is, whenever this function returns FTDM_SUCCESS
+ * someone *MUST* acknowledge the indication, either the signaling stack, this function or the core
+ * at some later point
+ * */
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication)
{
ftdm_status_t status = FTDM_SUCCESS;
+
+ ftdm_assert_return(ftdmchan, FTDM_FAIL, "Null channel\n");
+
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Indicating %s in state %s\n",
+ ftdm_channel_indication2str(indication), ftdm_channel_state2str(ftdmchan->state));
+
ftdm_channel_lock(ftdmchan);
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IND_ACK_PENDING)) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot indicate %s in channel with indication %s still pending in state %s\n",
+ ftdm_channel_indication2str(indication),
+ ftdm_channel_indication2str(ftdmchan->indication),
+ ftdm_channel_state2str(ftdmchan->state));
+ status = FTDM_EBUSY;
+ goto done;
+ }
+
+ ftdmchan->indication = indication;
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_IND_ACK_PENDING);
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot indicate %s in outgoing channel in state %s\n",
+ ftdm_channel_indication2str(indication), ftdm_channel_state2str(ftdmchan->state));
+ status = FTDM_EINVAL;
+ goto done;
+ }
+
if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n");
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring indication %s because the call is in %s state\n",
+ ftdm_channel_indication2str(indication), ftdm_channel_state2str(ftdmchan->state));
+ status = FTDM_ECANCELED;
goto done;
}
@@ -2387,53 +2273,52 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch
/* FIXME: ring and busy cannot be used with all signaling stacks
* (particularly isdn stacks I think, we should emulate or just move to hangup with busy cause) */
case FTDM_CHANNEL_INDICATE_RINGING:
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_RINGING, 1);
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_RINGING, 1);
break;
case FTDM_CHANNEL_INDICATE_BUSY:
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_BUSY, 1);
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_BUSY, 1);
break;
case FTDM_CHANNEL_INDICATE_PROCEED:
- if (ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_PROCEED_STATE)) {
- if (ftdmchan->state == FTDM_CHANNEL_STATE_RING) {
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROCEED, 1);
- }
+ if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_PROCEED_STATE)) {
+ ftdm_ack_indication(ftdmchan, indication, status);
+ goto done;
}
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROCEED, 1);
break;
case FTDM_CHANNEL_INDICATE_PROGRESS:
- if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
- } else {
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
- }
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
break;
case FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA:
- if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
- ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA);
- } else {
+ if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) {
if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
+ if (status != FTDM_SUCCESS) {
+ goto done;
+ }
}
/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n");
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring progress media because the call is terminating\n");
goto done;
}
-
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
}
+ status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
+ break;
+ case FTDM_CHANNEL_INDICATE_ANSWER:
+ /* _ftdm_channel_call_answer takes care of the indication ack */
+ status = _ftdm_channel_call_answer_nl(file, func, line, ftdmchan);
break;
default:
ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "Do not know how to indicate %d\n", indication);
- status = FTDM_FAIL;
+ status = FTDM_EINVAL;
break;
}
done:
ftdm_channel_unlock(ftdmchan);
- return FTDM_SUCCESS;
+ return status;
}
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_send_msg(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_sigmsg_t *sigmsg)
@@ -2457,6 +2342,16 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_send_msg(const char *file, const ch
return status;
}
+FT_DECLARE(ftdm_status_t) _ftdm_channel_reset(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
+{
+ ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "null channel");
+
+ ftdm_channel_lock(ftdmchan);
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_RESET, 1);
+ ftdm_channel_unlock(ftdmchan);
+ return FTDM_SUCCESS;
+}
+
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
{
ftdm_status_t status = FTDM_FAIL;
@@ -2475,16 +2370,20 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char
ftdm_log(FTDM_LOG_ERROR, "outgoing_call method not implemented in this span!\n");
}
+ if (status == FTDM_SUCCESS) {
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED);
+ ftdm_call_set_call_id(ftdmchan, &ftdmchan->caller_data);
+ ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100);
+ }
+
+ ftdm_channel_unlock(ftdmchan);
+
#ifdef __WINDOWS__
UNREFERENCED_PARAMETER(file);
UNREFERENCED_PARAMETER(func);
UNREFERENCED_PARAMETER(line);
#endif
- ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100);
-
- ftdm_channel_unlock(ftdmchan);
-
return status;
}
@@ -2492,9 +2391,18 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_set_sig_status(ftdm_channel_t *ftdmchan,
{
ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel\n");
ftdm_assert_return(ftdmchan->span != NULL, FTDM_FAIL, "Null span\n");
-
+
+ if (sigstatus == FTDM_SIG_STATE_DOWN) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "The user is not allowed to set the signaling status to DOWN, valid states are UP or SUSPENDED\n");
+ return FTDM_FAIL;
+ }
+
if (ftdmchan->span->set_channel_sig_status) {
- return ftdmchan->span->set_channel_sig_status(ftdmchan, sigstatus);
+ ftdm_status_t res;
+ ftdm_channel_lock(ftdmchan);
+ res = ftdmchan->span->set_channel_sig_status(ftdmchan, sigstatus);
+ ftdm_channel_unlock(ftdmchan);
+ return res;
} else {
ftdm_log(FTDM_LOG_ERROR, "set_channel_sig_status method not implemented!\n");
return FTDM_FAIL;
@@ -2508,7 +2416,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_get_sig_status(ftdm_channel_t *ftdmchan,
ftdm_assert_return(sigstatus != NULL, FTDM_FAIL, "Null sig status parameter\n");
if (ftdmchan->span->get_channel_sig_status) {
- return ftdmchan->span->get_channel_sig_status(ftdmchan, sigstatus);
+ ftdm_status_t res;
+ ftdm_channel_lock(ftdmchan);
+ res = ftdmchan->span->get_channel_sig_status(ftdmchan, sigstatus);
+ ftdm_channel_unlock(ftdmchan);
+ return res;
} else {
/* don't log error here, it can be called just to test if its supported */
return FTDM_NOTIMPL;
@@ -2519,6 +2431,11 @@ FT_DECLARE(ftdm_status_t) ftdm_span_set_sig_status(ftdm_span_t *span, ftdm_signa
{
ftdm_assert_return(span != NULL, FTDM_FAIL, "Null span\n");
+ if (sigstatus == FTDM_SIG_STATE_DOWN) {
+ ftdm_log(FTDM_LOG_WARNING, "The user is not allowed to set the signaling status to DOWN, valid states are UP or SUSPENDED\n");
+ return FTDM_FAIL;
+ }
+
if (span->set_span_sig_status) {
return span->set_span_sig_status(span, sigstatus);
} else {
@@ -2539,15 +2456,14 @@ FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signa
}
}
-static ftdm_status_t ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan);
-FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
+/* this function must be called with the channel lock */
+static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan)
{
ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel can't be done!\n");
- ftdm_mutex_lock(ftdmchan->mutex);
-
- memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
-
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OPEN);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_INUSE);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_WINK);
@@ -2574,12 +2490,13 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN;
ftdmchan->state = FTDM_CHANNEL_STATE_DOWN;
+ ftdmchan->state_status = FTDM_STATE_STATUS_COMPLETED;
ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_DEBUG_DTMF, NULL);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_INPUT_DUMP, NULL);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_OUTPUT_DUMP, NULL);
- if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) {
+ if (FTDM_IS_VOICE_CHANNEL(ftdmchan) && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED)) {
ftdm_sigmsg_t sigmsg;
memset(&sigmsg, 0, sizeof(sigmsg));
sigmsg.span_id = ftdmchan->span_id;
@@ -2587,18 +2504,48 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
sigmsg.channel = ftdmchan;
sigmsg.event_id = FTDM_SIGEVENT_RELEASED;
ftdm_span_send_signal(ftdmchan->span, &sigmsg);
+ ftdm_call_clear_call_id(&ftdmchan->caller_data);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED);
}
if (ftdmchan->txdrops || ftdmchan->rxdrops) {
- ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "channel dropped data: txdrops = %d, rxdrops = %d\n",
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "channel dropped data: txdrops = %d, rxdrops = %d\n",
ftdmchan->txdrops, ftdmchan->rxdrops);
}
+
+ memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_HOLD);
+
+ memset(ftdmchan->tokens, 0, sizeof(ftdmchan->tokens));
+ ftdmchan->token_count = 0;
+
+ ftdm_channel_flush_dtmf(ftdmchan);
+
+ if (ftdmchan->gen_dtmf_buffer) {
+ ftdm_buffer_zero(ftdmchan->gen_dtmf_buffer);
+ }
+
+ if (ftdmchan->digit_buffer) {
+ ftdm_buffer_zero(ftdmchan->digit_buffer);
+ }
+
+ if (!ftdmchan->dtmf_on) {
+ ftdmchan->dtmf_on = FTDM_DEFAULT_DTMF_ON;
+ }
+
+ if (!ftdmchan->dtmf_off) {
+ ftdmchan->dtmf_off = FTDM_DEFAULT_DTMF_OFF;
+ }
+
+ memset(ftdmchan->dtmf_hangup_buf, '\0', ftdmchan->span->dtmf_hangup_len);
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE)) {
+ ftdmchan->effective_codec = ftdmchan->native_codec;
+ ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE);
+ }
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "channel done\n");
-
-
- ftdm_mutex_unlock(ftdmchan->mutex);
-
return FTDM_SUCCESS;
}
@@ -2625,15 +2572,13 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_close(ftdm_channel_t **ftdmchan)
if (ftdm_test_flag(check, FTDM_CHANNEL_CONFIGURED)) {
ftdm_mutex_lock(check->mutex);
- if (ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) {
- status = check->fio->close(check);
- if (status == FTDM_SUCCESS) {
- ftdm_clear_flag(check, FTDM_CHANNEL_INUSE);
- ftdm_channel_reset(check);
- *ftdmchan = NULL;
- }
- } else {
- ftdm_log_chan_msg(check, FTDM_LOG_WARNING, "Called ftdm_channel_close but never ftdm_channel_open??\n");
+ if (!ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) {
+ ftdm_log_chan_msg(check, FTDM_LOG_WARNING, "Channel not opened, proceeding anyway\n");
+ }
+ status = check->fio->close(check);
+ if (status == FTDM_SUCCESS) {
+ ftdm_channel_done(check);
+ *ftdmchan = NULL;
}
check->ring_count = 0;
ftdm_mutex_unlock(check->mutex);
@@ -2693,7 +2638,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
GOTO_STATUS(done, FTDM_FAIL);
}
- ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT);
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT);
+ GOTO_STATUS(done, FTDM_SUCCESS);
}
}
break;
@@ -2701,7 +2647,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
{
if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CALLERID)) {
ftdm_fsk_demod_destroy(&ftdmchan->fsk);
- ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT);
+ GOTO_STATUS(done, FTDM_SUCCESS);
}
}
break;
@@ -2712,7 +2659,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
close(ftdmchan->fds[FTDM_READ_TRACE_INDEX]);
ftdmchan->fds[FTDM_READ_TRACE_INDEX] = -1;
}
- if ((ftdmchan->fds[FTDM_READ_TRACE_INDEX] = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) {
+ if ((ftdmchan->fds[FTDM_READ_TRACE_INDEX] = open(path, O_WRONLY | O_CREAT | O_TRUNC
+ | FTDM_O_BINARY, S_IRUSR | S_IWUSR)) > -1) {
ftdm_log(FTDM_LOG_DEBUG, "Tracing channel %u:%u input to [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, path);
GOTO_STATUS(done, FTDM_SUCCESS);
}
@@ -2728,7 +2676,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
close(ftdmchan->fds[FTDM_WRITE_TRACE_INDEX]);
ftdmchan->fds[FTDM_WRITE_TRACE_INDEX] = -1;
}
- if ((ftdmchan->fds[FTDM_WRITE_TRACE_INDEX] = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) {
+ if ((ftdmchan->fds[FTDM_WRITE_TRACE_INDEX] = open(path, O_WRONLY | O_CREAT | O_TRUNC
+ | FTDM_O_BINARY, S_IRUSR | S_IWUSR)) > -1) {
ftdm_log(FTDM_LOG_DEBUG, "Tracing channel %u:%u output to [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, path);
GOTO_STATUS(done, FTDM_SUCCESS);
}
@@ -2796,10 +2745,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
GOTO_STATUS(done, FTDM_FAIL);
}
if (start_chan_io_dump(ftdmchan, &ftdmchan->rxdump, size) != FTDM_SUCCESS) {
- ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to enable input dump of size %zd\n", size);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to enable input dump of size %"FTDM_SIZE_FMT"\n", size);
GOTO_STATUS(done, FTDM_FAIL);
}
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled input dump with size %zd\n", size);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled input dump with size %"FTDM_SIZE_FMT"\n", size);
GOTO_STATUS(done, FTDM_SUCCESS);
}
break;
@@ -2811,7 +2760,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No need to disable input dump\n");
GOTO_STATUS(done, FTDM_SUCCESS);
}
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled input dump of size %zd\n", ftdmchan->rxdump.size);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled input dump of size %"FTDM_SIZE_FMT"\n",
+ ftdmchan->rxdump.size);
stop_chan_io_dump(&ftdmchan->rxdump);
GOTO_STATUS(done, FTDM_SUCCESS);
}
@@ -2829,7 +2779,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to enable output dump of size %d\n", size);
GOTO_STATUS(done, FTDM_FAIL);
}
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled output dump with size %zd\n", size);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled output dump with size %"FTDM_SIZE_FMT"\n", size);
GOTO_STATUS(done, FTDM_SUCCESS);
}
break;
@@ -2841,7 +2791,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No need to disable output dump\n");
GOTO_STATUS(done, FTDM_SUCCESS);
}
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled output dump of size %zd\n", ftdmchan->rxdump.size);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled output dump of size %"FTDM_SIZE_FMT"\n", ftdmchan->rxdump.size);
stop_chan_io_dump(&ftdmchan->txdump);
GOTO_STATUS(done, FTDM_SUCCESS);
}
@@ -2874,7 +2824,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
GOTO_STATUS(done, FTDM_FAIL);
}
dump_chan_io_to_file(ftdmchan, &ftdmchan->txdump, obj);
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Dumped input of size %zd to file %p\n", ftdmchan->txdump.size, obj);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Dumped input of size %"FTDM_SIZE_FMT" to file %p\n", ftdmchan->txdump.size, obj);
GOTO_STATUS(done, FTDM_SUCCESS);
}
break;
@@ -2961,7 +2911,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
case FTDM_COMMAND_DISABLE_PROGRESS_DETECT:
{
if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_PROGRESS)) {
- ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT);
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT);
ftdm_channel_clear_detected_tones(ftdmchan);
ftdm_channel_clear_needed_tones(ftdmchan);
GOTO_STATUS(done, FTDM_SUCCESS);
@@ -2973,8 +2923,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
/* if they don't have thier own, use ours */
if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) {
teletone_dtmf_detect_init (&ftdmchan->dtmf_detect, ftdmchan->rate);
- ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_DTMF_DETECT);
- ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF);
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT);
+ ftdm_set_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF);
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Enabled software DTMF detector\n");
GOTO_STATUS(done, FTDM_SUCCESS);
}
@@ -3373,7 +3323,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, cons
ftdmchan->span_id, ftdmchan->chan_id,
currtime.tm_year-100, currtime.tm_mon+1, currtime.tm_mday,
currtime.tm_hour, currtime.tm_min, currtime.tm_sec, ftdmchan->native_codec == FTDM_CODEC_ULAW ? "ulaw" : ftdmchan->native_codec == FTDM_CODEC_ALAW ? "alaw" : "sln");
- ftdmchan->dtmfdbg.file = fopen(dfile, "w");
+ ftdmchan->dtmfdbg.file = fopen(dfile, "wb");
if (!ftdmchan->dtmfdbg.file) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "failed to open debug dtmf file %s\n", dfile);
} else {
@@ -3443,7 +3393,7 @@ static FIO_WRITE_FUNCTION(ftdm_raw_write)
}
if (ftdmchan->fds[FTDM_WRITE_TRACE_INDEX] > -1) {
if ((write(ftdmchan->fds[FTDM_WRITE_TRACE_INDEX], data, dlen)) != dlen) {
- ftdm_log(FTDM_LOG_WARNING, "Raw output trace failed to write all of the %zd bytes\n", dlen);
+ ftdm_log(FTDM_LOG_WARNING, "Raw output trace failed to write all of the %"FTDM_SIZE_FMT" bytes\n", dlen);
}
}
write_chan_io_dump(&ftdmchan->txdump, data, dlen);
@@ -3455,8 +3405,8 @@ static FIO_READ_FUNCTION(ftdm_raw_read)
ftdm_status_t status = ftdmchan->fio->read(ftdmchan, data, datalen);
if (status == FTDM_SUCCESS && ftdmchan->fds[FTDM_READ_TRACE_INDEX] > -1) {
ftdm_size_t dlen = *datalen;
- if ((ftdm_size_t)write(ftdmchan->fds[FTDM_READ_TRACE_INDEX], data, dlen) != dlen) {
- ftdm_log(FTDM_LOG_WARNING, "Raw input trace failed to write all of the %zd bytes\n", dlen);
+ if ((ftdm_size_t)write(ftdmchan->fds[FTDM_READ_TRACE_INDEX], data, (int)dlen) != dlen) {
+ ftdm_log(FTDM_LOG_WARNING, "Raw input trace failed to write all of the %"FTDM_SIZE_FMT" bytes\n", dlen);
}
}
@@ -3468,7 +3418,7 @@ static FIO_READ_FUNCTION(ftdm_raw_read)
ftdm_size_t dlen = *datalen;
ftdm_size_t rc = 0;
- write_chan_io_dump(&ftdmchan->rxdump, data, dlen);
+ write_chan_io_dump(&ftdmchan->rxdump, data, (int)dlen);
/* if dtmf debug is enabled and initialized, write there too */
if (ftdmchan->dtmfdbg.file) {
@@ -3626,23 +3576,21 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data
}
status = ftdm_raw_read(ftdmchan, data, datalen);
-
if (status != FTDM_SUCCESS) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "raw I/O read filed\n");
+ goto done;
}
- if (status == FTDM_SUCCESS) {
- if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN)
- && (ftdmchan->native_codec == FTDM_CODEC_ALAW || ftdmchan->native_codec == FTDM_CODEC_ULAW)) {
- unsigned char *rdata = data;
- for (i = 0; i < *datalen; i++) {
- rdata[i] = ftdmchan->rxgain_table[rdata[i]];
- }
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN)
+ && (ftdmchan->native_codec == FTDM_CODEC_ALAW || ftdmchan->native_codec == FTDM_CODEC_ULAW)) {
+ unsigned char *rdata = data;
+ for (i = 0; i < *datalen; i++) {
+ rdata[i] = ftdmchan->rxgain_table[rdata[i]];
}
- handle_dtmf(ftdmchan, *datalen);
}
+ handle_dtmf(ftdmchan, *datalen);
- if (status == FTDM_SUCCESS && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE) && ftdmchan->effective_codec != ftdmchan->native_codec) {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE) && ftdmchan->effective_codec != ftdmchan->native_codec) {
if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
codec_func = fio_ulaw2slin;
} else if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_ALAW) {
@@ -3843,7 +3791,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_write(ftdm_channel_t *ftdmchan, void *dat
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "cannot write in channel not open\n");
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "cannot write in channel not open\n");
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open");
status = FTDM_FAIL;
goto done;
@@ -4299,6 +4247,16 @@ static void print_channels_by_state(ftdm_stream_handle_t *stream, ftdm_channel_s
ftdm_mutex_unlock(globals.mutex);
}
+static void print_core_usage(ftdm_stream_handle_t *stream)
+{
+ stream->write_function(stream,
+ "--------------------------------------------------------------------------------\n"
+ "ftdm core state [!] - List all channels in or not in the given state\n"
+ "ftdm core flag - List all channels with the given flag value set\n"
+ "ftdm core calls - List all known calls to the FreeTDM core\n"
+ "--------------------------------------------------------------------------------\n");
+}
+
static char *handle_core_command(const char *cmd)
{
char *mycmd = NULL;
@@ -4309,22 +4267,31 @@ static char *handle_core_command(const char *cmd)
char *state = NULL;
char *flag = NULL;
uint32_t flagval = 0;
+ uint32_t current_call_id = 0;
+ ftdm_caller_data_t *calldata = NULL;
+ ftdm_channel_t *fchan = NULL;
ftdm_channel_state_t i = FTDM_CHANNEL_STATE_INVALID;
ftdm_stream_handle_t stream = { 0 };
FTDM_STANDARD_STREAM(stream);
- if (cmd) {
+ if (cmd && strlen(cmd)) {
mycmd = ftdm_strdup(cmd);
argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
} else {
- stream.write_function(&stream, "invalid core command\n");
+ print_core_usage(&stream);
+ goto done;
+ }
+
+ if (!argc) {
+ print_core_usage(&stream);
goto done;
}
if (!strcasecmp(argv[0], "state")) {
if (argc < 2) {
stream.write_function(&stream, "core state command requires an argument\n");
+ print_core_usage(&stream);
goto done;
}
state = argv[1];
@@ -4345,7 +4312,8 @@ static char *handle_core_command(const char *cmd)
stream.write_function(&stream, "\nTotal channels %s %s: %d\n", not ? "not in state" : "in state", ftdm_channel_state2str(i), count);
} else if (!strcasecmp(argv[0], "flag")) {
if (argc < 2) {
- stream.write_function(&stream, "core state command requires an argument\n");
+ stream.write_function(&stream, "core flag command requires an argument\n");
+ print_core_usage(&stream);
goto done;
}
flag = argv[1];
@@ -4356,8 +4324,28 @@ static char *handle_core_command(const char *cmd)
flagval = atoi(flag);
print_channels_by_flag(&stream, flagval, not, &count);
stream.write_function(&stream, "\nTotal channels %s %d: %d\n", not ? "without flag" : "with flag", flagval, count);
+ } else if (!strcasecmp(argv[0], "calls")) {
+ ftdm_mutex_lock(globals.call_id_mutex);
+ current_call_id = globals.last_call_id;
+ for (current_call_id = 0; current_call_id <= MAX_CALLIDS; current_call_id++) {
+ if (!globals.call_ids[current_call_id]) {
+ continue;
+ }
+ calldata = globals.call_ids[current_call_id];
+ fchan = calldata->fchan;
+ if (fchan) {
+ stream.write_function(&stream, "Call %d on channel %d:%d\n", current_call_id,
+ fchan->span_id, fchan->chan_id);
+ } else {
+ stream.write_function(&stream, "Call %d without a channel?\n", current_call_id);
+ }
+ count++;
+ }
+ ftdm_mutex_unlock(globals.call_id_mutex);
+ stream.write_function(&stream, "\nTotal calls: %d\n", count);
} else {
stream.write_function(&stream, "invalid core command %s\n", argv[0]);
+ print_core_usage(&stream);
}
done:
@@ -4377,6 +4365,8 @@ FT_DECLARE(char *) ftdm_api_execute(const char *cmd)
if ((p = strchr(dup, ' '))) {
*p++ = '\0';
cmd = p;
+ } else {
+ cmd = "";
}
type = dup;
@@ -4697,7 +4687,7 @@ static ftdm_status_t load_config(void)
len = strlen(val);
if (len >= FTDM_MAX_NAME_STR_SZ) {
len = FTDM_MAX_NAME_STR_SZ - 1;
- ftdm_log(FTDM_LOG_WARNING, "Truncating group name %s to %zd length\n", val, len);
+ ftdm_log(FTDM_LOG_WARNING, "Truncating group name %s to %"FTDM_SIZE_FMT" length\n", val, len);
}
memcpy(chan_config.group_name, val, len);
chan_config.group_name[len] = '\0';
@@ -5060,7 +5050,7 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const
ftdm_assert_return(parameters != NULL, FTDM_FAIL, "No parameters");
if (!span->chan_count) {
- ftdm_log(FTDM_LOG_WARNING, "Cannot configure signaling on span with no channels\n");
+ ftdm_log(FTDM_LOG_WARNING, "Cannot configure signaling on span %s with no channels\n", span->name);
return FTDM_FAIL;
}
@@ -5090,11 +5080,28 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const
FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span)
{
- if (span->start) {
- return span->start(span);
+ ftdm_status_t status = FTDM_FAIL;
+
+ ftdm_mutex_lock(span->mutex);
+
+ if (ftdm_test_flag(span, FTDM_SPAN_STARTED)) {
+ status = FTDM_EINVAL;
+ goto done;
}
- return FTDM_FAIL;
+ if (!span->start) {
+ status = FTDM_ENOSYS;
+ goto done;
+ }
+
+ status = span->start(span);
+ if (status == FTDM_SUCCESS) {
+ ftdm_set_flag_locked(span, FTDM_SPAN_STARTED);
+ }
+
+done:
+ ftdm_mutex_unlock(span->mutex);
+ return status;
}
FT_DECLARE(ftdm_status_t) ftdm_channel_add_to_group(const char* name, ftdm_channel_t* ftdmchan)
@@ -5247,7 +5254,6 @@ static void ftdm_group_add(ftdm_group_t *group)
ftdm_mutex_unlock(globals.group_mutex);
}
-
FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *name)
{
ftdm_group_t *new_group = NULL;
@@ -5281,6 +5287,11 @@ static ftdm_status_t ftdm_span_trigger_signal(const ftdm_span_t *span, ftdm_sigm
if (sigmsg->channel) {
ftdm_call_clear_data(&(sigmsg->channel->caller_data));
}
+ if (sigmsg->raw.autofree) {
+ ftdm_safe_free(sigmsg->raw.data);
+ sigmsg->raw.data = NULL;
+ sigmsg->raw.len = 0;
+ }
return status;
}
@@ -5288,8 +5299,6 @@ static ftdm_status_t ftdm_span_queue_signal(const ftdm_span_t *span, ftdm_sigmsg
{
ftdm_sigmsg_t *new_sigmsg = NULL;
- ftdm_assert_return((sigmsg->raw_data == NULL), FTDM_FAIL, "No raw data should be used with asynchronous notification\n");
-
new_sigmsg = ftdm_calloc(1, sizeof(*sigmsg));
if (!new_sigmsg) {
return FTDM_FAIL;
@@ -5318,7 +5327,7 @@ static void execute_safety_hangup(void *data)
fchan->hangup_timer = 0;
if (fchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Forcing hangup since the user did not confirmed our hangup after %dms\n", FORCE_HANGUP_TIMER);
- call_hangup(fchan, __FILE__, __FUNCTION__, __LINE__);
+ _ftdm_channel_call_hangup_nl(fchan, __FILE__, __FUNCTION__, __LINE__);
} else {
ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Not performing safety hangup, channel state is %s\n", ftdm_channel_state2str(fchan->state));
}
@@ -5328,7 +5337,7 @@ static void execute_safety_hangup(void *data)
FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t *sigmsg)
{
if (sigmsg->channel) {
- ftdm_mutex_lock(sigmsg->channel->mutex);
+ ftdm_mutex_lock(sigmsg->channel->mutex);
}
/* some core things to do on special events */
@@ -5336,8 +5345,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
case FTDM_SIGEVENT_SIGSTATUS_CHANGED:
{
- ftdm_signaling_status_t sigstatus = ftdm_test_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE) ? sigmsg->sigstatus : *((ftdm_signaling_status_t*)(sigmsg->raw_data));
- if (sigstatus == FTDM_SIG_STATE_UP) {
+ if (sigmsg->ev_data.sigstatus.status == FTDM_SIG_STATE_UP) {
ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_SIG_UP);
} else {
ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_SIG_UP);
@@ -5347,6 +5355,8 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
case FTDM_SIGEVENT_START:
{
+ ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_CALL_STARTED);
+ ftdm_call_set_call_id(sigmsg->channel, &sigmsg->channel->caller_data);
ftdm_set_echocancel_call_begin(sigmsg->channel);
if (sigmsg->channel->dtmfdbg.requested) {
ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DEBUG_DTMF, NULL);
@@ -5361,6 +5371,11 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
break;
case FTDM_SIGEVENT_STOP:
+ if (!ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_CALL_STARTED)) {
+ /* this happens for FXS devices which blindly send SIGEVENT_STOP, we should fix it there ... */
+ ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Ignoring SIGEVENT_STOP since user never knew about a call in this channel\n");
+ goto done;
+ }
if (ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_USER_HANGUP)) {
ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Ignoring SIGEVENT_STOP since user already requested hangup\n");
goto done;
@@ -5376,7 +5391,10 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
break;
}
-
+
+ if (sigmsg->channel) {
+ sigmsg->call_id = sigmsg->channel->caller_data.call_id;
+ }
/* if the signaling module uses a queue for signaling notifications, then enqueue it */
if (ftdm_test_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE)) {
ftdm_span_queue_signal(span, sigmsg);
@@ -5485,6 +5503,8 @@ FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
ftdm_mutex_create(&globals.mutex);
ftdm_mutex_create(&globals.span_mutex);
ftdm_mutex_create(&globals.group_mutex);
+ ftdm_mutex_create(&globals.call_id_mutex);
+
ftdm_sched_global_init();
if (ftdm_sched_create(&globals.timingsched, "freetdm-master") != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "Failed to create master timing schedule context\n");
@@ -5494,6 +5514,7 @@ FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
ftdm_log(FTDM_LOG_CRIT, "Failed to run master timing schedule context\n");
return FTDM_FAIL;
}
+
globals.running = 1;
return FTDM_SUCCESS;
}
@@ -5597,6 +5618,7 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void)
ftdm_mutex_destroy(&globals.mutex);
ftdm_mutex_destroy(&globals.span_mutex);
ftdm_mutex_destroy(&globals.group_mutex);
+ ftdm_mutex_destroy(&globals.call_id_mutex);
memset(&globals, 0, sizeof(globals));
return FTDM_SUCCESS;
@@ -5919,42 +5941,63 @@ FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen)
return new;
}
-FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan)
+static ftdm_status_t ftdm_call_set_call_id(ftdm_channel_t *fchan, ftdm_caller_data_t *caller_data)
{
- char func[255];
- char line[255];
- char states[255];
- uint8_t i = 0;
+ uint32_t current_call_id;
+
+ ftdm_assert_return(!caller_data->call_id, FTDM_FAIL, "Overwriting non-cleared call-id\n");
- 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;
- }
+ ftdm_mutex_lock(globals.call_id_mutex);
- stream.write_function(&stream, "%-30.30s %-30.30s %s", "-- States --", "-- Function --", "-- Location --\n");
+ current_call_id = globals.last_call_id;
- for (i = fchan->hindex; i < ftdm_array_len(fchan->history); i++) {
- if (!fchan->history[i].file) {
+ for (current_call_id = globals.last_call_id + 1;
+ current_call_id != globals.last_call_id;
+ current_call_id++ ) {
+ if (current_call_id > MAX_CALLIDS) {
+ current_call_id = 1;
+ }
+ if (globals.call_ids[current_call_id] == NULL) {
break;
}
- 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);
- snprintf(line, sizeof(func), "[%s:%d]", fchan->history[i].file, fchan->history[i].line);
- stream.write_function(&stream, "%-30.30s %-30.30s %s\n", states, func, line);
}
- for (i = 0; i < fchan->hindex; i++) {
- 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);
- snprintf(line, sizeof(func), "[%s:%d]", fchan->history[i].file, fchan->history[i].line);
- stream.write_function(&stream, "%-30.30s %-30.30s %s\n", states, func, line);
- }
+ ftdm_assert_return(globals.call_ids[current_call_id] == NULL, FTDM_FAIL, "We ran out of call ids\n");
- return stream.data;
+ globals.last_call_id = current_call_id;
+ caller_data->call_id = current_call_id;
+
+ globals.call_ids[current_call_id] = caller_data;
+ caller_data->fchan = fchan;
+
+ ftdm_mutex_unlock(globals.call_id_mutex);
+ return FTDM_SUCCESS;
}
+static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data)
+{
+ if (caller_data->call_id) {
+ ftdm_assert_return((caller_data->call_id <= MAX_CALLIDS), FTDM_FAIL, "Cannot clear call with invalid call-id\n");
+ } else {
+ /* there might not be a call at all */
+ return FTDM_SUCCESS;
+ }
+
+ ftdm_mutex_lock(globals.call_id_mutex);
+ if (globals.call_ids[caller_data->call_id]) {
+ ftdm_log(FTDM_LOG_DEBUG, "Cleared call with id %u\n", caller_data->call_id);
+ globals.call_ids[caller_data->call_id] = NULL;
+ caller_data->call_id = 0;
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "call-id did not exist %u\n", caller_data->call_id);
+ }
+ ftdm_mutex_unlock(globals.call_id_mutex);
+
+ return FTDM_SUCCESS;
+}
+
+
+
/* For Emacs:
* Local Variables:
diff --git a/libs/freetdm/src/ftdm_m3ua.c b/libs/freetdm/src/ftdm_m3ua.c
deleted file mode 100644
index 1a6fe362e7..0000000000
--- a/libs/freetdm/src/ftdm_m3ua.c
+++ /dev/null
@@ -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_done(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:
-*/
diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c
new file mode 100644
index 0000000000..f6c2c2320c
--- /dev/null
+++ b/libs/freetdm/src/ftdm_state.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies
+ * Moises Silva
+ * 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:
+ */
diff --git a/libs/freetdm/src/ftdm_threadmutex.c b/libs/freetdm/src/ftdm_threadmutex.c
index b1884ec587..6efa27714c 100644
--- a/libs/freetdm/src/ftdm_threadmutex.c
+++ b/libs/freetdm/src/ftdm_threadmutex.c
@@ -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
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h
index 2c79822b29..39cbc5ff2b 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h
@@ -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;
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
index f07f48b0d6..818f1c5754 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
@@ -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));
diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c
index 886c4a8fec..31c2421b9b 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c
+++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c
@@ -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;
}
diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c
index 6a8a4eb379..5b4ce7196a 100644
--- a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c
+++ b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c
@@ -1325,7 +1325,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
}
Q931ReleaseCRV(&isdn_data->q931, gen->CRV);
}
- ftdm_channel_done(ftdmchan);
+ ftdm_channel_close(&ftdmchan);
}
break;
case FTDM_CHANNEL_STATE_PROGRESS:
diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c
index 68f0e9e5a4..8be6d579e1 100644
--- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c
+++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c
@@ -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;
diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c b/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c
index fbe6ca0822..bfb67e4c78 100644
--- a/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c
+++ b/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c
@@ -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
diff --git a/libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c b/libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c
index 220a96515b..48a2f012eb 100644
--- a/libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c
+++ b/libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c
@@ -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,14 +278,16 @@ 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:
- {
- ftdm_channel_done(ftdmchan);
+ {
ftdmchan->call_data = NULL;
+ ftdm_channel_close(&ftdmchan);
- ftdm_channel_done(peerchan);
peerchan->call_data = NULL;
+ ftdm_channel_close(&peerchan);
}
break;
@@ -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;
}
diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
index 654e68ad9e..79850a3c1f 100644
--- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
+++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
@@ -33,6 +33,7 @@
* Contributors:
*
* Arnaldo Pereira
+ * Ricardo Barroetaveña
*
*/
@@ -49,16 +50,15 @@
#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 users kills a span we clear this flag to kill the signaling thread */
+/* when the user stops a span, we clear FTDM_R2_SPAN_STARTED, so that the signaling thread
+ * knows it must stop, and we wait for FTDM_R2_RUNNING to be clear, which tells us the
+ * signaling thread is done. */
/* FIXME: what about the calls that are already up-and-running? */
typedef enum {
FTDM_R2_RUNNING = (1 << 0),
+ FTDM_R2_SPAN_STARTED = (1 << 1),
} ftdm_r2_flag_t;
/* private call information stored in ftdmchan->call_data void* ptr,
@@ -73,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];
@@ -168,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) \
@@ -255,7 +253,7 @@ static void ftdm_r2_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sig.sigstatus = status;
+ sig.ev_data.sigstatus.status = status;
if (ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to change channel status to %s\n", ftdm_signaling_status2str(status));
}
@@ -349,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;
@@ -377,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;
@@ -394,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);
@@ -401,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");
@@ -411,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);
@@ -424,13 +488,14 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
static ftdm_status_t ftdm_r2_start(ftdm_span_t *span)
{
ftdm_r2_data_t *r2_data = span->signal_data;
- ftdm_set_flag(r2_data, FTDM_R2_RUNNING);
+ ftdm_set_flag(r2_data, FTDM_R2_SPAN_STARTED);
return ftdm_thread_create_detached(ftdm_r2_run, span);
}
static ftdm_status_t ftdm_r2_stop(ftdm_span_t *span)
{
ftdm_r2_data_t *r2_data = span->signal_data;
+ ftdm_clear_flag(r2_data, FTDM_R2_SPAN_STARTED);
while (ftdm_test_flag(r2_data, FTDM_R2_RUNNING)) {
ftdm_log(FTDM_LOG_DEBUG, "Waiting for R2 span %s\n", span->name);
ftdm_sleep(100);
@@ -449,6 +514,95 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_channel_sig_status)
return FTDM_SUCCESS;
}
+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_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;
+ }
+ return FTDM_SUCCESS;
+}
+
+static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_span_sig_status)
+{
+ 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 non-idle, report SUSPENDED. UP otherwise. */
+ *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;
+}
+
+static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status)
+{
+ ftdm_iterator_t *chaniter = NULL;
+ ftdm_iterator_t *citer = NULL;
+
+ 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;
+ }
+ /* 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);
+ /* 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_channel_unlock(fchan);
+ }
+ ftdm_iterator_free(chaniter);
+ return FTDM_SUCCESS;
+}
+
/* always called from the monitor thread */
static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
{
@@ -466,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);
}
}
@@ -500,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);
@@ -509,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) {
@@ -529,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;
}
/*
@@ -546,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);
}
}
@@ -568,14 +723,14 @@ static void dump_mf(openr2_chan_t *r2chan)
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO output in prefix %s\n", logname);
snprintf(dfile, sizeof(dfile), logname ? "%s.s%dc%d.input.alaw" : "%s/s%dc%d.input.alaw",
logname ? logname : r2data->logdir, ftdmchan->span_id, ftdmchan->chan_id);
- f = fopen(dfile, "w");
+ f = fopen(dfile, "wb");
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO input in file %s\n", dfile);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_DUMP_INPUT, f);
fclose(f);
snprintf(dfile, sizeof(dfile), logname ? "%s.s%dc%d.output.alaw" : "%s/s%dc%d.output.alaw",
logname ? logname : r2data->logdir, ftdmchan->span_id, ftdmchan->chan_id);
- f = fopen(dfile, "w");
+ f = fopen(dfile, "wb");
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO output in file %s\n", dfile);
ftdm_channel_command(ftdmchan, FTDM_COMMAND_DUMP_OUTPUT, f);
fclose(f);
@@ -585,6 +740,8 @@ static void dump_mf(openr2_chan_t *r2chan)
static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
{
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
+
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call accepted\n");
clear_accept_pending(ftdmchan);
@@ -607,6 +764,11 @@ static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t m
return;
}
} else {
+ /* nothing went wrong during call setup, MF has ended, we can and must disable the MF dump */
+ if (r2data->mf_dump_size) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_INPUT_DUMP, NULL);
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_OUTPUT_DUMP, NULL);
+ }
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
}
}
@@ -652,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)
@@ -665,7 +827,7 @@ static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf
static void ftdm_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
{
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
- ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Alarm notification: %d\n", alarm);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Alarm notification: %d\n", alarm);
}
static void ftdm_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
@@ -684,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);
}
@@ -1000,6 +1162,10 @@ static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *e
return -1;
}
+ if (fevent->e_type != FTDM_EVENT_OOB) {
+ return 0;
+ }
+
switch (fevent->enum_id) {
case FTDM_OOB_CAS_BITS_CHANGE:
{
@@ -1061,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,
@@ -1112,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,
@@ -1408,19 +1600,24 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
span->sig_read = NULL;
span->sig_write = NULL;
- /* let the core set the states, we just read them */
- span->get_channel_sig_status = ftdm_r2_get_channel_sig_status;
-
span->signal_cb = sig_cb;
span->signal_type = FTDM_SIGTYPE_R2;
span->signal_data = r2data;
span->outgoing_call = r2_outgoing_call;
+ span->get_span_sig_status = ftdm_r2_get_span_sig_status;
+ span->set_span_sig_status = ftdm_r2_set_span_sig_status;
+ span->get_channel_sig_status = ftdm_r2_get_channel_sig_status;
+ 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");
@@ -1443,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;
@@ -1456,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);
@@ -1630,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;
@@ -1662,6 +1846,9 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
uint32_t txqueue_size = 4;
short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count);
+ /* as long as this thread is running, this flag is set */
+ ftdm_set_flag(r2data, FTDM_R2_RUNNING);
+
#ifdef __linux__
r2data->monitor_thread_id = syscall(SYS_gettid);
#endif
@@ -1675,16 +1862,18 @@ 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);
}
memset(&start, 0, sizeof(start));
memset(&end, 0, sizeof(end));
- while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) {
+ while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_SPAN_STARTED)) {
res = gettimeofday(&end, NULL);
if (res) {
ftdm_log(FTDM_LOG_CRIT, "Failure gettimeofday [%s]\n", strerror(errno));
@@ -1709,7 +1898,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
/* deliver the actual channel events to the user now without any channel locking */
ftdm_span_trigger_signals(span);
-#ifndef WIN32
+
/* figure out what event to poll each channel for. POLLPRI when the channel is down,
* POLLPRI|POLLIN|POLLOUT otherwise */
memset(poll_events, 0, sizeof(short)*span->chan_count);
@@ -1721,16 +1910,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
for (i = 0; citer; citer = ftdm_iterator_next(citer), i++) {
ftdmchan = ftdm_iterator_current(citer);
r2chan = R2CALL(ftdmchan)->r2chan;
- poll_events[i] = POLLPRI;
+ poll_events[i] = FTDM_EVENTS;
if (openr2_chan_get_read_enabled(r2chan)) {
- poll_events[i] |= POLLIN;
+ poll_events[i] |= FTDM_READ;
}
}
-
status = ftdm_span_poll_event(span, waitms, poll_events);
-#else
- status = ftdm_span_poll_event(span, waitms, NULL);
-#endif
/* run any span timers */
ftdm_sched_run(r2data->sched);
@@ -1764,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);
@@ -1773,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 */
@@ -1786,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);
}
}
@@ -1794,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);
@@ -1850,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 \n" \
+"ftdm r2 loopstats \n" \
+"ftdm r2 block|unblock []\n" \
+"ftdm r2 version\n" \
+"ftdm r2 variants\n" \
+"--------------------------------------------------------------------------------\n"
static FIO_API_FUNCTION(ftdm_r2_api)
{
ftdm_span_t *span = NULL;
@@ -1951,7 +2146,7 @@ static FIO_API_FUNCTION(ftdm_r2_api)
"Max DNIS: %d\n"
"ANI First: %s\n"
"Immediate Accept: %s\n"
- "Job Thread: %lu\n"
+ "Job Thread: %u\n"
"Job Max ms: %d\n"
"Job Loops: %lu\n",
openr2_proto_get_variant_string(r2variant),
@@ -2033,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");
@@ -2066,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:
@@ -2095,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;
}
@@ -2115,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;
}
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c
index 50a01cc0ec..d0bc14c8d8 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c
@@ -839,7 +839,7 @@ static void handle_call_released(ftdm_span_t *span, sangomabc_connection_t *mcon
if ((ftdmchan = find_ftdmchan(span, event, 1))) {
ftdm_log(FTDM_LOG_DEBUG, "Releasing completely chan s%dc%d\n", BOOST_EVENT_SPAN(mcon->sigmod, event),
BOOST_EVENT_CHAN(mcon->sigmod, event));
- ftdm_channel_done(ftdmchan);
+ ftdm_channel_close(&ftdmchan);
} else {
ftdm_log(FTDM_LOG_CRIT, "Odd, We could not find chan: s%dc%d to release the call completely!!\n",
BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event));
@@ -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",
@@ -1105,8 +1104,9 @@ static void handle_call_loop_start(ftdm_span_t *span, sangomabc_connection_t *mc
ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_IN_LOOP, res);
if (res != FTDM_SUCCESS) {
+ ftdm_channel_t *toclose = ftdmchan;
ftdm_log(FTDM_LOG_CRIT, "yay, could not set the state of the channel to IN_LOOP, loop will fail\n");
- ftdm_channel_done(ftdmchan);
+ ftdm_channel_close(&toclose);
return;
}
ftdm_log(FTDM_LOG_DEBUG, "%d:%d starting loop\n", ftdmchan->span_id, ftdmchan->chan_id);
@@ -1266,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;
}
@@ -1353,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;
}
@@ -1365,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;
@@ -1373,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));
@@ -1388,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:
{
@@ -1426,11 +1422,12 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
ftdmchan->sflags = 0;
memset(ftdmchan->call_data, 0, sizeof(sangoma_boost_call_t));
if (sangoma_boost_data->sigmod && call_stopped_ack_sent) {
- /* we dont want to call ftdm_channel_done just yet until call released is received */
+ /* we dont want to call ftdm_channel_close just yet until call released is received */
ftdm_log(FTDM_LOG_DEBUG, "Waiting for call release confirmation before declaring chan %d:%d as available \n",
ftdmchan->span_id, ftdmchan->chan_id);
} else {
- ftdm_channel_done(ftdmchan);
+ ftdm_channel_t *toclose = ftdmchan;
+ ftdm_channel_close(&toclose);
}
}
break;
@@ -1638,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));
-
}
/**
@@ -1683,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);
}
}
@@ -1693,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);
}
}
@@ -2476,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;
}
@@ -2685,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);
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c
index 982dd4794d..6ddb74d253 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c
@@ -31,6 +31,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#define _GNU_SOURCE
+
#if HAVE_NETDB_H
#include
#endif
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj
index e3930d8188..2e7fb82041 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj
@@ -40,11 +40,12 @@
Disabled
- 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;%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
@@ -95,10 +95,11 @@
Level3
EditAndContinue
+ MultiThreadedDebugDLL
freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)
- $(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;%(AdditionalLibraryDirectories)
true
Console
false
@@ -110,7 +111,7 @@
Disabled
- 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;%(AdditionalIncludeDirectories)
WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
@@ -119,6 +120,7 @@
Level3
ProgramDatabase
+ MultiThreadedDebugDLL
freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)
@@ -135,11 +137,13 @@
WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
EnableFastChecks
- MultiThreadedDebugDLL
+ MultiThreadedDLL
Level3
ProgramDatabase
+ C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)
+ Disabled
true
@@ -147,23 +151,27 @@
true
true
MachineX86
+ freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)
+ $(OutDir);C:\Program Files\sangoma\sng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)
WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
EnableFastChecks
- MultiThreadedDebugDLL
+ MultiThreadedDLL
Level3
ProgramDatabase
+ C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)
true
Windows
true
true
+ freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
index e20d3ae7e0..259bf18b81 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
@@ -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);
@@ -65,7 +64,13 @@ ftdm_state_map_t sangoma_isdn_state_map = {
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
{FTDM_ANY_STATE, FTDM_END},
- {FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END}
+ {FTDM_CHANNEL_STATE_RESET, FTDM_CHANNEL_STATE_RESTART, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RESET, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
},
{
ZSD_INBOUND,
@@ -170,7 +175,13 @@ ftdm_state_map_t sangoma_isdn_state_map = {
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
{FTDM_ANY_STATE, FTDM_END},
- {FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_SUSPENDED, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+ {FTDM_CHANNEL_STATE_RESET, FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+ },
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RESET, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
},
{
ZSD_OUTBOUND,
@@ -203,7 +214,7 @@ ftdm_state_map_t sangoma_isdn_state_map = {
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_DIALING, FTDM_END},
{FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP,
- FTDM_CHANNEL_STATE_PROCEED, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP,
+ FTDM_CHANNEL_STATE_PROCEED, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP,
FTDM_CHANNEL_STATE_DOWN, FTDM_END}
},
{
@@ -211,14 +222,20 @@ ftdm_state_map_t sangoma_isdn_state_map = {
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_PROCEED, FTDM_END},
{FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP,
- FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
- },
+ FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
+ },
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
{FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
},
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RINGING, FTDM_END},
+ {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
+ },
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
@@ -252,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;
@@ -439,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);
}
@@ -452,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;
}
@@ -518,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;
}
@@ -582,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;
@@ -600,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
@@ -680,8 +690,17 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
break;
case FTDM_CHANNEL_STATE_RINGING:
{
- ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN};
- sngisdn_snd_alert(ftdmchan, prog_ind);
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ /* OUTBOUND...so we were told by the line of this so notify the user */
+ sigev.event_id = FTDM_SIGEVENT_RINGING;
+ ftdm_span_send_signal(ftdmchan->span, &sigev);
+ if (sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY)) {
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ }
+ } else {
+ ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN};
+ sngisdn_snd_alert(ftdmchan, prog_ind);
+ }
}
break;
case FTDM_CHANNEL_STATE_PROGRESS:
@@ -692,12 +711,9 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
sigev.event_id = FTDM_SIGEVENT_PROGRESS;
ftdm_span_send_signal(ftdmchan->span, &sigev);
} else {
- /* If we already sent a PROCEED before, do not send a PROGRESS as there is nothing to indicate to the remote switch */
- if (ftdmchan->last_state != FTDM_CHANNEL_STATE_PROCEED) {
- /* Send a progress message, indicating: Call is not end-to-end ISDN, further call progress may be available */
- ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN};
- sngisdn_snd_progress(ftdmchan, prog_ind);
- }
+ /* Send a progress message, indicating: Call is not end-to-end ISDN, further call progress may be available */
+ ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN};
+ sngisdn_snd_progress(ftdmchan, prog_ind);
}
}
break;
@@ -780,7 +796,7 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
sngisdn_snd_release(ftdmchan, 0);
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
- sngisdn_set_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN);
+ sngisdn_set_span_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN);
}
} else {
sngisdn_snd_disconnect(ftdmchan);
@@ -838,6 +854,11 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
/* IMPLEMENT ME */
}
break;
+ case FTDM_CHANNEL_STATE_RESET:
+ {
+ sngisdn_snd_restart(ftdmchan);
+ }
+ break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "unsupported sngisdn_rcvd state %s\n", ftdm_channel_state2str(ftdmchan->state));
@@ -850,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)
@@ -862,10 +882,6 @@ static FIO_CHANNEL_SEND_MSG_FUNCTION(ftdm_sangoma_isdn_send_msg)
ftdm_status_t status = FTDM_FAIL;
switch (sigmsg->event_id) {
- case FTDM_SIGEVENT_RESTART:
- /* TODO: Send a channel restart here */
- /* Implement me */
- break;
case FTDM_SIGEVENT_FACILITY:
sngisdn_snd_fac_req(ftdmchan);
break;
@@ -951,7 +967,8 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_span_sig_status)
}
static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span)
-{
+{
+ sngisdn_span_data_t *signal_data = span->signal_data;
ftdm_log(FTDM_LOG_INFO,"Starting span %s:%u.\n",span->name,span->span_id);
if (sngisdn_stack_start(span) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name);
@@ -961,6 +978,14 @@ static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span)
ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
+ if (signal_data->raw_trace_q921 == SNGISDN_OPT_TRUE) {
+ sngisdn_activate_trace(span, SNGISDN_TRACE_Q921);
+ }
+
+ if (signal_data->raw_trace_q931 == SNGISDN_OPT_TRUE) {
+ sngisdn_activate_trace(span, SNGISDN_TRACE_Q931);
+ }
+
/*start the span monitor thread*/
if (ftdm_thread_create_detached(ftdm_sangoma_isdn_run, span) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT,"Failed to start Sangoma ISDN Span Monitor Thread!\n");
@@ -1064,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);
@@ -1072,7 +1098,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
if (span->trunk_type == FTDM_TRUNK_BRI_PTMP ||
span->trunk_type == FTDM_TRUNK_BRI) {
- sngisdn_set_avail_rate(span, SNGISDN_AVAIL_PWR_SAVING);
+ sngisdn_set_span_avail_rate(span, SNGISDN_AVAIL_PWR_SAVING);
}
/* Initialize scheduling context */
@@ -1167,6 +1193,7 @@ static FIO_API_FUNCTION(ftdm_sangoma_isdn_api)
goto done;
}
+ /* TODO: Move functions to table + function pointers */
if (!strcasecmp(argv[0], "trace")) {
char *trace_opt;
@@ -1184,6 +1211,7 @@ static FIO_API_FUNCTION(ftdm_sangoma_isdn_api)
stream->write_function(stream, "-ERR failed to find span by name %s\n", argv[2]);
goto done;
}
+
if (!strcasecmp(trace_opt, "q921")) {
sngisdn_activate_trace(span, SNGISDN_TRACE_Q921);
} else if (!strcasecmp(trace_opt, "q931")) {
@@ -1192,7 +1220,7 @@ static FIO_API_FUNCTION(ftdm_sangoma_isdn_api)
sngisdn_activate_trace(span, SNGISDN_TRACE_DISABLE);
} else {
stream->write_function(stream, "-ERR invalid trace option \n");
- }
+ }
}
if (!strcasecmp(argv[0], "l1_stats")) {
ftdm_span_t *span;
@@ -1210,7 +1238,7 @@ static FIO_API_FUNCTION(ftdm_sangoma_isdn_api)
}
sngisdn_print_phy_stats(stream, span);
}
-
+
if (!strcasecmp(argv[0], "show_spans")) {
ftdm_span_t *span = NULL;
if (argc == 2) {
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
index f15eff9200..6a440e4f66 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
@@ -101,9 +101,11 @@ typedef enum {
FLAG_GLARE = (1 << 6),
FLAG_DELAYED_REL = (1 << 7),
FLAG_SENT_PROCEED = (1 << 8),
- FLAG_SEND_DISC = (1 << 9),
+ FLAG_SEND_DISC = (1 << 9),
/* Used for BRI only, flag is set after we request line CONNECTED */
- FLAG_ACTIVATING = (1 << 10),
+ FLAG_ACTIVATING = (1 << 10),
+ /* Used when we receive an ALERT msg + inband tones ready */
+ FLAG_MEDIA_READY = (1 << 11),
} sngisdn_flag_t;
@@ -259,6 +261,8 @@ typedef struct sngisdn_span_data {
int8_t facility_timeout;
uint8_t num_local_numbers;
uint8_t ignore_cause_value;
+ uint8_t raw_trace_q931;
+ uint8_t raw_trace_q921;
uint8_t timer_t3;
uint8_t restart_opt;
char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS];
@@ -352,8 +356,11 @@ void clear_call_glare_data(sngisdn_chan_data_t *sngisdn_info);
ftdm_status_t get_ftdmchan_by_suInstId(int16_t cc_id, uint32_t suInstId, sngisdn_chan_data_t **sngisdn_data);
ftdm_status_t get_ftdmchan_by_spInstId(int16_t cc_id, uint32_t spInstId, sngisdn_chan_data_t **sngisdn_data);
+ftdm_status_t sngisdn_set_span_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail);
+ftdm_status_t sngisdn_set_chan_avail_rate(ftdm_channel_t *chan, sngisdn_avail_t avail);
+void sngisdn_set_span_sig_status(ftdm_span_t *ftdmspan, ftdm_signaling_status_t status);
+void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status);
-ftdm_status_t sngisdn_set_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail);
ftdm_status_t sngisdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt);
@@ -374,6 +381,7 @@ void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan);
void sngisdn_snd_fac_req(ftdm_channel_t *ftdmchan);
void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan);
void sngisdn_snd_status_enq(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_restart(ftdm_channel_t *ftdmchan);
void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len);
void sngisdn_snd_event(ftdm_channel_t *dchan, ftdm_oob_event_t event);
@@ -421,8 +429,11 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event);
void sngisdn_rcv_phy_ind(SuId suId, Reason reason);
void sngisdn_rcv_q921_ind(BdMngmt *status);
-void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len);
-void sngisdn_trace_q931(char* str, uint8_t* data, uint32_t data_len);
+void sngisdn_trace_interpreted_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len);
+void sngisdn_trace_interpreted_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len);
+void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len);
+void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len);
+
void get_memory_info(void);
ftdm_status_t sng_isdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt);
@@ -453,6 +464,9 @@ ftdm_status_t set_redir_num(ftdm_channel_t *ftdmchan, RedirNmb *redirNmb);
ftdm_status_t set_calling_name(ftdm_channel_t *ftdmchan, ConEvnt *conEvnt);
ftdm_status_t set_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad);
ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_sngisdn_progind_t prog_ind);
+ftdm_status_t set_bear_cap_ie(ftdm_channel_t *ftdmchan, BearCap *bearCap);
+ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId);
+ftdm_status_t set_restart_ind_ie(ftdm_channel_t *ftdmchan, RstInd *rstInd);
ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr);
ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t *data_len);
@@ -482,7 +496,6 @@ static __inline__ void sngisdn_set_flag(sngisdn_chan_data_t *sngisdn_info, sngis
void handle_sng_log(uint8_t level, char *fmt,...);
-void sngisdn_set_span_sig_status(ftdm_span_t *ftdmspan, ftdm_signaling_status_t status);
void sngisdn_delayed_setup(void* p_sngisdn_info);
void sngisdn_delayed_release(void* p_sngisdn_info);
void sngisdn_delayed_connect(void* p_sngisdn_info);
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c
index cce10cc1dd..c979000223 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c
@@ -296,6 +296,10 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
parse_yesno(var, val, &signal_data->facility_ie_decode);
} else if (!strcasecmp(var, "ignore-cause-value")) {
parse_yesno(var, val, &signal_data->ignore_cause_value);
+ } else if (!strcasecmp(var, "q931-raw-trace")) {
+ parse_yesno(var, val, &signal_data->raw_trace_q931);
+ } else if (!strcasecmp(var, "q921-raw-trace")) {
+ parse_yesno(var, val, &signal_data->raw_trace_q921);
} else {
ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var);
}
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c
index 5060cb6bba..668b63006c 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c
@@ -47,7 +47,7 @@ void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status
sig.span_id = ftdmchan->span_id;
sig.channel = ftdmchan;
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sig.sigstatus = status;
+ sig.ev_data.sigstatus.status = status;
ftdm_span_send_signal(ftdmchan->span, &sig);
return;
}
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
index fb65d20cab..7e9e360c6d 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
@@ -33,7 +33,8 @@
*/
#include "ftmod_sangoma_isdn.h"
-ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn);
+static ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn);
+static void sngisdn_process_restart_confirm(ftdm_channel_t *ftdmchan);
/* Remote side transmit a SETUP */
void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
@@ -232,6 +233,9 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
}
break;
+ case FTDM_CHANNEL_STATE_RESET:
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n");
+ break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing SETUP in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
break;
@@ -274,6 +278,7 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event)
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
switch(ftdmchan->state) {
case FTDM_CHANNEL_STATE_PROCEED:
+ case FTDM_CHANNEL_STATE_RINGING:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_DIALING:
@@ -285,6 +290,9 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event)
case FTDM_CHANNEL_STATE_HANGUP:
/* Race condition, we just hung up the call - ignore this message */
break;
+ case FTDM_CHANNEL_STATE_RESET:
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n");
+ break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing CONNECT/CONNECT ACK in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
@@ -301,6 +309,9 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event)
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
/* Race condition, We just hung up an incoming call right after we sent a CONNECT - ignore this message */
break;
+ case FTDM_CHANNEL_STATE_RESET:
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n");
+ break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing CONNECT/CONNECT ACK in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
@@ -354,27 +365,47 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
goto sngisdn_process_cnst_ind_end;
}
-
+
switch(ftdmchan->state) {
case FTDM_CHANNEL_STATE_DIALING:
case FTDM_CHANNEL_STATE_PROCEED:
- if (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL) {
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
- } else if (evntType == MI_CALLPROC) {
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROCEED);
- } else {
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
- }
- break;
case FTDM_CHANNEL_STATE_PROGRESS:
+ case FTDM_CHANNEL_STATE_RINGING:
if (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL) {
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ sngisdn_set_flag(sngisdn_info, FLAG_MEDIA_READY);
+ }
+ switch (evntType) {
+ case MI_CALLPROC:
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROCEED);
+ }
+ break;
+ case MI_ALERTING:
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_PROCEED) {
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RINGING);
+ }
+ break;
+ case MI_PROGRESS:
+ if (sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY)) {
+
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ } else if (ftdmchan->state != FTDM_CHANNEL_STATE_PROGRESS) {
+
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS);
+ }
+ break;
+ default:
+ /* We should never reach this section !*/
+ ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle this event %d\n", evntType);
}
break;
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
/* We are already in progress media, we can't go to any higher state except up */
/* Do nothing */
break;
+ case FTDM_CHANNEL_STATE_RESET:
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n");
+ break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing ALERT/PROCEED/PROGRESS in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state));
@@ -414,6 +445,9 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
case FTDM_CHANNEL_STATE_UP:
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Receiving more digits %s, but we already proceeded with call\n", cnStEvnt->cdPtyNmb.nmbDigits.val);
break;
+ case FTDM_CHANNEL_STATE_RESET:
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n");
+ break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "\n", suId, suInstId, spInstId);
break;
@@ -477,6 +511,9 @@ void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event)
/* This is a race condition. We just sent a DISCONNECT, on this channel */
/* Do nothing */
break;
+ case FTDM_CHANNEL_STATE_RESET:
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n");
+ break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received DISCONNECT in an invalid state (%s)\n",
ftdm_channel_state2str(ftdmchan->state));
@@ -531,7 +568,7 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event)
case FTDM_CHANNEL_STATE_DIALING:
/* Remote side rejected our SETUP message on outbound call */
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
- sngisdn_set_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN);
+ sngisdn_set_span_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN);
}
/* fall-through */
case FTDM_CHANNEL_STATE_PROCEED:
@@ -581,6 +618,9 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event)
/* set abort flag so that we do not transmit another release complete on this channel once FS core is done */
}
break;
+ case FTDM_CHANNEL_STATE_RESET:
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n");
+ break;
default:
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received RELEASE in an invalid state (%s)\n",
ftdm_channel_state2str(ftdmchan->state));
@@ -1050,18 +1090,91 @@ void sngisdn_process_srv_cfm (sngisdn_event_data_t *sngisdn_event)
return;
}
+static void sngisdn_process_restart_confirm(ftdm_channel_t *ftdmchan)
+{
+ switch (ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_RESET:
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ break;
+ case FTDM_CHANNEL_STATE_DOWN:
+ /* Do nothing */
+ break;
+ default:
+ ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received RESTART CFM in an invalid state (%s)\n",
+ ftdm_channel_state2str(ftdmchan->state));
+ }
+
+ return;
+}
+
+
void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event)
{
int16_t suId = sngisdn_event->suId;
int16_t dChan = sngisdn_event->dChan;
uint8_t ces = sngisdn_event->ces;
uint8_t evntType = sngisdn_event->evntType;
-
- ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
-
- /* Function does not require any info from ssHlEvnt struct for now */
- /*Rst *rstEvnt = &sngisdn_event->event.rstEvnt;*/
+ uint8_t chan_no = 0;
+ Rst *rstEvnt = &sngisdn_event->event.rstEvnt;
+ sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[dChan].spans[1];
+ if (!signal_data) {
+ ftdm_log(FTDM_LOG_CRIT, "Received RESTART on unconfigured span (suId:%d)\n", suId);
+ return;
+ }
+
+ if (!rstEvnt->rstInd.eh.pres || !rstEvnt->rstInd.rstClass.pres) {
+ ftdm_log(FTDM_LOG_DEBUG, "Receved RESTART, but Restart Indicator IE not present\n");
+ return;
+ }
+
+ switch(rstEvnt->rstInd.rstClass.val) {
+ case IN_CL_INDCHAN: /* Indicated b-channel */
+ if (rstEvnt->chanId.eh.pres) {
+ if (rstEvnt->chanId.intType.val == IN_IT_BASIC) {
+ if (rstEvnt->chanId.infoChanSel.pres == PRSNT_NODEF) {
+ chan_no = rstEvnt->chanId.infoChanSel.val;
+ }
+ } else if (rstEvnt->chanId.intType.val == IN_IT_OTHER) {
+ if (rstEvnt->chanId.chanNmbSlotMap.pres == PRSNT_NODEF) {
+ chan_no = rstEvnt->chanId.chanNmbSlotMap.val[0];
+ }
+ }
+ }
+ if (!chan_no) {
+ ftdm_log(FTDM_LOG_CRIT, "Failed to determine channel from RESTART\n");
+ return;
+ }
+ break;
+ case IN_CL_SNGINT: /* Single interface */
+ case IN_CL_ALLINT: /* All interfaces */
+ /* In case restart class indicates all interfaces, we will duplicate
+ this event on each span associated to this d-channel in sngisdn_rcv_rst_cfm,
+ so treat it as a single interface anyway */
+ break;
+ default:
+ ftdm_log(FTDM_LOG_CRIT, "Invalid restart indicator class:%d\n", rstEvnt->rstInd.rstClass.val);
+ return;
+ }
+
+ if (chan_no) { /* For a single channel */
+ if (chan_no > ftdm_span_get_chan_count(signal_data->ftdm_span)) {
+ ftdm_log(FTDM_LOG_CRIT, "Received RESTART on invalid channel:%d\n", chan_no);
+ } else {
+ ftdm_channel_t *ftdmchan = ftdm_span_get_channel(signal_data->ftdm_span, chan_no);
+ sngisdn_process_restart_confirm(ftdmchan);
+ }
+ } else { /* for all channels */
+ ftdm_iterator_t *chaniter = NULL;
+ ftdm_iterator_t *curr = NULL;
+
+ chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL);
+ for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
+ sngisdn_process_restart_confirm((ftdm_channel_t*)ftdm_iterator_current(curr));
+ }
+ ftdm_iterator_free(chaniter);
+ }
+
ftdm_log(FTDM_LOG_DEBUG, "Processing RESTART CFM (suId:%u dChan:%d ces:%d type:%d)\n", suId, dChan, ces, evntType);
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
@@ -1090,7 +1203,7 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event)
return;
}
-ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn)
+static ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn)
{
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
index 297c59c3b7..bb04f887ab 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
@@ -51,72 +51,6 @@ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan)
ftdm_mutex_unlock(g_sngisdn_data.ccs[signal_data->cc_id].mutex);
memset(&conEvnt, 0, sizeof(conEvnt));
-
- conEvnt.bearCap[0].eh.pres = PRSNT_NODEF;
- conEvnt.bearCap[0].infoTranCap.pres = PRSNT_NODEF;
- conEvnt.bearCap[0].infoTranCap.val = sngisdn_get_infoTranCap_from_user(ftdmchan->caller_data.bearer_capability);
-
- conEvnt.bearCap[0].codeStand0.pres = PRSNT_NODEF;
- conEvnt.bearCap[0].codeStand0.val = IN_CSTD_CCITT;
- conEvnt.bearCap[0].infoTranRate0.pres = PRSNT_NODEF;
- conEvnt.bearCap[0].infoTranRate0.val = IN_ITR_64KBIT;
- conEvnt.bearCap[0].tranMode.pres = PRSNT_NODEF;
- conEvnt.bearCap[0].tranMode.val = IN_TM_CIRCUIT;
-
- conEvnt.chanId.eh.pres = PRSNT_NODEF;
- conEvnt.chanId.prefExc.pres = PRSNT_NODEF;
- conEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
- conEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
- conEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
- conEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
- conEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
- conEvnt.chanId.intIdent.pres = NOTPRSNT;
-
- if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
- ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
- /* Trillium stack rejests lyr1Ident on BRI, but Netbricks always sends it.
- Check with Trillium if this ever causes calls to fail in the field */
-
- /* BRI only params */
- conEvnt.chanId.intType.pres = PRSNT_NODEF;
- conEvnt.chanId.intType.val = IN_IT_BASIC;
- conEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
- conEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
- } else {
- /* PRI only params */
- conEvnt.bearCap[0].usrInfoLyr1Prot.pres = PRSNT_NODEF;
- conEvnt.bearCap[0].usrInfoLyr1Prot.val = sngisdn_get_usrInfoLyr1Prot_from_user(ftdmchan->caller_data.bearer_layer1);
-
- if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN &&
- conEvnt.bearCap[0].usrInfoLyr1Prot.val == IN_UIL1_G711ULAW) {
-
- /* We are bridging a call from T1 */
- conEvnt.bearCap[0].usrInfoLyr1Prot.val = IN_UIL1_G711ALAW;
-
- } else if (conEvnt.bearCap[0].usrInfoLyr1Prot.val == IN_UIL1_G711ALAW) {
-
- /* We are bridging a call from E1 */
- conEvnt.bearCap[0].usrInfoLyr1Prot.val = IN_UIL1_G711ULAW;
- }
-
- conEvnt.bearCap[0].lyr1Ident.pres = PRSNT_NODEF;
- conEvnt.bearCap[0].lyr1Ident.val = IN_L1_IDENT;
-
- conEvnt.chanId.intType.pres = PRSNT_NODEF;
- conEvnt.chanId.intType.val = IN_IT_OTHER;
- conEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
- conEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN;
- conEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
- conEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
- conEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
- conEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
- conEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
- conEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
- conEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
- conEvnt.chanId.chanNmbSlotMap.len = 1;
- conEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
- }
-
if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN) {
conEvnt.sndCmplt.eh.pres = PRSNT_NODEF;
}
@@ -126,6 +60,8 @@ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan)
}
ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Outgoing call: Called No:[%s] Calling No:[%s]\n", ftdmchan->caller_data.dnis.digits, ftdmchan->caller_data.cid_num.digits);
+ set_chan_id_ie(ftdmchan, &conEvnt.chanId);
+ set_bear_cap_ie(ftdmchan, &conEvnt.bearCap[0]);
set_called_num(ftdmchan, &conEvnt.cdPtyNmb);
set_calling_num(ftdmchan, &conEvnt.cgPtyNmb);
set_calling_num2(ftdmchan, &conEvnt.cgPtyNmb2);
@@ -161,38 +97,7 @@ void sngisdn_snd_setup_ack(ftdm_channel_t *ftdmchan)
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
- cnStEvnt.chanId.eh.pres = PRSNT_NODEF;
- cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF;
- cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
- cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
- cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
- cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
- cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
-
- if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
- ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
-
- /* BRI only params */
- cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
- cnStEvnt.chanId.intType.val = IN_IT_BASIC;
- cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
- cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
- } else {
- cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
- cnStEvnt.chanId.intType.val = IN_IT_OTHER;
- cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
- cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN;
- cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
- cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
- cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
- cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
- cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
- cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
- cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
- cnStEvnt.chanId.chanNmbSlotMap.len = 1;
- cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
- }
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending SETUP ACK (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
@@ -221,38 +126,7 @@ void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan)
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
- cnStEvnt.chanId.eh.pres = PRSNT_NODEF;
- cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF;
- cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
- cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
- cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
- cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
- cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
-
- if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
- ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
-
- /* BRI only params */
- cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
- cnStEvnt.chanId.intType.val = IN_IT_BASIC;
- cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
- cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
- } else {
- cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
- cnStEvnt.chanId.intType.val = IN_IT_OTHER;
- cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
- cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN;
- cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
- cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
- cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
- cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
- cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
- cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
- cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
- cnStEvnt.chanId.chanNmbSlotMap.len = 1;
- cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
- }
-
+ set_chan_id_ie(ftdmchan, &cnStEvnt.chanId);
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT COMPL (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
@@ -277,41 +151,11 @@ void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_i
}
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
-
- cnStEvnt.chanId.eh.pres = PRSNT_NODEF;
- cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF;
- cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
- cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
- cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
- cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
- cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
-
- if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
- ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
-
- /* BRI only params */
- cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
- cnStEvnt.chanId.intType.val = IN_IT_BASIC;
- cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
- cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
- } else {
- cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
- cnStEvnt.chanId.intType.val = IN_IT_OTHER;
- cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
- cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN;
- cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
- cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
- cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
- cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
- cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
- cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
- cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
- cnStEvnt.chanId.chanNmbSlotMap.len = 1;
- cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
- }
+ set_chan_id_ie(ftdmchan, &cnStEvnt.chanId);
set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind);
set_facility_ie(ftdmchan, &cnStEvnt.facilityStr);
+
ftdm_call_clear_data(&ftdmchan->caller_data);
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROCEED (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
@@ -397,39 +241,8 @@ void sngisdn_snd_connect(ftdm_channel_t *ftdmchan)
}
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
-
- cnStEvnt.chanId.eh.pres = PRSNT_NODEF;
- cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF;
- cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE;
- cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF;
- cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN;
- cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF;
- cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT;
- if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
- ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
-
- /* BRI only params */
- cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
- cnStEvnt.chanId.intType.val = IN_IT_BASIC;
- cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
- cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id;
- } else {
- cnStEvnt.chanId.intType.pres = PRSNT_NODEF;
- cnStEvnt.chanId.intType.val = IN_IT_OTHER;
- cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF;
- cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN;
- cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF;
- cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN;
- cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF;
- cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB;
- cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF;
- cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT;
- cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF;
- cnStEvnt.chanId.chanNmbSlotMap.len = 1;
- cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
- }
-
+ set_chan_id_ie(ftdmchan, &cnStEvnt.chanId);
set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind);
set_facility_ie(ftdmchan, &cnStEvnt.facilityStr);
ftdm_call_clear_data(&ftdmchan->caller_data);
@@ -563,6 +376,7 @@ void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan)
}
return;
}
+
void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare)
{
RelEvnt relEvnt;
@@ -618,6 +432,24 @@ void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare)
return;
}
+void sngisdn_snd_restart(ftdm_channel_t *ftdmchan)
+{
+ Rst rstEvnt;
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+ memset(&rstEvnt, 0, sizeof(rstEvnt));
+
+ set_chan_id_ie(ftdmchan, &rstEvnt.chanId);
+ set_restart_ind_ie(ftdmchan, &rstEvnt.rstInd);
+
+ ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending RESTART (suId:%d dchan:%d ces:%d)\n", signal_data->cc_id, signal_data->dchan_id, CES_MNGMNT);
+
+ if (sng_isdn_restart_request(signal_data->cc_id, &rstEvnt, signal_data->dchan_id, CES_MNGMNT, IN_SND_RST)) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused RESTART request\n");
+ }
+ return;
+}
+
/* We received an incoming frame on the d-channel, send data to the stack */
void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len)
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c
index af180d1f7c..3afdaa599e 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c
@@ -34,9 +34,6 @@
#include "ftmod_sangoma_isdn.h"
-#define MAX_DECODE_STR_LEN 2000
-
-
void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, ConEvnt *conEvnt, int16_t dChan, uint8_t ces)
{
uint8_t bchan_no = 0;
@@ -630,8 +627,9 @@ void sngisdn_rcv_rst_cfm (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces
ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+
ftdm_log(FTDM_LOG_INFO, "Received RESTART CFM (dChan:%d ces:%u type:%u)\n", dChan, ces, evntType);
-
+
/* Enqueue the event to each span within the dChan */
for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) {
signal_data = g_sngisdn_data.dchans[dChan].spans[i];
@@ -725,14 +723,25 @@ void sngisdn_rcv_q931_ind(InMngmt *status)
ftdmspan = signal_data->ftdm_span;
if (status->t.usta.alarm.event == LCM_EVENT_UP) {
+ uint32_t chan_no = status->t.usta.evntParm[2];
ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n",
status->t.usta.suId,
DECODE_LCM_CATEGORY(status->t.usta.alarm.category),
DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event,
DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
-
- sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_UP);
- sngisdn_set_avail_rate(ftdmspan, SNGISDN_AVAIL_UP);
+
+ if (chan_no) {
+ ftdm_channel_t *ftdmchan = ftdm_span_get_channel(ftdmspan, chan_no);
+ if (ftdmchan) {
+ sngisdn_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP);
+ sngisdn_set_chan_avail_rate(ftdmchan, SNGISDN_AVAIL_UP);
+ } else {
+ ftdm_log(FTDM_LOG_CRIT, "stack alarm event on invalid channel :%d\n", chan_no);
+ }
+ } else {
+ sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_UP);
+ sngisdn_set_span_avail_rate(ftdmspan, SNGISDN_AVAIL_UP);
+ }
} else {
ftdm_log(FTDM_LOG_WARNING, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n",
status->t.usta.suId,
@@ -741,7 +750,7 @@ void sngisdn_rcv_q931_ind(InMngmt *status)
DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause);
sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_DOWN);
- sngisdn_set_avail_rate(ftdmspan, SNGISDN_AVAIL_PWR_SAVING);
+ sngisdn_set_span_avail_rate(ftdmspan, SNGISDN_AVAIL_PWR_SAVING);
}
}
break;
@@ -765,9 +774,6 @@ void sngisdn_rcv_cc_ind(CcMngmt *status)
return;
}
-#define Q931_TRC_EVENT(event) (event == TL3PKTTX)?"TX": \
- (event == TL3PKTRX)?"RX":"UNKNOWN"
-
void sngisdn_rcv_q931_trace(InMngmt *trc, Buffer *mBuf)
{
MsgLen mlen;
@@ -776,13 +782,20 @@ void sngisdn_rcv_q931_trace(InMngmt *trc, Buffer *mBuf)
Buffer *tmp;
Data *cptr;
uint8_t data;
+ ftdm_trace_dir_t dir;
uint8_t tdata[1000];
- char *data_str = ftdm_calloc(1,MAX_DECODE_STR_LEN); /* TODO Find a proper size */
-
+ sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[trc->t.trc.suId];
+
ftdm_assert(mBuf != NULLP, "Received a Q931 trace with no buffer");
mlen = ((SsMsgInfo*)(mBuf->b_rptr))->len;
-
- if (mlen != 0) {
+
+ if (trc->t.trc.evnt == TL3PKTTX) {
+ dir = FTDM_TRACE_OUTGOING;
+ } else {
+ dir = FTDM_TRACE_INCOMING;
+ }
+
+ if (mlen) {
tmp = mBuf->b_cont;
cptr = tmp->b_rptr;
data = *cptr++;
@@ -797,41 +810,40 @@ void sngisdn_rcv_q931_trace(InMngmt *trc, Buffer *mBuf)
}
data = *cptr++;
}
-
- sngisdn_trace_q931(data_str, tdata, mlen);
- ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q931] s%d FRAME %s:%s\n", trc->t.trc.suId, Q931_TRC_EVENT(trc->t.trc.evnt), data_str);
+ if (signal_data->raw_trace_q931 == SNGISDN_OPT_TRUE) {
+ sngisdn_trace_raw_q931(signal_data, dir, tdata, mlen);
+ } else {
+ sngisdn_trace_interpreted_q931(signal_data, dir, tdata, mlen);
+ }
}
-
- ftdm_safe_free(data_str);
- /* We do not need to free mBuf in this case because stack does it */
- /* SPutMsg(mBuf); */
return;
}
-#define Q921_TRC_EVENT(event) (event == TL2FRMRX)?"RX": \
- (event == TL2FRMTX)?"TX": \
- (event == TL2TMR)?"TMR EXPIRED":"UNKNOWN"
-
void sngisdn_rcv_q921_trace(BdMngmt *trc, Buffer *mBuf)
{
MsgLen mlen;
+ Buffer *tmp;
MsgLen i;
int16_t j;
- Buffer *tmp;
Data *cptr;
uint8_t data;
- uint8_t tdata[16];
- char *data_str = ftdm_calloc(1,200); /* TODO Find a proper size */
-
+ ftdm_trace_dir_t dir;
+ uint8_t tdata[1000];
+ sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[trc->t.trc.lnkNmb];
if (trc->t.trc.evnt == TL2TMR) {
- goto end_of_trace;
+ return;
}
+ if (trc->t.trc.evnt == TL2FRMTX) {
+ dir = FTDM_TRACE_OUTGOING;
+ } else {
+ dir = FTDM_TRACE_INCOMING;
+ }
+
ftdm_assert(mBuf != NULLP, "Received a Q921 trace with no buffer");
mlen = ((SsMsgInfo*)(mBuf->b_rptr))->len;
-
if (mlen != 0) {
tmp = mBuf->b_cont;
cptr = tmp->b_rptr;
@@ -853,12 +865,12 @@ void sngisdn_rcv_q921_trace(BdMngmt *trc, Buffer *mBuf)
}
}
- sngisdn_trace_q921(data_str, tdata, mlen);
- ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] s%d FRAME %s:%s\n", trc->t.trc.lnkNmb, Q921_TRC_EVENT(trc->t.trc.evnt), data_str);
+ if (signal_data->raw_trace_q921 == SNGISDN_OPT_TRUE) {
+ sngisdn_trace_raw_q921(signal_data, dir, tdata, mlen);
+ } else {
+ sngisdn_trace_interpreted_q921(signal_data, dir, tdata, mlen);
+ }
}
-end_of_trace:
- ftdm_safe_free(data_str);
- SPutMsg(mBuf);
return;
}
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
index 76d11d6d34..28768a1f09 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
@@ -136,19 +136,25 @@ ftdm_status_t get_ftdmchan_by_spInstId(int16_t cc_id, uint32_t spInstId, sngisdn
return FTDM_SUCCESS;
}
-ftdm_status_t sngisdn_set_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail)
+ftdm_status_t sngisdn_set_chan_avail_rate(ftdm_channel_t *chan, sngisdn_avail_t avail)
{
- if (span->trunk_type == FTDM_TRUNK_BRI ||
- span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+ if (FTDM_SPAN_IS_BRI(chan->span)) {
+ ftdm_log_chan(chan, FTDM_LOG_DEBUG, "Setting availability rate to:%d\n", avail);
+ chan->availability_rate = avail;
+ }
+ return FTDM_SUCCESS;
+}
+ftdm_status_t sngisdn_set_span_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail)
+{
+ if (FTDM_SPAN_IS_BRI(span)) {
ftdm_iterator_t *chaniter = NULL;
ftdm_iterator_t *curr = NULL;
-
chaniter = ftdm_span_get_chan_iterator(span, NULL);
for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
ftdm_log_chan(((ftdm_channel_t*)ftdm_iterator_current(curr)), FTDM_LOG_DEBUG, "Setting availability rate to:%d\n", avail);
- ((ftdm_channel_t*)ftdm_iterator_current(curr))->availability_rate = avail;
+ sngisdn_set_chan_avail_rate(((ftdm_channel_t*)ftdm_iterator_current(curr)), avail);
}
ftdm_iterator_free(chaniter);
}
@@ -676,7 +682,6 @@ ftdm_status_t set_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad)
return FTDM_SUCCESS;
}
-
ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr)
{
ftdm_status_t status;
@@ -789,6 +794,93 @@ ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_s
return FTDM_SUCCESS;
}
+ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId)
+{
+ if (!ftdmchan) {
+ return FTDM_SUCCESS;
+ }
+ chanId->eh.pres = PRSNT_NODEF;
+ chanId->prefExc.pres = PRSNT_NODEF;
+ chanId->prefExc.val = IN_PE_EXCLSVE;
+ chanId->dChanInd.pres = PRSNT_NODEF;
+ chanId->dChanInd.val = IN_DSI_NOTDCHAN;
+ chanId->intIdentPres.pres = PRSNT_NODEF;
+ chanId->intIdentPres.val = IN_IIP_IMPLICIT;
+
+ if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI ||
+ ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
+
+ /* BRI only params */
+ chanId->intType.pres = PRSNT_NODEF;
+ chanId->intType.val = IN_IT_BASIC;
+ chanId->infoChanSel.pres = PRSNT_NODEF;
+ chanId->infoChanSel.val = ftdmchan->physical_chan_id;
+ } else {
+ chanId->intType.pres = PRSNT_NODEF;
+ chanId->intType.val = IN_IT_OTHER;
+ chanId->infoChanSel.pres = PRSNT_NODEF;
+ chanId->infoChanSel.val = IN_ICS_B1CHAN;
+ chanId->chanMapType.pres = PRSNT_NODEF;
+ chanId->chanMapType.val = IN_CMT_BCHAN;
+ chanId->nmbMap.pres = PRSNT_NODEF;
+ chanId->nmbMap.val = IN_NM_CHNNMB;
+ chanId->codeStand1.pres = PRSNT_NODEF;
+ chanId->codeStand1.val = IN_CSTD_CCITT;
+ chanId->chanNmbSlotMap.pres = PRSNT_NODEF;
+ chanId->chanNmbSlotMap.len = 1;
+ chanId->chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
+ }
+ return FTDM_SUCCESS;
+}
+
+ftdm_status_t set_bear_cap_ie(ftdm_channel_t *ftdmchan, BearCap *bearCap)
+{
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+ bearCap->eh.pres = PRSNT_NODEF;
+ bearCap->infoTranCap.pres = PRSNT_NODEF;
+ bearCap->infoTranCap.val = sngisdn_get_infoTranCap_from_user(ftdmchan->caller_data.bearer_capability);
+
+ bearCap->codeStand0.pres = PRSNT_NODEF;
+ bearCap->codeStand0.val = IN_CSTD_CCITT;
+ bearCap->infoTranRate0.pres = PRSNT_NODEF;
+ bearCap->infoTranRate0.val = IN_ITR_64KBIT;
+ bearCap->tranMode.pres = PRSNT_NODEF;
+ bearCap->tranMode.val = IN_TM_CIRCUIT;
+
+ if (!FTDM_SPAN_IS_BRI(ftdmchan->span)) {
+ /* Trillium stack rejests lyr1Ident on BRI, but Netbricks always sends it.
+ Check with Trillium if this ever causes calls to fail in the field */
+
+ /* PRI only params */
+ bearCap->usrInfoLyr1Prot.pres = PRSNT_NODEF;
+ bearCap->usrInfoLyr1Prot.val = sngisdn_get_usrInfoLyr1Prot_from_user(ftdmchan->caller_data.bearer_layer1);
+
+ if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN &&
+ bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ULAW) {
+
+ /* We are bridging a call from T1 */
+ bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ALAW;
+
+ } else if (bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ALAW) {
+
+ /* We are bridging a call from E1 */
+ bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ULAW;
+ }
+
+ bearCap->lyr1Ident.pres = PRSNT_NODEF;
+ bearCap->lyr1Ident.val = IN_L1_IDENT;
+ }
+ return FTDM_SUCCESS;
+}
+
+ftdm_status_t set_restart_ind_ie(ftdm_channel_t *ftdmchan, RstInd *rstInd)
+{
+ rstInd->eh.pres = PRSNT_NODEF;
+ rstInd->rstClass.pres = PRSNT_NODEF;
+ rstInd->rstClass.val = IN_CL_INDCHAN;
+ return FTDM_SUCCESS;
+}
void sngisdn_t3_timeout(void* p_sngisdn_info)
{
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c
index e5167164b3..8c421b0691 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c
@@ -36,14 +36,15 @@
#include "ftmod_sangoma_isdn_trace.h"
#define OCTET(x) (ieData[x-1] & 0xFF)
+#define MAX_DECODE_STR_LEN 2000
void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_start, uint32_t index_end);
-void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len);
-void sngisdn_trace_q931(char* str, uint8_t* data, uint32_t data_len);
uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset, uint8_t *data, uint16_t index_start);
uint8_t get_bits(uint8_t octet, uint8_t bitLo, uint8_t bitHi);
char* get_code_2_str(int code, struct code2str *pCodeTable);
+void sngisdn_decode_q921(char* str, uint8_t* data, uint32_t data_len);
+void sngisdn_decode_q931(char* str, uint8_t* data, uint32_t data_len);
char* get_code_2_str(int code, struct code2str *pCodeTable)
{
@@ -97,7 +98,43 @@ uint8_t get_bits(uint8_t octet, uint8_t bitLo, uint8_t bitHi)
return 0;
}
-void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len)
+void sngisdn_trace_interpreted_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len)
+{
+ char *data_str = ftdm_calloc(1,200); /* TODO Find a proper size */
+ sngisdn_decode_q921(data_str, data, data_len);
+ ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] s%d FRAME %s:%s\n", signal_data->ftdm_span->name, ftdm_trace_dir2str(dir), data_str);
+ ftdm_safe_free(data_str);
+}
+
+void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len)
+{
+ uint8_t *raw_data;
+ ftdm_sigmsg_t sigev;
+
+ memset(&sigev, 0, sizeof(sigev));
+
+ sigev.span_id = signal_data->ftdm_span->span_id;
+ sigev.chan_id = signal_data->dchan->chan_id;
+ sigev.channel = signal_data->dchan;
+ sigev.event_id = FTDM_SIGEVENT_TRACE_RAW;
+
+ sigev.ev_data.logevent.dir = dir;
+ sigev.ev_data.logevent.level = 2;
+
+ /* TODO: Map trace to call ID here */
+ sigev.call_id = 0;
+
+ raw_data = ftdm_malloc(data_len);
+ ftdm_assert(raw_data, "Failed to malloc");
+
+ memcpy(raw_data, data, 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);
+}
+
+void sngisdn_decode_q921(char* str, uint8_t* data, uint32_t data_len)
{
int str_len;
uint32_t i;
@@ -169,7 +206,43 @@ void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len)
return;
}
-void sngisdn_trace_q931(char* str, uint8_t* data, uint32_t data_len)
+
+void sngisdn_trace_interpreted_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len)
+{
+ char *data_str = ftdm_calloc(1,MAX_DECODE_STR_LEN); /* TODO Find a proper size */
+ sngisdn_decode_q931(data_str, data, data_len);
+ ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q931] %s FRAME %s:%s\n", signal_data->ftdm_span->name, ftdm_trace_dir2str(dir), data_str);
+ ftdm_safe_free(data_str);
+}
+
+void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len)
+{
+ uint8_t *raw_data;
+ ftdm_sigmsg_t sigev;
+
+ memset(&sigev, 0, sizeof(sigev));
+
+ sigev.span_id = signal_data->ftdm_span->span_id;
+ sigev.chan_id = signal_data->dchan->chan_id;
+ sigev.channel = signal_data->dchan;
+ sigev.event_id = FTDM_SIGEVENT_TRACE_RAW;
+
+ sigev.ev_data.logevent.dir = dir;
+ sigev.ev_data.logevent.level = 3;
+
+ /* TODO: Map trace to call ID here */
+
+ raw_data = ftdm_malloc(data_len);
+ ftdm_assert(raw_data, "Failed to malloc");
+
+ memcpy(raw_data, data, 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);
+}
+
+void sngisdn_decode_q931(char* str, uint8_t* data, uint32_t data_len)
{
uint32_t str_len;
uint8_t prot_disc, callRefFlag;
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c
index 34cca80140..dc2d24f42a 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c
@@ -1589,7 +1589,7 @@ static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int c
sigev.span_id = ftdmchan->span_id;
sigev.channel = ftdmchan;
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_DOWN;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN;
ftdm_span_send_signal(ftdmchan->span, &sigev);
/* if this is the first channel in the range */
@@ -1689,7 +1689,7 @@ static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int c
sigev.span_id = ftdmchan->span_id;
sigev.channel = ftdmchan;
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_UP;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_UP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
/* if this is the first channel in the range */
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c
index 7517ee42a0..dcfb7f79e0 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c
@@ -2004,7 +2004,7 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ
/* bring the sig status down */
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_DOWN;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN;
ftdm_span_send_signal(ftdmchan->span, &sigev);
/* unlock the channel again before we exit */
@@ -2135,7 +2135,7 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ
/* bring the sig status down */
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_UP;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_UP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
/* unlock the channel again before we exit */
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c
index 5c171a9f6b..9016771671 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c
@@ -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) {
@@ -841,7 +834,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
SS7_DEBUG_CHAN(ftdmchan,"All reset flags cleared %s\n", "");
/* all flags are down so we can bring up the sig status */
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_UP;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_UP;
ftdm_span_send_signal (ftdmchan->span, &sigev);
} /* if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) */
} /* if !blocked */
@@ -949,7 +942,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
/* if the sig_status is up...bring it down */
if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) {
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_DOWN;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN;
ftdm_span_send_signal (ftdmchan->span, &sigev);
}
@@ -1033,7 +1026,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
/* bring the sig status back up */
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_UP;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_UP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
}
@@ -1046,7 +1039,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
/* bring the sig status down */
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_DOWN;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN;
ftdm_span_send_signal(ftdmchan->span, &sigev);
/* go back to the last state */
@@ -1058,7 +1051,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
/* bring the sig status down */
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_DOWN;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN;
ftdm_span_send_signal(ftdmchan->span, &sigev);
/* send a BLA */
@@ -1076,7 +1069,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
/* bring the sig status up */
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_UP;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_UP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
/* send a uba */
@@ -1092,7 +1085,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
/* bring the sig status down */
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_DOWN;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN;
ftdm_span_send_signal(ftdmchan->span, &sigev);
/* send a blo */
@@ -1110,7 +1103,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
/* bring the sig status up */
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_UP;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_UP;
ftdm_span_send_signal(ftdmchan->span, &sigev);
/* send a ubl */
@@ -1149,7 +1142,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
/* bring the channel signaling status to down */
sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
- sigev.sigstatus = FTDM_SIG_STATE_DOWN;
+ sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN;
ftdm_span_send_signal (ftdmchan->span, &sigev);
/* remove any reset flags */
@@ -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 */
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h
index fe4b6f45c4..f28547f9fe 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h
@@ -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,...);
diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj
index b165ac82d3..40d0a73a5b 100644
--- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj
+++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj
@@ -100,7 +100,7 @@
EditAndContinue
- freetdm.lib;libsangoma.lib;%(AdditionalDependencies)
+ libsangoma.lib;%(AdditionalDependencies)
$(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)
true
Console
@@ -127,7 +127,7 @@
ProgramDatabase
- freetdm.lib;libsangoma.lib;%(AdditionalDependencies)
+ libsangoma.lib;%(AdditionalDependencies)
$(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories)
true
Console
@@ -148,7 +148,7 @@
ProgramDatabase
- freetdm.lib;libsangoma.lib;%(AdditionalDependencies)
+ libsangoma.lib;%(AdditionalDependencies)
$(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)
true
Console
@@ -174,7 +174,7 @@
ProgramDatabase
- freetdm.lib;libsangoma.lib;%(AdditionalDependencies)
+ libsangoma.lib;%(AdditionalDependencies)
$(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories)
true
Console
diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
index e1b6658945..2a203faf8d 100644
--- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
+++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
@@ -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;
}
@@ -1051,16 +1061,34 @@ FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
for(i = 1; i <= span->chan_count; i++) {
ftdm_channel_t *ftdmchan = span->channels[i];
+ uint32_t chan_events = 0;
+
+ /* translate events from ftdm to libsnagoma. if the user don't specify which events to poll the
+ * channel for, we just use SANG_WAIT_OBJ_HAS_EVENTS */
+ if (poll_events) {
+ if (poll_events[j] & FTDM_READ) {
+ chan_events = SANG_WAIT_OBJ_HAS_INPUT;
+ }
+ if (poll_events[j] & FTDM_WRITE) {
+ chan_events |= SANG_WAIT_OBJ_HAS_OUTPUT;
+ }
+ if (poll_events[j] & FTDM_EVENTS) {
+ chan_events |= SANG_WAIT_OBJ_HAS_EVENTS;
+ }
+ } else {
+ chan_events = SANG_WAIT_OBJ_HAS_EVENTS;
+ }
+
#ifdef LIBSANGOMA_VERSION
if (!ftdmchan->io_data) {
continue; /* should never happen but happens when shutting down */
}
pfds[j] = ftdmchan->io_data;
- inflags[j] = poll_events ? poll_events[j] : POLLPRI;
+ inflags[j] = chan_events;
#else
memset(&pfds[j], 0, sizeof(pfds[j]));
pfds[j].fd = span->channels[i]->sockfd;
- pfds[j].events = poll_events ? poll_events[j] : POLLPRI;
+ pfds[j].events = chan_events;
#endif
/* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */
@@ -1206,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
@@ -1219,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);
@@ -1231,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;
@@ -1401,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:
@@ -1520,9 +1471,7 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
return FTDM_SUCCESS;
}
}
-
return FTDM_FAIL;
-
}
/**
diff --git a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c
index 7320934a49..5b507bd0b9 100644
--- a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c
+++ b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c
@@ -31,7 +31,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
#include "private/ftdm_core.h"
#include "ftmod_zt.h"
@@ -53,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;
};
/**
@@ -182,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
@@ -986,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
@@ -998,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;
@@ -1147,6 +1209,7 @@ static FIO_WRITE_FUNCTION(zt_write)
bytes += 2;
}
+tryagain:
w = write(ftdmchan->sockfd, data, bytes);
if (w >= 0) {
@@ -1154,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;
}
diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h
index 4ee6ff5f52..38bc61188b 100644
--- a/libs/freetdm/src/include/freetdm.h
+++ b/libs/freetdm/src/include/freetdm.h
@@ -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,7 +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; /*! 0 if availability is supported
+ * \retval -1 if availability is not supported
+ */
+FT_DECLARE(int) ftdm_channel_get_availability(ftdm_channel_t *ftdmchan);
+
+/*! \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) */
@@ -672,7 +788,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) */
@@ -696,6 +824,14 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup(const char *file, const char
/*! \brief Hangup the call with cause recording the source code point where it was called (see ftdm_channel_call_hangup_with_cause for an easy to use macro) */
FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup_with_cause(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_call_cause_t);
+/*! \brief Reset the channel */
+#define ftdm_channel_reset(ftdmchan) _ftdm_channel_reset(__FILE__, __FUNCTION__, __LINE__, (ftdmchan))
+
+/*! \brief Reset the channel (see _ftdm_channel_reset for an easy to use macro)
+ * \note if there was a call on this channel, call will be cleared without any notifications to the user
+ */
+FT_DECLARE(ftdm_status_t) _ftdm_channel_reset(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan);
+
/*! \brief Put a call on hold (if supported by the signaling stack) */
#define ftdm_channel_call_hold(ftdmchan) _ftdm_channel_call_hold(__FILE__, __FUNCTION__, __LINE__, (ftdmchan))
@@ -735,6 +871,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_set_sig_status(ftdm_span_t *span, ftdm_signa
/*! \brief Get span signaling status (ie: whether protocol layer is up or down) */
FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signaling_status_t *status);
+
/*!
* \brief Set user private data in the channel
*
@@ -1404,9 +1541,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);
diff --git a/libs/freetdm/src/include/ftdm_call_utils.h b/libs/freetdm/src/include/ftdm_call_utils.h
index 835a5c6cdc..2418273343 100644
--- a/libs/freetdm/src/include/ftdm_call_utils.h
+++ b/libs/freetdm/src/include/ftdm_call_utils.h
@@ -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
+ * Ricardo Barroetaveña
+ *
*/
#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__ */
diff --git a/libs/freetdm/src/include/ftdm_declare.h b/libs/freetdm/src/include/ftdm_declare.h
index 4aba703f28..88a76930f7 100644
--- a/libs/freetdm/src/include/ftdm_declare.h
+++ b/libs/freetdm/src/include/ftdm_declare.h
@@ -158,12 +158,16 @@ typedef __int64 int64_t;
typedef __int32 int32_t;
typedef __int16 int16_t;
typedef __int8 int8_t;
+#define FTDM_O_BINARY O_BINARY
+#define FTDM_SIZE_FMT "Id"
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
#else
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
#endif /* _MSC_VER */
#else /* __WINDOWS__ */
+#define FTDM_O_BINARY 0
+#define FTDM_SIZE_FMT "zd"
#define FTDM_INVALID_SOCKET -1
typedef int ftdm_socket_t;
#include
@@ -179,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. */
diff --git a/libs/freetdm/src/include/ftdm_os.h b/libs/freetdm/src/include/ftdm_os.h
index 5026bb7236..a4605c3371 100644
--- a/libs/freetdm/src/include/ftdm_os.h
+++ b/libs/freetdm/src/include/ftdm_os.h
@@ -39,15 +39,21 @@
extern "C" {
#endif
+#if defined(__linux__) && !defined(__USE_BSD)
+#define __USE_BSD
+#endif
+
#include "ftdm_declare.h"
#include "ftdm_threadmutex.h"
-
#include
#ifndef __WINDOWS__
#include
#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)
@@ -111,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 */
diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h
index deabafd537..a5862e5d15 100644
--- a/libs/freetdm/src/include/private/ftdm_core.h
+++ b/libs/freetdm/src/include/private/ftdm_core.h
@@ -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);
@@ -599,10 +580,10 @@ FT_DECLARE(void) ftdm_channel_rotate_tokens(ftdm_channel_t *ftdmchan);
FT_DECLARE(int) ftdm_load_module(const char *name);
FT_DECLARE(int) ftdm_load_module_assume(const char *name);
FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap);
-FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan);
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
@@ -703,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;
diff --git a/libs/freetdm/src/include/private/ftdm_m3ua.h b/libs/freetdm/src/include/private/ftdm_m3ua.h
deleted file mode 100644
index 1bf830853c..0000000000
--- a/libs/freetdm/src/include/private/ftdm_m3ua.h
+++ /dev/null
@@ -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:
- */
-
diff --git a/libs/freetdm/src/include/private/ftdm_state.h b/libs/freetdm/src/include/private/ftdm_state.h
new file mode 100644
index 0000000000..7de015b72b
--- /dev/null
+++ b/libs/freetdm/src/include/private/ftdm_state.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies
+ * Moises Silva
+ * 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:
+ */
diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h
index 313044abc4..d79835733b 100644
--- a/libs/freetdm/src/include/private/ftdm_types.h
+++ b/libs/freetdm/src/include/private/ftdm_types.h
@@ -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,112 +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_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", "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,
diff --git a/libs/freetdm/src/m3ua/mstm3ua.c b/libs/freetdm/src/m3ua/mstm3ua.c
deleted file mode 100644
index 1d8179c58d..0000000000
--- a/libs/freetdm/src/m3ua/mstm3ua.c
+++ /dev/null
@@ -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);
-
-};
\ No newline at end of file
diff --git a/libs/freetdm/src/m3ua/mstm3ua.h b/libs/freetdm/src/m3ua/mstm3ua.h
deleted file mode 100644
index 13527dac35..0000000000
--- a/libs/freetdm/src/m3ua/mstm3ua.h
+++ /dev/null
@@ -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
-
diff --git a/libs/freetdm/src/m3ua_client.c b/libs/freetdm/src/m3ua_client.c
deleted file mode 100644
index 7608183896..0000000000
--- a/libs/freetdm/src/m3ua_client.c
+++ /dev/null
@@ -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
-#endif
-
-#include "freetdm.h"
-#include
-
-
-#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:
- */
-
-
diff --git a/libs/freetdm/src/m3ua_client.h b/libs/freetdm/src/m3ua_client.h
deleted file mode 100644
index e451156a41..0000000000
--- a/libs/freetdm/src/m3ua_client.h
+++ /dev/null
@@ -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
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-// Fix this for portability
-#include
-//#include
-#include
-#include
-#include
-//#include
-#include
-
-#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:
- */
diff --git a/libs/freetdm/src/testm3ua.c b/libs/freetdm/src/testm3ua.c
deleted file mode 100644
index 5848470e7a..0000000000
--- a/libs/freetdm/src/testm3ua.c
+++ /dev/null
@@ -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();
-
-}
diff --git a/libs/freetdm/src/testr2.c b/libs/freetdm/src/testr2.c
index 8ac90c59fd..72d98020bc 100644
--- a/libs/freetdm/src/testr2.c
+++ b/libs/freetdm/src/testr2.c
@@ -2,78 +2,158 @@
#include
#include
-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:
diff --git a/libs/freetdm/src/testsangomaboost.c b/libs/freetdm/src/testsangomaboost.c
index 01e5a6be22..b007fc186b 100644
--- a/libs/freetdm/src/testsangomaboost.c
+++ b/libs/freetdm/src/testsangomaboost.c
@@ -48,10 +48,7 @@
#include
#include
#include
-#if defined(__linux__) && !defined(__USE_BSD)
-#define __USE_BSD
-#endif
-#include
+
#include "freetdm.h"
diff --git a/libs/iksemel/configure.ac b/libs/iksemel/configure.ac
index f7687922c2..1b8af13683 100644
--- a/libs/iksemel/configure.ac
+++ b/libs/iksemel/configure.ac
@@ -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
diff --git a/libs/libg722_1/Makefile.am b/libs/libg722_1/Makefile.am
index f815fb8ddc..9d885335bb 100644
--- a/libs/libg722_1/Makefile.am
+++ b/libs/libg722_1/Makefile.am
@@ -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
diff --git a/libs/libg722_1/autogen.sh b/libs/libg722_1/autogen.sh
index 96422dbee3..98fb7e4f8a 100755
--- a/libs/libg722_1/autogen.sh
+++ b/libs/libg722_1/autogen.sh
@@ -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 ""
diff --git a/libs/libg722_1/configure.ac b/libs/libg722_1/configure.ac
index 64e276b280..62095ce374 100644
--- a/libs/libg722_1/configure.ac
+++ b/libs/libg722_1/configure.ac
@@ -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])
diff --git a/libs/libg722_1/doc/Makefile.am b/libs/libg722_1/doc/Makefile.am
index 4e58bbd8b8..a56809d00a 100644
--- a/libs/libg722_1/doc/Makefile.am
+++ b/libs/libg722_1/doc/Makefile.am
@@ -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
diff --git a/libs/libg722_1/g722_1.pc.in b/libs/libg722_1/g722_1.pc.in
new file mode 100644
index 0000000000..0fc01fbc73
--- /dev/null
+++ b/libs/libg722_1/g722_1.pc.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}
diff --git a/libs/libg722_1/g722_1.spec.in b/libs/libg722_1/g722_1.spec.in
index db1d06a686..0c2b26dbc3 100644
--- a/libs/libg722_1/g722_1.spec.in
+++ b/libs/libg722_1/g722_1.spec.in
@@ -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
diff --git a/libs/libg722_1/src/Makefile.am b/libs/libg722_1/src/Makefile.am
index 1943658d91..8600e920b2 100644
--- a/libs/libg722_1/src/Makefile.am
+++ b/libs/libg722_1/src/Makefile.am
@@ -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 "" $(VCPROJOUT); \
+ myfile=`echo $$file | sed -e 's|/|\\\\|g'`; \
+ echo "" $(VCPROJOUT8); \
done; \
- echo "" $(VCPROJOUT); \
+ echo "" $(VCPROJOUT8); \
for file in $(WIN32HEADERS); do \
- echo "" $(VCPROJOUT); \
+ myfile=`echo $$file | sed -e 's|/|\\\\|g'`; \
+ echo "" $(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 "" $(VCPROJOUT9); \
+ done; \
+ echo "" $(VCPROJOUT9); \
+ for file in $(WIN32HEADERS); do \
+ myfile=`echo $$file | sed -e 's|/|\\\\|g'`; \
+ echo "" $(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
-
-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
+ <$(srcdir)/g722_1/version.h.in >$@
diff --git a/libs/libg722_1/src/basop32.c b/libs/libg722_1/src/basop32.c
index 54220f4fac..3a51f45eee 100644
--- a/libs/libg722_1/src/basop32.c
+++ b/libs/libg722_1/src/basop32.c
@@ -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
#endif
+#include
+
#if defined(G722_1_USE_FIXED_POINT)
-#include
#include
#include
diff --git a/libs/libg722_1/src/basop32.h b/libs/libg722_1/src/basop32.h
index abc105f35e..36dae35297 100644
--- a/libs/libg722_1/src/basop32.h
+++ b/libs/libg722_1/src/basop32.h
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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
diff --git a/libs/libg722_1/src/bitstream.c b/libs/libg722_1/src/bitstream.c
index ddaabd0edf..016ab8ee45 100644
--- a/libs/libg722_1/src/bitstream.c
+++ b/libs/libg722_1/src/bitstream.c
@@ -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 */
diff --git a/libs/libg722_1/src/bitstream.h b/libs/libg722_1/src/bitstream.h
index 20e386513f..f2cc4b8bce 100644
--- a/libs/libg722_1/src/bitstream.h
+++ b/libs/libg722_1/src/bitstream.h
@@ -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 */
diff --git a/libs/libg722_1/src/coef2sam.c b/libs/libg722_1/src/coef2sam.c
index 38d4943ca8..19f5a211ac 100644
--- a/libs/libg722_1/src/coef2sam.c
+++ b/libs/libg722_1/src/coef2sam.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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
diff --git a/libs/libg722_1/src/coef2sam.h b/libs/libg722_1/src/coef2sam.h
index 731d28ddeb..21590761ea 100644
--- a/libs/libg722_1/src/coef2sam.h
+++ b/libs/libg722_1/src/coef2sam.h
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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)
diff --git a/libs/libg722_1/src/common.c b/libs/libg722_1/src/common.c
index 46f6595054..b763a8465d 100644
--- a/libs/libg722_1/src/common.c
+++ b/libs/libg722_1/src/common.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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;
diff --git a/libs/libg722_1/src/commonf.c b/libs/libg722_1/src/commonf.c
index dd2050aa1b..d86d1cf3ae 100644
--- a/libs/libg722_1/src/commonf.c
+++ b/libs/libg722_1/src/commonf.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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],
diff --git a/libs/libg722_1/src/dct4.c b/libs/libg722_1/src/dct4.c
index cb3a7fde03..9f0a61d6f6 100644
--- a/libs/libg722_1/src/dct4.c
+++ b/libs/libg722_1/src/dct4.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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 */
diff --git a/libs/libg722_1/src/dct4_a.c b/libs/libg722_1/src/dct4_a.c
index 0f9c90eba0..d4ed1504e1 100644
--- a/libs/libg722_1/src/dct4_a.c
+++ b/libs/libg722_1/src/dct4_a.c
@@ -6,29 +6,23 @@
* Adapted by Steve Underwood 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 --------------------------------------------------------*/
diff --git a/libs/libg722_1/src/dct4_a.h b/libs/libg722_1/src/dct4_a.h
index bcc63bf29d..4d4b95c68e 100644
--- a/libs/libg722_1/src/dct4_a.h
+++ b/libs/libg722_1/src/dct4_a.h
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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
diff --git a/libs/libg722_1/src/dct4_s.c b/libs/libg722_1/src/dct4_s.c
index 71151b3f14..c195693cef 100644
--- a/libs/libg722_1/src/dct4_s.c
+++ b/libs/libg722_1/src/dct4_s.c
@@ -6,29 +6,23 @@
* Adapted by Steve Underwood 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);
}
}
}
diff --git a/libs/libg722_1/src/dct4_s.h b/libs/libg722_1/src/dct4_s.h
index 68040d0659..533be1c7b9 100644
--- a/libs/libg722_1/src/dct4_s.h
+++ b/libs/libg722_1/src/dct4_s.h
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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] =
diff --git a/libs/libg722_1/src/decoder.c b/libs/libg722_1/src/decoder.c
index 80fcab4d5a..f1db32f282 100644
--- a/libs/libg722_1/src/decoder.c
+++ b/libs/libg722_1/src/decoder.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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++;
diff --git a/libs/libg722_1/src/decoderf.c b/libs/libg722_1/src/decoderf.c
index 761a0cff30..e0e8e61743 100644
--- a/libs/libg722_1/src/decoderf.c
+++ b/libs/libg722_1/src/decoderf.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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 --------------------------------------------------------*/
diff --git a/libs/libg722_1/src/defs.h b/libs/libg722_1/src/defs.h
index 7a565d0565..9c2c83dd10 100644
--- a/libs/libg722_1/src/defs.h
+++ b/libs/libg722_1/src/defs.h
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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)
diff --git a/libs/libg722_1/src/encoder.c b/libs/libg722_1/src/encoder.c
index fef4b44883..054d6b36bd 100644
--- a/libs/libg722_1/src/encoder.c
+++ b/libs/libg722_1/src/encoder.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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;
diff --git a/libs/libg722_1/src/encoderf.c b/libs/libg722_1/src/encoderf.c
index 36a52064f0..2589886aa3 100644
--- a/libs/libg722_1/src/encoderf.c
+++ b/libs/libg722_1/src/encoderf.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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;
diff --git a/libs/libg722_1/src/g722_1.h.in b/libs/libg722_1/src/g722_1.h.in
index e4a1e415b1..86c0921a65 100644
--- a/libs/libg722_1/src/g722_1.h.in
+++ b/libs/libg722_1/src/g722_1.h.in
@@ -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 */
diff --git a/libs/libg722_1/src/g722_1/g722_1.h b/libs/libg722_1/src/g722_1/g722_1.h
index 3408abbf31..6f2a497eb1 100644
--- a/libs/libg722_1/src/g722_1/g722_1.h
+++ b/libs/libg722_1/src/g722_1/g722_1.h
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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_)
diff --git a/libs/libg722_1/src/g722_1/version.h.in b/libs/libg722_1/src/g722_1/version.h.in
index f9c66d0745..e825425ce9 100644
--- a/libs/libg722_1/src/g722_1/version.h.in
+++ b/libs/libg722_1/src/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: version.h.in,v 1.2 2008/09/20 16:52:51 steveu Exp $
*/
#if !defined(_G722_1_VERSION_H_)
diff --git a/libs/libg722_1/src/huff_tab.c b/libs/libg722_1/src/huff_tab.c
index 07f5085b35..3583ba30ff 100644
--- a/libs/libg722_1/src/huff_tab.c
+++ b/libs/libg722_1/src/huff_tab.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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 */
diff --git a/libs/libg722_1/src/huff_tab.h b/libs/libg722_1/src/huff_tab.h
index a58b843f5e..3d58962c83 100644
--- a/libs/libg722_1/src/huff_tab.h
+++ b/libs/libg722_1/src/huff_tab.h
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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
diff --git a/libs/libg722_1/src/make_dct4_tables.c b/libs/libg722_1/src/make_dct4_tables.c
index 015daf355a..ffb4a94063 100644
--- a/libs/libg722_1/src/make_dct4_tables.c
+++ b/libs/libg722_1/src/make_dct4_tables.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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 ------------------------------------------------------------*/
diff --git a/libs/libg722_1/src/make_tables.c b/libs/libg722_1/src/make_tables.c
index d234d8a8a0..aa6d5cb748 100644
--- a/libs/libg722_1/src/make_tables.c
+++ b/libs/libg722_1/src/make_tables.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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 ------------------------------------------------------------*/
diff --git a/libs/libg722_1/src/sam2coef.c b/libs/libg722_1/src/sam2coef.c
index 50f61d27ce..604c2874c8 100644
--- a/libs/libg722_1/src/sam2coef.c
+++ b/libs/libg722_1/src/sam2coef.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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);
diff --git a/libs/libg722_1/src/sam2coef.h b/libs/libg722_1/src/sam2coef.h
index 26f3cbaa02..1df19bb48f 100644
--- a/libs/libg722_1/src/sam2coef.h
+++ b/libs/libg722_1/src/sam2coef.h
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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)
diff --git a/libs/libg722_1/src/tables.c b/libs/libg722_1/src/tables.c
index 62a0e8d808..a0eed803bf 100644
--- a/libs/libg722_1/src/tables.c
+++ b/libs/libg722_1/src/tables.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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
diff --git a/libs/libg722_1/src/tables.h b/libs/libg722_1/src/tables.h
index bf0aacba61..9b39979f18 100644
--- a/libs/libg722_1/src/tables.h
+++ b/libs/libg722_1/src/tables.h
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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
diff --git a/libs/libg722_1/src/utilities.c b/libs/libg722_1/src/utilities.c
new file mode 100644
index 0000000000..71cac6caf4
--- /dev/null
+++ b/libs/libg722_1/src/utilities.c
@@ -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
+#endif
+
+#include
+
+#if defined(G722_1_USE_MMX)
+#include
+#endif
+#if defined(G722_1_USE_SSE)
+#include
+#endif
+#if defined(G722_1_USE_SSE2)
+#include
+#endif
+#if defined(G722_1_USE_SSE3)
+#include
+#include
+#endif
+#if defined(G722_1_USE_SSE4_1)
+#include
+#endif
+#if defined(G722_1_USE_SSE4_2)
+#include
+#endif
+#if defined(G722_1_USE_SSE4A)
+#include
+#endif
+#if defined(G722_1_USE_SSE5)
+#include
+#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 ------------------------------------------------------------*/
diff --git a/libs/libg722_1/src/utilities.h b/libs/libg722_1/src/utilities.h
new file mode 100644
index 0000000000..9d17103a16
--- /dev/null
+++ b/libs/libg722_1/src/utilities.h
@@ -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 ------------------------------------------------------------*/
diff --git a/libs/libg722_1/test-data/Makefile.am b/libs/libg722_1/test-data/Makefile.am
index 83ddb94843..0b27a6830d 100644
--- a/libs/libg722_1/test-data/Makefile.am
+++ b/libs/libg722_1/test-data/Makefile.am
@@ -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
diff --git a/libs/libg722_1/test-data/itu/Makefile.am b/libs/libg722_1/test-data/itu/Makefile.am
index ae990154c0..df51ad0a07 100644
--- a/libs/libg722_1/test-data/itu/Makefile.am
+++ b/libs/libg722_1/test-data/itu/Makefile.am
@@ -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 =
diff --git a/libs/libg722_1/test-data/local/Makefile.am b/libs/libg722_1/test-data/local/Makefile.am
index a7aca423c5..142fb4cc4e 100644
--- a/libs/libg722_1/test-data/local/Makefile.am
+++ b/libs/libg722_1/test-data/local/Makefile.am
@@ -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 =
diff --git a/libs/libg722_1/tests/Makefile.am b/libs/libg722_1/tests/Makefile.am
index afad2f6433..aec0cecc29 100644
--- a/libs/libg722_1/tests/Makefile.am
+++ b/libs/libg722_1/tests/Makefile.am
@@ -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
diff --git a/libs/libg722_1/tests/g192_bit_stream.c b/libs/libg722_1/tests/g192_bit_stream.c
new file mode 100644
index 0000000000..36a853c6cc
--- /dev/null
+++ b/libs/libg722_1/tests/g192_bit_stream.c
@@ -0,0 +1,177 @@
+/*
+ * broadvoice - a library for the BroadVoice 16 and 32 codecs
+ *
+ * g192_bit_stream.c
+ *
+ * Copyright 2008-2009 Steve Underwood
+ *
+ * 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
+#include
+#include
+#include
+
+#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 ------------------------------------------------------------*/
diff --git a/libs/libg722_1/tests/g192_bit_stream.h b/libs/libg722_1/tests/g192_bit_stream.h
new file mode 100644
index 0000000000..1948aa2e80
--- /dev/null
+++ b/libs/libg722_1/tests/g192_bit_stream.h
@@ -0,0 +1,75 @@
+/*
+ * broadvoice - a library for the BroadVoice 16 and 32 codecs
+ *
+ * g192_bit_stream.h
+ *
+ * Copyright 2008-2009 Steve Underwood
+ *
+ * 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(_G192_BIT_STREAM_H_)
+#define _G192_BIT_STREAM_H_
+
+/*! \page g192_bit_stream_page ITU G.192 codec bit stream handling
+\section g192_bit_stream_page_sec_1 What does it do?
+
+\section g192_bit_stream_page_sec_2 How does it work?
+*/
+
+enum
+{
+ ITU_CODEC_BITSTREAM_PACKED = 0,
+ ITU_CODEC_BITSTREAM_G192 = 1
+};
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/*! \brief Write a frame of data to an output file.
+ \param out_data The buffer for the data to be written.
+ \param number_of_bits The number of bits to be written.
+ \param mode 0 = continuous, 1 = ITU G.192 codec bitstream format.
+ \param fp_bitstream The file context to be written to.
+ \return The number of words written. */
+int itu_codec_bitstream_write(const uint8_t out_data[],
+ int number_of_bits,
+ int mode,
+ FILE *fp_bitstream);
+
+/*! \brief Read a frame of data from an input file.
+ \param in_data The buffer for the data to be read.
+ \param p_erasure Set to TRUE if there is a frame erasure, else set to FALSE.
+ \param number_of_bits The number of bits to be read.
+ \param mode 0 = continuous, 1 = ITU G.192 codec bitstream format.
+ \param fp_bitstream The file context to be read from.
+ \return The number of words read. */
+int itu_codec_bitstream_read(uint8_t in_data[],
+ int16_t *p_erasure,
+ int number_of_bits,
+ int mode,
+ FILE *fp_bitstream);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
+/*- End of file ------------------------------------------------------------*/
diff --git a/libs/libg722_1/tests/g722_1_tests.c b/libs/libg722_1/tests/g722_1_tests.c
index 9f0b9519f9..7cc6befce1 100644
--- a/libs/libg722_1/tests/g722_1_tests.c
+++ b/libs/libg722_1/tests/g722_1_tests.c
@@ -6,14 +6,12 @@
* Adapted by Steve Underwood 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_tests.c,v 1.14 2008/11/21 15:30:22 steveu Exp $
*/
/*! \file */
@@ -36,7 +34,7 @@
#include
#include "timing.h"
-#include "itu_bit_stream.h"
+#include "g192_bit_stream.h"
typedef struct
{
@@ -227,7 +225,7 @@ static void parse_command_line(char *argv[], coder_control_t *control)
}
else if (strcasecmp(*argv, "i") == 0)
{
- control->encoded_format = ITU_CODEC_BITSTREAM_ITU;
+ control->encoded_format = ITU_CODEC_BITSTREAM_G192;
printf("Encoding format = ITU-format bitstream\n");
}
else
diff --git a/libs/libg722_1/tests/itu_bit_stream.c b/libs/libg722_1/tests/itu_bit_stream.c
deleted file mode 100644
index d07ef374eb..0000000000
--- a/libs/libg722_1/tests/itu_bit_stream.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * g722_1 - a library for the G.722.1 and Annex C codecs
- *
- * itu_bit_stream.c
- *
- * Adapted by Steve Underwood from the reference
- * code supplied with ITU G.722.1, which is:
- *
- * © 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: itu_bit_stream.c,v 1.6 2008/11/21 15:30:22 steveu Exp $
- */
-
-/*! \file */
-
-#if defined(HAVE_CONFIG_H)
-#include "config.h"
-#endif
-
-#include
-#include
-#include
-#include
-
-#include "itu_bit_stream.h"
-
-static const int16_t frame_start = 0x6B21;
-static const int16_t erased_frame_start = 0x6B20;
-static const int16_t one = 0x0081;
-static const int16_t zero = 0x007F;
-
-void 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)
- {
- fwrite(out_data, 1, number_of_bytes, fp_bitstream);
- return;
- }
- j = 0;
- out_array[j++] = frame_start;
- 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) ? one : zero;
- }
-
- 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 *p_frame_error_flag,
- int number_of_bits,
- int mode,
- FILE *fp_bitstream)
-{
- int i;
- int j;
- int bit_count;
- int nsamp;
- int len;
- int erased_frame;
- int16_t packed_word;
- int16_t bit;
- int16_t in_array[2 + number_of_bits];
-
- if (mode == ITU_CODEC_BITSTREAM_PACKED)
- return fread(in_data, 1, number_of_bits/8, fp_bitstream)*8;
-
- nsamp = fread(in_array, sizeof(int16_t), 2, fp_bitstream);
- if (nsamp < 2)
- return -1;
- if (in_array[0] != frame_start && in_array[0] != erased_frame_start)
- {
- *p_frame_error_flag = 1;
- return 0;
- }
- erased_frame = (in_array[0] == erased_frame_start);
- len = in_array[1];
- if (len > number_of_bits)
- {
- *p_frame_error_flag = 1;
- return 0;
- }
- nsamp = fread(in_array, sizeof(int16_t), len, fp_bitstream);
- if (nsamp != len)
- {
- *p_frame_error_flag = 1;
- return nsamp;
- }
- *p_frame_error_flag = 0;
-
- for (i = 0, j = 0; i < nsamp/8; i++)
- {
- packed_word = 0;
- bit_count = 7;
- while (bit_count >= 0)
- {
- bit = in_array[j++];
- if (bit == zero)
- bit = 0;
- else if (bit == one)
- bit = 1;
- else
- {
- /* Bad bit */
- bit = 1;
- *p_frame_error_flag = 1;
- /* printf("read_ITU_format: bit not zero or one: %4x\n", bit); */
- }
- packed_word = (packed_word << 1) | bit;
- bit_count--;
- }
- in_data[i] = packed_word;
- }
- if (erased_frame)
- *p_frame_error_flag = 1;
- return nsamp;
-}
-/*- End of function --------------------------------------------------------*/
-/*- End of file ------------------------------------------------------------*/
diff --git a/libs/libg722_1/tests/regression_tests.sh.in b/libs/libg722_1/tests/regression_tests.sh.in
index 6b52213b58..4be36b2008 100644
--- a/libs/libg722_1/tests/regression_tests.sh.in
+++ b/libs/libg722_1/tests/regression_tests.sh.in
@@ -16,9 +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: regression_tests.sh.in,v 1.4 2008/11/21 15:30:22 steveu Exp $
-#
STDOUT_DEST=xyzzy
STDERR_DEST=xyzzy2
@@ -33,7 +30,7 @@ diff $TMP_FILE ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_enc_out_32000.itu
RETVAL=$?
if [ $RETVAL != 0 ]
then
- echo g722_1_tests E failed!
+ echo g722_1_tests encode failed!
exit $RETVAL
fi
./g722_1_tests E I 24000 16000 ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_enc_in.pcm $TMP_FILE
@@ -41,17 +38,17 @@ diff $TMP_FILE ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_enc_out_24000.itu
RETVAL=$?
if [ $RETVAL != 0 ]
then
- echo g722_1_tests E failed!
+ echo g722_1_tests encode failed!
exit $RETVAL
fi
-echo g722_1_tests E completed OK
+echo g722_1_tests encode completed OK
./g722_1_tests D I 24000 16000 ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_enc_out_24000.itu $TMP_FILE
diff $TMP_FILE ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_dec_out_24000.pcm
RETVAL=$?
if [ $RETVAL != 0 ]
then
- echo g722_1_tests D failed!
+ echo g722_1_tests decode failed!
exit $RETVAL
fi
./g722_1_tests D I 32000 16000 ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_enc_out_32000.itu $TMP_FILE
@@ -59,7 +56,7 @@ diff $TMP_FILE ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_dec_out_32000.pcm
RETVAL=$?
if [ $RETVAL != 0 ]
then
- echo g722_1_tests D failed!
+ echo g722_1_tests decode failed!
exit $RETVAL
fi
@@ -68,7 +65,7 @@ diff $TMP_FILE ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_dec_out_24000_fe.pcm
RETVAL=$?
if [ $RETVAL != 0 ]
then
- echo g722_1_tests D failed!
+ echo g722_1_tests decode failed!
exit $RETVAL
fi
./g722_1_tests D I 32000 16000 ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_dec_in_32000_fe.itu $TMP_FILE
@@ -76,28 +73,28 @@ diff $TMP_FILE ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_dec_out_32000_fe.pcm
RETVAL=$?
if [ $RETVAL != 0 ]
then
- echo g722_1_tests D failed!
+ echo g722_1_tests decode failed!
exit $RETVAL
fi
-echo g722_1_tests D completed OK
+echo g722_1_tests decode completed OK
./g722_1_tests E I 32000 16000 ../test-data/local/short_wb_voice.wav $TMP_FILE
RETVAL=$?
if [ $RETVAL != 0 ]
then
- echo g722_1_tests E failed!
+ echo g722_1_tests encode failed!
exit $RETVAL
fi
-echo g722_1_tests E completed OK
+echo g722_1_tests encode completed OK
./g722_1_tests D I 32000 16000 $TMP_FILE test.au
RETVAL=$?
if [ $RETVAL != 0 ]
then
- echo g722_1_tests D failed!
+ echo g722_1_tests decode failed!
exit $RETVAL
fi
-echo g722_1_tests D completed OK
+echo g722_1_tests decode completed OK
echo
echo All regression tests successfully completed
diff --git a/libs/libg722_1/tests/timing.h b/libs/libg722_1/tests/timing.h
index 3fb1b3cc74..f95f3b8df1 100644
--- a/libs/libg722_1/tests/timing.h
+++ b/libs/libg722_1/tests/timing.h
@@ -1,5 +1,5 @@
/*
- * SpanDSP - a series of DSP components for telephony
+ * g722_1 - a library for the G.722.1 and Annex C codecs
*
* timing.h - Provide access to the Pentium/Athlon TSC timer register
*
@@ -21,8 +21,6 @@
* 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.
- *
- * $Id: timing.h,v 1.1 2008/10/17 15:17:39 steveu Exp $
*/
#if !defined(_TIMING_H_)
diff --git a/libs/libg722_1/unpack_g722_1_data.sh b/libs/libg722_1/unpack_g722_1_data.sh
index 75741e0dd1..f8b85f4d30 100755
--- a/libs/libg722_1/unpack_g722_1_data.sh
+++ b/libs/libg722_1/unpack_g722_1_data.sh
@@ -16,9 +16,6 @@
# 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.
-#
-# $Id: unpack_g722_1_data.sh,v 1.2 2008/09/26 12:09:29 steveu Exp $
-#
ITUDATA="../../../T-REC-G.722.1-200505-I!!SOFT-ZST-E.zip"
diff --git a/libs/openzap/mod_openzap/mod_openzap.c b/libs/openzap/mod_openzap/mod_openzap.c
index 8425372ef5..6a75dc85ff 100644
--- a/libs/openzap/mod_openzap/mod_openzap.c
+++ b/libs/openzap/mod_openzap/mod_openzap.c
@@ -821,7 +821,7 @@ static switch_status_t channel_receive_message_cas(switch_core_session_t *sessio
switch (msg->message_id) {
case SWITCH_MESSAGE_INDICATE_RINGING:
{
- if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
} else {
zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
@@ -830,7 +830,7 @@ static switch_status_t channel_receive_message_cas(switch_core_session_t *sessio
break;
case SWITCH_MESSAGE_INDICATE_PROGRESS:
{
- if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
} else {
@@ -841,7 +841,7 @@ static switch_status_t channel_receive_message_cas(switch_core_session_t *sessio
break;
case SWITCH_MESSAGE_INDICATE_ANSWER:
{
- if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
} else {
/* lets make the ozmod_r2 module life easier by moving thru each
@@ -888,7 +888,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session,
switch (msg->message_id) {
case SWITCH_MESSAGE_INDICATE_RINGING:
{
- if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
} else {
zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
@@ -897,7 +897,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session,
break;
case SWITCH_MESSAGE_INDICATE_PROGRESS:
{
- if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
} else {
@@ -914,7 +914,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session,
break;
case SWITCH_MESSAGE_INDICATE_ANSWER:
{
- if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
} else {
/* Don't skip messages in the ISDN call setup
@@ -957,7 +957,7 @@ static switch_status_t channel_receive_message_fxo(switch_core_session_t *sessio
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_OUTBOUND) {
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
@@ -991,7 +991,7 @@ static switch_status_t channel_receive_message_fxs(switch_core_session_t *sessio
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) {
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
@@ -1000,7 +1000,7 @@ static switch_status_t channel_receive_message_fxs(switch_core_session_t *sessio
}
break;
case SWITCH_MESSAGE_INDICATE_RINGING:
- if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
if (!switch_channel_test_flag(channel, CF_ANSWERED) &&
!switch_channel_test_flag(channel, CF_EARLY_MEDIA) &&
@@ -1052,7 +1052,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, "openzap_pre_buffer_size"))) {
int tmp = atoi(var);
if (tmp > -1) {
@@ -1327,7 +1327,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 (zap_channel_add_token(zchan, switch_core_session_get_uuid(*new_session), zchan->token_count) != ZAP_SUCCESS) {
switch_core_session_destroy(new_session);
@@ -1678,7 +1677,9 @@ static ZIO_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);
diff --git a/libs/spandsp/src/spandsp.h.in b/libs/spandsp/src/spandsp.h.in
index 9167c1c2cc..eaed548c97 100644
--- a/libs/spandsp/src/spandsp.h.in
+++ b/libs/spandsp/src/spandsp.h.in
@@ -39,8 +39,9 @@
#include
#include
@INSERT_MATH_HEADER@
+#if !defined(SPANDSP_NO_TIFF)
#include
-
+#endif
#include
#include
#include
diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c
index 45387b8585..aba4eef0eb 100644
--- a/libs/spandsp/src/t30.c
+++ b/libs/spandsp/src/t30.c
@@ -4275,6 +4275,7 @@ static void process_state_iv_eor(t30_state_t *s, const uint8_t *msg, int len)
break;
case T30_ERR:
/* TODO: Continue with the next message if MPS or EOM? */
+ s->current_status = T30_ERR_RETRYDCN;
s->timer_t5 = 0;
send_dcn(s);
break;
@@ -4319,6 +4320,7 @@ static void process_state_iv_eor_rnr(t30_state_t *s, const uint8_t *msg, int len
break;
case T30_ERR:
/* TODO: Continue with the next message if MPS or EOM? */
+ s->current_status = T30_ERR_RETRYDCN;
s->timer_t5 = 0;
send_dcn(s);
break;
diff --git a/libs/stfu/stfu.c b/libs/stfu/stfu.c
index 0422cd2081..d2c443a9e7 100644
--- a/libs/stfu/stfu.c
+++ b/libs/stfu/stfu.c
@@ -27,58 +27,169 @@
*/
#include "stfu.h"
+//#define DB_JB 1
+
+#ifndef UINT_MAX
+# define UINT_MAX 4294967295U
+#endif
+
+#ifndef UINT16_MAX
+# define UINT16_MAX 65535
+#endif
+
#ifdef _MSC_VER
/* warning C4706: assignment within conditional expression*/
#pragma warning(disable: 4706)
+/* warning C4996: 'strdup': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _strdup. See online help for details. */
+#pragma warning(disable:4996)
#endif
+#define least1(_z) (_z ? _z : 1)
+
+static int stfu_log_level = 7;
+
struct stfu_queue {
struct stfu_frame *array;
struct stfu_frame int_frame;
+ uint32_t real_array_size;
uint32_t array_size;
uint32_t array_len;
uint32_t wr_len;
+ uint32_t last_index;
+ int32_t last_jitter;
};
typedef struct stfu_queue stfu_queue_t;
struct stfu_instance {
struct stfu_queue a_queue;
struct stfu_queue b_queue;
+ struct stfu_queue c_queue;
struct stfu_queue *in_queue;
struct stfu_queue *out_queue;
+ struct stfu_queue *old_queue;
struct stfu_frame *last_frame;
uint32_t cur_ts;
uint32_t last_wr_ts;
uint32_t last_rd_ts;
- uint32_t interval;
+ uint32_t samples_per_packet;
+ uint32_t samples_per_second;
uint32_t miss_count;
uint32_t max_plc;
+ uint32_t qlen;
+ uint32_t max_qlen;
+ uint32_t orig_qlen;
+ uint32_t packet_count;
+ uint32_t consecutive_good_count;
+ uint32_t consecutive_bad_count;
+ uint32_t period_good_count;
+ uint32_t period_bad_count;
+ uint32_t period_packet_in_count;
+ uint32_t period_packet_out_count;
+ uint32_t period_missing_count;
+
+ uint32_t period_need_range;
+ uint32_t period_need_range_avg;
+ uint32_t period_clean_count;
+
+ uint32_t session_clean_count;
+ uint32_t session_missing_count;
+
+ uint32_t session_packet_in_count;
+ uint32_t session_packet_out_count;
+
+ uint32_t sync_out;
+ uint32_t sync_in;
+
+ int32_t ts_offset;
+ int32_t ts_drift;
+
+ int32_t ts_diff;
+ int32_t last_ts_diff;
+ int32_t same_ts;
+
+ uint32_t period_time;
+ uint32_t decrement_time;
+
+ uint32_t plc_len;
+ uint32_t plc_pt;
+ uint32_t diff;
+ uint32_t diff_total;
+ uint8_t ready;
+ uint8_t debug;
+
+ char *name;
+ stfu_n_call_me_t callback;
+ void *udata;
};
+static void stfu_n_reset_counters(stfu_instance_t *i);
+static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...);
+static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...);
+
+stfu_logger_t stfu_log = null_logger;
+
+int32_t stfu_n_get_drift(stfu_instance_t *i)
+{
+ return i->ts_drift;
+}
+
+void stfu_global_set_logger(stfu_logger_t logger)
+{
+ if (logger) {
+ stfu_log = logger;
+ } else {
+ stfu_log = null_logger;
+ }
+}
+
+void stfu_global_set_default_logger(int level)
+{
+ if (level < 0 || level > 7) {
+ level = 7;
+ }
+
+ stfu_log = default_logger;
+ stfu_log_level = level;
+}
+
+
static stfu_status_t stfu_n_resize_aqueue(stfu_queue_t *queue, uint32_t qlen)
{
unsigned char *m;
- if (qlen <= queue->array_size) {
- return STFU_IT_FAILED;;
+ if (qlen <= queue->real_array_size) {
+ queue->array_size = qlen;
+ if (queue->array_len > qlen) {
+ queue->array_len = qlen;
+ }
+ } else {
+ m = realloc(queue->array, qlen * sizeof(struct stfu_frame));
+ assert(m);
+ memset(m + queue->array_size * sizeof(struct stfu_frame), 0, (qlen * sizeof(struct stfu_frame)) - (queue->array_size * sizeof(struct stfu_frame)));
+ queue->array = (struct stfu_frame *) m;
+ queue->real_array_size = queue->array_size = qlen;
}
- m = realloc(queue->array, qlen * sizeof(struct stfu_frame));
- assert(m);
- memset(m + queue->array_size, 0, qlen * sizeof(struct stfu_frame) - queue->array_size);
- queue->array = (struct stfu_frame *) m;
- queue->array_size = qlen;
return STFU_IT_WORKED;
}
static void stfu_n_init_aqueue(stfu_queue_t *queue, uint32_t qlen)
{
+
queue->array = calloc(qlen, sizeof(struct stfu_frame));
assert(queue->array != NULL);
memset(queue->array, 0, sizeof(struct stfu_frame) * qlen);
- queue->array_size = qlen;
+ queue->real_array_size = queue->array_size = qlen;
queue->int_frame.plc = 1;
+ memset(queue->int_frame.data, 255, sizeof(queue->int_frame.data));
+}
+
+
+void stfu_n_call_me(stfu_instance_t *i, stfu_n_call_me_t callback, void *udata)
+{
+ i->callback = callback;
+ i->udata = udata;
}
void stfu_n_destroy(stfu_instance_t **i)
@@ -88,33 +199,66 @@ void stfu_n_destroy(stfu_instance_t **i)
if (i && *i) {
ii = *i;
*i = NULL;
+ if (ii->name) free(ii->name);
free(ii->a_queue.array);
free(ii->b_queue.array);
+ free(ii->c_queue.array);
free(ii);
}
}
+void stfu_n_debug(stfu_instance_t *i, const char *name)
+{
+ if (i->name) free(i->name);
+
+ if (name) {
+ i->name = strdup(name);
+ i->debug = 1;
+ } else {
+ i->name = strdup("none");
+ i->debug = 0;
+ }
+}
+
void stfu_n_report(stfu_instance_t *i, stfu_report_t *r)
{
assert(i);
- r->in_len = i->in_queue->array_len;
- r->in_size = i->in_queue->array_size;
- r->out_len = i->out_queue->array_len;
- r->out_size = i->out_queue->array_size;
+ r->qlen = i->qlen;
+ r->packet_in_count = i->period_packet_in_count;
+ r->clean_count = i->period_clean_count;
+ r->consecutive_good_count = i->consecutive_good_count;
+ r->consecutive_bad_count = i->consecutive_bad_count;
}
stfu_status_t stfu_n_resize(stfu_instance_t *i, uint32_t qlen)
{
stfu_status_t s;
+ if (i->qlen == i->max_qlen) {
+ return STFU_IT_FAILED;
+ }
+
+ if (i->max_qlen && qlen > i->max_qlen) {
+ if (i->qlen < i->max_qlen) {
+ qlen = i->max_qlen;
+ } else {
+ return STFU_IT_FAILED;
+ }
+ }
+
if ((s = stfu_n_resize_aqueue(&i->a_queue, qlen)) == STFU_IT_WORKED) {
s = stfu_n_resize_aqueue(&i->b_queue, qlen);
+ s = stfu_n_resize_aqueue(&i->c_queue, qlen);
+
+ i->qlen = qlen;
+ i->max_plc = 5;
+ i->last_frame = NULL;
}
return s;
}
-stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_plc)
+stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_qlen, uint32_t samples_per_packet, uint32_t samples_per_second)
{
struct stfu_instance *i;
@@ -123,116 +267,265 @@ stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_plc)
return NULL;
}
memset(i, 0, sizeof(*i));
+
+ i->qlen = qlen;
+ i->max_qlen = max_qlen;
+ i->orig_qlen = qlen;
+ i->samples_per_packet = samples_per_packet;
+
stfu_n_init_aqueue(&i->a_queue, qlen);
stfu_n_init_aqueue(&i->b_queue, qlen);
+ stfu_n_init_aqueue(&i->c_queue, qlen);
+
i->in_queue = &i->a_queue;
i->out_queue = &i->b_queue;
+ i->old_queue = &i->c_queue;
+ i->name = strdup("none");
+
+ i->max_plc = i->qlen / 2;
- if (max_plc) {
- i->max_plc = max_plc;
- } else {
- i->max_plc = qlen / 2;
- }
+ i->samples_per_second = samples_per_second ? samples_per_second : 8000;
+
+ i->period_time = ((i->samples_per_second * 20) / i->samples_per_packet);
+ i->decrement_time = ((i->samples_per_second * 15) / i->samples_per_packet);
return i;
}
+static void stfu_n_reset_counters(stfu_instance_t *i)
+{
+ if (stfu_log != null_logger && i->debug) {
+ stfu_log(STFU_LOG_EMERG, "%s COUNTER RESET........\n", i->name);
+ }
+
+ if (i->callback) {
+ i->callback(i, i->udata);
+ }
+
+ i->consecutive_good_count = 0;
+ i->consecutive_bad_count = 0;
+ i->period_good_count = 0;
+ i->period_clean_count = 0;
+ i->period_bad_count = 0;
+ i->period_packet_in_count = 0;
+ i->period_packet_out_count = 0;
+ i->period_missing_count = 0;
+
+ i->period_need_range = 0;
+ i->period_need_range_avg = 0;
+
+ i->diff = 0;
+ i->diff_total = 0;
+
+}
+
void stfu_n_reset(stfu_instance_t *i)
{
+ if (stfu_log != null_logger && i->debug) {
+ stfu_log(STFU_LOG_EMERG, "%s RESET\n", i->name);
+ }
+
+ i->ready = 0;
i->in_queue = &i->a_queue;
i->out_queue = &i->b_queue;
+ i->old_queue = &i->c_queue;
+
i->in_queue->array_len = 0;
i->out_queue->array_len = 0;
i->out_queue->wr_len = 0;
i->last_frame = NULL;
- i->miss_count = 0;
+ i->in_queue->last_jitter = 0;
+ i->out_queue->last_jitter = 0;
+
+
+ stfu_n_reset_counters(i);
+ stfu_n_sync(i, 1);
+
+ i->cur_ts = 0;
i->last_wr_ts = 0;
- i->miss_count = 0;
- i->interval = 0;
+ i->last_rd_ts = 0;
+ i->miss_count = 0;
+ i->packet_count = 0;
+
+
}
-static int32_t stfu_n_measure_interval(stfu_queue_t *queue)
+stfu_status_t stfu_n_sync(stfu_instance_t *i, uint32_t packets)
{
- uint32_t index;
- int32_t d, most = 0, last = 0, this, track[STFU_MAX_TRACK] = {0};
- for(index = 0; index < queue->array_len; index++) {
- this = queue->array[index].ts;
- if (last) {
+ if (packets > i->qlen) {
+ stfu_n_reset(i);
+ } else {
+ i->sync_out = packets;
+ i->sync_in = packets;
+ }
- if ((d = this - last) > 0 && d / 10 < STFU_MAX_TRACK) {
- track[(d/10)]++;
- }
- }
-
- last = this;
- }
-
- for(index = 0; index < STFU_MAX_TRACK; index++) {
- if (track[index] > track[most]) {
- most = index;
- }
- }
-
- return most * 10;
+ return STFU_IT_WORKED;
}
-static int16_t stfu_n_process(stfu_instance_t *i, stfu_queue_t *queue)
-{
- if (!i->interval && !(i->interval = stfu_n_measure_interval(queue))) {
- return -1;
- }
- return 0;
+static void stfu_n_swap(stfu_instance_t *i)
+{
+ stfu_queue_t *last_in = i->in_queue, *last_out = i->out_queue, *last_old = i->old_queue;
+
+ i->ready = 1;
+
+ i->in_queue = last_out;
+ i->out_queue = last_old;
+ i->old_queue = last_in;
+
+ i->in_queue->array_len = 0;
+ i->out_queue->wr_len = 0;
+ i->last_frame = NULL;
+ i->miss_count = 0;
+ i->in_queue->last_index = 0;
+ i->out_queue->last_index = 0;
+ i->out_queue->last_jitter = 0;
}
-stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void *data, size_t datalen, int last)
+stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void *data, size_t datalen, uint32_t timer_ts, int last)
{
- uint32_t index;
+ uint32_t index = 0;
stfu_frame_t *frame;
size_t cplen = 0;
+ int good_ts = 0;
+
+ if (!i->samples_per_packet && ts && i->last_rd_ts) {
+ i->ts_diff = ts - i->last_rd_ts;
+
+ if (i->last_ts_diff == i->ts_diff) {
+ if (++i->same_ts == 5) {
+ i->samples_per_packet = i->ts_diff;
+ }
+ } else {
+ i->same_ts = 0;
+ }
+
+ i->last_ts_diff = i->ts_diff;
+
+ if (!i->samples_per_packet) {
+ i->last_rd_ts = ts;
+ return STFU_IT_FAILED;
+ }
+ }
+
+ if (timer_ts && ts && !i->ts_offset) {
+ i->ts_offset = timer_ts - ts;
+ }
+
+ i->ts_drift = ts + (i->ts_offset - timer_ts);
+
+ if (i->sync_in) {
+ good_ts = 1;
+ i->sync_in = 0;
+ } else {
+
+ if ((ts && ts == i->last_rd_ts + i->samples_per_packet) || (i->last_rd_ts > 4294900000 && ts < 5000)) {
+ good_ts = 1;
+ }
+
+ if (i->last_wr_ts) {
+ if ((ts <= i->last_wr_ts && (i->last_wr_ts != UINT_MAX || ts == i->last_wr_ts))) {
+ if (stfu_log != null_logger && i->debug) {
+ stfu_log(STFU_LOG_EMERG, "%s TOO LATE !!! %u \n\n\n", i->name, ts);
+ }
+ if (i->in_queue->array_len < i->in_queue->array_size) {
+ i->in_queue->array_len++;
+ }
+ return STFU_ITS_TOO_LATE;
+ }
+ }
+ }
+
+ if (good_ts) {
+ i->period_clean_count++;
+ i->session_clean_count++;
+ }
+
+ i->period_packet_in_count++;
+ i->session_packet_in_count++;
+
+ i->period_need_range_avg = i->period_need_range / least1(i->period_missing_count);
+
+ if (i->period_missing_count > i->qlen * 2) {
+ if (stfu_log != null_logger && i->debug) {
+ stfu_log(STFU_LOG_EMERG, "%s resize %u %u\n", i->name, i->qlen, i->qlen + 1);
+ }
+ stfu_n_resize(i, i->qlen + 1);
+ stfu_n_reset_counters(i);
+ } else {
+ if (i->qlen > i->orig_qlen && (i->consecutive_good_count > i->decrement_time || i->period_clean_count > i->decrement_time)) {
+ stfu_n_resize(i, i->qlen - 1);
+ stfu_n_reset_counters(i);
+ stfu_n_sync(i, i->qlen);
+ }
+ }
+
+
+ i->diff = 0;
+
+ if (i->last_wr_ts) {
+ if (ts < 1000 && i->last_wr_ts > (UINT_MAX - 1000)) {
+ i->diff = abs(((UINT_MAX - i->last_wr_ts) + ts) / i->samples_per_packet);
+ } else if (ts) {
+ i->diff = abs(i->last_wr_ts - ts) / i->samples_per_packet;
+ }
+ }
+
+ i->diff_total += i->diff;
+
+ if ((i->period_packet_in_count > i->period_time)) {
+ uint32_t avg;
+
+ avg = i->diff_total / least1(i->period_packet_in_count);
+
+ i->period_packet_in_count = 0;
+
+ if (i->period_missing_count == 0 && i->qlen > i->orig_qlen) {
+ stfu_n_resize(i, i->qlen - 1);
+ stfu_n_sync(i, i->qlen);
+ }
+
+ stfu_n_reset_counters(i);
+ }
+
+
+
+
+ if (stfu_log != null_logger && i->debug) {
+ stfu_log(STFU_LOG_EMERG, "I: %s %u i=%u/%u - g:%u/%u c:%u/%u b:%u - %u:%u - %u %d %u %u %d %d %d\n", i->name,
+ i->qlen, i->period_packet_in_count, i->period_time, i->consecutive_good_count,
+ i->decrement_time, i->period_clean_count, i->decrement_time, i->consecutive_bad_count,
+ ts, ts / i->samples_per_packet,
+ i->period_missing_count, i->period_need_range_avg,
+ i->last_wr_ts, ts, i->diff, i->diff_total / least1(i->period_packet_in_count), i->ts_drift);
+ }
if (last || i->in_queue->array_len == i->in_queue->array_size) {
- stfu_queue_t *other_queue;
-
- if (i->out_queue->wr_len < i->out_queue->array_len) {
- return STFU_IT_FAILED;
- }
-
- other_queue = i->in_queue;
- i->in_queue = i->out_queue;
- i->out_queue = other_queue;
-
- i->in_queue->array_len = 0;
- i->out_queue->wr_len = 0;
- i->last_frame = NULL;
- i->miss_count = 0;
-
- if (stfu_n_process(i, i->out_queue) < 0) {
- if (i->in_queue->array_len == i->in_queue->array_size && i->out_queue->array_len == i->out_queue->array_size) {
- stfu_n_resize(i, i->out_queue->array_size * 2);
- }
- //return STFU_IT_FAILED;
- }
- for(index = 0; index < i->out_queue->array_len; index++) {
- i->out_queue->array[index].was_read = 0;
- }
- }
+ stfu_n_swap(i);
+ }
if (last) {
return STFU_IM_DONE;
}
- index = i->in_queue->array_len++;
+ index = i->in_queue->array_len++;
+ assert(index < i->in_queue->array_size);
frame = &i->in_queue->array[index];
+ if (i->in_queue->array_len == i->in_queue->array_size) {
+ stfu_n_swap(i);
+ }
+
if ((cplen = datalen) > sizeof(frame->data)) {
cplen = sizeof(frame->data);
}
i->last_rd_ts = ts;
+ i->packet_count++;
memcpy(frame->data, data, cplen);
+
frame->pt = pt;
frame->ts = ts;
frame->dlen = cplen;
@@ -241,23 +534,51 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void
return STFU_IT_WORKED;
}
-static int stfu_n_find_frame(stfu_queue_t *queue, uint32_t ts, stfu_frame_t **r_frame, uint32_t *index)
+static int stfu_n_find_any_frame(stfu_instance_t *in, stfu_queue_t *queue, stfu_frame_t **r_frame)
{
uint32_t i = 0;
stfu_frame_t *frame = NULL;
assert(r_frame);
- assert(index);
*r_frame = NULL;
- for(i = 0; i < queue->array_len; i++) {
+ for(i = 0; i < queue->real_array_size; i++) {
+ frame = &queue->array[i];
+ if (!frame->was_read) {
+ *r_frame = frame;
+ queue->last_index = i;
+ frame->was_read = 1;
+ in->period_packet_out_count++;
+ in->session_packet_out_count++;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int stfu_n_find_frame(stfu_instance_t *in, stfu_queue_t *queue, uint32_t ts, stfu_frame_t **r_frame)
+{
+ uint32_t i = 0;
+ stfu_frame_t *frame = NULL;
+
+ if (r_frame) {
+ *r_frame = NULL;
+ }
+
+ for(i = 0; i < queue->array_size; i++) {
frame = &queue->array[i];
if (frame->ts == ts) {
- *r_frame = frame;
- *index = i;
- frame->was_read = 1;
+ if (r_frame) {
+ *r_frame = frame;
+ queue->last_index = i;
+ frame->was_read = 1;
+ in->period_packet_out_count++;
+ in->session_packet_out_count++;
+ }
return 1;
}
}
@@ -267,47 +588,300 @@ static int stfu_n_find_frame(stfu_queue_t *queue, uint32_t ts, stfu_frame_t **r_
stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i)
{
- uint32_t index;
stfu_frame_t *rframe = NULL;
-
- if (((i->out_queue->wr_len == i->out_queue->array_len) || !i->out_queue->array_len)) {
- return NULL;
- }
+ int found = 0;
- if (i->cur_ts == 0) {
- i->cur_ts = i->out_queue->array[0].ts;
- } else {
- i->cur_ts += i->interval;
+ if (!i->samples_per_packet) {
+ return NULL;
}
+ if (!i->ready) {
+ if (stfu_log != null_logger && i->debug) {
+ stfu_log(STFU_LOG_EMERG, "%s XXXSKIP\n", i->name);
+ }
+ return NULL;
+ }
- if (stfu_n_find_frame(i->out_queue, i->cur_ts, &rframe, &index) || stfu_n_find_frame(i->in_queue, i->cur_ts, &rframe, &index)) {
+
+ if (i->cur_ts == 0 && i->last_wr_ts < 1000) {
+ uint32_t x = 0;
+ for (x = 0; x < i->out_queue->array_len; x++) {
+ if (!i->out_queue->array[x].was_read) {
+ i->cur_ts = i->out_queue->array[x].ts;
+ break;
+ }
+ if (i->cur_ts == 0) {
+ if (stfu_log != null_logger && i->debug) {
+ stfu_log(STFU_LOG_EMERG, "%s XXXPUNT\n", i->name);
+ return NULL;
+ }
+ }
+ }
+ } else {
+ i->cur_ts = i->cur_ts + i->samples_per_packet;
+ }
+
+ found = stfu_n_find_frame(i, i->out_queue, i->cur_ts, &rframe);
+
+ if (found) {
+ if (i->out_queue->array_len) {
+ i->out_queue->array_len--;
+ }
+ } else {
+ found = stfu_n_find_frame(i, i->in_queue, i->cur_ts, &rframe);
+
+ if (!found) {
+ found = stfu_n_find_frame(i, i->old_queue, i->cur_ts, &rframe);
+ }
+ }
+
+ if (i->sync_out) {
+ if (!found) {
+ if ((found = stfu_n_find_any_frame(i, i->out_queue, &rframe))) {
+ i->cur_ts = rframe->ts;
+ }
+
+ if (stfu_log != null_logger && i->debug) {
+ stfu_log(STFU_LOG_EMERG, "%s SYNC %u %u:%u\n", i->name, i->sync_out, i->cur_ts, i->cur_ts / i->samples_per_packet);
+ }
+
+ }
+ i->sync_out = 0;
+ }
+
+ if (!i->cur_ts) {
+ if (stfu_log != null_logger && i->debug) {
+ stfu_log(STFU_LOG_EMERG, "%s NO TS\n", i->name);
+ }
+ return NULL;
+ }
+
+
+ if (!found && i->samples_per_packet) {
+ uint32_t y;
+ stfu_frame_t *frame = NULL;
+
+ int32_t delay = i->last_rd_ts - i->cur_ts;
+ uint32_t need = abs(i->last_rd_ts - i->cur_ts) / i->samples_per_packet;
+
+
+ i->period_missing_count++;
+ i->session_missing_count++;
+ i->period_need_range += need;
+
+ if (stfu_log != null_logger && i->debug) {
+ stfu_log(STFU_LOG_EMERG, "%s MISSING %u:%u %u %u %d %u %d\n", i->name,
+ i->cur_ts, i->cur_ts / i->samples_per_packet, i->packet_count, i->last_rd_ts, delay, i->qlen, need);
+ }
+
+ if (i->packet_count > i->orig_qlen * 100 && delay > 0 && need > i->qlen && need < (i->qlen + 5)) {
+ i->packet_count = 0;
+ }
+
+ if (stfu_log != null_logger && i->debug) {
+ stfu_log(STFU_LOG_EMERG, "%s ", i->name);
+ for(y = 0; y < i->out_queue->array_size; y++) {
+ if ((y % 5) == 0) stfu_log(STFU_LOG_EMERG, "\n%s ", i->name);
+ frame = &i->out_queue->array[y];
+ stfu_log(STFU_LOG_EMERG, "%u:%u\t", frame->ts, frame->ts / i->samples_per_packet);
+ }
+ stfu_log(STFU_LOG_EMERG, "\n%s ", i->name);
+
+
+ for(y = 0; y < i->in_queue->array_size; y++) {
+ if ((y % 5) == 0) stfu_log(STFU_LOG_EMERG, "\n%s ", i->name);
+ frame = &i->in_queue->array[y];
+ stfu_log(STFU_LOG_EMERG, "%u:%u\t", frame->ts, frame->ts / i->samples_per_packet);
+ }
+ stfu_log(STFU_LOG_EMERG, "\n%s\n\n\n", i->name);
+
+ }
+
+ if (delay < 0) {
+ stfu_n_reset(i);
+ return NULL;
+ }
+ }
+
+ if (stfu_log != null_logger && i->debug) {
+ if (found) {
+ stfu_log(STFU_LOG_EMERG, "%s O: %u:%u %u\n", i->name, rframe->ts, rframe->ts / i->samples_per_packet, rframe->plc);
+ }
+ }
+
+ if (found) {
+ i->consecutive_good_count++;
+ i->period_good_count++;
+ i->consecutive_bad_count = 0;
+ } else {
+ i->consecutive_bad_count++;
+ i->period_bad_count++;
+ i->consecutive_good_count = 0;
+ }
+
+ if (found) {
i->last_frame = rframe;
- i->out_queue->wr_len++;
- i->last_wr_ts = rframe->ts;
- i->miss_count = 0;
+ i->out_queue->wr_len++;
+ i->last_wr_ts = rframe->ts;
+
+ i->miss_count = 0;
+ if (rframe->dlen) {
+ i->plc_len = rframe->dlen;
+ }
+
+ i->plc_pt = rframe->pt;
+
} else {
i->last_wr_ts = i->cur_ts;
rframe = &i->out_queue->int_frame;
-
- if (i->last_frame && i->last_frame != rframe) {
- rframe->dlen = i->last_frame->dlen;
- /* poor man's plc.. Copy the last frame, but we flag it so you can use a better one if you wish */
- memcpy(rframe->data, i->last_frame->data, rframe->dlen);
+ rframe->dlen = i->plc_len;
+ rframe->pt = i->plc_pt;
+ rframe->ts = i->cur_ts;
+ i->miss_count++;
+
+ if (stfu_log != null_logger && i->debug) {
+ stfu_log(STFU_LOG_EMERG, "%s PLC %d %d %ld %u:%u\n", i->name,
+ i->miss_count, rframe->plc, rframe->dlen, rframe->ts, rframe->ts / i->samples_per_packet);
}
- rframe->ts = i->cur_ts;
-
- if (++i->miss_count > i->max_plc) {
- i->out_queue->wr_len = i->out_queue->array_size;
- i->cur_ts = 0;
+ if (i->miss_count > i->max_plc) {
+ stfu_n_reset(i);
rframe = NULL;
}
}
- return rframe;
+ return rframe;
}
+#ifdef WIN32
+#ifndef vsnprintf
+#define vsnprintf _vsnprintf
+#endif
+#endif
+
+
+int vasprintf(char **ret, const char *format, va_list ap);
+
+int stfu_vasprintf(char **ret, const char *fmt, va_list ap)
+{
+#if !defined(WIN32) && !defined(__sun)
+ return vasprintf(ret, fmt, ap);
+#else
+ char *buf;
+ int len;
+ size_t buflen;
+ va_list ap2;
+ char *tmp = NULL;
+
+#ifdef _MSC_VER
+#if _MSC_VER >= 1500
+ /* hack for incorrect assumption in msvc header files for code analysis */
+ __analysis_assume(tmp);
+#endif
+ ap2 = ap;
+#else
+ va_copy(ap2, ap);
+#endif
+
+ len = vsnprintf(tmp, 0, fmt, ap2);
+
+ if (len > 0 && (buf = malloc((buflen = (size_t) (len + 1)))) != NULL) {
+ len = vsnprintf(buf, buflen, fmt, ap);
+ *ret = buf;
+ } else {
+ *ret = NULL;
+ len = -1;
+ }
+
+ va_end(ap2);
+ return len;
+#endif
+}
+
+
+
+
+int stfu_snprintf(char *buffer, size_t count, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(buffer, count-1, fmt, ap);
+ if (ret < 0)
+ buffer[count-1] = '\0';
+ va_end(ap);
+ return ret;
+}
+
+static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+ if (file && func && line && level && fmt) {
+ return;
+ }
+ return;
+}
+
+
+
+static const char *LEVEL_NAMES[] = {
+ "EMERG",
+ "ALERT",
+ "CRIT",
+ "ERROR",
+ "WARNING",
+ "NOTICE",
+ "INFO",
+ "DEBUG",
+ NULL
+};
+
+static const char *cut_path(const char *in)
+{
+ const char *p, *ret = in;
+ char delims[] = "/\\";
+ char *i;
+
+ for (i = delims; *i; i++) {
+ p = in;
+ while ((p = strchr(p, *i)) != 0) {
+ ret = ++p;
+ }
+ }
+ return ret;
+}
+
+
+static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...)
+{
+ const char *fp;
+ char *data;
+ va_list ap;
+ int ret;
+
+ if (level < 0 || level > 7) {
+ level = 7;
+ }
+ if (level > stfu_log_level) {
+ return;
+ }
+
+ fp = cut_path(file);
+
+ va_start(ap, fmt);
+
+ ret = stfu_vasprintf(&data, fmt, ap);
+
+ if (ret != -1) {
+ fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data);
+ free(data);
+ }
+
+ va_end(ap);
+
+}
+
+
/* For Emacs:
* Local Variables:
* mode:c
diff --git a/libs/stfu/stfu.h b/libs/stfu/stfu.h
index 900db6f9ac..b92bb3f839 100644
--- a/libs/stfu/stfu.h
+++ b/libs/stfu/stfu.h
@@ -38,6 +38,8 @@ extern "C" {
#include
#include
#include
+#include
+
#ifdef _MSC_VER
#ifndef uint32_t
@@ -62,6 +64,85 @@ typedef unsigned long in_addr_t;
#endif
#include
+
+
+#ifdef WIN32
+#include
+#include
+typedef SOCKET stfu_socket_t;
+typedef unsigned __int64 uint64_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int8 uint8_t;
+typedef __int64 int64_t;
+typedef __int32 int32_t;
+typedef __int16 int16_t;
+typedef __int8 int8_t;
+typedef intptr_t stfu_ssize_t;
+typedef int stfu_filehandle_t;
+#define STFU_SOCK_INVALID INVALID_SOCKET
+#define strerror_r(num, buf, size) strerror_s(buf, size, num)
+#if defined(STFU_DECLARE_STATIC)
+#define STFU_DECLARE(type) type __stdcall
+#define STFU_DECLARE_NONSTD(type) type __cdecl
+#define STFU_DECLARE_DATA
+#elif defined(STFU_EXPORTS)
+#define STFU_DECLARE(type) __declspec(dllexport) type __stdcall
+#define STFU_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl
+#define STFU_DECLARE_DATA __declspec(dllexport)
+#else
+#define STFU_DECLARE(type) __declspec(dllimport) type __stdcall
+#define STFU_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl
+#define STFU_DECLARE_DATA __declspec(dllimport)
+#endif
+#else
+#define STFU_DECLARE(type) type
+#define STFU_DECLARE_NONSTD(type) type
+#define STFU_DECLARE_DATA
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#define STFU_SOCK_INVALID -1
+typedef int stfu_socket_t;
+typedef ssize_t stfu_ssize_t;
+typedef int stfu_filehandle_t;
+#endif
+
+
+#define STFU_PRE __FILE__, __FUNCTION__, __LINE__
+#define STFU_LOG_LEVEL_DEBUG 7
+#define STFU_LOG_LEVEL_INFO 6
+#define STFU_LOG_LEVEL_NOTICE 5
+#define STFU_LOG_LEVEL_WARNING 4
+#define STFU_LOG_LEVEL_ERROR 3
+#define STFU_LOG_LEVEL_CRIT 2
+#define STFU_LOG_LEVEL_ALERT 1
+#define STFU_LOG_LEVEL_EMERG 0
+
+#define STFU_LOG_DEBUG STFU_PRE, STFU_LOG_LEVEL_DEBUG
+#define STFU_LOG_INFO STFU_PRE, STFU_LOG_LEVEL_INFO
+#define STFU_LOG_NOTICE STFU_PRE, STFU_LOG_LEVEL_NOTICE
+#define STFU_LOG_WARNING STFU_PRE, STFU_LOG_LEVEL_WARNING
+#define STFU_LOG_ERROR STFU_PRE, STFU_LOG_LEVEL_ERROR
+#define STFU_LOG_CRIT STFU_PRE, STFU_LOG_LEVEL_CRIT
+#define STFU_LOG_ALERT STFU_PRE, STFU_LOG_LEVEL_ALERT
+#define STFU_LOG_EMERG STFU_PRE, STFU_LOG_LEVEL_EMERG
+typedef void (*stfu_logger_t)(const char *file, const char *func, int line, int level, const char *fmt, ...);
+
+
+int stfu_vasprintf(char **ret, const char *fmt, va_list ap);
+
+extern stfu_logger_t stfu_log;
+
+/*! Sets the logger for libstfu. Default is the null_logger */
+void stfu_global_set_logger(stfu_logger_t logger);
+/*! Sets the default log level for libstfu */
+void stfu_global_set_default_logger(int level);
+
#define STFU_DATALEN 16384
#define STFU_QLEN 300
#define STFU_MAX_TRACK 256
@@ -69,7 +150,8 @@ typedef unsigned long in_addr_t;
typedef enum {
STFU_IT_FAILED,
STFU_IT_WORKED,
- STFU_IM_DONE
+ STFU_IM_DONE,
+ STFU_ITS_TOO_LATE
} stfu_status_t;
struct stfu_frame {
@@ -86,24 +168,29 @@ struct stfu_instance;
typedef struct stfu_instance stfu_instance_t;
typedef struct {
- uint32_t in_len;
- uint32_t in_size;
- uint32_t out_len;
- uint32_t out_size;
-
+ uint32_t qlen;
+ uint32_t packet_in_count;
+ uint32_t clean_count;
+ uint32_t consecutive_good_count;
+ uint32_t consecutive_bad_count;
} stfu_report_t;
+typedef void (*stfu_n_call_me_t)(stfu_instance_t *i, void *);
void stfu_n_report(stfu_instance_t *i, stfu_report_t *r);
void stfu_n_destroy(stfu_instance_t **i);
-stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_plc);
+stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_qlen, uint32_t samples_per_packet, uint32_t samples_per_second);
stfu_status_t stfu_n_resize(stfu_instance_t *i, uint32_t qlen);
-stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void *data, size_t datalen, int last);
+stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void *data, size_t datalen, uint32_t timer_ts, int last);
stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i);
void stfu_n_reset(stfu_instance_t *i);
+stfu_status_t stfu_n_sync(stfu_instance_t *i, uint32_t packets);
+void stfu_n_call_me(stfu_instance_t *i, stfu_n_call_me_t callback, void *udata);
+void stfu_n_debug(stfu_instance_t *i, const char *name);
+int32_t stfu_n_get_drift(stfu_instance_t *i);
-#define stfu_im_done(i) stfu_n_add_data(i, 0, NULL, 0, 1)
-#define stfu_n_eat(i,t,p,d,l) stfu_n_add_data(i, t, p, d, l, 0)
+#define stfu_im_done(i) stfu_n_add_data(i, 0, NULL, 0, 0, 1)
+#define stfu_n_eat(i,t,p,d,l,tt) stfu_n_add_data(i, t, p, d, l, tt, 0)
#ifdef __cplusplus
}
diff --git a/libs/win32/libg722_1/libg722_1.vcproj b/libs/win32/libg722_1/libg722_1.vcproj
index e3101a22b9..a7a9530d05 100644
--- a/libs/win32/libg722_1/libg722_1.vcproj
+++ b/libs/win32/libg722_1/libg722_1.vcproj
@@ -342,6 +342,10 @@
RelativePath="..\..\libg722_1\src\tables.c"
>
+
+
+
+
+
@@ -143,6 +144,7 @@
+
diff --git a/libs/win32/libg722_1/libg722_1.vcxproj.filters b/libs/win32/libg722_1/libg722_1.vcxproj.filters
index 855a60fae6..d54ad6e890 100644
--- a/libs/win32/libg722_1/libg722_1.vcxproj.filters
+++ b/libs/win32/libg722_1/libg722_1.vcxproj.filters
@@ -60,6 +60,9 @@
Source Files
+
+ Source Files
+
@@ -92,5 +95,8 @@
Header Files
+
+ Header Files
+
\ No newline at end of file
diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h
index 13410a00ae..422d5f2930 100644
--- a/src/include/private/switch_core_pvt.h
+++ b/src/include/private/switch_core_pvt.h
@@ -31,7 +31,8 @@
* this file does not exist!!!!
*
*/
-
+#define SPANDSP_NO_TIFF 1
+#include "spandsp.h"
#include "switch_profile.h"
#ifndef WIN32
@@ -169,6 +170,7 @@ struct switch_core_session {
switch_log_level_t loglevel;
uint32_t soft_lock;
switch_ivr_dmachine_t *dmachine;
+ plc_state_t *plc;
};
struct switch_media_bug {
diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h
index 8a4928d14a..7a19bd165e 100644
--- a/src/include/switch_apr.h
+++ b/src/include/switch_apr.h
@@ -1230,6 +1230,8 @@ SWITCH_DECLARE(int) switch_sockaddr_equal(const switch_sockaddr_t *sa1, const sw
SWITCH_DECLARE(switch_status_t) switch_sockaddr_info_get(switch_sockaddr_t ** sa, const char *hostname,
int32_t family, switch_port_t port, int32_t flags, switch_memory_pool_t *pool);
+SWITCH_DECLARE(switch_status_t) switch_sockaddr_create(switch_sockaddr_t **sa, switch_memory_pool_t *pool);
+
/**
* Send data over a network.
* @param sock The socket to send the data over.
diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h
index d6bce5e8bf..e726554d81 100644
--- a/src/include/switch_channel.h
+++ b/src/include/switch_channel.h
@@ -312,6 +312,8 @@ SWITCH_DECLARE(switch_status_t) switch_channel_caller_extension_masquerade(switc
*/
SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel_t *channel, switch_caller_extension_t *caller_extension);
+SWITCH_DECLARE(void) switch_channel_sort_cid(switch_channel_t *channel, switch_bool_t in);
+
/*!
\brief Retrieve caller extension from a given channel
\param channel channel to retrieve extension from
diff --git a/src/include/switch_core.h b/src/include/switch_core.h
index 840a06c204..bcd3c0aee2 100644
--- a/src/include/switch_core.h
+++ b/src/include/switch_core.h
@@ -246,6 +246,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_close(_Inout_ switch_media
*/
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all(_In_ switch_core_session_t *session);
+SWITCH_DECLARE(switch_status_t) switch_core_media_bug_enumerate(switch_core_session_t *session, switch_stream_handle_t *stream);
+
/*!
\brief Read a frame from the bug
\param bug the bug to read from
diff --git a/src/include/switch_cpp.h b/src/include/switch_cpp.h
index 0ede8e638f..0bd2a8b2b0 100644
--- a/src/include/switch_cpp.h
+++ b/src/include/switch_cpp.h
@@ -216,6 +216,7 @@ SWITCH_DECLARE(void) consoleCleanLog(char *msg);
char *tts_name;
char *voice_name;
+ SWITCH_DECLARE(int) insertFile(const char *file, const char *insert_file, int sample_point);
SWITCH_DECLARE(int) answer();
SWITCH_DECLARE(int) preAnswer();
SWITCH_DECLARE(void) hangup(const char *cause = "normal_clearing");
diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h
index 7269a2b8d9..c48a40e6d1 100644
--- a/src/include/switch_rtp.h
+++ b/src/include/switch_rtp.h
@@ -229,7 +229,14 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_sessi
\param queue_frames the number of frames to delay
\return SWITCH_STATUS_SUCCESS
*/
-SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session, uint32_t queue_frames);
+SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session,
+ uint32_t queue_frames,
+ uint32_t max_queue_frames,
+ uint32_t samples_per_packet, uint32_t samples_per_second);
+
+SWITCH_DECLARE(switch_status_t) switch_rtp_debug_jitter_buffer(switch_rtp_t *rtp_session, const char *name);
+
+SWITCH_DECLARE(switch_status_t) switch_rtp_deactivate_jitter_buffer(switch_rtp_t *rtp_session);
/*!
\brief Set an RTP Flag
diff --git a/src/include/switch_types.h b/src/include/switch_types.h
index c01638089f..bb5f59865f 100644
--- a/src/include/switch_types.h
+++ b/src/include/switch_types.h
@@ -790,6 +790,8 @@ typedef enum {
SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION,
SWITCH_MESSAGE_INDICATE_UDPTL_MODE,
SWITCH_MESSAGE_INDICATE_CLEAR_PROGRESS,
+ SWITCH_MESSAGE_INDICATE_JITTER_BUFFER,
+ SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH,
SWITCH_MESSAGE_INVALID
} switch_core_session_message_types_t;
@@ -1093,6 +1095,10 @@ typedef enum {
CF_PASSTHRU_PTIME_MISMATCH,
CF_BRIDGE_NOWRITE,
CF_RECOVERED,
+ CF_JITTERBUFFER,
+ CF_DIALPLAN,
+ CF_BLOCK_BROADCAST_UNTIL_MEDIA,
+ CF_CNG_PLC,
/* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
CF_FLAG_MAX
} switch_channel_flag_t;
diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h
index e2a7335226..3360f33fe5 100644
--- a/src/include/switch_utils.h
+++ b/src/include/switch_utils.h
@@ -622,7 +622,7 @@ SWITCH_DECLARE(unsigned int) switch_separate_string(_In_ char *buf, char delim,
SWITCH_DECLARE(unsigned int) switch_separate_string_string(char *buf, char *delim, _Post_count_(return) char **array, unsigned int arraylen);
SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str);
-SWITCH_DECLARE(char *) switch_strip_spaces(const char *str);
+SWITCH_DECLARE(char *) switch_strip_spaces(char *str, switch_bool_t dup);
SWITCH_DECLARE(char *) switch_strip_whitespace(const char *str);
SWITCH_DECLARE(char *) switch_strip_commas(char *in, char *out, switch_size_t len);
SWITCH_DECLARE(char *) switch_strip_nonnumerics(char *in, char *out, switch_size_t len);
diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c
index a99c884529..20ee167945 100644
--- a/src/mod/applications/mod_commands/mod_commands.c
+++ b/src/mod/applications/mod_commands/mod_commands.c
@@ -1428,8 +1428,8 @@ SWITCH_STANDARD_API(cond_function)
int a_is_num, b_is_num;
*expr++ = '\0';
b = expr;
- s_a = switch_strip_spaces(a);
- s_b = switch_strip_spaces(b);
+ s_a = switch_strip_spaces(a, SWITCH_TRUE);
+ s_b = switch_strip_spaces(b, SWITCH_TRUE);
a_is_num = switch_is_number(s_a);
b_is_num = switch_is_number(s_b);
@@ -2226,6 +2226,40 @@ SWITCH_STANDARD_API(uuid_deflect)
return SWITCH_STATUS_SUCCESS;
}
+#define UUID_RECOVERY_REFRESH_SYNTAX " "
+SWITCH_STANDARD_API(uuid_recovery_refresh)
+{
+ switch_core_session_t *tsession = NULL;
+ char *uuid = NULL, *text = NULL;
+
+ if (!zstr(cmd) && (uuid = strdup(cmd))) {
+ if ((text = strchr(uuid, ' '))) {
+ *text++ = '\0';
+ }
+ }
+
+ if (zstr(uuid) || zstr(text)) {
+ stream->write_function(stream, "-USAGE: %s\n", UUID_RECOVERY_REFRESH_SYNTAX);
+ } else {
+ if ((tsession = switch_core_session_locate(uuid))) {
+ switch_core_session_message_t msg = { 0 };
+
+ /* Tell the channel to recovery_refresh the call */
+ msg.from = __FILE__;
+ msg.string_arg = text;
+ msg.message_id = SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH;
+ switch_core_session_receive_message(tsession, &msg);
+ stream->write_function(stream, "+OK:%s\n", msg.string_reply);
+ switch_core_session_rwunlock(tsession);
+ } else {
+ stream->write_function(stream, "-ERR No Such Channel %s!\n", uuid);
+ }
+ }
+
+ switch_safe_free(uuid);
+ return SWITCH_STATUS_SUCCESS;
+}
+
#define SCHED_TRANSFER_SYNTAX "[+]