diff --git a/.gitignore b/.gitignore
index adcfda37f4..304b42c1f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,10 +70,12 @@ config.status
configure.lineno
/freeswitch
/fs_cli
+/fs_encode
/fs_ivrd
/libtool
/modules.conf
/quiet_libtool
+/tone2wav
/scripts/fsxs
/scripts/gentls_cert
/a.out.dSYM
diff --git a/Freeswitch.2010.sln b/Freeswitch.2010.sln
index 186969891a..4f48314f5b 100644
--- a/Freeswitch.2010.sln
+++ b/Freeswitch.2010.sln
@@ -964,7 +964,9 @@ Global
{692F6330-4D87-4C82-81DF-40DB5892636E}.Release|Win32.ActiveCfg = Release|Win32
{692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64.ActiveCfg = Release|x64
{692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64 Setup.ActiveCfg = Release|x64
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64 Setup.Build.0 = Release|x64
{692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x86 Setup.ActiveCfg = Release|Win32
+ {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x86 Setup.Build.0 = Release|Win32
{D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|Win32.ActiveCfg = Release|x64
{D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64.ActiveCfg = Release|x64
{D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64.Build.0 = Release|x64
diff --git a/conf/autoload_configs/callcenter.conf.xml b/conf/autoload_configs/callcenter.conf.xml
index 9140193b22..a069413ac6 100644
--- a/conf/autoload_configs/callcenter.conf.xml
+++ b/conf/autoload_configs/callcenter.conf.xml
@@ -13,6 +13,7 @@
+
diff --git a/conf/autoload_configs/erlang_event.conf.xml b/conf/autoload_configs/erlang_event.conf.xml
index ec14e21a25..62deb84f67 100644
--- a/conf/autoload_configs/erlang_event.conf.xml
+++ b/conf/autoload_configs/erlang_event.conf.xml
@@ -2,7 +2,16 @@
+
+
+
+
+
diff --git a/conf/autoload_configs/modules.conf.xml b/conf/autoload_configs/modules.conf.xml
index 90d66f5798..f5627fe965 100644
--- a/conf/autoload_configs/modules.conf.xml
+++ b/conf/autoload_configs/modules.conf.xml
@@ -1,17 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/autoload_configs/sangoma_codec.conf.xml b/conf/autoload_configs/sangoma_codec.conf.xml
index 05d70de0a7..eed9d673e1 100644
--- a/conf/autoload_configs/sangoma_codec.conf.xml
+++ b/conf/autoload_configs/sangoma_codec.conf.xml
@@ -4,14 +4,15 @@
diff --git a/conf/autoload_configs/switch.conf.xml b/conf/autoload_configs/switch.conf.xml
index 7a68a7f2bd..896dd0e712 100644
--- a/conf/autoload_configs/switch.conf.xml
+++ b/conf/autoload_configs/switch.conf.xml
@@ -15,6 +15,11 @@
+
+
+
+
+
@@ -81,6 +86,7 @@
+
diff --git a/conf/autoload_configs/voicemail.conf.xml b/conf/autoload_configs/voicemail.conf.xml
index 14ad98b41c..06bd6f6dca 100644
--- a/conf/autoload_configs/voicemail.conf.xml
+++ b/conf/autoload_configs/voicemail.conf.xml
@@ -33,9 +33,10 @@
-
-
-
+ -->
+
+
+
diff --git a/conf/dialplan/default.xml b/conf/dialplan/default.xml
index 9e762b97a2..a19f68399e 100644
--- a/conf/dialplan/default.xml
+++ b/conf/dialplan/default.xml
@@ -1,88 +1,763 @@
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-service
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/directory/default.xml b/conf/directory/default.xml
index 1e583033a9..8af7aea135 100644
--- a/conf/directory/default.xml
+++ b/conf/directory/default.xml
@@ -21,7 +21,7 @@
-
+
diff --git a/conf/sip_profiles/internal.xml b/conf/sip_profiles/internal.xml
index 50833bfbec..3e756a85c0 100644
--- a/conf/sip_profiles/internal.xml
+++ b/conf/sip_profiles/internal.xml
@@ -42,6 +42,26 @@
+
+
+
+
+
+
@@ -112,6 +132,8 @@
+
+
diff --git a/conf/skinny_profiles/internal.xml b/conf/skinny_profiles/internal.xml
index 5feac1ffbf..52da89741d 100644
--- a/conf/skinny_profiles/internal.xml
+++ b/conf/skinny_profiles/internal.xml
@@ -16,7 +16,7 @@
-
+
diff --git a/conf/vars.xml b/conf/vars.xml
index c638a80582..fced2ef139 100644
--- a/conf/vars.xml
+++ b/conf/vars.xml
@@ -195,7 +195,7 @@
-
+
diff --git a/configure.in b/configure.in
index de7261266e..77df2a614c 100644
--- a/configure.in
+++ b/configure.in
@@ -373,6 +373,11 @@ if test "x$have_libz" = "xyes" ; then
APR_ADDTO(SWITCH_AM_LDFLAGS, -lz)
fi
+AC_CHECK_LIB(resolv, res_init, have_libresolv=yes, have_libresolv=no)
+if test "x$have_libresolv" = "xyes" ; then
+APR_ADDTO(SWITCH_AM_LDFLAGS, -lresolv)
+fi
+
ESL_LDFLAGS=
PLATFORM_CORE_DEPLIBS=
# tweak platform specific flags
diff --git a/libs/esl/perl/logger.pl b/libs/esl/perl/logger.pl
index d0dbb1750e..08213c033f 100644
--- a/libs/esl/perl/logger.pl
+++ b/libs/esl/perl/logger.pl
@@ -17,13 +17,13 @@ my $USAGE = "
FreeSWITCH Logger Utility
USAGE:
--h --helpThis help
+-h --help This help
-p --port Choose port
-P -pass Choose password
-f --file Output file
-pb --paste-bin Post to FreeSWITCH Paste Bin
-sp --sip-profiles List of SIP profiles to trace
--sd --sip-debug Set SIP debug level
+-sd --sip-debug Set SIP debug level
No arguments given will trace profile 'internal' to STDOUT
";
diff --git a/libs/freetdm/freetdm.2010.sln b/libs/freetdm/freetdm.2010.sln
new file mode 100644
index 0000000000..1806e9ea23
--- /dev/null
+++ b/libs/freetdm/freetdm.2010.sln
@@ -0,0 +1,137 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "freetdm", "msvc\freetdm.2010.vcxproj", "{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testanalog", "msvc\testanalog\testanalog.2010.vcxproj", "{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testisdn", "msvc\testisdn\testisdn.2010.vcxproj", "{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_freetdm", "mod_freetdm\mod_freetdm.2010.vcxproj", "{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_analog", "src\ftmod\ftmod_analog\ftmod_analog.2010.vcxproj", "{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_analog_em", "src\ftmod\ftmod_analog_em\ftmod_analog_em.2010.vcxproj", "{B3F49375-2834-4937-9D8C-4AC2EC911010}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_isdn", "src\ftmod\ftmod_isdn\ftmod_isdn.2010.vcxproj", "{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_pika", "src\ftmod\ftmod_pika\ftmod_pika.2010.vcxproj", "{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_wanpipe", "src\ftmod\ftmod_wanpipe\ftmod_wanpipe.2010.vcxproj", "{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_sangoma_boost", "src\ftmod\ftmod_sangoma_boost\ftmod_sangoma_boost.2010.vcxproj", "{D021EF2A-460D-4827-A0F7-41FDECF46F1B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testboost", "msvc\testboost\testboost.2010.vcxproj", "{2B1BAF36-0241-43E7-B865-A8338AD48E2E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsangomaboost", "msvc\testboost\testsangomaboost.2010.vcxproj", "{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_sangoma_isdn", "src\ftmod\ftmod_sangoma_isdn\ftmod_sangoma_isdn.2010.vcxproj", "{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_r2", "src\ftmod\ftmod_r2\ftmod_r2.2010.vcxproj", "{08C3EA27-A51D-47F8-B47D-B189C649CF30}"
+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
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.Build.0 = Debug|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|x64.ActiveCfg = Debug|x64
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|x64.Build.0 = Debug|x64
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.ActiveCfg = Release|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.Build.0 = Release|Win32
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|x64.ActiveCfg = Release|x64
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|x64.Build.0 = Release|x64
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.Build.0 = Debug|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|x64.ActiveCfg = Debug|x64
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|x64.Build.0 = Debug|x64
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.ActiveCfg = Release|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.Build.0 = Release|Win32
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|x64.ActiveCfg = Release|x64
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|x64.Build.0 = Release|x64
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|x64.ActiveCfg = Debug|x64
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.ActiveCfg = Release|Win32
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|x64.ActiveCfg = Release|x64
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.Build.0 = Debug|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|x64.ActiveCfg = Debug|x64
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|x64.Build.0 = Debug|x64
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.ActiveCfg = Release|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.Build.0 = Release|Win32
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|x64.ActiveCfg = Release|x64
+ {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|x64.Build.0 = Release|x64
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.ActiveCfg = Debug|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.Build.0 = Debug|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|x64.ActiveCfg = Debug|x64
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|x64.Build.0 = Debug|x64
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.ActiveCfg = Release|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.Build.0 = Release|Win32
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|x64.ActiveCfg = Release|x64
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|x64.Build.0 = Release|x64
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|Win32.Build.0 = Debug|Win32
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|x64.ActiveCfg = Debug|x64
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|x64.Build.0 = Debug|x64
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|Win32.ActiveCfg = Release|Win32
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|Win32.Build.0 = Release|Win32
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|x64.ActiveCfg = Release|x64
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|x64.Build.0 = Release|x64
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.ActiveCfg = Debug|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|x64.ActiveCfg = Debug|x64
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.ActiveCfg = Release|Win32
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|x64.ActiveCfg = Release|x64
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|x64.ActiveCfg = Debug|x64
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|x64.ActiveCfg = Release|x64
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.Build.0 = Debug|Win32
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|x64.ActiveCfg = Debug|x64
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|x64.ActiveCfg = Release|x64
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.Build.0 = Debug|Win32
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|x64.ActiveCfg = Debug|x64
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|x64.Build.0 = Debug|x64
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|Win32.ActiveCfg = Release|Win32
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|Win32.Build.0 = Release|Win32
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|x64.ActiveCfg = Release|x64
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|x64.Build.0 = Release|x64
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.Build.0 = Debug|Win32
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|x64.ActiveCfg = Debug|x64
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|x64.Build.0 = Debug|x64
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|Win32.ActiveCfg = Release|Win32
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|Win32.Build.0 = Release|Win32
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|x64.ActiveCfg = Release|x64
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|x64.Build.0 = Release|x64
+ {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.Build.0 = Debug|Win32
+ {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|x64.ActiveCfg = Debug|x64
+ {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|x64.Build.0 = Debug|x64
+ {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|Win32.ActiveCfg = Release|Win32
+ {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|Win32.Build.0 = Release|Win32
+ {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|Win32
+ {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|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.ActiveCfg = Debug|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.Build.0 = Debug|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|x64.ActiveCfg = Debug|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.ActiveCfg = Release|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.Build.0 = Release|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|x64.ActiveCfg = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c
index 18c1d4aebe..6a23a4436d 100755
--- a/libs/freetdm/mod_freetdm/mod_freetdm.c
+++ b/libs/freetdm/mod_freetdm/mod_freetdm.c
@@ -149,6 +149,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);
+static const char* channel_get_variable(switch_core_session_t *session, switch_event_t *var_event, const char *variable_name);
ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session_t **sp);
void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream);
void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream);
@@ -425,8 +426,11 @@ static switch_status_t channel_on_routing(switch_core_session_t *session)
tech_pvt = switch_core_session_get_private(session);
assert(tech_pvt != NULL);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel));
+ 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);
return SWITCH_STATUS_SUCCESS;
}
@@ -837,9 +841,9 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session,
assert(tech_pvt != NULL);
if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
- switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
- return SWITCH_STATUS_FALSE;
- }
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
if (ftdm_channel_call_check_hangup(tech_pvt->ftdmchan)) {
return SWITCH_STATUS_SUCCESS;
@@ -852,7 +856,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session,
switch (msg->message_id) {
case SWITCH_MESSAGE_INDICATE_RINGING:
{
- ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_PROGRESS);
+ ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_RINGING);
}
break;
case SWITCH_MESSAGE_INDICATE_PROGRESS:
@@ -884,9 +888,9 @@ static switch_status_t channel_receive_message_fxo(switch_core_session_t *sessio
assert(tech_pvt != NULL);
if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
- switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
- return SWITCH_STATUS_FALSE;
- }
+ switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE);
+ return SWITCH_STATUS_FALSE;
+ }
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
return SWITCH_STATUS_SUCCESS;
@@ -935,7 +939,7 @@ static switch_status_t channel_receive_message_fxs(switch_core_session_t *sessio
!switch_channel_test_flag(channel, CF_EARLY_MEDIA) &&
!switch_channel_test_flag(channel, CF_RING_READY)
) {
- ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_RING);
+ ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_RINGING);
switch_channel_mark_ring_ready(channel);
}
break;
@@ -1046,6 +1050,27 @@ switch_io_routines_t freetdm_io_routines = {
/*.receive_message*/ channel_receive_message
};
+static const char* channel_get_variable(switch_core_session_t *session, switch_event_t *var_event, const char *variable_name)
+{
+ const char *variable = NULL;
+
+ if (var_event) {
+ if ((variable = switch_event_get_header(var_event, variable_name))) {
+ return variable;
+ }
+ }
+ if (session) {
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ if ((variable = switch_channel_get_variable(channel, variable_name))) {
+ return variable;
+ }
+ }
+ if ((variable = switch_core_get_variable(variable_name))) {
+ return variable;
+ }
+ return NULL;
+}
+
/* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
*/
@@ -1223,20 +1248,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
}
}
- if (session) {
- /* take out some other values from the session if they're present */
- switch_channel_t *channel = switch_core_session_get_channel(session);
- const char *freetdmvar;
- freetdmvar = switch_channel_get_variable(channel, "freetdm_bearer_capability");
- if (freetdmvar) {
- caller_data.bearer_capability = (uint8_t)atoi(freetdmvar);
- }
- freetdmvar = switch_channel_get_variable(channel, "freetdm_bearer_layer1");
- if (freetdmvar) {
- caller_data.bearer_layer1 = (uint8_t)atoi(freetdmvar);
- }
- }
-
if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) {
caller_data.screen = 1;
}
@@ -1245,29 +1256,37 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
caller_data.pres = 1;
}
- if (!zstr(dest)) {
- ftdm_set_string(caller_data.dnis.digits, dest);
+ if ((var = channel_get_variable(session, var_event, "freetdm_bearer_capability"))) {
+ caller_data.bearer_capability = (uint8_t)atoi(var);
}
- if ((var = switch_event_get_header(var_event, "freetdm_outbound_ton")) || (var = switch_core_get_variable("freetdm_outbound_ton"))) {
- if (!strcasecmp(var, "national")) {
- caller_data.dnis.type = FTDM_TON_NATIONAL;
- } else if (!strcasecmp(var, "international")) {
- caller_data.dnis.type = FTDM_TON_INTERNATIONAL;
- } else if (!strcasecmp(var, "local")) {
- caller_data.dnis.type = FTDM_TON_SUBSCRIBER_NUMBER;
- } else if (!strcasecmp(var, "unknown")) {
- caller_data.dnis.type = FTDM_TON_UNKNOWN;
- }
+ if ((var = channel_get_variable(session, var_event, "freetdm_bearer_layer1"))) {
+ caller_data.bearer_layer1 = (uint8_t)atoi(var);
+ }
+
+ if ((var = channel_get_variable(session, var_event, "freetdm_screening_ind"))) {
+ ftdm_set_screening_ind(var, &caller_data.screen);
+ }
+
+ if ((var = channel_get_variable(session, var_event, "freetdm_presentation_ind"))) {
+ ftdm_set_presentation_ind(var, &caller_data.pres);
+ }
+
+ if ((var = channel_get_variable(session, var_event, "freetdm_outbound_ton"))) {
+ ftdm_set_ton(var, &caller_data.dnis.type);
} else {
caller_data.dnis.type = outbound_profile->destination_number_ton;
}
- if ((var = switch_event_get_header(var_event, "freetdm_custom_call_data")) || (var = switch_core_get_variable("freetdm_custom_call_data"))) {
+ 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);
}
+ if (!zstr(dest)) {
+ ftdm_set_string(caller_data.dnis.digits, dest);
+ }
+
caller_data.dnis.plan = outbound_profile->destination_number_numplan;
/* blindly copy data from outbound_profile. They will be overwritten
@@ -2071,6 +2090,9 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
switch(sigmsg->event_id) {
case FTDM_SIGEVENT_START:
{
+ ftdm_channel_add_var(sigmsg->channel, "screening_ind", ftdm_screening2str(caller_data->screen));
+ ftdm_channel_add_var(sigmsg->channel, "presentation_ind", ftdm_presentation2str(caller_data->pres));
+
ftdm_enable_channel_dtmf(sigmsg->channel, NULL);
return ftdm_channel_from_event(sigmsg, &session);
}
@@ -2133,7 +2155,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
spanid, chanid, (uuid) ? uuid : "N/A");
}
}
- break;
+ break;
case FTDM_SIGEVENT_SIGSTATUS_CHANGED:
{
ftdm_signaling_status_t sigstatus = sigmsg->raw_data ? *((ftdm_signaling_status_t*)(sigmsg->raw_data)) : sigmsg->sigstatus;
@@ -2141,6 +2163,10 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
spanid, chanid, ftdm_signaling_status2str(sigstatus));
}
break;
+ case FTDM_SIGEVENT_PROCEED:
+ case FTDM_SIGEVENT_MSG:
+ /* FS does not have handlers for these messages, so ignore them for now */
+ break;
default:
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
diff --git a/libs/freetdm/msvc/freetdm.2010.vcxproj b/libs/freetdm/msvc/freetdm.2010.vcxproj
new file mode 100644
index 0000000000..71eb6dbf22
--- /dev/null
+++ b/libs/freetdm/msvc/freetdm.2010.vcxproj
@@ -0,0 +1,223 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ freetdm
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ freetdm
+ Win32Proj
+
+
+
+ DynamicLibrary
+ MultiByte
+ true
+
+
+ DynamicLibrary
+ MultiByte
+
+
+ DynamicLibrary
+ MultiByte
+ true
+
+
+ DynamicLibrary
+ MultiByte
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ $(IntDir)BuildLog-freetdm.htm
+
+
+ Disabled
+ ../src/include;../src/include/private;../src/isdn/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+ false
+ false
+
+
+ Level4
+ true
+ ProgramDatabase
+ CompileAsC
+
+
+ true
+
+
+
+
+ $(IntDir)BuildLog-freetdm.htm
+
+
+ ../src/include;../src/include/private;../src/isdn/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ false
+ false
+
+
+ Level4
+ true
+ ProgramDatabase
+ CompileAsC
+
+
+
+
+ $(IntDir)BuildLog-freetdm.htm
+
+
+ X64
+
+
+ Disabled
+ ../src/include;../src/include/private;../src/isdn/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+ false
+ false
+
+
+ Level4
+ true
+ ProgramDatabase
+ CompileAsC
+
+
+ true
+ MachineX64
+
+
+
+
+ $(IntDir)BuildLog-freetdm.htm
+
+
+ X64
+
+
+ ../src/include;../src/include/private;../src/isdn/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ false
+ false
+
+
+ Level4
+ true
+ ProgramDatabase
+ CompileAsC
+
+
+ MachineX64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/msvc/freetdm.2010.vcxproj.filters b/libs/freetdm/msvc/freetdm.2010.vcxproj.filters
new file mode 100644
index 0000000000..ed642baf3d
--- /dev/null
+++ b/libs/freetdm/msvc/freetdm.2010.vcxproj.filters
@@ -0,0 +1,128 @@
+
+
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/msvc/testanalog/testanalog.2010.vcxproj b/libs/freetdm/msvc/testanalog/testanalog.2010.vcxproj
new file mode 100644
index 0000000000..719dc618a9
--- /dev/null
+++ b/libs/freetdm/msvc/testanalog/testanalog.2010.vcxproj
@@ -0,0 +1,213 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ testanalog
+ {BB833648-BAFF-4BE2-94DB-F8BB043C588C}
+ testanalog
+ Win32Proj
+
+
+
+ Application
+ Unicode
+ true
+
+
+ Application
+ Unicode
+
+
+ Application
+ Unicode
+ true
+
+
+ Application
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ $(IntDir)BuildLog-testanalog.htm
+
+
+ Disabled
+ ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ EditAndContinue
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Console
+ false
+
+
+ MachineX86
+
+
+
+
+ $(IntDir)BuildLog-testanalog.htm
+
+
+ ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Console
+ true
+ true
+ false
+
+
+ MachineX86
+
+
+
+
+ $(IntDir)BuildLog-testanalog.htm
+
+
+ X64
+
+
+ Disabled
+ ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Console
+ false
+
+
+ MachineX64
+
+
+
+
+ $(IntDir)BuildLog-testanalog.htm
+
+
+ X64
+
+
+ ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Console
+ true
+ true
+ false
+
+
+ MachineX64
+
+
+
+
+
+
+
+ {93b8812c-3ec4-4f78-8970-ffbfc99e167d}
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/msvc/testanalog/testanalog.2010.vcxproj.filters b/libs/freetdm/msvc/testanalog/testanalog.2010.vcxproj.filters
new file mode 100644
index 0000000000..7ac3635cc5
--- /dev/null
+++ b/libs/freetdm/msvc/testanalog/testanalog.2010.vcxproj.filters
@@ -0,0 +1,14 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/msvc/testboost/testboost.2010.vcxproj b/libs/freetdm/msvc/testboost/testboost.2010.vcxproj
new file mode 100644
index 0000000000..62061485c2
--- /dev/null
+++ b/libs/freetdm/msvc/testboost/testboost.2010.vcxproj
@@ -0,0 +1,218 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ testboost
+ {2B1BAF36-0241-43E7-B865-A8338AD48E2E}
+ testboost
+ Win32Proj
+
+
+
+ Application
+ Unicode
+ true
+
+
+ Application
+ Unicode
+
+
+ Application
+ Unicode
+ true
+
+
+ Application
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\testboost\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\testboost\$(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\testboost\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\testboost\$(Configuration)\
+ false
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ $(IntDir)BuildLog-testboost.htm
+
+
+ Disabled
+ ../../src/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ EditAndContinue
+ 4100;%(DisableSpecificWarnings)
+
+
+ ..\..\debug\freetdm.lib;%(AdditionalDependencies)
+ true
+ Console
+ false
+
+
+ MachineX86
+
+
+
+
+ $(IntDir)BuildLog-testboost.htm
+
+
+ ../../src/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Console
+ true
+ true
+ false
+
+
+ MachineX86
+
+
+
+
+ $(IntDir)BuildLog-testboost.htm
+
+
+ X64
+
+
+ Disabled
+ ../../src/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ freetdm.lib;%(AdditionalDependencies)
+ true
+ Console
+ false
+
+
+ MachineX64
+ ../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories)
+
+
+
+
+ $(IntDir)BuildLog-testboost.htm
+
+
+ X64
+
+
+ ../../src/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Console
+ true
+ true
+ false
+
+
+ MachineX64
+ freetdm.lib;%(AdditionalDependencies)
+ ../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories)
+
+
+
+
+
+
+
+ {93b8812c-3ec4-4f78-8970-ffbfc99e167d}
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/msvc/testboost/testboost.2010.vcxproj.filters b/libs/freetdm/msvc/testboost/testboost.2010.vcxproj.filters
new file mode 100644
index 0000000000..74181d60a8
--- /dev/null
+++ b/libs/freetdm/msvc/testboost/testboost.2010.vcxproj.filters
@@ -0,0 +1,14 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj b/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj
new file mode 100644
index 0000000000..b6c0518883
--- /dev/null
+++ b/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj
@@ -0,0 +1,218 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ testsangomaboost
+ {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}
+ testsangomaboost
+ Win32Proj
+
+
+
+ Application
+ Unicode
+ true
+
+
+ Application
+ Unicode
+
+
+ Application
+ Unicode
+ true
+
+
+ Application
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ $(IntDir)BuildLog-testsangomaboost.htm
+
+
+ Disabled
+ ../../src/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ EditAndContinue
+ 4100;%(DisableSpecificWarnings)
+
+
+ ..\..\debug\freetdm.lib;%(AdditionalDependencies)
+ true
+ Console
+ false
+
+
+ MachineX86
+
+
+
+
+ $(IntDir)BuildLog-testsangomaboost.htm
+
+
+ ../../src/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Console
+ true
+ true
+ false
+
+
+ MachineX86
+
+
+
+
+ $(IntDir)BuildLog-testsangomaboost.htm
+
+
+ X64
+
+
+ Disabled
+ ../../src/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ false
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ freetdm.lib;%(AdditionalDependencies)
+ true
+ Console
+ false
+
+
+ MachineX64
+ ../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories)
+
+
+
+
+ $(IntDir)BuildLog-testsangomaboost.htm
+
+
+ X64
+
+
+ ../../src/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Console
+ true
+ true
+ false
+
+
+ MachineX64
+ freetdm.lib;%(AdditionalDependencies)
+ ../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories)
+
+
+
+
+
+
+
+ {93b8812c-3ec4-4f78-8970-ffbfc99e167d}
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj.filters b/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj.filters
new file mode 100644
index 0000000000..e72f14e161
--- /dev/null
+++ b/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj.filters
@@ -0,0 +1,14 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/msvc/testisdn/testisdn.2010.vcxproj b/libs/freetdm/msvc/testisdn/testisdn.2010.vcxproj
new file mode 100644
index 0000000000..2dfdeb042f
--- /dev/null
+++ b/libs/freetdm/msvc/testisdn/testisdn.2010.vcxproj
@@ -0,0 +1,213 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ testisdn
+ {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}
+ testisdn
+ Win32Proj
+
+
+
+ Application
+ Unicode
+ true
+
+
+ Application
+ Unicode
+
+
+ Application
+ Unicode
+ true
+
+
+ Application
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ $(IntDir)BuildLog-testisdn.htm
+
+
+ Disabled
+ ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ EditAndContinue
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Console
+ false
+
+
+ MachineX86
+
+
+
+
+ $(IntDir)BuildLog-testisdn.htm
+
+
+ ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Console
+ true
+ true
+ false
+
+
+ MachineX86
+
+
+
+
+ $(IntDir)BuildLog-testisdn.htm
+
+
+ X64
+
+
+ Disabled
+ ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Console
+ false
+
+
+ MachineX64
+
+
+
+
+ $(IntDir)BuildLog-testisdn.htm
+
+
+ X64
+
+
+ ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Console
+ true
+ true
+ false
+
+
+ MachineX64
+
+
+
+
+
+
+
+ {93b8812c-3ec4-4f78-8970-ffbfc99e167d}
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/msvc/testisdn/testisdn.2010.vcxproj.filters b/libs/freetdm/msvc/testisdn/testisdn.2010.vcxproj.filters
new file mode 100644
index 0000000000..9d48828d4a
--- /dev/null
+++ b/libs/freetdm/msvc/testisdn/testisdn.2010.vcxproj.filters
@@ -0,0 +1,14 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/openzap.2005.sln b/libs/freetdm/openzap.2005.sln
deleted file mode 100644
index c9f666b381..0000000000
--- a/libs/freetdm/openzap.2005.sln
+++ /dev/null
@@ -1,82 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual Studio 2005
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openzap", "msvc\openzap.2005.vcproj", "{93B8812C-3EC4-4F78-8970-FFBFC99E167D}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testanalog", "msvc\testanalog\testanalog.2005.vcproj", "{BB833648-BAFF-4BE2-94DB-F8BB043C588C}"
- ProjectSection(ProjectDependencies) = postProject
- {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testisdn", "msvc\testisdn\testisdn.2005.vcproj", "{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}"
- ProjectSection(ProjectDependencies) = postProject
- {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_openzap", "mod_openzap\mod_openzap.2005.vcproj", "{FE3540C5-3303-46E0-A69E-D92F775687F1}"
- ProjectSection(ProjectDependencies) = postProject
- {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog", "src\ozmod\ozmod_analog\ozmod_analog.2005.vcproj", "{37C94798-6E33-4B4F-8EE0-C72A7DC91157}"
- ProjectSection(ProjectDependencies) = postProject
- {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog_em", "src\ozmod\ozmod_analog_em\ozmod_analog_em.2005.vcproj", "{C539D7C8-26A8-4A94-B938-77672165C130}"
- ProjectSection(ProjectDependencies) = postProject
- {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_isdn", "src\ozmod\ozmod_isdn\ozmod_isdn.2005.vcproj", "{729344A5-D5E9-434D-8EE8-AF8C6C795D15}"
- ProjectSection(ProjectDependencies) = postProject
- {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_wanpipe", "src\ozmod\ozmod_wanpipe\ozmod_wanpipe.2005.vcproj", "{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_pika", "src\ozmod\ozmod_pika\ozmod_pika.2005.vcproj", "{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Release|Win32 = Release|Win32
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.ActiveCfg = Debug|Win32
- {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.Build.0 = Debug|Win32
- {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.ActiveCfg = Release|Win32
- {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.Build.0 = Release|Win32
- {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.ActiveCfg = Debug|Win32
- {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.Build.0 = Debug|Win32
- {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.ActiveCfg = Release|Win32
- {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.Build.0 = Release|Win32
- {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.ActiveCfg = Debug|Win32
- {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.Build.0 = Debug|Win32
- {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.ActiveCfg = Release|Win32
- {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.Build.0 = Release|Win32
- {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.ActiveCfg = Debug|Win32
- {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.Build.0 = Debug|Win32
- {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.ActiveCfg = Release|Win32
- {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.Build.0 = Release|Win32
- {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.ActiveCfg = Debug|Win32
- {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.Build.0 = Debug|Win32
- {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.ActiveCfg = Release|Win32
- {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.Build.0 = Release|Win32
- {C539D7C8-26A8-4A94-B938-77672165C130}.Debug|Win32.ActiveCfg = Debug|Win32
- {C539D7C8-26A8-4A94-B938-77672165C130}.Debug|Win32.Build.0 = Debug|Win32
- {C539D7C8-26A8-4A94-B938-77672165C130}.Release|Win32.ActiveCfg = Release|Win32
- {C539D7C8-26A8-4A94-B938-77672165C130}.Release|Win32.Build.0 = Release|Win32
- {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.ActiveCfg = Debug|Win32
- {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.Build.0 = Debug|Win32
- {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.ActiveCfg = Release|Win32
- {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.Build.0 = Release|Win32
- {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32
- {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32
- {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|Win32.ActiveCfg = Debug|Win32
- {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/libs/freetdm/src/ftdm_call_utils.c b/libs/freetdm/src/ftdm_call_utils.c
index d91b3bc9e2..69f2fb4fff 100644
--- a/libs/freetdm/src/ftdm_call_utils.c
+++ b/libs/freetdm/src/ftdm_call_utils.c
@@ -36,80 +36,101 @@
#include
-FT_DECLARE(ftdm_status_t) ftdm_span_set_npi(const char *npi_string, uint8_t *target)
+FT_DECLARE(ftdm_status_t) ftdm_set_npi(const char *string, uint8_t *target)
{
- if (!strcasecmp(npi_string, "isdn") || !strcasecmp(npi_string, "e164")) {
- *target = FTDM_NPI_ISDN;
- } else if (!strcasecmp(npi_string, "data")) {
- *target = FTDM_NPI_DATA;
- } else if (!strcasecmp(npi_string, "telex")) {
- *target = FTDM_NPI_TELEX;
- } else if (!strcasecmp(npi_string, "national")) {
- *target = FTDM_NPI_NATIONAL;
- } else if (!strcasecmp(npi_string, "private")) {
- *target = FTDM_NPI_PRIVATE;
- } else if (!strcasecmp(npi_string, "reserved")) {
- *target = FTDM_NPI_RESERVED;
- } else if (!strcasecmp(npi_string, "unknown")) {
- *target = FTDM_NPI_UNKNOWN;
- } else {
- ftdm_log(FTDM_LOG_WARNING, "Invalid NPI value (%s)\n", npi_string);
- *target = FTDM_NPI_UNKNOWN;
- return FTDM_FAIL;
+ uint8_t val;
+ ftdm_status_t status = FTDM_SUCCESS;
+
+ val = ftdm_str2ftdm_npi(string);
+ if (val == FTDM_NPI_INVALID) {
+ ftdm_log(FTDM_LOG_WARNING, "Invalid NPI string (%s)\n", string);
+ status = FTDM_FAIL;
+ val = FTDM_NPI_UNKNOWN;
}
- return FTDM_SUCCESS;
+ *target = val;
+ return status;
}
-FT_DECLARE(ftdm_status_t) ftdm_span_set_ton(const char *ton_string, uint8_t *target)
+FT_DECLARE(ftdm_status_t) ftdm_set_ton(const char *string, uint8_t *target)
{
- if (!strcasecmp(ton_string, "national")) {
- *target = FTDM_TON_NATIONAL;
- } else if (!strcasecmp(ton_string, "international")) {
- *target = FTDM_TON_INTERNATIONAL;
- } else if (!strcasecmp(ton_string, "local")) {
- *target = FTDM_TON_SUBSCRIBER_NUMBER;
- } else if (!strcasecmp(ton_string, "unknown")) {
- *target = FTDM_TON_UNKNOWN;
- } else {
- ftdm_log(FTDM_LOG_WARNING, "Invalid TON value (%s)\n", ton_string);
- *target = FTDM_TON_UNKNOWN;
- return FTDM_FAIL;
+ uint8_t val;
+ ftdm_status_t status = FTDM_SUCCESS;
+
+ val = ftdm_str2ftdm_ton(string);
+ if (val == FTDM_TON_INVALID) {
+ ftdm_log(FTDM_LOG_WARNING, "Invalid TON string (%s)\n", string);
+ status = FTDM_FAIL;
+ val = FTDM_TON_UNKNOWN;
}
- return FTDM_SUCCESS;
+ *target = val;
+ return status;
}
-FT_DECLARE(ftdm_status_t) ftdm_span_set_bearer_capability(const char *bc_string, ftdm_bearer_cap_t *target)
+FT_DECLARE(ftdm_status_t) ftdm_set_bearer_capability(const char *string, uint8_t *target)
{
- if (!strcasecmp(bc_string, "speech")) {
- *target = FTDM_BEARER_CAP_SPEECH;
- } else if (!strcasecmp(bc_string, "unrestricted-digital")) {
- *target = FTDM_BEARER_CAP_64K_UNRESTRICTED;
- } else if (!strcasecmp(bc_string, "3.1Khz")) {
- *target = FTDM_BEARER_CAP_3_1KHZ_AUDIO;
- } else {
- ftdm_log(FTDM_LOG_WARNING, "Unsupported Bearer Capability value (%s)\n", bc_string);
- return FTDM_FAIL;
+ uint8_t val;
+ ftdm_status_t status = FTDM_SUCCESS;
+
+ val = ftdm_str2ftdm_bearer_cap(string);
+ if (val == FTDM_NPI_INVALID) {
+ ftdm_log(FTDM_LOG_WARNING, "Invalid Bearer-Capability string (%s)\n", string);
+ status = FTDM_FAIL;
+ val = FTDM_BEARER_CAP_SPEECH;
}
- return FTDM_SUCCESS;
+
+ *target = val;
+ return status;
}
-FT_DECLARE(ftdm_status_t) ftdm_span_set_bearer_layer1(const char *bc_string, ftdm_user_layer1_prot_t *target)
+FT_DECLARE(ftdm_status_t) ftdm_set_bearer_layer1(const char *string, uint8_t *target)
{
- if (!strcasecmp(bc_string, "v110")) {
- *target = FTDM_USER_LAYER1_PROT_V110;
- } else if (!strcasecmp(bc_string, "ulaw")) {
- *target = FTDM_USER_LAYER1_PROT_ULAW;
- } else if (!strcasecmp(bc_string, "alaw")) {
- *target =FTDM_USER_LAYER1_PROT_ALAW ;
- } else {
- ftdm_log(FTDM_LOG_WARNING, "Unsupported Bearer Layer1 Prot value (%s)\n", bc_string);
- return FTDM_FAIL;
+ uint8_t val;
+ ftdm_status_t status = FTDM_SUCCESS;
+
+ val = ftdm_str2ftdm_usr_layer1_prot(string);
+ if (val == FTDM_USER_LAYER1_PROT_INVALID) {
+ ftdm_log(FTDM_LOG_WARNING, "Invalid Bearer Layer 1 Protocol string (%s)\n", string);
+ status = FTDM_FAIL;
+ val = FTDM_USER_LAYER1_PROT_ULAW;
}
- return FTDM_SUCCESS;
+
+ *target = val;
+ return status;
}
+FT_DECLARE(ftdm_status_t) ftdm_set_screening_ind(const char *string, uint8_t *target)
+{
+ uint8_t val;
+ ftdm_status_t status = FTDM_SUCCESS;
-FT_DECLARE(ftdm_status_t) ftdm_is_number(char *number)
+ val = ftdm_str2ftdm_screening(string);
+ if (val == FTDM_SCREENING_INVALID) {
+ ftdm_log(FTDM_LOG_WARNING, "Invalid screening indicator string (%s)\n", string);
+ status = FTDM_FAIL;
+ val = FTDM_SCREENING_NOT_SCREENED;
+ }
+
+ *target = val;
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_set_presentation_ind(const char *string, uint8_t *target)
+{
+ uint8_t val;
+ ftdm_status_t status = FTDM_SUCCESS;
+
+ val = ftdm_str2ftdm_presentation(string);
+ if (val == FTDM_PRES_INVALID) {
+ ftdm_log(FTDM_LOG_WARNING, "Invalid presentation string (%s)\n", string);
+ status = FTDM_FAIL;
+ val = FTDM_PRES_ALLOWED;
+ }
+
+ *target = val;
+ return status;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_is_number(const char *number)
{
if (!number) {
return FTDM_FAIL;
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index 23ed68c45a..658736e4de 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -38,8 +38,6 @@
*/
#define _GNU_SOURCE
-#ifndef WIN32
-#endif
#include "private/ftdm_core.h"
#include
#ifdef WIN32
@@ -150,6 +148,24 @@ 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(TON_NAMES, TON_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_ton, ftdm_ton2str, ftdm_ton_t, TON_NAMES, FTDM_TON_INVALID)
+
+FTDM_ENUM_NAMES(NPI_NAMES, NPI_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_npi, ftdm_npi2str, ftdm_npi_t, NPI_NAMES, FTDM_NPI_INVALID)
+
+FTDM_ENUM_NAMES(PRESENTATION_NAMES, PRESENTATION_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_presentation, ftdm_presentation2str, ftdm_presentation_t, PRESENTATION_NAMES, FTDM_PRES_INVALID)
+
+FTDM_ENUM_NAMES(SCREENING_NAMES, SCREENING_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_screening, ftdm_screening2str, ftdm_screening_t, SCREENING_NAMES, FTDM_SCREENING_INVALID)
+
+FTDM_ENUM_NAMES(BEARER_CAP_NAMES, BEARER_CAP_STRINGS)
+FTDM_STR2ENUM(ftdm_str2ftdm_bearer_cap, ftdm_bearer_cap2str, ftdm_bearer_cap_t, BEARER_CAP_NAMES, FTDM_BEARER_CAP_INVALID)
+
+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)
+
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)
@@ -2078,6 +2094,10 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
goto done;
}
+#ifndef FREETDM_SKIP_SIG_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
+ * remove this only in netborder branch for 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);
@@ -2098,7 +2118,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
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;
}
-
+#endif
ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1);
done:
@@ -2247,14 +2267,19 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch
switch (indication) {
/* 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_RING:
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_RING, 1);
+ case FTDM_CHANNEL_INDICATE_RINGING:
+ 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);
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);
+ }
+ }
+ break;
case FTDM_CHANNEL_INDICATE_PROGRESS:
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
@@ -2262,7 +2287,6 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch
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);
@@ -2281,7 +2305,6 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch
ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
}
break;
-
default:
ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "Do not know how to indicate %d\n", indication);
status = FTDM_FAIL;
@@ -2318,6 +2341,8 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char
UNREFERENCED_PARAMETER(line);
#endif
+ ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100);
+
ftdm_channel_unlock(ftdmchan);
return status;
@@ -2866,16 +2891,17 @@ done:
FT_DECLARE(ftdm_status_t) ftdm_channel_wait(ftdm_channel_t *ftdmchan, ftdm_wait_flag_t *flags, int32_t to)
{
- assert(ftdmchan != NULL);
- assert(ftdmchan->fio != NULL);
+ ftdm_status_t status = FTDM_FAIL;
+ ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel\n");
+ ftdm_assert_return(ftdmchan->fio != NULL, FTDM_FAIL, "Null io interface\n");
+ ftdm_assert_return(ftdmchan->fio->wait != NULL, FTDM_NOTIMPL, "wait method not implemented\n");
- if (!ftdmchan->fio->wait) {
- snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented");
- return FTDM_FAIL;
+ status = ftdmchan->fio->wait(ftdmchan, flags, to);
+ if (status == FTDM_TIMEOUT) {
+ /* make sure the flags are cleared on timeout */
+ *flags = 0;
}
-
- return ftdmchan->fio->wait(ftdmchan, flags, to);
-
+ return status;
}
/*******************************/
@@ -4860,7 +4886,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
if (sigmsg->channel) {
ftdm_mutex_lock(sigmsg->channel->mutex);
}
-
+
/* some core things to do on special events */
switch (sigmsg->event_id) {
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj
new file mode 100644
index 0000000000..81cb93fa44
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj
@@ -0,0 +1,198 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ ftmod_analog
+ {37C94798-6E33-4B4F-8EE0-C72A7DC91157}
+ ftmod_analog
+ Win32Proj
+
+
+
+ DynamicLibrary
+ Unicode
+ true
+
+
+ DynamicLibrary
+ Unicode
+
+
+ DynamicLibrary
+ Unicode
+ true
+
+
+ DynamicLibrary
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ Disabled
+ ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ EditAndContinue
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Windows
+ MachineX86
+
+
+
+
+ MaxSpeed
+ true
+ ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ true
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Windows
+ true
+ true
+ MachineX86
+
+
+
+
+ X64
+
+
+ Disabled
+ ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ false
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Windows
+ MachineX64
+
+
+
+
+ X64
+
+
+ MaxSpeed
+ true
+ ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ true
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Windows
+ true
+ true
+ MachineX64
+
+
+
+
+
+
+
+
+
+
+ {93b8812c-3ec4-4f78-8970-ffbfc99e167d}
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj.filters
new file mode 100644
index 0000000000..b6fed5927a
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj.filters
@@ -0,0 +1,23 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
index fc9bea6ef0..99d256655a 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
@@ -438,7 +438,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
{
if (state_counter > 5000 || !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT)) {
ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_CALLERID_DETECT, NULL);
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
}
}
break;
@@ -492,8 +492,8 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
}
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) &&
- (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
- || ftdmchan->last_state >= FTDM_CHANNEL_STATE_IDLE)) {
+ (ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
+ || ftdmchan->last_state >= FTDM_CHANNEL_STATE_RING)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
} else {
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
@@ -535,7 +535,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
}
}
case FTDM_CHANNEL_STATE_UP:
- case FTDM_CHANNEL_STATE_IDLE:
+ case FTDM_CHANNEL_STATE_RING:
{
ftdm_sleep(interval);
continue;
@@ -599,7 +599,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
ftdm_channel_use(ftdmchan);
}
break;
- case FTDM_CHANNEL_STATE_IDLE:
+ case FTDM_CHANNEL_STATE_RING:
{
ftdm_channel_use(ftdmchan);
sig.event_id = FTDM_SIGEVENT_START;
@@ -669,7 +669,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
continue;
}
break;
- case FTDM_CHANNEL_STATE_RING:
+ case FTDM_CHANNEL_STATE_RINGING:
{
ftdm_buffer_zero(dt_buffer);
teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
@@ -732,7 +732,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) >= analog_data->max_dialstr))) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
last_digit = 0;
collecting = 0;
}
@@ -890,7 +890,7 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
if (ftdm_test_flag(analog_data, FTDM_ANALOG_CALLERID)) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
} else {
- ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_IDLE);
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RING);
}
event->channel->ring_count = 1;
ftdm_mutex_unlock(event->channel->mutex);
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj b/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj
deleted file mode 100644
index 7a1cf53b20..0000000000
--- a/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj
+++ /dev/null
@@ -1,202 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj
new file mode 100644
index 0000000000..44792df89f
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj
@@ -0,0 +1,198 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ ftmod_analog_em
+ {B3F49375-2834-4937-9D8C-4AC2EC911010}
+ ftmod_analog_em
+ Win32Proj
+
+
+
+ DynamicLibrary
+ Unicode
+ true
+
+
+ DynamicLibrary
+ Unicode
+
+
+ DynamicLibrary
+ Unicode
+ true
+
+
+ DynamicLibrary
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ Disabled
+ ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ EditAndContinue
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Windows
+ MachineX86
+
+
+
+
+ MaxSpeed
+ true
+ ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ true
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Windows
+ true
+ true
+ MachineX86
+
+
+
+
+ X64
+
+
+ Disabled
+ ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ false
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Windows
+ MachineX64
+
+
+
+
+ X64
+
+
+ MaxSpeed
+ true
+ ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ true
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Windows
+ true
+ true
+ MachineX64
+
+
+
+
+
+
+
+
+
+
+ {93b8812c-3ec4-4f78-8970-ffbfc99e167d}
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj.filters
new file mode 100644
index 0000000000..3326f9fd16
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj.filters
@@ -0,0 +1,23 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj b/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj
deleted file mode 100644
index 9ecbadc232..0000000000
--- a/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj
+++ /dev/null
@@ -1,202 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2010.vcxproj
new file mode 100644
index 0000000000..bd2e2fe4f0
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2010.vcxproj
@@ -0,0 +1,223 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ ftmod_isdn
+ {729344A5-D5E9-434D-8EE8-AF8C6C795D15}
+ ftmod_isdn
+ Win32Proj
+
+
+
+ DynamicLibrary
+ Unicode
+ true
+
+
+ DynamicLibrary
+ Unicode
+
+
+ DynamicLibrary
+ Unicode
+ true
+
+
+ DynamicLibrary
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ true
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ Disabled
+ ..\..\isdn\include;..\..\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ EditAndContinue
+
+
+ true
+ Windows
+ MachineX86
+
+
+
+
+ MaxSpeed
+ true
+ ..\..\isdn\include;..\..\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ true
+
+
+ Level4
+ true
+ ProgramDatabase
+
+
+ true
+ Windows
+ true
+ true
+ MachineX86
+
+
+
+
+ X64
+
+
+ Disabled
+ ..\..\isdn\include;..\..\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+
+
+ true
+ Windows
+ MachineX64
+
+
+
+
+ X64
+
+
+ MaxSpeed
+ true
+ ..\..\isdn\include;..\..\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ true
+
+
+ Level4
+ true
+ ProgramDatabase
+
+
+ true
+ Windows
+ true
+ true
+ MachineX64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {93b8812c-3ec4-4f78-8970-ffbfc99e167d}
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2010.vcxproj.filters
new file mode 100644
index 0000000000..30824888fc
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2010.vcxproj.filters
@@ -0,0 +1,110 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c
index 669e85218a..68f0e9e5a4 100644
--- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c
+++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c
@@ -462,7 +462,7 @@ static ftdm_state_map_t isdn_state_map = {
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_RING, FTDM_END},
- {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}
},
{
ZSD_INBOUND,
@@ -479,7 +479,7 @@ static ftdm_state_map_t isdn_state_map = {
{
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
- {FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+ {FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
{FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_UP, FTDM_END},
},
@@ -495,6 +495,7 @@ static ftdm_state_map_t isdn_state_map = {
/**
* \brief Handler for channel state change
* \param ftdmchan Channel to handle
+ * \note This function MUST be called with the channel locked
*/
static __inline__ void state_advance(ftdm_channel_t *chan)
{
@@ -536,6 +537,8 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
break;
case FTDM_CHANNEL_STATE_PROGRESS:
+ /* RINGING is an alias for PROGRESS state in inbound calls ATM */
+ case FTDM_CHANNEL_STATE_RINGING:
{
if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
sig.event_id = FTDM_SIGEVENT_PROGRESS;
@@ -727,15 +730,13 @@ 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);
- if (ftdm_test_flag(chan, FTDM_CHANNEL_STATE_CHANGE)) {
- ftdm_channel_lock(chan);
-
+ 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_unlock(chan);
}
+ ftdm_channel_unlock(chan);
}
}
}
@@ -991,7 +992,16 @@ static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event
if (!chan) {
ftdm_log(FTDM_LOG_ERROR, "-- Unable to get channel %d:%d\n", ftdm_span_get_id(span), pevent->ring.channel);
- goto done;
+ return ret;
+ }
+
+ ftdm_channel_lock(chan);
+
+ if (chan->call_data) {
+ /* we could drop the incoming call, but most likely the pointer is just a ghost of the past,
+ * this check is just to detect potentially unreleased pointers */
+ ftdm_log_chan(chan, FTDM_LOG_ERROR, "channel already has call %p!\n", chan->call_data);
+ chan->call_data = NULL;
}
if (ftdm_channel_get_state(chan) != FTDM_CHANNEL_STATE_DOWN || ftdm_test_flag(chan, FTDM_CHANNEL_INUSE)) {
@@ -1051,9 +1061,10 @@ static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event
/* hurr, this is valid as along as nobody releases the call */
chan->call_data = pevent->ring.call;
- ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RING);
+ ftdm_set_state(chan, FTDM_CHANNEL_STATE_RING);
done:
+ ftdm_channel_unlock(chan);
return ret;
}
diff --git a/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2010.vcxproj
new file mode 100644
index 0000000000..c4004bda21
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2010.vcxproj
@@ -0,0 +1,198 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ ftmod_pika
+ {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}
+ ftmod_pika
+ Win32Proj
+
+
+
+ DynamicLibrary
+ Unicode
+ true
+
+
+ DynamicLibrary
+ Unicode
+
+
+ DynamicLibrary
+ Unicode
+ true
+
+
+ DynamicLibrary
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ true
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ Disabled
+ ..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level3
+ EditAndContinue
+
+
+ pikahmpapi.lib;%(AdditionalDependencies)
+ ..\..\..\pika\aoh\lib;%(AdditionalLibraryDirectories)
+ true
+ Windows
+ MachineX86
+
+
+
+
+ MaxSpeed
+ true
+ ..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ true
+
+
+ Level3
+ ProgramDatabase
+
+
+ pikahmpapi.lib;%(AdditionalDependencies)
+ ..\..\..\pika\aoh\lib;%(AdditionalLibraryDirectories)
+ true
+ Windows
+ true
+ true
+ MachineX86
+
+
+
+
+ X64
+
+
+ Disabled
+ ..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level3
+ ProgramDatabase
+
+
+ pikahmpapi.lib;%(AdditionalDependencies)
+ ..\..\..\pika\aoh\lib;%(AdditionalLibraryDirectories)
+ true
+ Windows
+ MachineX64
+
+
+
+
+ X64
+
+
+ MaxSpeed
+ true
+ ..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ true
+
+
+ Level3
+ ProgramDatabase
+
+
+ pikahmpapi.lib;%(AdditionalDependencies)
+ ..\..\..\pika\aoh\lib;%(AdditionalLibraryDirectories)
+ true
+ Windows
+ true
+ true
+ MachineX64
+
+
+
+
+
+
+
+
+
+
+ {93b8812c-3ec4-4f78-8970-ffbfc99e167d}
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2010.vcxproj.filters
new file mode 100644
index 0000000000..4d4cec4668
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2010.vcxproj.filters
@@ -0,0 +1,23 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj
new file mode 100644
index 0000000000..f66f5afc0d
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj
@@ -0,0 +1,95 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+
+ ftmod_r2
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}
+ Win32Proj
+
+
+
+ DynamicLibrary
+
+
+ DynamicLibrary
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ true
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ true
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ Disabled
+ ..\..\include;c:\Program Files\openr2\include\openr2;C:\Program Files\openr2\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_R2_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level3
+ EditAndContinue
+
+
+ freetdm.lib;openr2.lib;%(AdditionalDependencies)
+ C:\Program Files\openr2\lib;$(OutDir);%(AdditionalLibraryDirectories)
+ true
+ Windows
+ MachineX86
+
+
+
+
+ ..\..\include;C:\Program Files\openr2\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_R2_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level3
+ ProgramDatabase
+
+
+ true
+ Windows
+ true
+ true
+ MachineX86
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj.filters
new file mode 100644
index 0000000000..9c91228e09
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj.filters
@@ -0,0 +1,22 @@
+
+
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h
index 5a3ca76c56..6fbf272d07 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftdm_sangoma_boost.h
@@ -58,7 +58,7 @@ typedef struct ftdm_sangoma_boost_trunkgroup {
ftdm_size_t size; /* Number of b-channels in group */
unsigned int last_used_index; /* index of last b-channel used */
ftdm_channel_t* ftdmchans[MAX_CHANS_PER_TRUNKGROUP];
- //DAVIDY need to merge congestion timeouts to this struct
+ //TODO need to merge congestion timeouts to this struct
} ftdm_sangoma_boost_trunkgroup_t;
#endif
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj
new file mode 100644
index 0000000000..1dd09211e2
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj
@@ -0,0 +1,206 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ ftmod_sangoma_boost
+ {D021EF2A-460D-4827-A0F7-41FDECF46F1B}
+ ftmod_sangoma_boost
+ Win32Proj
+
+
+
+ DynamicLibrary
+ Unicode
+ true
+
+
+ DynamicLibrary
+ Unicode
+
+
+ DynamicLibrary
+ Unicode
+ true
+
+
+ DynamicLibrary
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ true
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ Disabled
+ ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_SANGOMA_BOOST_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ EditAndContinue
+ 4100;%(DisableSpecificWarnings)
+
+
+ freetdm.lib;%(AdditionalDependencies)
+ $(OutDir);%(AdditionalLibraryDirectories)
+ true
+ Windows
+ MachineX86
+
+
+
+
+ MaxSpeed
+ true
+ ..\..\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_SANGOMA_BOOST_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ true
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Windows
+ true
+ true
+ MachineX86
+
+
+
+
+ X64
+
+
+ Disabled
+ ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_SANGOMA_BOOST_EXPORTS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ freetdm.lib;%(AdditionalDependencies)
+ $(OutDir);%(AdditionalLibraryDirectories)
+ true
+ Windows
+ MachineX64
+
+
+
+
+ X64
+
+
+ MaxSpeed
+ true
+ ..\..\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_SANGOMA_BOOST_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ true
+
+
+ Level4
+ true
+ ProgramDatabase
+ 4100;%(DisableSpecificWarnings)
+
+
+ true
+ Windows
+ true
+ true
+ MachineX64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {93b8812c-3ec4-4f78-8970-ffbfc99e167d}
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj.filters
new file mode 100644
index 0000000000..2aeed155cd
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj.filters
@@ -0,0 +1,35 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
\ No newline at end of file
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 c9691e232b..50a01cc0ec 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
@@ -55,7 +55,7 @@ ftdm_mutex_t *g_boost_modules_mutex = NULL;
ftdm_hash_t *g_boost_modules_hash = NULL;
#define MAX_TRUNK_GROUPS 64
-//DAVIDY need to merge congestion_timeouts with ftdm_sangoma_boost_trunkgroups
+//TODO need to merge congestion_timeouts with ftdm_sangoma_boost_trunkgroups
static time_t congestion_timeouts[MAX_TRUNK_GROUPS];
static ftdm_sangoma_boost_trunkgroup_t *g_trunkgroups[MAX_TRUNK_GROUPS];
@@ -2582,17 +2582,17 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
} else if (!strcasecmp(var, "remote_port")) {
remote_port = atoi(val);
} else if (!strcasecmp(var, "outbound-called-ton")) {
- ftdm_span_set_ton(val, &span->default_caller_data.dnis.type);
+ ftdm_set_ton(val, &span->default_caller_data.dnis.type);
} else if (!strcasecmp(var, "outbound-called-npi")) {
- ftdm_span_set_npi(val, &span->default_caller_data.dnis.plan);
+ ftdm_set_npi(val, &span->default_caller_data.dnis.plan);
} else if (!strcasecmp(var, "outbound-calling-ton")) {
- ftdm_span_set_ton(val, &span->default_caller_data.cid_num.type);
+ ftdm_set_ton(val, &span->default_caller_data.cid_num.type);
} else if (!strcasecmp(var, "outbound-calling-npi")) {
- ftdm_span_set_npi(val, &span->default_caller_data.cid_num.plan);
+ ftdm_set_npi(val, &span->default_caller_data.cid_num.plan);
} else if (!strcasecmp(var, "outbound-rdnis-ton")) {
- ftdm_span_set_ton(val, &span->default_caller_data.rdnis.type);
+ ftdm_set_ton(val, &span->default_caller_data.rdnis.type);
} else if (!strcasecmp(var, "outbound-rdnis-npi")) {
- ftdm_span_set_npi(val, &span->default_caller_data.rdnis.plan);
+ ftdm_set_npi(val, &span->default_caller_data.rdnis.plan);
} else if (!sigmod) {
snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
FAIL_CONFIG_RETURN(FTDM_FAIL);
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj
new file mode 100644
index 0000000000..b4d234cc7d
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj
@@ -0,0 +1,121 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+
+ ftmod_sangoma_isdn
+ {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}
+ ftmod_sangoma_isdn
+ Win32Proj
+
+
+
+ DynamicLibrary
+ true
+
+
+ DynamicLibrary
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ true
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ true
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ Disabled
+ C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ EnableFastChecks
+
+
+ Level3
+ EditAndContinue
+
+
+ freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)
+ $(OutDir);C:\Program Files\libsng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)
+ true
+ Console
+ false
+
+
+ MachineX86
+
+
+
+
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level3
+ ProgramDatabase
+
+
+ true
+ Windows
+ true
+ true
+ MachineX86
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {93b8812c-3ec4-4f78-8970-ffbfc99e167d}
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj.filters
new file mode 100644
index 0000000000..5f592fa9ef
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj.filters
@@ -0,0 +1,57 @@
+
+
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
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 77ad917bf1..03b5a5fb1d 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
@@ -40,8 +40,8 @@
#include
#endif
-static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj);
+static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj);
static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span);
static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span);
@@ -115,7 +115,20 @@ ftdm_state_map_t sangoma_isdn_state_map = {
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_RING, FTDM_END},
- {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}
+ {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROCEED, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_PROCEED, FTDM_END},
+ {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
+ FTDM_CHANNEL_STATE_UP, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RINGING, 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},
},
{
ZSD_INBOUND,
@@ -189,9 +202,17 @@ ftdm_state_map_t sangoma_isdn_state_map = {
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_DIALING, FTDM_END},
- {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS,
- FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_DOWN, 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_DOWN, FTDM_END}
},
+ {
+ ZSD_OUTBOUND,
+ 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},
+ },
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
@@ -604,13 +625,15 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
break;
case FTDM_CHANNEL_STATE_GET_CALLERID:
{
- sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
- sngisdn_snd_proceed(ftdmchan);
+ if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
+ sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
+ sngisdn_snd_proceed(ftdmchan);
+ }
/* Wait in this state until we get FACILITY msg */
}
break;
case FTDM_CHANNEL_STATE_RING: /* incoming call request */
- {
+ {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending incoming call from %s to %s to FTDM core\n", ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.dnis.digits);
/* we have enough information to inform FTDM of the call*/
@@ -635,6 +658,26 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
}
}
break;
+ case FTDM_CHANNEL_STATE_PROCEED:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ /*OUTBOUND...so we were told by the line of this so noifiy the user*/
+ sigev.event_id = FTDM_SIGEVENT_PROCEED;
+ ftdm_span_send_signal(ftdmchan->span, &sigev);
+ } else {
+ if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
+ sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
+ sngisdn_snd_proceed(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);
+ }
+ break;
case FTDM_CHANNEL_STATE_PROGRESS:
{
/*check if the channel is inbound or outbound*/
@@ -642,9 +685,13 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
/*OUTBOUND...so we were told by the line of this so noifiy the user*/
sigev.event_id = FTDM_SIGEVENT_PROGRESS;
ftdm_span_send_signal(ftdmchan->span, &sigev);
- } else if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
- sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
- sngisdn_snd_proceed(ftdmchan);
+ } 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);
+ }
}
}
break;
@@ -654,7 +701,9 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
ftdm_span_send_signal(ftdmchan->span, &sigev);
} else {
- sngisdn_snd_progress(ftdmchan);
+ /* Send a progress message, indicating: In-band information/pattern available */
+ ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_IB_AVAIL};
+ sngisdn_snd_progress(ftdmchan, prog_ind);
}
}
break;
@@ -750,9 +799,7 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
break;
case FTDM_CHANNEL_STATE_DOWN: /* the call is finished and removed */
{
- uint8_t glare = 0;
-
- glare = sngisdn_test_flag(sngisdn_info, FLAG_GLARE);
+ uint8_t glare = sngisdn_test_flag(sngisdn_info, FLAG_GLARE);
/* clear all of the call specific data store in the channel structure */
clear_call_data(sngisdn_info);
@@ -992,6 +1039,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
span->state_map = &sangoma_isdn_state_map;
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);
if (span->trunk_type == FTDM_TRUNK_BRI_PTMP ||
span->trunk_type == FTDM_TRUNK_BRI) {
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 81a98cf0d3..b9ab3395ae 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
@@ -64,6 +64,33 @@
/* TODO: rename all *_cc_* to *_an_* */
+#define SNGISDN_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL };
+#define SNGISDN_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) _TYPE _FUNC1 (const char *name); const char * _FUNC2 (_TYPE type);
+#define SNGISDN_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX) \
+ _TYPE _FUNC1 (const char *name) \
+{ \
+ int i; \
+ _TYPE t = _MAX ; \
+ \
+ for (i = 0; i < _MAX ; i++) { \
+ if (!strcasecmp(name, _STRINGS[i])) { \
+ t = (_TYPE) i; \
+ break; \
+} \
+} \
+ \
+ return t; \
+} \
+ const char * _FUNC2 (_TYPE type) \
+{ \
+ if (type > _MAX) { \
+ type = _MAX; \
+} \
+ return _STRINGS[(int)type]; \
+} \
+
+
+
typedef enum {
FLAG_RESET_RX = (1 << 0),
FLAG_RESET_TX = (1 << 1),
@@ -75,7 +102,8 @@ typedef enum {
FLAG_DELAYED_REL = (1 << 7),
FLAG_SENT_PROCEED = (1 << 8),
FLAG_SEND_DISC = (1 << 9),
- FLAG_ACTIVATING = (1 << 10), /* Used for BRI only, flag is set after we request line CONNECTED */
+ /* Used for BRI only, flag is set after we request line CONNECTED */
+ FLAG_ACTIVATING = (1 << 10),
} sngisdn_flag_t;
@@ -135,6 +163,51 @@ typedef enum {
SNGISDN_EVENT_RST_IND,
} ftdm_sngisdn_event_id_t;
+typedef enum {
+ /* Call is not end-to-end ISDN */
+ SNGISDN_PROGIND_DESCR_NETE_ISDN,
+ /* Destination address is non-ISDN */
+ SNGISDN_PROGIND_DESCR_DEST_NISDN,
+ /* Origination address is non-ISDN */
+ SNGISDN_PROGIND_DESCR_ORIG_NISDN,
+ /* Call has returned to the ISDN */
+ SNGISDN_PROGIND_DESCR_RET_ISDN,
+ /* Interworking as occured and has resulted in a telecommunication service change */
+ SNGISDN_PROGIND_DESCR_SERV_CHANGE,
+ /* In-band information or an appropriate pattern is now available */
+ SNGISDN_PROGIND_DESCR_IB_AVAIL,
+ /* Invalid */
+ SNGISDN_PROGIND_DESCR_INVALID,
+} ftdm_sngisdn_progind_descr_t;
+#define SNGISDN_PROGIND_DESCR_STRINGS "not-end-to-end-isdn", "destination-is-non-isdn", "origination-is-non-isdn", "call-returned-to-isdn", "service-change", "inband-info-available", "invalid"
+SNGISDN_STR2ENUM_P(ftdm_str2ftdm_sngisdn_progind_descr, ftdm_sngisdn_progind_descr2str, ftdm_sngisdn_progind_descr_t);
+
+typedef enum {
+ /* User */
+ SNGISDN_PROGIND_LOC_USER,
+ /* Private network serving the local user */
+ SNGISDN_PROGIND_LOC_PRIV_NET_LOCAL_USR,
+ /* Public network serving the local user */
+ SNGISDN_PROGIND_LOC_PUB_NET_LOCAL_USR,
+ /* Transit network */
+ SNGISDN_PROGIND_LOC_TRANSIT_NET,
+ /* Public network serving remote user */
+ SNGISDN_PROGIND_LOC_PUB_NET_REMOTE_USR,
+ /* Private network serving remote user */
+ SNGISDN_PROGIND_LOC_PRIV_NET_REMOTE_USR,
+ /* Network beyond the interworking point */
+ SNGISDN_PROGIND_LOC_NET_BEYOND_INTRW,
+ /* Invalid */
+ SNGISDN_PROGIND_LOC_INVALID,
+} ftdm_sngisdn_progind_loc_t;
+#define SNGISDN_PROGIND_LOC_STRINGS "user", "private-net-local-user", "public-net-local-user", "transit-network", "public-net-remote-user", "private-net-remote-user", "beyond-interworking", "invalid"
+SNGISDN_STR2ENUM_P(ftdm_str2ftdm_sngisdn_progind_loc, ftdm_sngisdn_progind_loc2str, ftdm_sngisdn_progind_loc_t);
+
+typedef struct ftdm_sngisdn_prog_ind {
+ ftdm_sngisdn_progind_loc_t loc; /* location */
+ ftdm_sngisdn_progind_descr_t descr; /* description */
+} ftdm_sngisdn_progind_t;
+
/* Only timers that can be cancelled are listed here */
#define SNGISDN_NUM_TIMERS 1
/* Increase NUM_TIMERS as number of ftdm_sngisdn_timer_t increases */
@@ -181,10 +254,13 @@ typedef struct sngisdn_span_data {
uint8_t trace_flags; /* TODO: change to flags, so we can use ftdm_test_flag etc.. */
uint8_t overlap_dial;
uint8_t setup_arb;
+ uint8_t facility_ie_decode;
uint8_t facility;
int8_t facility_timeout;
uint8_t num_local_numbers;
+ uint8_t ignore_cause_value;
uint8_t timer_t3;
+ uint8_t restart_opt;
char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS];
ftdm_sched_t *sched;
ftdm_queue_t *event_queue;
@@ -288,13 +364,14 @@ void stack_pst_init(Pst *pst);
void sngisdn_snd_setup(ftdm_channel_t *ftdmchan);
void sngisdn_snd_setup_ack(ftdm_channel_t *ftdmchan);
void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan);
-void sngisdn_snd_progress(ftdm_channel_t *ftdmchan);
-void sngisdn_snd_alert(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_progress(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind);
+void sngisdn_snd_alert(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind);
void sngisdn_snd_connect(ftdm_channel_t *ftdmchan);
void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan);
void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare);
void sngisdn_snd_reset(ftdm_channel_t *ftdmchan);
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_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len);
@@ -358,14 +435,25 @@ void sngisdn_rcv_cc_ind(CcMngmt *status);
void sngisdn_rcv_sng_log(uint8_t level, char *fmt,...);
void sngisdn_rcv_sng_assert(char *message);
-ftdm_status_t cpy_calling_num_from_stack(ftdm_caller_data_t *ftdm, CgPtyNmb *cgPtyNmb);
-ftdm_status_t cpy_called_num_from_stack(ftdm_caller_data_t *ftdm, CdPtyNmb *cdPtyNmb);
-ftdm_status_t cpy_redir_num_from_stack(ftdm_caller_data_t *ftdm, RedirNmb *redirNmb);
-ftdm_status_t cpy_calling_name_from_stack(ftdm_caller_data_t *ftdm, Display *display);
-ftdm_status_t cpy_calling_num_from_user(CgPtyNmb *cgPtyNmb, ftdm_caller_data_t *ftdm);
-ftdm_status_t cpy_called_num_from_user(CdPtyNmb *cdPtyNmb, ftdm_caller_data_t *ftdm);
-ftdm_status_t cpy_redir_num_from_user(RedirNmb *redirNmb, ftdm_caller_data_t *ftdm);
-ftdm_status_t cpy_calling_name_from_user(ConEvnt *conEvnt, ftdm_channel_t *ftdmchan);
+ftdm_status_t get_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb);
+ftdm_status_t get_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb);
+ftdm_status_t get_redir_num(ftdm_channel_t *ftdmchan, RedirNmb *redirNmb);
+ftdm_status_t get_calling_name_from_display(ftdm_channel_t *ftdmchan, Display *display);
+ftdm_status_t get_calling_name_from_usr_usr(ftdm_channel_t *ftdmchan, UsrUsr *usrUsr);
+ftdm_status_t get_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad);
+ftdm_status_t get_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd);
+ftdm_status_t get_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr);
+ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t data_len);
+
+ftdm_status_t set_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb);
+ftdm_status_t set_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb);
+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_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr);
+ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t *data_len);
+
uint8_t sngisdn_get_infoTranCap_from_stack(ftdm_bearer_cap_t bearer_capability);
uint8_t sngisdn_get_usrInfoLyr1Prot_from_stack(ftdm_user_layer1_prot_t layer1_prot);
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 3b264ae02f..6afab42a89 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
@@ -34,13 +34,24 @@
#include "ftmod_sangoma_isdn.h"
-ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span);
-ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span);
-ftdm_status_t add_local_number(const char* val, ftdm_span_t *span);
+static ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span);
+static ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span);
+static ftdm_status_t add_local_number(const char* val, ftdm_span_t *span);
+static ftdm_status_t parse_yesno(const char* var, const char* val, uint8_t *target);
extern ftdm_sngisdn_data_t g_sngisdn_data;
-ftdm_status_t add_local_number(const char* val, ftdm_span_t *span)
+static ftdm_status_t parse_yesno(const char* var, const char* val, uint8_t *target)
+{
+ if (ftdm_true(val)) {
+ *target = SNGISDN_OPT_TRUE;
+ } else {
+ *target = SNGISDN_OPT_FALSE;
+ }
+ return FTDM_SUCCESS;
+}
+
+static ftdm_status_t add_local_number(const char* val, ftdm_span_t *span)
{
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
@@ -53,7 +64,7 @@ ftdm_status_t add_local_number(const char* val, ftdm_span_t *span)
return FTDM_SUCCESS;
}
-ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span)
+static ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span)
{
unsigned i;
ftdm_iterator_t *chaniter = NULL;
@@ -160,7 +171,7 @@ ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span)
return FTDM_SUCCESS;
}
-ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span)
+static ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span)
{
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
if (!strcasecmp(signalling, "net") ||
@@ -190,7 +201,10 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
signal_data->min_digits = 8;
signal_data->overlap_dial = SNGISDN_OPT_DEFAULT;
signal_data->setup_arb = SNGISDN_OPT_DEFAULT;
+ signal_data->facility_ie_decode = SNGISDN_OPT_DEFAULT;
+ signal_data->ignore_cause_value = SNGISDN_OPT_DEFAULT;
signal_data->timer_t3 = 8;
+ signal_data->restart_opt = SNGISDN_OPT_DEFAULT;
signal_data->link_id = span->span_id;
span->default_caller_data.bearer_capability = IN_ITC_SPEECH;
@@ -201,20 +215,19 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
if (span->trunk_type == FTDM_TRUNK_BRI ||
span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
-
- ftdm_span_set_npi("unknown", &span->default_caller_data.dnis.plan);
- ftdm_span_set_ton("unknown", &span->default_caller_data.dnis.type);
- ftdm_span_set_npi("unknown", &span->default_caller_data.cid_num.plan);
- ftdm_span_set_ton("unknown", &span->default_caller_data.cid_num.type);
- ftdm_span_set_npi("unknown", &span->default_caller_data.rdnis.plan);
- ftdm_span_set_ton("unknown", &span->default_caller_data.rdnis.type);
+ ftdm_set_npi("unknown", &span->default_caller_data.dnis.plan);
+ ftdm_set_ton("unknown", &span->default_caller_data.dnis.type);
+ ftdm_set_npi("unknown", &span->default_caller_data.cid_num.plan);
+ ftdm_set_ton("unknown", &span->default_caller_data.cid_num.type);
+ ftdm_set_npi("unknown", &span->default_caller_data.rdnis.plan);
+ ftdm_set_ton("unknown", &span->default_caller_data.rdnis.type);
} else {
- ftdm_span_set_npi("e164", &span->default_caller_data.dnis.plan);
- ftdm_span_set_ton("national", &span->default_caller_data.dnis.type);
- ftdm_span_set_npi("e164", &span->default_caller_data.cid_num.plan);
- ftdm_span_set_ton("national", &span->default_caller_data.cid_num.type);
- ftdm_span_set_npi("e164", &span->default_caller_data.rdnis.plan);
- ftdm_span_set_ton("national", &span->default_caller_data.rdnis.type);
+ ftdm_set_npi("isdn", &span->default_caller_data.dnis.plan);
+ ftdm_set_ton("national", &span->default_caller_data.dnis.type);
+ ftdm_set_npi("isdn", &span->default_caller_data.cid_num.plan);
+ ftdm_set_ton("national", &span->default_caller_data.cid_num.type);
+ ftdm_set_npi("isdn", &span->default_caller_data.rdnis.plan);
+ ftdm_set_ton("national", &span->default_caller_data.rdnis.type);
}
for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) {
@@ -246,40 +259,30 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
} else {
ftdm_log(FTDM_LOG_ERROR, "Invalid value for parameter:%s:%s\n", var, val);
}
- } else if (!strcasecmp(var, "setup arbitration")) {
- if (!strcasecmp(val, "yes")) {
- signal_data->setup_arb = SNGISDN_OPT_TRUE;
- } else if (!strcasecmp(val, "no")) {
- signal_data->setup_arb = SNGISDN_OPT_FALSE;
- } else {
- ftdm_log(FTDM_LOG_ERROR, "Invalid value for parameter:%s:%s\n", var, val);
- }
+ } else if (!strcasecmp(var, "setup-arbitration")) {
+ parse_yesno(var, val, &signal_data->setup_arb);
} else if (!strcasecmp(var, "facility")) {
- if (!strcasecmp(val, "yes")) {
- signal_data->facility = SNGISDN_OPT_TRUE;
- } else if (!strcasecmp(val, "no")) {
- signal_data->facility = SNGISDN_OPT_FALSE;
- } else {
- ftdm_log(FTDM_LOG_ERROR, "Invalid value for parameter:%s:%s\n", var, val);
- }
+ parse_yesno(var, val, &signal_data->facility);
} else if (!strcasecmp(var, "min_digits")) {
signal_data->min_digits = atoi(val);
} else if (!strcasecmp(var, "outbound-called-ton")) {
- ftdm_span_set_ton(val, &span->default_caller_data.dnis.type);
+ ftdm_set_ton(val, &span->default_caller_data.dnis.type);
} else if (!strcasecmp(var, "outbound-called-npi")) {
- ftdm_span_set_npi(val, &span->default_caller_data.dnis.plan);
+ ftdm_set_npi(val, &span->default_caller_data.dnis.plan);
} else if (!strcasecmp(var, "outbound-calling-ton")) {
- ftdm_span_set_ton(val, &span->default_caller_data.cid_num.type);
+ ftdm_set_ton(val, &span->default_caller_data.cid_num.type);
} else if (!strcasecmp(var, "outbound-calling-npi")) {
- ftdm_span_set_npi(val, &span->default_caller_data.cid_num.plan);
+ ftdm_set_npi(val, &span->default_caller_data.cid_num.plan);
} else if (!strcasecmp(var, "outbound-rdnis-ton")) {
- ftdm_span_set_ton(val, &span->default_caller_data.rdnis.type);
+ ftdm_set_ton(val, &span->default_caller_data.rdnis.type);
} else if (!strcasecmp(var, "outbound-rdnis-npi")) {
- ftdm_span_set_npi(val, &span->default_caller_data.rdnis.plan);
+ ftdm_set_npi(val, &span->default_caller_data.rdnis.plan);
} else if (!strcasecmp(var, "outbound-bearer_cap")) {
- ftdm_span_set_bearer_capability(val, &span->default_caller_data.bearer_capability);
+ ftdm_set_bearer_capability(val, (uint8_t*)&span->default_caller_data.bearer_capability);
} else if (!strcasecmp(var, "outbound-bearer_layer1")) {
- ftdm_span_set_bearer_layer1(val, &span->default_caller_data.bearer_layer1);
+ ftdm_set_bearer_layer1(val, &span->default_caller_data.bearer_layer1);
+ } else if (!strcasecmp(var, "channel-restart-on-link-up")) {
+ parse_yesno(var, val, &signal_data->restart_opt);
} else if (!strcasecmp(var, "local-number")) {
if (add_local_number(val, span) != FTDM_SUCCESS) {
return FTDM_FAIL;
@@ -289,6 +292,10 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
if (signal_data->facility_timeout < 0) {
signal_data->facility_timeout = 0;
}
+ } else if (!strcasecmp(var, "facility-ie-decode")) {
+ 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 {
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_stack_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c
index 6c75fb3a81..de10a9fac0 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c
@@ -686,7 +686,16 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span)
cfg.t.cfg.s.inDLSAP.statEnqOpt = FALSE;
cfg.t.cfg.s.inDLSAP.rstOpt = FALSE;
}
-
+
+ /* Override the restart options if user selected that option */
+ if (signal_data->restart_opt != SNGISDN_OPT_DEFAULT) {
+ if (signal_data->restart_opt == SNGISDN_OPT_TRUE) {
+ cfg.t.cfg.s.inDLSAP.rstOpt = TRUE;
+ } else {
+ cfg.t.cfg.s.inDLSAP.rstOpt = FALSE;
+ }
+ }
+
for (i = 0; i < IN_MAXBCHNL; i++)
{
cfg.t.cfg.s.inDLSAP.bProf[i].profNmb = 0;
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 3fe0422a4e..d557ca3ba0 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
@@ -127,10 +127,16 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
ftdm_channel_add_var(ftdmchan, "isdn_specific_var", "1");
#endif
/* Fill in call information */
- cpy_calling_num_from_stack(&ftdmchan->caller_data, &conEvnt->cgPtyNmb);
- cpy_called_num_from_stack(&ftdmchan->caller_data, &conEvnt->cdPtyNmb);
- cpy_calling_name_from_stack(&ftdmchan->caller_data, &conEvnt->display);
- cpy_redir_num_from_stack(&ftdmchan->caller_data, &conEvnt->redirNmb);
+ get_calling_num(ftdmchan, &conEvnt->cgPtyNmb);
+ get_called_num(ftdmchan, &conEvnt->cdPtyNmb);
+ get_redir_num(ftdmchan, &conEvnt->redirNmb);
+ get_calling_subaddr(ftdmchan, &conEvnt->cgPtySad);
+
+ if (get_calling_name_from_display(ftdmchan, &conEvnt->display) != FTDM_SUCCESS) {
+ get_calling_name_from_usr_usr(ftdmchan, &conEvnt->usrUsr);
+ }
+ get_prog_ind_ie(ftdmchan, &conEvnt->progInd);
+
ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Incoming call: Called No:[%s] Calling No:[%s]\n", ftdmchan->caller_data.dnis.digits, ftdmchan->caller_data.cid_num.digits);
if (conEvnt->bearCap[0].eh.pres) {
@@ -138,37 +144,43 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
ftdmchan->caller_data.bearer_capability = sngisdn_get_infoTranCap_from_stack(conEvnt->bearCap[0].infoTranCap.val);
}
- if (signal_data->switchtype == SNGISDN_SWITCH_NI2) {
- if (conEvnt->shift11.eh.pres && conEvnt->ni2OctStr.eh.pres) {
- if (conEvnt->ni2OctStr.str.len == 4 && conEvnt->ni2OctStr.str.val[0] == 0x37) {
- snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", conEvnt->ni2OctStr.str.val[3]);
- }
+
+ if (conEvnt->shift11.eh.pres && conEvnt->ni2OctStr.eh.pres) {
+ if (conEvnt->ni2OctStr.str.len == 4 && conEvnt->ni2OctStr.str.val[0] == 0x37) {
+ snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", conEvnt->ni2OctStr.str.val[3]);
}
-
- if (signal_data->facility == SNGISDN_OPT_TRUE && conEvnt->facilityStr.eh.pres) {
- /* Verify whether the Caller Name will come in a subsequent FACILITY message */
- uint16_t ret_val;
- char retrieved_str[255];
-
- ret_val = sng_isdn_retrieve_facility_caller_name(conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len, retrieved_str);
- /*
- return values for "sng_isdn_retrieve_facility_information_following":
- If there will be no information following, or fails to decode IE, returns -1
- If there will be no information following, but current FACILITY IE contains a caller name, returns 0
- If there will be information following, returns 1
- */
+ }
- if (ret_val == 1) {
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Expecting Caller name in FACILITY\n");
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GET_CALLERID);
- /* Launch timer in case we never get a FACILITY msg */
- if (signal_data->facility_timeout) {
- ftdm_sched_timer(signal_data->sched, "facility_timeout", signal_data->facility_timeout,
- sngisdn_facility_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_TIMER_FACILITY]);
+ if (conEvnt->facilityStr.eh.pres) {
+ if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
+ get_facility_ie(ftdmchan, &conEvnt->facilityStr);
+ } else if (signal_data->facility == SNGISDN_OPT_TRUE) {
+ if (signal_data->switchtype == SNGISDN_SWITCH_NI2) {
+ /* Verify whether the Caller Name will come in a subsequent FACILITY message */
+ uint16_t ret_val;
+ char retrieved_str[255];
+
+ ret_val = sng_isdn_retrieve_facility_caller_name(conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len, retrieved_str);
+ /*
+ return values for "sng_isdn_retrieve_facility_information_following":
+ If there will be no information following, or fails to decode IE, returns -1
+ If there will be no information following, but current FACILITY IE contains a caller name, returns 0
+ If there will be information following, returns 1
+ */
+
+ if (ret_val == 1) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Expecting Caller name in FACILITY\n");
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GET_CALLERID);
+ /* Launch timer in case we never get a FACILITY msg */
+ if (signal_data->facility_timeout) {
+ ftdm_sched_timer(signal_data->sched, "facility_timeout", signal_data->facility_timeout,
+ sngisdn_facility_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_TIMER_FACILITY]);
+ }
+ break;
+ } else if (ret_val == 0) {
+ strcpy(ftdmchan->caller_data.cid_name, retrieved_str);
}
break;
- } else if (ret_val == 0) {
- strcpy(ftdmchan->caller_data.cid_name, retrieved_str);
}
}
}
@@ -243,11 +255,9 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event)
uint8_t ces = sngisdn_event->ces;
sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info;
ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
-
- ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
+ CnStEvnt *cnStEvnt = &sngisdn_event->event.cnStEvnt;
- /* Function does not require any info from conStEvnt struct for now */
- /* CnStEvnt *cnStEvnt = &sngisdn_event->event.cnStEvnt; */
+ ISDN_FUNC_TRACE_ENTER(__FUNCTION__);
ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n");
@@ -269,9 +279,11 @@ 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_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_DIALING:
+ get_prog_ind_ie(ftdmchan, &cnStEvnt->progInd);
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
break;
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
@@ -335,9 +347,13 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
suId, suInstId, spInstId, ces);
switch(evntType) {
+ case MI_CALLPROC:
case MI_PROGRESS:
- if (signal_data->switchtype == SNGISDN_SWITCH_NI2 &&
- cnStEvnt->causeDgn[0].eh.pres && cnStEvnt->causeDgn[0].causeVal.pres) {
+ case MI_ALERTING:
+ get_prog_ind_ie(ftdmchan, &cnStEvnt->progInd);
+
+ if (signal_data->ignore_cause_value != SNGISDN_OPT_TRUE &&
+ cnStEvnt->causeDgn[0].eh.pres && cnStEvnt->causeDgn[0].causeVal.pres) {
switch(cnStEvnt->causeDgn[0].causeVal.val) {
case 17: /* User Busy */
@@ -362,22 +378,20 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
goto sngisdn_process_cnst_ind_end;
}
}
- /* fall-through */
- case MI_ALERTING:
- case MI_CALLPROC:
-
+
switch(ftdmchan->state) {
- case FTDM_CHANNEL_STATE_DIALING:
- if (evntType == MI_PROGRESS ||
- (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL)) {
+ 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:
- if (evntType == MI_PROGRESS ||
- (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL)) {
+ if (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
}
break;
@@ -406,7 +420,7 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
ftdm_size_t min_digits = ((sngisdn_span_data_t*)ftdmchan->span->signal_data)->min_digits;
ftdm_size_t num_digits;
- cpy_called_num_from_stack(&ftdmchan->caller_data, &cnStEvnt->cdPtyNmb);
+ get_called_num(ftdmchan, &cnStEvnt->cdPtyNmb);
num_digits = strlen(ftdmchan->caller_data.dnis.digits);
if (cnStEvnt->sndCmplt.eh.pres || num_digits >= min_digits) {
@@ -417,6 +431,7 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
}
break;
case FTDM_CHANNEL_STATE_RING:
+ case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_UP:
@@ -446,6 +461,7 @@ void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event)
uint32_t spInstId = sngisdn_event->spInstId;
sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info;
ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
DiscEvnt *discEvnt = &sngisdn_event->event.discEvnt;
@@ -454,12 +470,20 @@ void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event)
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing DISCONNECT (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId);
ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n");
- switch (ftdmchan->state) {
+ switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_RING:
case FTDM_CHANNEL_STATE_DIALING:
+ case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
- case FTDM_CHANNEL_STATE_UP:
+ case FTDM_CHANNEL_STATE_UP:
+ if (discEvnt->facilityStr.eh.pres) {
+ if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
+ get_facility_ie(ftdmchan, &discEvnt->facilityStr);
+ } else {
+ /* Call libsng_isdn facility decode function and copy variables here */
+ }
+ }
if (discEvnt->causeDgn[0].eh.pres && discEvnt->causeDgn[0].causeVal.pres) {
ftdmchan->caller_data.hangup_cause = discEvnt->causeDgn[0].causeVal.val;
} else {
@@ -503,6 +527,7 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event)
uint32_t spInstId = sngisdn_event->spInstId;
sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info;
ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
RelEvnt *relEvnt = &sngisdn_event->event.relEvnt;
@@ -538,6 +563,7 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event)
sngisdn_set_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN);
}
/* fall-through */
+ case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_UP:
@@ -547,6 +573,15 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event)
not changed while we were waiting for ftdmchan->mutex by comparing suInstId's */
if (((sngisdn_chan_data_t*)ftdmchan->call_data)->suInstId == suInstId ||
((sngisdn_chan_data_t*)ftdmchan->call_data)->spInstId == spInstId) {
+
+ if (relEvnt->facilityStr.eh.pres) {
+ if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
+ get_facility_ie(ftdmchan, &relEvnt->facilityStr);
+ } else {
+ /* Call libsng_isdn facility decode function and copy variables here */
+ }
+ }
+
if (relEvnt->causeDgn[0].eh.pres && relEvnt->causeDgn[0].causeVal.pres) {
ftdmchan->caller_data.hangup_cause = relEvnt->causeDgn[0].causeVal.val;
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "cause:%d\n", ftdmchan->caller_data.hangup_cause);
@@ -725,15 +760,16 @@ void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event)
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_GET_CALLERID:
/* Update the caller ID Name */
+
if (facEvnt->facElmt.facStr.pres) {
char retrieved_str[255];
-
+
/* return values for "sng_isdn_retrieve_facility_information_following":
If there will be no information following, or fails to decode IE, returns -1
If there will be no information following, but current FACILITY IE contains a caller name, returns 0
If there will be information following, returns 1
*/
-
+
if (sng_isdn_retrieve_facility_caller_name(&facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len, retrieved_str) == 0) {
strcpy(ftdmchan->caller_data.cid_name, retrieved_str);
} else {
@@ -751,6 +787,25 @@ void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event)
/* We received the caller ID Name in FACILITY, but its too late, facility-timeout already occurred */
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "FACILITY received, but we already proceeded with call\n");
break;
+ case FTDM_CHANNEL_STATE_UP:
+ {
+ ftdm_sigmsg_t sigev;
+ if (facEvnt->facElmt.facStr.pres) {
+ if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
+ get_facility_ie_str(ftdmchan, &facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len);
+ } else {
+ /* Call libsng_isdn facility decode function and copy variables here */
+ }
+ }
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.chan_id = ftdmchan->chan_id;
+ sigev.span_id = ftdmchan->span_id;
+ sigev.channel = ftdmchan;
+
+ sigev.event_id = FTDM_SIGEVENT_MSG;
+ ftdm_span_send_signal(ftdmchan->span, &sigev);
+ }
+ break;
default:
/* We do not support other FACILITY types for now, so do nothing */
break;
@@ -865,6 +920,7 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event)
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "T302 Timer expired, proceeding with call\n");
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
break;
+ case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Remote switch expecting OVERLAP receive, but we are already PROCEEDING\n");
@@ -882,6 +938,7 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event)
break;
case 3:
switch (ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
/* T310 timer has expired */
ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val;
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 b58bef23e5..08b14a08ce 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
@@ -36,9 +36,10 @@
void sngisdn_snd_setup(ftdm_channel_t *ftdmchan)
{
- ConEvnt conEvnt;
+ ConEvnt conEvnt;
sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
- sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+ ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN};
ftdm_assert((!sngisdn_info->suInstId && !sngisdn_info->spInstId), "Trying to call out, but call data was not cleared\n");
@@ -116,14 +117,6 @@ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan)
conEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
}
- conEvnt.progInd.eh.pres = PRSNT_NODEF;
- conEvnt.progInd.location.pres = PRSNT_NODEF;
- conEvnt.progInd.location.val = IN_LOC_USER;
- conEvnt.progInd.codeStand0.pres = PRSNT_NODEF;
- conEvnt.progInd.codeStand0.val = IN_CSTD_CCITT;
- conEvnt.progInd.progDesc.pres = PRSNT_NODEF;
- conEvnt.progInd.progDesc.val = IN_PD_NOTETEISDN; /* Not end-to-end ISDN */
-
if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN) {
conEvnt.sndCmplt.eh.pres = PRSNT_NODEF;
}
@@ -133,10 +126,13 @@ 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);
- cpy_called_num_from_user(&conEvnt.cdPtyNmb, &ftdmchan->caller_data);
- cpy_calling_num_from_user(&conEvnt.cgPtyNmb, &ftdmchan->caller_data);
- cpy_redir_num_from_user(&conEvnt.redirNmb, &ftdmchan->caller_data);
- cpy_calling_name_from_user(&conEvnt, ftdmchan);
+ set_called_num(ftdmchan, &conEvnt.cdPtyNmb);
+ set_calling_num(ftdmchan, &conEvnt.cgPtyNmb);
+ set_calling_subaddr(ftdmchan, &conEvnt.cgPtySad);
+ set_redir_num(ftdmchan, &conEvnt.redirNmb);
+ set_calling_name(ftdmchan, &conEvnt);
+ set_facility_ie(ftdmchan, &conEvnt.facilityStr);
+ set_prog_ind_ie(ftdmchan, &conEvnt.progInd, prog_ind);
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending SETUP (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);
@@ -323,14 +319,14 @@ void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan)
return;
}
-void sngisdn_snd_progress(ftdm_channel_t *ftdmchan)
+void sngisdn_snd_progress(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind)
{
CnStEvnt cnStEvnt;
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
- if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
+ if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending PROGRESS, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
@@ -344,14 +340,7 @@ void sngisdn_snd_progress(ftdm_channel_t *ftdmchan)
}
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
-
- cnStEvnt.progInd.eh.pres = PRSNT_NODEF;
- cnStEvnt.progInd.location.pres = PRSNT_NODEF;
- cnStEvnt.progInd.location.val = IN_LOC_USER;
- cnStEvnt.progInd.codeStand0.pres = PRSNT_NODEF;
- cnStEvnt.progInd.codeStand0.val = IN_CSTD_CCITT;
- cnStEvnt.progInd.progDesc.pres = PRSNT_NODEF;
- cnStEvnt.progInd.progDesc.val = IN_PD_IBAVAIL;
+ set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind);
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROGRESS (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);
if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_PROGRESS, signal_data->dchan_id, sngisdn_info->ces)) {
@@ -360,14 +349,14 @@ void sngisdn_snd_progress(ftdm_channel_t *ftdmchan)
return;
}
-void sngisdn_snd_alert(ftdm_channel_t *ftdmchan)
+void sngisdn_snd_alert(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind)
{
CnStEvnt cnStEvnt;
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
- if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
+ if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending ALERT, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
@@ -376,13 +365,7 @@ void sngisdn_snd_alert(ftdm_channel_t *ftdmchan)
memset(&cnStEvnt, 0, sizeof(cnStEvnt));
- cnStEvnt.progInd.eh.pres = PRSNT_NODEF;
- cnStEvnt.progInd.location.pres = PRSNT_NODEF;
- cnStEvnt.progInd.location.val = IN_LOC_USER;
- cnStEvnt.progInd.codeStand0.pres = PRSNT_NODEF;
- cnStEvnt.progInd.codeStand0.val = IN_CSTD_CCITT;
- cnStEvnt.progInd.progDesc.pres = PRSNT_NODEF;
- cnStEvnt.progInd.progDesc.val = IN_PD_NOTETEISDN;
+ set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind);
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending ALERT (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);
@@ -394,10 +377,10 @@ void sngisdn_snd_alert(ftdm_channel_t *ftdmchan)
void sngisdn_snd_connect(ftdm_channel_t *ftdmchan)
{
- CnStEvnt cnStEvnt;
-
+ CnStEvnt cnStEvnt;
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+ ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN};
if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending CONNECT, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
@@ -408,7 +391,6 @@ 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;
@@ -440,14 +422,8 @@ void sngisdn_snd_connect(ftdm_channel_t *ftdmchan)
cnStEvnt.chanId.chanNmbSlotMap.len = 1;
cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
}
-
- cnStEvnt.progInd.eh.pres = PRSNT_NODEF;
- cnStEvnt.progInd.location.pres = PRSNT_NODEF;
- cnStEvnt.progInd.location.val = IN_LOC_USER;
- cnStEvnt.progInd.codeStand0.pres = PRSNT_NODEF;
- cnStEvnt.progInd.codeStand0.val = IN_CSTD_CCITT;
- cnStEvnt.progInd.progDesc.pres = PRSNT_NODEF;
- cnStEvnt.progInd.progDesc.val = IN_PD_NOTETEISDN; /* Not end-to-end ISDN */
+
+ set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind);
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT (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);
if (sng_isdn_con_response(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, signal_data->dchan_id, sngisdn_info->ces)) {
@@ -456,6 +432,32 @@ void sngisdn_snd_connect(ftdm_channel_t *ftdmchan)
return;
}
+void sngisdn_snd_fac_req(ftdm_channel_t *ftdmchan)
+{
+ FacEvnt facEvnt;
+
+ sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+ if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending FACILITY, but no call data, ignoring (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
+ return;
+ }
+
+ memset(&facEvnt, 0, sizeof(facEvnt));
+
+ set_facility_ie_str(ftdmchan, &facEvnt.facElmt.facStr.val[2], (ftdm_size_t*)&facEvnt.facElmt.facStr.len);
+
+ facEvnt.facElmt.facStr.val[0] = 0x1C;
+ facEvnt.facElmt.facStr.val[1] = facEvnt.facElmt.facStr.len;
+
+ ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending FACILITY (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);
+
+ if (sng_isdn_facility_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &facEvnt, MI_FACIL, signal_data->dchan_id, sngisdn_info->ces)) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused FACILITY request\n");
+ }
+ return;
+}
void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan)
{
@@ -510,7 +512,7 @@ void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan)
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
- if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
+ if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending DISCONNECT, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
@@ -531,6 +533,8 @@ void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan)
discEvnt.causeDgn[0].recommend.pres = NOTPRSNT;
discEvnt.causeDgn[0].dgnVal.pres = NOTPRSNT;
+ set_facility_ie(ftdmchan, &discEvnt.facilityStr);
+
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending DISCONNECT (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
if (sng_isdn_disc_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &discEvnt)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused DISCONNECT request\n");
@@ -575,6 +579,8 @@ void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare)
spInstId = sngisdn_info->spInstId;
}
+ set_facility_ie(ftdmchan, &relEvnt.facilityStr);
+
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending RELEASE/RELEASE COMPLETE (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, suInstId, spInstId);
if (glare) {
@@ -589,6 +595,7 @@ void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare)
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_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
index 056bf66ef2..42bcd1e20a 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
@@ -33,6 +33,15 @@
*/
#include "ftmod_sangoma_isdn.h"
+#define SNGISDN_Q931_FACILITY_IE_ID 0x1C
+
+/* ftmod_sangoma_isdn specific enum look-up functions */
+
+SNGISDN_ENUM_NAMES(SNGISDN_PROGIND_DESCR_NAMES, SNGISDN_PROGIND_DESCR_STRINGS)
+SNGISDN_STR2ENUM(ftdm_str2ftdm_sngisdn_progind_descr, ftdm_sngisdn_progind_descr2str, ftdm_sngisdn_progind_descr_t, SNGISDN_PROGIND_DESCR_NAMES, SNGISDN_PROGIND_DESCR_INVALID)
+
+SNGISDN_ENUM_NAMES(SNGISDN_PROGIND_LOC_NAMES, SNGISDN_PROGIND_LOC_STRINGS)
+SNGISDN_STR2ENUM(ftdm_str2ftdm_sngisdn_progind_loc, ftdm_sngisdn_progind_loc2str, ftdm_sngisdn_progind_loc_t, SNGISDN_PROGIND_LOC_NAMES, SNGISDN_PROGIND_LOC_INVALID)
ftdm_status_t sngisdn_check_free_ids(void);
@@ -129,7 +138,6 @@ ftdm_status_t get_ftdmchan_by_spInstId(int16_t cc_id, uint32_t spInstId, sngisdn
ftdm_status_t sngisdn_set_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail)
{
-
if (span->trunk_type == FTDM_TRUNK_BRI ||
span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
@@ -147,77 +155,84 @@ ftdm_status_t sngisdn_set_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail)
return FTDM_SUCCESS;
}
-ftdm_status_t cpy_calling_num_from_stack(ftdm_caller_data_t *ftdm, CgPtyNmb *cgPtyNmb)
+ftdm_status_t get_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb)
{
+ ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
if (cgPtyNmb->eh.pres != PRSNT_NODEF) {
return FTDM_FAIL;
}
if (cgPtyNmb->screenInd.pres == PRSNT_NODEF) {
- ftdm->screen = cgPtyNmb->screenInd.val;
+ caller_data->screen = cgPtyNmb->screenInd.val;
}
if (cgPtyNmb->presInd0.pres == PRSNT_NODEF) {
- ftdm->pres = cgPtyNmb->presInd0.val;
+ caller_data->pres = cgPtyNmb->presInd0.val;
}
if (cgPtyNmb->nmbPlanId.pres == PRSNT_NODEF) {
- ftdm->cid_num.plan = cgPtyNmb->nmbPlanId.val;
+ caller_data->cid_num.plan = cgPtyNmb->nmbPlanId.val;
}
+
if (cgPtyNmb->typeNmb1.pres == PRSNT_NODEF) {
- ftdm->cid_num.type = cgPtyNmb->typeNmb1.val;
+ caller_data->cid_num.type = cgPtyNmb->typeNmb1.val;
}
if (cgPtyNmb->nmbDigits.pres == PRSNT_NODEF) {
- ftdm_copy_string(ftdm->cid_num.digits, (const char*)cgPtyNmb->nmbDigits.val, cgPtyNmb->nmbDigits.len+1);
+ ftdm_copy_string(caller_data->cid_num.digits, (const char*)cgPtyNmb->nmbDigits.val, cgPtyNmb->nmbDigits.len+1);
}
+ memcpy(&caller_data->ani, &caller_data->cid_num, sizeof(caller_data->ani));
return FTDM_SUCCESS;
}
-ftdm_status_t cpy_called_num_from_stack(ftdm_caller_data_t *ftdm, CdPtyNmb *cdPtyNmb)
+ftdm_status_t get_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb)
{
+ ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
if (cdPtyNmb->eh.pres != PRSNT_NODEF) {
return FTDM_FAIL;
}
if (cdPtyNmb->nmbPlanId.pres == PRSNT_NODEF) {
- ftdm->dnis.plan = cdPtyNmb->nmbPlanId.val;
+ caller_data->dnis.plan = cdPtyNmb->nmbPlanId.val;
}
if (cdPtyNmb->typeNmb0.pres == PRSNT_NODEF) {
- ftdm->dnis.type = cdPtyNmb->typeNmb0.val;
+ caller_data->dnis.type = cdPtyNmb->typeNmb0.val;
}
if (cdPtyNmb->nmbDigits.pres == PRSNT_NODEF) {
- unsigned i = strlen(ftdm->dnis.digits);
+ /* In overlap receive mode, append the new digits to the existing dnis */
+ unsigned i = strlen(caller_data->dnis.digits);
- ftdm_copy_string(&ftdm->dnis.digits[i], (const char*)cdPtyNmb->nmbDigits.val, cdPtyNmb->nmbDigits.len+1);
+ ftdm_copy_string(&caller_data->dnis.digits[i], (const char*)cdPtyNmb->nmbDigits.val, cdPtyNmb->nmbDigits.len+1);
}
return FTDM_SUCCESS;
}
-ftdm_status_t cpy_redir_num_from_stack(ftdm_caller_data_t *ftdm, RedirNmb *redirNmb)
+ftdm_status_t get_redir_num(ftdm_channel_t *ftdmchan, RedirNmb *redirNmb)
{
+ ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
if (redirNmb->eh.pres != PRSNT_NODEF) {
return FTDM_FAIL;
}
if (redirNmb->nmbPlanId.pres == PRSNT_NODEF) {
- ftdm->rdnis.plan = redirNmb->nmbPlanId.val;
+ caller_data->rdnis.plan = redirNmb->nmbPlanId.val;
}
if (redirNmb->typeNmb.pres == PRSNT_NODEF) {
- ftdm->rdnis.type = redirNmb->typeNmb.val;
+ caller_data->rdnis.type = redirNmb->typeNmb.val;
}
if (redirNmb->nmbDigits.pres == PRSNT_NODEF) {
- ftdm_copy_string(ftdm->rdnis.digits, (const char*)redirNmb->nmbDigits.val, redirNmb->nmbDigits.len+1);
+ ftdm_copy_string(caller_data->rdnis.digits, (const char*)redirNmb->nmbDigits.val, redirNmb->nmbDigits.len+1);
}
return FTDM_SUCCESS;
}
-ftdm_status_t cpy_calling_name_from_stack(ftdm_caller_data_t *ftdm, Display *display)
+ftdm_status_t get_calling_name_from_display(ftdm_channel_t *ftdmchan, Display *display)
{
+ ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
if (display->eh.pres != PRSNT_NODEF) {
return FTDM_FAIL;
}
@@ -225,71 +240,209 @@ ftdm_status_t cpy_calling_name_from_stack(ftdm_caller_data_t *ftdm, Display *dis
return FTDM_FAIL;
}
- ftdm_copy_string(ftdm->cid_name, (const char*)display->dispInfo.val, display->dispInfo.len+1);
+ ftdm_copy_string(caller_data->cid_name, (const char*)display->dispInfo.val, display->dispInfo.len+1);
return FTDM_SUCCESS;
}
-ftdm_status_t cpy_calling_num_from_user(CgPtyNmb *cgPtyNmb, ftdm_caller_data_t *ftdm)
+ftdm_status_t get_calling_name_from_usr_usr(ftdm_channel_t *ftdmchan, UsrUsr *usrUsr)
{
- uint8_t len = strlen(ftdm->cid_num.digits);
+ ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
+ if (usrUsr->eh.pres != PRSNT_NODEF) {
+ return FTDM_FAIL;
+ }
+
+ if (usrUsr->protocolDisc.val != PD_IA5) {
+ return FTDM_FAIL;
+ }
+
+ if (usrUsr->usrInfo.pres != PRSNT_NODEF) {
+ return FTDM_FAIL;
+ }
+
+ ftdm_copy_string(caller_data->cid_name, (const char*)usrUsr->usrInfo.val, usrUsr->usrInfo.len+1);
+ return FTDM_SUCCESS;
+}
+
+ftdm_status_t get_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad)
+{
+ char subaddress[100];
+
+ if (cgPtySad->eh.pres != PRSNT_NODEF) {
+ return FTDM_FAIL;
+ }
+ memset(subaddress, 0, sizeof(subaddress));
+ if(cgPtySad->sadInfo.len >= sizeof(subaddress)) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Calling Party Subaddress exceeds local size limit (len:%d max:%d)\n", cgPtySad->sadInfo.len, sizeof(subaddress));
+ cgPtySad->sadInfo.len = sizeof(subaddress)-1;
+ }
+
+ memcpy(subaddress, (char*)cgPtySad->sadInfo.val, cgPtySad->sadInfo.len);
+ subaddress[cgPtySad->sadInfo.len] = '\0';
+ ftdm_channel_add_var(ftdmchan, "isdn.calling_subaddr", subaddress);
+ return FTDM_SUCCESS;
+}
+
+ftdm_status_t get_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr)
+{
+ if (!facilityStr->eh.pres) {
+ return FTDM_FAIL;
+ }
+
+ return get_facility_ie_str(ftdmchan, facilityStr->facilityStr.val, facilityStr->facilityStr.len);
+}
+
+ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t data_len)
+{
+ ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
+ if (data_len > sizeof(caller_data->raw_data)-2) {
+ ftdm_log(FTDM_LOG_CRIT, "Length of Facility IE exceeds maximum length\n");
+ return FTDM_FAIL;
+ }
+
+ memset(caller_data->raw_data, 0, sizeof(caller_data->raw_data));
+ /* Always include Facility IE identifier + len so this can be used as a sanity check by the user */
+ caller_data->raw_data[0] = SNGISDN_Q931_FACILITY_IE_ID;
+ caller_data->raw_data[1] = data_len;
+
+ memcpy(&caller_data->raw_data[2], data, data_len);
+ caller_data->raw_data_len = data_len+2;
+ return FTDM_SUCCESS;
+}
+
+ftdm_status_t get_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd)
+{
+ uint8_t val;
+ if (!progInd->eh.pres) {
+ return FTDM_FAIL;
+ }
+
+ if (progInd->progDesc.pres) {
+ switch (progInd->progDesc.val) {
+ case IN_PD_NOTETEISDN:
+ val = SNGISDN_PROGIND_DESCR_NETE_ISDN;
+ break;
+ case IN_PD_DSTNOTISDN:
+ val = SNGISDN_PROGIND_DESCR_DEST_NISDN;
+ break;
+ case IN_PD_ORGNOTISDN:
+ val = SNGISDN_PROGIND_DESCR_ORIG_NISDN;
+ break;
+ case IN_PD_CALLRET:
+ val = SNGISDN_PROGIND_DESCR_RET_ISDN;
+ break;
+ case IN_PD_DELRESP:
+ val = SNGISDN_PROGIND_DESCR_SERV_CHANGE;
+ break;
+ case IN_PD_IBAVAIL:
+ val = SNGISDN_PROGIND_DESCR_IB_AVAIL;
+ break;
+ default:
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unknown Progress Indicator Description (%d)\n", progInd->progDesc.val);
+ val = SNGISDN_PROGIND_DESCR_INVALID;
+ break;
+ }
+ ftdm_channel_add_var(ftdmchan, "isdn.prog_ind.descr", ftdm_sngisdn_progind_descr2str(val));
+ }
+
+ if (progInd->location.pres) {
+ switch (progInd->location.val) {
+ case IN_LOC_USER:
+ val = SNGISDN_PROGIND_LOC_USER;
+ break;
+ case IN_LOC_PRIVNETLU:
+ val = SNGISDN_PROGIND_LOC_PRIV_NET_LOCAL_USR;
+ break;
+ case IN_LOC_PUBNETLU:
+ val = SNGISDN_PROGIND_LOC_PUB_NET_LOCAL_USR;
+ break;
+ case IN_LOC_TRANNET:
+ val = SNGISDN_PROGIND_LOC_TRANSIT_NET;
+ break;
+ case IN_LOC_PUBNETRU:
+ val = SNGISDN_PROGIND_LOC_PUB_NET_REMOTE_USR;
+ break;
+ case IN_LOC_PRIVNETRU:
+ val = SNGISDN_PROGIND_LOC_PRIV_NET_REMOTE_USR;
+ break;
+ case IN_LOC_NETINTER:
+ val = SNGISDN_PROGIND_LOC_NET_BEYOND_INTRW;
+ break;
+ default:
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unknown Progress Indicator Location (%d)", progInd->location.val);
+ val = SNGISDN_PROGIND_LOC_INVALID;
+ break;
+ }
+ ftdm_channel_add_var(ftdmchan, "isdn.prog_ind.loc", ftdm_sngisdn_progind_loc2str(val));
+ }
+ return FTDM_SUCCESS;
+}
+
+
+ftdm_status_t set_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb)
+{
+ ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
+ uint8_t len = strlen(caller_data->cid_num.digits);
if (!len) {
return FTDM_SUCCESS;
}
cgPtyNmb->eh.pres = PRSNT_NODEF;
cgPtyNmb->screenInd.pres = PRSNT_NODEF;
- cgPtyNmb->screenInd.val = ftdm->screen;
+ cgPtyNmb->screenInd.val = caller_data->screen;
cgPtyNmb->presInd0.pres = PRSNT_NODEF;
- cgPtyNmb->presInd0.val = ftdm->pres;
-
+ cgPtyNmb->presInd0.val = caller_data->pres;
+
cgPtyNmb->nmbPlanId.pres = PRSNT_NODEF;
- cgPtyNmb->nmbPlanId.val = ftdm->cid_num.plan;
+ cgPtyNmb->nmbPlanId.val = caller_data->cid_num.plan;
cgPtyNmb->typeNmb1.pres = PRSNT_NODEF;
- cgPtyNmb->typeNmb1.val = ftdm->cid_num.type;
+ cgPtyNmb->typeNmb1.val = caller_data->cid_num.type;
cgPtyNmb->nmbDigits.pres = PRSNT_NODEF;
cgPtyNmb->nmbDigits.len = len;
- memcpy(cgPtyNmb->nmbDigits.val, ftdm->cid_num.digits, len);
+ memcpy(cgPtyNmb->nmbDigits.val, caller_data->cid_num.digits, len);
return FTDM_SUCCESS;
}
-ftdm_status_t cpy_called_num_from_user(CdPtyNmb *cdPtyNmb, ftdm_caller_data_t *ftdm)
+ftdm_status_t set_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb)
{
- uint8_t len = strlen(ftdm->dnis.digits);
+ ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
+ uint8_t len = strlen(caller_data->dnis.digits);
+
if (!len) {
return FTDM_SUCCESS;
}
cdPtyNmb->eh.pres = PRSNT_NODEF;
cdPtyNmb->nmbPlanId.pres = PRSNT_NODEF;
- if (ftdm->dnis.plan == FTDM_NPI_INVALID) {
+ if (caller_data->dnis.plan == FTDM_NPI_INVALID) {
cdPtyNmb->nmbPlanId.val = FTDM_NPI_UNKNOWN;
} else {
- cdPtyNmb->nmbPlanId.val = ftdm->dnis.plan;
+ cdPtyNmb->nmbPlanId.val = caller_data->dnis.plan;
}
cdPtyNmb->typeNmb0.pres = PRSNT_NODEF;
- if (ftdm->dnis.type == FTDM_TON_INVALID) {
+ if (caller_data->dnis.type == FTDM_TON_INVALID) {
cdPtyNmb->typeNmb0.val = FTDM_TON_UNKNOWN;
} else {
- cdPtyNmb->typeNmb0.val = ftdm->dnis.type;
+ cdPtyNmb->typeNmb0.val = caller_data->dnis.type;
}
cdPtyNmb->nmbDigits.pres = PRSNT_NODEF;
cdPtyNmb->nmbDigits.len = len;
- memcpy(cdPtyNmb->nmbDigits.val, ftdm->dnis.digits, len);
+ memcpy(cdPtyNmb->nmbDigits.val, caller_data->dnis.digits, len);
return FTDM_SUCCESS;
}
-ftdm_status_t cpy_redir_num_from_user(RedirNmb *redirNmb, ftdm_caller_data_t *ftdm)
+ftdm_status_t set_redir_num(ftdm_channel_t *ftdmchan, RedirNmb *redirNmb)
{
- uint8_t len = strlen(ftdm->rdnis.digits);
+ ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
+ uint8_t len = strlen(caller_data->rdnis.digits);
if (!len) {
return FTDM_SUCCESS;
}
@@ -297,36 +450,36 @@ ftdm_status_t cpy_redir_num_from_user(RedirNmb *redirNmb, ftdm_caller_data_t *ft
redirNmb->eh.pres = PRSNT_NODEF;
redirNmb->nmbPlanId.pres = PRSNT_NODEF;
- if (ftdm->rdnis.plan == FTDM_NPI_INVALID) {
+ if (caller_data->rdnis.plan == FTDM_NPI_INVALID) {
redirNmb->nmbPlanId.val = FTDM_NPI_UNKNOWN;
} else {
- redirNmb->nmbPlanId.val = ftdm->rdnis.plan;
+ redirNmb->nmbPlanId.val = caller_data->rdnis.plan;
}
redirNmb->typeNmb.pres = PRSNT_NODEF;
- if (ftdm->rdnis.type == FTDM_TON_INVALID) {
+ if (caller_data->rdnis.type == FTDM_TON_INVALID) {
redirNmb->typeNmb.val = FTDM_TON_UNKNOWN;
} else {
- redirNmb->typeNmb.val = ftdm->rdnis.type;
+ redirNmb->typeNmb.val = caller_data->rdnis.type;
}
redirNmb->nmbDigits.pres = PRSNT_NODEF;
redirNmb->nmbDigits.len = len;
- memcpy(redirNmb->nmbDigits.val, ftdm->rdnis.digits, len);
+ memcpy(redirNmb->nmbDigits.val, caller_data->rdnis.digits, len);
return FTDM_SUCCESS;
}
-ftdm_status_t cpy_calling_name_from_user(ConEvnt *conEvnt, ftdm_channel_t *ftdmchan)
+ftdm_status_t set_calling_name(ftdm_channel_t *ftdmchan, ConEvnt *conEvnt)
{
uint8_t len;
- ftdm_caller_data_t *ftdm = &ftdmchan->caller_data;
+ ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
/* sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; */
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
- len = strlen(ftdm->cid_name);
+ len = strlen(caller_data->cid_name);
if (!len) {
return FTDM_SUCCESS;
}
@@ -341,7 +494,7 @@ ftdm_status_t cpy_calling_name_from_user(ConEvnt *conEvnt, ftdm_channel_t *ftdmc
conEvnt->usrUsr.usrInfo.len = len;
/* in sangoma_brid we used to send usr-usr info as !,
change to previous style if current one does not work */
- memcpy(conEvnt->usrUsr.usrInfo.val, ftdm->cid_name, len);
+ memcpy(conEvnt->usrUsr.usrInfo.val, caller_data->cid_name, len);
} else {
switch (signal_data->switchtype) {
case SNGISDN_SWITCH_NI2:
@@ -359,7 +512,7 @@ ftdm_status_t cpy_calling_name_from_user(ConEvnt *conEvnt, ftdm_channel_t *ftdmc
conEvnt->display.eh.pres = PRSNT_NODEF;
conEvnt->display.dispInfo.pres = PRSNT_NODEF;
conEvnt->display.dispInfo.len = len;
- memcpy(conEvnt->display.dispInfo.val, ftdm->cid_name, len);
+ memcpy(conEvnt->display.dispInfo.val, caller_data->cid_name, len);
break;
case SNGISDN_SWITCH_QSIG:
/* It seems like QSIG does not support Caller ID Name */
@@ -372,6 +525,139 @@ ftdm_status_t cpy_calling_name_from_user(ConEvnt *conEvnt, ftdm_channel_t *ftdmc
return FTDM_SUCCESS;
}
+ftdm_status_t set_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad)
+{
+ const char* clg_subaddr = NULL;
+ clg_subaddr = ftdm_channel_get_var(ftdmchan, "isdn.calling_subaddr");
+ if ((clg_subaddr != NULL) && (*clg_subaddr)) {
+ unsigned len = strlen (clg_subaddr);
+ cgPtySad->eh.pres = PRSNT_NODEF;
+ cgPtySad->typeSad.pres = 1;
+ cgPtySad->typeSad.val = 0; /* NSAP */
+ cgPtySad->oddEvenInd.pres = 1;
+ cgPtySad->oddEvenInd.val = 0;
+
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending Calling Party Subaddress:%s\n", clg_subaddr);
+ cgPtySad->sadInfo.pres = 1;
+ cgPtySad->sadInfo.len = len;
+ memcpy(cgPtySad->sadInfo.val, clg_subaddr, len);
+ }
+ return FTDM_SUCCESS;
+}
+
+
+ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr)
+{
+ ftdm_status_t status;
+ status = set_facility_ie_str(ftdmchan, facilityStr->facilityStr.val, (ftdm_size_t*)&facilityStr->facilityStr.len);
+ if (status == FTDM_SUCCESS) {
+ facilityStr->eh.pres = PRSNT_NODEF;
+ facilityStr->facilityStr.pres = PRSNT_NODEF;
+ }
+ return status;
+}
+
+ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t *data_len)
+{
+ ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
+
+ if (caller_data->raw_data_len > 0 && caller_data->raw_data[0] == SNGISDN_Q931_FACILITY_IE_ID) {
+
+ *data_len = caller_data->raw_data[1];
+ memcpy(data, &caller_data->raw_data[2], *data_len);
+ return FTDM_SUCCESS;
+ }
+ return FTDM_FAIL;
+}
+
+ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_sngisdn_progind_t prog_ind)
+{
+ const char *str = NULL;
+ int descr = prog_ind.descr;
+ int loc = prog_ind.loc;
+
+ str = ftdm_channel_get_var(ftdmchan, "isdn.prog_ind.descr");
+ if (str && *str) {
+ /* User wants to override progress indicator */
+ descr = ftdm_str2ftdm_sngisdn_progind_descr(str);
+ }
+
+ if (descr == SNGISDN_PROGIND_DESCR_INVALID) {
+ /* User does not want to send progress indicator */
+ return FTDM_SUCCESS;
+ }
+
+ str = ftdm_channel_get_var(ftdmchan, "isdn.prog_ind.loc");
+ if (str && *str) {
+ loc = ftdm_str2ftdm_sngisdn_progind_loc(str);
+ }
+ if (loc == SNGISDN_PROGIND_LOC_INVALID) {
+ loc = SNGISDN_PROGIND_LOC_USER;
+ }
+
+ progInd->eh.pres = PRSNT_NODEF;
+ progInd->codeStand0.pres = PRSNT_NODEF;
+ progInd->codeStand0.val = IN_CSTD_CCITT;
+
+ progInd->progDesc.pres = PRSNT_NODEF;
+ switch(descr) {
+ case SNGISDN_PROGIND_DESCR_NETE_ISDN:
+ progInd->progDesc.val = IN_PD_NOTETEISDN;
+ break;
+ case SNGISDN_PROGIND_DESCR_DEST_NISDN:
+ progInd->progDesc.val = IN_PD_DSTNOTISDN;
+ break;
+ case SNGISDN_PROGIND_DESCR_ORIG_NISDN:
+ progInd->progDesc.val = IN_PD_ORGNOTISDN;
+ break;
+ case SNGISDN_PROGIND_DESCR_RET_ISDN:
+ progInd->progDesc.val = IN_PD_CALLRET;
+ break;
+ case SNGISDN_PROGIND_DESCR_SERV_CHANGE:
+ /* Trillium defines do not match ITU-T Q931 Progress descriptions,
+ indicate a delayed response for now */
+ progInd->progDesc.val = IN_PD_DELRESP;
+ break;
+ case SNGISDN_PROGIND_DESCR_IB_AVAIL:
+ progInd->progDesc.val = IN_PD_IBAVAIL;
+ break;
+ default:
+ ftdm_log(FTDM_LOG_WARNING, "Invalid prog_ind description:%d\n", descr);
+ progInd->progDesc.val = IN_PD_NOTETEISDN;
+ break;
+ }
+
+ progInd->location.pres = PRSNT_NODEF;
+ switch (loc) {
+ case SNGISDN_PROGIND_LOC_USER:
+ progInd->location.val = IN_LOC_USER;
+ break;
+ case SNGISDN_PROGIND_LOC_PRIV_NET_LOCAL_USR:
+ progInd->location.val = IN_LOC_PRIVNETLU;
+ break;
+ case SNGISDN_PROGIND_LOC_PUB_NET_LOCAL_USR:
+ progInd->location.val = IN_LOC_PUBNETLU;
+ break;
+ case SNGISDN_PROGIND_LOC_TRANSIT_NET:
+ progInd->location.val = IN_LOC_TRANNET;
+ break;
+ case SNGISDN_PROGIND_LOC_PUB_NET_REMOTE_USR:
+ progInd->location.val = IN_LOC_PUBNETRU;
+ break;
+ case SNGISDN_PROGIND_LOC_PRIV_NET_REMOTE_USR:
+ progInd->location.val = IN_LOC_PRIVNETRU;
+ break;
+ case SNGISDN_PROGIND_LOC_NET_BEYOND_INTRW:
+ progInd->location.val = IN_LOC_NETINTER;
+ break;
+ default:
+ ftdm_log(FTDM_LOG_WARNING, "Invalid prog_ind location:%d\n", loc);
+ progInd->location.val = IN_PD_NOTETEISDN;
+ }
+ return FTDM_SUCCESS;
+}
+
+
void sngisdn_t3_timeout(void* p_sngisdn_info)
{
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info;
@@ -528,13 +814,12 @@ uint8_t sngisdn_get_infoTranCap_from_stack(ftdm_bearer_cap_t bearer_capability)
switch(bearer_capability) {
case FTDM_BEARER_CAP_SPEECH:
return IN_ITC_SPEECH;
-
case FTDM_BEARER_CAP_64K_UNRESTRICTED:
return IN_ITC_UNRDIG;
-
case FTDM_BEARER_CAP_3_1KHZ_AUDIO:
return IN_ITC_A31KHZ;
-
+ case FTDM_BEARER_CAP_INVALID:
+ return IN_ITC_SPEECH;
/* Do not put a default case here, so we can see compile warnings if we have unhandled cases */
}
return FTDM_BEARER_CAP_SPEECH;
@@ -545,13 +830,12 @@ uint8_t sngisdn_get_usrInfoLyr1Prot_from_stack(ftdm_user_layer1_prot_t layer1_pr
switch(layer1_prot) {
case FTDM_USER_LAYER1_PROT_V110:
return IN_UIL1_CCITTV110;
-
case FTDM_USER_LAYER1_PROT_ULAW:
return IN_UIL1_G711ULAW;
-
case FTDM_USER_LAYER1_PROT_ALAW:
return IN_UIL1_G711ALAW;
-
+ case FTDM_USER_LAYER1_PROT_INVALID:
+ return IN_UIL1_G711ULAW;
/* Do not put a default case here, so we can see compile warnings if we have unhandled cases */
}
return IN_UIL1_G711ULAW;
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 624d35c147..e5167164b3 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
@@ -613,6 +613,21 @@ uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset
return 0;
break;
case PROT_Q931_IE_CALLED_PARTY_SUBADDRESS:
+ {
+ uint8_t type;
+ uint8_t currentOct, j=0;
+ char calling_subaddr_string[82];
+ memset(calling_subaddr_string, 0, sizeof(calling_subaddr_string));
+ type = get_bits(OCTET(3),5,7);
+ currentOct = 3;
+ while(currentOct++ <= len+1) {
+ calling_subaddr_string[j++]=ia5[get_bits(OCTET(currentOct),1,4)][get_bits(OCTET(currentOct),5,8)];
+ }
+ calling_subaddr_string[j++]='\0';
+ *str_len += sprintf(&str[*str_len], "%s (l:%d) type:%s(%d) \n",
+ calling_subaddr_string, (j-1), get_code_2_str(type, dcodQ931TypeOfSubaddressTable), type);
+ }
+ break;
case PROT_Q931_IE_REDIRECTION_NUMBER:
case PROT_Q931_IE_NOTIFICATION_IND:
case PROT_Q931_IE_DATE_TIME:
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h
index d210c50db9..f054de9377 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.h
@@ -544,5 +544,11 @@ struct code2str dcodQ931GenDigitsTypeTable[] = {
{-1, "Invalid"},
};
+struct code2str dcodQ931TypeOfSubaddressTable[] = {
+ { 0x00, "NSAP"},
+ { 0x02, "User-specified"},
+ { -1, "Invalid"},
+};
+
#endif /* __FTMOD_SANGOMA_ISDN_TRACE_H__ */
diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj
new file mode 100644
index 0000000000..b165ac82d3
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj
@@ -0,0 +1,201 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ ftmod_wanpipe
+ {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}
+ ftmod_wanpipe
+ Win32Proj
+
+
+
+ DynamicLibrary
+ MultiByte
+ true
+
+
+ DynamicLibrary
+ MultiByte
+
+
+ DynamicLibrary
+ MultiByte
+ true
+
+
+ DynamicLibrary
+ MultiByte
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>10.0.30319.1
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ false
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+ AllRules.ruleset
+
+
+
+
+
+ Disabled
+ ../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level3
+ EditAndContinue
+
+
+ freetdm.lib;libsangoma.lib;%(AdditionalDependencies)
+ $(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)
+ true
+ Console
+ false
+
+
+ MachineX86
+
+
+
+
+ X64
+
+
+ Disabled
+ ../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level3
+ ProgramDatabase
+
+
+ freetdm.lib;libsangoma.lib;%(AdditionalDependencies)
+ $(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories)
+ true
+ Console
+ false
+
+
+ MachineX64
+
+
+
+
+ ../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level3
+ ProgramDatabase
+
+
+ freetdm.lib;libsangoma.lib;%(AdditionalDependencies)
+ $(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)
+ true
+ Console
+ true
+ true
+ false
+
+
+ MachineX86
+
+
+
+
+ X64
+
+
+ ../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level3
+ ProgramDatabase
+
+
+ freetdm.lib;libsangoma.lib;%(AdditionalDependencies)
+ $(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories)
+ true
+ Console
+ true
+ true
+ false
+
+
+ MachineX64
+
+
+
+
+
+
+
+ {93b8812c-3ec4-4f78-8970-ffbfc99e167d}
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj.filters
new file mode 100644
index 0000000000..15a8bc3d35
--- /dev/null
+++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj.filters
@@ -0,0 +1,18 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
index 17f0219b1f..0fd2cd66be 100644
--- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
+++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
@@ -123,6 +123,10 @@ static __inline__ int tdmv_api_wait_socket(ftdm_channel_t *ftdmchan, int timeout
uint32_t outflags = 0;
sangoma_wait_obj_t *sangoma_wait_obj = ftdmchan->io_data;
+ if (timeout == -1) {
+ timeout = SANGOMA_WAIT_INFINITE;
+ }
+
err = sangoma_waitfor(sangoma_wait_obj, inflags, &outflags, timeout);
*flags = 0;
if (err == SANG_STATUS_SUCCESS) {
@@ -789,10 +793,11 @@ static void wanpipe_write_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_tx_hdr_t *t
ftdmchan->iostats.tx.queue_size = tx_stats->wp_api_tx_hdr_max_queue_length;
ftdmchan->iostats.tx.queue_len = tx_stats->wp_api_tx_hdr_number_of_frames_in_queue;
- if (ftdmchan->iostats.tx.queue_len >= ftdmchan->iostats.rx.queue_size) {
+ /* we don't test for 80% full in tx since is typically full for voice channels, should we test tx 80% full for D-channels? */
+ if (ftdmchan->iostats.tx.queue_len >= ftdmchan->iostats.tx.queue_size) {
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Tx Queue Full (%d/%d)\n",
- ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size);
- ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL);
+ ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.tx.queue_size);
+ ftdm_set_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL);
} else if (ftdm_test_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL)){
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Tx Queue no longer full (%d/%d)\n",
ftdmchan->iostats.tx.queue_len, ftdmchan->iostats.tx.queue_size);
@@ -801,7 +806,10 @@ static void wanpipe_write_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_tx_hdr_t *t
if (ftdmchan->iostats.tx.idle_packets < tx_stats->wp_api_tx_hdr_number_of_frames_in_queue) {
ftdmchan->iostats.tx.idle_packets = tx_stats->wp_api_tx_hdr_tx_idle_packets;
- ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Tx idle: %d\n", ftdmchan->iostats.tx.idle_packets);
+ /* HDLC channels do not always transmit, so its ok for drivers to fill with idle */
+ if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Tx idle: %d\n", ftdmchan->iostats.tx.idle_packets);
+ }
}
if (!ftdmchan->iostats.tx.packets) {
@@ -850,6 +858,16 @@ static void wanpipe_read_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_rx_hdr_t *rx
ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FRAME);
}
+ if (ftdmchan->iostats.rx.queue_len >= (0.8 * ftdmchan->iostats.rx.queue_size)) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Rx Queue length exceeded 80% threshold (%d/%d)\n",
+ ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size);
+ ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES);
+ } else if (ftdm_test_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES)){
+ ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Rx Queue length reduced 80% threshold (%d/%d)\n",
+ ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size);
+ ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES);
+ }
+
if (ftdmchan->iostats.rx.queue_len >= ftdmchan->iostats.rx.queue_size) {
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Rx Queue Full (%d/%d)\n",
ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size);
diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj b/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj
deleted file mode 100644
index abebf30427..0000000000
--- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj
+++ /dev/null
@@ -1,196 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h b/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h
deleted file mode 100644
index 3801ff9c8c..0000000000
--- a/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h
+++ /dev/null
@@ -1,351 +0,0 @@
-/*****************************************************************************
-* wanpipe_tdm_api_iface.h
-*
-* WANPIPE(tm) AFT TE1 Hardware Support
-*
-* Authors: Nenad Corbic
-*
-* Copyright (c) 2007 - 08, Sangoma Technologies
-* 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 nor the
-* names of its contributors may be used to endorse or promote products
-* derived from this software without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED BY ``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 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.
-
-* ============================================================================
-* Oct 04, 2005 Nenad Corbic Initial version.
-*
-* Jul 25, 2006 David Rokhvarg Ported to Windows.
-*****************************************************************************/
-
-#ifndef __WANPIPE_TDM_API_IFACE_H_
-#define __WANPIPE_TDM_API_IFACE_H_
-
-
-#if defined(__WINDOWS__)
-typedef HANDLE sng_fd_t;
-#else
-typedef int sng_fd_t;
-#endif
-
-/* Indicate to library that new features exist */
-#define WP_TDM_FEATURE_DTMF_EVENTS 1
-#define WP_TDM_FEATURE_FE_ALARM 1
-#define WP_TDM_FEATURE_EVENTS 1
-#define WP_TDM_FEATURE_LINK_STATUS 1
-
-enum wanpipe_tdm_api_cmds {
-
- SIOC_WP_TDM_GET_USR_MTU_MRU, /* 0x00 */
-
- SIOC_WP_TDM_SET_USR_PERIOD, /* 0x01 */
- SIOC_WP_TDM_GET_USR_PERIOD, /* 0x02 */
-
- SIOC_WP_TDM_SET_HW_MTU_MRU, /* 0x03 */
- SIOC_WP_TDM_GET_HW_MTU_MRU, /* 0x04 */
-
- SIOC_WP_TDM_SET_CODEC, /* 0x05 */
- SIOC_WP_TDM_GET_CODEC, /* 0x06 */
-
- SIOC_WP_TDM_SET_POWER_LEVEL, /* 0x07 */
- SIOC_WP_TDM_GET_POWER_LEVEL, /* 0x08 */
-
- SIOC_WP_TDM_TOGGLE_RX, /* 0x09 */
- SIOC_WP_TDM_TOGGLE_TX, /* 0x0A */
-
- SIOC_WP_TDM_GET_HW_CODING, /* 0x0B */
- SIOC_WP_TDM_SET_HW_CODING, /* 0x0C */
-
- SIOC_WP_TDM_GET_FULL_CFG, /* 0x0D */
-
- SIOC_WP_TDM_SET_EC_TAP, /* 0x0E */
- SIOC_WP_TDM_GET_EC_TAP, /* 0x0F */
-
- SIOC_WP_TDM_ENABLE_RBS_EVENTS, /* 0x10 */
- SIOC_WP_TDM_DISABLE_RBS_EVENTS, /* 0x11 */
- SIOC_WP_TDM_WRITE_RBS_BITS, /* 0x12 */
-
- SIOC_WP_TDM_GET_STATS, /* 0x13 */
- SIOC_WP_TDM_FLUSH_BUFFERS, /* 0x14 */
-
- SIOC_WP_TDM_READ_EVENT, /* 0x15 */
-
- SIOC_WP_TDM_SET_EVENT, /* 0x16 */
-
- SIOC_WP_TDM_SET_RX_GAINS, /* 0x17 */
- SIOC_WP_TDM_SET_TX_GAINS, /* 0x18 */
- SIOC_WP_TDM_CLEAR_RX_GAINS, /* 0x19 */
- SIOC_WP_TDM_CLEAR_TX_GAINS, /* 0x1A */
-
- SIOC_WP_TDM_GET_FE_ALARMS, /* 0x1B */
-
- SIOC_WP_TDM_ENABLE_HWEC, /* 0x1C */
- SIOC_WP_TDM_DISABLE_HWEC, /* 0x1D */
-
- SIOC_WP_TDM_SET_FE_STATUS, /* 0x1E */
- SIOC_WP_TDM_GET_FE_STATUS, /* 0x1F */
-
- SIOC_WP_TDM_GET_HW_DTMF, /* 0x20 */
-
- SIOC_WP_TDM_NOTSUPP /* */
-
-};
-
-#define SIOC_WP_TDM_GET_LINK_STATUS SIOC_WP_TDM_GET_FE_STATUS
-
-enum wanpipe_tdm_api_events {
- WP_TDMAPI_EVENT_NONE,
- WP_TDMAPI_EVENT_RBS,
- WP_TDMAPI_EVENT_ALARM,
- WP_TDMAPI_EVENT_DTMF,
- WP_TDMAPI_EVENT_RM_DTMF,
- WP_TDMAPI_EVENT_RXHOOK,
- WP_TDMAPI_EVENT_RING,
- WP_TDMAPI_EVENT_RING_DETECT,
- WP_TDMAPI_EVENT_RING_TRIP_DETECT,
- WP_TDMAPI_EVENT_TONE,
- WP_TDMAPI_EVENT_TXSIG_KEWL,
- WP_TDMAPI_EVENT_TXSIG_START,
- WP_TDMAPI_EVENT_TXSIG_OFFHOOK,
- WP_TDMAPI_EVENT_TXSIG_ONHOOK,
- WP_TDMAPI_EVENT_ONHOOKTRANSFER,
- WP_TDMAPI_EVENT_SETPOLARITY,
- WP_TDMAPI_EVENT_BRI_CHAN_LOOPBACK,
- WP_TDMAPI_EVENT_LINK_STATUS
-};
-
-#define WP_TDMAPI_EVENT_FE_ALARM WP_TDMAPI_EVENT_ALARM
-
-
-#define WP_TDMAPI_EVENT_ENABLE 0x01
-#define WP_TDMAPI_EVENT_DISABLE 0x02
-#define WP_TDMAPI_EVENT_MODE_DECODE(mode) \
- ((mode) == WP_TDMAPI_EVENT_ENABLE) ? "Enable" : \
- ((mode) == WP_TDMAPI_EVENT_DISABLE) ? "Disable" : \
- "(Unknown mode)"
-
-#define WPTDM_A_BIT WAN_RBS_SIG_A
-#define WPTDM_B_BIT WAN_RBS_SIG_B
-#define WPTDM_C_BIT WAN_RBS_SIG_C
-#define WPTDM_D_BIT WAN_RBS_SIG_D
-
-#define WP_TDMAPI_EVENT_RXHOOK_OFF 0x01
-#define WP_TDMAPI_EVENT_RXHOOK_ON 0x02
-#define WP_TDMAPI_EVENT_RXHOOK_DECODE(state) \
- ((state) == WP_TDMAPI_EVENT_RXHOOK_OFF) ? "Off-hook" : \
- ((state) == WP_TDMAPI_EVENT_RXHOOK_ON) ? "On-hook" : \
- "(Unknown state)"
-
-#define WP_TDMAPI_EVENT_RING_PRESENT 0x01
-#define WP_TDMAPI_EVENT_RING_STOP 0x02
-#define WP_TDMAPI_EVENT_RING_DECODE(state) \
- ((state) == WP_TDMAPI_EVENT_RING_PRESENT) ? "Ring Present" : \
- ((state) == WP_TDMAPI_EVENT_RING_STOP) ? "Ring Stop" : \
- "(Unknown state)"
-
-#define WP_TDMAPI_EVENT_RING_TRIP_PRESENT 0x01
-#define WP_TDMAPI_EVENT_RING_TRIP_STOP 0x02
-#define WP_TDMAPI_EVENT_RING_TRIP_DECODE(state) \
- ((state) == WP_TDMAPI_EVENT_RING_TRIP_PRESENT) ? "Ring Present" : \
- ((state) == WP_TDMAPI_EVENT_RING_TRIP_STOP) ? "Ring Stop" : \
- "(Unknown state)"
-/*Link Status */
-#define WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED 0x01
-#define WP_TDMAPI_EVENT_LINK_STATUS_DISCONNECTED 0x02
-#define WP_TDMAPI_EVENT_LINK_STATUS_DECODE(status) \
- ((status) == WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED) ? "Connected" : \
- ((status) == WP_TDMAPI_EVENT_LINK_STATUS_DISCONNECTED) ? "Disconnected" : \
- "Unknown"
-#define WP_TDMAPI_EVENT_TONE_DIAL 0x01
-#define WP_TDMAPI_EVENT_TONE_BUSY 0x02
-#define WP_TDMAPI_EVENT_TONE_RING 0x03
-#define WP_TDMAPI_EVENT_TONE_CONGESTION 0x04
-
-/* BRI channels list */
-#define WAN_BRI_BCHAN1 0x01
-#define WAN_BRI_BCHAN2 0x02
-#define WAN_BRI_DCHAN 0x03
-
-
-typedef struct {
-
- u_int8_t type;
- u_int8_t mode;
- u_int32_t time_stamp;
- u_int8_t channel;
- u_int32_t chan_map;
- u_int8_t span;
- union {
- struct {
- u_int8_t alarm;
- } te1_alarm;
- struct {
- u_int8_t rbs_bits;
- } te1_rbs;
- struct {
- u_int8_t state;
- u_int8_t sig;
- } rm_hook;
- struct {
- u_int8_t state;
- } rm_ring;
- struct {
- u_int8_t type;
- } rm_tone;
- struct {
- u_int8_t digit; /* DTMF: digit */
- u_int8_t port; /* DTMF: SOUT/ROUT */
- u_int8_t type; /* DTMF: PRESET/STOP */
- } dtmf;
- struct {
- u_int16_t polarity;
- u_int16_t ohttimer;
- } rm_common;
- struct{
- u_int16_t status;
- } linkstatus;
- } wp_tdm_api_event_u;
-#define wp_tdm_api_event_type type
-#define wp_tdm_api_event_mode mode
-#define wp_tdm_api_event_alarm wp_tdm_api_event_u.te1_alarm.alarm
-#define wp_tdm_api_event_alarm wp_tdm_api_event_u.te1_alarm.alarm
-#define wp_tdm_api_event_rbs_bits wp_tdm_api_event_u.te1_rbs.rbs_bits
-#define wp_tdm_api_event_hook_state wp_tdm_api_event_u.rm_hook.state
-#define wp_tdm_api_event_hook_sig wp_tdm_api_event_u.rm_hook.sig
-#define wp_tdm_api_event_ring_state wp_tdm_api_event_u.rm_ring.state
-#define wp_tdm_api_event_tone_type wp_tdm_api_event_u.rm_tone.type
-#define wp_tdm_api_event_dtmf_digit wp_tdm_api_event_u.dtmf.digit
-#define wp_tdm_api_event_dtmf_type wp_tdm_api_event_u.dtmf.type
-#define wp_tdm_api_event_dtmf_port wp_tdm_api_event_u.dtmf.port
-#define wp_tdm_api_event_ohttimer wp_tdm_api_event_u.rm_common.ohttimer
-#define wp_tdm_api_event_polarity wp_tdm_api_event_u.rm_common.polarity
-#define wp_tdm_api_event_link_status wp_tdm_api_event_u.linkstatus.status
-} wp_tdm_api_event_t;
-
-typedef struct {
- union {
- unsigned char reserved[16];
- }wp_rx_hdr_u;
-} wp_tdm_api_rx_hdr_t;
-
-typedef struct {
- wp_tdm_api_rx_hdr_t hdr;
- unsigned char data[1];
-} wp_tdm_api_rx_element_t;
-
-typedef struct {
- union {
- struct {
- unsigned char _rbs_rx_bits;
- unsigned int _time_stamp;
- }wp_tx;
- unsigned char reserved[16];
- }wp_tx_hdr_u;
-#define wp_api_time_stamp wp_tx_hdr_u.wp_tx._time_stamp
-} wp_tdm_api_tx_hdr_t;
-
-typedef struct {
- wp_tdm_api_tx_hdr_t hdr;
- unsigned char data[1];
-} wp_tdm_api_tx_element_t;
-
-
-
-typedef struct wp_tdm_chan_stats
-{
- unsigned int rx_packets; /* total packets received */
- unsigned int tx_packets; /* total packets transmitted */
- unsigned int rx_bytes; /* total bytes received */
- unsigned int tx_bytes; /* total bytes transmitted */
- unsigned int rx_errors; /* bad packets received */
- unsigned int tx_errors; /* packet transmit problems */
- unsigned int rx_dropped; /* no space in linux buffers */
- unsigned int tx_dropped; /* no space available in linux */
- unsigned int multicast; /* multicast packets received */
-#if !defined(__WINDOWS__)
- unsigned int collisions;
-#endif
- /* detailed rx_errors: */
- unsigned int rx_length_errors;
- unsigned int rx_over_errors; /* receiver ring buff overflow */
- unsigned int rx_crc_errors; /* recved pkt with crc error */
- unsigned int rx_frame_errors; /* recv'd frame alignment error */
-#if !defined(__WINDOWS__)
- unsigned int rx_fifo_errors; /* recv'r fifo overrun */
-#endif
- unsigned int rx_missed_errors; /* receiver missed packet */
-
- /* detailed tx_errors */
-#if !defined(__WINDOWS__)
- unsigned int tx_aborted_errors;
- unsigned int tx_carrier_errors;
-#endif
- unsigned int tx_fifo_errors;
- unsigned int tx_heartbeat_errors;
- unsigned int tx_window_errors;
-
-}wp_tdm_chan_stats_t;
-
-
-
-typedef struct wanpipe_tdm_api_cmd{
- unsigned int cmd;
- unsigned int hw_tdm_coding; /* Set/Get HW TDM coding: uLaw muLaw */
- unsigned int hw_mtu_mru; /* Set/Get HW TDM MTU/MRU */
- unsigned int usr_period; /* Set/Get User Period in ms */
- unsigned int tdm_codec; /* Set/Get TDM Codec: SLinear */
- unsigned int power_level; /* Set/Get Power level treshold */
- unsigned int rx_disable; /* Enable/Disable Rx */
- unsigned int tx_disable; /* Enable/Disable Tx */
- unsigned int usr_mtu_mru; /* Set/Get User TDM MTU/MRU */
- unsigned int ec_tap; /* Echo Cancellation Tap */
- unsigned int rbs_poll; /* Enable/Disable RBS Polling */
- unsigned int rbs_rx_bits; /* Rx RBS Bits */
- unsigned int rbs_tx_bits; /* Tx RBS Bits */
- unsigned int hdlc; /* HDLC based device */
- unsigned int idle_flag; /* IDLE flag to Tx */
- unsigned int fe_alarms; /* FE Alarms detected */
- wp_tdm_chan_stats_t stats; /* TDM Statistics */
- /* Do NOT add anything above this! Important for binary backward compatibility. */
- wp_tdm_api_event_t event; /* TDM Event */
- unsigned int data_len;
- void *data;
- unsigned char fe_status; /* FE status - Connected or Disconnected */
- unsigned int hw_dtmf; /* HW DTMF enabled */
-}wanpipe_tdm_api_cmd_t;
-
-typedef struct wanpipe_tdm_api_event{
- int (*wp_rbs_event)(sng_fd_t fd, unsigned char rbs_bits);
- int (*wp_dtmf_event)(sng_fd_t fd, unsigned char dtmf, unsigned char type, unsigned char port);
- int (*wp_rxhook_event)(sng_fd_t fd, unsigned char hook_state);
- int (*wp_ring_detect_event)(sng_fd_t fd, unsigned char ring_state);
- int (*wp_ring_trip_detect_event)(sng_fd_t fd, unsigned char ring_state);
- int (*wp_fe_alarm_event)(sng_fd_t fd, unsigned char fe_alarm_event);
- int (*wp_link_status_event)(sng_fd_t fd, unsigned char link_status_event);
-}wanpipe_tdm_api_event_t;
-
-typedef struct wanpipe_tdm_api{
- wanpipe_tdm_api_cmd_t wp_tdm_cmd;
- wanpipe_tdm_api_event_t wp_tdm_event;
-}wanpipe_tdm_api_t;
-
-
-#endif
diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h
index eff6305913..5ae14abb31 100644
--- a/libs/freetdm/src/include/freetdm.h
+++ b/libs/freetdm/src/include/freetdm.h
@@ -41,6 +41,7 @@
#include "ftdm_declare.h"
+#include "ftdm_call_utils.h"
/*! \brief Max number of channels per physical span */
#define FTDM_MAX_CHANNELS_PHYSICAL_SPAN 32
@@ -62,23 +63,6 @@
#define FTDM_INVALID_INT_PARM 0xFF
-/*! \brief FreeTDM APIs possible return codes */
-typedef enum {
- FTDM_SUCCESS, /*!< Success */
- FTDM_FAIL, /*!< Failure, generic error return code, use ftdm_channel_get_last_error or ftdm_span_get_last_error for details */
- FTDM_MEMERR, /*!< Memory error, most likely allocation failure */
- 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 */
-} ftdm_status_t;
-
-/*! \brief FreeTDM bool type. */
-typedef enum {
- FTDM_FALSE,
- FTDM_TRUE
-} ftdm_bool_t;
-
/*! \brief Thread/Mutex OS abstraction API. */
#include "ftdm_os.h"
@@ -220,8 +204,10 @@ typedef enum {
FTDM_TON_SUBSCRIBER_NUMBER,
FTDM_TON_ABBREVIATED_NUMBER,
FTDM_TON_RESERVED,
- FTDM_TON_INVALID = 255
+ FTDM_TON_INVALID
} ftdm_ton_t;
+#define TON_STRINGS "unknown", "international", "national", "network-specific", "subscriber-number", "abbreviated-number", "reserved", "invalid"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_ton, ftdm_ton2str, ftdm_ton_t)
/*! Numbering Plan Identification (NPI) */
typedef enum {
@@ -232,8 +218,52 @@ typedef enum {
FTDM_NPI_NATIONAL = 8,
FTDM_NPI_PRIVATE = 9,
FTDM_NPI_RESERVED = 10,
- FTDM_NPI_INVALID = 255
+ FTDM_NPI_INVALID
} ftdm_npi_t;
+#define NPI_STRINGS "unknown", "ISDN", "data", "telex", "national", "private", "reserved", "invalid"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_npi, ftdm_npi2str, ftdm_npi_t)
+
+/*! Presentation Ind */
+typedef enum {
+ FTDM_PRES_ALLOWED,
+ FTDM_PRES_RESTRICTED,
+ FTDM_PRES_NOT_AVAILABLE,
+ FTDM_PRES_RESERVED,
+ FTDM_PRES_INVALID
+} ftdm_presentation_t;
+#define PRESENTATION_STRINGS "presentation-allowed", "presentation-restricted", "number-not-available", "reserved", "Invalid"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_presentation, ftdm_presentation2str, ftdm_presentation_t)
+
+/*! Screening Ind */
+typedef enum {
+ FTDM_SCREENING_NOT_SCREENED,
+ FTDM_SCREENING_VERIFIED_PASSED,
+ FTDM_SCREENING_VERIFIED_FAILED,
+ FTDM_SCREENING_NETWORK_PROVIDED,
+ FTDM_SCREENING_INVALID
+} ftdm_screening_t;
+#define SCREENING_STRINGS "user-provided-not-screened", "user-provided-verified-and-passed", "user-provided-verified-and-failed", "network-provided", "invalid"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_screening, ftdm_screening2str, ftdm_screening_t)
+
+/*! \brief bearer capability */
+typedef enum {
+ FTDM_BEARER_CAP_SPEECH = 0x00,
+ FTDM_BEARER_CAP_64K_UNRESTRICTED = 0x02,
+ FTDM_BEARER_CAP_3_1KHZ_AUDIO = 0x03,
+ FTDM_BEARER_CAP_INVALID
+} ftdm_bearer_cap_t;
+#define BEARER_CAP_STRINGS "speech", "unrestricted-digital-information", "3.1-Khz-audio", "invalid"
+FTDM_STR2ENUM_P(ftdm_str2ftdm_bearer_cap, ftdm_bearer_cap2str, ftdm_bearer_cap_t)
+
+/*! \brief user information layer 1 protocol */
+typedef enum {
+ FTDM_USER_LAYER1_PROT_V110 = 0x01,
+ FTDM_USER_LAYER1_PROT_ULAW = 0x02,
+ FTDM_USER_LAYER1_PROT_ALAW = 0x03,
+ FTDM_USER_LAYER1_PROT_INVALID
+} ftdm_user_layer1_prot_t;
+#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)
/*! \brief Number abstraction */
typedef struct {
@@ -242,20 +272,6 @@ typedef struct {
uint8_t plan;
} ftdm_number_t;
-/*! \brief bearer capability */
-typedef enum {
- FTDM_BEARER_CAP_SPEECH = 0x00,
- FTDM_BEARER_CAP_64K_UNRESTRICTED = 0x02,
- FTDM_BEARER_CAP_3_1KHZ_AUDIO = 0x03
-} ftdm_bearer_cap_t;
-
-/*! \brief user information layer 1 protocol */
-typedef enum {
- FTDM_USER_LAYER1_PROT_V110 = 0x01,
- FTDM_USER_LAYER1_PROT_ULAW = 0x02,
- FTDM_USER_LAYER1_PROT_ALAW = 0x03,
-} ftdm_user_layer1_prot_t;
-
/*! \brief Caller information */
typedef struct ftdm_caller_data {
char cid_date[8]; /*!< Caller ID date */
@@ -285,11 +301,12 @@ typedef enum {
/*! \brief Signaling messages sent by the stacks */
typedef enum {
- FTDM_SIGEVENT_START, /*!< Incoming call (ie: incoming SETUP msg or Ring) */
+ FTDM_SIGEVENT_START,/*!< Incoming call (ie: incoming SETUP msg or Ring) */
FTDM_SIGEVENT_STOP, /*!< Hangup */
FTDM_SIGEVENT_RELEASED, /*!< Channel is completely released and available */
FTDM_SIGEVENT_UP, /*!< Outgoing call has been answered */
- FTDM_SIGEVENT_FLASH, /*< Flash event (typically on-hook/off-hook for analog devices) */
+ FTDM_SIGEVENT_FLASH, /*!< Flash event (typically on-hook/off-hook for analog devices) */
+ FTDM_SIGEVENT_PROCEED, /*!< Outgoing call got a response */
FTDM_SIGEVENT_PROGRESS, /*!< Outgoing call is making progress */
FTDM_SIGEVENT_PROGRESS_MEDIA, /*!< Outgoing call is making progress and there is media available */
FTDM_SIGEVENT_ALARM_TRAP, /*!< Hardware alarm ON */
@@ -299,11 +316,12 @@ typedef enum {
FTDM_SIGEVENT_RESTART, /*!< Restart has been requested. Typically you hangup your call resources here */
FTDM_SIGEVENT_SIGSTATUS_CHANGED, /*!< Signaling protocol status changed (ie: D-chan up), see new status in raw_data ftdm_sigmsg_t member */
FTDM_SIGEVENT_COLLISION, /*!< Outgoing call was dropped because an incoming call arrived at the same time */
+ FTDM_SIGEVENT_MSG, /*!< We received an in-call msg */
FTDM_SIGEVENT_INVALID
} ftdm_signal_event_t;
-#define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROGRESS", \
+#define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROCEED", "PROGRESS", \
"PROGRESS_MEDIA", "ALARM_TRAP", "ALARM_CLEAR", \
- "COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "COLLISION", "INVALID"
+ "COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "COLLISION", "MSG", "INVALID"
/*! \brief Move from string to ftdm_signal_event_t and viceversa */
FTDM_STR2ENUM_P(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t)
@@ -585,7 +603,7 @@ typedef enum {
* This is used during incoming calls when you want to request the signaling stack
* to notify about indications occurring locally */
typedef enum {
- FTDM_CHANNEL_INDICATE_RING,
+ FTDM_CHANNEL_INDICATE_RINGING,
FTDM_CHANNEL_INDICATE_PROCEED,
FTDM_CHANNEL_INDICATE_PROGRESS,
FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA,
diff --git a/libs/freetdm/src/include/ftdm_call_utils.h b/libs/freetdm/src/include/ftdm_call_utils.h
new file mode 100644
index 0000000000..835a5c6cdc
--- /dev/null
+++ b/libs/freetdm/src/include/ftdm_call_utils.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2010, Sangoma Technologies
+ * David Yat Sin
+ * 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_CALL_UTILS_H__
+#define __FTDM_CALL_UTILS_H__
+
+/*!
+ * \brief Set the Numbering Plan Identification from a string
+ *
+ * \param npi_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_npi(const char *npi_string, uint8_t *target);
+
+
+/*!
+ * \brief Set the Type of number from a string
+ *
+ * \param ton_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_ton(const char *ton_string, uint8_t *target);
+
+/*!
+ * \brief Set the Bearer Capability from a string
+ *
+ * \param bc_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_bearer_capability(const char *bc_string, uint8_t *target);
+
+/*!
+ * \brief Set the Bearer Capability - Layer 1 from a string
+ *
+ * \param bc_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_bearer_layer1(const char *bc_string, uint8_t *target);
+
+/*!
+ * \brief Set the Screening Ind from a string
+ *
+ * \param screen_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_screening_ind(const char *string, uint8_t *target);
+
+
+/*!
+ * \brief Set the Presentation Ind from an enum
+ *
+ * \param screen_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_presentation_ind(const char *string, uint8_t *target);
+
+
+/*!
+ * \brief Checks whether a string contains only numbers
+ *
+ * \param number string value
+ *
+ * \retval FTDM_SUCCESS success
+ * \retval FTDM_FAIL failure
+ */
+FT_DECLARE(ftdm_status_t) ftdm_is_number(const char *number);
+
+#endif /* __FTDM_CALL_UTILS_H__ */
+
diff --git a/libs/freetdm/src/include/ftdm_declare.h b/libs/freetdm/src/include/ftdm_declare.h
index ab3b5c8966..4aba703f28 100644
--- a/libs/freetdm/src/include/ftdm_declare.h
+++ b/libs/freetdm/src/include/ftdm_declare.h
@@ -171,6 +171,23 @@ typedef int ftdm_socket_t;
#include
#endif
+/*! \brief FreeTDM APIs possible return codes */
+typedef enum {
+ FTDM_SUCCESS, /*!< Success */
+ FTDM_FAIL, /*!< Failure, generic error return code, use ftdm_channel_get_last_error or ftdm_span_get_last_error for details */
+ FTDM_MEMERR, /*!< Memory error, most likely allocation failure */
+ 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 */
+} ftdm_status_t;
+
+/*! \brief FreeTDM bool type. */
+typedef enum {
+ FTDM_FALSE,
+ FTDM_TRUE
+} ftdm_bool_t;
+
/*!
* \brief FreeTDM channel.
* This is the basic data structure used to place calls and I/O operations
diff --git a/libs/freetdm/src/include/private/ftdm_call_utils.h b/libs/freetdm/src/include/private/ftdm_call_utils.h
deleted file mode 100644
index 782abde927..0000000000
--- a/libs/freetdm/src/include/private/ftdm_call_utils.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2010, Sangoma Technologies
- * David Yat Sin
- * 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_CALL_UTILS_H__
-#define __FTDM_CALL_UTILS_H__
-
-#include "freetdm.h"
-
-FT_DECLARE(ftdm_status_t) ftdm_span_set_npi(const char *npi_string, uint8_t *target);
-FT_DECLARE(ftdm_status_t) ftdm_span_set_ton(const char *ton_string, uint8_t *target);
-FT_DECLARE(ftdm_status_t) ftdm_span_set_bearer_capability(const char *bc_string, ftdm_bearer_cap_t *target);
-FT_DECLARE(ftdm_status_t) ftdm_span_set_bearer_layer1(const char *bc_string, ftdm_user_layer1_prot_t *target);
-FT_DECLARE(ftdm_status_t) ftdm_is_number(char *number);
-
-#endif /* __FTDM_CALL_UTILS_H__ */
-
diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h
index d9cefc3c6f..f265cb1a3d 100644
--- a/libs/freetdm/src/include/private/ftdm_types.h
+++ b/libs/freetdm/src/include/private/ftdm_types.h
@@ -181,6 +181,8 @@ typedef enum {
* after having called ftdm_send_span_signal(), which with this flag it will just enqueue the signal
* for later delivery */
FTDM_SPAN_USE_SIGNALS_QUEUE = (1 << 10),
+ /* If this flag is set, channel will be moved to proceed state when calls goes to routing */
+ FTDM_SPAN_USE_PROCEED_STATE = (1 << 11),
} ftdm_span_flag_t;
/*! \brief Channel supported features */
@@ -204,6 +206,7 @@ typedef enum {
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,
@@ -211,6 +214,7 @@ typedef enum {
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,
@@ -223,8 +227,8 @@ typedef enum {
FTDM_CHANNEL_STATE_INVALID
} ftdm_channel_state_t;
#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
- "RING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
- "RESTART", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \
+ "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)
diff --git a/libs/freetdm/src/testanalog.c b/libs/freetdm/src/testanalog.c
index 84d09f73c9..326bb5aec5 100644
--- a/libs/freetdm/src/testanalog.c
+++ b/libs/freetdm/src/testanalog.c
@@ -50,7 +50,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_signal)
switch(sigmsg->event_id) {
case FTDM_SIGEVENT_START:
- ftdm_channel_call_indicate(sigmsg->channel, FTDM_CHANNEL_INDICATE_RING);
+ ftdm_channel_call_indicate(sigmsg->channel, FTDM_CHANNEL_INDICATE_RINGING);
ftdm_log(FTDM_LOG_DEBUG, "launching thread and indicating ring\n");
ftdm_thread_create_detached(test_call, sigmsg->channel);
break;
diff --git a/libs/freetdm/src/testsangomaboost.c b/libs/freetdm/src/testsangomaboost.c
index 38eac3c190..85b5332635 100644
--- a/libs/freetdm/src/testsangomaboost.c
+++ b/libs/freetdm/src/testsangomaboost.c
@@ -45,10 +45,14 @@
#include
-#include "freetdm.h"
#include
#include
#include
+#ifdef __linux__
+#define __USE_BSD
+#include
+#endif
+#include "freetdm.h"
/* arbitrary limit for max calls in this sample program */
@@ -338,9 +342,9 @@ int main(int argc, char *argv[])
exit(-1);
}
- if (!strcasecmp(argv[2], "cpe")) {
+ if (!strcmp(argv[2], "cpe")) {
sigtype = "pri_cpe";
- } else if (!strcasecmp(argv[2], "net")) {
+ } else if (!strcmp(argv[2], "net")) {
sigtype = "pri_net";
} else {
fprintf(stderr, "Valid signaling types are cpe and net only\n");
diff --git a/libs/libsndfile/M4/lt~obsolete.m4 b/libs/libsndfile/M4/lt~obsolete.m4
deleted file mode 100644
index c573da90c5..0000000000
--- a/libs/libsndfile/M4/lt~obsolete.m4
+++ /dev/null
@@ -1,98 +0,0 @@
-# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
-#
-# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
-# Written by Scott James Remnant, 2004.
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 5 lt~obsolete.m4
-
-# These exist entirely to fool aclocal when bootstrapping libtool.
-#
-# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
-# which have later been changed to m4_define as they aren't part of the
-# exported API, or moved to Autoconf or Automake where they belong.
-#
-# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
-# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
-# using a macro with the same name in our local m4/libtool.m4 it'll
-# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
-# and doesn't know about Autoconf macros at all.)
-#
-# So we provide this file, which has a silly filename so it's always
-# included after everything else. This provides aclocal with the
-# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
-# because those macros already exist, or will be overwritten later.
-# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
-#
-# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
-# Yes, that means every name once taken will need to remain here until
-# we give up compatibility with versions before 1.7, at which point
-# we need to keep only those names which we still refer to.
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
-
-m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
-m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
-m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
-m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
-m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
-m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
-m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
-m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
-m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
-m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
-m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
-m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
-m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
-m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
-m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
-m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
-m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
-m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
-m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
-m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
-m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
-m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
-m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
-m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
-m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
-m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
-m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
-m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
-m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
-m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
-m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
-m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
-m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
-m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
-m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
-m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
-m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
-m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
-m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
-m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
-m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
-m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
-m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
-m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
-m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
-m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
-m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
-m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
-m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
-m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
-m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
-m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
-m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
-m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
-m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
-m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
-m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj b/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj
index c6aaba5cd6..b3931497c7 100644
--- a/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj
+++ b/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj
@@ -127,6 +127,11 @@
+
+
+ {70a49bc2-7500-41d0-b75d-edcc5be987a0}
+
+
diff --git a/scripts/perl/add_user b/scripts/perl/add_user
new file mode 100755
index 0000000000..d16ebb5efe
--- /dev/null
+++ b/scripts/perl/add_user
@@ -0,0 +1,306 @@
+#!/usr/bin/perl
+#
+# add_user
+#
+# Add one or more users to the XML directory
+#
+#
+
+use strict;
+use warnings;
+use Getopt::Long;
+use Data::Dumper;
+
+## Useful items
+my $path_sep;
+my $config_path;
+my @dir_elem;
+my $user_template = &get_user_template;
+my $new_user_count = 0;
+
+## Command line args
+my $users;
+my $domain;
+my $dirpath;
+my $help;
+
+## Misc items somewhat related to cmd line args
+my $start;
+my $end;
+my $user;
+
+## Check for Windows vs. *nix
+if ( $^O =~ m/^win/i ) {
+ ## Detected Windows (probably)
+ $path_sep = "\\"; # single backslash (\)
+ use File::Spec::Win32;
+} else {
+ $path_sep = '/'; # single slash (/)
+ use File::Spec;
+}
+
+GetOptions(
+ 'h' => \$help,
+ 'help' => \$help,
+ 'domain=s' => \$domain,
+ 'users=s' => \$users,
+ 'confpath=s' => \$config_path,
+);
+
+if ( $help ) {
+ usage();
+ exit(0);
+}
+
+if ( ! $domain ) {
+ $domain='default';
+}
+
+## Validate users if specified on command line
+if ( $users ) {
+ ($start,$end) = split /-/,$users;
+ if ( ! $start && ! $end ) {
+ die "Please specify both a start and end range, separated by a hyphen:\n add_user --users=xxxx-yyyy\n";
+ }
+
+ unless ( $start =~ m/[1-9]\d+/ ) {
+ die "Start of range '$start' is not numeric or is too short\n";
+ }
+
+ unless ( $end =~ m/[1-9]\d+/ ) {
+ die "End of range '$end' is not numberic or is too short\n";
+ }
+
+ if ( $end <= $start ) {
+ die "End of range needs to be greater than start of range\n";
+ }
+} else {
+ ## Look for user id in $ARGV[0]
+ if ( ! $ARGV[0] ) {
+ die "You must specify user id as a command line argument to add user, or use the --users option.\n";
+ }
+ unless ( $ARGV[0] =~ m/^[1-9]\d+$/ ) {
+ die "User id must be numeric, be at least 2 digits long, and cannot begin with the digit zero.\n"
+ }
+ $user = $ARGV[0];
+}
+
+if ( ! $config_path ) {
+ $config_path = '/usr/local/freeswitch/conf';
+}
+
+## Check to make sure the directories in question exists
+unless ( -d $config_path ) {
+ die "Configuration path '$config_path' does not exist.\n";
+}
+
+my $directory_path = $config_path . $path_sep . 'directory';
+unless ( -d $directory_path ) {
+ die "Directory path '$directory_path' does not exist.\n";
+}
+
+## Now check domain pathname and test existence
+if ( ! $domain ) {
+ $domain = 'default';
+}
+
+## Full directory path includes the domain name
+my $full_dir_path = $directory_path . $path_sep . $domain;
+unless ( -d $full_dir_path ) {
+ die "Full path to directory and domain '$full_dir_path' does not exist. \n";
+}
+
+unless ( -w $full_dir_path ) {
+ die "This user does not have write access to '$full_dir_path'.\n";
+}
+print "\n";
+
+## Regexp assemble items to show user what a PCRE might look like for his new users
+my $ra_present;
+my $ra_new;
+my $ra_all;
+eval { require Regexp::Assemble; };
+if ( ! $@ ) {
+ ## If Regexp::Assemble is available flag it for later building regexes
+ $ra_present = 'true';
+ $ra_new = Regexp::Assemble->new( # new user regex
+ reduce => 1,
+ flags => 0,
+);
+ $ra_all = Regexp::Assemble->new( # all users regex w/ new users thrown in
+ reduce => 1,
+ flags => 0,
+);
+}
+
+## If we're this far then we can read in the existing users and put them in a hash
+## Later we can check hash to avoid adding duplicate users
+my %current_users;
+my @CURRENT_USER_FILES = glob($full_dir_path . $path_sep . '*.xml');
+foreach ( @CURRENT_USER_FILES ) {
+ #print "User: $_\n";
+ open(FILEIN,'<',$_);
+ while() {
+ next unless m/user id|number-alias/;
+ m/user id="(\d+)"/;
+ my $user_id = $1;
+ if ( ! $user_id ) {
+ m/alias="(\d+)"/;
+ $user_id = $1;
+ }
+
+ next unless $user_id;
+ $current_users{$user_id}++;
+
+ if ( $ra_present && $user_id =~ m/^\d+$/ ) {
+ #print "Adding $user_id to \$re_all...\n";
+ $ra_all->add($user_id)->anchor_line_begin->anchor_line_end;
+ }
+ last;
+ }
+ close(FILEIN);
+}
+
+#print Dumper(%current_users) . "\n";
+if ( $start && $end ) {
+ ## Add range of users
+ foreach $user ($start .. $end) {
+ &add_user($user);
+ }
+} else {
+ ## Add single user
+ &add_user($user);
+}
+
+print "\nOperation complete. ";
+if ( $new_user_count == 0 ) {
+ print "No users added.\n";
+ exit(0);
+} else {
+ printf "%d user%s added.\n", $new_user_count, $new_user_count==1 ? "" : "s";
+ print "Be sure to reloadxml.\n\n";
+}
+
+if ( $ra_present ) {
+ print "Regular expression information:\n\n";
+ ## Regexp::Assemble adds some stuff we really don't need
+ ## These lines just make the regexp pattern a bit more readable
+ my $tmp = $ra_new->as_string;
+ $tmp =~ s/\?://g;
+ $tmp =~ s/^\(\?\-xism:\^/^(/;
+ $tmp =~ s/\$\)$/)\$/;
+ $tmp =~ s/\\d/[0-9]/g; # [0-9] is sometimes easier to read than \d
+ print " Sample regex for all new users: " . $tmp . "\n";
+ $tmp = $ra_all->as_string;
+ $tmp =~ s/\?://g;
+ $tmp =~ s/^\(\?\-xism:\^/^(/;
+ $tmp =~ s/\$\)$/)\$/;
+ $tmp =~ s/\\d/[0-9]/g; # [0-9] is sometimes easier to read than \d
+ print "Sample regex for all new AND current users: " . $tmp . "\n\n";
+ print "In the default configuration you can modify the expression in the condition for 'Local_Extension'.\n";
+ print ""
+} else {
+ print "If CPAN module Regexp::Assemble were installed this program would be able to suggest a regex for your new users.\n"
+}
+
+exit(0);
+
+sub add_user {
+ my $user_id = shift;
+ if ( exists( $current_users{$user_id} ) ) {
+ warn "User id $user_id already exists, skipping...\n";
+ } else {
+ my $new_user = $user_template;
+ $new_user =~ s/__USERID__/$user_id/g;
+ #print "Adding user id '$user_id' with this XML:\n";
+ #print $new_user . "\n";
+
+ ## Attempt to create the user file
+ my $user_file_name = $full_dir_path . $path_sep . $user_id . '.xml';
+
+ ## Does it already exist?
+ if ( -f $user_file_name ) {
+ warn "$user_file_name exists, skipping...\n";
+ }
+ my $fh;
+ open($fh,'>',$user_file_name);
+ if ( ! $fh ) {
+ warn "Unable to open '$user_file_name' - $!\n";
+ warn "Skipping...\n";
+ next;
+ }
+
+ print $fh $new_user;
+ close($fh);
+ print "Added $user_id in file $user_file_name \n";
+ $new_user_count++;
+ if ( $ra_present ) {
+ $ra_new->add($user_id)->anchor_line_begin->anchor_line_end;
+ $ra_all->add($user_id)->anchor_line_begin->anchor_line_end;
+ }
+ }
+
+}
+
+sub get_user_template {
+ my $templ = <
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ENDUSERTEMPLATE
+
+ return $templ;
+}
+
+sub usage {
+ print < [--domain=] [--confpath=]
+ add_user --users=- [--domain=] [--confpath=]
+
+In its simplest form, add_user will simply add the user_id specified at the command line.
+By default, users are added to the "default" domain. Use the --domain option to specify
+a different domain for the user(s) that are added.
+
+To specify a range of user IDs use the --users option. Separate the beginning and
+end of the range with a hyphen (-) character.
+
+By default add_user will look for the XML directory in its default location of
+/usr/local/freeswitch/conf/directory. Use the --confpath (configuration path)
+option to specify an alternate directory location.
+
+
+ NOTES:
+
+add_user assumes
+User IDs must be numeric and cannot begin with zero.
+User IDs must be at least two digits long and have no specific length limit.
+If a user ID exists it will be skipped.
+If a domain specified does not exist no users will be created.
+
+ENDUSAGE
+
+}
diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h
index 3df9001b0c..13410a00ae 100644
--- a/src/include/private/switch_core_pvt.h
+++ b/src/include/private/switch_core_pvt.h
@@ -135,6 +135,7 @@ struct switch_core_session {
switch_mutex_t *frame_read_mutex;
switch_thread_rwlock_t *rwlock;
+ switch_thread_rwlock_t *io_rwlock;
void *streams[SWITCH_MAX_STREAMS];
int stream_count;
diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h
index a1f13edd85..d6bce5e8bf 100644
--- a/src/include/switch_channel.h
+++ b/src/include/switch_channel.h
@@ -179,8 +179,8 @@ SWITCH_DECLARE(void) switch_channel_uninit(switch_channel_t *channel);
SWITCH_DECLARE(void) switch_channel_set_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile);
/*!
- \brief Retrive the given channel's caller profile
- \param channel channel to retrive the profile from
+ \brief Retrieve the given channel's caller profile
+ \param channel channel to retrieve the profile from
\return the requested profile
*/
SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_caller_profile(switch_channel_t *channel);
@@ -195,8 +195,8 @@ SWITCH_DECLARE(void) switch_channel_set_originator_caller_profile(switch_channel
SWITCH_DECLARE(void) switch_channel_set_hunt_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile);
/*!
- \brief Retrive the given channel's originator caller profile
- \param channel channel to retrive the profile from
+ \brief Retrieve the given channel's originator caller profile
+ \param channel channel to retrieve the profile from
\return the requested profile
*/
SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_originator_caller_profile(switch_channel_t *channel);
@@ -209,8 +209,8 @@ SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_originator_caller_p
SWITCH_DECLARE(void) switch_channel_set_originatee_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile);
/*!
- \brief Retrive the given channel's originatee caller profile
- \param channel channel to retrive the profile from
+ \brief Retrieve the given channel's originatee caller profile
+ \param channel channel to retrieve the profile from
\return the requested profile
*/
SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_originatee_caller_profile(switch_channel_t *channel);
@@ -223,16 +223,16 @@ SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_originatee_caller_p
SWITCH_DECLARE(void) switch_channel_set_origination_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile);
/*!
- \brief Retrive the given channel's origination caller profile
- \param channel channel to retrive the profile from
+ \brief Retrieve the given channel's origination caller profile
+ \param channel channel to retrieve the profile from
\return the requested profile
*/
SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_origination_caller_profile(switch_channel_t *channel);
/*!
- \brief Retrive the given channel's unique id
- \param channel channel to retrive the unique id from
+ \brief Retrieve the given channel's unique id
+ \param channel channel to retrieve the unique id from
\return the unique id
*/
SWITCH_DECLARE(char *) switch_channel_get_uuid(switch_channel_t *channel);
@@ -241,7 +241,7 @@ SWITCH_DECLARE(char *) switch_channel_get_uuid(switch_channel_t *channel);
\brief Set a variable on a given channel
\param channel channel to set variable on
\param varname the name of the variable
- \param value the vaule of the variable
+ \param value the value of the variable
\returns SWITCH_STATUS_SUCCESS if successful
*/
diff --git a/src/include/switch_core.h b/src/include/switch_core.h
index 3f636d00c4..840a06c204 100644
--- a/src/include/switch_core.h
+++ b/src/include/switch_core.h
@@ -354,6 +354,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void);
///\ingroup core1
///\{
+
+SWITCH_DECLARE(switch_status_t) switch_core_session_io_read_lock(switch_core_session_t *session);
+SWITCH_DECLARE(switch_status_t) switch_core_session_io_write_lock(switch_core_session_t *session);
+SWITCH_DECLARE(switch_status_t) switch_core_session_io_rwunlock(switch_core_session_t *session);
+
#ifdef SWITCH_DEBUG_RWLOCKS
SWITCH_DECLARE(switch_status_t) switch_core_session_perform_read_lock(_In_ switch_core_session_t *session, const char *file, const char *func, int line);
#endif
@@ -882,6 +887,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(_In_ switch_core_sessio
SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_get_flags(_In_ switch_core_session_t *session,
_In_ const char *app, _In_opt_z_ const char *arg, _Out_opt_ int32_t *flags);
+SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_async(switch_core_session_t *session, const char *app, const char *arg);
+
SWITCH_DECLARE(switch_status_t) switch_core_session_get_app_flags(const char *app, int32_t *flags);
/*!
@@ -1024,6 +1031,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_queue_event(_In_ switch_core
*/
SWITCH_DECLARE(uint32_t) switch_core_session_event_count(_In_ switch_core_session_t *session);
+/*
+ Number of parsable messages waiting on the session.
+ */
+SWITCH_DECLARE(uint32_t) switch_core_session_messages_waiting(switch_core_session_t *session);
+
/*!
\brief DE-Queue an event on a given session
\param session the session to de-queue the message on
diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h
index 249ac63a58..d277bd030f 100644
--- a/src/include/switch_ivr.h
+++ b/src/include/switch_ivr.h
@@ -874,6 +874,11 @@ SWITCH_DECLARE(void) switch_ivr_dmachine_set_input_timeout_ms(switch_ivr_dmachin
SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_clear_realm(switch_ivr_dmachine_t *dmachine, const char *realm);
SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_set_realm(switch_ivr_dmachine_t *dmachine, const char *realm);
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_get_file_handle(switch_core_session_t *session, switch_file_handle_t **fh);
+SWITCH_DECLARE(switch_status_t) switch_ivr_release_file_handle(switch_core_session_t *session, switch_file_handle_t **fh);
+SWITCH_DECLARE(switch_status_t) switch_ivr_process_fh(switch_core_session_t *session, const char *cmd, switch_file_handle_t *fhp);
+
/** @} */
SWITCH_END_EXTERN_C
diff --git a/src/mod/.gitignore b/src/mod/.gitignore
index 47cdbafa70..b6e7842a50 100644
--- a/src/mod/.gitignore
+++ b/src/mod/.gitignore
@@ -7,6 +7,7 @@
/applications/mod_spandsp/mod_spandsp.log
/applications/mod_commands/Makefile
/applications/mod_conference/Makefile
+/applications/mod_db/Makefile
/applications/mod_dptools/Makefile
/applications/mod_enum/Makefile
/applications/mod_enum/Makefile.in
diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c
index 1b0ba1331a..ca92b17fa4 100644
--- a/src/mod/applications/mod_callcenter/mod_callcenter.c
+++ b/src/mod/applications/mod_callcenter/mod_callcenter.c
@@ -1346,6 +1346,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_time_t t_agent_called = 0;
switch_time_t t_agent_answered = 0;
switch_time_t t_member_called = atoi(h->member_joined_epoch);
+ switch_event_t *event = NULL;
switch_mutex_lock(globals.mutex);
globals.threads++;
@@ -1360,6 +1361,21 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_safe_free(sql);
goto done;
}
+
+ /* Proceed contact the agent to offer the member */
+ if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-offering");
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Type", h->agent_type);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", h->member_caller_name);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", h->member_caller_number);
+ switch_event_fire(&event);
+ }
+
+ /* CallBack Mode */
if (!strcasecmp(h->agent_type, CC_AGENT_TYPE_CALLBACK)) {
switch_event_create(&ovars, SWITCH_EVENT_REQUEST_PARAMS);
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_queue", "%s", h->queue_name);
@@ -1375,6 +1391,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_safe_free(dialstr);
switch_event_destroy(&ovars);
+ /* UUID Standby Mode */
} else if (!strcasecmp(h->agent_type, CC_AGENT_TYPE_UUID_STANDBY)) {
agent_session = switch_core_session_locate(h->agent_uuid);
if (agent_session) {
@@ -1400,14 +1417,17 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
cc_agent_update("status", cc_agent_status2str(CC_AGENT_STATUS_LOGGED_OUT), h->agent_name);
cc_agent_update("uuid", "", h->agent_name);
}
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Invalid agent type '%s' for agent '%s', aborting member offering", h->agent_type, h->agent_name);
+ status = SWITCH_CAUSE_USER_NOT_REGISTERED;
}
+ /* Originate/Bridge is not finished, processing the return value */
if (status == SWITCH_STATUS_SUCCESS) {
/* Agent Answered */
const char *agent_uuid = switch_core_session_get_uuid(agent_session);
switch_channel_t *member_channel = switch_core_session_get_channel(member_session);
switch_channel_t *agent_channel = switch_core_session_get_channel(agent_session);
- switch_event_t *event;
switch_channel_set_variable(agent_channel, "cc_member_pre_answer_uuid", NULL);
diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c
index ba4b6d310d..c7edfd5420 100644
--- a/src/mod/applications/mod_commands/mod_commands.c
+++ b/src/mod/applications/mod_commands/mod_commands.c
@@ -3968,6 +3968,47 @@ SWITCH_STANDARD_API(uuid_getvar_function)
return SWITCH_STATUS_SUCCESS;
}
+
+#define FILEMAN_SYNTAX " :"
+SWITCH_STANDARD_API(uuid_fileman_function)
+{
+ switch_core_session_t *psession = NULL;
+ char *mycmd = NULL, *argv[4] = { 0 };
+ int argc = 0;
+
+ if (!zstr(cmd) && (mycmd = strdup(cmd))) {
+ argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ if (argc >= 2 && !zstr(argv[0])) {
+ char *uuid = argv[0];
+ char *cmd = argv[1];
+
+ if ((psession = switch_core_session_locate(uuid))) {
+ switch_channel_t *channel;
+ switch_file_handle_t *fh = NULL;
+
+ channel = switch_core_session_get_channel(psession);
+
+ if (switch_ivr_get_file_handle(psession, &fh) == SWITCH_STATUS_SUCCESS) {
+ switch_ivr_process_fh(psession, cmd, fh);
+ switch_ivr_release_file_handle(psession, &fh);
+ }
+
+ switch_core_session_rwunlock(psession);
+
+ } else {
+ stream->write_function(stream, "-ERR No Such Channel!\n");
+ }
+ goto done;
+ }
+ }
+
+ stream->write_function(stream, "-USAGE: %s\n", GETVAR_SYNTAX);
+
+ done:
+ switch_safe_free(mycmd);
+ return SWITCH_STATUS_SUCCESS;
+}
+
#define UUID_SEND_DTMF_SYNTAX " "
SWITCH_STANDARD_API(uuid_send_dtmf_function)
{
@@ -4674,6 +4715,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
SWITCH_ADD_API(commands_api_interface, "uuid_display", "change display", uuid_display_function, DISPLAY_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_dump", "uuid_dump", uuid_dump_function, DUMP_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_exists", "see if a uuid exists", uuid_exists_function, EXISTS_SYNTAX);
+ SWITCH_ADD_API(commands_api_interface, "uuid_fileman", "uuid_fileman", uuid_fileman_function, FILEMAN_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_flush_dtmf", "Flush dtmf on a given uuid", uuid_flush_dtmf_function, "");
SWITCH_ADD_API(commands_api_interface, "uuid_getvar", "uuid_getvar", uuid_getvar_function, GETVAR_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_hold", "hold", uuid_hold_function, HOLD_SYNTAX);
@@ -4785,6 +4827,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
switch_console_set_complete("add uuid_display ::console::list_uuid");
switch_console_set_complete("add uuid_dump ::console::list_uuid");
switch_console_set_complete("add uuid_exists ::console::list_uuid");
+ switch_console_set_complete("add uuid_fileman ::console::list_uuid");
switch_console_set_complete("add uuid_flush_dtmf ::console::list_uuid");
switch_console_set_complete("add uuid_getvar ::console::list_uuid");
switch_console_set_complete("add uuid_hold ::console::list_uuid");
diff --git a/src/mod/applications/mod_hash/mod_hash.c b/src/mod/applications/mod_hash/mod_hash.c
index 29a056104f..2609b6cb87 100644
--- a/src/mod/applications/mod_hash/mod_hash.c
+++ b/src/mod/applications/mod_hash/mod_hash.c
@@ -130,7 +130,7 @@ SWITCH_LIMIT_INCR(limit_incr_hash)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
char *hashkey = NULL;
- switch_bool_t status = SWITCH_STATUS_SUCCESS;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
limit_hash_item_t *item = NULL;
time_t now = switch_epoch_time_now(NULL);
limit_hash_private_t *pvt = NULL;
diff --git a/src/mod/asr_tts/mod_cepstral/WinReadme.txt b/src/mod/asr_tts/mod_cepstral/WinReadme.txt
new file mode 100644
index 0000000000..56b4e79a39
--- /dev/null
+++ b/src/mod/asr_tts/mod_cepstral/WinReadme.txt
@@ -0,0 +1,4 @@
+The Cepstral SDK for Windows should be placed in c:\dev\cepstral
+ex. C:\dev\cepstral\sdk\include
+This SDK can be obtained from http://cepstral.com/
+If you want a prebuilt version you may download one from http://files.freeswitch.org/windows/installer/
\ No newline at end of file
diff --git a/src/mod/asr_tts/mod_cepstral/mod_cepstral.2010.vcxproj b/src/mod/asr_tts/mod_cepstral/mod_cepstral.2010.vcxproj
index 2bc46efdca..b7e42eb850 100644
--- a/src/mod/asr_tts/mod_cepstral/mod_cepstral.2010.vcxproj
+++ b/src/mod/asr_tts/mod_cepstral/mod_cepstral.2010.vcxproj
@@ -66,13 +66,13 @@
- C:\Program Files\Cepstral\sdk\include;%(AdditionalIncludeDirectories)
+ C:\dev\cepstral\sdk\include;%(AdditionalIncludeDirectories)
swift.lib;%(AdditionalDependencies)
- C:\Program Files\Cepstral\sdk\lib\winnt;C:\Program Files\Cepstral\sdk\lib\windows;%(AdditionalLibraryDirectories)
+ C:\dev\cepstral\sdk\lib\lib-windows;%(AdditionalLibraryDirectories)
false
@@ -83,13 +83,13 @@
X64
- C:\Program Files\Cepstral\sdk\include;%(AdditionalIncludeDirectories)
+ C:\dev\cepstral\sdk\include;%(AdditionalIncludeDirectories)
swift.lib;%(AdditionalDependencies)
- C:\Program Files\Cepstral\sdk\lib\winnt;C:\Program Files\Cepstral\sdk\lib\windows;%(AdditionalLibraryDirectories)
+ C:\dev\cepstral\sdk\lib\lib-windows_x64;%(AdditionalLibraryDirectories)
false
@@ -98,13 +98,13 @@
- C:\Program Files\Cepstral\sdk\include;%(AdditionalIncludeDirectories)
+ C:\dev\cepstral\sdk\include;%(AdditionalIncludeDirectories)
swift.lib;%(AdditionalDependencies)
- C:\Program Files\Cepstral\sdk\lib\winnt;C:\Program Files\Cepstral\sdk\lib\windows;%(AdditionalLibraryDirectories)
+ C:\dev\cepstral\sdk\lib\lib-windows;%(AdditionalLibraryDirectories)
false
@@ -115,13 +115,13 @@
X64
- C:\Program Files\Cepstral\sdk\include;%(AdditionalIncludeDirectories)
+ C:\dev\cepstral\sdk\include;%(AdditionalIncludeDirectories)
swift.lib;%(AdditionalDependencies)
- C:\Program Files\Cepstral\sdk\lib\winnt;C:\Program Files\Cepstral\sdk\lib\windows;%(AdditionalLibraryDirectories)
+ C:\dev\cepstral\sdk\lib\lib-windows_x64;%(AdditionalLibraryDirectories)
false
@@ -132,9 +132,8 @@
-
+
{202d7a4e-760d-4d0e-afa1-d7459ced30ff}
- false
diff --git a/src/mod/codecs/mod_celt/mod_celt.vcxproj b/src/mod/codecs/mod_celt/mod_celt.vcxproj
index 01c55d4217..ee8a70ca3f 100644
--- a/src/mod/codecs/mod_celt/mod_celt.vcxproj
+++ b/src/mod/codecs/mod_celt/mod_celt.vcxproj
@@ -62,10 +62,6 @@
<_ProjectFileVersion>10.0.30319.1
- $(Platform)\$(Configuration)\
- $(Platform)\$(Configuration)\
- $(Platform)\$(Configuration)\
- $(Platform)\$(Configuration)\
diff --git a/src/mod/endpoints/mod_dingaling/mod_dingaling.c b/src/mod/endpoints/mod_dingaling/mod_dingaling.c
index 7558e1b1b8..75329a0848 100644
--- a/src/mod/endpoints/mod_dingaling/mod_dingaling.c
+++ b/src/mod/endpoints/mod_dingaling/mod_dingaling.c
@@ -514,13 +514,19 @@ static switch_status_t chat_send(const char *proto, const char *from, const char
from = hint;
} else {
char *p;
- ffrom = switch_mprintf("%s+%s", proto, from);
- from = ffrom;
+
+ if (!(profile->user_flags & LDL_FLAG_COMPONENT)) {
+ from = ffrom = strdup(profile->login);
+ } else {
+ from = ffrom = switch_mprintf("%s+%s", proto, from);
+ }
+
if ((p = strchr(from, '/'))) {
*p = '\0';
}
}
ldl_handle_send_msg(profile->handle, (char *) from, (char *) to, NULL, switch_str_nil(body));
+ switch_safe_free(ffrom);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile %s\n", f_host ? f_host : "NULL");
return SWITCH_STATUS_FALSE;
@@ -602,7 +608,7 @@ static void ipchanged_event_handler(switch_event_t *event)
for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) {
switch_hash_this(hi, NULL, NULL, &val);
profile = (mdl_profile_t *) val;
- if (old_ip4 && !strcmp(profile->extip, old_ip4)) {
+ if (old_ip4 && profile->extip && !strcmp(profile->extip, old_ip4)) {
tmp = profile->extip;
profile->extip = strdup(new_ip4);
switch_safe_free(tmp);
diff --git a/src/mod/endpoints/mod_gsmopen/gsmopen.h b/src/mod/endpoints/mod_gsmopen/gsmopen.h
index fd94bccc2a..05ef1641bf 100644
--- a/src/mod/endpoints/mod_gsmopen/gsmopen.h
+++ b/src/mod/endpoints/mod_gsmopen/gsmopen.h
@@ -158,7 +158,7 @@ typedef enum {
#define WARNINGA(...) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "rev "GSMOPEN_SVN_VERSION "[%p|%-7lx][WARNINGA %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
#define NOTICA(...) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "rev "GSMOPEN_SVN_VERSION "[%p|%-7lx][NOTICA %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ );
-#define GSMOPEN_P_LOG NULL, (unsigned long)55, __LINE__, tech_pvt ? tech_pvt->name ? tech_pvt->name : "none" : "none", -1, tech_pvt ? tech_pvt->interface_state : -1, tech_pvt ? tech_pvt->phone_callflow : -1
+#define GSMOPEN_P_LOG (void *)NULL, (unsigned long)55, __LINE__, tech_pvt ? tech_pvt->name ? tech_pvt->name : "none" : "none", -1, tech_pvt ? tech_pvt->interface_state : -1, tech_pvt ? tech_pvt->phone_callflow : -1
/*********************************/
#define GSMOPEN_CAUSE_NORMAL 1
diff --git a/src/mod/endpoints/mod_gsmopen/gsmopen_protocol.cpp b/src/mod/endpoints/mod_gsmopen/gsmopen_protocol.cpp
index e4bb6b9200..76d32ac3f0 100644
--- a/src/mod/endpoints/mod_gsmopen/gsmopen_protocol.cpp
+++ b/src/mod/endpoints/mod_gsmopen/gsmopen_protocol.cpp
@@ -3294,12 +3294,18 @@ int alsa_write(private_t * tech_pvt, short *data, int datalen)
time_t now_timestamp;
/* size_t frames = 0; */
snd_pcm_state_t state;
- snd_pcm_sframes_t delayp1;
- snd_pcm_sframes_t delayp2;
+ snd_pcm_sframes_t delayp1=0;
+ snd_pcm_sframes_t delayp2=0;
if(tech_pvt->no_sound==1){
return res;
}
+
+
+ memset(sizbuf, 255, sizeof(sizbuf));
+ memset(sizbuf2, 255, sizeof(sizbuf));
+ memset(silencebuf, 255, sizeof(sizbuf));
+
//ERRORA("data=%p, datalen=%d\n", GSMOPEN_P_LOG, (void *)data, datalen);
/* We have to digest the frame in 160-byte portions */
if (datalen > sizeof(sizbuf) - sizpos) {
@@ -3307,8 +3313,11 @@ int alsa_write(private_t * tech_pvt, short *data, int datalen)
res = -1;
} else {
memcpy(sizbuf + sizpos, data, datalen);
+ memset(data, 255, datalen);
len += datalen;
pos = 0;
+
+
#ifdef ALSA_MONITOR
alsa_monitor_write(sizbuf, len);
#endif
@@ -3456,6 +3465,7 @@ int alsa_write(private_t * tech_pvt, short *data, int datalen)
if (res == -ESTRPIPE) {
ERRORA("You've got some big problems\n", GSMOPEN_P_LOG);
} else if (res == -EAGAIN) {
+ DEBUGA_GSMOPEN("Momentarily busy\n", GSMOPEN_P_LOG);
res = 0;
} else if (res < 0) {
ERRORA("Error %d on audio write: \"%s\"\n", GSMOPEN_P_LOG, res, snd_strerror(res));
@@ -3572,9 +3582,11 @@ int alsa_read(private_t * tech_pvt, short *data, int datalen)
return r;
} else if (r == -EAGAIN) {
- DEBUGA_GSMOPEN("ALSA read -EAGAIN, the soundcard is not ready to be read by gsmopen\n", GSMOPEN_P_LOG);
+ int count=0;
while (r == -EAGAIN) {
- gsmopen_sleep(1000);
+ gsmopen_sleep(10000);
+ DEBUGA_GSMOPEN("%d ALSA read -EAGAIN, the soundcard is not ready to be read by gsmopen\n", GSMOPEN_P_LOG, count);
+ count++;
if (tech_pvt->alsa_capture_is_mono) {
r = snd_pcm_readi(tech_pvt->alsac, buf + readpos, left);
diff --git a/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp b/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp
index cb440d3bcb..7e20b7c25e 100644
--- a/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp
+++ b/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp
@@ -1904,14 +1904,25 @@ static switch_status_t load_config(int reload_type)
if (globals.GSMOPEN_INTERFACES[interface_id].controldevprotocol != PROTOCOL_NO_SERIAL) {
res = gsmopen_serial_config(&globals.GSMOPEN_INTERFACES[interface_id]);
if (res) {
- ERRORA("gsmopen_serial_config failed\n", GSMOPEN_P_LOG);
- ERRORA("STARTING interface_id=%d FAILED\n", GSMOPEN_P_LOG, interface_id);
- //return SWITCH_STATUS_FALSE;
- globals.GSMOPEN_INTERFACES[interface_id].running=0;
- alarm_event(&globals.GSMOPEN_INTERFACES[interface_id], ALARM_FAILED_INTERFACE, "gsmopen_serial_config failed");
- globals.GSMOPEN_INTERFACES[interface_id].active=0;
- globals.GSMOPEN_INTERFACES[interface_id].name[0]='\0';
- continue;
+ int count = 0;
+ ERRORA("gsmopen_serial_config failed, let's try again\n", GSMOPEN_P_LOG);
+ while(res && count < 5){
+ switch_sleep(100000); //0.1 seconds
+ res = gsmopen_serial_config(&globals.GSMOPEN_INTERFACES[interface_id]);
+ count++;
+ if (res) {
+ ERRORA("%d: gsmopen_serial_config failed, let's try again\n", GSMOPEN_P_LOG, count);
+ }
+ }
+ if (res) {
+ ERRORA("STARTING interface_id=%d FAILED\n", GSMOPEN_P_LOG, interface_id);
+ //return SWITCH_STATUS_FALSE;
+ globals.GSMOPEN_INTERFACES[interface_id].running=0;
+ alarm_event(&globals.GSMOPEN_INTERFACES[interface_id], ALARM_FAILED_INTERFACE, "gsmopen_serial_config failed");
+ globals.GSMOPEN_INTERFACES[interface_id].active=0;
+ globals.GSMOPEN_INTERFACES[interface_id].name[0]='\0';
+ continue;
+ }
}
}
diff --git a/src/mod/endpoints/mod_skypopen/osscuse/98-osscuse.rules b/src/mod/endpoints/mod_skypopen/osscuse/98-osscuse.rules
new file mode 100644
index 0000000000..c1430fd5c0
--- /dev/null
+++ b/src/mod/endpoints/mod_skypopen/osscuse/98-osscuse.rules
@@ -0,0 +1,7 @@
+# Since these devices are not part of 'sound' subsystem the group is forced
+# to audio by name
+# /dev/cuse can stay mode 0660 root:root since osspd is run as root
+# and drops privileges to user level when opened by user
+KERNEL=="dsp", GROUP="audio"
+KERNEL=="mixer", GROUP="audio"
+KERNEL=="adsp", GROUP="audio"
diff --git a/src/mod/endpoints/mod_skypopen/osscuse/LICENSE b/src/mod/endpoints/mod_skypopen/osscuse/LICENSE
new file mode 100644
index 0000000000..d511905c16
--- /dev/null
+++ b/src/mod/endpoints/mod_skypopen/osscuse/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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 General Public License for more details.
+
+ 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/src/mod/endpoints/mod_skypopen/osscuse/Makefile b/src/mod/endpoints/mod_skypopen/osscuse/Makefile
new file mode 100644
index 0000000000..a42d37a8a3
--- /dev/null
+++ b/src/mod/endpoints/mod_skypopen/osscuse/Makefile
@@ -0,0 +1,69 @@
+# These can be overridden if needed
+# DESTDIR is completely respected
+CC := gcc
+AR := ar
+CFLAGS := -Wall $(CFLAGS)
+XLDFLAGS := $(LDFLAGS)
+LDFLAGS := -L. -lossp $(LDFLAGS)
+prefix := /usr/local
+DESTDIR :=
+UDEVDIR := /etc/udev/rules.d
+
+ifeq "$(origin OSSPD_CFLAGS)" "undefined"
+OSSPD_CFLAGS := $(shell pkg-config --cflags fuse)
+endif
+
+ifeq "$(origin OSSPD_LDFLAGS)" "undefined"
+OSSPD_LDFLAGS := $(shell pkg-config --libs fuse)
+endif
+
+ifeq "$(origin OSSP_PADSP_CFLAGS)" "undefined"
+OSSP_PADSP_CFLAGS := $(shell pkg-config --cflags libpulse)
+endif
+
+ifeq "$(origin OSSP_PADSP_LDFLAGS)" "undefined"
+OSSP_PADSP_LDFLAGS := $(shell pkg-config --libs libpulse)
+endif
+
+ifeq "$(origin OSSP_ALSAP_CFLAGS)" "undefined"
+OSSP_ALSAP_CFLAGS := $(shell pkg-config --libs alsa)
+endif
+
+ifeq "$(origin OSSP_ALSAP_LDFLAGS)" "undefined"
+OSSP_ALSAP_LDFLAGS := $(shell pkg-config --libs alsa)
+endif
+
+headers := ossp.h ossp-util.h ossp-slave.h
+
+#all: osspd ossp-padsp ossp-alsap
+all: osspd ossp-alsap
+
+install:
+ mkdir -p $(DESTDIR)$(prefix)/sbin
+ install -m755 osspd ossp-padsp ossp-alsap $(DESTDIR)$(prefix)/sbin
+ mkdir -p $(DESTDIR)$(UDEVDIR)
+ install -m644 98-osscuse.rules $(DESTDIR)$(UDEVDIR)
+
+libossp.a: ossp.c ossp.h ossp-util.c ossp-util.h ossp-slave.c ossp-slave.h
+ $(CC) $(CFLAGS) -c -o ossp.o ossp.c
+ $(CC) $(CFLAGS) -c -o ossp-util.o ossp-util.c
+ $(CC) $(CFLAGS) -c -o ossp-slave.o ossp-slave.c
+ $(AR) rc $@ ossp.o ossp-util.o ossp-slave.o
+
+osspd: osspd.c libossp.a $(headers)
+ $(CC) $(CFLAGS) $(OSSPD_CFLAGS) -o $@ $< $(OSSPD_LDFLAGS) $(LDFLAGS)
+
+ossp-padsp: ossp-padsp.c libossp.a $(headers)
+ $(CC) $(CFLAGS) $(OSSP_PADSP_CFLAGS) -o $@ $< $(OSSP_PADSP_LDFLAGS) $(LDFLAGS)
+
+ossp-alsap: ossp-alsap.c libossp.a $(headers)
+ $(CC) $(CFLAGS) $(OSSP_ALSAP_CFLAGS) -o $@ $< $(OSSP_ALSAP_LDFLAGS) $(LDFLAGS)
+
+osstest: osstest.c
+ $(CC) $(CFLAGS) -o $@ $< $(XLDFLAGS)
+
+test: osstest
+ @./osstest
+
+clean:
+ rm -f *.o *.a osspd ossp-padsp ossp-alsap osstest
diff --git a/src/mod/endpoints/mod_skypopen/osscuse/README b/src/mod/endpoints/mod_skypopen/osscuse/README
new file mode 100644
index 0000000000..6b716c76e4
--- /dev/null
+++ b/src/mod/endpoints/mod_skypopen/osscuse/README
@@ -0,0 +1,119 @@
+
+ OSS Proxy - emulate OSS device using CUSE
+
+ Copyright (C) 2008-2009 SUSE Linux Products GmbH
+ Copyright (C) 2008-2009 Tejun Heo
+
+1. What is it?
+--------------
+
+Well, first, OSS refers to Open Sound System. If it still doesn't
+ring a bell, think /dev/dsp, /dev/adsp and /dev/mixer.
+
+Currently, Linux supports two audio programming interface - ALSA and
+OSS. The latter one is deprecated and has been that way for a long
+time but there still are applications which still use them including
+UML (usermode Linux) host sound support.
+
+ALSA contains OSS emulation but sadly the emulation is behind
+multiplexing layer (which is in userland) which means that if your
+sound card doesn't support multiple audio streams, only either one of
+ALSA or OSS interface would be usable at any given moment.
+
+There have been also attempts to emulate OSS in userland using dynamic
+library preloading - aoss and more recently padsp. This works for
+many applications but it's just not easy to emulate everything using
+the technique. Things like polling, signals, forking, privilege
+changes make it very difficult to emulate things reliably.
+
+OSS Proxy uses CUSE (extension of FUSE allowing character devices to
+be implemented in userspace) to implement OSS interface - /dev/dsp,
+/dev/adsp and /dev/mixer. From the POV of the applications, these
+devices are proper character devices and behave exactly the same way
+so it can be made quite versatile.
+
+
+2. Hmmm... So, how does the whole thing work?
+---------------------------------------------
+
+The OSS Proxy daemon - osspd - should be started first. Note that
+osspd will fail to start if sound device number regions are already
+occupied. You'll need to turn off OSS or its emulation[1].
+
+On startup, osspd creates /dev/dsp, /dev/adsp and /dev/mixer using
+CUSE. When an application access one of the devices, all IOs are
+redirected to osspd via CUSE. Upon receiving a new DSP open request,
+osspd creates a slave process which drops the root privilege and
+assumes the opening process's credentials. After handshaking, osspd
+forwards all relevant IOs to the slave which is responsible for
+actually playing the sound.
+
+Currently there's only one slave implemented - ossp-padsp, which as
+the name suggests forwards (again) the sound to pulseaudio. To sum
+up, the whole pipe looks like the following.
+
+ App <-> /dev/dsp <-> CUSE <-> osspd <-> ossp-padsp <-> pulseaudio
+
+Which is a lot of forwarding, but on modern machines, it won't be too
+noticeable.
+
+
+3. What works?
+--------------
+
+Well, MIDI part isn't implemented and I doubt it will be in any near
+future but except that everything should work. Playing, recording,
+5.1ch, A-V syncing, all should work. If not, it's a bug, so please
+report.
+
+The mixer behaves a bit differently tho. In the original OSS,
+/dev/mixer is the hardware mixer, so adjusting volumes there affects
+all audio streams. When using ossp, each process group gets its own
+mixer and the mixer always contains only two knobs - PCM and IGAIN.
+Combined with per-stream volume control of pulseaudio, this scheme
+works quite well for applications with embedded volume control
+although it makes standalone OSS mixer programs virtually useless[2].
+
+
+4. How do I use it?
+-------------------
+
+First you need CUSE support in kernel which might land on 2.6.28 with
+sufficient luck[3] and then you also need libfuse which supports
+CUSE[4]. Once you have both, it should be easy. First build it by
+running `make'. You can set OSSPD_CFLAGS, OSSPD_LDFLAGS,
+OSSP_PADSP_CFLAGS and OSSP_PADSP_LDFLAGS if you have stuff at
+non-default locations.
+
+After build completes, there will be two executables - `osspd' and
+`ossp-padsp'. Just copy them to where other system executables live.
+Specific location doesn't matter as long as both files end up in the
+same directory.
+
+Execute `osspd'. It will create the device files and you're all set.
+`osspd' uses syslog with LOG_DAEMON facility, so if something doesn't
+work take a look at what osspd complains about.
+
+
+[1] As of this writing, turning on any sound support makes the
+ soundcore module claim OSS device regions. Patch to make it claim
+ OSS device regions only when OSS support or emulation is enabled
+ is scheduled for 2.6.28. Even with the patch, soundcore will
+ claim OSS device regions if OSS support or ALSA OSS emulation is
+ enabled. Make sure they're turned off.
+
+[2] If you have a strong reason to use standalone OSS mixer program,
+ you can play some shell tricks to put it into the same process
+ group as the target audio application. e.g. To use aumix with
+ mpg123 - `(mpg123 asdf.mp3 > /dev/null 2>&1 & aumix)', but
+ seriously, just use PA or ALSA one.
+
+[3] For the time being, here's the git tree with all the necessary
+ changes. This tree is base on top of 2.6.27-rc3.
+
+ http://git.kernel.org/?p=linux/kernel/git/tj/misc.git;a=shortlog;h=cuse
+ git://git.kernel.org/pub/scm/linux/kernel/git/tj/misc.git cuse
+
+[4] And libfuse with the modifications can be found at...
+
+ http://userweb.kernel.org/~tj/ossp/fuse-cuse.tar.gz
diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-alsap.c b/src/mod/endpoints/mod_skypopen/osscuse/ossp-alsap.c
new file mode 100644
index 0000000000..607e05ca84
--- /dev/null
+++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp-alsap.c
@@ -0,0 +1,613 @@
+/*
+ * ossp-alsap - ossp DSP slave which forwards to alsa
+ *
+ * Copyright (C) 2009 Maarten Lankhorst
+ *
+ * This file is released under the GPLv2.
+ *
+ * Why an alsa plugin as well? Just to show how much
+ * the alsa userspace api sucks ;-)
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "ossp-slave.h"
+
+enum {
+ AFMT_FLOAT = 0x00004000,
+ AFMT_S32_LE = 0x00001000,
+ AFMT_S32_BE = 0x00002000,
+};
+
+static size_t page_size;
+
+/* alsa structures */
+static snd_pcm_t *pcm[2];
+static snd_pcm_hw_params_t *hw_params;
+static snd_pcm_sw_params_t *sw_params;
+static int block;
+
+static unsigned int byte_counter[2];
+static snd_pcm_uframes_t mmap_pos[2];
+static int stream_corked[2];
+static int stream_notify;
+
+static struct format {
+ snd_pcm_format_t format;
+ snd_pcm_sframes_t rate;
+ int channels;
+} hw_format = { SND_PCM_FORMAT_U8, 8000, 1 };
+
+#if 0
+/* future mmap stuff */
+static size_t mmap_raw_size, mmap_size;
+static int mmap_fd[2] = { -1, -1 };
+static void *mmap_map[2];
+static uint64_t mmap_idx[2]; /* mmap pointer */
+static uint64_t mmap_last_idx[2]; /* last idx for get_ptr */
+static struct ring_buf mmap_stg[2]; /* staging ring buffer */
+static size_t mmap_lead[2]; /* lead bytes */
+static int mmap_sync[2]; /* sync with backend stream */
+#endif
+
+static snd_pcm_format_t fmt_oss_to_alsa(int fmt)
+{
+ switch (fmt) {
+ case AFMT_U8: return SND_PCM_FORMAT_U8;
+ case AFMT_A_LAW: return SND_PCM_FORMAT_A_LAW;
+ case AFMT_MU_LAW: return SND_PCM_FORMAT_MU_LAW;
+ case AFMT_S16_LE: return SND_PCM_FORMAT_S16_LE;
+ case AFMT_S16_BE: return SND_PCM_FORMAT_S16_BE;
+ case AFMT_FLOAT: return SND_PCM_FORMAT_FLOAT;
+ case AFMT_S32_LE: return SND_PCM_FORMAT_S32_LE;
+ case AFMT_S32_BE: return SND_PCM_FORMAT_S32_BE;
+ default: return SND_PCM_FORMAT_U8;
+ }
+}
+
+static int fmt_alsa_to_oss(snd_pcm_format_t fmt)
+{
+ switch (fmt) {
+ case SND_PCM_FORMAT_U8: return AFMT_U8;
+ case SND_PCM_FORMAT_A_LAW: return AFMT_A_LAW;
+ case SND_PCM_FORMAT_MU_LAW: return AFMT_MU_LAW;
+ case SND_PCM_FORMAT_S16_LE: return AFMT_S16_LE;
+ case SND_PCM_FORMAT_S16_BE: return AFMT_S16_BE;
+ case SND_PCM_FORMAT_FLOAT: return AFMT_FLOAT;
+ case SND_PCM_FORMAT_S32_LE: return AFMT_S32_LE;
+ case SND_PCM_FORMAT_S32_BE: return AFMT_S32_BE;
+ default: return AFMT_U8;
+ }
+}
+
+static void flush_streams(int drain)
+{
+ /* FIXME: snd_pcm_drain appears to be able to deadlock,
+ * always drop or check state? */
+ if (drain) {
+ if (pcm[PLAY])
+ snd_pcm_drain(pcm[PLAY]);
+ if (pcm[REC])
+ snd_pcm_drain(pcm[REC]);
+ } else {
+ if (pcm[PLAY])
+ snd_pcm_drop(pcm[PLAY]);
+ if (pcm[REC])
+ snd_pcm_drop(pcm[REC]);
+ }
+
+ /* XXX: Really needed? */
+#if 0
+ if (pcm[PLAY]) {
+ snd_pcm_close(pcm[PLAY]);
+ snd_pcm_open(&pcm[PLAY], "default",
+ SND_PCM_STREAM_PLAYBACK, block);
+ }
+ if (pcm[REC]) {
+ snd_pcm_close(pcm[REC]);
+ snd_pcm_open(&pcm[REC], "default",
+ SND_PCM_STREAM_CAPTURE, block);
+ }
+#endif
+}
+
+static void kill_streams(void)
+{
+ flush_streams(0);
+}
+
+static int trigger_streams(int play, int rec)
+{
+ int ret = 0;
+
+ if (pcm[PLAY] && play >= 0) {
+ ret = snd_pcm_sw_params_set_start_threshold(pcm[PLAY], sw_params,
+ play ? 1 : -1);
+ if (ret >= 0)
+ snd_pcm_sw_params(pcm[PLAY], sw_params);
+ }
+ if (ret >= 0 && pcm[REC] && rec >= 0) {
+ ret = snd_pcm_sw_params_set_start_threshold(pcm[REC], sw_params,
+ rec ? 1 : -1);
+ if (ret >= 0)
+ snd_pcm_sw_params(pcm[REC], sw_params);
+ }
+
+ return ret;
+}
+
+static ssize_t alsap_mixer(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp, int tfd)
+{
+return -EBUSY;
+}
+
+static int set_hw_params(snd_pcm_t *pcm)
+{
+ int ret;
+ unsigned rate;
+
+ ret = snd_pcm_hw_params_any(pcm, hw_params);
+ if (ret >= 0)
+ ret = snd_pcm_hw_params_set_access(pcm, hw_params,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ rate = hw_format.rate;
+ if (ret >= 0)
+ ret = snd_pcm_hw_params_set_rate_minmax(pcm, hw_params,
+ &rate, NULL,
+ &rate, NULL);
+ if (ret >= 0)
+ ret = snd_pcm_hw_params_set_format(pcm, hw_params, hw_format.format);
+ if (ret >= 0)
+ ret = snd_pcm_hw_params_set_channels(pcm, hw_params,
+ hw_format.channels);
+ if (ret >= 0)
+ ret = snd_pcm_hw_params(pcm, hw_params);
+ if (ret >= 0)
+ ret = snd_pcm_sw_params_current(pcm, sw_params);
+ if (ret >= 0)
+ ret = snd_pcm_sw_params(pcm, sw_params);
+ return ret;
+}
+
+static ssize_t alsap_open(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp, int tfd)
+{
+ struct ossp_dsp_open_arg *arg = carg;
+ int ret;
+ block = arg->flags & O_NONBLOCK ? SND_PCM_NONBLOCK : 0;
+ int access;
+// block |= SND_PCM_ASYNC;
+ /* Woop dee dooo.. I love handling things in SIGIO (PAIN!!)
+ * Probably needed for MMAP
+ */
+
+ if (!hw_params)
+ ret = snd_pcm_hw_params_malloc(&hw_params);
+ if (ret < 0)
+ return ret;
+
+ if (!sw_params)
+ ret = snd_pcm_sw_params_malloc(&sw_params);
+ if (ret < 0)
+ return ret;
+
+ if (pcm[PLAY])
+ snd_pcm_close(pcm[PLAY]);
+ if (pcm[REC])
+ snd_pcm_close(pcm[REC]);
+ pcm[REC] = pcm[PLAY] = NULL;
+
+ access = arg->flags & O_ACCMODE;
+ if (access == O_WRONLY || access == O_RDWR) {
+ ret = snd_pcm_open(&pcm[PLAY], "default",
+ SND_PCM_STREAM_PLAYBACK, block);
+ if (ret >= 0)
+ ret = set_hw_params(pcm[PLAY]);
+ }
+
+ if (ret >= 0 && (access == O_RDONLY || access == O_RDWR)) {
+ ret = snd_pcm_open(&pcm[REC], "default",
+ SND_PCM_STREAM_CAPTURE, block);
+ if (ret >= 0)
+ ret = set_hw_params(pcm[REC]);
+ }
+
+ if (ret < 0) {
+ if (pcm[PLAY])
+ snd_pcm_close(pcm[PLAY]);
+ if (pcm[REC])
+ snd_pcm_close(pcm[REC]);
+ pcm[REC] = pcm[PLAY] = NULL;
+ return ret;
+ }
+ return 0;
+}
+
+#define GIOVANNI
+#ifdef GIOVANNI
+
+#define GIOVA_SLEEP 40000
+#define GIOVA_BLK 3840
+static ssize_t alsap_write(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp, int tfd)
+{
+ usleep((GIOVA_SLEEP/GIOVA_BLK)* din_sz);
+ return din_sz;
+}
+static ssize_t alsap_read(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp, int tfd)
+{
+ usleep((GIOVA_SLEEP/GIOVA_BLK)* *dout_szp);
+ return *dout_szp;
+}
+#else// GIOVANNI
+static ssize_t alsap_write(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp, int tfd)
+{
+// struct ossp_dsp_rw_arg *arg = carg;
+ int ret, insize;
+
+ insize = snd_pcm_bytes_to_frames(pcm[PLAY], din_sz);
+
+ if (snd_pcm_state(pcm[PLAY]) == SND_PCM_STATE_SETUP)
+ snd_pcm_prepare(pcm[PLAY]);
+
+// snd_pcm_start(pcm[PLAY]);
+ ret = snd_pcm_writei(pcm[PLAY], din, insize);
+ if (ret < 0)
+ ret = snd_pcm_recover(pcm[PLAY], ret, 1);
+
+ if (ret >= 0)
+ return snd_pcm_frames_to_bytes(pcm[PLAY], ret);
+ else
+ return ret;
+}
+
+static ssize_t alsap_read(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp, int tfd)
+{
+// struct ossp_dsp_rw_arg *arg = carg;
+ int ret, outsize;
+
+ outsize = snd_pcm_bytes_to_frames(pcm[REC], *dout_szp);
+
+ if (snd_pcm_state(pcm[REC]) == SND_PCM_STATE_SETUP)
+ snd_pcm_prepare(pcm[REC]);
+
+ ret = snd_pcm_readi(pcm[REC], dout, outsize);
+ if (ret < 0)
+ ret = snd_pcm_recover(pcm[REC], ret, 1);
+ if (ret >= 0)
+ *dout_szp = ret = snd_pcm_frames_to_bytes(pcm[REC], ret);
+ else
+ *dout_szp = 0;
+
+ return ret;
+}
+#endif// GIOVANNI
+
+static ssize_t alsap_poll(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp, int tfd)
+{
+ unsigned revents = 0;
+
+ stream_notify |= *(int *)carg;
+
+ if (pcm[PLAY])
+ revents |= POLLOUT;
+ if (pcm[REC])
+ revents |= POLLIN;
+
+ *(unsigned *)rarg = revents;
+ return 0;
+}
+
+
+static ssize_t alsap_flush(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp, int tfd)
+{
+ flush_streams(opcode == OSSP_DSP_SYNC);
+ return 0;
+}
+
+static ssize_t alsap_post(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp, int tfd)
+{
+ int ret;
+
+ ret = trigger_streams(1, 1);
+ if (ret >= 0 && pcm[PLAY])
+ ret = snd_pcm_start(pcm[PLAY]);
+ if (pcm[REC])
+ ret = snd_pcm_start(pcm[REC]);
+ return ret;
+}
+
+static ssize_t alsap_get_param(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp,
+ int tfd)
+{
+ int v = 0;
+
+ switch (opcode) {
+ case OSSP_DSP_GET_RATE:
+ return hw_format.rate;
+
+ case OSSP_DSP_GET_CHANNELS:
+ return hw_format.channels;
+
+ case OSSP_DSP_GET_FORMAT: {
+ v = fmt_alsa_to_oss(hw_format.format);
+ break;
+ }
+
+ case OSSP_DSP_GET_BLKSIZE: {
+ snd_pcm_uframes_t psize;
+ snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL);
+ v = psize;
+ break;
+ }
+
+ case OSSP_DSP_GET_FORMATS:
+ v = AFMT_U8 | AFMT_A_LAW | AFMT_MU_LAW | AFMT_S16_LE |
+ AFMT_S16_BE | AFMT_FLOAT | AFMT_S32_LE | AFMT_S32_BE;
+ break;
+
+ case OSSP_DSP_GET_TRIGGER:
+ if (!stream_corked[PLAY])
+ v |= PCM_ENABLE_OUTPUT;
+ if (!stream_corked[REC])
+ v |= PCM_ENABLE_INPUT;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ *(int *)rarg = v;
+
+ return 0;
+}
+
+static ssize_t alsap_set_param(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp,
+ int tfd)
+{
+ int v = *(int *)carg;
+ int ret = 0;
+
+ /* kill the streams before changing parameters */
+ kill_streams();
+
+ switch (opcode) {
+ case OSSP_DSP_SET_RATE: {
+ hw_format.rate = v;
+ break;
+ }
+
+ case OSSP_DSP_SET_CHANNELS: {
+ hw_format.channels = v;
+ break;
+ }
+
+ case OSSP_DSP_SET_FORMAT: {
+ snd_pcm_format_t format = fmt_oss_to_alsa(v);
+ hw_format.format = format;
+ break;
+ }
+
+ case OSSP_DSP_SET_SUBDIVISION:
+ if (!v)
+ v = 1;
+#if 0
+ if (!v) {
+ v = user_subdivision ?: 1;
+ break;
+ }
+ user_frag_size = 0;
+ user_subdivision = v;
+ break;
+
+ case OSSP_DSP_SET_FRAGMENT:
+ user_subdivision = 0;
+ user_frag_size = 1 << (v & 0xffff);
+ user_max_frags = (v >> 16) & 0xffff;
+ if (user_frag_size < 4)
+ user_frag_size = 4;
+ if (user_max_frags < 2)
+ user_max_frags = 2;
+#else
+ case OSSP_DSP_SET_FRAGMENT:
+#endif
+ break;
+ default:
+ assert(0);
+ }
+
+ if (pcm[PLAY])
+ ret = set_hw_params(pcm[PLAY]);
+ if (ret >= 0 && pcm[REC])
+ ret = set_hw_params(pcm[REC]);
+
+ if (rarg)
+ *(int *)rarg = v;
+ return 0;
+}
+
+static ssize_t alsap_set_trigger(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp,
+ int fd)
+{
+ int enable = *(int *)carg;
+
+ stream_corked[PLAY] = !!(enable & PCM_ENABLE_OUTPUT);
+ stream_corked[REC] = !!(enable & PCM_ENABLE_INPUT);
+
+ return trigger_streams(enable & PCM_ENABLE_OUTPUT,
+ enable & PCM_ENABLE_INPUT);
+}
+
+static ssize_t alsap_get_space(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp, int tfd)
+{
+ int dir = (opcode == OSSP_DSP_GET_OSPACE) ? PLAY : REC;
+ int underrun = 0;
+ struct audio_buf_info info = { };
+ unsigned long bufsize;
+ snd_pcm_uframes_t avail, fragsize;
+ snd_pcm_state_t state;
+
+ if (!pcm[dir])
+ return -EINVAL;
+
+ state = snd_pcm_state(pcm[dir]);
+ if (state == SND_PCM_STATE_XRUN) {
+ snd_pcm_recover(pcm[dir], -EPIPE, 0);
+ underrun = 1;
+ } else if (state == SND_PCM_STATE_SUSPENDED) {
+ snd_pcm_recover(pcm[dir], -ESTRPIPE, 0);
+ underrun = 1;
+ }
+
+ snd_pcm_hw_params_current(pcm[dir], hw_params);
+ snd_pcm_hw_params_get_period_size(hw_params, &fragsize, NULL);
+ snd_pcm_hw_params_get_buffer_size(hw_params, &bufsize);
+ info.fragsize = snd_pcm_frames_to_bytes(pcm[dir], fragsize);
+ info.fragstotal = bufsize / fragsize;
+ if (!underrun) {
+ avail = snd_pcm_avail_update(pcm[dir]);
+ info.fragments = avail / fragsize;
+ } else
+ info.fragments = info.fragstotal;
+
+ info.bytes = info.fragsize * info.fragments;
+
+ *(struct audio_buf_info *)rarg = info;
+ return 0;
+}
+
+static ssize_t alsap_get_ptr(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp, int tfd)
+{
+ int dir = (opcode == OSSP_DSP_GET_OPTR) ? PLAY : REC;
+ struct count_info info = { };
+
+ if (!pcm[dir])
+ return -EIO;
+
+ snd_pcm_hw_params_current(pcm[dir], hw_params);
+ info.bytes = byte_counter[dir];
+ snd_pcm_hw_params_get_periods(hw_params, (unsigned int *)&info.blocks, NULL);
+ info.ptr = mmap_pos[dir];
+
+ *(struct count_info *)rarg = info;
+ return 0;
+}
+
+static ssize_t alsap_get_odelay(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp,
+ int fd)
+{
+ snd_pcm_sframes_t delay;
+
+ if (!pcm[PLAY])
+ return -EIO;
+
+ if (snd_pcm_delay(pcm[PLAY], &delay) < 0)
+ return -EIO;
+
+ *(int *)rarg = snd_pcm_frames_to_bytes(pcm[PLAY], delay);
+ return 0;
+}
+
+static ossp_action_fn_t action_fn_tbl[OSSP_NR_OPCODES] = {
+ [OSSP_MIXER] = alsap_mixer,
+ [OSSP_DSP_OPEN] = alsap_open,
+ [OSSP_DSP_READ] = alsap_read,
+ [OSSP_DSP_WRITE] = alsap_write,
+ [OSSP_DSP_POLL] = alsap_poll,
+#if 0
+ [OSSP_DSP_MMAP] = alsap_mmap,
+ [OSSP_DSP_MUNMAP] = alsap_munmap,
+#endif
+ [OSSP_DSP_RESET] = alsap_flush,
+ [OSSP_DSP_SYNC] = alsap_flush,
+ [OSSP_DSP_POST] = alsap_post,
+ [OSSP_DSP_GET_RATE] = alsap_get_param,
+ [OSSP_DSP_GET_CHANNELS] = alsap_get_param,
+ [OSSP_DSP_GET_FORMAT] = alsap_get_param,
+ [OSSP_DSP_GET_BLKSIZE] = alsap_get_param,
+ [OSSP_DSP_GET_FORMATS] = alsap_get_param,
+ [OSSP_DSP_SET_RATE] = alsap_set_param,
+ [OSSP_DSP_SET_CHANNELS] = alsap_set_param,
+ [OSSP_DSP_SET_FORMAT] = alsap_set_param,
+ [OSSP_DSP_SET_SUBDIVISION] = alsap_set_param,
+ [OSSP_DSP_SET_FRAGMENT] = alsap_set_param,
+ [OSSP_DSP_GET_TRIGGER] = alsap_get_param,
+ [OSSP_DSP_SET_TRIGGER] = alsap_set_trigger,
+ [OSSP_DSP_GET_OSPACE] = alsap_get_space,
+ [OSSP_DSP_GET_ISPACE] = alsap_get_space,
+ [OSSP_DSP_GET_OPTR] = alsap_get_ptr,
+ [OSSP_DSP_GET_IPTR] = alsap_get_ptr,
+ [OSSP_DSP_GET_ODELAY] = alsap_get_odelay,
+};
+
+static int action_pre(void)
+{
+ return 0;
+}
+
+static void action_post(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+ int rc;
+
+ ossp_slave_init(argc, argv);
+
+ page_size = sysconf(_SC_PAGE_SIZE);
+
+ /* Okay, now we're open for business */
+ rc = 0;
+ do {
+ rc = ossp_slave_process_command(ossp_cmd_fd, action_fn_tbl,
+ action_pre, action_post);
+ } while (rc > 0);
+
+ return rc ? 1 : 0;
+}
diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.c b/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.c
new file mode 100644
index 0000000000..4c5cb2d129
--- /dev/null
+++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.c
@@ -0,0 +1,250 @@
+/*
+ * ossp-slave - OSS Proxy: Common codes for slaves
+ *
+ * Copyright (C) 2008-2010 SUSE Linux Products GmbH
+ * Copyright (C) 2008-2010 Tejun Heo
+ *
+ * This file is released under the GPLv2.
+ */
+
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "ossp-slave.h"
+
+static const char *usage =
+"usage: ossp-SLAVE [options]\n"
+"\n"
+"proxies commands from osspd to pulseaudio\n"
+"\n"
+"options:\n"
+" -u UID uid to use\n"
+" -g GID gid to use\n"
+" -c CMD_FD fd to receive commands from osspd\n"
+" -n NOTIFY_FD fd to send async notifications to osspd\n"
+" -m MMAP_FD fd to use for mmap\n"
+" -o MMAP_OFFSET mmap offset\n"
+" -s MMAP_SIZE mmap size\n"
+" -l LOG_LEVEL set log level\n"
+" -t enable log timestamps\n";
+
+char ossp_user_name[OSSP_USER_NAME_LEN];
+int ossp_cmd_fd = -1, ossp_notify_fd = -1;
+void *ossp_mmap_addr[2];
+
+void ossp_slave_init(int argc, char **argv)
+{
+ int have_uid = 0, have_gid = 0;
+ uid_t uid;
+ gid_t gid;
+ int mmap_fd = -1;
+ off_t mmap_off = 0;
+ size_t mmap_size = 0;
+ int opt;
+ struct passwd *pw, pw_buf;
+ struct sigaction sa;
+ char pw_sbuf[sysconf(_SC_GETPW_R_SIZE_MAX)];
+
+ while ((opt = getopt(argc, argv, "u:g:c:n:m:o:s:l:t")) != -1) {
+ switch (opt) {
+ case 'u':
+ have_uid = 1;
+ uid = strtol(optarg, NULL, 0);
+ break;
+ case 'g':
+ have_gid = 1;
+ gid = strtol(optarg, NULL, 0);
+ break;
+ case 'c':
+ ossp_cmd_fd = strtol(optarg, NULL, 0);
+ break;
+ case 'n':
+ ossp_notify_fd = strtol(optarg, NULL, 0);
+ break;
+ case 'm':
+ mmap_fd = strtol(optarg, NULL, 0);
+ break;
+ case 'o':
+ mmap_off = strtoull(optarg, NULL, 0);
+ break;
+ case 's':
+ mmap_size = strtoul(optarg, NULL, 0);
+ break;
+ case 'l':
+ ossp_log_level = strtol(optarg, NULL, 0);
+ break;
+ case 't':
+ ossp_log_timestamp = 1;
+ break;
+ }
+ }
+
+ if (!have_uid || !have_gid || ossp_cmd_fd < 0 || ossp_notify_fd < 0) {
+ fprintf(stderr, usage);
+ _exit(1);
+ }
+
+ snprintf(ossp_user_name, sizeof(ossp_user_name), "uid%d", uid);
+ if (getpwuid_r(uid, &pw_buf, pw_sbuf, sizeof(pw_sbuf), &pw) == 0)
+ snprintf(ossp_user_name, sizeof(ossp_user_name), "%s",
+ pw->pw_name);
+
+ snprintf(ossp_log_name, sizeof(ossp_log_name), "ossp-padsp[%s:%d]",
+ ossp_user_name, getpid());
+
+ if (mmap_fd >= 0) {
+ void *p;
+
+ if (!mmap_off || !mmap_size) {
+ fprintf(stderr, usage);
+ _exit(1);
+ }
+
+ p = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ mmap_fd, mmap_off);
+ if (p == MAP_FAILED)
+ fatal_e(-errno, "mmap failed");
+
+ ossp_mmap_addr[PLAY] = p;
+ ossp_mmap_addr[REC] = p + mmap_size / 2;
+ close(mmap_fd);
+ }
+
+ /* mmap done, drop privileges */
+ if (setresgid(gid, gid, gid) || setresuid(uid, uid, uid))
+ fatal_e(-errno, "failed to drop privileges");
+
+ /* block SIGPIPE */
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ if (sigaction(SIGPIPE, &sa, NULL))
+ fatal_e(-errno, "failed to ignore SIGPIPE");
+}
+
+int ossp_slave_process_command(int cmd_fd,
+ ossp_action_fn_t const *action_fn_tbl,
+ int (*action_pre_fn)(void),
+ void (*action_post_fn)(void))
+{
+ static struct sized_buf carg_sbuf = { }, rarg_sbuf = { };
+ static struct sized_buf din_sbuf = { }, dout_sbuf = { };
+ struct ossp_cmd cmd;
+ int fd = -1;
+ char cmsg_buf[CMSG_SPACE(sizeof(fd))];
+ struct iovec iov = { &cmd, sizeof(cmd) };
+ struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1,
+ .msg_control = cmsg_buf,
+ .msg_controllen = sizeof(cmsg_buf) };
+ struct cmsghdr *cmsg;
+ size_t carg_size, din_size, rarg_size, dout_size;
+ char *carg = NULL, *din = NULL, *rarg = NULL, *dout = NULL;
+ struct ossp_reply reply = { .magic = OSSP_REPLY_MAGIC };
+ ssize_t ret;
+
+ ret = recvmsg(cmd_fd, &msg, 0);
+ if (ret == 0)
+ return 0;
+ if (ret < 0) {
+ ret = -errno;
+ err_e(ret, "failed to read command channel");
+ return ret;
+ }
+
+ if (ret != sizeof(cmd)) {
+ err("command struct size mismatch (%zu, should be %zu)",
+ ret, sizeof(cmd));
+ return -EINVAL;
+ }
+
+ if (cmd.magic != OSSP_CMD_MAGIC) {
+ err("illegal command magic 0x%x", cmd.magic);
+ return -EINVAL;
+ }
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS)
+ fd = *(int *)CMSG_DATA(cmsg);
+ else {
+ err("unknown cmsg %d:%d received (opcode %d)",
+ cmsg->cmsg_level, cmsg->cmsg_type, cmd.opcode);
+ return -EINVAL;
+ }
+ }
+
+ if (cmd.opcode >= OSSP_NR_OPCODES) {
+ err("unknown opcode %d", cmd.opcode);
+ return -EINVAL;
+ }
+
+ carg_size = ossp_arg_sizes[cmd.opcode].carg_size;
+ din_size = cmd.din_size;
+ rarg_size = ossp_arg_sizes[cmd.opcode].rarg_size;
+ dout_size = cmd.dout_size;
+
+ if ((fd >= 0) != ossp_arg_sizes[cmd.opcode].has_fd) {
+ err("fd=%d unexpected for opcode %d", fd, cmd.opcode);
+ return -EINVAL;
+ }
+
+ if (ensure_sbuf_size(&carg_sbuf, carg_size) ||
+ ensure_sbuf_size(&din_sbuf, din_size) ||
+ ensure_sbuf_size(&rarg_sbuf, rarg_size) ||
+ ensure_sbuf_size(&dout_sbuf, dout_size)) {
+ err("failed to allocate command buffers");
+ return -ENOMEM;
+ }
+
+ if (carg_size) {
+ carg = carg_sbuf.buf;
+ ret = read_fill(cmd_fd, carg, carg_size);
+ if (ret < 0)
+ return ret;
+ }
+ if (din_size) {
+ din = din_sbuf.buf;
+ ret = read_fill(cmd_fd, din, din_size);
+ if (ret < 0)
+ return ret;
+ }
+ if (rarg_size)
+ rarg = rarg_sbuf.buf;
+ if (dout_size)
+ dout = dout_sbuf.buf;
+
+ ret = -EINVAL;
+ if (action_fn_tbl[cmd.opcode]) {
+ ret = action_pre_fn();
+ if (ret == 0) {
+ ret = action_fn_tbl[cmd.opcode](cmd.opcode, carg,
+ din, din_size, rarg,
+ dout, &dout_size, fd);
+ action_post_fn();
+ }
+ }
+
+ reply.result = ret;
+ if (ret >= 0)
+ reply.dout_size = dout_size;
+ else {
+ rarg_size = 0;
+ dout_size = 0;
+ }
+
+ if (write_fill(cmd_fd, &reply, sizeof(reply)) < 0 ||
+ write_fill(cmd_fd, rarg, rarg_size) < 0 ||
+ write_fill(cmd_fd, dout, dout_size) < 0)
+ return -EIO;
+
+ return 1;
+}
diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.h b/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.h
new file mode 100644
index 0000000000..10c22cdb02
--- /dev/null
+++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.h
@@ -0,0 +1,28 @@
+/*
+ * ossp-slave - OSS Proxy: Common codes for slaves
+ *
+ * Copyright (C) 2008-2010 SUSE Linux Products GmbH
+ * Copyright (C) 2008-2010 Tejun Heo
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _OSSP_SLAVE_H
+#define _OSSP_SLAVE_H
+
+#include "ossp.h"
+#include "ossp-util.h"
+
+#define OSSP_USER_NAME_LEN 128
+
+extern char ossp_user_name[OSSP_USER_NAME_LEN];
+extern int ossp_cmd_fd, ossp_notify_fd;
+extern void *ossp_mmap_addr[2];
+
+void ossp_slave_init(int argc, char **argv);
+int ossp_slave_process_command(int cmd_fd,
+ ossp_action_fn_t const *action_fn_tbl,
+ int (*action_pre_fn)(void),
+ void (*action_post_fn)(void));
+
+#endif /* _OSSP_SLAVE_H */
diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.c b/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.c
new file mode 100644
index 0000000000..325cefd5fd
--- /dev/null
+++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.c
@@ -0,0 +1,369 @@
+/*
+ * ossp-util - OSS Proxy: Common utilities
+ *
+ * Copyright (C) 2008-2010 SUSE Linux Products GmbH
+ * Copyright (C) 2008-2010 Tejun Heo
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "ossp-util.h"
+
+#define BIT(nr) (1UL << (nr))
+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
+#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
+
+char ossp_log_name[OSSP_LOG_NAME_LEN];
+int ossp_log_level = OSSP_LOG_DFL;
+int ossp_log_timestamp;
+
+static const char *severity_strs[] = {
+ [OSSP_LOG_CRIT] = "CRIT",
+ [OSSP_LOG_ERR] = " ERR",
+ [OSSP_LOG_WARN] = "WARN",
+ [OSSP_LOG_INFO] = NULL,
+ [OSSP_LOG_DBG0] = "DBG0",
+ [OSSP_LOG_DBG1] = "DBG1",
+};
+
+static int severity_map[] = {
+ [OSSP_LOG_CRIT] = LOG_ERR,
+ [OSSP_LOG_ERR] = LOG_ERR,
+ [OSSP_LOG_WARN] = LOG_WARNING,
+ [OSSP_LOG_INFO] = LOG_INFO,
+ [OSSP_LOG_DBG0] = LOG_DEBUG,
+ [OSSP_LOG_DBG1] = LOG_DEBUG,
+};
+
+void log_msg(int severity, const char *fmt, ...)
+{
+ static int syslog_opened = 0;
+ char buf[1024];
+ size_t len = sizeof(buf), off = 0;
+ va_list ap;
+
+ if (severity > abs(ossp_log_level))
+ return;
+
+ if (ossp_log_level < 0 && !syslog_opened)
+ openlog(ossp_log_name, 0, LOG_DAEMON);
+
+ assert(severity >= 0 && severity < ARRAY_SIZE(severity_strs));
+
+ if (ossp_log_timestamp) {
+ static uint64_t start;
+ uint64_t now;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ now = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+ if (!start)
+ start = now;
+
+ off += snprintf(buf + off, len - off, "<%08"PRIu64"> ",
+ now - start);
+ }
+
+ if (ossp_log_level > 0) {
+ char sev_buf[16] = "";
+ if (severity_strs[severity])
+ snprintf(sev_buf, sizeof(sev_buf), " %s",
+ severity_strs[severity]);
+ off += snprintf(buf + off, len - off, "%s%s: ",
+ ossp_log_name, sev_buf);
+ } else if (severity_strs[severity])
+ off += snprintf(buf + off, len - off, "%s ",
+ severity_strs[severity]);
+
+ va_start(ap, fmt);
+ off += vsnprintf(buf + off, len - off, fmt, ap);
+ va_end(ap);
+
+ off += snprintf(buf + off, len - off, "\n");
+
+ if (ossp_log_level > 0)
+ fputs(buf, stderr);
+ else
+ syslog(severity_map[severity], "%s", buf);
+}
+
+int read_fill(int fd, void *buf, size_t size)
+{
+ while (size) {
+ ssize_t ret;
+ int rc;
+
+ ret = read(fd, buf, size);
+ if (ret <= 0) {
+ if (ret == 0)
+ rc = -EIO;
+ else
+ rc = -errno;
+ err_e(rc, "failed to read_fill %zu bytes from fd %d",
+ size, fd);
+ return rc;
+ }
+ buf += ret;
+ size -= ret;
+ }
+ return 0;
+}
+
+int write_fill(int fd, const void *buf, size_t size)
+{
+ while (size) {
+ ssize_t ret;
+ int rc;
+
+ ret = write(fd, buf, size);
+ if (ret <= 0) {
+ if (ret == 0)
+ rc = -EIO;
+ else
+ rc = -errno;
+ err_e(rc, "failed to write_fill %zu bytes to fd %d",
+ size, fd);
+ return rc;
+ }
+ buf += ret;
+ size -= ret;
+ }
+ return 0;
+}
+
+void ring_fill(struct ring_buf *ring, const void *buf, size_t size)
+{
+ size_t tail;
+
+ assert(ring_space(ring) >= size);
+
+ tail = (ring->head + ring->size - ring->bytes) % ring->size;
+
+ if (ring->head >= tail) {
+ size_t todo = min(size, ring->size - ring->head);
+
+ memcpy(ring->buf + ring->head, buf, todo);
+ ring->head = (ring->head + todo) % ring->size;
+ ring->bytes += todo;
+ buf += todo;
+ size -= todo;
+ }
+
+ assert(ring->size - ring->head >= size);
+ memcpy(ring->buf + ring->head, buf, size);
+ ring->head += size;
+ ring->bytes += size;
+}
+
+void *ring_data(struct ring_buf *ring, size_t *sizep)
+{
+ size_t tail;
+
+ if (!ring->bytes)
+ return NULL;
+
+ tail = (ring->head + ring->size - ring->bytes) % ring->size;
+
+ *sizep = min(ring->bytes, ring->size - tail);
+ return ring->buf + tail;
+}
+
+int ring_resize(struct ring_buf *ring, size_t new_size)
+{
+ struct ring_buf new_ring = { .size = new_size };
+ void *p;
+ size_t size;
+
+ if (ring_bytes(ring) > new_size)
+ return -ENOSPC;
+
+ new_ring.buf = calloc(1, new_size);
+ if (new_size && !new_ring.buf)
+ return -ENOMEM;
+
+ while ((p = ring_data(ring, &size))) {
+ ring_fill(&new_ring, p, size);
+ ring_consume(ring, size);
+ }
+
+ free(ring->buf);
+ *ring = new_ring;
+ return 0;
+}
+
+int ensure_sbuf_size(struct sized_buf *sbuf, size_t size)
+{
+ char *new_buf;
+
+ if (sbuf->size >= size)
+ return 0;
+
+ new_buf = realloc(sbuf->buf, size);
+ if (size && !new_buf)
+ return -ENOMEM;
+
+ sbuf->buf = new_buf;
+ sbuf->size = size;
+ return 0;
+}
+
+static unsigned long __ffs(unsigned long word)
+{
+ int num = 0;
+
+ if (BITS_PER_LONG == 64) {
+ if ((word & 0xffffffff) == 0) {
+ num += 32;
+ word >>= 32;
+ }
+ }
+
+ if ((word & 0xffff) == 0) {
+ num += 16;
+ word >>= 16;
+ }
+ if ((word & 0xff) == 0) {
+ num += 8;
+ word >>= 8;
+ }
+ if ((word & 0xf) == 0) {
+ num += 4;
+ word >>= 4;
+ }
+ if ((word & 0x3) == 0) {
+ num += 2;
+ word >>= 2;
+ }
+ if ((word & 0x1) == 0)
+ num += 1;
+ return num;
+}
+
+#define ffz(x) __ffs(~(x))
+
+unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
+ unsigned long offset)
+{
+ const unsigned long *p = addr + BITOP_WORD(offset);
+ unsigned long result = offset & ~(BITS_PER_LONG-1);
+ unsigned long tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset %= BITS_PER_LONG;
+ if (offset) {
+ tmp = *(p++);
+ tmp |= ~0UL >> (BITS_PER_LONG - offset);
+ if (size < BITS_PER_LONG)
+ goto found_first;
+ if (~tmp)
+ goto found_middle;
+ size -= BITS_PER_LONG;
+ result += BITS_PER_LONG;
+ }
+ while (size & ~(BITS_PER_LONG-1)) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+
+found_first:
+ tmp |= ~0UL << size;
+ if (tmp == ~0UL) /* Are any bits zero? */
+ return result + size; /* Nope. */
+found_middle:
+ return result + ffz(tmp);
+}
+
+void __set_bit(int nr, volatile unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+ *p |= mask;
+}
+
+void __clear_bit(int nr, volatile unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+ *p &= ~mask;
+}
+
+int get_proc_self_info(pid_t pid, pid_t *ppid_r,
+ char *cmd_buf, size_t cmd_buf_sz)
+
+{
+ char path[64], buf[4096];
+ int fd = -1;
+ char *cmd_start, *cmd_end, *ppid_start, *end;
+ ssize_t ret;
+ pid_t ppid;
+ int i, rc;
+
+ snprintf(path, sizeof(path), "/proc/%ld/stat", (long)pid);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ rc = -errno;
+ goto out;
+ }
+
+ ret = read(fd, buf, sizeof(buf));
+ if (ret < 0)
+ goto out;
+ if (ret == sizeof(buf)) {
+ rc = -EOVERFLOW;
+ goto out;
+ }
+ buf[ret] = '\0';
+
+ rc = -EINVAL;
+ cmd_start = strchr(buf, '(');
+ cmd_end = strrchr(buf, ')');
+ if (!cmd_start || !cmd_end)
+ goto out;
+ cmd_start++;
+
+ ppid_start = cmd_end;
+ for (i = 0; i < 3; i++) {
+ ppid_start = strchr(ppid_start, ' ');
+ if (!ppid_start)
+ goto out;
+ ppid_start++;
+ }
+
+ ppid = strtoul(ppid_start, &end, 10);
+ if (end == ppid_start || *end != ' ')
+ goto out;
+
+ if (ppid_r)
+ *ppid_r = ppid;
+ if (cmd_buf) {
+ size_t len = min_t(size_t, cmd_end - cmd_start, cmd_buf_sz - 1);
+ memcpy(cmd_buf, cmd_start, len);
+ cmd_buf[len] = '\0';
+ }
+
+ rc = 0;
+ out:
+ close(fd);
+
+ return rc;
+}
diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.h b/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.h
new file mode 100644
index 0000000000..f48d02257a
--- /dev/null
+++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.h
@@ -0,0 +1,609 @@
+/*
+ * ossp-util - OSS Proxy: Common utilities
+ *
+ * Copyright (C) 2008-2010 SUSE Linux Products GmbH
+ * Copyright (C) 2008-2010 Tejun Heo
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _OSSP_UTIL_H
+#define _OSSP_UTIL_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "ossp.h"
+
+#define OSSP_LOG_NAME_LEN 128
+
+enum {
+ OSSP_LOG_CRIT = 1,
+ OSSP_LOG_ERR,
+ OSSP_LOG_WARN,
+ OSSP_LOG_INFO,
+ OSSP_LOG_DFL = OSSP_LOG_INFO, /* default log level */
+ OSSP_LOG_DBG0,
+ OSSP_LOG_DBG1,
+ OSSP_LOG_MAX = OSSP_LOG_DBG1,
+};
+
+extern char ossp_log_name[OSSP_LOG_NAME_LEN];
+extern int ossp_log_level;
+extern int ossp_log_timestamp;
+
+#define BITS_PER_BYTE 8
+#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long))
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
+
+/* ARRAY_SIZE and min/max macros stolen from linux/kernel.h */
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+
+#define max(x, y) ({ \
+ typeof(x) _max1 = (x); \
+ typeof(y) _max2 = (y); \
+ (void) (&_max1 == &_max2); \
+ _max1 > _max2 ? _max1 : _max2; })
+
+#define min_t(type, x, y) ({ \
+ type __min1 = (x); \
+ type __min2 = (y); \
+ __min1 < __min2 ? __min1: __min2; })
+
+#define max_t(type, x, y) ({ \
+ type __max1 = (x); \
+ type __max2 = (y); \
+ __max1 > __max2 ? __max1: __max2; })
+
+void log_msg(int severity, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+#define fatal(fmt, args...) do { \
+ log_msg(OSSP_LOG_CRIT, fmt , ##args); \
+ _exit(1); \
+} while (0)
+#define err(fmt, args...) log_msg(OSSP_LOG_ERR, fmt , ##args)
+#define warn(fmt, args...) log_msg(OSSP_LOG_WARN, fmt , ##args)
+#define info(fmt, args...) log_msg(OSSP_LOG_INFO, fmt , ##args)
+#define dbg0(fmt, args...) log_msg(OSSP_LOG_DBG0, fmt , ##args)
+#define dbg1(fmt, args...) log_msg(OSSP_LOG_DBG1, fmt , ##args)
+
+#define fatal_e(e, fmt, args...) \
+ fatal(fmt" (%s)" , ##args, strerror(-(e)))
+#define err_e(e, fmt, args...) \
+ err(fmt" (%s)" , ##args, strerror(-(e)))
+#define warn_e(e, fmt, args...) \
+ warn(fmt" (%s)" , ##args, strerror(-(e)))
+#define info_e(e, fmt, args...) \
+ info(fmt" (%s)" , ##args, strerror(-(e)))
+#define dbg0_e(e, fmt, args...) \
+ dbg0(fmt" (%s)" , ##args, strerror(-(e)))
+#define dbg1_e(e, fmt, args...) \
+ dbg1(fmt" (%s)" , ##args, strerror(-(e)))
+
+struct ring_buf {
+ char *buf;
+ size_t size;
+ size_t head;
+ size_t bytes;
+};
+
+static inline size_t ring_size(struct ring_buf *ring)
+{
+ return ring->size;
+}
+
+static inline size_t ring_bytes(struct ring_buf *ring)
+{
+ return ring->bytes;
+}
+
+static inline size_t ring_space(struct ring_buf *ring)
+{
+ return ring->size - ring->bytes;
+}
+
+static inline void ring_consume(struct ring_buf *ring, size_t size)
+{
+ assert(ring->bytes >= size);
+ ring->bytes -= size;
+}
+
+static inline void ring_manual_init(struct ring_buf *ring, void *buf,
+ size_t size, size_t head, size_t bytes)
+{
+ ring->buf = buf;
+ ring->size = size;
+ ring->head = head;
+ ring->bytes = bytes;
+}
+
+void ring_fill(struct ring_buf *ring, const void *buf, size_t size);
+void *ring_data(struct ring_buf *ring, size_t *sizep);
+int ring_resize(struct ring_buf *ring, size_t new_size);
+
+struct sized_buf {
+ char *buf;
+ size_t size;
+};
+
+int ensure_sbuf_size(struct sized_buf *sbuf, size_t size);
+
+int read_fill(int fd, void *buf, size_t size);
+int write_fill(int fd, const void *buf, size_t size);
+
+/*
+ * Bitops lifted from linux asm-generic implementation.
+ */
+unsigned long find_next_zero_bit(const unsigned long *addr, unsigned
+ long size, unsigned long offset);
+#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
+extern void __set_bit(int nr, volatile unsigned long *addr);
+extern void __clear_bit(int nr, volatile unsigned long *addr);
+
+typedef ssize_t (*ossp_action_fn_t)(enum ossp_opcode opcode,
+ void *carg, void *din, size_t din_sz,
+ void *rarg, void *dout, size_t *dout_szp,
+ int fd);
+
+int get_proc_self_info(pid_t tid, pid_t *pgrp,
+ char *cmd_buf, size_t cmd_buf_sz);
+
+/*
+ * Doubly linked list handling code shamelessly stolen from the Linux
+ * kernel 2.6.26 include/linux/list.h.
+ */
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+/**
+ * list_is_singular - tests whether a list has just one entry.
+ * @head: the list to test.
+ */
+static inline int list_is_singular(const struct list_head *head)
+{
+ return !list_empty(head) && (head->next == head->prev);
+}
+
+static inline void __list_splice(const struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(const struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+ for (pos = (head)->prev, n = pos->prev; \
+ pos != (head); pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member) \
+ for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) \
+ for (; &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ n = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+#endif /*_OSSP_UTIL_H*/
diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp.c b/src/mod/endpoints/mod_skypopen/osscuse/ossp.c
new file mode 100644
index 0000000000..96f98fa37a
--- /dev/null
+++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp.c
@@ -0,0 +1,83 @@
+/*
+ * ossp - OSS Proxy: emulate OSS device using CUSE
+ *
+ * Copyright (C) 2008-2010 SUSE Linux Products GmbH
+ * Copyright (C) 2008-2010 Tejun Heo
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include "ossp.h"
+
+const struct ossp_arg_size ossp_arg_sizes[OSSP_NR_OPCODES] = {
+ [OSSP_MIXER] = { sizeof(struct ossp_mixer_arg),
+ sizeof(struct ossp_mixer_arg), 0 },
+
+ [OSSP_DSP_OPEN] = { sizeof(struct ossp_dsp_open_arg), 0, 0 },
+ [OSSP_DSP_READ] = { sizeof(struct ossp_dsp_rw_arg), 0, 0 },
+ [OSSP_DSP_WRITE] = { sizeof(struct ossp_dsp_rw_arg), 0, 0 },
+ [OSSP_DSP_POLL] = { sizeof(int), sizeof(unsigned), 0 },
+ [OSSP_DSP_MMAP] = { sizeof(struct ossp_dsp_mmap_arg), 0, 0 },
+ [OSSP_DSP_MUNMAP] = { sizeof(int), 0, 0 },
+
+ [OSSP_DSP_RESET] = { 0, 0, 0 },
+ [OSSP_DSP_SYNC] = { 0, 0, 0 },
+ [OSSP_DSP_POST] = { 0, 0, 0 },
+ [OSSP_DSP_GET_RATE] = { 0, sizeof(int), 0 },
+ [OSSP_DSP_GET_CHANNELS] = { 0, sizeof(int), 0 },
+ [OSSP_DSP_GET_FORMAT] = { 0, sizeof(int), 0 },
+ [OSSP_DSP_GET_BLKSIZE] = { 0, sizeof(int), 0 },
+ [OSSP_DSP_GET_FORMATS] = { 0, sizeof(int), 0 },
+ [OSSP_DSP_SET_RATE] = { sizeof(int), sizeof(int), 0 },
+ [OSSP_DSP_SET_CHANNELS] = { sizeof(int), sizeof(int), 0 },
+ [OSSP_DSP_SET_FORMAT] = { sizeof(int), sizeof(int), 0 },
+ [OSSP_DSP_SET_SUBDIVISION] = { sizeof(int), sizeof(int), 0 },
+ [OSSP_DSP_SET_FRAGMENT] = { sizeof(int), 0, 0 },
+ [OSSP_DSP_GET_TRIGGER] = { 0, sizeof(int), 0 },
+ [OSSP_DSP_SET_TRIGGER] = { sizeof(int), 0, 0 },
+ [OSSP_DSP_GET_OSPACE] = { 0, sizeof(struct audio_buf_info), 0 },
+ [OSSP_DSP_GET_ISPACE] = { 0, sizeof(struct audio_buf_info), 0 },
+ [OSSP_DSP_GET_OPTR] = { 0, sizeof(struct count_info), 0 },
+ [OSSP_DSP_GET_IPTR] = { 0, sizeof(struct count_info), 0 },
+ [OSSP_DSP_GET_ODELAY] = { 0, sizeof(int), 0 },
+};
+
+const char *ossp_cmd_str[OSSP_NR_OPCODES] = {
+ [OSSP_MIXER] = "MIXER",
+
+ [OSSP_DSP_OPEN] = "OPEN",
+ [OSSP_DSP_READ] = "READ",
+ [OSSP_DSP_WRITE] = "WRITE",
+ [OSSP_DSP_POLL] = "POLL",
+ [OSSP_DSP_MMAP] = "MMAP",
+ [OSSP_DSP_MUNMAP] = "MUNMAP",
+
+ [OSSP_DSP_RESET] = "RESET",
+ [OSSP_DSP_SYNC] = "SYNC",
+ [OSSP_DSP_POST] = "POST",
+
+ [OSSP_DSP_GET_RATE] = "GET_RATE",
+ [OSSP_DSP_GET_CHANNELS] = "GET_CHANNELS",
+ [OSSP_DSP_GET_FORMAT] = "GET_FORMAT",
+ [OSSP_DSP_GET_BLKSIZE] = "GET_BLKSIZE",
+ [OSSP_DSP_GET_FORMATS] = "GET_FORMATS",
+ [OSSP_DSP_SET_RATE] = "SET_RATE",
+ [OSSP_DSP_SET_CHANNELS] = "SET_CHANNELS",
+ [OSSP_DSP_SET_FORMAT] = "SET_FORMAT",
+ [OSSP_DSP_SET_SUBDIVISION] = "SET_BUSDIVISION",
+
+ [OSSP_DSP_SET_FRAGMENT] = "SET_FRAGMENT",
+ [OSSP_DSP_GET_TRIGGER] = "GET_TRIGGER",
+ [OSSP_DSP_SET_TRIGGER] = "SET_TRIGGER",
+ [OSSP_DSP_GET_OSPACE] = "GET_OSPACE",
+ [OSSP_DSP_GET_ISPACE] = "GET_ISPACE",
+ [OSSP_DSP_GET_OPTR] = "GET_OPTR",
+ [OSSP_DSP_GET_IPTR] = "GET_IPTR",
+ [OSSP_DSP_GET_ODELAY] = "GET_ODELAY",
+};
+
+const char *ossp_notify_str[OSSP_NR_NOTIFY_OPCODES] = {
+ [OSSP_NOTIFY_POLL] = "POLL",
+ [OSSP_NOTIFY_OBITUARY] = "OBITUARY",
+ [OSSP_NOTIFY_VOLCHG] = "VOLCHG",
+};
diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp.h b/src/mod/endpoints/mod_skypopen/osscuse/ossp.h
new file mode 100644
index 0000000000..9d03e63adf
--- /dev/null
+++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp.h
@@ -0,0 +1,117 @@
+/*
+ * ossp - OSS Proxy: emulate OSS device using CUSE
+ *
+ * Copyright (C) 2008-2010 SUSE Linux Products GmbH
+ * Copyright (C) 2008-2010 Tejun Heo
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef _OSSP_H
+#define _OSSP_H
+
+#include
+#include
+#include
+
+#define OSSP_VERSION "1.3.2"
+#define OSSP_CMD_MAGIC 0xdeadbeef
+#define OSSP_REPLY_MAGIC 0xbeefdead
+#define OSSP_NOTIFY_MAGIC 0xbebebebe
+
+#define PLAY 0
+#define REC 1
+#define LEFT 0
+#define RIGHT 1
+
+enum ossp_opcode {
+ OSSP_MIXER,
+
+ OSSP_DSP_OPEN,
+ OSSP_DSP_READ,
+ OSSP_DSP_WRITE,
+ OSSP_DSP_POLL,
+ OSSP_DSP_MMAP,
+ OSSP_DSP_MUNMAP,
+
+ OSSP_DSP_RESET,
+ OSSP_DSP_SYNC,
+ OSSP_DSP_POST,
+
+ OSSP_DSP_GET_RATE,
+ OSSP_DSP_GET_CHANNELS,
+ OSSP_DSP_GET_FORMAT,
+ OSSP_DSP_GET_BLKSIZE,
+ OSSP_DSP_GET_FORMATS,
+ OSSP_DSP_SET_RATE,
+ OSSP_DSP_SET_CHANNELS,
+ OSSP_DSP_SET_FORMAT,
+ OSSP_DSP_SET_SUBDIVISION,
+
+ OSSP_DSP_SET_FRAGMENT,
+ OSSP_DSP_GET_TRIGGER,
+ OSSP_DSP_SET_TRIGGER,
+ OSSP_DSP_GET_OSPACE,
+ OSSP_DSP_GET_ISPACE,
+ OSSP_DSP_GET_OPTR,
+ OSSP_DSP_GET_IPTR,
+ OSSP_DSP_GET_ODELAY,
+
+ OSSP_NR_OPCODES,
+};
+
+enum ossp_notify_opcode {
+ OSSP_NOTIFY_POLL,
+ OSSP_NOTIFY_OBITUARY,
+ OSSP_NOTIFY_VOLCHG,
+
+ OSSP_NR_NOTIFY_OPCODES,
+};
+
+struct ossp_mixer_arg {
+ int vol[2][2];
+};
+
+struct ossp_dsp_open_arg {
+ int flags;
+ pid_t opener_pid;
+};
+
+struct ossp_dsp_rw_arg {
+ unsigned nonblock:1;
+};
+
+struct ossp_dsp_mmap_arg {
+ int dir;
+ size_t size;
+};
+
+struct ossp_cmd {
+ unsigned magic;
+ enum ossp_opcode opcode;
+ size_t din_size;
+ size_t dout_size;
+};
+
+struct ossp_reply {
+ unsigned magic;
+ int result;
+ size_t dout_size; /* <= cmd.data_in_size */
+};
+
+struct ossp_notify {
+ unsigned magic;
+ enum ossp_notify_opcode opcode;
+};
+
+struct ossp_arg_size {
+ ssize_t carg_size;
+ ssize_t rarg_size;
+ unsigned has_fd:1;
+};
+
+extern const struct ossp_arg_size ossp_arg_sizes[OSSP_NR_OPCODES];
+extern const char *ossp_cmd_str[OSSP_NR_OPCODES];
+extern const char *ossp_notify_str[OSSP_NR_NOTIFY_OPCODES];
+
+#endif /* _OSSP_H */
diff --git a/src/mod/endpoints/mod_skypopen/osscuse/osspd.c b/src/mod/endpoints/mod_skypopen/osscuse/osspd.c
new file mode 100644
index 0000000000..dc9f36a09b
--- /dev/null
+++ b/src/mod/endpoints/mod_skypopen/osscuse/osspd.c
@@ -0,0 +1,2374 @@
+/*
+ * osspd - OSS Proxy Daemon: emulate OSS device using CUSE
+ *
+ * Copyright (C) 2008-2010 SUSE Linux Products GmbH
+ * Copyright (C) 2008-2010 Tejun Heo
+ *
+ * This file is released under the GPLv2.
+ */
+#undef GIOVANNI
+
+#define FUSE_USE_VERSION 28
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "ossp.h"
+#include "ossp-util.h"
+
+/*
+ * MMAP support needs to be updated to the new fuse MMAP API. Disable
+ * it for the time being.
+ */
+#warning mmap support disabled for now
+/* #define OSSP_MMAP */
+
+#define DFL_MIXER_NAME "mixer"
+#define DFL_DSP_NAME "dsp"
+#define DFL_ADSP_NAME "adsp"
+#define STRFMT "S[%u/%d]"
+#define STRID(os) os->id, os->pid
+
+#define dbg1_os(os, fmt, args...) dbg1(STRFMT" "fmt, STRID(os) , ##args)
+#define dbg0_os(os, fmt, args...) dbg0(STRFMT" "fmt, STRID(os) , ##args)
+#define warn_os(os, fmt, args...) warn(STRFMT" "fmt, STRID(os) , ##args)
+#define err_os(os, fmt, args...) err(STRFMT" "fmt, STRID(os) , ##args)
+#define warn_ose(os, err, fmt, args...) \
+ warn_e(err, STRFMT" "fmt, STRID(os) , ##args)
+#define err_ose(os, err, fmt, args...) \
+ err_e(err, STRFMT" "fmt, STRID(os) , ##args)
+
+enum {
+ SNDRV_OSS_VERSION = ((3<<16)|(8<<8)|(1<<4)|(0)), /* 3.8.1a */
+ DFL_MIXER_MAJOR = 14,
+ DFL_MIXER_MINOR = 0,
+ DFL_DSP_MAJOR = 14,
+ DFL_DSP_MINOR = 3,
+ DFL_ADSP_MAJOR = 14,
+ DFL_ADSP_MINOR = 12,
+ DFL_MAX_STREAMS = 128,
+ MIXER_PUT_DELAY = 600, /* 10 mins */
+ /* DSPS_MMAP_SIZE / 2 must be multiple of SHMLBA */
+ DSPS_MMAP_SIZE = 2 * (512 << 10), /* 512k for each dir */
+};
+
+struct ossp_uid_cnt {
+ struct list_head link;
+ uid_t uid;
+ unsigned nr_os;
+};
+
+struct ossp_mixer {
+ pid_t pgrp;
+ struct list_head link;
+ struct list_head delayed_put_link;
+ unsigned refcnt;
+ /* the following two fields are protected by mixer_mutex */
+ int vol[2][2];
+ int modify_counter;
+ time_t put_expires;
+};
+
+struct ossp_mixer_cmd {
+ struct ossp_mixer *mixer;
+ struct ossp_mixer_arg set;
+ int out_dir;
+ int rvol;
+};
+
+#define for_each_vol(i, j) \
+ for (i = 0, j = 0; i < 2; j += i << 1, j++, i = j >> 1, j &= 1)
+
+struct ossp_stream {
+ unsigned id; /* stream ID */
+ struct list_head link;
+ struct list_head pgrp_link;
+ struct list_head notify_link;
+ unsigned refcnt;
+ pthread_mutex_t cmd_mutex;
+ pthread_mutex_t mmap_mutex;
+ struct fuse_pollhandle *ph;
+
+ /* stream owner info */
+ pid_t pid;
+ pid_t pgrp;
+ uid_t uid;
+ gid_t gid;
+
+ /* slave info */
+ pid_t slave_pid;
+ int cmd_fd;
+ int notify_tx;
+ int notify_rx;
+
+ /* the following dead flag is set asynchronously, keep it separate. */
+ int dead;
+
+ /* stream mixer state, protected by mixer_mutex */
+ int mixer_pending;
+ int vol[2][2];
+ int vol_set[2][2];
+
+ off_t mmap_off;
+ size_t mmap_size;
+
+ struct ossp_uid_cnt *ucnt;
+ struct fuse_session *se; /* associated fuse session */
+ struct ossp_mixer *mixer;
+};
+
+struct ossp_dsp_stream {
+ struct ossp_stream os;
+ unsigned rw;
+ unsigned mmapped;
+ int nonblock;
+};
+
+#define os_to_dsps(_os) container_of(_os, struct ossp_dsp_stream, os)
+
+static unsigned max_streams;
+static unsigned umax_streams;
+static unsigned hashtbl_size;
+static char dsp_slave_path[PATH_MAX];
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t mixer_mutex = PTHREAD_MUTEX_INITIALIZER;
+static unsigned long *os_id_bitmap;
+static unsigned nr_mixers;
+static struct list_head *mixer_tbl; /* indexed by PGRP */
+static struct list_head *os_tbl; /* indexed by ID */
+static struct list_head *os_pgrp_tbl; /* indexed by PGRP */
+static struct list_head *os_notify_tbl; /* indexed by notify fd */
+static LIST_HEAD(uid_cnt_list);
+static int notify_epfd; /* epoll used to monitor notify fds */
+static pthread_t notify_poller_thread;
+static pthread_t slave_reaper_thread;
+static pthread_t mixer_delayed_put_thread;
+static pthread_t cuse_mixer_thread;
+static pthread_t cuse_adsp_thread;
+static pthread_cond_t notify_poller_kill_wait = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t slave_reaper_wait = PTHREAD_COND_INITIALIZER;
+static LIST_HEAD(slave_corpse_list);
+static LIST_HEAD(mixer_delayed_put_head); /* delayed reference */
+static pthread_cond_t mixer_delayed_put_cond = PTHREAD_COND_INITIALIZER;
+
+static int init_wait_fd = -1;
+static int exit_on_idle;
+static struct fuse_session *mixer_se;
+static struct fuse_session *dsp_se;
+static struct fuse_session *adsp_se;
+
+static void put_os(struct ossp_stream *os);
+
+
+/***************************************************************************
+ * Accessors
+ */
+
+static struct list_head *mixer_tbl_head(pid_t pid)
+{
+ return &mixer_tbl[pid % hashtbl_size];
+}
+
+static struct list_head *os_tbl_head(uint64_t id)
+{
+ return &os_tbl[id % hashtbl_size];
+}
+
+static struct list_head *os_pgrp_tbl_head(pid_t pgrp)
+{
+ return &os_pgrp_tbl[pgrp % hashtbl_size];
+}
+
+static struct list_head *os_notify_tbl_head(int notify_rx)
+{
+ return &os_notify_tbl[notify_rx % hashtbl_size];
+}
+
+static struct ossp_mixer *find_mixer_locked(pid_t pgrp)
+{
+ struct ossp_mixer *mixer;
+
+ list_for_each_entry(mixer, mixer_tbl_head(pgrp), link)
+ if (mixer->pgrp == pgrp)
+ return mixer;
+ return NULL;
+}
+
+static struct ossp_mixer *find_mixer(pid_t pgrp)
+{
+ struct ossp_mixer *mixer;
+
+ pthread_mutex_lock(&mutex);
+ mixer = find_mixer_locked(pgrp);
+ pthread_mutex_unlock(&mutex);
+ return mixer;
+}
+
+static struct ossp_stream *find_os(unsigned id)
+{
+ struct ossp_stream *os, *found = NULL;
+
+ pthread_mutex_lock(&mutex);
+ list_for_each_entry(os, os_tbl_head(id), link)
+ if (os->id == id) {
+ found = os;
+ break;
+ }
+ pthread_mutex_unlock(&mutex);
+ return found;
+}
+
+static struct ossp_stream *find_os_by_notify_rx(int notify_rx)
+{
+ struct ossp_stream *os, *found = NULL;
+
+ pthread_mutex_lock(&mutex);
+ list_for_each_entry(os, os_notify_tbl_head(notify_rx), notify_link)
+ if (os->notify_rx == notify_rx) {
+ found = os;
+ break;
+ }
+ pthread_mutex_unlock(&mutex);
+ return found;
+}
+
+
+/***************************************************************************
+ * Command and ioctl helpers
+ */
+
+static ssize_t exec_cmd_intern(struct ossp_stream *os, enum ossp_opcode opcode,
+ const void *carg, size_t carg_size, const void *din, size_t din_size,
+ void *rarg, size_t rarg_size, void *dout, size_t *dout_sizep, int fd)
+{
+ size_t dout_size = dout_sizep ? *dout_sizep : 0;
+ struct ossp_cmd cmd = { .magic = OSSP_CMD_MAGIC, .opcode = opcode,
+ .din_size = din_size,
+ .dout_size = dout_size };
+ struct iovec iov = { &cmd, sizeof(cmd) };
+ struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
+ struct ossp_reply reply = { };
+ char cmsg_buf[CMSG_SPACE(sizeof(fd))];
+ char reason[512];
+ int rc;
+
+ if (os->dead)
+ return -EIO;
+
+ //dbg1_os(os, "opcode %s=%d carg=%zu din=%zu rarg=%zu dout=%zu",
+ //ossp_cmd_str[opcode], opcode, carg_size, din_size, rarg_size,
+ //dout_size);
+#ifndef GIOVANNI
+memset(dout, 255, dout_size);
+memset(din, 255, din_size);
+
+#define GIOVA_BLK 3840
+#define GIOVA_SLEEP 40000
+switch(opcode){
+
+ case 1: //OPEN
+ reply.result = 0;
+ break;
+ case 2: //READ
+ usleep((GIOVA_SLEEP/GIOVA_BLK)* *dout_sizep);
+ reply.result = *dout_sizep;
+ break;
+ case 3: //WRITE
+ usleep((GIOVA_SLEEP/GIOVA_BLK)* din_size);
+ reply.result = din_size;
+ break;
+ case 9: //POST
+ reply.result = -32;
+ break;
+ case 13: //GET_BLKSIZE
+ reply.result = 0;
+ *(int *)rarg = GIOVA_BLK;
+ break;
+ case 14: //GET_FORMATS
+ reply.result = 0;
+ *(int *)rarg = 28731;
+ break;
+ case 15: //SET_RATE
+ reply.result = 0;
+ *(int *)rarg = *(int *) carg;
+ break;
+ case 16: //SET_CHANNELS
+ reply.result = 0;
+ *(int *)rarg = *(int *) carg;
+ break;
+ case 17: //SET_FORMAT
+ reply.result = 0;
+ *(int *)rarg = *(int *) carg;
+ break;
+ case 19: //SET_FRAGMENT
+ reply.result = 0;
+ break;
+ default:
+ reply.result = 0;
+ break;
+}
+#endif // GIOVANNI
+
+#ifdef GIOVANNI
+ if (fd >= 0) {
+ struct cmsghdr *cmsg;
+
+ msg.msg_control = cmsg_buf;
+ msg.msg_controllen = sizeof(cmsg_buf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ *(int *)CMSG_DATA(cmsg) = fd;
+ msg.msg_controllen = cmsg->cmsg_len;
+ }
+
+ if (sendmsg(os->cmd_fd, &msg, 0) <= 0) {
+ rc = -errno;
+ snprintf(reason, sizeof(reason), "command sendmsg failed: %s",
+ strerror(-rc));
+ goto fail;
+ }
+
+ if ((rc = write_fill(os->cmd_fd, carg, carg_size)) < 0 ||
+ (rc = write_fill(os->cmd_fd, din, din_size)) < 0) {
+ snprintf(reason, sizeof(reason),
+ "can't tranfer command argument and/or data: %s",
+ strerror(-rc));
+ goto fail;
+ }
+ if ((rc = read_fill(os->cmd_fd, &reply, sizeof(reply))) < 0) {
+ snprintf(reason, sizeof(reason), "can't read reply: %s",
+ strerror(-rc));
+ goto fail;
+ }
+
+ if (reply.magic != OSSP_REPLY_MAGIC) {
+ snprintf(reason, sizeof(reason),
+ "reply magic mismatch %x != %x",
+ reply.magic, OSSP_REPLY_MAGIC);
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ if (reply.result < 0)
+ goto out_unlock;
+
+ if (reply.dout_size > dout_size) {
+ snprintf(reason, sizeof(reason),
+ "data out size overflow %zu > %zu",
+ reply.dout_size, dout_size);
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ dout_size = reply.dout_size;
+ if (dout_sizep)
+ *dout_sizep = dout_size;
+
+ if ((rc = read_fill(os->cmd_fd, rarg, rarg_size)) < 0 ||
+ (rc = read_fill(os->cmd_fd, dout, dout_size)) < 0) {
+ snprintf(reason, sizeof(reason), "can't read data out: %s",
+ strerror(-rc));
+ goto fail;
+ }
+
+#endif // GIOVANNI
+
+out_unlock:
+ //dbg1_os(os, " completed, result=%d dout=%zu",
+ //reply.result, dout_size);
+
+//if(rarg)
+ //dbg1_os(os, " 2 %s=%d completed, result=%d dout=%zu carg=%d rarg=%d", ossp_cmd_str[opcode], opcode,
+ //reply.result, dout_size, carg ? *(int *) carg : 666, *(int *)rarg);
+ return reply.result;
+
+fail:
+ warn_os(os, "communication with slave failed (%s)", reason);
+ os->dead = 1;
+ return rc;
+}
+
+static ssize_t exec_cmd(struct ossp_stream *os, enum ossp_opcode opcode,
+ const void *carg, size_t carg_size, const void *din, size_t din_size,
+ void *rarg, size_t rarg_size, void *dout, size_t *dout_sizep, int fd)
+{
+ int is_mixer;
+ int i, j;
+ ssize_t ret, mret;
+
+ /* mixer command is handled exlicitly below */
+ is_mixer = opcode == OSSP_MIXER;
+ if (is_mixer) {
+ ret = -pthread_mutex_trylock(&os->cmd_mutex);
+ if (ret)
+ return ret;
+ } else {
+ pthread_mutex_lock(&os->cmd_mutex);
+
+ ret = exec_cmd_intern(os, opcode, carg, carg_size,
+ din, din_size, rarg, rarg_size,
+ dout, dout_sizep, fd);
+ }
+
+ /* lazy mixer handling */
+ pthread_mutex_lock(&mixer_mutex);
+
+ if (os->mixer_pending) {
+ struct ossp_mixer_arg marg;
+ repeat_mixer:
+ /* we have mixer command pending */
+ memcpy(marg.vol, os->vol_set, sizeof(os->vol_set));
+ memset(os->vol_set, -1, sizeof(os->vol_set));
+
+ pthread_mutex_unlock(&mixer_mutex);
+ mret = exec_cmd_intern(os, OSSP_MIXER, &marg, sizeof(marg),
+ NULL, 0, &marg, sizeof(marg), NULL, NULL,
+ -1);
+ pthread_mutex_lock(&mixer_mutex);
+
+ /* was there mixer set request while executing mixer command? */
+ for_each_vol(i, j)
+ if (os->vol_set[i][j] >= 0)
+ goto repeat_mixer;
+
+ /* update internal mixer state */
+ if (mret == 0) {
+ for_each_vol(i, j) {
+ if (marg.vol[i][j] >= 0) {
+ if (os->vol[i][j] != marg.vol[i][j])
+ os->mixer->modify_counter++;
+ os->vol[i][j] = marg.vol[i][j];
+ }
+ }
+ }
+ os->mixer_pending = 0;
+ }
+
+ pthread_mutex_unlock(&os->cmd_mutex);
+
+ /*
+ * mixer mutex must be released after cmd_mutex so that
+ * exec_mixer_cmd() can guarantee that mixer_pending flags
+ * will be handled immediately or when the currently
+ * in-progress command completes.
+ */
+ pthread_mutex_unlock(&mixer_mutex);
+
+ return is_mixer ? mret : ret;
+}
+
+static ssize_t exec_simple_cmd(struct ossp_stream *os,
+ enum ossp_opcode opcode, void *carg, void *rarg)
+{
+ return exec_cmd(os, opcode,
+ carg, ossp_arg_sizes[opcode].carg_size, NULL, 0,
+ rarg, ossp_arg_sizes[opcode].rarg_size, NULL, NULL, -1);
+}
+
+static int ioctl_prep_uarg(fuse_req_t req, void *in, size_t in_sz, void *out,
+ size_t out_sz, void *uarg, const void *in_buf,
+ size_t in_bufsz, size_t out_bufsz)
+{
+ struct iovec in_iov = { }, out_iov = { };
+ int retry = 0;
+
+ if (in) {
+ if (!in_bufsz) {
+ in_iov.iov_base = uarg;
+ in_iov.iov_len = in_sz;
+ retry = 1;
+ } else {
+ assert(in_bufsz == in_sz);
+ memcpy(in, in_buf, in_sz);
+ }
+ }
+
+ if (out) {
+ if (!out_bufsz) {
+ out_iov.iov_base = uarg;
+ out_iov.iov_len = out_sz;
+ retry = 1;
+ } else
+ assert(out_bufsz == out_sz);
+ }
+
+ if (retry)
+ fuse_reply_ioctl_retry(req, &in_iov, 1, &out_iov, 1);
+
+ return retry;
+}
+
+#define PREP_UARG(inp, outp) do { \
+ if (ioctl_prep_uarg(req, (inp), sizeof(*(inp)), \
+ (outp), sizeof(*(outp)), uarg, \
+ in_buf, in_bufsz, out_bufsz)) \
+ return; \
+} while (0)
+
+#define IOCTL_RETURN(result, outp) do { \
+ if ((outp) != NULL) \
+ fuse_reply_ioctl(req, result, (outp), sizeof(*(outp))); \
+ else \
+ fuse_reply_ioctl(req, result, NULL, 0); \
+ return; \
+} while (0)
+
+
+/***************************************************************************
+ * Mixer implementation
+ */
+
+static void put_mixer_real(struct ossp_mixer *mixer)
+{
+ if (!--mixer->refcnt) {
+ dbg0("DESTROY mixer(%d)", mixer->pgrp);
+ list_del_init(&mixer->link);
+ list_del_init(&mixer->delayed_put_link);
+ free(mixer);
+ nr_mixers--;
+
+ /*
+ * If exit_on_idle, mixer for pgrp0 is touched during
+ * init and each stream has mixer attached. As mixers
+ * are destroyed after they have been idle for
+ * MIXER_PUT_DELAY seconds, we can use it for idle
+ * detection. Note that this might race with
+ * concurrent open. The race is inherent.
+ */
+ if (exit_on_idle && !nr_mixers) {
+ info("idle, exiting");
+ exit(0);
+ }
+ }
+}
+
+static struct ossp_mixer *get_mixer(pid_t pgrp)
+{
+ struct ossp_mixer *mixer;
+
+ pthread_mutex_lock(&mutex);
+
+ /* is there a matching one? */
+ mixer = find_mixer_locked(pgrp);
+ if (mixer) {
+ if (list_empty(&mixer->delayed_put_link))
+ mixer->refcnt++;
+ else
+ list_del_init(&mixer->delayed_put_link);
+ goto out_unlock;
+ }
+
+ /* reap delayed put list if there are too many mixers */
+ while (nr_mixers > 2 * max_streams &&
+ !list_empty(&mixer_delayed_put_head)) {
+ struct ossp_mixer *mixer =
+ list_first_entry(&mixer_delayed_put_head,
+ struct ossp_mixer, delayed_put_link);
+
+ assert(mixer->refcnt == 1);
+ put_mixer_real(mixer);
+ }
+
+ /* create a new one */
+ mixer = calloc(1, sizeof(*mixer));
+ if (!mixer) {
+ warn("failed to allocate mixer for %d", pgrp);
+ mixer = NULL;
+ goto out_unlock;
+ }
+
+ mixer->pgrp = pgrp;
+ INIT_LIST_HEAD(&mixer->link);
+ INIT_LIST_HEAD(&mixer->delayed_put_link);
+ mixer->refcnt = 1;
+ memset(mixer->vol, -1, sizeof(mixer->vol));
+
+ list_add(&mixer->link, mixer_tbl_head(pgrp));
+ nr_mixers++;
+ dbg0("CREATE mixer(%d)", pgrp);
+
+out_unlock:
+ pthread_mutex_unlock(&mutex);
+ return mixer;
+}
+
+static void put_mixer(struct ossp_mixer *mixer)
+{
+ pthread_mutex_lock(&mutex);
+
+ if (mixer) {
+ if (mixer->refcnt == 1) {
+ struct timespec ts;
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ mixer->put_expires = ts.tv_sec + MIXER_PUT_DELAY;
+ list_add_tail(&mixer->delayed_put_link,
+ &mixer_delayed_put_head);
+ pthread_cond_signal(&mixer_delayed_put_cond);
+ } else
+ put_mixer_real(mixer);
+ }
+
+ pthread_mutex_unlock(&mutex);
+}
+
+static void *mixer_delayed_put_worker(void *arg)
+{
+ struct ossp_mixer *mixer;
+ struct timespec ts;
+ time_t now;
+
+ pthread_mutex_lock(&mutex);
+again:
+ clock_gettime(CLOCK_REALTIME, &ts);
+ now = ts.tv_sec;
+
+ mixer = NULL;
+ while (!list_empty(&mixer_delayed_put_head)) {
+ mixer = list_first_entry(&mixer_delayed_put_head,
+ struct ossp_mixer, delayed_put_link);
+
+ if (now <= mixer->put_expires)
+ break;
+
+ assert(mixer->refcnt == 1);
+ put_mixer_real(mixer);
+ mixer = NULL;
+ }
+
+ if (mixer) {
+ ts.tv_sec = mixer->put_expires + 1;
+ pthread_cond_timedwait(&mixer_delayed_put_cond, &mutex, &ts);
+ } else
+ pthread_cond_wait(&mixer_delayed_put_cond, &mutex);
+
+ goto again;
+}
+
+static void init_mixer_cmd(struct ossp_mixer_cmd *mxcmd,
+ struct ossp_mixer *mixer)
+{
+ memset(mxcmd, 0, sizeof(*mxcmd));
+ memset(&mxcmd->set.vol, -1, sizeof(mxcmd->set.vol));
+ mxcmd->mixer = mixer;
+ mxcmd->out_dir = -1;
+}
+
+static int exec_mixer_cmd(struct ossp_mixer_cmd *mxcmd, struct ossp_stream *os)
+{
+ int i, j, rc;
+
+ /*
+ * Set pending flags before trying to execute mixer command.
+ * Combined with lock release order in exec_cmd(), this
+ * guarantees that the mixer command will be executed
+ * immediately or when the current command completes.
+ */
+ pthread_mutex_lock(&mixer_mutex);
+ os->mixer_pending = 1;
+ for_each_vol(i, j)
+ if (mxcmd->set.vol[i][j] >= 0)
+ os->vol_set[i][j] = mxcmd->set.vol[i][j];
+ pthread_mutex_unlock(&mixer_mutex);
+
+ rc = exec_simple_cmd(os, OSSP_MIXER, NULL, NULL);
+ if (rc >= 0) {
+ dbg0_os(os, "volume set=%d/%d:%d/%d get=%d/%d:%d/%d",
+ mxcmd->set.vol[PLAY][LEFT], mxcmd->set.vol[PLAY][RIGHT],
+ mxcmd->set.vol[REC][LEFT], mxcmd->set.vol[REC][RIGHT],
+ os->vol[PLAY][LEFT], os->vol[PLAY][RIGHT],
+ os->vol[REC][LEFT], os->vol[REC][RIGHT]);
+ } else if (rc != -EBUSY)
+ warn_ose(os, rc, "mixer command failed");
+
+ return rc;
+}
+
+static void finish_mixer_cmd(struct ossp_mixer_cmd *mxcmd)
+{
+ struct ossp_mixer *mixer = mxcmd->mixer;
+ struct ossp_stream *os;
+ int dir = mxcmd->out_dir;
+ int vol[2][2] = { };
+ int cnt[2][2] = { };
+ int i, j;
+
+ pthread_mutex_lock(&mixer_mutex);
+
+ /* get volume of all streams attached to this mixer */
+ pthread_mutex_lock(&mutex);
+ list_for_each_entry(os, os_pgrp_tbl_head(mixer->pgrp), pgrp_link) {
+ if (os->pgrp != mixer->pgrp)
+ continue;
+ for_each_vol(i, j) {
+ if (os->vol[i][j] < 0)
+ continue;
+ vol[i][j] += os->vol[i][j];
+ cnt[i][j]++;
+ }
+ }
+ pthread_mutex_unlock(&mutex);
+
+ /* calculate the summary volume values */
+ for_each_vol(i, j) {
+ if (mxcmd->set.vol[i][j] >= 0)
+ vol[i][j] = mxcmd->set.vol[i][j];
+ else if (cnt[i][j])
+ vol[i][j] = vol[i][j] / cnt[i][j];
+ else if (mixer->vol[i][j] >= 0)
+ vol[i][j] = mixer->vol[i][j];
+ else
+ vol[i][j] = 100;
+
+ vol[i][j] = min(max(0, vol[i][j]), 100);
+ }
+
+ if (dir >= 0)
+ mxcmd->rvol = vol[dir][LEFT] | (vol[dir][RIGHT] << 8);
+
+ pthread_mutex_unlock(&mixer_mutex);
+}
+
+static void mixer_simple_ioctl(fuse_req_t req, struct ossp_mixer *mixer,
+ unsigned cmd, void *uarg, const void *in_buf,
+ size_t in_bufsz, size_t out_bufsz,
+ int *not_minep)
+{
+ const char *id = "OSS Proxy", *name = "Mixer";
+ int i;
+
+ switch (cmd) {
+ case SOUND_MIXER_INFO: {
+ struct mixer_info info = { };
+
+ PREP_UARG(NULL, &info);
+ strncpy(info.id, id, sizeof(info.id) - 1);
+ strncpy(info.name, name, sizeof(info.name) - 1);
+ info.modify_counter = mixer->modify_counter;
+ IOCTL_RETURN(0, &info);
+ }
+
+ case SOUND_OLD_MIXER_INFO: {
+ struct _old_mixer_info info = { };
+
+ PREP_UARG(NULL, &info);
+ strncpy(info.id, id, sizeof(info.id) - 1);
+ strncpy(info.name, name, sizeof(info.name) - 1);
+ IOCTL_RETURN(0, &info);
+ }
+
+ case OSS_GETVERSION:
+ i = SNDRV_OSS_VERSION;
+ goto puti;
+ case SOUND_MIXER_READ_DEVMASK:
+ case SOUND_MIXER_READ_STEREODEVS:
+ i = SOUND_MASK_PCM | SOUND_MASK_IGAIN;
+ goto puti;
+ case SOUND_MIXER_READ_CAPS:
+ i = SOUND_CAP_EXCL_INPUT;
+ goto puti;
+ case SOUND_MIXER_READ_RECMASK:
+ case SOUND_MIXER_READ_RECSRC:
+ i = SOUND_MASK_IGAIN;
+ goto puti;
+ puti:
+ PREP_UARG(NULL, &i);
+ IOCTL_RETURN(0, &i);
+
+ case SOUND_MIXER_WRITE_RECSRC:
+ IOCTL_RETURN(0, NULL);
+
+ default:
+ *not_minep = 1;
+ return;
+ }
+ assert(0);
+}
+
+static void mixer_do_ioctl(fuse_req_t req, struct ossp_mixer *mixer,
+ unsigned cmd, void *uarg, const void *in_buf,
+ size_t in_bufsz, size_t out_bufsz)
+{
+ struct ossp_mixer_cmd mxcmd;
+ struct ossp_stream *os, **osa;
+ int not_mine = 0;
+ int slot = cmd & 0xff, dir;
+ int nr_os;
+ int i, rc;
+
+ mixer_simple_ioctl(req, mixer, cmd, uarg, in_buf, in_bufsz, out_bufsz,
+ ¬_mine);
+ if (!not_mine)
+ return;
+
+ rc = -ENXIO;
+ if (!(cmd & (SIOC_IN | SIOC_OUT)))
+ goto err;
+
+ /*
+ * Okay, it's not one of the easy ones. Build mxcmd for
+ * actual volume control.
+ */
+ if (cmd & SIOC_IN)
+ PREP_UARG(&i, &i);
+ else
+ PREP_UARG(NULL, &i);
+
+ switch (slot) {
+ case SOUND_MIXER_PCM:
+ dir = PLAY;
+ break;
+ case SOUND_MIXER_IGAIN:
+ dir = REC;
+ break;
+ default:
+ i = 0;
+ IOCTL_RETURN(0, &i);
+ }
+
+ init_mixer_cmd(&mxcmd, mixer);
+
+ if (cmd & SIOC_IN) {
+ unsigned l, r;
+
+ rc = -EINVAL;
+ l = i & 0xff;
+ r = (i >> 8) & 0xff;
+ if (l > 100 || r > 100)
+ goto err;
+
+ mixer->vol[dir][LEFT] = mxcmd.set.vol[dir][LEFT] = l;
+ mixer->vol[dir][RIGHT] = mxcmd.set.vol[dir][RIGHT] = r;
+ }
+ mxcmd.out_dir = dir;
+
+ /*
+ * Apply volume conrol
+ */
+ /* acquire target streams */
+ pthread_mutex_lock(&mutex);
+ osa = calloc(max_streams, sizeof(osa[0]));
+ if (!osa) {
+ pthread_mutex_unlock(&mutex);
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ nr_os = 0;
+ list_for_each_entry(os, os_pgrp_tbl_head(mixer->pgrp), pgrp_link) {
+ if (os->pgrp == mixer->pgrp) {
+ osa[nr_os++] = os;
+ os->refcnt++;
+ }
+ }
+
+ pthread_mutex_unlock(&mutex);
+
+ /* execute mxcmd for each stream and put it */
+ for (i = 0; i < nr_os; i++) {
+ exec_mixer_cmd(&mxcmd, osa[i]);
+ put_os(osa[i]);
+ }
+
+ finish_mixer_cmd(&mxcmd);
+ free(osa);
+
+ IOCTL_RETURN(0, out_bufsz ? &mxcmd.rvol : NULL);
+
+err:
+ fuse_reply_err(req, -rc);
+}
+
+static void mixer_open(fuse_req_t req, struct fuse_file_info *fi)
+{
+ pid_t pid = fuse_req_ctx(req)->pid, pgrp;
+ struct ossp_mixer *mixer;
+ int rc;
+
+ rc = get_proc_self_info(pid, &pgrp, NULL, 0);
+ if (rc) {
+ err_e(rc, "get_proc_self_info(%d) failed", pid);
+ fuse_reply_err(req, -rc);
+ return;
+ }
+
+ mixer = get_mixer(pgrp);
+ fi->fh = pgrp;
+
+ if (mixer)
+ fuse_reply_open(req, fi);
+ else
+ fuse_reply_err(req, ENOMEM);
+}
+
+static void mixer_ioctl(fuse_req_t req, int signed_cmd, void *uarg,
+ struct fuse_file_info *fi, unsigned int flags,
+ const void *in_buf, size_t in_bufsz, size_t out_bufsz)
+{
+ struct ossp_mixer *mixer;
+
+ mixer = find_mixer(fi->fh);
+ if (!mixer) {
+ fuse_reply_err(req, EBADF);
+ return;
+ }
+
+ mixer_do_ioctl(req, mixer, signed_cmd, uarg, in_buf, in_bufsz,
+ out_bufsz);
+}
+
+static void mixer_release(fuse_req_t req, struct fuse_file_info *fi)
+{
+ struct ossp_mixer *mixer;
+
+ mixer = find_mixer(fi->fh);
+ if (mixer) {
+ put_mixer(mixer);
+ fuse_reply_err(req, 0);
+ } else
+ fuse_reply_err(req, EBADF);
+}
+
+
+/***************************************************************************
+ * Stream implementation
+ */
+
+static int alloc_os(size_t stream_size, size_t mmap_size, pid_t pid, uid_t pgrp,
+ uid_t uid, gid_t gid, int cmd_sock,
+ const int *notify, struct fuse_session *se,
+ struct ossp_stream **osp)
+{
+ struct ossp_uid_cnt *tmp_ucnt, *ucnt = NULL;
+ struct ossp_stream *os;
+ int rc;
+
+ assert(stream_size >= sizeof(struct ossp_stream));
+ os = calloc(1, stream_size);
+ if (!os)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&os->link);
+ INIT_LIST_HEAD(&os->pgrp_link);
+ INIT_LIST_HEAD(&os->notify_link);
+ os->refcnt = 1;
+
+ rc = -pthread_mutex_init(&os->cmd_mutex, NULL);
+ if (rc)
+ goto err_free;
+
+ rc = -pthread_mutex_init(&os->mmap_mutex, NULL);
+ if (rc)
+ goto err_destroy_cmd_mutex;
+
+ pthread_mutex_lock(&mutex);
+
+ list_for_each_entry(tmp_ucnt, &uid_cnt_list, link)
+ if (tmp_ucnt->uid == uid) {
+ ucnt = tmp_ucnt;
+ break;
+ }
+ if (!ucnt) {
+ rc = -ENOMEM;
+ ucnt = calloc(1, sizeof(*ucnt));
+ if (!ucnt)
+ goto err_unlock;
+ ucnt->uid = uid;
+ list_add(&ucnt->link, &uid_cnt_list);
+ }
+
+ rc = -EBUSY;
+ if (ucnt->nr_os + 1 > umax_streams)
+ goto err_unlock;
+
+ /* everything looks fine, allocate id and init stream */
+ rc = -EBUSY;
+ os->id = find_next_zero_bit(os_id_bitmap, max_streams, 0);
+ if (os->id >= max_streams)
+ goto err_unlock;
+ __set_bit(os->id, os_id_bitmap);
+
+ os->cmd_fd = cmd_sock;
+ os->notify_tx = notify[1];
+ os->notify_rx = notify[0];
+ os->pid = pid;
+ os->pgrp = pgrp;
+ os->uid = uid;
+ os->gid = gid;
+ if (mmap_size) {
+ os->mmap_off = os->id * mmap_size;
+ os->mmap_size = mmap_size;
+ }
+ os->ucnt = ucnt;
+ os->se = se;
+
+ memset(os->vol, -1, sizeof(os->vol));
+ memset(os->vol_set, -1, sizeof(os->vol));
+
+ list_add(&os->link, os_tbl_head(os->id));
+ list_add(&os->pgrp_link, os_pgrp_tbl_head(os->pgrp));
+
+ ucnt->nr_os++;
+ *osp = os;
+ pthread_mutex_unlock(&mutex);
+ return 0;
+
+err_unlock:
+ pthread_mutex_unlock(&mutex);
+ pthread_mutex_destroy(&os->mmap_mutex);
+err_destroy_cmd_mutex:
+ pthread_mutex_destroy(&os->cmd_mutex);
+err_free:
+ free(os);
+ return rc;
+}
+
+static void shutdown_notification(struct ossp_stream *os)
+{
+ struct ossp_notify obituary = { .magic = OSSP_NOTIFY_MAGIC,
+ .opcode = OSSP_NOTIFY_OBITUARY };
+ ssize_t ret;
+
+ /*
+ * Shutdown notification for this stream. We politely ask
+ * notify_poller to shut the receive side down to avoid racing
+ * with it.
+ */
+ while (os->notify_rx >= 0) {
+ ret = write(os->notify_tx, &obituary, sizeof(obituary));
+ if (ret <= 0) {
+ if (ret == 0)
+ warn_os(os, "unexpected EOF on notify_tx");
+ else if (errno != EPIPE)
+ warn_ose(os, -errno,
+ "unexpected error on notify_tx");
+ close(os->notify_rx);
+ os->notify_rx = -1;
+ break;
+ }
+
+ if (ret != sizeof(obituary))
+ warn_os(os, "short transfer on notify_tx");
+ pthread_cond_wait(¬ify_poller_kill_wait, &mutex);
+ }
+}
+
+static void put_os(struct ossp_stream *os)
+{
+ if (!os)
+ return;
+
+ pthread_mutex_lock(&mutex);
+
+ assert(os->refcnt);
+ if (--os->refcnt) {
+ pthread_mutex_unlock(&mutex);
+ return;
+ }
+
+ os->dead = 1;
+ shutdown_notification(os);
+
+ dbg0_os(os, "DESTROY");
+
+ list_del_init(&os->link);
+ list_del_init(&os->pgrp_link);
+ list_del_init(&os->notify_link);
+ os->ucnt->nr_os--;
+
+ pthread_mutex_unlock(&mutex);
+
+ close(os->cmd_fd);
+ close(os->notify_tx);
+ put_mixer(os->mixer);
+ pthread_mutex_destroy(&os->cmd_mutex);
+ pthread_mutex_destroy(&os->mmap_mutex);
+
+ pthread_mutex_lock(&mutex);
+ dbg1_os(os, "stream dead, requesting reaping");
+ list_add_tail(&os->link, &slave_corpse_list);
+ pthread_cond_signal(&slave_reaper_wait);
+ pthread_mutex_unlock(&mutex);
+}
+
+static void set_extra_env(pid_t pid)
+{
+ char procenviron[32];
+ const int step = 1024;
+ char *data = malloc(step + 1);
+ int ofs = 0;
+ int fd;
+ int ret;
+
+ if (!data)
+ return;
+
+ sprintf(procenviron, "/proc/%d/environ", pid);
+ fd = open(procenviron, O_RDONLY);
+ if (fd < 0)
+ return;
+
+ /*
+ * There should really be a 'read whole file to a newly allocated
+ * buffer' function.
+ */
+ while ((ret = read(fd, data + ofs, step)) > 0) {
+ char *newdata;
+ ofs += ret;
+ newdata = realloc(data, ofs + step + 1);
+ if (!newdata) {
+ ret = -1;
+ break;
+ }
+ data = newdata;
+ }
+ if (ret == 0) {
+ char *ptr = data;
+ /* Append the extra 0 for end condition */
+ data[ofs] = 0;
+
+ while ((ret = strlen(ptr)) > 0) {
+ /*
+ * Copy all PULSE variables and DISPLAY so that
+ * ssh -X remotehost 'mplayer -ao oss' will work
+ */
+ if (!strncmp(ptr, "DISPLAY=", 8) ||
+ !strncmp(ptr, "PULSE_", 6))
+ putenv(ptr);
+ ptr += ret + 1;
+ }
+ }
+
+ free(data);
+ close(fd);
+}
+
+#ifndef GIOVANNI
+int contapid = 13000;
+#endif// GIOVANNI
+
+static int create_os(const char *slave_path,
+ size_t stream_size, size_t mmap_size,
+ pid_t pid, pid_t pgrp, uid_t uid, gid_t gid,
+ struct fuse_session *se, struct ossp_stream **osp)
+{
+ static pthread_mutex_t create_mutex = PTHREAD_MUTEX_INITIALIZER;
+ int cmd_sock[2] = { -1, -1 };
+ int notify_sock[2] = { -1, -1 };
+ struct ossp_stream *os = NULL;
+ struct epoll_event ev = { };
+ int i, rc;
+
+ /*
+ * Only one thread can be creating a stream. This is to avoid
+ * leaking unwanted fds into slaves.
+ */
+ pthread_mutex_lock(&create_mutex);
+
+ /* prepare communication channels */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd_sock) ||
+ socketpair(AF_UNIX, SOCK_STREAM, 0, notify_sock)) {
+ rc = -errno;
+ warn_e(rc, "failed to create slave command channel");
+ goto close_all;
+ }
+
+ if (fcntl(notify_sock[0], F_SETFL, O_NONBLOCK) < 0) {
+ rc = -errno;
+ warn_e(rc, "failed to set NONBLOCK on notify sock");
+ goto close_all;
+ }
+
+ /*
+ * Alloc stream which will be responsible for all server side
+ * resources from now on.
+ */
+ rc = alloc_os(stream_size, mmap_size, pid, pgrp, uid, gid, cmd_sock[0],
+ notify_sock, se, &os);
+ if (rc) {
+ warn_e(rc, "failed to allocate stream for %d", pid);
+ goto close_all;
+ }
+
+ rc = -ENOMEM;
+ os->mixer = get_mixer(pgrp);
+ if (!os->mixer)
+ goto put_os;
+
+ /*
+ * Register notification. If successful, notify_poller has
+ * custody of notify_rx fd.
+ */
+ pthread_mutex_lock(&mutex);
+ list_add(&os->notify_link, os_notify_tbl_head(os->notify_rx));
+ pthread_mutex_unlock(&mutex);
+
+#ifndef GIOVANNI
+ os->slave_pid = contapid;
+ contapid++;
+ if(contapid > 30000)
+ contapid=13000;
+#endif //GIOVANNI
+
+//#ifdef GIOVANNI
+ ev.events = EPOLLIN;
+ ev.data.fd = notify_sock[0];
+ if (epoll_ctl(notify_epfd, EPOLL_CTL_ADD, notify_sock[0], &ev)) {
+ /*
+ * Without poller watching this notify sock, poller
+ * shutdown sequence in shutdown_notification() can't
+ * be used. Kill notification rx manually.
+ */
+ rc = -errno;
+ warn_ose(os, rc, "failed to add notify epoll");
+ close(os->notify_rx);
+ os->notify_rx = -1;
+ goto put_os;
+ }
+
+ /* start slave */
+ os->slave_pid = fork();
+ if (os->slave_pid < 0) {
+ rc = -errno;
+ warn_ose(os, rc, "failed to fork slave");
+ goto put_os;
+ }
+
+ if (os->slave_pid == 0) {
+ /* child */
+ char id_str[2][16], fd_str[3][16];
+ char mmap_off_str[32], mmap_size_str[32];
+ char log_str[16], slave_path_copy[PATH_MAX];
+ char *argv[] = { slave_path_copy, "-u", id_str[0],
+ "-g", id_str[1], "-c", fd_str[0],
+ "-n", fd_str[1], "-m", fd_str[2],
+ "-o", mmap_off_str, "-s", mmap_size_str,
+ "-l", log_str, NULL, NULL };
+ struct passwd *pwd;
+
+ /* drop stuff we don't need */
+ if (close(cmd_sock[0]) || close(notify_sock[0]))
+ fatal_e(-errno, "failed to close server pipe fds");
+
+#ifdef OSSP_MMAP
+ if (!mmap_size)
+ close(fuse_mmap_fd(se));
+#endif
+
+ clearenv();
+ pwd = getpwuid(os->uid);
+ if (pwd) {
+ setenv("LOGNAME", pwd->pw_name, 1);
+ setenv("USER", pwd->pw_name, 1);
+ setenv("HOME", pwd->pw_dir, 1);
+ }
+ /* Set extra environment variables from the caller */
+ set_extra_env(pid);
+
+ /* prep and exec */
+ slave_path_copy[sizeof(slave_path_copy) - 1] = '\0';
+ strncpy(slave_path_copy, slave_path, sizeof(slave_path_copy) - 1);
+ if (slave_path_copy[sizeof(slave_path_copy) - 1] != '\0') {
+ rc = -errno;
+ err_ose(os, rc, "slave path too long");
+ goto child_fail;
+ }
+
+ snprintf(id_str[0], sizeof(id_str[0]), "%d", os->uid);
+ snprintf(id_str[1], sizeof(id_str[0]), "%d", os->gid);
+ snprintf(fd_str[0], sizeof(fd_str[0]), "%d", cmd_sock[1]);
+ snprintf(fd_str[1], sizeof(fd_str[1]), "%d", notify_sock[1]);
+ snprintf(fd_str[2], sizeof(fd_str[2]), "%d",
+#ifdef OSSP_MMAP
+ mmap_size ? fuse_mmap_fd(se) :
+#endif
+ -1);
+ snprintf(mmap_off_str, sizeof(mmap_off_str), "0x%llx",
+ (unsigned long long)os->mmap_off);
+ snprintf(mmap_size_str, sizeof(mmap_size_str), "0x%zx",
+ mmap_size);
+ snprintf(log_str, sizeof(log_str), "%d", ossp_log_level);
+ if (ossp_log_timestamp)
+ argv[ARRAY_SIZE(argv) - 2] = "-t";
+
+ execv(slave_path, argv);
+ rc = -errno;
+ err_ose(os, rc, "execv failed for <%d>", pid);
+ child_fail:
+ _exit(1);
+ }
+//#endif //GIOVANNI
+
+ /* turn on CLOEXEC on all server side fds */
+ if (fcntl(os->cmd_fd, F_SETFD, FD_CLOEXEC) < 0 ||
+ fcntl(os->notify_tx, F_SETFD, FD_CLOEXEC) < 0 ||
+ fcntl(os->notify_rx, F_SETFD, FD_CLOEXEC) < 0) {
+ rc = -errno;
+ err_ose(os, rc, "failed to set CLOEXEC on server side fds");
+ goto put_os;
+ }
+
+ dbg0_os(os, "CREATE slave=%d %s", os->slave_pid, slave_path);
+ dbg0_os(os, " client=%d cmd=%d:%d notify=%d:%d mmap=%d:0x%llx:%zu",
+ pid, cmd_sock[0], cmd_sock[1], notify_sock[0], notify_sock[1],
+#ifdef OSSP_MMAP
+ os->mmap_size ? fuse_mmap_fd(se) :
+#endif
+ -1,
+ (unsigned long long)os->mmap_off, os->mmap_size);
+
+ *osp = os;
+ rc = 0;
+ goto close_client_fds;
+
+put_os:
+ put_os(os);
+close_client_fds:
+ close(cmd_sock[1]);
+ pthread_mutex_unlock(&create_mutex);
+ return rc;
+
+close_all:
+ for (i = 0; i < 2; i++) {
+ close(cmd_sock[i]);
+ close(notify_sock[i]);
+ }
+ pthread_mutex_unlock(&create_mutex);
+ return rc;
+}
+
+static void dsp_open_common(fuse_req_t req, struct fuse_file_info *fi,
+ struct fuse_session *se)
+{
+ const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req);
+ struct ossp_dsp_open_arg arg = { };
+ struct ossp_stream *os = NULL;
+ struct ossp_mixer *mixer;
+ struct ossp_dsp_stream *dsps;
+ struct ossp_mixer_cmd mxcmd;
+ pid_t pgrp;
+ ssize_t ret;
+
+ ret = get_proc_self_info(fuse_ctx->pid, &pgrp, NULL, 0);
+ if (ret) {
+ err_e(ret, "get_proc_self_info(%d) failed", fuse_ctx->pid);
+ goto err;
+ }
+
+ ret = create_os(dsp_slave_path, sizeof(*dsps), DSPS_MMAP_SIZE,
+ fuse_ctx->pid, pgrp, fuse_ctx->uid, fuse_ctx->gid,
+ se, &os);
+ if (ret)
+ goto err;
+ dsps = os_to_dsps(os);
+ mixer = os->mixer;
+
+ switch (fi->flags & O_ACCMODE) {
+ case O_WRONLY:
+ dsps->rw |= 1 << PLAY;
+ break;
+ case O_RDONLY:
+ dsps->rw |= 1 << REC;
+ break;
+ case O_RDWR:
+ dsps->rw |= (1 << PLAY) | (1 << REC);
+ break;
+ default:
+ assert(0);
+ }
+
+ arg.flags = fi->flags;
+ arg.opener_pid = os->pid;
+ ret = exec_simple_cmd(&dsps->os, OSSP_DSP_OPEN, &arg, NULL);
+ if (ret < 0) {
+ put_os(os);
+ goto err;
+ }
+
+ memcpy(os->vol, mixer->vol, sizeof(os->vol));
+ if (os->vol[PLAY][0] >= 0 || os->vol[REC][0] >= 0) {
+ init_mixer_cmd(&mxcmd, mixer);
+ memcpy(mxcmd.set.vol, os->vol, sizeof(os->vol));
+ exec_mixer_cmd(&mxcmd, os);
+ finish_mixer_cmd(&mxcmd);
+ }
+
+ fi->direct_io = 1;
+ fi->nonseekable = 1;
+ fi->fh = os->id;
+
+ fuse_reply_open(req, fi);
+ return;
+
+err:
+ fuse_reply_err(req, -ret);
+}
+
+static void dsp_open(fuse_req_t req, struct fuse_file_info *fi)
+{
+ dsp_open_common(req, fi, dsp_se);
+}
+
+static void adsp_open(fuse_req_t req, struct fuse_file_info *fi)
+{
+ dsp_open_common(req, fi, adsp_se);
+}
+
+static void dsp_release(fuse_req_t req, struct fuse_file_info *fi)
+{
+ struct ossp_stream *os;
+
+ os = find_os(fi->fh);
+ if (os) {
+ put_os(os);
+ fuse_reply_err(req, 0);
+ } else
+ fuse_reply_err(req, EBADF);
+}
+
+static void dsp_read(fuse_req_t req, size_t size, off_t off,
+ struct fuse_file_info *fi)
+{
+ struct ossp_dsp_rw_arg arg = { };
+ struct ossp_stream *os;
+ struct ossp_dsp_stream *dsps;
+ void *buf = NULL;
+ ssize_t ret;
+
+ ret = -EBADF;
+ os = find_os(fi->fh);
+ if (!os)
+ goto out;
+ dsps = os_to_dsps(os);
+
+ ret = -EINVAL;
+ if (!(dsps->rw & (1 << REC)))
+ goto out;
+
+ ret = -ENXIO;
+ if (dsps->mmapped)
+ goto out;
+
+ ret = -ENOMEM;
+ buf = malloc(size);
+ if (!buf)
+ goto out;
+
+ arg.nonblock = (fi->flags & O_NONBLOCK) || dsps->nonblock;
+
+ ret = exec_cmd(os, OSSP_DSP_READ, &arg, sizeof(arg),
+ NULL, 0, NULL, 0, buf, &size, -1);
+out:
+ if (ret >= 0)
+ fuse_reply_buf(req, buf, size);
+ else
+ fuse_reply_err(req, -ret);
+
+ free(buf);
+}
+
+static void dsp_write(fuse_req_t req, const char *buf, size_t size, off_t off,
+ struct fuse_file_info *fi)
+{
+ struct ossp_dsp_rw_arg arg = { };
+ struct ossp_stream *os;
+ struct ossp_dsp_stream *dsps;
+ ssize_t ret;
+
+ ret = -EBADF;
+ os = find_os(fi->fh);
+ if (!os)
+ goto out;
+ dsps = os_to_dsps(os);
+
+ ret = -EINVAL;
+ if (!(dsps->rw & (1 << PLAY)))
+ goto out;
+
+ ret = -ENXIO;
+ if (dsps->mmapped)
+ goto out;
+
+ arg.nonblock = (fi->flags & O_NONBLOCK) || dsps->nonblock;
+
+ ret = exec_cmd(os, OSSP_DSP_WRITE, &arg, sizeof(arg),
+ buf, size, NULL, 0, NULL, NULL, -1);
+out:
+ if (ret >= 0)
+ fuse_reply_write(req, ret);
+ else
+ fuse_reply_err(req, -ret);
+}
+
+static void dsp_poll(fuse_req_t req, struct fuse_file_info *fi,
+ struct fuse_pollhandle *ph)
+{
+ int notify = ph != NULL;
+ unsigned revents = 0;
+ struct ossp_stream *os;
+ ssize_t ret;
+
+ ret = -EBADF;
+ os = find_os(fi->fh);
+ if (!os)
+ goto out;
+
+ if (ph) {
+ pthread_mutex_lock(&mutex);
+ if (os->ph)
+ fuse_pollhandle_destroy(os->ph);
+ os->ph = ph;
+ pthread_mutex_unlock(&mutex);
+ }
+
+ ret = exec_simple_cmd(os, OSSP_DSP_POLL, ¬ify, &revents);
+out:
+ if (ret >= 0)
+ fuse_reply_poll(req, revents);
+ else
+ fuse_reply_err(req, -ret);
+}
+
+static void dsp_ioctl(fuse_req_t req, int signed_cmd, void *uarg,
+ struct fuse_file_info *fi, unsigned int flags,
+ const void *in_buf, size_t in_bufsz, size_t out_bufsz)
+{
+ /* some ioctl constants are long and has the highest bit set */
+ unsigned cmd = signed_cmd;
+ struct ossp_stream *os;
+ struct ossp_dsp_stream *dsps;
+ enum ossp_opcode op;
+ ssize_t ret;
+ int i;
+
+ ret = -EBADF;
+ os = find_os(fi->fh);
+ if (!os)
+ goto err;
+ dsps = os_to_dsps(os);
+
+ /* mixer commands are allowed on DSP devices */
+ if (((cmd >> 8) & 0xff) == 'M') {
+ mixer_do_ioctl(req, os->mixer, cmd, uarg, in_buf, in_bufsz,
+ out_bufsz);
+ return;
+ }
+
+ /* and the rest */
+ switch (cmd) {
+ case OSS_GETVERSION:
+ i = SNDRV_OSS_VERSION;
+ PREP_UARG(NULL, &i);
+ IOCTL_RETURN(0, &i);
+
+ case SNDCTL_DSP_GETCAPS:
+ i = DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
+#ifdef OSSP_MMAP
+ DSP_CAP_MMAP |
+#endif
+ DSP_CAP_MULTI;
+ PREP_UARG(NULL, &i);
+ IOCTL_RETURN(0, &i);
+
+ case SNDCTL_DSP_NONBLOCK:
+ dsps->nonblock = 1;
+ ret = 0;
+ IOCTL_RETURN(0, NULL);
+
+ case SNDCTL_DSP_RESET: op = OSSP_DSP_RESET; goto nd;
+ case SNDCTL_DSP_SYNC: op = OSSP_DSP_SYNC; goto nd;
+ case SNDCTL_DSP_POST: op = OSSP_DSP_POST; goto nd;
+ nd:
+ ret = exec_simple_cmd(&dsps->os, op, NULL, NULL);
+ if (ret)
+ goto err;
+ IOCTL_RETURN(0, NULL);
+
+ case SOUND_PCM_READ_RATE: op = OSSP_DSP_GET_RATE; goto ri;
+ case SOUND_PCM_READ_BITS: op = OSSP_DSP_GET_FORMAT; goto ri;
+ case SOUND_PCM_READ_CHANNELS: op = OSSP_DSP_GET_CHANNELS; goto ri;
+ case SNDCTL_DSP_GETBLKSIZE: op = OSSP_DSP_GET_BLKSIZE; goto ri;
+ case SNDCTL_DSP_GETFMTS: op = OSSP_DSP_GET_FORMATS; goto ri;
+ case SNDCTL_DSP_GETTRIGGER: op = OSSP_DSP_GET_TRIGGER; goto ri;
+ ri:
+ PREP_UARG(NULL, &i);
+ ret = exec_simple_cmd(&dsps->os, op, NULL, &i);
+ if (ret)
+ goto err;
+ IOCTL_RETURN(0, &i);
+
+ case SNDCTL_DSP_SPEED: op = OSSP_DSP_SET_RATE; goto wi;
+ case SNDCTL_DSP_SETFMT: op = OSSP_DSP_SET_FORMAT; goto wi;
+ case SNDCTL_DSP_CHANNELS: op = OSSP_DSP_SET_CHANNELS; goto wi;
+ case SNDCTL_DSP_SUBDIVIDE: op = OSSP_DSP_SET_SUBDIVISION; goto wi;
+ wi:
+ PREP_UARG(&i, &i);
+ ret = exec_simple_cmd(&dsps->os, op, &i, &i);
+ if (ret)
+ goto err;
+ IOCTL_RETURN(0, &i);
+
+ case SNDCTL_DSP_STEREO:
+ PREP_UARG(NULL, &i);
+ i = 2;
+ ret = exec_simple_cmd(&dsps->os, OSSP_DSP_SET_CHANNELS, &i, &i);
+ i--;
+ if (ret)
+ goto err;
+ IOCTL_RETURN(0, &i);
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ PREP_UARG(&i, NULL);
+ ret = exec_simple_cmd(&dsps->os,
+ OSSP_DSP_SET_FRAGMENT, &i, NULL);
+ if (ret)
+ goto err;
+ IOCTL_RETURN(0, NULL);
+
+ case SNDCTL_DSP_SETTRIGGER:
+ PREP_UARG(&i, NULL);
+ ret = exec_simple_cmd(&dsps->os,
+ OSSP_DSP_SET_TRIGGER, &i, NULL);
+ if (ret)
+ goto err;
+ IOCTL_RETURN(0, NULL);
+
+ case SNDCTL_DSP_GETOSPACE:
+ case SNDCTL_DSP_GETISPACE: {
+ struct audio_buf_info info;
+
+ ret = -EINVAL;
+ if (cmd == SNDCTL_DSP_GETOSPACE) {
+ if (!(dsps->rw & (1 << PLAY)))
+ goto err;
+ op = OSSP_DSP_GET_OSPACE;
+ } else {
+ if (!(dsps->rw & (1 << REC)))
+ goto err;
+ op = OSSP_DSP_GET_ISPACE;
+ }
+
+ PREP_UARG(NULL, &info);
+ ret = exec_simple_cmd(&dsps->os, op, NULL, &info);
+ if (ret)
+ goto err;
+ IOCTL_RETURN(0, &info);
+ }
+
+ case SNDCTL_DSP_GETOPTR:
+ case SNDCTL_DSP_GETIPTR: {
+ struct count_info info;
+
+ op = cmd == SNDCTL_DSP_GETOPTR ? OSSP_DSP_GET_OPTR
+ : OSSP_DSP_GET_IPTR;
+ PREP_UARG(NULL, &info);
+ ret = exec_simple_cmd(&dsps->os, op, NULL, &info);
+ if (ret)
+ goto err;
+ IOCTL_RETURN(0, &info);
+ }
+
+ case SNDCTL_DSP_GETODELAY:
+ PREP_UARG(NULL, &i);
+ i = 0;
+ ret = exec_simple_cmd(&dsps->os, OSSP_DSP_GET_ODELAY, NULL, &i);
+ IOCTL_RETURN(ret, &i); /* always copy out result, 0 on err */
+
+ case SOUND_PCM_WRITE_FILTER:
+ case SOUND_PCM_READ_FILTER:
+ ret = -EIO;
+ goto err;
+
+ case SNDCTL_DSP_MAPINBUF:
+ case SNDCTL_DSP_MAPOUTBUF:
+ ret = -EINVAL;
+ goto err;
+
+ case SNDCTL_DSP_SETSYNCRO:
+ case SNDCTL_DSP_SETDUPLEX:
+ case SNDCTL_DSP_PROFILE:
+ IOCTL_RETURN(0, NULL);
+
+ default:
+ warn_os(os, "unknown ioctl 0x%x", cmd);
+ ret = -EINVAL;
+ goto err;
+ }
+ assert(0); /* control shouldn't reach here */
+err:
+ fuse_reply_err(req, -ret);
+}
+
+#ifdef OSSP_MMAP
+static int dsp_mmap_dir(int prot)
+{
+ if (!(prot & PROT_WRITE))
+ return REC;
+ return PLAY;
+}
+
+static void dsp_mmap(fuse_req_t req, void *addr, size_t len, int prot,
+ int flags, off_t offset, struct fuse_file_info *fi,
+ uint64_t mh)
+{
+ int dir = dsp_mmap_dir(prot);
+ struct ossp_dsp_mmap_arg arg = { };
+ struct ossp_stream *os;
+ struct ossp_dsp_stream *dsps;
+ ssize_t ret;
+
+ os = find_os(fi->fh);
+ if (!os) {
+ fuse_reply_err(req, EBADF);
+ return;
+ }
+ dsps = os_to_dsps(os);
+
+ if (!os->mmap_off || len > os->mmap_size / 2) {
+ fuse_reply_err(req, EINVAL);
+ return;
+ }
+
+ pthread_mutex_lock(&os->mmap_mutex);
+
+ ret = -EBUSY;
+ if (dsps->mmapped & (1 << dir))
+ goto out_unlock;
+
+ arg.dir = dir;
+ arg.size = len;
+
+ ret = exec_simple_cmd(os, OSSP_DSP_MMAP, &arg, NULL);
+ if (ret == 0)
+ dsps->mmapped |= 1 << dir;
+
+out_unlock:
+ pthread_mutex_unlock(&os->mmap_mutex);
+
+ if (ret == 0)
+ fuse_reply_mmap(req, os->mmap_off + dir * os->mmap_size / 2, 0);
+ else
+ fuse_reply_err(req, -ret);
+}
+
+static void dsp_munmap(fuse_req_t req, size_t len, struct fuse_file_info *fi,
+ off_t offset, uint64_t mh)
+{
+ struct ossp_stream *os;
+ struct ossp_dsp_stream *dsps;
+ int dir, rc;
+
+ os = find_os(fi->fh);
+ if (!os)
+ goto out;
+ dsps = os_to_dsps(os);
+
+ pthread_mutex_lock(&os->mmap_mutex);
+
+ for (dir = 0; dir < 2; dir++)
+ if (offset == os->mmap_off + dir * os->mmap_size / 2)
+ break;
+ if (dir == 2 || len > os->mmap_size / 2) {
+ warn_os(os, "invalid munmap request "
+ "offset=%llu len=%zu mmapped=0x%x",
+ (unsigned long long)offset, len, dsps->mmapped);
+ goto out_unlock;
+ }
+
+ rc = exec_simple_cmd(os, OSSP_DSP_MUNMAP, &dir, NULL);
+ if (rc)
+ warn_ose(os, rc, "MUNMAP failed for dir=%d", dir);
+
+ dsps->mmapped &= ~(1 << dir);
+
+out_unlock:
+ pthread_mutex_unlock(&os->mmap_mutex);
+out:
+ fuse_reply_none(req);
+}
+#endif
+
+
+/***************************************************************************
+ * Notify poller
+ */
+
+static void *notify_poller(void *arg)
+{
+ struct epoll_event events[1024];
+ int i, nfds;
+
+repeat:
+ nfds = epoll_wait(notify_epfd, events, ARRAY_SIZE(events), -1);
+ for (i = 0; i < nfds; i++) {
+ int do_notify = 0;
+ struct ossp_stream *os;
+ struct ossp_notify notify;
+ ssize_t ret;
+
+ os = find_os_by_notify_rx(events[i].data.fd);
+ if (!os) {
+ err("can't find stream for notify_rx fd %d",
+ events[i].data.fd);
+ epoll_ctl(notify_epfd, EPOLL_CTL_DEL, events[i].data.fd,
+ NULL);
+ /* we don't know what's going on, don't close the fd */
+ continue;
+ }
+
+ while ((ret = read(os->notify_rx,
+ ¬ify, sizeof(notify))) > 0) {
+ if (os->dead)
+ continue;
+ if (ret != sizeof(notify)) {
+ warn_os(os, "short read on notify_rx (%zu, "
+ "expected %zu), killing the stream",
+ ret, sizeof(notify));
+ os->dead = 1;
+ break;
+ }
+ if (notify.magic != OSSP_NOTIFY_MAGIC) {
+ warn_os(os, "invalid magic on notification, "
+ "killing the stream");
+ os->dead = 1;
+ break;
+ }
+
+ if (notify.opcode >= OSSP_NR_NOTIFY_OPCODES)
+ goto unknown;
+
+ dbg1_os(os, "NOTIFY %s", ossp_notify_str[notify.opcode]);
+
+ switch (notify.opcode) {
+ case OSSP_NOTIFY_POLL:
+ do_notify = 1;
+ break;
+ case OSSP_NOTIFY_OBITUARY:
+ os->dead = 1;
+ break;
+ case OSSP_NOTIFY_VOLCHG:
+ pthread_mutex_lock(&mixer_mutex);
+ os->mixer->modify_counter++;
+ pthread_mutex_unlock(&mixer_mutex);
+ break;
+ default:
+ unknown:
+ warn_os(os, "unknown notification %d",
+ notify.opcode);
+ }
+ }
+ if (ret == 0)
+ os->dead = 1;
+ else if (ret < 0 && errno != EAGAIN) {
+ warn_ose(os, -errno, "read fail on notify fd");
+ os->dead = 1;
+ }
+
+ if (!do_notify && !os->dead)
+ continue;
+
+ pthread_mutex_lock(&mutex);
+
+ if (os->ph) {
+ fuse_lowlevel_notify_poll(os->ph);
+ fuse_pollhandle_destroy(os->ph);
+ os->ph = NULL;
+ }
+
+ if (os->dead) {
+ dbg0_os(os, "removing %d from notify poll list",
+ os->notify_rx);
+ epoll_ctl(notify_epfd, EPOLL_CTL_DEL, os->notify_rx,
+ NULL);
+ close(os->notify_rx);
+ os->notify_rx = -1;
+ pthread_cond_broadcast(¬ify_poller_kill_wait);
+ }
+
+ pthread_mutex_unlock(&mutex);
+ }
+ goto repeat;
+}
+
+
+/***************************************************************************
+ * Slave corpse reaper
+ */
+
+static void *slave_reaper(void *arg)
+{
+ struct ossp_stream *os;
+ int status;
+ pid_t pid;
+
+ pthread_mutex_lock(&mutex);
+repeat:
+ while (list_empty(&slave_corpse_list))
+ pthread_cond_wait(&slave_reaper_wait, &mutex);
+
+ os = list_first_entry(&slave_corpse_list, struct ossp_stream, link);
+ list_del_init(&os->link);
+
+ pthread_mutex_unlock(&mutex);
+
+ do {
+ pid = waitpid(os->slave_pid, &status, 0);
+ } while (pid < 0 && errno == EINTR);
+
+ if (pid < 0) {
+ if (errno == ECHILD)
+ warn_ose(os, -errno, "slave %d already gone?",
+ os->slave_pid);
+ else
+ fatal_e(-errno, "waitpid(%d) failed", os->slave_pid);
+ }
+
+ pthread_mutex_lock(&mutex);
+
+ dbg1_os(os, "slave %d reaped", os->slave_pid);
+ __clear_bit(os->id, os_id_bitmap);
+ free(os);
+
+ goto repeat;
+}
+
+
+/***************************************************************************
+ * Stuff to bind and start everything
+ */
+
+static void ossp_daemonize(void)
+{
+ int fd, pfd[2];
+ pid_t pid;
+ ssize_t ret;
+ int err;
+
+ fd = open("/dev/null", O_RDWR);
+ if (fd >= 0) {
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ if (fd > 2)
+ close(fd);
+ }
+
+ if (pipe(pfd))
+ fatal_e(-errno, "failed to create pipe for init wait");
+
+ if (fcntl(pfd[0], F_SETFD, FD_CLOEXEC) < 0 ||
+ fcntl(pfd[1], F_SETFD, FD_CLOEXEC) < 0)
+ fatal_e(-errno, "failed to set CLOEXEC on init wait pipe");
+
+ pid = fork();
+ if (pid < 0)
+ fatal_e(-errno, "failed to fork for daemon");
+
+ if (pid == 0) {
+ close(pfd[0]);
+ init_wait_fd = pfd[1];
+
+ /* be evil, my child */
+ chdir("/");
+ setsid();
+ return;
+ }
+
+ /* wait for init completion and pass over success indication */
+ close(pfd[1]);
+
+ do {
+ ret = read(pfd[0], &err, sizeof(err));
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret == sizeof(err) && err == 0)
+ exit(0);
+
+ fatal("daemon init failed ret=%zd err=%d", ret, err);
+ exit(1);
+}
+
+static void ossp_init_done(void *userdata)
+{
+ /* init complete, notify parent if it's waiting */
+ if (init_wait_fd >= 0) {
+ ssize_t ret;
+ int err = 0;
+
+ ret = write(init_wait_fd, &err, sizeof(err));
+ if (ret != sizeof(err))
+ fatal_e(-errno, "failed to notify init completion, "
+ "ret=%zd", ret);
+ close(init_wait_fd);
+ init_wait_fd = -1;
+ }
+}
+
+static const struct cuse_lowlevel_ops mixer_ops = {
+ .open = mixer_open,
+ .release = mixer_release,
+ .ioctl = mixer_ioctl,
+};
+
+static const struct cuse_lowlevel_ops dsp_ops = {
+ .init_done = ossp_init_done,
+ .open = dsp_open,
+ .release = dsp_release,
+ .read = dsp_read,
+ .write = dsp_write,
+ .poll = dsp_poll,
+ .ioctl = dsp_ioctl,
+#ifdef OSSP_MMAP
+ .mmap = dsp_mmap,
+ .munmap = dsp_munmap,
+#endif
+};
+
+static const struct cuse_lowlevel_ops adsp_ops = {
+ .open = adsp_open,
+ .release = dsp_release,
+ .read = dsp_read,
+ .write = dsp_write,
+ .poll = dsp_poll,
+ .ioctl = dsp_ioctl,
+#ifdef OSSP_MMAP
+ .mmap = dsp_mmap,
+ .munmap = dsp_munmap,
+#endif
+};
+
+static const char *usage =
+"usage: osspd [options]\n"
+"\n"
+"options:\n"
+" --help print this help message\n"
+" --dsp=NAME DSP device name (default dsp)\n"
+" --dsp-maj=MAJ DSP device major number (default 14)\n"
+" --dsp-min=MIN DSP device minor number (default 3)\n"
+" --adsp=NAME Aux DSP device name (default adsp, blank to disable)\n"
+" --adsp-maj=MAJ Aux DSP device major number (default 14)\n"
+" --adsp-min=MIN Aux DSP device minor number (default 12)\n"
+" --mixer=NAME mixer device name (default mixer, blank to disable)\n"
+" --mixer-maj=MAJ mixer device major number (default 14)\n"
+" --mixer-min=MIN mixer device minor number (default 0)\n"
+" --max=MAX maximum number of open streams (default 256)\n"
+" --umax=MAX maximum number of open streams per UID (default --max)\n"
+" --exit-on-idle exit if idle\n"
+" --dsp-slave=PATH DSP slave (default ossp-padsp in the same dir)\n"
+" --log=LEVEL log level (0..6)\n"
+" --timestamp timestamp log messages\n"
+" -v increase verbosity, can be specified multiple times\n"
+" -f Run in foreground (don't daemonize)\n"
+"\n";
+
+struct ossp_param {
+ char *dsp_name;
+ unsigned dsp_major;
+ unsigned dsp_minor;
+ char *adsp_name;
+ unsigned adsp_major;
+ unsigned adsp_minor;
+ char *mixer_name;
+ unsigned mixer_major;
+ unsigned mixer_minor;
+ unsigned max_streams;
+ unsigned umax_streams;
+ char *dsp_slave_path;
+ unsigned log_level;
+ int exit_on_idle;
+ int timestamp;
+ int fg;
+ int help;
+};
+
+#define OSSP_OPT(t, p) { t, offsetof(struct ossp_param, p), 1 }
+
+static const struct fuse_opt ossp_opts[] = {
+ OSSP_OPT("--dsp=%s", dsp_name),
+ OSSP_OPT("--dsp-maj=%u", dsp_major),
+ OSSP_OPT("--dsp-min=%u", dsp_minor),
+ OSSP_OPT("--adsp=%s", adsp_name),
+ OSSP_OPT("--adsp-maj=%u", adsp_major),
+ OSSP_OPT("--adsp-min=%u", adsp_minor),
+ OSSP_OPT("--mixer=%s", mixer_name),
+ OSSP_OPT("--mixer-maj=%u", mixer_major),
+ OSSP_OPT("--mixer-min=%u", mixer_minor),
+ OSSP_OPT("--max=%u", max_streams),
+ OSSP_OPT("--umax=%u", umax_streams),
+ OSSP_OPT("--exit-on-idle", exit_on_idle),
+ OSSP_OPT("--dsp-slave=%s", dsp_slave_path),
+ OSSP_OPT("--timestamp", timestamp),
+ OSSP_OPT("--log=%u", log_level),
+ OSSP_OPT("-f", fg),
+ FUSE_OPT_KEY("-h", 0),
+ FUSE_OPT_KEY("--help", 0),
+ FUSE_OPT_KEY("-v", 1),
+ FUSE_OPT_END
+};
+
+static struct fuse_session *setup_ossp_cuse(const struct cuse_lowlevel_ops *ops,
+ const char *name, int major,
+ int minor, int argc, char **argv)
+{
+ char name_buf[128];
+ const char *bufp = name_buf;
+ struct cuse_info ci = { .dev_major = major, .dev_minor = minor,
+ .dev_info_argc = 1, .dev_info_argv = &bufp,
+ .flags = CUSE_UNRESTRICTED_IOCTL };
+ struct fuse_session *se;
+ int fd;
+
+ snprintf(name_buf, sizeof(name_buf), "DEVNAME=%s", name);
+
+ se = cuse_lowlevel_setup(argc, argv, &ci, ops, NULL, NULL);
+ if (!se) {
+ err("failed to setup %s CUSE", name);
+ return NULL;
+ }
+
+ fd = fuse_chan_fd(fuse_session_next_chan(se, NULL));
+ if (
+#ifdef OSSP_MMAP
+ fd != fuse_mmap_fd(se) &&
+#endif
+ fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
+ err_e(-errno, "failed to set CLOEXEC on %s CUSE fd", name);
+ cuse_lowlevel_teardown(se);
+ return NULL;
+ }
+
+ return se;
+}
+
+static void *cuse_worker(void *arg)
+{
+ struct fuse_session *se = arg;
+ int rc;
+
+ rc = fuse_session_loop_mt(se);
+ cuse_lowlevel_teardown(se);
+
+ return (void *)(unsigned long)rc;
+}
+
+static int process_arg(void *data, const char *arg, int key,
+ struct fuse_args *outargs)
+{
+ struct ossp_param *param = data;
+
+ switch (key) {
+ case 0:
+ fprintf(stderr, usage);
+ param->help = 1;
+ return 0;
+ case 1:
+ param->log_level++;
+ return 0;
+ }
+ return 1;
+}
+
+int main(int argc, char **argv)
+{
+ static struct ossp_param param = {
+ .dsp_name = DFL_DSP_NAME,
+ .dsp_major = DFL_DSP_MAJOR, .dsp_minor = DFL_DSP_MINOR,
+ .adsp_name = DFL_ADSP_NAME,
+ .adsp_major = DFL_ADSP_MAJOR, .adsp_minor = DFL_ADSP_MINOR,
+ .mixer_name = DFL_MIXER_NAME,
+ .mixer_major = DFL_MIXER_MAJOR, .mixer_minor = DFL_MIXER_MINOR,
+ .max_streams = DFL_MAX_STREAMS,
+ };
+ struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+ char path_buf[PATH_MAX], *dir;
+ char adsp_buf[64] = "", mixer_buf[64] = "";
+ struct sigaction sa;
+ struct stat stat_buf;
+ ssize_t ret;
+ unsigned u;
+
+ snprintf(ossp_log_name, sizeof(ossp_log_name), "osspd");
+ param.log_level = ossp_log_level;
+
+ if (fuse_opt_parse(&args, ¶m, ossp_opts, process_arg))
+ fatal("failed to parse arguments");
+
+ if (param.help)
+ return 0;
+
+ max_streams = param.max_streams;
+ hashtbl_size = max_streams / 2 + 13;
+
+ umax_streams = max_streams;
+ if (param.umax_streams)
+ umax_streams = param.umax_streams;
+ if (param.log_level > OSSP_LOG_MAX)
+ param.log_level = OSSP_LOG_MAX;
+ if (!param.fg)
+ param.log_level = -param.log_level;
+ ossp_log_level = param.log_level;
+ ossp_log_timestamp = param.timestamp;
+
+ if (!param.fg)
+ ossp_daemonize();
+
+ /* daemonization already handled, prevent forking inside FUSE */
+ fuse_opt_add_arg(&args, "-f");
+
+ info("OSS Proxy v%s (C) 2008-2010 by Tejun Heo ",
+ OSSP_VERSION);
+
+ /* ignore stupid SIGPIPEs */
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ if (sigaction(SIGPIPE, &sa, NULL))
+ fatal_e(-errno, "failed to ignore SIGPIPE");
+
+//#ifdef GIOVANNI
+ /* determine slave path and check for availability */
+ ret = readlink("/proc/self/exe", path_buf, PATH_MAX - 1);
+ if (ret < 0)
+ fatal_e(-errno, "failed to determine executable path");
+ path_buf[ret] = '\0';
+ dir = dirname(path_buf);
+
+ if (param.dsp_slave_path) {
+ strncpy(dsp_slave_path, param.dsp_slave_path, PATH_MAX - 1);
+ dsp_slave_path[PATH_MAX - 1] = '\0';
+ } else {
+ ret = snprintf(dsp_slave_path, PATH_MAX, "%s/%s",
+ dir, "ossp-padsp");
+ if (ret >= PATH_MAX)
+ fatal("dsp slave pathname too long");
+ }
+
+ if (stat(dsp_slave_path, &stat_buf))
+ fatal_e(-errno, "failed to stat %s", dsp_slave_path);
+ if (!S_ISREG(stat_buf.st_mode) || !(stat_buf.st_mode & 0444))
+ fatal("%s is not executable", dsp_slave_path);
+
+//#endif// GIOVANNI
+ /* allocate tables */
+ os_id_bitmap = calloc(BITS_TO_LONGS(max_streams), sizeof(long));
+ mixer_tbl = calloc(hashtbl_size, sizeof(mixer_tbl[0]));
+ os_tbl = calloc(hashtbl_size, sizeof(os_tbl[0]));
+ os_pgrp_tbl = calloc(hashtbl_size, sizeof(os_pgrp_tbl[0]));
+ os_notify_tbl = calloc(hashtbl_size, sizeof(os_notify_tbl[0]));
+ if (!os_id_bitmap || !mixer_tbl || !os_tbl || !os_pgrp_tbl ||
+ !os_notify_tbl)
+ fatal("failed to allocate stream hash tables");
+ for (u = 0; u < hashtbl_size; u++) {
+ INIT_LIST_HEAD(&mixer_tbl[u]);
+ INIT_LIST_HEAD(&os_tbl[u]);
+ INIT_LIST_HEAD(&os_pgrp_tbl[u]);
+ INIT_LIST_HEAD(&os_notify_tbl[u]);
+ }
+ __set_bit(0, os_id_bitmap); /* don't use id 0 */
+
+ /* create mixer delayed reference worker */
+ ret = -pthread_create(&mixer_delayed_put_thread, NULL,
+ mixer_delayed_put_worker, NULL);
+ if (ret)
+ fatal_e(ret, "failed to create mixer delayed put worker");
+
+ /* if exit_on_idle, touch mixer for pgrp0 */
+ exit_on_idle = param.exit_on_idle;
+ if (exit_on_idle) {
+ struct ossp_mixer *mixer;
+
+ mixer = get_mixer(0);
+ if (!mixer)
+ fatal("failed to touch idle mixer");
+ put_mixer(mixer);
+ }
+
+ /* create notify epoll and kick off watcher thread */
+ notify_epfd = epoll_create(max_streams);
+ if (notify_epfd < 0)
+ fatal_e(-errno, "failed to create notify epoll");
+ if (fcntl(notify_epfd, F_SETFD, FD_CLOEXEC) < 0)
+ fatal_e(-errno, "failed to set CLOEXEC on notify epfd");
+
+ ret = -pthread_create(¬ify_poller_thread, NULL, notify_poller, NULL);
+ if (ret)
+ fatal_e(ret, "failed to create notify poller thread");
+
+ /* create reaper for slave corpses */
+ ret = -pthread_create(&slave_reaper_thread, NULL, slave_reaper, NULL);
+ if (ret)
+ fatal_e(ret, "failed to create slave reaper thread");
+
+#ifdef GIOVANNI
+ /* we're set, let's setup fuse structures */
+ if (strlen(param.mixer_name))
+ mixer_se = setup_ossp_cuse(&mixer_ops, param.mixer_name,
+ param.mixer_major, param.mixer_minor,
+ args.argc, args.argv);
+ if (strlen(param.adsp_name))
+ adsp_se = setup_ossp_cuse(&dsp_ops, param.adsp_name,
+ param.adsp_major, param.adsp_minor,
+ args.argc, args.argv);
+
+#endif// GIOVANNI
+ dsp_se = setup_ossp_cuse(&dsp_ops, param.dsp_name,
+ param.dsp_major, param.dsp_minor,
+ args.argc, args.argv);
+ if (!dsp_se)
+ fatal("can't create dsp, giving up");
+
+#ifdef GIOVANNI
+ if (mixer_se)
+ snprintf(mixer_buf, sizeof(mixer_buf), ", %s (%d:%d)",
+ param.mixer_name, param.mixer_major, param.mixer_minor);
+ if (adsp_se)
+ snprintf(adsp_buf, sizeof(adsp_buf), ", %s (%d:%d)",
+ param.adsp_name, param.adsp_major, param.adsp_minor);
+
+#endif// GIOVANNI
+ info("Creating %s (%d:%d)%s%s", param.dsp_name, param.dsp_major,
+ param.dsp_minor, adsp_buf, mixer_buf);
+
+#ifdef GIOVANNI
+ /* start threads for mixer and adsp */
+ if (mixer_se) {
+ ret = -pthread_create(&cuse_mixer_thread, NULL,
+ cuse_worker, mixer_se);
+ if (ret)
+ err_e(ret, "failed to create mixer worker");
+ }
+ if (adsp_se) {
+ ret = -pthread_create(&cuse_adsp_thread, NULL,
+ cuse_worker, adsp_se);
+ if (ret)
+ err_e(ret, "failed to create adsp worker");
+ }
+#endif// GIOVANNI
+
+ /* run CUSE for /dev/dsp in the main thread */
+ ret = (ssize_t)cuse_worker(dsp_se);
+ if (ret < 0)
+ fatal("dsp worker failed");
+ return 0;
+}
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c
index 3c8404dd6b..3bb926adf3 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.c
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.c
@@ -3936,7 +3936,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session
dest_num = p + 5;
}
}
-#endif
+
if (profile->pres_type) {
char *sql;
@@ -3957,6 +3957,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session
sofia_glue_actually_execute_sql(profile, sql, profile->ireg_mutex);
switch_safe_free(sql);
}
+#endif
caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h
index 750fb60c15..6970a7ab05 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.h
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.h
@@ -224,6 +224,7 @@ typedef enum {
PFLAG_IN_DIALOG_CHAT,
PFLAG_DEL_SUBS_ON_REG,
PFLAG_IGNORE_183NOSDP,
+ PFLAG_PRESENCE_PROBE_ON_REGISTER,
/* No new flags below this line */
PFLAG_MAX
} PFLAGS;
@@ -957,6 +958,7 @@ void sofia_presence_event_thread_start(void);
void sofia_reg_expire_call_id(sofia_profile_t *profile, const char *call_id, int reboot);
switch_status_t sofia_glue_tech_choose_video_port(private_object_t *tech_pvt, int force);
switch_status_t sofia_glue_tech_set_video_codec(private_object_t *tech_pvt, int force);
+char *sofia_glue_get_register_host(const char *uri);
const char *sofia_glue_strip_proto(const char *uri);
switch_status_t reconfig_sofia(sofia_profile_t *profile);
void sofia_glue_del_gateway(sofia_gateway_t *gp);
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index e749abdc01..e20d868548 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -2156,6 +2156,30 @@ static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag)
sipip = profile->sipip;
}
+ gateway->extension = switch_core_strdup(gateway->pool, extension);
+
+
+ if (!strncasecmp(proxy, "sip:", 4)) {
+ gateway->register_proxy = switch_core_strdup(gateway->pool, proxy);
+ gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy + 4);
+ } else {
+ gateway->register_proxy = switch_core_sprintf(gateway->pool, "sip:%s", proxy);
+ gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy);
+ }
+
+ /* This checks to make sure we provide the right contact on register for targets behind nat with us. */
+ if (sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
+ char *register_host = NULL;
+
+ register_host = sofia_glue_get_register_host(gateway->register_proxy);
+
+ if (register_host && switch_is_lan_addr(register_host)) {
+ sipip = profile->sipip;
+ }
+
+ switch_safe_free(register_host);
+ }
+
if (extension_in_contact) {
format = strchr(sipip, ':') ? "" : "";
gateway->register_contact = switch_core_sprintf(gateway->pool, format, extension,
@@ -2170,16 +2194,6 @@ static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag)
profile->tls_sip_port : profile->sip_port, params);
}
- gateway->extension = switch_core_strdup(gateway->pool, extension);
-
- if (!strncasecmp(proxy, "sip:", 4)) {
- gateway->register_proxy = switch_core_strdup(gateway->pool, proxy);
- gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy + 4);
- } else {
- gateway->register_proxy = switch_core_sprintf(gateway->pool, "sip:%s", proxy);
- gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy);
- }
-
gateway->expires_str = switch_core_strdup(gateway->pool, expire_seconds);
if ((gateway->freq = atoi(gateway->expires_str)) < 5) {
@@ -2391,6 +2405,12 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
} else {
sofia_clear_pflag(profile, PFLAG_IGNORE_183NOSDP);
}
+ } else if (!strcasecmp(var, "presence-probe-on-register")) {
+ if (switch_true(val)) {
+ sofia_set_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER);
+ } else {
+ sofia_clear_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER);
+ }
} else if (!strcasecmp(var, "cid-in-1xx")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_CID_IN_1XX);
@@ -3056,6 +3076,12 @@ switch_status_t config_sofia(int reload, char *profile_name)
} else {
sofia_clear_pflag(profile, PFLAG_IGNORE_183NOSDP);
}
+ } else if (!strcasecmp(var, "presence-probe-on-register")) {
+ if (switch_true(val)) {
+ sofia_set_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER);
+ } else {
+ sofia_clear_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER);
+ }
} else if (!strcasecmp(var, "cid-in-1xx")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_CID_IN_1XX);
@@ -4406,7 +4432,6 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status
contact_host, astate, "outbound", user_agent,
profile->name, mod_sofia_globals.hostname, switch_str_nil(full_contact),
switch_str_nil(presence_id), switch_str_nil(presence_data), switch_str_nil(p));
-
switch_assert(sql);
sofia_glue_actually_execute_sql(profile, sql, profile->ireg_mutex);
@@ -5959,7 +5984,9 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t
/* Barf if we didn't get our private */
assert(switch_core_session_get_private(session));
- if (!strncasecmp(sip->sip_content_type->c_type, "message", 7) && !strcasecmp(sip->sip_content_type->c_subtype, "update_display")) {
+ if (sip->sip_content_type && sip->sip_content_type->c_subtype && sip->sip_content_type->c_type &&
+ !strncasecmp(sip->sip_content_type->c_type, "message", 7) &&
+ !strcasecmp(sip->sip_content_type->c_subtype, "update_display")) {
sofia_update_callee_id(session, profile, sip, SWITCH_TRUE);
goto end;
}
@@ -6856,8 +6883,9 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_
sql =
switch_mprintf
- ("select call_id from sip_dialogs where call_info='%q' and sip_from_user='%q' and sip_from_host='%q' and call_id is not null",
- switch_str_nil(p), user, host);
+ ("select call_id from sip_dialogs where call_info='%q' and ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') "
+ "and call_id is not null",
+ switch_str_nil(p), user, host, user, host);
if ((str = sofia_glue_execute_sql2str(profile, profile->ireg_mutex, sql, cid, sizeof(cid)))) {
bnh = nua_handle_by_call_id(nua, str);
diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c
index fa828607bd..57a2bfaa6a 100644
--- a/src/mod/endpoints/mod_sofia/sofia_glue.c
+++ b/src/mod/endpoints/mod_sofia/sofia_glue.c
@@ -5734,6 +5734,48 @@ char *sofia_glue_execute_sql2str(sofia_profile_t *profile, switch_mutex_t *mutex
return ret;
}
+char *sofia_glue_get_register_host(const char *uri)
+{
+ char *register_host = NULL;
+ const char *s;
+ char *p = NULL;
+
+ if (zstr(uri)) {
+ return NULL;
+ }
+
+ if ((s = switch_stristr("sip:", uri))) {
+ s += 4;
+ } else if ((s = switch_stristr("sips:", uri))) {
+ s += 5;
+ }
+
+ if (!s) {
+ return NULL;
+ }
+
+ register_host = strdup(s);
+
+ /* remove port for register_host for testing nat acl take into account
+ ipv6 addresses which are required to have brackets around the addr
+ */
+
+ if ((p = strchr(register_host, ']'))) {
+ if (*(p + 1) == ':') {
+ *(p + 1) = '\0';
+ }
+ } else {
+ if ((p = strrchr(register_host, ':'))) {
+ *p = '\0';
+ }
+ }
+
+ /* register_proxy should always start with "sip:" or "sips:" */
+ assert(register_host);
+
+ return register_host;
+}
+
const char *sofia_glue_strip_proto(const char *uri)
{
char *p;
@@ -5983,7 +6025,6 @@ void sofia_glue_tech_simplify(private_object_t *tech_pvt)
}
}
-
void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl)
{
switch_core_session_message_t *msg;
diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c
index dc02ca47ae..5c2517db61 100644
--- a/src/mod/endpoints/mod_sofia/sofia_presence.c
+++ b/src/mod/endpoints/mod_sofia/sofia_presence.c
@@ -567,7 +567,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
}
if (probe_euser && probe_host && (profile = sofia_glue_find_profile(probe_host))) {
- sql = switch_mprintf("select status,rpid from sip_dialogs where sip_from_user='%q' and sip_from_host='%q'", probe_euser, probe_host);
+ sql = switch_mprintf("select status,rpid from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q')",
+ probe_euser, probe_host, probe_euser, probe_host);
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_presence_dialog_callback, &dh);
h.profile = profile;
@@ -591,9 +592,11 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
"'%q','%q' "
"from sip_registrations left join sip_dialogs on "
- "(sip_dialogs.sip_from_user = sip_registrations.sip_user "
- "and (sip_dialogs.sip_from_host = sip_registrations.orig_server_host or "
- "sip_dialogs.sip_from_host = sip_registrations.sip_host) ) "
+ "sip_dialogs.presence_id = sip_registrations.sip_user || '@' || sip_registrations.sip_host "
+
+
+ "or (sip_dialogs.sip_from_user = sip_registrations.sip_user "
+ "and sip_dialogs.sip_from_host = sip_registrations.sip_host) "
"left join sip_presence on "
"(sip_registrations.sip_user=sip_presence.sip_user and sip_registrations.orig_server_host=sip_presence.sip_host and "
@@ -601,7 +604,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
"where sip_dialogs.presence_id='%q@%q' or (sip_registrations.sip_user='%q' and "
"(sip_registrations.orig_server_host='%q' or sip_registrations.sip_host='%q' "
"or sip_registrations.presence_hosts like '%%%q%%'))",
- dh.status, dh.rpid, probe_euser, probe_host, probe_euser, probe_host, probe_host, probe_host);
+ dh.status, dh.rpid,
+ probe_euser, probe_host, probe_euser, probe_host, probe_host, probe_host);
switch_assert(sql);
if (mod_sofia_globals.debug_presence > 0) {
@@ -711,9 +715,10 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
sql = switch_mprintf("update sip_dialogs set call_info='%q',call_info_state='%q' where hostname='%q' and uuid='%q'",
call_info, call_info_state, mod_sofia_globals.hostname, uuid);
} else {
- sql = switch_mprintf("update sip_dialogs set call_info='%q', call_info_state='%q' where hostname='%q' and sip_dialogs.sip_from_user='%q' "
- "and sip_dialogs.sip_from_host='%q' and call_info='%q'",
- call_info, call_info_state, mod_sofia_globals.hostname, euser, host, call_info);
+ sql = switch_mprintf("update sip_dialogs set call_info='%q', call_info_state='%q' where hostname='%q' and "
+ "((sip_dialogs.sip_from_user='%q' and sip_dialogs.sip_from_host='%q') or presence_id='%q@%q') and call_info='%q'",
+
+ call_info, call_info_state, mod_sofia_globals.hostname, euser, host, euser, host, call_info);
}
@@ -737,7 +742,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
}
- sql = switch_mprintf("select status,rpid from sip_dialogs where sip_from_user='%q' and sip_from_host='%q'", euser, host);
+ sql = switch_mprintf("select status,rpid from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q')",
+ euser, host, euser, host);
sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_presence_dialog_callback, &dh);
switch_safe_free(sql);
@@ -753,17 +759,20 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
"(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and "
"sip_subscriptions.profile_name=sip_presence.profile_name) "
"left join sip_dialogs on "
+
+ "sip_dialogs.presence_id = sip_subscriptions.sub_to_user || '@' || sip_subscriptions.sub_to_host or "
+
"(sip_dialogs.sip_from_user = sip_subscriptions.sub_to_user "
"and sip_dialogs.sip_from_host = sip_subscriptions.sub_to_host) "
"where sip_subscriptions.expires > -1 and "
- "(event='%q' or event='%q') and (sub_to_user='%q' or sip_dialogs.presence_id like '%q@%%') "
+ "(event='%q' or event='%q') and sub_to_user='%q' "
"and (sub_to_host='%q' or presence_hosts like '%%%q%%') "
"and (sip_subscriptions.profile_name = '%q' or sip_subscriptions.presence_hosts != sip_subscriptions.sub_to_host)",
switch_str_nil(status), switch_str_nil(rpid), host,
dh.status,dh.rpid,
- event_type, alt_event_type, euser, euser, host, host, profile->name))) {
+ event_type, alt_event_type, euser, host, host, profile->name))) {
struct presence_helper helper = { 0 };
@@ -1616,7 +1625,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
}
- /* commenting to test
+
if (helper->event){
const char *uuid = switch_event_get_header_nil(helper->event, "unique-id");
@@ -1625,7 +1634,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
}
}
- */
+
nua_handle_bind(nh, &mod_sofia_globals.keep_private);
@@ -1918,7 +1927,8 @@ static void sync_sla(sofia_profile_t *profile, const char *to_user, const char *
switch_core_hash_init(&sh->hash, sh->pool);
sql = switch_mprintf("select sip_from_user,sip_from_host,call_info,call_info_state,uuid from sip_dialogs "
- "where hostname='%q' " "and sip_from_user='%q' and sip_from_host='%q' ", mod_sofia_globals.hostname, to_user, to_host);
+ "where hostname='%q' and ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q')",
+ mod_sofia_globals.hostname, to_user, to_host, to_user, to_host);
if (mod_sofia_globals.debug_sla > 1) {
@@ -1954,7 +1964,8 @@ static void sync_sla(sofia_profile_t *profile, const char *to_user, const char *
if (clear) {
- sql = switch_mprintf("delete from sip_dialogs where sip_from_user='%q' and sip_from_host='%q' and call_info_state='seized'", to_user, to_host);
+ sql = switch_mprintf("delete from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') "
+ "and call_info_state='seized'", to_user, to_host, to_user, to_host);
if (mod_sofia_globals.debug_sla > 1) {
@@ -2326,8 +2337,9 @@ void sofia_presence_handle_sip_i_subscribe(int status,
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CANCEL LINE SEIZE\n");
}
- sql = switch_mprintf("delete from sip_dialogs where sip_from_user='%q' and sip_from_host='%q' and call_info_state='seized'",
- to_user, to_host);
+ sql = switch_mprintf("delete from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') "
+ "and call_info_state='seized'",
+ to_user, to_host, to_user, to_host);
if (mod_sofia_globals.debug_sla > 1) {
@@ -2360,8 +2372,9 @@ void sofia_presence_handle_sip_i_subscribe(int status,
- sql = switch_mprintf("delete from sip_dialogs where sip_from_user='%q' and sip_from_host='%q' and call_info_state='seized'",
- to_user, to_host);
+ sql = switch_mprintf("delete from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') "
+ "and call_info_state='seized'",
+ to_user, to_host, to_user, to_host);
if (mod_sofia_globals.debug_sla > 1) {
diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c
index 4bb879659c..e93bdaac08 100644
--- a/src/mod/endpoints/mod_sofia/sofia_reg.c
+++ b/src/mod/endpoints/mod_sofia/sofia_reg.c
@@ -142,16 +142,22 @@ void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now)
int ss_state = nua_callstate_authenticating;
sub_state_t ostate = gw_sub_ptr->state;
char *user_via = NULL;
+ char *register_host = NULL;
if (!now) {
gw_sub_ptr->state = ostate = SUB_STATE_UNSUBED;
gw_sub_ptr->expires_str = "0";
}
- if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) {
+ register_host = sofia_glue_get_register_host(gateway_ptr->register_proxy);
+
+ /* check for NAT and place a Via header if necessary (hostname or non-local IP) */
+ if (register_host && sofia_glue_check_nat(gateway_ptr->profile, register_host)) {
user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport);
}
+ switch_safe_free(register_host);
+
switch (ostate) {
case SUB_STATE_NOSUB:
break;
@@ -189,7 +195,15 @@ void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now)
nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private);
if (now) {
- nua_subscribe(gateway_ptr->sub_nh, NUTAG_URL(gateway_ptr->register_url), TAG_IF(user_via, SIPTAG_VIA_STR(user_via)), SIPTAG_EVENT_STR(gw_sub_ptr->event), SIPTAG_ACCEPT_STR(gw_sub_ptr->content_type), SIPTAG_TO_STR(gateway_ptr->register_from), SIPTAG_FROM_STR(gateway_ptr->register_from), SIPTAG_CONTACT_STR(gateway_ptr->register_contact), SIPTAG_EXPIRES_STR(gw_sub_ptr->expires_str), // sofia stack bases its auto-refresh stuff on this
+ nua_subscribe(gateway_ptr->sub_nh,
+ NUTAG_URL(gateway_ptr->register_url),
+ TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
+ SIPTAG_EVENT_STR(gw_sub_ptr->event),
+ SIPTAG_ACCEPT_STR(gw_sub_ptr->content_type),
+ SIPTAG_TO_STR(gateway_ptr->register_from),
+ SIPTAG_FROM_STR(gateway_ptr->register_from),
+ SIPTAG_CONTACT_STR(gateway_ptr->register_contact),
+ SIPTAG_EXPIRES_STR(gw_sub_ptr->expires_str), /* sofia stack bases its auto-refresh stuff on this */
TAG_NULL());
gw_sub_ptr->retry = now + gw_sub_ptr->retry_seconds;
} else {
@@ -266,6 +280,7 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now)
for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
reg_state_t ostate = gateway_ptr->state;
char *user_via = NULL;
+ char *register_host = NULL;
if (!now) {
gateway_ptr->state = ostate = REG_STATE_UNREGED;
@@ -277,10 +292,15 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now)
nua_handle_t *nh = nua_handle(profile->nua, NULL, NUTAG_URL(gateway_ptr->register_url), TAG_END());
sofia_private_t *pvt;
- if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) {
+ register_host = sofia_glue_get_register_host(gateway_ptr->register_proxy);
+
+ /* check for NAT and place a Via header if necessary (hostname or non-local IP) */
+ if (register_host && sofia_glue_check_nat(gateway_ptr->profile, register_host)) {
user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport);
}
+ switch_safe_free(register_host);
+
pvt = malloc(sizeof(*pvt));
switch_assert(pvt);
memset(pvt, 0, sizeof(*pvt));
@@ -335,10 +355,15 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now)
sofia_reg_new_handle(gateway_ptr, now ? 1 : 0);
}
- if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) {
+ register_host = sofia_glue_get_register_host(gateway_ptr->register_proxy);
+
+ /* check for NAT and place a Via header if necessary (hostname or non-local IP) */
+ if (register_host && sofia_glue_check_nat(gateway_ptr->profile, register_host)) {
user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport);
}
+ switch_safe_free(register_host);
+
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Registering %s\n", gateway_ptr->name);
if (now) {
@@ -1114,19 +1139,23 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
}
if (auth_res != AUTH_OK && !stale) {
+ if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) {
+ if (regtype == REG_REGISTER) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SIP auth %s (REGISTER) on sofia profile '%s' "
+ "for [%s@%s] from ip %s\n", forbidden ? "failure" : "challenge", profile->name, to_user, to_host, network_ip);
+ }
+ }
+
if (profile->debug) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send %s for [%s@%s] from ip '%s'\n",
- forbidden ? "forbidden" : "challenge", to_user, to_host, network_ip);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send %s for [%s@%s]\n",
+ forbidden ? "forbidden" : "challenge", to_user, to_host);
}
if (auth_res == AUTH_FORBIDDEN) {
nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
-
+
/* Log line added to support Fail2Ban */
if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) {
- if (regtype == REG_REGISTER) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth failure (REGISTER) on sofia profile '%s' "
- "for [%s@%s] from ip %s\n", profile->name, to_user, to_host, network_ip);
- } else if (regtype == REG_INVITE) {
+ if (regtype == REG_INVITE) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth failure (INVITE) on sofia profile '%s' "
"for [%s@%s] from ip %s\n", profile->name, to_user, to_host, network_ip);
}
@@ -1416,27 +1445,27 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
}
}
-
-#if 0
- if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
- switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, sub_host);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, sub_host);
- switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event_type", "presence");
- switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
- switch_event_fire(&s_event);
+ if (sofia_test_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER)) {
+ if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+ switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, sub_host);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, sub_host);
+ switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event_type", "presence");
+ switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
+ switch_event_fire(&s_event);
+ }
+ } else {
+ if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+ switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, sub_host);
+ switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
+ switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "status", "Registered");
+ switch_event_fire(&s_event);
+ }
}
-#else
- if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
- switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, sub_host);
- switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
- switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "status", "Registered");
- switch_event_fire(&s_event);
- }
-#endif
+
} else {
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_UNREGISTER) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", profile->name);
diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c
index 941db22c84..ee7cfc9eaf 100644
--- a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c
+++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c
@@ -691,7 +691,7 @@ SWITCH_STANDARD_API(event_sink_function)
switch_mutex_lock(listener->filter_mutex);
if (!listener->filters) {
- switch_event_create_plain(&listener->filters, SWITCH_EVENT_CHANNEL_DATA);
+ switch_event_create_plain(&listener->filters, SWITCH_EVENT_CLONE);
}
if (!strcasecmp(action, "delete")) {
@@ -702,7 +702,7 @@ SWITCH_STANDARD_API(event_sink_function)
if (!strcasecmp(header_val, "all")) {
switch_event_destroy(&listener->filters);
- switch_event_create_plain(&listener->filters, SWITCH_EVENT_CHANNEL_DATA);
+ switch_event_create_plain(&listener->filters, SWITCH_EVENT_CLONE);
} else {
switch_event_del_header(listener->filters, header_val);
}
@@ -1744,7 +1744,7 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even
switch_mutex_lock(listener->filter_mutex);
if (!listener->filters) {
- switch_event_create_plain(&listener->filters, SWITCH_EVENT_CHANNEL_DATA);
+ switch_event_create_plain(&listener->filters, SWITCH_EVENT_CLONE);
}
if (!strcasecmp(header_name, "delete") && header_val) {
@@ -1754,7 +1754,7 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even
}
if (!strcasecmp(header_name, "all")) {
switch_event_destroy(&listener->filters);
- switch_event_create_plain(&listener->filters, SWITCH_EVENT_CHANNEL_DATA);
+ switch_event_create_plain(&listener->filters, SWITCH_EVENT_CLONE);
} else {
switch_event_del_header_val(listener->filters, header_name, header_val);
}
diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.cxx
index ca001f64b1..f4bf780086 100644
--- a/src/mod/languages/mod_managed/freeswitch_wrap.cxx
+++ b/src/mod/languages/mod_managed/freeswitch_wrap.cxx
@@ -6744,6 +6744,42 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_destroy() {
}
+SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_io_read_lock(void * jarg1) {
+ int jresult ;
+ switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_core_session_t *)jarg1;
+ result = (switch_status_t)switch_core_session_io_read_lock(arg1);
+ jresult = result;
+ return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_io_write_lock(void * jarg1) {
+ int jresult ;
+ switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_core_session_t *)jarg1;
+ result = (switch_status_t)switch_core_session_io_write_lock(arg1);
+ jresult = result;
+ return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_io_rwunlock(void * jarg1) {
+ int jresult ;
+ switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_core_session_t *)jarg1;
+ result = (switch_status_t)switch_core_session_io_rwunlock(arg1);
+ jresult = result;
+ return jresult;
+}
+
+
SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_read_lock(void * jarg1) {
int jresult ;
switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
@@ -7626,6 +7662,22 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_execute_application_get_fl
}
+SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_execute_application_async(void * jarg1, char * jarg2, char * jarg3) {
+ int jresult ;
+ switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
+ char *arg2 = (char *) 0 ;
+ char *arg3 = (char *) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_core_session_t *)jarg1;
+ arg2 = (char *)jarg2;
+ arg3 = (char *)jarg3;
+ result = (switch_status_t)switch_core_session_execute_application_async(arg1,(char const *)arg2,(char const *)arg3);
+ jresult = result;
+ return jresult;
+}
+
+
SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_get_app_flags(char * jarg1, void * jarg2) {
int jresult ;
char *arg1 = (char *) 0 ;
@@ -7856,6 +7908,18 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_core_session_event_count(void
}
+SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_core_session_messages_waiting(void * jarg1) {
+ unsigned long jresult ;
+ switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
+ uint32_t result;
+
+ arg1 = (switch_core_session_t *)jarg1;
+ result = (uint32_t)switch_core_session_messages_waiting(arg1);
+ jresult = (unsigned long)result;
+ return jresult;
+}
+
+
SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_dequeue_event(void * jarg1, void * jarg2, int jarg3) {
int jresult ;
switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
@@ -28289,6 +28353,50 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_dmachine_set_realm(void * jarg1, ch
}
+SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_get_file_handle(void * jarg1, void * jarg2) {
+ int jresult ;
+ switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
+ switch_file_handle_t **arg2 = (switch_file_handle_t **) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_core_session_t *)jarg1;
+ arg2 = (switch_file_handle_t **)jarg2;
+ result = (switch_status_t)switch_ivr_get_file_handle(arg1,arg2);
+ jresult = result;
+ return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_release_file_handle(void * jarg1, void * jarg2) {
+ int jresult ;
+ switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
+ switch_file_handle_t **arg2 = (switch_file_handle_t **) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_core_session_t *)jarg1;
+ arg2 = (switch_file_handle_t **)jarg2;
+ result = (switch_status_t)switch_ivr_release_file_handle(arg1,arg2);
+ jresult = result;
+ return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_process_fh(void * jarg1, char * jarg2, void * jarg3) {
+ int jresult ;
+ switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
+ char *arg2 = (char *) 0 ;
+ switch_file_handle_t *arg3 = (switch_file_handle_t *) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_core_session_t *)jarg1;
+ arg2 = (char *)jarg2;
+ arg3 = (switch_file_handle_t *)jarg3;
+ result = (switch_status_t)switch_ivr_process_fh(arg1,(char const *)arg2,arg3);
+ jresult = result;
+ return jresult;
+}
+
+
SWIGEXPORT int SWIGSTDCALL CSharp_SWITCH_RTP_MAX_BUF_LEN_get() {
int jresult ;
int result;
diff --git a/src/mod/languages/mod_managed/managed/swig.cs b/src/mod/languages/mod_managed/managed/swig.cs
index bd901911ed..10fd3c6bc6 100644
--- a/src/mod/languages/mod_managed/managed/swig.cs
+++ b/src/mod/languages/mod_managed/managed/swig.cs
@@ -1103,6 +1103,21 @@ public class freeswitch {
return ret;
}
+ public static switch_status_t switch_core_session_io_read_lock(SWIGTYPE_p_switch_core_session session) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_io_read_lock(SWIGTYPE_p_switch_core_session.getCPtr(session));
+ return ret;
+ }
+
+ public static switch_status_t switch_core_session_io_write_lock(SWIGTYPE_p_switch_core_session session) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_io_write_lock(SWIGTYPE_p_switch_core_session.getCPtr(session));
+ return ret;
+ }
+
+ public static switch_status_t switch_core_session_io_rwunlock(SWIGTYPE_p_switch_core_session session) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_io_rwunlock(SWIGTYPE_p_switch_core_session.getCPtr(session));
+ return ret;
+ }
+
public static switch_status_t switch_core_session_read_lock(SWIGTYPE_p_switch_core_session session) {
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_read_lock(SWIGTYPE_p_switch_core_session.getCPtr(session));
return ret;
@@ -1439,6 +1454,11 @@ public class freeswitch {
return ret;
}
+ public static switch_status_t switch_core_session_execute_application_async(SWIGTYPE_p_switch_core_session session, string app, string arg) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_execute_application_async(SWIGTYPE_p_switch_core_session.getCPtr(session), app, arg);
+ return ret;
+ }
+
public static switch_status_t switch_core_session_get_app_flags(string app, SWIGTYPE_p_int flags) {
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_get_app_flags(app, SWIGTYPE_p_int.getCPtr(flags));
return ret;
@@ -1518,6 +1538,11 @@ public class freeswitch {
return ret;
}
+ public static uint switch_core_session_messages_waiting(SWIGTYPE_p_switch_core_session session) {
+ uint ret = freeswitchPINVOKE.switch_core_session_messages_waiting(SWIGTYPE_p_switch_core_session.getCPtr(session));
+ return ret;
+ }
+
public static switch_status_t switch_core_session_dequeue_event(SWIGTYPE_p_switch_core_session session, SWIGTYPE_p_p_switch_event arg1, switch_bool_t force) {
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_dequeue_event(SWIGTYPE_p_switch_core_session.getCPtr(session), SWIGTYPE_p_p_switch_event.getCPtr(arg1), (int)force);
return ret;
@@ -4461,6 +4486,21 @@ public class freeswitch {
return ret;
}
+ public static switch_status_t switch_ivr_get_file_handle(SWIGTYPE_p_switch_core_session session, SWIGTYPE_p_p_switch_file_handle fh) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_get_file_handle(SWIGTYPE_p_switch_core_session.getCPtr(session), SWIGTYPE_p_p_switch_file_handle.getCPtr(fh));
+ return ret;
+ }
+
+ public static switch_status_t switch_ivr_release_file_handle(SWIGTYPE_p_switch_core_session session, SWIGTYPE_p_p_switch_file_handle fh) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_release_file_handle(SWIGTYPE_p_switch_core_session.getCPtr(session), SWIGTYPE_p_p_switch_file_handle.getCPtr(fh));
+ return ret;
+ }
+
+ public static switch_status_t switch_ivr_process_fh(SWIGTYPE_p_switch_core_session session, string cmd, switch_file_handle fhp) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_process_fh(SWIGTYPE_p_switch_core_session.getCPtr(session), cmd, switch_file_handle.getCPtr(fhp));
+ return ret;
+ }
+
public static switch_status_t switch_rtp_add_crypto_key(SWIGTYPE_p_switch_rtp rtp_session, switch_rtp_crypto_direction_t direction, uint index, switch_rtp_crypto_key_type_t type, SWIGTYPE_p_unsigned_char key, SWIGTYPE_p_switch_size_t keylen) {
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_add_crypto_key(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), (int)direction, index, (int)type, SWIGTYPE_p_unsigned_char.getCPtr(key), SWIGTYPE_p_switch_size_t.getCPtr(keylen));
if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve();
@@ -7245,6 +7285,15 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_destroy")]
public static extern int switch_core_destroy();
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_io_read_lock")]
+ public static extern int switch_core_session_io_read_lock(HandleRef jarg1);
+
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_io_write_lock")]
+ public static extern int switch_core_session_io_write_lock(HandleRef jarg1);
+
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_io_rwunlock")]
+ public static extern int switch_core_session_io_rwunlock(HandleRef jarg1);
+
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_read_lock")]
public static extern int switch_core_session_read_lock(HandleRef jarg1);
@@ -7449,6 +7498,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_execute_application_get_flags")]
public static extern int switch_core_session_execute_application_get_flags(HandleRef jarg1, string jarg2, string jarg3, HandleRef jarg4);
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_execute_application_async")]
+ public static extern int switch_core_session_execute_application_async(HandleRef jarg1, string jarg2, string jarg3);
+
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_get_app_flags")]
public static extern int switch_core_session_get_app_flags(string jarg1, HandleRef jarg2);
@@ -7497,6 +7549,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_event_count")]
public static extern uint switch_core_session_event_count(HandleRef jarg1);
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_messages_waiting")]
+ public static extern uint switch_core_session_messages_waiting(HandleRef jarg1);
+
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_dequeue_event")]
public static extern int switch_core_session_dequeue_event(HandleRef jarg1, HandleRef jarg2, int jarg3);
@@ -12228,6 +12283,15 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_dmachine_set_realm")]
public static extern int switch_ivr_dmachine_set_realm(HandleRef jarg1, string jarg2);
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_get_file_handle")]
+ public static extern int switch_ivr_get_file_handle(HandleRef jarg1, HandleRef jarg2);
+
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_release_file_handle")]
+ public static extern int switch_ivr_release_file_handle(HandleRef jarg1, HandleRef jarg2);
+
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_process_fh")]
+ public static extern int switch_ivr_process_fh(HandleRef jarg1, string jarg2, HandleRef jarg3);
+
[DllImport("mod_managed", EntryPoint="CSharp_SWITCH_RTP_MAX_BUF_LEN_get")]
public static extern int SWITCH_RTP_MAX_BUF_LEN_get();
@@ -17103,6 +17167,36 @@ namespace FreeSWITCH.Native {
using System;
using System.Runtime.InteropServices;
+public class SWIGTYPE_p_p_switch_file_handle {
+ private HandleRef swigCPtr;
+
+ internal SWIGTYPE_p_p_switch_file_handle(IntPtr cPtr, bool futureUse) {
+ swigCPtr = new HandleRef(this, cPtr);
+ }
+
+ protected SWIGTYPE_p_p_switch_file_handle() {
+ swigCPtr = new HandleRef(null, IntPtr.Zero);
+ }
+
+ internal static HandleRef getCPtr(SWIGTYPE_p_p_switch_file_handle obj) {
+ return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr;
+ }
+}
+
+}
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.35
+ *
+ * Do not make changes to this file unless you know what you are doing--modify
+ * the SWIG interface file instead.
+ * ----------------------------------------------------------------------------- */
+
+namespace FreeSWITCH.Native {
+
+using System;
+using System.Runtime.InteropServices;
+
public class SWIGTYPE_p_p_switch_frame {
private HandleRef swigCPtr;
diff --git a/src/mod/languages/mod_managed/mono28.patch b/src/mod/languages/mod_managed/mono28.patch
new file mode 100644
index 0000000000..7ec60f596c
--- /dev/null
+++ b/src/mod/languages/mod_managed/mono28.patch
@@ -0,0 +1,75 @@
+diff --git a/src/mod/languages/mod_managed/Makefile b/src/mod/languages/mod_managed/Makefile
+index 0ac49b4..ec44ff5 100644
+--- a/src/mod/languages/mod_managed/Makefile
++++ b/src/mod/languages/mod_managed/Makefile
+@@ -1,6 +1,6 @@
+-LOCAL_INSERT_CFLAGS= /usr/bin/pkg-config mono --cflags
+-LOCAL_INSERT_LDFLAGS= /usr/bin/pkg-config mono --libs
+-#MOD_CFLAGS=-D_REENTRANT -pthread -I/opt/mono-1.9/lib/pkgconfig/../../include/mono-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -lmono
++LOCAL_INSERT_CFLAGS= /usr/bin/pkg-config mono-2 --cflags
++LOCAL_INSERT_LDFLAGS= /usr/bin/pkg-config mono-2 --libs
++#MOD_CFLAGS=-D_REENTRANT -pthread -I/usr/lib/mono -lmono
+ BASE=../../../..
+ VERBOSE=1
+ include $(BASE)/build/modmake.rules
+diff --git a/src/mod/languages/mod_managed/freeswitch.i b/src/mod/languages/mod_managed/freeswitch.i
+index ffbdf9b..117d58c 100644
+--- a/src/mod/languages/mod_managed/freeswitch.i
++++ b/src/mod/languages/mod_managed/freeswitch.i
+@@ -8,7 +8,6 @@
+
+ /* Callback for returning strings to C# without leaking memory */
+ #ifndef _MANAGED
+-#include
+ #include
+ #include
+ #include
+diff --git a/src/mod/languages/mod_managed/freeswitch_managed.h b/src/mod/languages/mod_managed/freeswitch_managed.h
+index 1d0b6a7..13ffe5d 100644
+--- a/src/mod/languages/mod_managed/freeswitch_managed.h
++++ b/src/mod/languages/mod_managed/freeswitch_managed.h
+@@ -40,7 +40,6 @@ typedef void (*hangupFunction) (void);
+ typedef char *(*inputFunction) (void *, switch_input_type_t);
+
+ #ifndef _MANAGED
+-#include
+ #include
+ #include
+ #include
+@@ -73,7 +72,7 @@ extern mod_managed_globals globals;
+ #ifdef WIN32
+ #define RESULT_FREE(x) CoTaskMemFree(x)
+ #else
+-#define RESULT_FREE(x) g_free(x)
++#define RESULT_FREE(x) mono_free(x)
+ #endif
+
+ SWITCH_END_EXTERN_C
+diff --git a/src/mod/languages/mod_managed/mod_managed.cpp b/src/mod/languages/mod_managed/mod_managed.cpp
+index ec2d866..87e831f 100644
+--- a/src/mod/languages/mod_managed/mod_managed.cpp
++++ b/src/mod/languages/mod_managed/mod_managed.cpp
+@@ -208,18 +208,13 @@ switch_status_t loadRuntime()
+ }
+
+ /* Already loaded? */
+- MonoAssemblyName name;
+- name.name = MOD_MANAGED_ASM_NAME;
+- name.major = MOD_MANAGED_ASM_V1;
+- name.minor = MOD_MANAGED_ASM_V2;
+- name.revision = MOD_MANAGED_ASM_V3;
+- name.build = MOD_MANAGED_ASM_V4;
+- name.culture = "";
+- name.hash_value = "";
+-
++ MonoAssemblyName *name = mono_assembly_name_new (MOD_MANAGED_ASM_NAME);
++ //Note also that it can't be allocated on the stack anymore and you'll need to create and destroy it with the following API:
++ //mono_assembly_name_free (name);
++
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Calling mono_assembly_loaded.\n");
+
+- if (!(globals.mod_mono_asm = mono_assembly_loaded(&name))) {
++ if (!(globals.mod_mono_asm = mono_assembly_loaded(name))) {
+ /* Open the assembly */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Calling mono_domain_assembly_open.\n");
+ globals.mod_mono_asm = mono_domain_assembly_open(globals.domain, filename);
diff --git a/src/mod/languages/mod_perl/mod_perl_wrap.cpp b/src/mod/languages/mod_perl/mod_perl_wrap.cpp
index 370c88bc99..2efbdf1abc 100644
--- a/src/mod/languages/mod_perl/mod_perl_wrap.cpp
+++ b/src/mod/languages/mod_perl/mod_perl_wrap.cpp
@@ -9732,17 +9732,17 @@ XS(SWIG_init) {
SWIG_TypeClientData(SWIGTYPE_p_IVRMenu, (void*) "freeswitch::IVRMenu");
SWIG_TypeClientData(SWIGTYPE_p_API, (void*) "freeswitch::API");
SWIG_TypeClientData(SWIGTYPE_p_input_callback_state, (void*) "freeswitch::input_callback_state_t");
- /*@SWIG:/usr/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+ /*@SWIG:/usr/local/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do {
SV *sv = get_sv((char*) SWIG_prefix "S_HUP", TRUE | 0x2 | GV_ADDMULTI);
sv_setsv(sv, SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(S_HUP)));
SvREADONLY_on(sv);
} while(0) /*@SWIG@*/;
- /*@SWIG:/usr/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+ /*@SWIG:/usr/local/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do {
SV *sv = get_sv((char*) SWIG_prefix "S_FREE", TRUE | 0x2 | GV_ADDMULTI);
sv_setsv(sv, SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(S_FREE)));
SvREADONLY_on(sv);
} while(0) /*@SWIG@*/;
- /*@SWIG:/usr/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do {
+ /*@SWIG:/usr/local/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do {
SV *sv = get_sv((char*) SWIG_prefix "S_RDLOCK", TRUE | 0x2 | GV_ADDMULTI);
sv_setsv(sv, SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(S_RDLOCK)));
SvREADONLY_on(sv);
diff --git a/src/switch_channel.c b/src/switch_channel.c
index c63a1aadb9..a9c87c5954 100644
--- a/src/switch_channel.c
+++ b/src/switch_channel.c
@@ -2518,7 +2518,12 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_ring_ready_value(swi
if ((arg = strchr(app, ' '))) {
*arg++ = '\0';
}
- switch_core_session_execute_application(channel->session, app, arg);
+
+ if (switch_core_session_in_thread(channel->session)) {
+ switch_core_session_execute_application(channel->session, app, arg);
+ } else {
+ switch_core_session_execute_application_async(channel->session, app, arg);
+ }
}
return SWITCH_STATUS_SUCCESS;
@@ -2571,7 +2576,12 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_pre_answered(switch_
if ((arg = strchr(app, ' '))) {
*arg++ = '\0';
}
- switch_core_session_execute_application(channel->session, app, arg);
+
+ if (switch_core_session_in_thread(channel->session)) {
+ switch_core_session_execute_application(channel->session, app, arg);
+ } else {
+ switch_core_session_execute_application_async(channel->session, app, arg);
+ }
}
if ((var = switch_channel_get_variable(channel, SWITCH_PASSTHRU_PTIME_MISMATCH_VARIABLE))) {
@@ -2750,7 +2760,12 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_answered(switch_chan
}
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "%s execute on answer: %s(%s)\n", channel->name, app,
switch_str_nil(arg));
- switch_core_session_execute_application(channel->session, app, arg);
+
+ if (switch_core_session_in_thread(channel->session)) {
+ switch_core_session_execute_application(channel->session, app, arg);
+ } else {
+ switch_core_session_execute_application_async(channel->session, app, arg);
+ }
}
}
diff --git a/src/switch_core_rwlock.c b/src/switch_core_rwlock.c
index 4285491dc1..57168d9a29 100644
--- a/src/switch_core_rwlock.c
+++ b/src/switch_core_rwlock.c
@@ -36,6 +36,46 @@
#include "private/switch_core_pvt.h"
+SWITCH_DECLARE(switch_status_t) switch_core_session_io_read_lock(switch_core_session_t *session)
+{
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (session->io_rwlock) {
+ if (switch_thread_rwlock_tryrdlock(session->io_rwlock) == SWITCH_STATUS_SUCCESS) {
+ status = SWITCH_STATUS_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_core_session_io_write_lock(switch_core_session_t *session)
+{
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (session->io_rwlock) {
+ switch_thread_rwlock_wrlock(session->io_rwlock);
+ status = SWITCH_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
+
+SWITCH_DECLARE(switch_status_t) switch_core_session_io_rwunlock(switch_core_session_t *session)
+{
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (session->io_rwlock) {
+ switch_thread_rwlock_unlock(session->io_rwlock);
+ status = SWITCH_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
+
+
#ifdef SWITCH_DEBUG_RWLOCKS
SWITCH_DECLARE(switch_status_t) switch_core_session_perform_read_lock(switch_core_session_t *session, const char *file, const char *func, int line)
#else
diff --git a/src/switch_core_session.c b/src/switch_core_session.c
index b3bb638c76..fc7648155a 100644
--- a/src/switch_core_session.c
+++ b/src/switch_core_session.c
@@ -855,12 +855,31 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_queue_event(switch_core_sess
if (switch_queue_trypush(session->event_queue, *event) == SWITCH_STATUS_SUCCESS) {
*event = NULL;
status = SWITCH_STATUS_SUCCESS;
+
+ if (switch_channel_test_flag(session->channel, CF_PROXY_MODE) || switch_channel_test_flag(session->channel, CF_THREAD_SLEEPING)) {
+ switch_core_session_wake_session_thread(session);
+ }
}
}
return status;
}
+SWITCH_DECLARE(uint32_t) switch_core_session_messages_waiting(switch_core_session_t *session)
+{
+ int x = 0;
+
+ if (session->private_event_queue) {
+ x += switch_queue_size(session->private_event_queue);
+ }
+
+ if (session->message_queue) {
+ x += switch_queue_size(session->message_queue);
+ }
+
+ return x;
+}
+
SWITCH_DECLARE(uint32_t) switch_core_session_event_count(switch_core_session_t *session)
{
if (session->event_queue) {
@@ -1648,6 +1667,7 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_uuid(switch_
switch_thread_rwlock_create(&session->bug_rwlock, session->pool);
switch_thread_cond_create(&session->cond, session->pool);
switch_thread_rwlock_create(&session->rwlock, session->pool);
+ switch_thread_rwlock_create(&session->io_rwlock, session->pool);
switch_queue_create(&session->message_queue, SWITCH_MESSAGE_QUEUE_LEN, session->pool);
switch_queue_create(&session->event_queue, SWITCH_EVENT_QUEUE_LEN, session->pool);
switch_queue_create(&session->private_event_queue, SWITCH_EVENT_QUEUE_LEN, session->pool);
@@ -1799,6 +1819,28 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_app_flags(const char *ap
}
+SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_async(switch_core_session_t *session, const char *app, const char *arg)
+{
+ switch_event_t *execute_event;
+
+ if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute");
+ switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", app);
+
+ if (arg) {
+ switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", arg);
+ }
+
+ switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true");
+ switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE);
+
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ return SWITCH_STATUS_FALSE;
+}
+
+
SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_get_flags(switch_core_session_t *session, const char *app,
const char *arg, int32_t *flags)
{
@@ -1831,10 +1873,16 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_get_flag
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Application %s Requires media on channel %s!\n",
app, switch_channel_get_name(session->channel));
} else if (!switch_test_flag(application_interface, SAF_SUPPORT_NOMEDIA) && !switch_channel_media_ready(session->channel)) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Application %s Requires media! pre_answering channel %s\n",
- app, switch_channel_get_name(session->channel));
- if (switch_channel_pre_answer(session->channel) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Well, that didn't work very well did it? ...\n");
+ if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Application %s Requires media! pre_answering channel %s\n",
+ app, switch_channel_get_name(session->channel));
+ if (switch_channel_pre_answer(session->channel) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Well, that didn't work very well did it? ...\n");
+ switch_goto_status(SWITCH_STATUS_FALSE, done);
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
+ "Cannot execute app '%s' media required on an outbound channel that does not have media established\n", app);
switch_goto_status(SWITCH_STATUS_FALSE, done);
}
}
diff --git a/src/switch_cpp.cpp b/src/switch_cpp.cpp
index 469ae18c4b..40462db567 100644
--- a/src/switch_cpp.cpp
+++ b/src/switch_cpp.cpp
@@ -1269,120 +1269,7 @@ SWITCH_DECLARE(switch_status_t) CoreSession::process_callback_result(char *resul
this_check(SWITCH_STATUS_FALSE);
sanity_check(SWITCH_STATUS_FALSE);
- if (zstr(result)) {
- return SWITCH_STATUS_SUCCESS;
- }
-
- if (fhp) {
- if (!switch_test_flag(fhp, SWITCH_FILE_OPEN)) {
- return SWITCH_STATUS_FALSE;
- }
-
- if (!strncasecmp(result, "speed", 5)) {
- char *p;
-
- if ((p = strchr(result, ':'))) {
- p++;
- if (*p == '+' || *p == '-') {
- int step;
- if (!(step = atoi(p))) {
- step = 1;
- }
- fhp->speed += step;
- } else {
- int speed = atoi(p);
- fhp->speed = speed;
- }
- return SWITCH_STATUS_SUCCESS;
- }
-
- return SWITCH_STATUS_FALSE;
-
- } else if (!strncasecmp(result, "volume", 6)) {
- char *p;
-
- if ((p = strchr(result, ':'))) {
- p++;
- if (*p == '+' || *p == '-') {
- int step;
- if (!(step = atoi(p))) {
- step = 1;
- }
- fhp->vol += step;
- } else {
- int vol = atoi(p);
- fhp->vol = vol;
- }
- return SWITCH_STATUS_SUCCESS;
- }
-
- if (fhp->vol) {
- switch_normalize_volume(fhp->vol);
- }
-
- return SWITCH_STATUS_FALSE;
- } else if (!strcasecmp(result, "pause")) {
- if (switch_test_flag(fhp, SWITCH_FILE_PAUSE)) {
- switch_clear_flag(fhp, SWITCH_FILE_PAUSE);
- } else {
- switch_set_flag(fhp, SWITCH_FILE_PAUSE);
- }
- return SWITCH_STATUS_SUCCESS;
- } else if (!strcasecmp(result, "stop")) {
- return SWITCH_STATUS_FALSE;
- } else if (!strcasecmp(result, "truncate")) {
- switch_core_file_truncate(fhp, 0);
- } else if (!strcasecmp(result, "restart")) {
- unsigned int pos = 0;
- fhp->speed = 0;
- switch_core_file_seek(fhp, &pos, 0, SEEK_SET);
- return SWITCH_STATUS_SUCCESS;
- } else if (!strncasecmp(result, "seek", 4)) {
- switch_codec_t *codec;
- unsigned int samps = 0;
- unsigned int pos = 0;
- char *p;
- codec = switch_core_session_get_read_codec(session);
-
- if ((p = strchr(result, ':'))) {
- p++;
- if (*p == '+' || *p == '-') {
- int step;
- int32_t target;
- if (!(step = atoi(p))) {
- step = 1000;
- }
-
- samps = step * (codec->implementation->samples_per_second / 1000);
- target = (int32_t)fhp->pos + samps;
-
- if (target < 0) {
- target = 0;
- }
-
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "seek to position %d\n", target);
- switch_core_file_seek(fhp, &pos, target, SEEK_SET);
-
- } else {
- samps = atoi(p) * (codec->implementation->samples_per_second / 1000);
- if (samps < 0) {
- samps = 0;
- }
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "seek to position %d\n", samps);
- switch_core_file_seek(fhp, &pos, samps, SEEK_SET);
- }
- }
-
- return SWITCH_STATUS_SUCCESS;
- }
- }
-
- if (!strcmp(result, "true") || !strcmp(result, "undefined")) {
- return SWITCH_STATUS_SUCCESS;
- }
-
-
- return SWITCH_STATUS_FALSE;
+ return switch_ivr_process_fh(session, result, fhp);
}
/* For Emacs:
diff --git a/src/switch_ivr.c b/src/switch_ivr.c
index f076f6cb9f..00917adc34 100644
--- a/src/switch_ivr.c
+++ b/src/switch_ivr.c
@@ -763,6 +763,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session,
write_frame.samples = write_frame.datalen / sizeof(int16_t);
}
+ if (switch_channel_test_flag(channel, CF_RECOVERED) && switch_channel_test_flag(channel, CF_CONTROLLED)) {
+ switch_channel_clear_flag(channel, CF_CONTROLLED);
+ }
+
if (switch_channel_test_flag(channel, CF_CONTROLLED)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot park channels that are under control already.\n");
return SWITCH_STATUS_FALSE;
@@ -2559,6 +2563,124 @@ SWITCH_DECLARE(switch_bool_t) switch_ivr_uuid_exists(const char *uuid)
return exists;
}
+SWITCH_DECLARE(switch_status_t) switch_ivr_process_fh(switch_core_session_t *session, const char *cmd, switch_file_handle_t *fhp)
+{
+ if (zstr(cmd)) {
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ if (fhp) {
+ if (!switch_test_flag(fhp, SWITCH_FILE_OPEN)) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (!strncasecmp(cmd, "speed", 5)) {
+ char *p;
+
+ if ((p = strchr(cmd, ':'))) {
+ p++;
+ if (*p == '+' || *p == '-') {
+ int step;
+ if (!(step = atoi(p))) {
+ step = 1;
+ }
+ fhp->speed += step;
+ } else {
+ int speed = atoi(p);
+ fhp->speed = speed;
+ }
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ return SWITCH_STATUS_FALSE;
+
+ } else if (!strncasecmp(cmd, "volume", 6)) {
+ char *p;
+
+ if ((p = strchr(cmd, ':'))) {
+ p++;
+ if (*p == '+' || *p == '-') {
+ int step;
+ if (!(step = atoi(p))) {
+ step = 1;
+ }
+ fhp->vol += step;
+ } else {
+ int vol = atoi(p);
+ fhp->vol = vol;
+ }
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ if (fhp->vol) {
+ switch_normalize_volume(fhp->vol);
+ }
+
+ return SWITCH_STATUS_FALSE;
+ } else if (!strcasecmp(cmd, "pause")) {
+ if (switch_test_flag(fhp, SWITCH_FILE_PAUSE)) {
+ switch_clear_flag(fhp, SWITCH_FILE_PAUSE);
+ } else {
+ switch_set_flag(fhp, SWITCH_FILE_PAUSE);
+ }
+ return SWITCH_STATUS_SUCCESS;
+ } else if (!strcasecmp(cmd, "stop")) {
+ return SWITCH_STATUS_FALSE;
+ } else if (!strcasecmp(cmd, "truncate")) {
+ switch_core_file_truncate(fhp, 0);
+ } else if (!strcasecmp(cmd, "restart")) {
+ unsigned int pos = 0;
+ fhp->speed = 0;
+ switch_core_file_seek(fhp, &pos, 0, SEEK_SET);
+ return SWITCH_STATUS_SUCCESS;
+ } else if (!strncasecmp(cmd, "seek", 4)) {
+ switch_codec_t *codec;
+ unsigned int samps = 0;
+ unsigned int pos = 0;
+ char *p;
+ codec = switch_core_session_get_read_codec(session);
+
+ if ((p = strchr(cmd, ':'))) {
+ p++;
+ if (*p == '+' || *p == '-') {
+ int step;
+ int32_t target;
+ if (!(step = atoi(p))) {
+ step = 1000;
+ }
+
+ samps = step * (codec->implementation->samples_per_second / 1000);
+ target = (int32_t)fhp->pos + samps;
+
+ if (target < 0) {
+ target = 0;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "seek to position %d\n", target);
+ switch_core_file_seek(fhp, &pos, target, SEEK_SET);
+
+ } else {
+ samps = atoi(p) * (codec->implementation->samples_per_second / 1000);
+ if (samps < 0) {
+ samps = 0;
+ }
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "seek to position %d\n", samps);
+ switch_core_file_seek(fhp, &pos, samps, SEEK_SET);
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+ }
+ }
+
+ if (!strcmp(cmd, "true") || !strcmp(cmd, "undefined")) {
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ return SWITCH_STATUS_FALSE;
+
+}
+
/* For Emacs:
* Local Variables:
diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c
index b6363ffa53..4d320d0e5c 100644
--- a/src/switch_ivr_bridge.c
+++ b/src/switch_ivr_bridge.c
@@ -155,7 +155,6 @@ struct switch_ivr_bridge_data {
switch_input_callback_function_t input_callback;
void *session_data;
int clean_exit;
- uint32_t skip_frames;
};
typedef struct switch_ivr_bridge_data switch_ivr_bridge_data_t;
@@ -169,7 +168,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
switch_channel_t *chan_a, *chan_b;
switch_frame_t *read_frame;
switch_core_session_t *session_a, *session_b;
- uint32_t loop_count = 0;
+ uint32_t read_frame_count = 0;
const char *app_name = NULL, *app_arg = NULL;
const char *hook_var = NULL;
int inner_bridge = 0;
@@ -181,6 +180,8 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
const char *bridge_answer_timeout = NULL;
int answer_timeout, sent_update = 0;
time_t answer_limit = 0;
+ const char *exec_app = NULL;
+ const char *exec_data = NULL;
#ifdef SWITCH_VIDEO_IN_THREADS
switch_thread_t *vid_thread = NULL;
@@ -201,6 +202,10 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
chan_a = switch_core_session_get_channel(session_a);
chan_b = switch_core_session_get_channel(session_b);
+ if ((exec_app = switch_channel_get_variable(chan_a, "bridge_pre_execute_app"))) {
+ exec_data = switch_channel_get_variable(chan_a, "bridge_pre_execute_data");
+ }
+
bypass_media_after_bridge = switch_channel_test_flag(chan_a, CF_BYPASS_MEDIA_AFTER_BRIDGE);
switch_channel_clear_flag(chan_a, CF_BYPASS_MEDIA_AFTER_BRIDGE);
@@ -212,7 +217,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
}
inner_bridge = switch_channel_test_flag(chan_a, CF_INNER_BRIDGE);
-
+
if (!switch_channel_test_flag(chan_a, CF_ANSWERED) && (bridge_answer_timeout = switch_channel_get_variable(chan_a, "bridge_answer_timeout"))) {
if ((answer_timeout = atoi(bridge_answer_timeout)) < 0) {
answer_timeout = 0;
@@ -285,7 +290,6 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
switch_channel_state_t b_state;
switch_status_t status;
switch_event_t *event;
- loop_count++;
if (switch_channel_test_flag(chan_a, CF_TRANSFER)) {
data->clean_exit = 1;
@@ -309,7 +313,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
goto end_of_bridge_loop;
}
- if (loop_count > DEFAULT_LEAD_FRAMES && switch_channel_media_ack(chan_a) && switch_core_session_private_event_count(session_a)) {
+ if (read_frame_count > DEFAULT_LEAD_FRAMES && switch_channel_media_ack(chan_a) && switch_core_session_private_event_count(session_a)) {
switch_channel_set_flag(chan_b, CF_SUSPEND);
msg.string_arg = data->b_uuid;
msg.message_id = SWITCH_MESSAGE_INDICATE_UNBRIDGE;
@@ -341,13 +345,24 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
}
#endif
- if (loop_count > DEFAULT_LEAD_FRAMES && switch_channel_media_ack(chan_a) &&
- (bypass_media_after_bridge || switch_channel_test_flag(chan_a, CF_BYPASS_MEDIA_AFTER_BRIDGE)) && switch_channel_test_flag(chan_a, CF_ANSWERED)
- && switch_channel_test_flag(chan_b, CF_ANSWERED)) {
- switch_ivr_nomedia(switch_core_session_get_uuid(session_a), SMF_REBRIDGE);
- bypass_media_after_bridge = 0;
- switch_channel_clear_flag(chan_a, CF_BYPASS_MEDIA_AFTER_BRIDGE);
- goto end_of_bridge_loop;
+ if (read_frame_count > DEFAULT_LEAD_FRAMES && switch_channel_media_ack(chan_a)) {
+
+ if (exec_app) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session_a), SWITCH_LOG_DEBUG, "%s Bridge execute app %s(%s)\n",
+ switch_channel_get_name(chan_a), exec_app, exec_data);
+
+ switch_core_session_execute_application_async(session_a, exec_app, exec_data);
+ exec_app = exec_data = NULL;
+ }
+
+
+ if ((bypass_media_after_bridge || switch_channel_test_flag(chan_a, CF_BYPASS_MEDIA_AFTER_BRIDGE)) && switch_channel_test_flag(chan_a, CF_ANSWERED)
+ && switch_channel_test_flag(chan_b, CF_ANSWERED)) {
+ switch_ivr_nomedia(switch_core_session_get_uuid(session_a), SMF_REBRIDGE);
+ bypass_media_after_bridge = 0;
+ switch_channel_clear_flag(chan_a, CF_BYPASS_MEDIA_AFTER_BRIDGE);
+ goto end_of_bridge_loop;
+ }
}
/* if 1 channel has DTMF pass it to the other */
@@ -454,6 +469,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
status = switch_core_session_read_frame(session_a, &read_frame, SWITCH_IO_FLAG_NONE, stream_id);
if (SWITCH_READ_ACCEPTABLE(status)) {
+ read_frame_count++;
if (switch_test_flag(read_frame, SFF_CNG)) {
if (silence_val) {
switch_generate_sln_silence((int16_t *) silence_frame.data, silence_frame.samples, silence_val);
@@ -463,11 +479,6 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
}
}
- if (data->skip_frames) {
- data->skip_frames--;
- continue;
- }
-
if (switch_channel_test_flag(chan_a, CF_BRIDGE_NOWRITE)) {
continue;
}
@@ -1193,35 +1204,22 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses
switch_channel_set_variable(peer_channel, SWITCH_SIGNAL_BOND_VARIABLE, switch_core_session_get_uuid(session));
if ((app = switch_channel_get_variable(caller_channel, "bridge_pre_execute_aleg_app"))) {
- switch_event_t *execute_event;
-
- data = switch_channel_get_variable(caller_channel, "bridge_pre_execute_aleg_data");
- if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute");
- switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", app);
- switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", data);
- switch_event_add_header(execute_event, SWITCH_STACK_BOTTOM, "lead-frames", "%d", 5);
- switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true");
- switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE);
- a_leg->skip_frames = DEFAULT_LEAD_FRAMES;
+ switch_channel_set_variable(caller_channel, "bridge_pre_execute_app", app);
+
+ if ((data = switch_channel_get_variable(caller_channel, "bridge_pre_execute_aleg_data"))) {
+ switch_channel_set_variable(caller_channel, "bridge_pre_execute_data", data);
}
-
}
if ((app = switch_channel_get_variable(caller_channel, "bridge_pre_execute_bleg_app"))) {
- switch_event_t *execute_event;
- data = switch_channel_get_variable(caller_channel, "bridge_pre_execute_bleg_data");
- if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute");
- switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", app);
- switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", data);
- switch_event_add_header(execute_event, SWITCH_STACK_BOTTOM, "lead-frames", "%d", 5);
- switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true");
- switch_core_session_queue_private_event(peer_session, &execute_event, SWITCH_FALSE);
- b_leg->skip_frames = DEFAULT_LEAD_FRAMES;
- }
- }
+ switch_channel_set_variable(peer_channel, "bridge_pre_execute_app", app);
+ if ((data = switch_channel_get_variable(caller_channel, "bridge_pre_execute_bleg_data"))) {
+ switch_channel_set_variable(peer_channel, "bridge_pre_execute_data", data);
+ }
+
+ }
+
switch_channel_set_private(peer_channel, "_bridge_", b_leg);
switch_channel_set_state(peer_channel, CS_EXCHANGE_MEDIA);
audio_bridge_thread(NULL, (void *) a_leg);
diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c
index da76cf6cbc..e61534798b 100644
--- a/src/switch_ivr_originate.c
+++ b/src/switch_ivr_originate.c
@@ -635,8 +635,17 @@ static uint8_t check_channel_status(originate_global_t *oglobals, originate_stat
}
}
}
-
- switch_ivr_parse_all_events(originate_status[i].peer_session);
+
+ if (!switch_channel_test_flag(originate_status[i].peer_channel, CF_PARK) &&
+ !switch_channel_test_flag(originate_status[i].peer_channel, CF_CONSUME_ON_ORIGINATE)) {
+ if (switch_core_session_messages_waiting(originate_status[i].peer_session)) {
+ if (switch_channel_test_flag(originate_status[i].peer_channel, CF_THREAD_SLEEPING)) {
+ switch_core_session_wake_session_thread(originate_status[i].peer_session);
+ } else {
+ switch_ivr_parse_all_events(originate_status[i].peer_session);
+ }
+ }
+ }
state = switch_channel_get_state(originate_status[i].peer_channel);
if (state >= CS_HANGUP || state == CS_RESET || switch_channel_test_flag(originate_status[i].peer_channel, CF_TRANSFER) ||
diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c
index 7285b894ea..3c8fa5e10f 100644
--- a/src/switch_ivr_play_say.c
+++ b/src/switch_ivr_play_say.c
@@ -913,6 +913,31 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_gentones(switch_core_session_t *sessi
return SWITCH_STATUS_SUCCESS;
}
+SWITCH_DECLARE(switch_status_t) switch_ivr_get_file_handle(switch_core_session_t *session, switch_file_handle_t **fh)
+{
+ switch_file_handle_t *fhp;
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+
+ *fh = NULL;
+ switch_core_session_io_read_lock(session);
+
+ if ((fhp = switch_channel_get_private(channel, "__fh"))) {
+ *fh = fhp;
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ switch_core_session_io_rwunlock(session);
+
+ return SWITCH_STATUS_FALSE;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_release_file_handle(switch_core_session_t *session, switch_file_handle_t **fh)
+{
+ *fh = NULL;
+ switch_core_session_io_rwunlock(session);
+
+ return SWITCH_STATUS_SUCCESS;
+}
#define FILE_STARTSAMPLES 1024 * 32
#define FILE_BLOCKSIZE 1024 * 8
@@ -994,6 +1019,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
}
+
+
if (play_delimiter) {
file_dup = switch_core_session_strdup(session, file);
argc = switch_separate_string(file_dup, play_delimiter, argv, (sizeof(argv) / sizeof(argv[0])));
@@ -1134,6 +1161,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
status = SWITCH_STATUS_NOTFOUND;
continue;
}
+
+ switch_core_session_io_write_lock(session);
+ switch_channel_set_private(channel, "__fh", fh);
+ switch_core_session_io_rwunlock(session);
+
if (switch_test_flag(fh, SWITCH_FILE_NATIVE)) {
asis = 1;
}
@@ -1208,7 +1240,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"Raw Codec Activation Failed %s@%uhz %u channels %dms\n", codec_name, fh->samplerate, fh->channels, interval);
+ switch_core_session_io_write_lock(session);
+ switch_channel_set_private(channel, "__fh", NULL);
+ switch_core_session_io_rwunlock(session);
+
switch_core_file_close(fh);
+
switch_core_session_reset(session, SWITCH_TRUE, SWITCH_FALSE);
status = SWITCH_STATUS_GENERR;
continue;
@@ -1228,6 +1265,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
if (switch_core_timer_init(&timer, timer_name, interval, samples, pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Setup timer failed!\n");
switch_core_codec_destroy(&codec);
+ switch_core_session_io_write_lock(session);
+ switch_channel_set_private(channel, "__fh", NULL);
+ switch_core_session_io_rwunlock(session);
switch_core_file_close(fh);
switch_core_session_reset(session, SWITCH_TRUE, SWITCH_FALSE);
status = SWITCH_STATUS_GENERR;
@@ -1538,6 +1578,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
}
switch_channel_set_variable_printf(channel, "playback_samples", "%d", fh->samples_out);
+ switch_core_session_io_write_lock(session);
+ switch_channel_set_private(channel, "__fh", NULL);
+ switch_core_session_io_rwunlock(session);
+
switch_core_file_close(fh);
if (fh->audio_buffer) {
diff --git a/src/switch_odbc.c b/src/switch_odbc.c
index 36c3c996e8..a1c476e4a1 100644
--- a/src/switch_odbc.c
+++ b/src/switch_odbc.c
@@ -364,7 +364,6 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_exec_string(switch_odbc_
goto done;
}
- result = SQLExecute(stmt);
result = SQLFetch(stmt);
if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO && result != SQL_NO_DATA) {
diff --git a/src/switch_utils.c b/src/switch_utils.c
index 75be02a31f..1a29e2b715 100644
--- a/src/switch_utils.c
+++ b/src/switch_utils.c
@@ -726,18 +726,31 @@ SWITCH_DECLARE(switch_bool_t) switch_is_lan_addr(const char *ip)
if (zstr(ip))
return SWITCH_FALSE;
- return (strncmp(ip, "10.", 3) &&
- strncmp(ip, "192.168.", 8) &&
- strncmp(ip, "127.", 4) &&
+ return (strncmp(ip, "10.", 3) && /* 10.0.0.0 - 10.255.255.255 (10/8 prefix) */
+ strncmp(ip, "192.168.", 8) && /* 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) */
+ strncmp(ip, "127.", 4) && /* 127.0.0.0 - 127.255.255.255 (127/8 prefix) */
strncmp(ip, "255.", 4) &&
- strncmp(ip, "0.", 2) &&
+ strncmp(ip, "0.", 2) &&
strncmp(ip, "1.", 2) &&
strncmp(ip, "2.", 2) &&
- strncmp(ip, "172.16.", 7) &&
+ strncmp(ip, "172.16.", 7) && /* 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) */
strncmp(ip, "172.17.", 7) &&
strncmp(ip, "172.18.", 7) &&
strncmp(ip, "172.19.", 7) &&
- strncmp(ip, "172.2", 5) && strncmp(ip, "172.30.", 7) && strncmp(ip, "172.31.", 7) && strncmp(ip, "192.0.2.", 8) && strncmp(ip, "169.254.", 8)
+ strncmp(ip, "172.20.", 7) &&
+ strncmp(ip, "172.21.", 7) &&
+ strncmp(ip, "172.22.", 7) &&
+ strncmp(ip, "172.23.", 7) &&
+ strncmp(ip, "172.24.", 7) &&
+ strncmp(ip, "172.25.", 7) &&
+ strncmp(ip, "172.26.", 7) &&
+ strncmp(ip, "172.27.", 7) &&
+ strncmp(ip, "172.28.", 7) &&
+ strncmp(ip, "172.29.", 7) &&
+ strncmp(ip, "172.30.", 7) &&
+ strncmp(ip, "172.31.", 7) &&
+ strncmp(ip, "192.0.2.", 8) && /* 192.0.2.0 - 192.0.2.255 (192.0.2/24 prefix) */
+ strncmp(ip, "169.254.", 8) /* 169.254.0.0 - 169.254.255.255 (169.254/16 prefix) */
)? SWITCH_FALSE : SWITCH_TRUE;
}
diff --git a/w32/Setup/Setup.wixproj b/w32/Setup/Setup.wixproj
index 7d11c90a4b..fa6c832777 100644
--- a/w32/Setup/Setup.wixproj
+++ b/w32/Setup/Setup.wixproj
@@ -336,6 +336,15 @@
Binaries;Content;Satellites
MODLOCATION
+
+ mod_cepstral
+ {692f6330-4d87-4c82-81df-40db5892636e}
+ True
+
+
+ Binaries;Content;Satellites
+ MODLOCATION
+
mod_pocketsphinx
{2286da73-9fc5-45bc-a508-85994c3317ab}