diff --git a/Freeswitch.2008.express.sln b/Freeswitch.2008.express.sln index 672406bda2..d9cb441e2f 100644 --- a/Freeswitch.2008.express.sln +++ b/Freeswitch.2008.express.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 +# Visual C++ Express 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchConsole", "w32\Console\FreeSwitchConsole.2008.vcproj", "{1AF3A893-F7BE-43DD-B697-8AB2397C0D67}" ProjectSection(ProjectDependencies) = postProject {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} @@ -11,6 +11,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchCoreLib", "w32\Li ProjectSection(ProjectDependencies) = postProject {8D04B550-D240-4A44-8A18-35DA3F7038D9} = {8D04B550-D240-4A44-8A18-35DA3F7038D9} {89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C} + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3} {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} @@ -1641,6 +1642,7 @@ Global {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|Win32.Build.0 = Release|Win32 {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x64.ActiveCfg = Release|Win32 {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32 + {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|Win32.Build.0 = Debug|Win32 {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64.ActiveCfg = Debug|Win32 {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64.Build.0 = Debug|Win32 {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|Win32.ActiveCfg = Release|Win32 @@ -2046,6 +2048,7 @@ Global {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|Win32.Build.0 = Debug|Win32 {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|x64.ActiveCfg = Debug|Win32 {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|Win32.ActiveCfg = Release|Win32 + {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|Win32.Build.0 = Release|Win32 {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|x64.ActiveCfg = Release|Win32 {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|Win32.ActiveCfg = Release|Win32 {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|x64.ActiveCfg = Release|x64 diff --git a/Freeswitch.2010.sln b/Freeswitch.2010.sln index 186969891a..edee701d51 100644 --- a/Freeswitch.2010.sln +++ b/Freeswitch.2010.sln @@ -707,6 +707,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_distributor", "src\mod\ EndProject Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Setup", "w32\Setup\Setup.wixproj", "{47213370-B933-487D-9F45-BCA26D7E2B6F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_pt", "src\mod\say\mod_say_pt\mod_say_pt.2010.vcxproj", "{7C22BDFF-CC09-400C-8A09-660733980028}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Win32 = All|Win32 @@ -3619,6 +3621,23 @@ Global {47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x64 Setup.Build.0 = Release|x64 {47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x86 Setup.ActiveCfg = Release|x86 {47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x86 Setup.Build.0 = Release|x86 + {7C22BDFF-CC09-400C-8A09-660733980028}.All|Win32.ActiveCfg = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.All|x64.ActiveCfg = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.All|x64.Build.0 = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.All|x64 Setup.ActiveCfg = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.All|x86 Setup.ActiveCfg = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|Win32.ActiveCfg = Debug|Win32 + {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|Win32.Build.0 = Debug|Win32 + {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x64.ActiveCfg = Debug|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x64.Build.0 = Debug|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x64 Setup.ActiveCfg = Debug|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x86 Setup.ActiveCfg = Debug|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Release|Win32.ActiveCfg = Release|Win32 + {7C22BDFF-CC09-400C-8A09-660733980028}.Release|Win32.Build.0 = Release|Win32 + {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x64.ActiveCfg = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x64.Build.0 = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x64 Setup.ActiveCfg = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x86 Setup.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -3769,6 +3788,7 @@ Global {A4B122CF-5196-476B-8C0E-D8BD59AC3C14} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} {0382E8FD-CFDC-41C0-8B03-792C7C84FC31} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} + {7C22BDFF-CC09-400C-8A09-660733980028} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0} = {57D119DC-484F-420F-B9E9-8589FD9A8DF8} {7BFD517E-7F8F-4A40-A78E-8D3632738227} = {57D119DC-484F-420F-B9E9-8589FD9A8DF8} {6374D55C-FABE-4A02-9CF1-4145308A56C5} = {57D119DC-484F-420F-B9E9-8589FD9A8DF8} diff --git a/Makefile.am b/Makefile.am index da89572c6f..df1ee2e0d0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -276,7 +276,8 @@ bin_PROGRAMS = freeswitch fs_cli fs_ivrd tone2wav fs_encode ## ## fs_cli () ## -fs_cli_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c libs/esl/src/esl_threadmutex.c libs/esl/fs_cli.c libs/esl/src/esl_json.c +fs_cli_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c \ + libs/esl/src/esl_threadmutex.c libs/esl/fs_cli.c libs/esl/src/esl_json.c libs/esl/src/esl_buffer.c fs_cli_CFLAGS = $(AM_CFLAGS) -I$(switch_srcdir)/libs/esl/src/include fs_cli_LDFLAGS = $(AM_LDFLAGS) -lpthread $(ESL_LDFLAGS) -lm @@ -304,7 +305,8 @@ tone2wav_LDADD = libfreeswitch.la ## ## fs_ivrd () ## -fs_ivrd_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c libs/esl/src/esl_threadmutex.c libs/esl/ivrd.c libs/esl/src/esl_json.c +fs_ivrd_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c \ + libs/esl/src/esl_threadmutex.c libs/esl/ivrd.c libs/esl/src/esl_json.c libs/esl/src/esl_buffer.c fs_ivrd_CFLAGS = $(AM_CFLAGS) -I$(switch_srcdir)/libs/esl/src/include fs_ivrd_LDFLAGS = $(AM_LDFLAGS) -lpthread $(ESL_LDFLAGS) -lm diff --git a/build/modules.conf.in b/build/modules.conf.in index 13e655672c..69d90a8dd4 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -73,6 +73,8 @@ endpoints/mod_loopback #event_handlers/mod_event_multicast event_handlers/mod_event_socket event_handlers/mod_cdr_csv +event_handlers/mod_cdr_sqlite +#event_handlers/mod_cdr_pg_csv #event_handlers/mod_radius_cdr #event_handlers/mod_erlang_event formats/mod_native_file @@ -100,6 +102,7 @@ say/mod_say_en #say/mod_say_fr #say/mod_say_it #say/mod_say_nl +#say/mod_say_pt say/mod_say_ru #say/mod_say_zh #say/mod_say_hu diff --git a/conf/autoload_configs/cdr_pg_csv.conf.xml b/conf/autoload_configs/cdr_pg_csv.conf.xml index ec62053190..2f2efa9b26 100644 --- a/conf/autoload_configs/cdr_pg_csv.conf.xml +++ b/conf/autoload_configs/cdr_pg_csv.conf.xml @@ -1,23 +1,21 @@ + + + + + + + - + + + - - - - - - - - - - - diff --git a/conf/autoload_configs/cdr_sqlite.conf.xml b/conf/autoload_configs/cdr_sqlite.conf.xml new file mode 100644 index 0000000000..872c04c4fb --- /dev/null +++ b/conf/autoload_configs/cdr_sqlite.conf.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/conf/autoload_configs/modules.conf.xml b/conf/autoload_configs/modules.conf.xml index 118d7c4d81..51c62f2059 100644 --- a/conf/autoload_configs/modules.conf.xml +++ b/conf/autoload_configs/modules.conf.xml @@ -19,6 +19,7 @@ + diff --git a/conf/autoload_configs/switch.conf.xml b/conf/autoload_configs/switch.conf.xml index 896dd0e712..fba809ba2c 100644 --- a/conf/autoload_configs/switch.conf.xml +++ b/conf/autoload_configs/switch.conf.xml @@ -23,7 +23,13 @@ - + diff --git a/conf/directory/default/default.xml b/conf/directory/default/default.xml index 5db60112dc..aa138f18d9 100644 --- a/conf/directory/default/default.xml +++ b/conf/directory/default/default.xml @@ -1,7 +1,7 @@ @@ -390,15 +397,10 @@ - - - - - @@ -409,10 +411,7 @@ - - - @@ -425,20 +424,10 @@ - - - - - - - - - - - - - + + + diff --git a/docs/phrase/phrase_es_ES.xml b/docs/phrase/phrase_es_ES.xml new file mode 100644 index 0000000000..ad99c1bf73 --- /dev/null +++ b/docs/phrase/phrase_es_ES.xml @@ -0,0 +1,994 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/phrase/phrase_es_MX.xml b/docs/phrase/phrase_es_MX.xml new file mode 100644 index 0000000000..527f8c3c89 --- /dev/null +++ b/docs/phrase/phrase_es_MX.xml @@ -0,0 +1,993 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/phrase/phrase_pt_BR.xml b/docs/phrase/phrase_pt_BR.xml new file mode 100644 index 0000000000..9cc400c76b --- /dev/null +++ b/docs/phrase/phrase_pt_BR.xml @@ -0,0 +1,987 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/phrase/phrase_pt_PT.xml b/docs/phrase/phrase_pt_PT.xml new file mode 100644 index 0000000000..a0e59deb85 --- /dev/null +++ b/docs/phrase/phrase_pt_PT.xml @@ -0,0 +1,987 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/freeswitch.spec b/freeswitch.spec index ceacfbafb2..05401b8e8a 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -379,7 +379,7 @@ ENDPOINTS_MODULES="endpoints/mod_dingaling endpoints/mod_loopback ../../libs/fre # Event Handlers # ###################################################################################################################### -EVENT_HANDLERS_MODULES="event_handlers/mod_cdr_csv event_handlers/mod_event_socket event_handlers/mod_event_multicast" +EVENT_HANDLERS_MODULES="event_handlers/mod_cdr_csv event_handlers/mod_cdr_sqlite event_handlers/mod_event_socket event_handlers/mod_event_multicast" ###################################################################################################################### # # File and Audio Format Handlers @@ -620,6 +620,7 @@ fi %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/callcenter.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/cdr_csv.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/cdr_pg_csv.conf.xml +%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/cdr_sqlite.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/cidlookup.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/conference.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/console.conf.xml @@ -746,6 +747,7 @@ fi %{prefix}/mod/mod_bv.so* %{prefix}/mod/mod_callcenter.so* %{prefix}/mod/mod_cdr_csv.so* +%{prefix}/mod/mod_cdr_sqlite.so* %{prefix}/mod/mod_celt.so* %{prefix}/mod/mod_cidlookup.so* %{prefix}/mod/mod_cluechoo.so* diff --git a/libs/esl/Makefile b/libs/esl/Makefile index a180406bda..ab50bac4d9 100644 --- a/libs/esl/Makefile +++ b/libs/esl/Makefile @@ -9,9 +9,9 @@ CXXFLAGS=$(BASE_FLAGS) -Wall -Werror -Wno-unused-variable MYLIB=libesl.a LIBS=-lncurses -lpthread -lesl -lm LDFLAGS=-L. -OBJS=src/esl.o src/esl_event.o src/esl_threadmutex.o src/esl_config.o src/esl_json.o -SRC=src/esl.c src/esl_json.c src/esl_event.c src/esl_threadmutex.c src/esl_config.c src/esl_oop.cpp src/esl_json.c -HEADERS=src/include/esl_config.h src/include/esl_event.h src/include/esl.h src/include/esl_threadmutex.h src/include/esl_oop.h src/include/esl_json.h +OBJS=src/esl.o src/esl_event.o src/esl_threadmutex.o src/esl_config.o src/esl_json.o src/esl_buffer.o +SRC=src/esl.c src/esl_json.c src/esl_event.c src/esl_threadmutex.c src/esl_config.c src/esl_oop.cpp src/esl_json.c src/esl_buffer.c +HEADERS=src/include/esl_config.h src/include/esl_event.h src/include/esl.h src/include/esl_threadmutex.h src/include/esl_oop.h src/include/esl_json.h src/include/esl_buffer.h SOLINK=-shared -Xlinker -x # comment the next line to disable c++ (no swig mods for you then) OBJS += src/esl_oop.o diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index 569e2cd169..1e3bf04ca1 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -656,7 +656,7 @@ static int process_command(esl_handle_t *handle, const char *cmd) "-----------------------------------------------\n" "/help \tHelp\n" "/exit, /quit, /bye, ... \tExit the program.\n" - "/event, /noevent, /nixevent\tEvent commands.\n" + "/event, /noevents, /nixevent\tEvent commands.\n" "/log, /nolog \tLog commands.\n" "/uuid \tFilter logs for a single call uuid\n" "/filter \tFilter commands.\n" @@ -692,7 +692,7 @@ static int process_command(esl_handle_t *handle, const char *cmd) } else if ( !strncasecmp(cmd, "event", 5) || - !strncasecmp(cmd, "noevent", 7) || + !strncasecmp(cmd, "noevents", 8) || !strncasecmp(cmd, "nixevent", 8) || !strncasecmp(cmd, "log", 3) || !strncasecmp(cmd, "nolog", 5) || diff --git a/libs/esl/lua/esl_lua.2008.sln b/libs/esl/lua/esl_lua.2008.sln new file mode 100644 index 0000000000..cdfbd44ab7 --- /dev/null +++ b/libs/esl/lua/esl_lua.2008.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ESL", "esl_lua.2008.vcproj", "{86B6AB99-A261-455A-9CD6-9142A5A1652E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {86B6AB99-A261-455A-9CD6-9142A5A1652E}.Debug|Win32.ActiveCfg = Debug|Win32 + {86B6AB99-A261-455A-9CD6-9142A5A1652E}.Debug|Win32.Build.0 = Debug|Win32 + {86B6AB99-A261-455A-9CD6-9142A5A1652E}.Debug|x64.ActiveCfg = Debug|x64 + {86B6AB99-A261-455A-9CD6-9142A5A1652E}.Debug|x64.Build.0 = Debug|x64 + {86B6AB99-A261-455A-9CD6-9142A5A1652E}.Release|Win32.ActiveCfg = Release|Win32 + {86B6AB99-A261-455A-9CD6-9142A5A1652E}.Release|Win32.Build.0 = Release|Win32 + {86B6AB99-A261-455A-9CD6-9142A5A1652E}.Release|x64.ActiveCfg = Release|x64 + {86B6AB99-A261-455A-9CD6-9142A5A1652E}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/libs/esl/lua/esl_lua.2008.vcproj b/libs/esl/lua/esl_lua.2008.vcproj new file mode 100644 index 0000000000..38111c8580 --- /dev/null +++ b/libs/esl/lua/esl_lua.2008.vcproj @@ -0,0 +1,351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/esl/perl/ESL/Dispatch.pm b/libs/esl/perl/ESL/Dispatch.pm index 1d21934046..d1712d1cfc 100644 --- a/libs/esl/perl/ESL/Dispatch.pm +++ b/libs/esl/perl/ESL/Dispatch.pm @@ -40,7 +40,8 @@ sub set_callback($;$$) { $self->{_callback}->{$event} = shift; my $subclass = shift; if($subclass) { - $self->{_custom_subclass} = split(/,/, $subclass); + my @subclasses = split(/,/, $subclass); + $self->{_custom_subclass} = \@subclasses; } } @@ -79,7 +80,7 @@ sub run($;) { for(;;) { # Only register for events we have callbacks for. for my $key ( keys %{$self->{_callback}} ) { - if ($key eq "CUSTOM") { + if ($key =~ m/custom/i) { foreach $subclass (@{$self->{_custom_subclass}}) { $self->{_esl}->events("plain", "$key $subclass"); } diff --git a/libs/esl/src/esl.2008.vcproj b/libs/esl/src/esl.2008.vcproj index 101348dd59..89daa17d9e 100644 --- a/libs/esl/src/esl.2008.vcproj +++ b/libs/esl/src/esl.2008.vcproj @@ -290,6 +290,10 @@ RelativePath=".\esl.c" > + + @@ -316,6 +320,10 @@ RelativePath=".\include\esl.h" > + + diff --git a/libs/esl/src/esl.2010.vcxproj b/libs/esl/src/esl.2010.vcxproj index b215fe4bc8..fd5e3a8353 100644 --- a/libs/esl/src/esl.2010.vcxproj +++ b/libs/esl/src/esl.2010.vcxproj @@ -128,6 +128,7 @@ + @@ -135,6 +136,7 @@ + diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c index ce582d3837..f5bab62fcb 100644 --- a/libs/esl/src/esl.c +++ b/libs/esl/src/esl.c @@ -428,6 +428,10 @@ ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t s esl_mutex_create(&handle->mutex); } + if (!handle->packet_buf) { + esl_buffer_create(&handle->packet_buf, BUF_CHUNK, BUF_START, 0); + } + handle->connected = 1; esl_send_recv(handle, "connect\n\n"); @@ -632,6 +636,10 @@ ESL_DECLARE(esl_status_t) esl_connect_timeout(esl_handle_t *handle, const char * if (!handle->mutex) { esl_mutex_create(&handle->mutex); } + + if (!handle->packet_buf) { + esl_buffer_create(&handle->packet_buf, BUF_CHUNK, BUF_START, 0); + } handle->sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -805,6 +813,11 @@ ESL_DECLARE(esl_status_t) esl_disconnect(esl_handle_t *handle) esl_mutex_destroy(&mutex); } + if (handle->packet_buf) { + esl_buffer_destroy(&handle->packet_buf); + } + + return status; } @@ -825,7 +838,7 @@ ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms if (check_q) { esl_mutex_lock(handle->mutex); - if (handle->race_event) { + if (handle->race_event || esl_buffer_packet_count(handle->packet_buf)) { esl_mutex_unlock(handle->mutex); return esl_recv_event(handle, check_q, save_event); } @@ -894,12 +907,15 @@ ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms } +static esl_ssize_t handle_recv(esl_handle_t *handle, void *data, esl_size_t datalen) +{ + return recv(handle->sock, data, datalen, 0); +} ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_event_t **save_event) { char *c; esl_ssize_t rrval; - int crc = 0; esl_event_t *revent = NULL; char *beg; char *hname, *hval; @@ -907,7 +923,6 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ char *cl; esl_ssize_t len; int zc = 0; - int bread = 0; if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) { return ESL_FAIL; @@ -916,9 +931,7 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ esl_mutex_lock(handle->mutex); if (!handle->connected || handle->sock == ESL_SOCK_INVALID) { - handle->connected = 0; - esl_mutex_unlock(handle->mutex); - return ESL_FAIL; + goto fail; } esl_event_safe_destroy(&handle->last_event); @@ -932,76 +945,62 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ goto parse_event; } - memset(handle->header_buf, 0, sizeof(handle->header_buf)); + + while(!revent && handle->connected) { + esl_size_t len1; + + if ((len1 = esl_buffer_read_packet(handle->packet_buf, handle->socket_buf, sizeof(handle->socket_buf)))) { + char *data = (char *) handle->socket_buf; + char *p, *e; + + esl_event_create(&revent, ESL_EVENT_CLONE); + revent->event_id = ESL_EVENT_SOCKET_DATA; + esl_event_add_header_string(revent, ESL_STACK_BOTTOM, "Event-Name", "SOCKET_DATA"); + + hname = p = data; + while(p) { + hname = p; + p = NULL; - c = handle->header_buf; - beg = c; + if ((hval = strchr(hname, ':'))) { + *hval++ = '\0'; + while(*hval == ' ' || *hval == '\t') hval++; - while(handle->connected) { - if (bread + 2 >= sizeof(handle->header_buf)) { - esl_log(ESL_LOG_CRIT, "OUT OF BUFFER SPACE!\n"); - handle->connected = 0; - esl_mutex_unlock(handle->mutex); - return ESL_DISCONNECTED; + if ((e = strchr(hval, '\n'))) { + *e++ = '\0'; + while(*e == '\n' || *e == '\r') e++; + + if (hname && hval) { + esl_url_decode(hval); + esl_log(ESL_LOG_DEBUG, "RECV HEADER [%s] = [%s]\n", hname, hval); + esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval); + } + + p = e; + } + } + } + + break; } - rrval = recv(handle->sock, c, 1, 0); + rrval = handle_recv(handle, handle->socket_buf, sizeof(handle->socket_buf)); + if (rrval == 0) { if (++zc >= 100) { - handle->connected = 0; - esl_mutex_unlock(handle->mutex); - return ESL_DISCONNECTED; + goto fail; } + continue; } else if (rrval < 0) { strerror_r(handle->errnum, handle->err, sizeof(handle->err)); goto fail; - } else { - zc = 0; - - if (*c == '\n') { - - *(c+1) = '\0'; - - if (++crc == 2) { - break; - } - - if (!revent) { - esl_event_create(&revent, ESL_EVENT_CLONE); - revent->event_id = ESL_EVENT_SOCKET_DATA; - esl_event_add_header_string(revent, ESL_STACK_BOTTOM, "Event-Name", "SOCKET_DATA"); - - } - - hname = beg; - hval = col = NULL; - - if (hname && (col = strchr(hname, ':'))) { - hval = col + 1; - *col = '\0'; - while(*hval == ' ') hval++; - } - - *c = '\0'; - - if (hname && hval) { - esl_url_decode(hval); - esl_log(ESL_LOG_DEBUG, "RECV HEADER [%s] = [%s]\n", hname, hval); - esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval); - } - - c = beg; - bread = 0; - continue; - - } else { - crc = 0; - } - - c++; } - } + zc = 0; + + esl_buffer_write(handle->packet_buf, handle->socket_buf, rrval); + } + if (!revent) { goto fail; } @@ -1016,12 +1015,28 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ *(body + len) = '\0'; do { - esl_ssize_t r; - if ((r = recv(handle->sock, body + sofar, len - sofar, 0)) < 0) { - strerror_r(handle->errnum, handle->err, sizeof(handle->err)); - goto fail; + esl_ssize_t r,s = esl_buffer_inuse(handle->packet_buf); + + if (s >= len) { + sofar = esl_buffer_read(handle->packet_buf, body, len); + } else { + r = handle_recv(handle, handle->socket_buf, sizeof(handle->socket_buf)); + + if (r < 0) { + strerror_r(handle->errnum, handle->err, sizeof(handle->err)); + goto fail; + } else if (r == 0) { + if (++zc >= 100) { + goto fail; + } + continue; + } + + zc = 0; + + esl_buffer_write(handle->packet_buf, handle->socket_buf, r); } - sofar += r; + } while (sofar < len); revent->body = body; @@ -1123,6 +1138,8 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ fail: + esl_mutex_unlock(handle->mutex); + handle->connected = 0; return ESL_FAIL; diff --git a/libs/esl/src/esl_buffer.c b/libs/esl/src/esl_buffer.c new file mode 100644 index 0000000000..8032169fe3 --- /dev/null +++ b/libs/esl/src/esl_buffer.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2010, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "esl_buffer.h" + +static unsigned buffer_id = 0; + +struct esl_buffer { + unsigned char *data; + unsigned char *head; + esl_size_t used; + esl_size_t actually_used; + esl_size_t datalen; + esl_size_t max_len; + esl_size_t blocksize; + unsigned id; + int loops; +}; + + +ESL_DECLARE(esl_status_t) esl_buffer_create(esl_buffer_t **buffer, esl_size_t blocksize, esl_size_t start_len, esl_size_t max_len) +{ + esl_buffer_t *new_buffer; + + new_buffer = malloc(sizeof(*new_buffer)); + if (new_buffer) { + memset(new_buffer, 0, sizeof(*new_buffer)); + + if (start_len) { + new_buffer->data = malloc(start_len); + if (!new_buffer->data) { + free(new_buffer); + return ESL_FAIL; + } + memset(new_buffer->data, 0, start_len); + } + + new_buffer->max_len = max_len; + new_buffer->datalen = start_len; + new_buffer->id = buffer_id++; + new_buffer->blocksize = blocksize; + new_buffer->head = new_buffer->data; + + *buffer = new_buffer; + return ESL_SUCCESS; + } + + return ESL_FAIL; +} + +ESL_DECLARE(esl_size_t) esl_buffer_len(esl_buffer_t *buffer) +{ + + assert(buffer != NULL); + + return buffer->datalen; + +} + + +ESL_DECLARE(esl_size_t) esl_buffer_freespace(esl_buffer_t *buffer) +{ + assert(buffer != NULL); + + + if (buffer->max_len) { + return (esl_size_t) (buffer->max_len - buffer->used); + } + return 1000000; + +} + +ESL_DECLARE(esl_size_t) esl_buffer_inuse(esl_buffer_t *buffer) +{ + assert(buffer != NULL); + + return buffer->used; +} + +ESL_DECLARE(esl_size_t) esl_buffer_seek(esl_buffer_t *buffer, esl_size_t datalen) +{ + esl_size_t reading = 0; + + assert(buffer != NULL); + + if (buffer->used < 1) { + buffer->used = 0; + return 0; + } else if (buffer->used >= datalen) { + reading = datalen; + } else { + reading = buffer->used; + } + + buffer->used = buffer->actually_used - reading; + buffer->head = buffer->data + reading; + + return reading; +} + +ESL_DECLARE(esl_size_t) esl_buffer_toss(esl_buffer_t *buffer, esl_size_t datalen) +{ + esl_size_t reading = 0; + + assert(buffer != NULL); + + if (buffer->used < 1) { + buffer->used = 0; + return 0; + } else if (buffer->used >= datalen) { + reading = datalen; + } else { + reading = buffer->used; + } + + buffer->used -= reading; + buffer->head += reading; + + return buffer->used; +} + +ESL_DECLARE(void) esl_buffer_set_loops(esl_buffer_t *buffer, int loops) +{ + buffer->loops = loops; +} + +ESL_DECLARE(esl_size_t) esl_buffer_read_loop(esl_buffer_t *buffer, void *data, esl_size_t datalen) +{ + esl_size_t len; + if ((len = esl_buffer_read(buffer, data, datalen)) < datalen) { + if (buffer->loops == 0) { + return len; + } + buffer->head = buffer->data; + buffer->used = buffer->actually_used; + len = esl_buffer_read(buffer, (char*)data + len, datalen - len); + buffer->loops--; + } + return len; +} + +ESL_DECLARE(esl_size_t) esl_buffer_read(esl_buffer_t *buffer, void *data, esl_size_t datalen) +{ + esl_size_t reading = 0; + + assert(buffer != NULL); + assert(data != NULL); + + + if (buffer->used < 1) { + buffer->used = 0; + return 0; + } else if (buffer->used >= datalen) { + reading = datalen; + } else { + reading = buffer->used; + } + + memcpy(data, buffer->head, reading); + buffer->used -= reading; + buffer->head += reading; + + /* if (buffer->id == 4) printf("%u o %d = %d\n", buffer->id, (unsigned)reading, (unsigned)buffer->used); */ + return reading; +} + + +ESL_DECLARE(esl_size_t) esl_buffer_packet_count(esl_buffer_t *buffer) +{ + char *pe, *p, *e, *head = (char *) buffer->head; + esl_size_t x = 0; + + assert(buffer != NULL); + + e = (head + buffer->used); + + for (p = head; p && *p && p < e; p++) { + if (*p == '\n') { + pe = p+1; + if (*pe == '\r') pe++; + if (pe <= e && *pe == '\n') { + p = pe++; + x++; + } + } + } + + return x; +} + +ESL_DECLARE(esl_size_t) esl_buffer_read_packet(esl_buffer_t *buffer, void *data, esl_size_t maxlen) +{ + char *pe, *p, *e, *head = (char *) buffer->head; + esl_size_t datalen = 0; + + assert(buffer != NULL); + assert(data != NULL); + + e = (head + buffer->used); + + for (p = head; p && *p && p < e; p++) { + if (*p == '\n') { + pe = p+1; + if (*pe == '\r') pe++; + if (pe <= e && *pe == '\n') { + pe++; + datalen = pe - head; + if (datalen > maxlen) { + datalen = maxlen; + } + break; + } + } + } + + return esl_buffer_read(buffer, data, datalen); +} + +ESL_DECLARE(esl_size_t) esl_buffer_write(esl_buffer_t *buffer, const void *data, esl_size_t datalen) +{ + esl_size_t freespace, actual_freespace; + + assert(buffer != NULL); + assert(data != NULL); + assert(buffer->data != NULL); + + if (!datalen) { + return buffer->used; + } + + actual_freespace = buffer->datalen - buffer->actually_used; + if (actual_freespace < datalen && (!buffer->max_len || (buffer->used + datalen <= buffer->max_len))) { + memmove(buffer->data, buffer->head, buffer->used); + buffer->head = buffer->data; + buffer->actually_used = buffer->used; + } + + freespace = buffer->datalen - buffer->used; + + /* + if (buffer->data != buffer->head) { + memmove(buffer->data, buffer->head, buffer->used); + buffer->head = buffer->data; + } + */ + + if (freespace < datalen) { + esl_size_t new_size, new_block_size; + void *data1; + + new_size = buffer->datalen + datalen; + new_block_size = buffer->datalen + buffer->blocksize; + + if (new_block_size > new_size) { + new_size = new_block_size; + } + buffer->head = buffer->data; + data1 = realloc(buffer->data, new_size); + if (!data1) { + return 0; + } + buffer->data = data1; + buffer->head = buffer->data; + buffer->datalen = new_size; + } + + + freespace = buffer->datalen - buffer->used; + + if (freespace < datalen) { + return 0; + } else { + memcpy(buffer->head + buffer->used, data, datalen); + buffer->used += datalen; + buffer->actually_used += datalen; + } + /* if (buffer->id == 4) printf("%u i %d = %d\n", buffer->id, (unsigned)datalen, (unsigned)buffer->used); */ + + return buffer->used; +} + +ESL_DECLARE(void) esl_buffer_zero(esl_buffer_t *buffer) +{ + assert(buffer != NULL); + assert(buffer->data != NULL); + + buffer->used = 0; + buffer->actually_used = 0; + buffer->head = buffer->data; +} + +ESL_DECLARE(esl_size_t) esl_buffer_zwrite(esl_buffer_t *buffer, const void *data, esl_size_t datalen) +{ + esl_size_t w; + + if (!(w = esl_buffer_write(buffer, data, datalen))) { + esl_buffer_zero(buffer); + return esl_buffer_write(buffer, data, datalen); + } + + return w; +} + +ESL_DECLARE(void) esl_buffer_destroy(esl_buffer_t **buffer) +{ + if (*buffer) { + free((*buffer)->data); + free(*buffer); + } + + *buffer = NULL; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/libs/esl/src/include/esl.h b/libs/esl/src/include/esl.h index 9f28c3d925..99ab53ae95 100644 --- a/libs/esl/src/include/esl.h +++ b/libs/esl/src/include/esl.h @@ -251,6 +251,7 @@ typedef int esl_filehandle_t; #include "esl_json.h" typedef int16_t esl_port_t; +typedef size_t esl_size_t; typedef enum { ESL_SUCCESS, @@ -259,7 +260,11 @@ typedef enum { ESL_DISCONNECTED } esl_status_t; +#define BUF_CHUNK 65536 * 50 +#define BUF_START 65536 * 100 + #include +#include /*! \brief A handle that will hold the socket information and different events received. */ @@ -273,7 +278,8 @@ typedef struct { /*! The error number reported by the OS */ int errnum; /*! The inner contents received by the socket. Used only internally. */ - char header_buf[4196]; + esl_buffer_t *packet_buf; + char socket_buf[65536]; /*! Last command reply */ char last_reply[1024]; /*! Las command reply when called with esl_send_recv */ diff --git a/libs/esl/src/include/esl_buffer.h b/libs/esl/src/include/esl_buffer.h new file mode 100644 index 0000000000..c7901e4ede --- /dev/null +++ b/libs/esl/src/include/esl_buffer.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2010, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "esl.h" +#ifndef ESL_BUFFER_H +#define ESL_BUFFER_H +/** + * @defgroup esl_buffer Buffer Routines + * @ingroup buffer + * The purpose of this module is to make a plain buffering interface that can be used for read/write buffers + * throughout the application. + * @{ + */ +struct esl_buffer; +typedef struct esl_buffer esl_buffer_t; + +/*! \brief Allocate a new dynamic esl_buffer + * \param buffer returned pointer to the new buffer + * \param blocksize length to realloc by as data is added + * \param start_len ammount of memory to reserve initially + * \param max_len length the buffer is allowed to grow to + * \return status + */ +ESL_DECLARE(esl_status_t) esl_buffer_create(esl_buffer_t **buffer, esl_size_t blocksize, esl_size_t start_len, esl_size_t max_len); + +/*! \brief Get the length of a esl_buffer_t + * \param buffer any buffer of type esl_buffer_t + * \return int size of the buffer. + */ +ESL_DECLARE(esl_size_t) esl_buffer_len(esl_buffer_t *buffer); + +/*! \brief Get the freespace of a esl_buffer_t + * \param buffer any buffer of type esl_buffer_t + * \return int freespace in the buffer. + */ +ESL_DECLARE(esl_size_t) esl_buffer_freespace(esl_buffer_t *buffer); + +/*! \brief Get the in use amount of a esl_buffer_t + * \param buffer any buffer of type esl_buffer_t + * \return int ammount of buffer curently in use + */ +ESL_DECLARE(esl_size_t) esl_buffer_inuse(esl_buffer_t *buffer); + +/*! \brief Read data from a esl_buffer_t up to the ammount of datalen if it is available. Remove read data from buffer. + * \param buffer any buffer of type esl_buffer_t + * \param data pointer to the read data to be returned + * \param datalen amount of data to be returned + * \return int ammount of data actually read + */ +ESL_DECLARE(esl_size_t) esl_buffer_read(esl_buffer_t *buffer, void *data, esl_size_t datalen); + +ESL_DECLARE(esl_size_t) esl_buffer_read_packet(esl_buffer_t *buffer, void *data, esl_size_t maxlen); +ESL_DECLARE(esl_size_t) esl_buffer_packet_count(esl_buffer_t *buffer); + +/*! \brief Read data endlessly from a esl_buffer_t + * \param buffer any buffer of type esl_buffer_t + * \param data pointer to the read data to be returned + * \param datalen amount of data to be returned + * \return int ammount of data actually read + * \note Once you have read all the data from the buffer it will loop around. + */ +ESL_DECLARE(esl_size_t) esl_buffer_read_loop(esl_buffer_t *buffer, void *data, esl_size_t datalen); + +/*! \brief Assign a number of loops to read + * \param buffer any buffer of type esl_buffer_t + * \param loops the number of loops (-1 for infinite) + */ +ESL_DECLARE(void) esl_buffer_set_loops(esl_buffer_t *buffer, int32_t loops); + +/*! \brief Write data into a esl_buffer_t up to the length of datalen + * \param buffer any buffer of type esl_buffer_t + * \param data pointer to the data to be written + * \param datalen amount of data to be written + * \return int amount of buffer used after the write, or 0 if no space available + */ +ESL_DECLARE(esl_size_t) esl_buffer_write(esl_buffer_t *buffer, const void *data, esl_size_t datalen); + +/*! \brief Remove data from the buffer + * \param buffer any buffer of type esl_buffer_t + * \param datalen amount of data to be removed + * \return int size of buffer, or 0 if unable to toss that much data + */ +ESL_DECLARE(esl_size_t) esl_buffer_toss(esl_buffer_t *buffer, esl_size_t datalen); + +/*! \brief Remove all data from the buffer + * \param buffer any buffer of type esl_buffer_t + */ +ESL_DECLARE(void) esl_buffer_zero(esl_buffer_t *buffer); + +/*! \brief Destroy the buffer + * \param buffer buffer to destroy + * \note only neccessary on dynamic buffers (noop on pooled ones) + */ +ESL_DECLARE(void) esl_buffer_destroy(esl_buffer_t **buffer); + +/*! \brief Seek to offset from the beginning of the buffer + * \param buffer buffer to seek + * \param datalen offset in bytes + * \return new position + */ +ESL_DECLARE(esl_size_t) esl_buffer_seek(esl_buffer_t *buffer, esl_size_t datalen); + +/** @} */ + +ESL_DECLARE(esl_size_t) esl_buffer_zwrite(esl_buffer_t *buffer, const void *data, esl_size_t datalen); + +#endif +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index 5e804b7505..2ab5c29e18 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -73,6 +73,7 @@ libfreetdm_la_SOURCES = \ $(SRC)/hashtable.c \ $(SRC)/hashtable_itr.c \ $(SRC)/ftdm_io.c \ + $(SRC)/ftdm_state.c \ $(SRC)/ftdm_queue.c \ $(SRC)/ftdm_sched.c \ $(SRC)/ftdm_call_utils.c \ diff --git a/libs/freetdm/conf/freetdm.conf.xml b/libs/freetdm/conf/freetdm.conf.xml index 63a3ea62cd..43197af4bc 100644 --- a/libs/freetdm/conf/freetdm.conf.xml +++ b/libs/freetdm/conf/freetdm.conf.xml @@ -12,31 +12,81 @@ with the signaling protocols that you can run on top of your I/O interfaces. + - + - - + + + + + + + - - + + + + + + + + + + + + + + + + - diff --git a/libs/freetdm/conf/m3ua.conf b/libs/freetdm/conf/m3ua.conf deleted file mode 100644 index e3eeed3a4a..0000000000 --- a/libs/freetdm/conf/m3ua.conf +++ /dev/null @@ -1,38 +0,0 @@ -;M3UA SS7 Links Config -; -;ss7box-m3ua_mode => true -;local_sctp_ip => localhost -;local sctp_port => 30000 -;remote_sctp_ip => localhost -;remote_sctp_port => 30001 -;opc => 0-0-0 -;dpc => 0-0-0 - - -; AP Specific Stuff. This will likely move later. - -; CNAM Gateways -cnam1_dpc => 0-0-0 -cnam1_ssn => 253 -cnam2_dpc => 0-0-0 -cnam2_ssn => 253 -cnam3_dpc => 0-0-0 -cnam3_ssn => 253 - -;LNP Gateways -lnp1_dpc => 0-0-0 -lnp1_ssn => 253 -lnp2_dpc => 0-0-0 -lnp2_ssn => 253 -lnp3_dpc => 0-0-0 -lnp3_ssn => 253 - -;LNP Gateways -sms8001_dpc => 0-0-0 -sms8001_ssn => 253 -sms8002_dpc => 0-0-0 -sms8002_ssn => 253 -sms8003_dpc => 0-0-0 -sms8003_ssn => 253 - - diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac index e26f10b0b2..a070e994a3 100644 --- a/libs/freetdm/configure.ac +++ b/libs/freetdm/configure.ac @@ -160,7 +160,7 @@ AC_ARG_WITH([pritap], [AS_HELP_STRING([--with-pritap], [Install ftmod_pritap])], [case "${withval}" in no) enable_pritap="no" ;; - *) enable_pritab="yes" ;; + *) enable_pritap="yes" ;; esac], [enable_pritap="no"] ) diff --git a/libs/freetdm/docs/locking.txt b/libs/freetdm/docs/locking.txt new file mode 100644 index 0000000000..851d045b41 --- /dev/null +++ b/libs/freetdm/docs/locking.txt @@ -0,0 +1,125 @@ +Last Updated: Fri 30 Dec, 2010 + +== Background == + +FreeTDM is a threaded library. As such, locking considerations must be taken when using it and when writing code inside the library. + +At the moment locks are not exposed to users. This means API users cannot acquire a lock on a channel or span structure. There is no +need for users to lock channels or spans since all their interactions with those structures should be done thru the FreeTDM API which +can (and in most cases must) internally lock on their behalf. + +Internally, locking can be done either by the core or the signaling modules. To better understand the locking considerations we must +understand first the threading model of FreeTDM. + +== Threading Model == + +At startup, when the user calls ftdm_global_init(), just one timing thread is created to dispatch internal timers. If you write +a signaling module or any other code using the scheduling API, you can choose to run your schedule in this timing thread or in +a thread of your choice. This is the only thread launched at initialization. + +If the application decides to use ftdm_global_configuration(), which reads freetdm.conf to create the spans and channels data +structures, then possibly another thread will be launched for CPU usage monitoring (only if enabled in the configuration cpu_monitor=yes +This thread sole purpose is to check the CPU and raise an alarm if reaches a configurable threshold, the alarm then is checked to avoid +placing or receiving further calls. + +At this point FreeTDM has initialized and configured its channels input output configuration. + +The user is then supposed to configure the signaling via ftdm_configure_span_signaling() and then start the signaling work +using ftdm_span_start(). This will typically launch at least 1 thread per span. Some signaling modules (actually just the analog one) +launches another thread per channel when receiving a call. The rest of the signaling modules currently launch only one thread per +span and the signaling for all channels within the span is handled in that thread. We call that thread 'the signaling thread'. + +At this point the user can start placing calls using the FreeTDM call API ftdm_channel_call_place(). Any of the possible threads in +which the user calls the FreeTDM API is called 'the user thread', depending on the application thread model (the application using FreeTDM) +this user thread may be different each time or the same all the time, we cannot make any assumptions. In the case of FreeSWITCH, the most +common user of FreeTDM, the user thread is most of the cases a thread for each new call leg. + +At this point we have identified 4 types of threads. + +1. The timing thread (the core thread that triggers timers). + Its responsibility is simply check for timers that were scheduled and trigger them when the time comes. This means that if you decide + to use the scheduling API in freerun mode (where you use the core timer thread) you callbacks will be executed in this global thread + and you MUST not block at all since there might be other events waiting. + +2. The CPU thread (we don't really care about this one as it does not interact with channels or spans). + +3. The signaling thread. + There is one thread of this per span. This thread takes care of reading signaling specific messages from the network (ISDN network, etc) and + changing the channel call state accordingly and processing state changes caused by user API calls (like ftdm_channel_call_hangup for example). + +4. The user thread. + This is a thread in which the user decides to execute FreeTDM APIs, in some cases it might even be the same than the signaling thread (because + most SIGEVENT notifications are delivered by the signaling thread, however we are advicing users to not use FreeTDM unsafe APIs from the + thread where they receive SIGEVENT notifications as some APIs may block for a few milliseconds, effectively blocking the whole signaling thread + that is servicing a span. + +== Application Locking == + +Users of the FreeTDM API will typically have locking of their own for their own application-specific data structures (in the case of FreeSWITCH, the +session lock for example). Other application-specific locks may be involved. + +== DeadLocks == + +As soon as we think of application locks, and we mix them with the FreeTDM internal locks, the possibility of deadlocks arise. + +A typical deadlock scenario when 2 locks are involved is: + +- User Thread - - Signaling Thread - +1. Application locks applock. 1. A network message is received for a channel. + +2. Aplication invokes a FreeTDM call API (ie: ftdm_channel_call_hangup()). 2. The involved channel is locked. + +3. The FreeTDM API attempts to acquire the channel lock and stalls because 3. The message processing results in a notification + the signaling thread just acquired it. to be delivered to the user via the callback function + provided for that purpose. The callback is then called. + +4. The thread is now deadlocked because the signaling thread will never 4. The application callback attempts to acquire its application + release the channel lock. lock but deadlocks because the user thread already has it. + +To avoid this signaling modules should not deliver signals to the user while holding the channel lock. An easy way to avoid this is +to not deliver signals while processing a state change, but rather defer them until the channel lock is released. Most new signaling modules +accomplish this by setting the span flag FTDM_SPAN_USE_SIGNALS_QUEUE, this flag tells the core to enqueue signals (ie FTDM_SIGEVENT_START) +when ftdm_span_send_signal() is called and not deliver them until ftdm_span_trigger_signals() is called, which is done by the signaling module +in its signaling thread when no channel lock is being held. + +== State changes while locking == + +Only 2 types of threads should be performing state changes. + +User threads. +The user thread is a random thread that was crated by the API user. We do not know what threading model users of FreeTDM will follow +and therefore cannot make assumptions about it. The user should be free to call FreeTDM APIs from any thread, except threads that +are under our control, like the signaling threads. Although it may work in most situations, is discouraged for users to try +to use FreeTDM APIs from the signaling thread, that is, the thread where the signaling callback provided during configuration +is called (the callback where FTDM_SIGEVENT_XXX signals are delivered). + +A user thread may request state changes implicitly through calls to FreeTDM API's. The idea of state changes is internal to freetdm +and should not be exposed to users of the API (except for debugging purposes, like the ftdm_channel_get_state, ftdm_channel_get_state_str etc) + +This is an example of the API's that implicitly request a state change. + +ftdm_channel_call_answer() + +Signaling modules should guarantee that upon releasing a lock on a channel, any state changes will be already processed and +not deferred to other threads, otherwise that leads to a situation where a state change requested by the signaling module is pending +to be serviced by another signaling module thread but a user thread wins the channel lock and attempts to perform a state change which will +fail because another state change is pending (and user threads are not meant to process signaling states). + +ONLY one signaling thread per channel should try to perform state changes and processing of the states, +otherwise complexity arises and is not worth it! + +At some point before we stablished this policies we could have 3 different threads doing state changes. + +1. A user random thread could implcitly try to change the state in response to a call API. +2. The ftmod signaling thread could try to change the state in response to other state changes. +3. The lower level signaling stack threads could try to change the state in response to stack events. + +As a result, lower level signaling stack thread could set a state and then let the signaling thread to +process it, but when unlocking the channel, the user thread may win the lock over the signaling thread and +may try to set a state change of its own and fail (due to the unprocessed state change)! + +The rule is, the signaling module should never unlock a channel with states pending to process this way the user, +when acquiring a channel lock (inside ftdm_channel_call_answer for example) it will always find a consistent state +for the channel and not in the middle of state processing. + + diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.2010.vcxproj b/libs/freetdm/mod_freetdm/mod_freetdm.2010.vcxproj index 9f01a3b1a1..ec69333410 100644 --- a/libs/freetdm/mod_freetdm/mod_freetdm.2010.vcxproj +++ b/libs/freetdm/mod_freetdm/mod_freetdm.2010.vcxproj @@ -103,7 +103,7 @@ ProgramDatabase - FreeSwitch.lib;%(AdditionalDependencies) + FreeSwitchCore.lib;%(AdditionalDependencies) ../../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) true $(OutDir)$(TargetName).pdb @@ -127,7 +127,7 @@ ProgramDatabase - FreeSwitch.lib;%(AdditionalDependencies) + FreeSwitchCore.lib;%(AdditionalDependencies) ../../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) true $(OutDir)$(TargetName).pdb diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index ef3989c19c..7bbdef6dae 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -421,16 +421,18 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) private_t *tech_pvt = NULL; channel = switch_core_session_get_channel(session); - assert(channel != NULL); + switch_assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); + switch_assert(tech_pvt != NULL); - assert(tech_pvt->ftdmchan != NULL); + switch_assert(tech_pvt->ftdmchan != NULL); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel)); - ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_PROCEED); + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { + ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_PROCEED); + } return SWITCH_STATUS_SUCCESS; } @@ -441,10 +443,10 @@ static switch_status_t channel_on_execute(switch_core_session_t *session) private_t *tech_pvt = NULL; channel = switch_core_session_get_channel(session); - assert(channel != NULL); + switch_assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); + switch_assert(tech_pvt != NULL); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel)); @@ -802,7 +804,7 @@ static switch_status_t channel_receive_message_cas(switch_core_session_t *sessio phy_id = ftdm_channel_get_ph_id(tech_pvt->ftdmchan); ftdm_log(FTDM_LOG_DEBUG, "Got Freeswitch message in R2 channel %d [%d]\n", phy_id, msg->message_id); - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_SUCCESS; } @@ -849,7 +851,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session, return SWITCH_STATUS_SUCCESS; } - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_SUCCESS; } @@ -892,7 +894,7 @@ static switch_status_t channel_receive_message_fxo(switch_core_session_t *sessio return SWITCH_STATUS_FALSE; } - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_SUCCESS; } @@ -924,7 +926,7 @@ static switch_status_t channel_receive_message_fxs(switch_core_session_t *sessio return SWITCH_STATUS_FALSE; } - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_SUCCESS; } @@ -981,7 +983,7 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_PROGRESS: case SWITCH_MESSAGE_INDICATE_ANSWER: - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { if ((var = switch_channel_get_variable(channel, "freetdm_pre_buffer_size"))) { int tmp = atoi(var); if (tmp > -1) { @@ -1136,6 +1138,10 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi direction = FTDM_BOTTOM_UP; } else if (*argv[1] == 'a') { direction = FTDM_TOP_DOWN; + } else if (*argv[1] == 'r') { + direction = FTDM_RR_DOWN; + } else if (*argv[1] == 'R') { + direction = FTDM_RR_UP; } else { chan_id = atoi(argv[1]); } @@ -1278,6 +1284,10 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi caller_data.dnis.type = outbound_profile->destination_number_ton; } + if ((var = channel_get_variable(session, var_event, "freetdm_calling_party_category"))) { + ftdm_set_calling_party_category(var, (uint8_t *)&caller_data.cpc); + } + if ((var = channel_get_variable(session, var_event, "freetdm_custom_call_data"))) { ftdm_set_string(caller_data.raw_data, var); caller_data.raw_data_len = (uint32_t)strlen(var); @@ -1363,7 +1373,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi tech_pvt->caller_profile = caller_profile; - switch_channel_set_flag(channel, CF_OUTBOUND); switch_channel_set_state(channel, CS_INIT); if (ftdm_channel_add_token(ftdmchan, switch_core_session_get_uuid(*new_session), ftdm_channel_get_token_count(ftdmchan)) != FTDM_SUCCESS) { switch_core_session_destroy(new_session); @@ -1633,6 +1642,14 @@ static FIO_SIGNAL_CB_FUNCTION(on_common_signal) } return FTDM_SUCCESS; } + + case FTDM_SIGEVENT_RELEASED: + case FTDM_SIGEVENT_INDICATION_COMPLETED: + { + /* Swallow these events */ + return FTDM_BREAK; + } + break; default: return FTDM_SUCCESS; break; @@ -1723,7 +1740,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal) } } break; - case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break; + case FTDM_SIGEVENT_SIGSTATUS_CHANGED: { /* twiddle */ } break; default: { @@ -1778,7 +1795,6 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal) } } break; - case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break; case FTDM_SIGEVENT_STOP: { @@ -1811,7 +1827,9 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal) switch_clear_flag_locked(tech_pvt, TFLAG_HOLD); } - if (channel_a && channel_b && !switch_channel_test_flag(channel_a, CF_OUTBOUND) && !switch_channel_test_flag(channel_b, CF_OUTBOUND)) { + if (channel_a && channel_b && switch_channel_direction(channel_a) == SWITCH_CALL_DIRECTION_INBOUND && + switch_channel_direction(channel_b) == SWITCH_CALL_DIRECTION_INBOUND) { + cause = SWITCH_CAUSE_ATTENDED_TRANSFER; if (br_a_uuid && br_b_uuid) { switch_ivr_uuid_bridge(br_a_uuid, br_b_uuid); @@ -1911,7 +1929,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal) case FTDM_SIGEVENT_COLLECTED_DIGIT: { int span_id = ftdm_channel_get_span_id(sigmsg->channel); - char *dtmf = sigmsg->raw_data; + char *dtmf = sigmsg->ev_data.collected.digits; char *regex = SPAN_CONFIG[span_id].dial_regex; char *fail_regex = SPAN_CONFIG[span_id].fail_dial_regex; ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(sigmsg->channel); @@ -2003,8 +2021,6 @@ static FIO_SIGNAL_CB_FUNCTION(on_r2_signal) } break; - case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break; - /* on DNIS received from the R2 forward side, return status == FTDM_BREAK to stop requesting DNIS */ case FTDM_SIGEVENT_COLLECTED_DIGIT: { @@ -2077,13 +2093,14 @@ static FIO_SIGNAL_CB_FUNCTION(on_r2_signal) case FTDM_SIGEVENT_SIGSTATUS_CHANGED: { - ftdm_signaling_status_t sigstatus = sigmsg->raw_data ? *((ftdm_signaling_status_t*)(sigmsg->raw_data)) : sigmsg->ev_data.sigstatus.status; + ftdm_signaling_status_t sigstatus = sigmsg->ev_data.sigstatus.status; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%d:%d signalling changed to: %s\n", spanid, chanid, ftdm_signaling_status2str(sigstatus)); } break; case FTDM_SIGEVENT_PROCEED:{} break; + case FTDM_SIGEVENT_INDICATION_COMPLETED:{} break; default: { @@ -2122,8 +2139,6 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal) } break; - case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break; - case FTDM_SIGEVENT_STOP: case FTDM_SIGEVENT_RESTART: { @@ -2183,7 +2198,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal) break; case FTDM_SIGEVENT_SIGSTATUS_CHANGED: { - ftdm_signaling_status_t sigstatus = sigmsg->raw_data ? *((ftdm_signaling_status_t*)(sigmsg->raw_data)) : sigmsg->ev_data.sigstatus.status; + ftdm_signaling_status_t sigstatus = sigmsg->ev_data.sigstatus.status; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%d:%d signalling changed to :%s\n", spanid, chanid, ftdm_signaling_status2str(sigstatus)); } @@ -2707,6 +2722,9 @@ static switch_status_t load_config(void) char *hold_music = NULL; char *fail_dial_regex = NULL; const char *enable_callerid = "true"; + const char *answer_polarity = "false"; + const char *hangup_polarity = "false"; + int polarity_delay = 600; int callwaiting = 1; uint32_t span_id = 0, to = 0, max = 0; @@ -2778,6 +2796,12 @@ static switch_status_t load_config(void) dial_regex = val; } else if (!strcasecmp(var, "enable-callerid")) { enable_callerid = val; + } else if (!strcasecmp(var, "answer-polarity-reverse")) { + answer_polarity = val; + } else if (!strcasecmp(var, "hangup-polarity-reverse")) { + hangup_polarity = val; + } else if (!strcasecmp(var, "polarity-delay")) { + polarity_delay = atoi(val); } else if (!strcasecmp(var, "fail-dial-regex")) { fail_dial_regex = val; } else if (!strcasecmp(var, "hold-music")) { @@ -2838,6 +2862,9 @@ static switch_status_t load_config(void) "max_dialstr", &max, "hotline", hotline ? hotline : "", "enable_callerid", enable_callerid, + "answer_polarity_reverse", answer_polarity, + "hangup_polarity_reverse", hangup_polarity, + "polarity_delay", &polarity_delay, "callwaiting", &callwaiting, FTDM_TAG_END) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM analog span %s\n", ftdm_span_get_name(span)); @@ -3526,7 +3553,19 @@ void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t * switch_channel_cause2str(caller_data->hangup_cause)); } -#define FT_SYNTAX "list || dump [] || q931_pcap on|off [pcapfilename without suffix] || gains [] || dtmf on|off []" +#define FT_SYNTAX "USAGE:\n" \ +"--------------------------------------------------------------------------------\n" \ +"ftdm list\n" \ +"ftdm start|stop \n" \ +"ftdm restart \n" \ +"ftdm dump []\n" \ +"ftdm sigstatus get|set [] [] []\n" \ +"ftdm trace []\n" \ +"ftdm notrace []\n" \ +"ftdm q931_pcap on|off [pcapfilename without suffix]\n" \ +"ftdm gains []\n" \ +"ftdm dtmf on|off []\n" \ +"--------------------------------------------------------------------------------\n" SWITCH_STANDARD_API(ft_function) { char *mycmd = NULL, *argv[10] = { 0 }; diff --git a/libs/freetdm/msvc/freetdm.2008.vcproj b/libs/freetdm/msvc/freetdm.2008.vcproj index c72891e525..0539ff3f42 100644 --- a/libs/freetdm/msvc/freetdm.2008.vcproj +++ b/libs/freetdm/msvc/freetdm.2008.vcproj @@ -94,78 +94,6 @@ Name="VCPostBuildEventTool" /> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -452,6 +456,10 @@ RelativePath="..\src\ftdm_sched.c" > + + diff --git a/libs/freetdm/src/ftdm_call_utils.c b/libs/freetdm/src/ftdm_call_utils.c index 69f2fb4fff..2b72f05b77 100644 --- a/libs/freetdm/src/ftdm_call_utils.c +++ b/libs/freetdm/src/ftdm_call_utils.c @@ -30,6 +30,12 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributors: + * + * Moises Silva + * Ricardo Barroetaveña + * */ #include "private/ftdm_core.h" @@ -144,3 +150,20 @@ FT_DECLARE(ftdm_status_t) ftdm_is_number(const char *number) return FTDM_SUCCESS; } + +FT_DECLARE(ftdm_status_t) ftdm_set_calling_party_category(const char *string, uint8_t *target) +{ + uint8_t val; + ftdm_status_t status = FTDM_SUCCESS; + + val = ftdm_str2ftdm_calling_party_category(string); + if (val == FTDM_CPC_INVALID) { + ftdm_log(FTDM_LOG_WARNING, "Invalid category string (%s)\n", string); + val = FTDM_CPC_ORDINARY; + status = FTDM_FAIL; + } + + *target = val; + return status; +} + diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 1fdb867138..076e8ba9f3 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -63,7 +63,7 @@ ftdm_time_t time_last_throttle_log = 0; ftdm_time_t time_current_throttle_log = 0; static ftdm_iterator_t *get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter); -static ftdm_status_t ftdm_call_set_call_id(ftdm_caller_data_t *caller_data); +static ftdm_status_t ftdm_call_set_call_id(ftdm_channel_t *fchan, ftdm_caller_data_t *caller_data); static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data); static ftdm_status_t ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan); static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan); @@ -268,9 +268,6 @@ FTDM_STR2ENUM(ftdm_str2ftdm_analog_start_type, ftdm_analog_start_type2str, ftdm_ FTDM_ENUM_NAMES(SIGNAL_NAMES, SIGNAL_STRINGS) FTDM_STR2ENUM(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t, SIGNAL_NAMES, FTDM_SIGEVENT_INVALID) -FTDM_ENUM_NAMES(CHANNEL_STATE_NAMES, CHANNEL_STATE_STRINGS) -FTDM_STR2ENUM(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t, CHANNEL_STATE_NAMES, FTDM_CHANNEL_STATE_INVALID) - FTDM_ENUM_NAMES(MDMF_TYPE_NAMES, MDMF_STRINGS) FTDM_STR2ENUM(ftdm_str2ftdm_mdmf_type, ftdm_mdmf_type2str, ftdm_mdmf_type_t, MDMF_TYPE_NAMES, MDMF_INVALID) @@ -304,6 +301,12 @@ FTDM_STR2ENUM(ftdm_str2ftdm_bearer_cap, ftdm_bearer_cap2str, ftdm_bearer_cap_t, FTDM_ENUM_NAMES(USER_LAYER1_PROT_NAMES, USER_LAYER1_PROT_STRINGS) FTDM_STR2ENUM(ftdm_str2ftdm_usr_layer1_prot, ftdm_user_layer1_prot2str, ftdm_user_layer1_prot_t, USER_LAYER1_PROT_NAMES, FTDM_USER_LAYER1_PROT_INVALID) +FTDM_ENUM_NAMES(CALLING_PARTY_CATEGORY_NAMES, CALLING_PARTY_CATEGORY_STRINGS) +FTDM_STR2ENUM(ftdm_str2ftdm_calling_party_category, ftdm_calling_party_category2str, ftdm_calling_party_category_t, CALLING_PARTY_CATEGORY_NAMES, FTDM_CPC_INVALID) + +FTDM_ENUM_NAMES(INDICATION_NAMES, INDICATION_STRINGS) +FTDM_STR2ENUM(ftdm_str2channel_indication, ftdm_channel_indication2str, ftdm_channel_indication_t, INDICATION_NAMES, FTDM_CHANNEL_INDICATE_INVALID) + static ftdm_status_t ftdm_group_add_channels(ftdm_span_t* span, int currindex, const char* name); static const char *cut_path(const char *in) @@ -615,6 +618,9 @@ static ftdm_status_t ftdm_channel_destroy(ftdm_channel_t *ftdmchan) ftdm_mutex_destroy(&ftdmchan->mutex); ftdm_mutex_destroy(&ftdmchan->pre_buffer_mutex); + if (ftdmchan->state_completed_interrupt) { + ftdm_interrupt_destroy(&ftdmchan->state_completed_interrupt); + } } return FTDM_SUCCESS; @@ -730,11 +736,28 @@ static void ftdm_span_add(ftdm_span_t *span) FT_DECLARE(ftdm_status_t) ftdm_span_stop(ftdm_span_t *span) { - ftdm_status_t status = FTDM_FAIL; - if (span->stop) { - status = span->stop(span); - span->stop = NULL; + ftdm_status_t status = FTDM_SUCCESS; + + ftdm_mutex_lock(span->mutex); + + if (!ftdm_test_flag(span, FTDM_SPAN_STARTED)) { + status = FTDM_EINVAL; + goto done; } + + if (!span->stop) { + status = FTDM_ENOSYS; + goto done; + } + + status = span->stop(span); + if (FTDM_SUCCESS == status) { + ftdm_clear_flag(span, FTDM_SPAN_STARTED); + } + +done: + ftdm_mutex_unlock(span->mutex); + return status; } @@ -1022,6 +1045,8 @@ FT_DECLARE(ftdm_status_t) ftdm_span_add_channel(ftdm_span_t *span, ftdm_socket_t } ftdm_set_flag(new_chan, FTDM_CHANNEL_CONFIGURED | FTDM_CHANNEL_READY); + new_chan->state = FTDM_CHANNEL_STATE_DOWN; + new_chan->state_status = FTDM_STATE_STATUS_COMPLETED; *chan = new_chan; return FTDM_SUCCESS; } @@ -1091,10 +1116,43 @@ FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms, s return FTDM_NOTIMPL; } +/* handle oob events and send the proper SIGEVENT signal to user, when applicable */ +static __inline__ ftdm_status_t ftdm_event_handle_oob(ftdm_event_t *event) +{ + ftdm_sigmsg_t sigmsg; + ftdm_status_t status = FTDM_SUCCESS; + ftdm_channel_t *fchan = event->channel; + ftdm_span_t *span = fchan->span; + + memset(&sigmsg, 0, sizeof(sigmsg)); + sigmsg.span_id = span->span_id; + sigmsg.chan_id = fchan->chan_id; + sigmsg.channel = fchan; + switch (event->enum_id) { + case FTDM_OOB_ALARM_CLEAR: + { + sigmsg.event_id = FTDM_SIGEVENT_ALARM_CLEAR; + ftdm_clear_flag_locked(fchan, FTDM_CHANNEL_IN_ALARM); + status = ftdm_span_send_signal(span, &sigmsg); + } + break; + case FTDM_OOB_ALARM_TRAP: + { + sigmsg.event_id = FTDM_SIGEVENT_ALARM_TRAP; + ftdm_set_flag_locked(fchan, FTDM_CHANNEL_IN_ALARM); + status = ftdm_span_send_signal(span, &sigmsg); + } + break; + default: + /* NOOP */ + break; + } + return status; +} + FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t **event) { ftdm_status_t status = FTDM_FAIL; - ftdm_sigmsg_t sigmsg; ftdm_assert_return(span->fio != NULL, FTDM_FAIL, "No I/O module attached to this span!\n"); if (!span->fio->next_event) { @@ -1107,76 +1165,39 @@ FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t * return status; } - /* before returning the event to the user we do some core operations with certain OOB events */ - memset(&sigmsg, 0, sizeof(sigmsg)); - sigmsg.span_id = span->span_id; - sigmsg.chan_id = (*event)->channel->chan_id; - sigmsg.channel = (*event)->channel; - switch ((*event)->enum_id) { - case FTDM_OOB_ALARM_CLEAR: - { - sigmsg.event_id = FTDM_SIGEVENT_ALARM_CLEAR; - ftdm_clear_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM); - ftdm_span_send_signal(span, &sigmsg); - } - break; - case FTDM_OOB_ALARM_TRAP: - { - sigmsg.event_id = FTDM_SIGEVENT_ALARM_TRAP; - ftdm_set_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM); - ftdm_span_send_signal(span, &sigmsg); - } - break; - default: - /* NOOP */ - break; + status = ftdm_event_handle_oob(*event); + if (status != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "failed to handle event %d\n", **event); } - return status; } FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm_event_t **event) { ftdm_status_t status = FTDM_FAIL; - ftdm_sigmsg_t sigmsg; ftdm_span_t *span = ftdmchan->span; ftdm_assert_return(span->fio != NULL, FTDM_FAIL, "No I/O module attached to this span!\n"); + ftdm_channel_lock(ftdmchan); + if (!span->fio->channel_next_event) { ftdm_log(FTDM_LOG_ERROR, "channel_next_event method not implemented in module %s!", span->fio->name); - return FTDM_NOTIMPL; + status = FTDM_NOTIMPL; + goto done; } status = span->fio->channel_next_event(ftdmchan, event); if (status != FTDM_SUCCESS) { - return status; + goto done; } - /* before returning the event to the user we do some core operations with certain OOB events */ - memset(&sigmsg, 0, sizeof(sigmsg)); - sigmsg.span_id = span->span_id; - sigmsg.chan_id = (*event)->channel->chan_id; - sigmsg.channel = (*event)->channel; - switch ((*event)->enum_id) { - case FTDM_OOB_ALARM_CLEAR: - { - sigmsg.event_id = FTDM_SIGEVENT_ALARM_CLEAR; - ftdm_clear_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM); - ftdm_span_send_signal(span, &sigmsg); - } - break; - case FTDM_OOB_ALARM_TRAP: - { - sigmsg.event_id = FTDM_SIGEVENT_ALARM_TRAP; - ftdm_set_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM); - ftdm_span_send_signal(span, &sigmsg); - } - break; - default: - /* NOOP */ - break; + status = ftdm_event_handle_oob(*event); + if (status != FTDM_SUCCESS) { + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "failed to handle event %d\n", **event); } +done: + ftdm_channel_unlock(ftdmchan); return status; } @@ -1344,236 +1365,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_add_token(ftdm_channel_t *ftdmchan, char } -FT_DECLARE(ftdm_status_t) ftdm_channel_complete_state(ftdm_channel_t *ftdmchan) -{ - ftdm_channel_state_t state = ftdmchan->state; - - if (state == FTDM_CHANNEL_STATE_PROGRESS) { - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS); - } else if (state == FTDM_CHANNEL_STATE_UP) { - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS); - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA); - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_ANSWERED); - } else if (state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) { - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS); - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA); - } - - return FTDM_SUCCESS; -} - -static int ftdm_parse_state_map(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, ftdm_state_map_t *state_map) -{ - int x = 0, ok = 0; - ftdm_state_direction_t direction = ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? ZSD_OUTBOUND : ZSD_INBOUND; - - for(x = 0; x < FTDM_MAP_NODE_SIZE; x++) { - int i = 0, proceed = 0; - if (!state_map->nodes[x].type) { - break; - } - - if (state_map->nodes[x].direction != direction) { - continue; - } - - if (state_map->nodes[x].check_states[0] == FTDM_ANY_STATE) { - proceed = 1; - } else { - for(i = 0; i < FTDM_MAP_MAX; i++) { - if (state_map->nodes[x].check_states[i] == ftdmchan->state) { - proceed = 1; - break; - } - } - } - - if (!proceed) { - continue; - } - - for(i = 0; i < FTDM_MAP_MAX; i++) { - ok = (state_map->nodes[x].type == ZSM_ACCEPTABLE); - if (state_map->nodes[x].states[i] == FTDM_END) { - break; - } - if (state_map->nodes[x].states[i] == state) { - ok = !ok; - goto end; - } - } - } - end: - - return ok; -} - -/* this function MUST be called with the channel lock held. If waitrq == 1, the channel will be unlocked/locked (never call it with waitrq == 1 with an lock recursivity > 1) */ -#define DEFAULT_WAIT_TIME 1000 -FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int waitrq) -{ - int ok = 1; - int waitms = DEFAULT_WAIT_TIME; - - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) { - ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR, "Ignored state change request from %s to %s, the channel is not ready\n", - ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); - return FTDM_FAIL; - } - - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { - ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR, "Ignored state change request from %s to %s, the previous state change has not been processed yet\n", - ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); - return FTDM_FAIL; - } - - if (ftdmchan->state == state) { - ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "Why bother changing state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); - return FTDM_FAIL; - } - - if (ftdmchan->span->state_map) { - ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map); - goto end; - } - - /* basic core state validation (by-passed if the signaling module provides a state_map) */ - switch(ftdmchan->state) { - case FTDM_CHANNEL_STATE_HANGUP: - case FTDM_CHANNEL_STATE_TERMINATING: - { - ok = 0; - switch(state) { - case FTDM_CHANNEL_STATE_DOWN: - case FTDM_CHANNEL_STATE_BUSY: - case FTDM_CHANNEL_STATE_RESTART: - ok = 1; - break; - default: - break; - } - } - break; - case FTDM_CHANNEL_STATE_UP: - { - ok = 1; - switch(state) { - case FTDM_CHANNEL_STATE_PROGRESS: - case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: - case FTDM_CHANNEL_STATE_RING: - ok = 0; - break; - default: - break; - } - } - break; - case FTDM_CHANNEL_STATE_DOWN: - { - ok = 0; - - switch(state) { - case FTDM_CHANNEL_STATE_DIALTONE: - case FTDM_CHANNEL_STATE_COLLECT: - case FTDM_CHANNEL_STATE_DIALING: - case FTDM_CHANNEL_STATE_RING: - case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: - case FTDM_CHANNEL_STATE_PROGRESS: - case FTDM_CHANNEL_STATE_IDLE: - case FTDM_CHANNEL_STATE_GET_CALLERID: - case FTDM_CHANNEL_STATE_GENRING: - ok = 1; - break; - default: - break; - } - } - break; - case FTDM_CHANNEL_STATE_BUSY: - { - switch(state) { - case FTDM_CHANNEL_STATE_UP: - ok = 0; - break; - default: - break; - } - } - break; - case FTDM_CHANNEL_STATE_RING: - { - switch(state) { - case FTDM_CHANNEL_STATE_UP: - ok = 1; - break; - default: - break; - } - } - break; - default: - break; - } - -end: - - if (ok) { - ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Changed state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); - ftdmchan->last_state = ftdmchan->state; - ftdmchan->state = state; - ftdmchan->history[ftdmchan->hindex].file = file; - ftdmchan->history[ftdmchan->hindex].func = func; - ftdmchan->history[ftdmchan->hindex].line = line; - ftdmchan->history[ftdmchan->hindex].state = ftdmchan->state; - ftdmchan->history[ftdmchan->hindex].last_state = ftdmchan->last_state; - ftdmchan->history[ftdmchan->hindex].time = ftdm_current_time_in_ms(); - ftdmchan->hindex++; - if (ftdmchan->hindex == ftdm_array_len(ftdmchan->history)) { - ftdmchan->hindex = 0; - } - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); - - ftdm_mutex_lock(ftdmchan->span->mutex); - ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE); - if (ftdmchan->span->pendingchans) { - ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan); - } - ftdm_mutex_unlock(ftdmchan->span->mutex); - } else { - ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "VETO state change from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); - } - - /* there is an inherent race here between set and check of the change flag but we do not care because - * the flag should never last raised for more than a few ms for any state change */ - while (waitrq && waitms > 0) { - /* give a chance to the signaling stack to process it */ - ftdm_mutex_unlock(ftdmchan->mutex); - - ftdm_sleep(10); - waitms -= 10; - - ftdm_mutex_lock(ftdmchan->mutex); - - /* if the flag is no longer set, the state change was processed (or is being processed) */ - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { - break; - } - - /* if the state is no longer what we set, the state change was - * obviously processed (and the current state change flag is for other state change) */ - if (ftdmchan->state != state) { - break; - } - } - - if (waitms <= 0) { - ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "state change from %s to %s was most likely not processed after aprox %dms\n", - ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(state), DEFAULT_WAIT_TIME); - } - - return ok ? FTDM_SUCCESS : FTDM_FAIL; -} - FT_DECLARE(uint32_t) ftdm_group_get_id(const ftdm_group_t *group) { return group->group_id; @@ -1706,6 +1497,21 @@ static ftdm_status_t __inline__ get_best_rated(ftdm_channel_t **fchan, ftdm_chan return FTDM_SUCCESS; } +static uint32_t __inline__ rr_next(uint32_t last, uint32_t min, uint32_t max, ftdm_direction_t direction) +{ + uint32_t next = min; + + ftdm_log(FTDM_LOG_DEBUG, "last = %d, min = %d, max = %d\n", last, min, max); + + if (direction == FTDM_RR_DOWN) { + next = (last >= max) ? min : ++last; + } else { + next = (last <= min) ? max : --last; + } + return next; +} + + FT_DECLARE(int) ftdm_channel_get_availability(ftdm_channel_t *ftdmchan) { int availability = -1; @@ -1748,6 +1554,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_dir if (direction == FTDM_TOP_DOWN) { i = 0; + } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) { + i = rr_next(group->last_used_index, 0, group->chan_count - 1, direction); } else { i = group->chan_count-1; } @@ -1762,16 +1570,24 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_dir if (request_voice_channel(check, ftdmchan, caller_data, direction)) { status = FTDM_SUCCESS; + if (direction == FTDM_RR_UP || direction == FTDM_RR_DOWN) { + group->last_used_index = i; + } break; } calculate_best_rate(check, &best_rated, &best_rate); if (direction == FTDM_TOP_DOWN) { - if (i >= group->chan_count) { + if (i >= (group->chan_count - 1)) { break; } i++; + } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) { + if (check == best_rated) { + group->last_used_index = i; + } + i = rr_next(i, 0, group->chan_count - 1, direction); } else { if (i == 0) { break; @@ -1850,6 +1666,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc if (direction == FTDM_TOP_DOWN) { i = 1; + } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) { + i = rr_next(span->last_used_index, 1, span->chan_count, direction); } else { i = span->chan_count; } @@ -1860,6 +1678,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc if (i > span->chan_count) { break; } + } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) { + if (i == span->last_used_index) { + break; + } } else { if (i == 0) { break; @@ -1873,6 +1695,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc if (request_voice_channel(check, ftdmchan, caller_data, direction)) { status = FTDM_SUCCESS; + if (direction == FTDM_RR_UP || direction == FTDM_RR_DOWN) { + span->last_used_index = i; + } break; } @@ -1880,6 +1705,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc if (direction == FTDM_TOP_DOWN) { i++; + } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) { + if (check == best_rated) { + span->last_used_index = i; + } + i = rr_next(i, 1, span->chan_count, direction); } else { i--; } @@ -1894,17 +1724,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc return status; } - -FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan) -{ - if (ftdmchan->init_state != FTDM_CHANNEL_STATE_DOWN) { - ftdm_set_state(ftdmchan, ftdmchan->init_state); - ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN; - } - - return FTDM_SUCCESS; -} - FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan) { ftdm_status_t status = FTDM_FAIL; @@ -2079,6 +1898,28 @@ FT_DECLARE(void) ftdm_span_set_trunk_type(ftdm_span_t *span, ftdm_trunk_type_t t span->trunk_type = type; } +FT_DECLARE(ftdm_status_t) ftdm_span_set_blocking_mode(const ftdm_span_t *span, ftdm_bool_t enabled) +{ + ftdm_channel_t *fchan = NULL; + ftdm_iterator_t *citer = NULL; + ftdm_iterator_t *curr = NULL; + + citer = ftdm_span_get_chan_iterator(span, NULL); + if (!citer) { + return FTDM_ENOMEM; + } + for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) { + fchan = ftdm_iterator_current(curr); + if (enabled) { + ftdm_clear_flag_locked(fchan, FTDM_CHANNEL_NONBLOCK); + } else { + ftdm_set_flag_locked(fchan, FTDM_CHANNEL_NONBLOCK); + } + } + ftdm_iterator_free(citer); + return FTDM_SUCCESS; +} + FT_DECLARE(ftdm_trunk_type_t) ftdm_span_get_trunk_type(const ftdm_span_t *span) { return span->trunk_type; @@ -2165,19 +2006,107 @@ FT_DECLARE(ftdm_bool_t) ftdm_channel_call_check_done(const ftdm_channel_t *ftdmc FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hold(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan) { + ftdm_status_t status; ftdm_channel_lock(ftdmchan); + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_HOLD); - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_DIALTONE, 0); + status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_DIALTONE, 0); ftdm_channel_unlock(ftdmchan); - return FTDM_SUCCESS; + + return status; } FT_DECLARE(ftdm_status_t) _ftdm_channel_call_unhold(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan) { + ftdm_status_t status; + ftdm_channel_lock(ftdmchan); - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 0); + + status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 0); + ftdm_channel_unlock(ftdmchan); - return FTDM_SUCCESS; + + return status; +} + +FT_DECLARE(void) ftdm_ack_indication(ftdm_channel_t *fchan, ftdm_channel_indication_t indication, ftdm_status_t status) +{ + ftdm_sigmsg_t msg; + ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Acknowledging indication %s in state %s (rc = %d)\n", + ftdm_channel_indication2str(indication), ftdm_channel_state2str(fchan->state), status); + ftdm_clear_flag(fchan, FTDM_CHANNEL_IND_ACK_PENDING); + memset(&msg, 0, sizeof(msg)); + msg.channel = fchan; + msg.event_id = FTDM_SIGEVENT_INDICATION_COMPLETED; + msg.ev_data.indication_completed.indication = indication; + msg.ev_data.indication_completed.status = status; + ftdm_span_send_signal(fchan->span, &msg); +} + +/*! \brief Answer call without locking the channel. The caller must have locked first + * \note This function was added because ftdm_channel_call_indicate needs to answer the call + * when its already locking the channel, ftdm_channel_set_state cannot be called with the same + * lock locked once or more (recursive lock) and wait for the result */ +static ftdm_status_t _ftdm_channel_call_answer_nl(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan) +{ + ftdm_status_t status = FTDM_SUCCESS; + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + status = FTDM_EINVAL; + goto done; + } + + if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call is already TERMINATING\n"); + status = FTDM_ECANCELED; + goto done; + } + + if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) { + /* We will fail RFC's if we not skip states, but some modules apart from ftmod_sangoma_isdn + * expect the call to always to go PROGRESS and PROGRESS MEDIA state before going to UP, so + * use FTDM_SPAN_USE_SKIP_STATES for now while we update the sig modules */ + + if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) { + status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1); + if (status != FTDM_SUCCESS) { + status = FTDM_ECANCELED; + goto done; + } + } + + /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */ + if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n"); + status = FTDM_ECANCELED; + goto done; + } + + if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) { + status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1); + if (status != FTDM_SUCCESS) { + status = FTDM_ECANCELED; + goto done; + } + } + + /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */ + if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to UP\n"); + status = FTDM_ECANCELED; + goto done; + } + } + + status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1); + if (status != FTDM_SUCCESS) { + status = FTDM_ECANCELED; + goto done; + } + +done: + + return status; } FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan) @@ -2186,55 +2115,17 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char ftdm_channel_lock(ftdmchan); - if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call is already TERMINATING\n"); - goto done; - } - - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_ANSWERED); - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS); - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA); - - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - goto done; - } - - if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) { - /* We will fail RFC's if we not skip states, but some modules apart from ftmod_sangoma_isdn - * expect the call to always to go PROGRESS and PROGRESS MEDIA state before going to UP, so - * use FTDM_SPAN_USE_SKIP_STATESfor now while we update the sig modules */ - - if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) { - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1); - } - - /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */ - if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n"); - goto done; - } - - if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) { - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1); - } - - /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */ - if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to UP\n"); - goto done; - } - } - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1); - -done: + status = _ftdm_channel_call_answer_nl(file, func, line, ftdmchan); ftdm_channel_unlock(ftdmchan); return status; } /* lock must be acquired by the caller! */ -static ftdm_status_t call_hangup(ftdm_channel_t *chan, const char *file, const char *func, int line) +static ftdm_status_t _ftdm_channel_call_hangup_nl(ftdm_channel_t *chan, const char *file, const char *func, int line) { + ftdm_status_t status = FTDM_SUCCESS; + ftdm_set_flag(chan, FTDM_CHANNEL_USER_HANGUP); ftdm_set_echocancel_call_end(chan); @@ -2247,34 +2138,47 @@ static ftdm_status_t call_hangup(ftdm_channel_t *chan, const char *file, const c if (chan->hangup_timer) { ftdm_sched_cancel_timer(globals.timingsched, chan->hangup_timer); } - ftdm_channel_set_state(file, func, line, chan, FTDM_CHANNEL_STATE_HANGUP, 1); + status = ftdm_channel_set_state(file, func, line, chan, FTDM_CHANNEL_STATE_HANGUP, 1); } else { /* the signaling stack did not touch the state, - * core is responsible from clearing flags and stuff */ - ftdm_channel_close(&chan); + * core is responsible from clearing flags and stuff, however, because ftmod_analog + * is a bitch in a serious need of refactoring, we also check whether the channel is open + * to avoid an spurious warning about the channel not being open. This is because ftmod_analog + * does not follow our convention of sending SIGEVENT_STOP and waiting for the user to move + * to HANGUP (implicitly through ftdm_channel_call_hangup(), as soon as ftmod_analog is fixed + * this check can be removed */ + if (ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) { + ftdm_channel_close(&chan); + } } - return FTDM_SUCCESS; + return status; } FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup_with_cause(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_call_cause_t cause) { + ftdm_status_t status = FTDM_SUCCESS; ftdm_channel_lock(ftdmchan); ftdmchan->caller_data.hangup_cause = cause; - call_hangup(ftdmchan, file, func, line); + status = _ftdm_channel_call_hangup_nl(ftdmchan, file, func, line); ftdm_channel_unlock(ftdmchan); - return FTDM_SUCCESS; + return status; } FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan) { + ftdm_status_t status = FTDM_SUCCESS; + ftdm_channel_lock(ftdmchan); + ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING; - call_hangup(ftdmchan, file, func, line); + + status = _ftdm_channel_call_hangup_nl(ftdmchan, file, func, line); + ftdm_channel_unlock(ftdmchan); - return FTDM_SUCCESS; + return status; } FT_DECLARE(const char *) ftdm_channel_get_last_error(const ftdm_channel_t *ftdmchan) @@ -2292,42 +2196,6 @@ FT_DECLARE(ftdm_caller_data_t *) ftdm_channel_get_caller_data(ftdm_channel_t *ft return &ftdmchan->caller_data; } -FT_DECLARE(int) ftdm_channel_get_state(const ftdm_channel_t *ftdmchan) -{ - int state; - ftdm_channel_lock(ftdmchan); - state = ftdmchan->state; - ftdm_channel_unlock(ftdmchan); - return state; -} - -FT_DECLARE(const char *) ftdm_channel_get_state_str(const ftdm_channel_t *ftdmchan) -{ - const char *state; - ftdm_channel_lock(ftdmchan); - state = ftdm_channel_state2str(ftdmchan->state); - ftdm_channel_unlock(ftdmchan); - return state; -} - -FT_DECLARE(int) ftdm_channel_get_last_state(const ftdm_channel_t *ftdmchan) -{ - int last_state; - ftdm_channel_lock(ftdmchan); - last_state = ftdmchan->last_state; - ftdm_channel_unlock(ftdmchan); - return last_state; -} - -FT_DECLARE(const char *) ftdm_channel_get_last_state_str(const ftdm_channel_t *ftdmchan) -{ - const char *state; - ftdm_channel_lock(ftdmchan); - state = ftdm_channel_state2str(ftdmchan->last_state); - ftdm_channel_unlock(ftdmchan); - return state; -} - FT_DECLARE(ftdm_channel_t *) ftdm_span_get_channel(const ftdm_span_t *span, uint32_t chanid) { ftdm_channel_t *chan; @@ -2359,13 +2227,48 @@ FT_DECLARE(uint32_t) ftdm_channel_get_ph_span_id(const ftdm_channel_t *ftdmchan) return id; } +/* + * Every user requested indication *MUST* be acknowledged with the proper status (ftdm_status_t) + * However, if the indication fails before we notify the signaling stack, we don't need to ack + * but if we already notified the signaling stack about the indication, the signaling stack is + * responsible for the acknowledge. Bottom line is, whenever this function returns FTDM_SUCCESS + * someone *MUST* acknowledge the indication, either the signaling stack, this function or the core + * at some later point + * */ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication) { ftdm_status_t status = FTDM_SUCCESS; + + ftdm_assert_return(ftdmchan, FTDM_FAIL, "Null channel\n"); + + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Indicating %s in state %s\n", + ftdm_channel_indication2str(indication), ftdm_channel_state2str(ftdmchan->state)); + ftdm_channel_lock(ftdmchan); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IND_ACK_PENDING)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot indicate %s in channel with indication %s still pending in state %s\n", + ftdm_channel_indication2str(indication), + ftdm_channel_indication2str(ftdmchan->indication), + ftdm_channel_state2str(ftdmchan->state)); + status = FTDM_EBUSY; + goto done; + } + + ftdmchan->indication = indication; + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_IND_ACK_PENDING); + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot indicate %s in outgoing channel in state %s\n", + ftdm_channel_indication2str(indication), ftdm_channel_state2str(ftdmchan->state)); + status = FTDM_EINVAL; + goto done; + } + if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n"); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring indication %s because the call is in %s state\n", + ftdm_channel_indication2str(indication), ftdm_channel_state2str(ftdmchan->state)); + status = FTDM_ECANCELED; goto done; } @@ -2373,55 +2276,52 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch /* FIXME: ring and busy cannot be used with all signaling stacks * (particularly isdn stacks I think, we should emulate or just move to hangup with busy cause) */ case FTDM_CHANNEL_INDICATE_RINGING: - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_RINGING, 1); + status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_RINGING, 1); break; case FTDM_CHANNEL_INDICATE_BUSY: - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_BUSY, 1); + status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_BUSY, 1); break; case FTDM_CHANNEL_INDICATE_PROCEED: - if (ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_PROCEED_STATE)) { - if (ftdmchan->state == FTDM_CHANNEL_STATE_RING) { - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROCEED, 1); - } + if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_PROCEED_STATE)) { + ftdm_ack_indication(ftdmchan, indication, status); + goto done; } + status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROCEED, 1); break; case FTDM_CHANNEL_INDICATE_PROGRESS: - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS); - } else { - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1); - } + status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1); break; case FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA: - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS); - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA); - } else { - if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) { - if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) { - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1); - } - - /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */ - if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n"); + if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) { + if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) { + status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1); + if (status != FTDM_SUCCESS) { goto done; } } - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1); + /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */ + if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring progress media because the call is terminating\n"); + goto done; + } } + status = ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1); + break; + case FTDM_CHANNEL_INDICATE_ANSWER: + /* _ftdm_channel_call_answer takes care of the indication ack */ + status = _ftdm_channel_call_answer_nl(file, func, line, ftdmchan); break; default: ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "Do not know how to indicate %d\n", indication); - status = FTDM_FAIL; + status = FTDM_EINVAL; break; } done: ftdm_channel_unlock(ftdmchan); - return FTDM_SUCCESS; + return status; } FT_DECLARE(ftdm_status_t) _ftdm_channel_call_send_msg(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_sigmsg_t *sigmsg) @@ -2473,14 +2373,19 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char ftdm_log(FTDM_LOG_ERROR, "outgoing_call method not implemented in this span!\n"); } + if (status == FTDM_SUCCESS) { + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED); + ftdm_call_set_call_id(ftdmchan, &ftdmchan->caller_data); + ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100); + } + + ftdm_channel_unlock(ftdmchan); + #ifdef __WINDOWS__ UNREFERENCED_PARAMETER(file); UNREFERENCED_PARAMETER(func); UNREFERENCED_PARAMETER(line); #endif - ftdm_call_set_call_id(&ftdmchan->caller_data); - ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100); - ftdm_channel_unlock(ftdmchan); return status; } @@ -2488,9 +2393,18 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_set_sig_status(ftdm_channel_t *ftdmchan, { ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel\n"); ftdm_assert_return(ftdmchan->span != NULL, FTDM_FAIL, "Null span\n"); - + + if (sigstatus == FTDM_SIG_STATE_DOWN) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "The user is not allowed to set the signaling status to DOWN, valid states are UP or SUSPENDED\n"); + return FTDM_FAIL; + } + if (ftdmchan->span->set_channel_sig_status) { - return ftdmchan->span->set_channel_sig_status(ftdmchan, sigstatus); + ftdm_status_t res; + ftdm_channel_lock(ftdmchan); + res = ftdmchan->span->set_channel_sig_status(ftdmchan, sigstatus); + ftdm_channel_unlock(ftdmchan); + return res; } else { ftdm_log(FTDM_LOG_ERROR, "set_channel_sig_status method not implemented!\n"); return FTDM_FAIL; @@ -2504,7 +2418,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_get_sig_status(ftdm_channel_t *ftdmchan, ftdm_assert_return(sigstatus != NULL, FTDM_FAIL, "Null sig status parameter\n"); if (ftdmchan->span->get_channel_sig_status) { - return ftdmchan->span->get_channel_sig_status(ftdmchan, sigstatus); + ftdm_status_t res; + ftdm_channel_lock(ftdmchan); + res = ftdmchan->span->get_channel_sig_status(ftdmchan, sigstatus); + ftdm_channel_unlock(ftdmchan); + return res; } else { /* don't log error here, it can be called just to test if its supported */ return FTDM_NOTIMPL; @@ -2515,6 +2433,11 @@ FT_DECLARE(ftdm_status_t) ftdm_span_set_sig_status(ftdm_span_t *span, ftdm_signa { ftdm_assert_return(span != NULL, FTDM_FAIL, "Null span\n"); + if (sigstatus == FTDM_SIG_STATE_DOWN) { + ftdm_log(FTDM_LOG_WARNING, "The user is not allowed to set the signaling status to DOWN, valid states are UP or SUSPENDED\n"); + return FTDM_FAIL; + } + if (span->set_span_sig_status) { return span->set_span_sig_status(span, sigstatus); } else { @@ -2535,10 +2458,11 @@ FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signa } } +/* this function must be called with the channel lock */ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan) { ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel can't be done!\n"); - ftdm_mutex_lock(ftdmchan->mutex); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OPEN); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF); @@ -2568,12 +2492,13 @@ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan) ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN; ftdmchan->state = FTDM_CHANNEL_STATE_DOWN; + ftdmchan->state_status = FTDM_STATE_STATUS_COMPLETED; ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_DEBUG_DTMF, NULL); ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_INPUT_DUMP, NULL); ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_OUTPUT_DUMP, NULL); - if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) { + if (FTDM_IS_VOICE_CHANNEL(ftdmchan) && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED)) { ftdm_sigmsg_t sigmsg; memset(&sigmsg, 0, sizeof(sigmsg)); sigmsg.span_id = ftdmchan->span_id; @@ -2582,6 +2507,7 @@ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan) sigmsg.event_id = FTDM_SIGEVENT_RELEASED; ftdm_span_send_signal(ftdmchan->span, &sigmsg); ftdm_call_clear_call_id(&ftdmchan->caller_data); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED); } if (ftdmchan->txdrops || ftdmchan->rxdrops) { @@ -2622,7 +2548,6 @@ static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan) ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE); } ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "channel done\n"); - ftdm_mutex_unlock(ftdmchan->mutex); return FTDM_SUCCESS; } @@ -2649,14 +2574,13 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_close(ftdm_channel_t **ftdmchan) if (ftdm_test_flag(check, FTDM_CHANNEL_CONFIGURED)) { ftdm_mutex_lock(check->mutex); - if (ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) { - status = check->fio->close(check); - if (status == FTDM_SUCCESS) { - ftdm_channel_done(check); - *ftdmchan = NULL; - } - } else { - ftdm_log_chan_msg(check, FTDM_LOG_WARNING, "Called ftdm_channel_close but never ftdm_channel_open??\n"); + if (!ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) { + ftdm_log_chan_msg(check, FTDM_LOG_WARNING, "Channel not opened, proceeding anyway\n"); + } + status = check->fio->close(check); + if (status == FTDM_SUCCESS) { + ftdm_channel_done(check); + *ftdmchan = NULL; } check->ring_count = 0; ftdm_mutex_unlock(check->mutex); @@ -2716,7 +2640,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno)); GOTO_STATUS(done, FTDM_FAIL); } - ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT); + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT); + GOTO_STATUS(done, FTDM_SUCCESS); } } break; @@ -2724,7 +2649,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co { if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CALLERID)) { ftdm_fsk_demod_destroy(&ftdmchan->fsk); - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT); + GOTO_STATUS(done, FTDM_SUCCESS); } } break; @@ -2987,7 +2913,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co case FTDM_COMMAND_DISABLE_PROGRESS_DETECT: { if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_PROGRESS)) { - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT); ftdm_channel_clear_detected_tones(ftdmchan); ftdm_channel_clear_needed_tones(ftdmchan); GOTO_STATUS(done, FTDM_SUCCESS); @@ -2999,8 +2925,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co /* if they don't have thier own, use ours */ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) { teletone_dtmf_detect_init (&ftdmchan->dtmf_detect, ftdmchan->rate); - ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_DTMF_DETECT); - ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF); + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT); + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Enabled software DTMF detector\n"); GOTO_STATUS(done, FTDM_SUCCESS); } @@ -3652,23 +3578,21 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data } status = ftdm_raw_read(ftdmchan, data, datalen); - if (status != FTDM_SUCCESS) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "raw I/O read filed\n"); + goto done; } - if (status == FTDM_SUCCESS) { - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN) - && (ftdmchan->native_codec == FTDM_CODEC_ALAW || ftdmchan->native_codec == FTDM_CODEC_ULAW)) { - unsigned char *rdata = data; - for (i = 0; i < *datalen; i++) { - rdata[i] = ftdmchan->rxgain_table[rdata[i]]; - } + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN) + && (ftdmchan->native_codec == FTDM_CODEC_ALAW || ftdmchan->native_codec == FTDM_CODEC_ULAW)) { + unsigned char *rdata = data; + for (i = 0; i < *datalen; i++) { + rdata[i] = ftdmchan->rxgain_table[rdata[i]]; } - handle_dtmf(ftdmchan, *datalen); } + handle_dtmf(ftdmchan, *datalen); - if (status == FTDM_SUCCESS && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE) && ftdmchan->effective_codec != ftdmchan->native_codec) { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE) && ftdmchan->effective_codec != ftdmchan->native_codec) { if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_SLIN) { codec_func = fio_ulaw2slin; } else if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_ALAW) { @@ -3869,7 +3793,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_write(ftdm_channel_t *ftdmchan, void *dat if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "cannot write in channel not open\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "cannot write in channel not open\n"); snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open"); status = FTDM_FAIL; goto done; @@ -4325,6 +4249,16 @@ static void print_channels_by_state(ftdm_stream_handle_t *stream, ftdm_channel_s ftdm_mutex_unlock(globals.mutex); } +static void print_core_usage(ftdm_stream_handle_t *stream) +{ + stream->write_function(stream, + "--------------------------------------------------------------------------------\n" + "ftdm core state [!] - List all channels in or not in the given state\n" + "ftdm core flag - List all channels with the given flag value set\n" + "ftdm core calls - List all known calls to the FreeTDM core\n" + "--------------------------------------------------------------------------------\n"); +} + static char *handle_core_command(const char *cmd) { char *mycmd = NULL; @@ -4335,22 +4269,31 @@ static char *handle_core_command(const char *cmd) char *state = NULL; char *flag = NULL; uint32_t flagval = 0; + uint32_t current_call_id = 0; + ftdm_caller_data_t *calldata = NULL; + ftdm_channel_t *fchan = NULL; ftdm_channel_state_t i = FTDM_CHANNEL_STATE_INVALID; ftdm_stream_handle_t stream = { 0 }; FTDM_STANDARD_STREAM(stream); - if (cmd) { + if (cmd && strlen(cmd)) { mycmd = ftdm_strdup(cmd); argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); } else { - stream.write_function(&stream, "invalid core command\n"); + print_core_usage(&stream); + goto done; + } + + if (!argc) { + print_core_usage(&stream); goto done; } if (!strcasecmp(argv[0], "state")) { if (argc < 2) { stream.write_function(&stream, "core state command requires an argument\n"); + print_core_usage(&stream); goto done; } state = argv[1]; @@ -4371,7 +4314,8 @@ static char *handle_core_command(const char *cmd) stream.write_function(&stream, "\nTotal channels %s %s: %d\n", not ? "not in state" : "in state", ftdm_channel_state2str(i), count); } else if (!strcasecmp(argv[0], "flag")) { if (argc < 2) { - stream.write_function(&stream, "core state command requires an argument\n"); + stream.write_function(&stream, "core flag command requires an argument\n"); + print_core_usage(&stream); goto done; } flag = argv[1]; @@ -4382,8 +4326,28 @@ static char *handle_core_command(const char *cmd) flagval = atoi(flag); print_channels_by_flag(&stream, flagval, not, &count); stream.write_function(&stream, "\nTotal channels %s %d: %d\n", not ? "without flag" : "with flag", flagval, count); + } else if (!strcasecmp(argv[0], "calls")) { + ftdm_mutex_lock(globals.call_id_mutex); + current_call_id = globals.last_call_id; + for (current_call_id = 0; current_call_id <= MAX_CALLIDS; current_call_id++) { + if (!globals.call_ids[current_call_id]) { + continue; + } + calldata = globals.call_ids[current_call_id]; + fchan = calldata->fchan; + if (fchan) { + stream.write_function(&stream, "Call %d on channel %d:%d\n", current_call_id, + fchan->span_id, fchan->chan_id); + } else { + stream.write_function(&stream, "Call %d without a channel?\n", current_call_id); + } + count++; + } + ftdm_mutex_unlock(globals.call_id_mutex); + stream.write_function(&stream, "\nTotal calls: %d\n", count); } else { stream.write_function(&stream, "invalid core command %s\n", argv[0]); + print_core_usage(&stream); } done: @@ -4403,6 +4367,8 @@ FT_DECLARE(char *) ftdm_api_execute(const char *cmd) if ((p = strchr(dup, ' '))) { *p++ = '\0'; cmd = p; + } else { + cmd = ""; } type = dup; @@ -5086,7 +5052,7 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const ftdm_assert_return(parameters != NULL, FTDM_FAIL, "No parameters"); if (!span->chan_count) { - ftdm_log(FTDM_LOG_WARNING, "Cannot configure signaling on span with no channels\n"); + ftdm_log(FTDM_LOG_WARNING, "Cannot configure signaling on span %s with no channels\n", span->name); return FTDM_FAIL; } @@ -5116,18 +5082,38 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(ftdm_span_t *span, const FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span) { - if (span->start) { - /* check the alarms again before starting the signaling module - this works-around some I/O modules (netborder I/O module) that cannot - check the alarm status before during configuration because the spans are - not really started yet at the I/O level */ - if (ftdm_set_channels_alarms(span, 0) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "%d: Failed to set channel alarms\n", span->span_id); - return FTDM_FAIL; - } - return span->start(span); + ftdm_status_t status = FTDM_FAIL; + + ftdm_mutex_lock(span->mutex); + + if (ftdm_test_flag(span, FTDM_SPAN_STARTED)) { + status = FTDM_EINVAL; + goto done; } - return FTDM_FAIL; + + if (!span->start) { + status = FTDM_ENOSYS; + goto done; + } + + /* check the alarms again before starting the signaling module + this works-around some I/O modules (netborder I/O module) that cannot + check the alarm status before during configuration because the spans are + not really started yet at the I/O level */ + if (ftdm_set_channels_alarms(span, 0) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Failed to set channel alarms in span %s\n", span->name); + status = FTDM_FAIL; + goto done; + } + + status = span->start(span); + if (status == FTDM_SUCCESS) { + ftdm_set_flag_locked(span, FTDM_SPAN_STARTED); + } + +done: + ftdm_mutex_unlock(span->mutex); + return status; } FT_DECLARE(ftdm_status_t) ftdm_channel_add_to_group(const char* name, ftdm_channel_t* ftdmchan) @@ -5280,7 +5266,6 @@ static void ftdm_group_add(ftdm_group_t *group) ftdm_mutex_unlock(globals.group_mutex); } - FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *name) { ftdm_group_t *new_group = NULL; @@ -5314,7 +5299,11 @@ static ftdm_status_t ftdm_span_trigger_signal(const ftdm_span_t *span, ftdm_sigm if (sigmsg->channel) { ftdm_call_clear_data(&(sigmsg->channel->caller_data)); } - ftdm_safe_free(sigmsg->raw_data); + if (sigmsg->raw.autofree) { + ftdm_safe_free(sigmsg->raw.data); + sigmsg->raw.data = NULL; + sigmsg->raw.len = 0; + } return status; } @@ -5350,7 +5339,7 @@ static void execute_safety_hangup(void *data) fchan->hangup_timer = 0; if (fchan->state == FTDM_CHANNEL_STATE_TERMINATING) { ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Forcing hangup since the user did not confirmed our hangup after %dms\n", FORCE_HANGUP_TIMER); - call_hangup(fchan, __FILE__, __FUNCTION__, __LINE__); + _ftdm_channel_call_hangup_nl(fchan, __FILE__, __FUNCTION__, __LINE__); } else { ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Not performing safety hangup, channel state is %s\n", ftdm_channel_state2str(fchan->state)); } @@ -5368,8 +5357,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t case FTDM_SIGEVENT_SIGSTATUS_CHANGED: { - ftdm_signaling_status_t sigstatus = ftdm_test_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE) ? sigmsg->ev_data.sigstatus.status : *((ftdm_signaling_status_t*)(sigmsg->raw_data)); - if (sigstatus == FTDM_SIG_STATE_UP) { + if (sigmsg->ev_data.sigstatus.status == FTDM_SIG_STATE_UP) { ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_SIG_UP); } else { ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_SIG_UP); @@ -5379,7 +5367,8 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t case FTDM_SIGEVENT_START: { - ftdm_call_set_call_id(&sigmsg->channel->caller_data); + ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_CALL_STARTED); + ftdm_call_set_call_id(sigmsg->channel, &sigmsg->channel->caller_data); ftdm_set_echocancel_call_begin(sigmsg->channel); if (sigmsg->channel->dtmfdbg.requested) { ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DEBUG_DTMF, NULL); @@ -5394,6 +5383,11 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t break; case FTDM_SIGEVENT_STOP: + if (!ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_CALL_STARTED)) { + /* this happens for FXS devices which blindly send SIGEVENT_STOP, we should fix it there ... */ + ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Ignoring SIGEVENT_STOP since user never knew about a call in this channel\n"); + goto done; + } if (ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_USER_HANGUP)) { ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Ignoring SIGEVENT_STOP since user already requested hangup\n"); goto done; @@ -5959,78 +5953,58 @@ FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen) return new; } -FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan) -{ - char func[255]; - char line[255]; - char states[255]; - uint8_t i = 0; - - ftdm_stream_handle_t stream = { 0 }; - FTDM_STANDARD_STREAM(stream); - if (!fchan->history[0].file) { - stream.write_function(&stream, "-- No state history --\n"); - return stream.data; - } - - stream.write_function(&stream, "%-30.30s %-30.30s %s", "-- States --", "-- Function --", "-- Location --\n"); - - for (i = fchan->hindex; i < ftdm_array_len(fchan->history); i++) { - if (!fchan->history[i].file) { - break; - } - snprintf(states, sizeof(states), "%-5.15s => %-5.15s", ftdm_channel_state2str(fchan->history[i].last_state), ftdm_channel_state2str(fchan->history[i].state)); - snprintf(func, sizeof(func), "[%s]", fchan->history[i].func); - snprintf(line, sizeof(func), "[%s:%d]", fchan->history[i].file, fchan->history[i].line); - stream.write_function(&stream, "%-30.30s %-30.30s %s\n", states, func, line); - } - - for (i = 0; i < fchan->hindex; i++) { - snprintf(states, sizeof(states), "%-5.15s => %-5.15s", ftdm_channel_state2str(fchan->history[i].last_state), ftdm_channel_state2str(fchan->history[i].state)); - snprintf(func, sizeof(func), "[%s]", fchan->history[i].func); - snprintf(line, sizeof(func), "[%s:%d]", fchan->history[i].file, fchan->history[i].line); - stream.write_function(&stream, "%-30.30s %-30.30s %s\n", states, func, line); - } - - return stream.data; -} - -static ftdm_status_t ftdm_call_set_call_id(ftdm_caller_data_t *caller_data) +static ftdm_status_t ftdm_call_set_call_id(ftdm_channel_t *fchan, ftdm_caller_data_t *caller_data) { uint32_t current_call_id; - ftdm_assert_return(!caller_data->call_id, FTDM_FAIL, "Overwriting non-cleared call-id"); + + ftdm_assert_return(!caller_data->call_id, FTDM_FAIL, "Overwriting non-cleared call-id\n"); ftdm_mutex_lock(globals.call_id_mutex); + current_call_id = globals.last_call_id; - do { - if (++current_call_id > MAX_CALLIDS) { + for (current_call_id = globals.last_call_id + 1; + current_call_id != globals.last_call_id; + current_call_id++ ) { + if (current_call_id > MAX_CALLIDS) { current_call_id = 1; } - if (globals.call_ids[current_call_id] != NULL) { - continue; + if (globals.call_ids[current_call_id] == NULL) { + break; } - } while (0); + } + + ftdm_assert_return(globals.call_ids[current_call_id] == NULL, FTDM_FAIL, "We ran out of call ids\n"); globals.last_call_id = current_call_id; caller_data->call_id = current_call_id; globals.call_ids[current_call_id] = caller_data; + caller_data->fchan = fchan; + ftdm_mutex_unlock(globals.call_id_mutex); return FTDM_SUCCESS; } static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data) { - ftdm_assert_return((caller_data->call_id && caller_data->call_id <= MAX_CALLIDS), FTDM_FAIL, "Clearing call with invalid call-id\n"); + if (caller_data->call_id) { + ftdm_assert_return((caller_data->call_id <= MAX_CALLIDS), FTDM_FAIL, "Cannot clear call with invalid call-id\n"); + } else { + /* there might not be a call at all */ + return FTDM_SUCCESS; + } + ftdm_mutex_lock(globals.call_id_mutex); if (globals.call_ids[caller_data->call_id]) { - caller_data->call_id = 0; + ftdm_log(FTDM_LOG_DEBUG, "Cleared call with id %u\n", caller_data->call_id); globals.call_ids[caller_data->call_id] = NULL; + caller_data->call_id = 0; } else { ftdm_log(FTDM_LOG_CRIT, "call-id did not exist %u\n", caller_data->call_id); } ftdm_mutex_unlock(globals.call_id_mutex); + return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/ftdm_m3ua.c b/libs/freetdm/src/ftdm_m3ua.c deleted file mode 100644 index 8d3e00213a..0000000000 --- a/libs/freetdm/src/ftdm_m3ua.c +++ /dev/null @@ -1,692 +0,0 @@ -/* - * ftdm_m3ua.c - * freetdm - * - * Created by Shane Burrell on 4/3/08. - * Copyright 2008 Shane Burrell. All rights reserved. - * - * - * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include "freetdm.h" -#include "m3ua_client.h" -#include "ftdm_m3ua.h" - -#define MAX_REQ_ID MAX_PENDING_CALLS -typedef uint16_t m3ua_request_id_t; - -typedef enum { - BST_FREE, - BST_WAITING, - BST_READY, - BST_FAIL -} m3ua_request_status_t; - -typedef struct { - m3ua_request_status_t status; - m3uac_event_t event; - ftdm_span_t *span; - ftdm_channel_t *ftdmchan; -} m3ua_request_t; - - -struct general_config { - uint32_t region; -}; -typedef struct general_config general_config_t; - - -struct m3ua_channel_profile { - char name[80]; - int cust_span; - unsigned char opc[3]; - unsigned char dpc[3]; - int local_ip[4]; - int local_port; - int remote_ip[4]; - int remote_port; - int m3ua_mode; -}; -typedef struct m3ua_channel_profile m3ua_channel_profile_t; - -static struct { - ftdm_hash_t *profile_hash; - general_config_t general_config; -} globals; - -struct m3ua_span_data { - uint32_t boardno; - uint32_t flags; -}; -typedef struct m3ua_span_data m3ua_span_data_t; - -struct m3ua_chan_data { - ftdm_buffer_t *digit_buffer; - ftdm_mutex_t *digit_mutex; - ftdm_size_t dtmf_len; - uint32_t flags; - uint32_t hdlc_bytes; -}; -typedef struct m3ua_chan_data m3ua_chan_data_t; - -static ftdm_mutex_t *request_mutex = NULL; -static ftdm_mutex_t *signal_mutex = NULL; - -static uint8_t req_map[MAX_REQ_ID+1] = { 0 }; - -static void release_request_id(m3ua_request_id_t r) -{ - ftdm_mutex_lock(request_mutex); - req_map[r] = 0; - ftdm_mutex_unlock(request_mutex); -} - -/*static m3ua_request_id_t next_request_id(void) -{ - m3ua_request_id_t r = 0; - int ok = 0; - - while(!ok) { - ftdm_mutex_lock(request_mutex); - for (r = 1; r <= MAX_REQ_ID; r++) { - if (!req_map[r]) { - ok = 1; - req_map[r] = 1; - break; - } - } - ftdm_mutex_unlock(request_mutex); - if (!ok) { - ftdm_sleep(5); - } - } - return r; -} -*/ - -static __inline__ void state_advance(ftdm_channel_t *ftdmchan) -{ - - m3ua_data_t *m3ua_data = ftdmchan->span->signal_data; - m3uac_connection_t *mcon = &m3ua_data->mcon; - ftdm_sigmsg_t sig; - ftdm_status_t status; - - ftdm_log(FTDM_LOG_DEBUG, "%d:%d STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state)); - - memset(&sig, 0, sizeof(sig)); - sig.chan_id = ftdmchan->chan_id; - sig.span_id = ftdmchan->span_id; - sig.channel = ftdmchan; - - switch (ftdmchan->state) { - case FTDM_CHANNEL_STATE_DOWN: - { - if (ftdmchan->extra_id) { - release_request_id((m3ua_request_id_t)ftdmchan->extra_id); - ftdmchan->extra_id = 0; - } - ftdm_channel_close(&ftdmchan); - } - break; - case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: - case FTDM_CHANNEL_STATE_PROGRESS: - { - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA; - if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); - } - } else { - m3uac_exec_command(mcon, - ftdmchan->physical_span_id-1, - ftdmchan->physical_chan_id-1, - 0, - SIGBOOST_EVENT_CALL_START_ACK, - 0); - } - } - break; - case FTDM_CHANNEL_STATE_RING: - { - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - sig.event_id = FTDM_SIGEVENT_START; - if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); - } - } - - } - break; - case FTDM_CHANNEL_STATE_RESTART: - { - if (ftdmchan->last_state != FTDM_CHANNEL_STATE_HANGUP && ftdmchan->last_state != FTDM_CHANNEL_STATE_DOWN) { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); - } else { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - } - } - break; - case FTDM_CHANNEL_STATE_UP: - { - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - sig.event_id = FTDM_SIGEVENT_UP; - if ((status = m3ua_data->signal_cb(&sig) != FTDM_SUCCESS)) { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); - } - } else { - if (!(ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA))) { - m3uac_exec_command(mcon, - ftdmchan->physical_span_id-1, - ftdmchan->physical_chan_id-1, - 0, - SIGBOOST_EVENT_CALL_START_ACK, - 0); - } - - m3uac_exec_command(mcon, - ftdmchan->physical_span_id-1, - ftdmchan->physical_chan_id-1, - 0, - SIGBOOST_EVENT_CALL_ANSWERED, - 0); - } - } - break; - case FTDM_CHANNEL_STATE_DIALING: - { - } - break; - case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: - { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - } - break; - case FTDM_CHANNEL_STATE_HANGUP: - { - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_ANSWERED) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_PROGRESS) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_MEDIA)) { - m3uac_exec_command(mcon, - ftdmchan->physical_span_id-1, - ftdmchan->physical_chan_id-1, - 0, - SIGBOOST_EVENT_CALL_STOPPED, - ftdmchan->caller_data.hangup_cause); - } else { - m3uac_exec_command(mcon, - ftdmchan->physical_span_id-1, - ftdmchan->physical_chan_id-1, - 0, - SIGBOOST_EVENT_CALL_START_NACK, - ftdmchan->caller_data.hangup_cause); - } - } - break; - case FTDM_CHANNEL_STATE_CANCEL: - { - sig.event_id = FTDM_SIGEVENT_STOP; - status = m3ua_data->signal_cb(&sig); - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - m3uac_exec_command(mcon, - ftdmchan->physical_span_id-1, - ftdmchan->physical_chan_id-1, - 0, - SIGBOOST_EVENT_CALL_START_NACK_ACK, - 0); - } - break; - case FTDM_CHANNEL_STATE_TERMINATING: - { - sig.event_id = FTDM_SIGEVENT_STOP; - status = m3ua_data->signal_cb(&sig); - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - m3uac_exec_command(mcon, - ftdmchan->physical_span_id-1, - ftdmchan->physical_chan_id-1, - 0, - SIGBOOST_EVENT_CALL_STOPPED_ACK, - 0); - } - break; - default: - break; - } -} - - -static __inline__ void check_state(ftdm_span_t *span) -{ - if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) { - uint32_t j; - ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE); - for(j = 1; j <= span->chan_count; j++) { - if (ftdm_test_flag((&span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) { - ftdm_clear_flag_locked((&span->channels[j]), FTDM_CHANNEL_STATE_CHANGE); - state_advance(&span->channels[j]); - ftdm_channel_complete_state(&span->channels[j]); - } - } - } -} - - -static int parse_ss7_event(ftdm_span_t *span, m3uac_connection_t *mcon, m3uac_event_t *event) -{ - ftdm_mutex_lock(signal_mutex); - - if (!ftdm_running()) { - ftdm_log(FTDM_LOG_WARNING, "System is shutting down.\n"); - goto end; - } - - - if (ftdm_test_flag(span, FTDM_SPAN_SUSPENDED) && - event->event_id != SIGBOOST_EVENT_SYSTEM_RESTART_ACK && event->event_id != SIGBOOST_EVENT_HEARTBEAT) { - - ftdm_log(FTDM_LOG_WARNING, - "INVALID EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n", - m3uac_event_id_name(event->event_id), - event->event_id, - event->span+1, - event->chan+1, - event->release_cause, - event->call_setup_id, - event->fseqno, - (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"), - (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A") - ); - - goto end; - } - - - ftdm_log(FTDM_LOG_DEBUG, - "RX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n", - m3uac_event_id_name(event->event_id), - event->event_id, - event->span+1, - event->chan+1, - event->release_cause, - event->call_setup_id, - event->fseqno, - (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"), - (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A") - ); - - - - switch(event->event_id) { - - case SIGBOOST_EVENT_CALL_START: - //handle_call_start(span, mcon, event); - break; - case SIGBOOST_EVENT_CALL_STOPPED: - //handle_call_stop(span, mcon, event); - break; - case SIGBOOST_EVENT_CALL_START_ACK: - //handle_call_start_ack(mcon, event); - break; - case SIGBOOST_EVENT_CALL_START_NACK: - //handle_call_start_nack(span, mcon, event); - break; - case SIGBOOST_EVENT_CALL_ANSWERED: - //handle_call_answer(span, mcon, event); - break; - case SIGBOOST_EVENT_HEARTBEAT: - //handle_heartbeat(mcon, event); - break; - case SIGBOOST_EVENT_CALL_STOPPED_ACK: - case SIGBOOST_EVENT_CALL_START_NACK_ACK: - //handle_call_done(span, mcon, event); - break; - case SIGBOOST_EVENT_INSERT_CHECK_LOOP: - //handle_call_loop_start(event); - break; - case SIGBOOST_EVENT_REMOVE_CHECK_LOOP: - //handle_call_stop(event); - break; - case SIGBOOST_EVENT_SYSTEM_RESTART_ACK: - //handle_restart_ack(mcon, span, event); - break; - case SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE: - //handle_gap_abate(event); - break; - default: - ftdm_log(FTDM_LOG_WARNING, "No handler implemented for [%s]\n", m3uac_event_id_name(event->event_id)); - break; - } - - end: - - ftdm_mutex_unlock(signal_mutex); - - return 0; -} - -static FIO_CONFIGURE_FUNCTION(m3ua_configure) -{ - m3ua_channel_profile_t *profile = NULL; - - int ok = 1; - - if (!(profile = (m3ua_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) { - profile = ftdm_malloc(sizeof(*profile)); - memset(profile, 0, sizeof(*profile)); - ftdm_set_string(profile->name, category); - hashtable_insert(globals.profile_hash, (void *)profile->name, profile); - ftdm_log(FTDM_LOG_INFO, "creating profile [%s]\n", category); - } - -// ftdm_set_string(m3ua_data->mcon. cfg.local_ip, local_ip); - if (!strcasecmp(var, "local_sctp_port")) { - profile->local_port = 30000 ; - profile->remote_port = 30000; - profile->cust_span++; - } - ok = 1; - - - if (ok) { - ftdm_log(FTDM_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category); - } else { - ftdm_log(FTDM_LOG_ERROR, "unknown param [%s]\n", var); - } - - return FTDM_SUCCESS; -} - -static FIO_CONFIGURE_SPAN_FUNCTION(m3ua_configure_span) -{ - - return FTDM_FAIL; -} - -static FIO_OPEN_FUNCTION(m3ua_open) -{ - - return FTDM_FAIL; -} - -static FIO_CLOSE_FUNCTION(m3ua_close) -{ - - return FTDM_FAIL; -} - -/*static FIO_SET_INTERVAL_FUNCTION(m3ua_set_interval) -{ - - return 0; -}*/ - -static FIO_WAIT_FUNCTION(m3ua_wait) -{ - - return FTDM_FAIL; -} - -static FIO_READ_FUNCTION(m3ua_read) -{ - - return FTDM_FAIL; -} - -static FIO_WRITE_FUNCTION(m3ua_write) -{ - - return FTDM_FAIL; -} - -static FIO_COMMAND_FUNCTION(m3ua_command) -{ - return FTDM_FAIL; -} - -static FIO_SPAN_POLL_EVENT_FUNCTION(m3ua_poll_event) -{ - return FTDM_FAIL; -} - -static FIO_SPAN_NEXT_EVENT_FUNCTION(m3ua_next_event) -{ - return FTDM_FAIL; -} - - -static FIO_SPAN_DESTROY_FUNCTION(m3ua_span_destroy) -{ - m3ua_span_data_t *span_data = (m3ua_span_data_t *) span->io_data; - - if (span_data) { - ftdm_safe_free(span_data); - } - - return FTDM_SUCCESS; -} -static FIO_CHANNEL_DESTROY_FUNCTION(m3ua_channel_destroy) -{ - m3ua_chan_data_t *chan_data = (m3ua_chan_data_t *) ftdmchan->io_data; - m3ua_span_data_t *span_data = (m3ua_span_data_t *) ftdmchan->span->io_data; - - if (!chan_data) { - return FTDM_FAIL; - } - - - - - - - ftdm_mutex_destroy(&chan_data->digit_mutex); - ftdm_buffer_destroy(&chan_data->digit_buffer); - - - ftdm_safe_free(chan_data); - - if (span_data) { - ftdm_safe_free(span_data); - } - - - return FTDM_SUCCESS; -} - - - -static FIO_GET_ALARMS_FUNCTION(m3ua_get_alarms) -{ - return FTDM_FAIL; -} - -static ftdm_io_interface_t m3ua_interface; - -ftdm_status_t m3ua_init(ftdm_io_interface_t **zint) -{ - assert(zint != NULL); - memset(&m3ua_interface, 0, sizeof(m3ua_interface)); - - m3ua_interface.name = "m3ua"; - m3ua_interface.configure = m3ua_configure; - m3ua_interface.configure_span = m3ua_configure_span; - m3ua_interface.open = m3ua_open; - m3ua_interface.close = m3ua_close; - m3ua_interface.wait = m3ua_wait; - m3ua_interface.read = m3ua_read; - m3ua_interface.write = m3ua_write; - m3ua_interface.command = m3ua_command; - m3ua_interface.poll_event = m3ua_poll_event; - m3ua_interface.next_event = m3ua_next_event; - m3ua_interface.channel_destroy = m3ua_channel_destroy; - m3ua_interface.span_destroy = m3ua_span_destroy; - m3ua_interface.get_alarms = m3ua_get_alarms; - *zint = &m3ua_interface; - - return FTDM_FAIL; -} - -ftdm_status_t m3ua_destroy(void) -{ - return FTDM_FAIL; -} - - -static void *m3ua_run(ftdm_thread_t *me, void *obj) -{ - ftdm_span_t *span = (ftdm_span_t *) obj; - m3ua_data_t *m3ua_data = span->signal_data; - m3uac_connection_t *mcon, *pcon; - uint32_t ms = 10, too_long = 60000; - - - m3ua_data->pcon = m3ua_data->mcon; - - if (m3uac_connection_open(&m3ua_data->mcon, - m3ua_data->mcon.cfg.local_ip, - m3ua_data->mcon.cfg.local_port, - m3ua_data->mcon.cfg.remote_ip, - m3ua_data->mcon.cfg.remote_port) < 0) { - ftdm_log(FTDM_LOG_DEBUG, "Error: Opening MCON Socket [%d] %s\n", m3ua_data->mcon.socket, strerror(errno)); - goto end; - } - - if (m3uac_connection_open(&m3ua_data->pcon, - m3ua_data->pcon.cfg.local_ip, - ++m3ua_data->pcon.cfg.local_port, - m3ua_data->pcon.cfg.remote_ip, - m3ua_data->pcon.cfg.remote_port) < 0) { - ftdm_log(FTDM_LOG_DEBUG, "Error: Opening PCON Socket [%d] %s\n", m3ua_data->pcon.socket, strerror(errno)); - goto end; - } - - mcon = &m3ua_data->mcon; - pcon = &m3ua_data->pcon; - - top: - - //init_outgoing_array(); - - m3uac_exec_command(mcon, - 0, - 0, - -1, - SIGBOOST_EVENT_SYSTEM_RESTART, - 0); - - while (ftdm_test_flag(m3ua_data, FTDM_M3UA_RUNNING)) { - fd_set rfds, efds; - struct timeval tv = { 0, ms * 1000 }; - int max, activity, i = 0; - m3uac_event_t *event = NULL; - - if (!ftdm_running()) { - m3uac_exec_command(mcon, - 0, - 0, - -1, - SIGBOOST_EVENT_SYSTEM_RESTART, - 0); - break; - } - - FD_ZERO(&rfds); - FD_ZERO(&efds); - FD_SET(mcon->socket, &rfds); - FD_SET(mcon->socket, &efds); - FD_SET(pcon->socket, &rfds); - FD_SET(pcon->socket, &efds); - - max = ((pcon->socket > mcon->socket) ? pcon->socket : mcon->socket) + 1; - - if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) { - goto error; - } - - if (activity) { - if (FD_ISSET(pcon->socket, &efds) || FD_ISSET(mcon->socket, &efds)) { - goto error; - } - - if (FD_ISSET(pcon->socket, &rfds)) { - if ((event = m3uac_connection_readp(pcon, i))) { - parse_ss7_event(span, mcon, event); - } else goto top; - } - - if (FD_ISSET(mcon->socket, &rfds)) { - if ((event = m3uac_connection_read(mcon, i))) { - parse_ss7_event(span, mcon, event); - } else goto top; - } - } - - check_state(span); - mcon->hb_elapsed += ms; - - if (mcon->hb_elapsed >= too_long && (mcon->up || !ftdm_test_flag(span, FTDM_SPAN_SUSPENDED))) { - ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART); - ftdm_set_flag_locked(span, FTDM_SPAN_SUSPENDED); - mcon->up = 0; - ftdm_log(FTDM_LOG_CRIT, "Lost Heartbeat!\n"); - } - - } - - goto end; - - error: - ftdm_log(FTDM_LOG_CRIT, "Socket Error!\n"); - - end: - - m3uac_connection_close(&m3ua_data->mcon); - m3uac_connection_close(&m3ua_data->pcon); - - ftdm_clear_flag(m3ua_data, FTDM_M3UA_RUNNING); - - ftdm_log(FTDM_LOG_DEBUG, "M3UA thread ended.\n"); - return NULL; -} -ftdm_status_t m3ua_start(ftdm_span_t *span) -{ - m3ua_data_t *m3ua_data = span->signal_data; - ftdm_set_flag(m3ua_data, FTDM_M3UA_RUNNING); - return ftdm_thread_create_detached(m3ua_run, span); -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: -*/ diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c new file mode 100644 index 0000000000..f6c2c2320c --- /dev/null +++ b/libs/freetdm/src/ftdm_state.c @@ -0,0 +1,486 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * Moises Silva + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "private/ftdm_core.h" + +FTDM_ENUM_NAMES(CHANNEL_STATE_NAMES, CHANNEL_STATE_STRINGS) +FTDM_STR2ENUM(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t, CHANNEL_STATE_NAMES, FTDM_CHANNEL_STATE_INVALID) + +FTDM_ENUM_NAMES(CHANNEL_STATE_STATUS_NAMES, CHANNEL_STATE_STATUS_STRINGS) +FTDM_STR2ENUM(ftdm_str2ftdm_state_status, ftdm_state_status2str, ftdm_state_status_t, CHANNEL_STATE_STATUS_NAMES, FTDM_STATE_STATUS_INVALID) + +/* This function is only needed for boost and we should get rid of it at the next refactoring */ +FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *fchan) +{ + ftdm_channel_lock(fchan); + + if (fchan->init_state != FTDM_CHANNEL_STATE_DOWN) { + ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, fchan, fchan->init_state, 1); + fchan->init_state = FTDM_CHANNEL_STATE_DOWN; + } + + ftdm_channel_unlock(fchan); + return FTDM_SUCCESS; +} + +FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const char *func, int line, ftdm_channel_t *fchan) +{ + uint8_t hindex = 0; + ftdm_time_t diff = 0; + ftdm_channel_state_t state = fchan->state; + + if (fchan->state_status == FTDM_STATE_STATUS_COMPLETED) { + ftdm_assert_return(!ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE), FTDM_FAIL, + "State change flag set but state is not completed\n"); + return FTDM_SUCCESS; + } + + ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE); + + if (state == FTDM_CHANNEL_STATE_PROGRESS) { + ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS); + } else if (state == FTDM_CHANNEL_STATE_UP) { + ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS); + ftdm_set_flag(fchan, FTDM_CHANNEL_MEDIA); + ftdm_set_flag(fchan, FTDM_CHANNEL_ANSWERED); + } else if (state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) { + ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS); + ftdm_set_flag(fchan, FTDM_CHANNEL_MEDIA); + } + + /* if there is a pending ack for an indication + * MAINTENANCE WARNING: we're assuming an indication performed + * via state change will involve a single state change + */ + if (ftdm_test_flag(fchan, FTDM_CHANNEL_IND_ACK_PENDING)) { + ftdm_ack_indication(fchan, fchan->indication, FTDM_SUCCESS); + } + + hindex = (fchan->hindex == 0) ? (ftdm_array_len(fchan->history) - 1) : (fchan->hindex - 1); + + ftdm_assert(!fchan->history[hindex].end_time, "End time should be zero!\n"); + + fchan->history[hindex].end_time = ftdm_current_time_in_ms(); + + fchan->state_status = FTDM_STATE_STATUS_COMPLETED; + + diff = fchan->history[hindex].end_time - fchan->history[hindex].time; + + ftdm_log_chan_ex(fchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Completed state change from %s to %s in %llums\n", + ftdm_channel_state2str(fchan->last_state), ftdm_channel_state2str(state), diff); + + + if (ftdm_test_flag(fchan, FTDM_CHANNEL_BLOCKING)) { + ftdm_clear_flag(fchan, FTDM_CHANNEL_BLOCKING); + ftdm_interrupt_signal(fchan->state_completed_interrupt); + } + + return FTDM_SUCCESS; +} + +FT_DECLARE(ftdm_status_t) _ftdm_set_state(const char *file, const char *func, int line, + ftdm_channel_t *fchan, ftdm_channel_state_t state) +{ + if (fchan->state_status != FTDM_STATE_STATUS_COMPLETED) { + /* the current state is not completed, setting a new state from a signaling module + when the current state is not completed is equivalent to implicitly acknowledging + the current state */ + _ftdm_channel_complete_state(file, func, line, fchan); + } + return ftdm_channel_set_state(file, func, line, fchan, state, 0); +} + +static int ftdm_parse_state_map(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, ftdm_state_map_t *state_map) +{ + int x = 0, ok = 0; + ftdm_state_direction_t direction = ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) ? ZSD_OUTBOUND : ZSD_INBOUND; + + for(x = 0; x < FTDM_MAP_NODE_SIZE; x++) { + int i = 0, proceed = 0; + if (!state_map->nodes[x].type) { + break; + } + + if (state_map->nodes[x].direction != direction) { + continue; + } + + if (state_map->nodes[x].check_states[0] == FTDM_ANY_STATE) { + proceed = 1; + } else { + for(i = 0; i < FTDM_MAP_MAX; i++) { + if (state_map->nodes[x].check_states[i] == ftdmchan->state) { + proceed = 1; + break; + } + } + } + + if (!proceed) { + continue; + } + + for(i = 0; i < FTDM_MAP_MAX; i++) { + ok = (state_map->nodes[x].type == ZSM_ACCEPTABLE); + if (state_map->nodes[x].states[i] == FTDM_END) { + break; + } + if (state_map->nodes[x].states[i] == state) { + ok = !ok; + goto end; + } + } + } + end: + + return ok; +} + +/* this function MUST be called with the channel lock held. If waitrq == 1, the channel will be unlocked/locked (never call it with waitrq == 1 with an lock recursivity > 1) */ +#define DEFAULT_WAIT_TIME 1000 +FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int waitrq) +{ + ftdm_status_t status; + int ok = 1; + int waitms = DEFAULT_WAIT_TIME; + + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) { + ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR, "Ignored state change request from %s to %s, the channel is not ready\n", + ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); + return FTDM_FAIL; + } + + if (ftdmchan->state_status != FTDM_STATE_STATUS_COMPLETED) { + ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_ERROR, + "Ignored state change request from %s to %s, the previous state change has not been processed yet (status = %s)\n", + ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state), + ftdm_state_status2str(ftdmchan->state_status)); + return FTDM_FAIL; + } + + if (ftdmchan->state == state) { + ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "Why bother changing state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); + return FTDM_FAIL; + } + + if (!ftdmchan->state_completed_interrupt) { + status = ftdm_interrupt_create(&ftdmchan->state_completed_interrupt, FTDM_INVALID_SOCKET); + if (status != FTDM_SUCCESS) { + ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_CRIT, + "Failed to create state change interrupt when moving from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); + return status; + } + } + + + if (ftdmchan->span->state_map) { + ok = ftdm_parse_state_map(ftdmchan, state, ftdmchan->span->state_map); + goto end; + } + + /* basic core state validation (by-passed if the signaling module provides a state_map) */ + switch(ftdmchan->state) { + case FTDM_CHANNEL_STATE_HANGUP: + case FTDM_CHANNEL_STATE_TERMINATING: + { + ok = 0; + switch(state) { + case FTDM_CHANNEL_STATE_DOWN: + case FTDM_CHANNEL_STATE_BUSY: + case FTDM_CHANNEL_STATE_RESTART: + ok = 1; + break; + default: + break; + } + } + break; + case FTDM_CHANNEL_STATE_UP: + { + ok = 1; + switch(state) { + case FTDM_CHANNEL_STATE_PROGRESS: + case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: + case FTDM_CHANNEL_STATE_RING: + ok = 0; + break; + default: + break; + } + } + break; + case FTDM_CHANNEL_STATE_DOWN: + { + ok = 0; + + switch(state) { + case FTDM_CHANNEL_STATE_DIALTONE: + case FTDM_CHANNEL_STATE_COLLECT: + case FTDM_CHANNEL_STATE_DIALING: + case FTDM_CHANNEL_STATE_RING: + case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: + case FTDM_CHANNEL_STATE_PROGRESS: + case FTDM_CHANNEL_STATE_IDLE: + case FTDM_CHANNEL_STATE_GET_CALLERID: + case FTDM_CHANNEL_STATE_GENRING: + ok = 1; + break; + default: + break; + } + } + break; + case FTDM_CHANNEL_STATE_BUSY: + { + switch(state) { + case FTDM_CHANNEL_STATE_UP: + ok = 0; + break; + default: + break; + } + } + break; + case FTDM_CHANNEL_STATE_RING: + { + switch(state) { + case FTDM_CHANNEL_STATE_UP: + ok = 1; + break; + default: + break; + } + } + break; + default: + break; + } + +end: + + if (!ok) { + ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "VETO state change from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); + goto done; + } + + ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_DEBUG, "Changed state from %s to %s\n", ftdm_channel_state2str(ftdmchan->state), ftdm_channel_state2str(state)); + ftdmchan->last_state = ftdmchan->state; + ftdmchan->state = state; + ftdmchan->state_status = FTDM_STATE_STATUS_NEW; + ftdmchan->history[ftdmchan->hindex].file = file; + ftdmchan->history[ftdmchan->hindex].func = func; + ftdmchan->history[ftdmchan->hindex].line = line; + ftdmchan->history[ftdmchan->hindex].state = ftdmchan->state; + ftdmchan->history[ftdmchan->hindex].last_state = ftdmchan->last_state; + ftdmchan->history[ftdmchan->hindex].time = ftdm_current_time_in_ms(); + ftdmchan->history[ftdmchan->hindex].end_time = 0; + ftdmchan->hindex++; + if (ftdmchan->hindex == ftdm_array_len(ftdmchan->history)) { + ftdmchan->hindex = 0; + } + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); + + ftdm_mutex_lock(ftdmchan->span->mutex); + ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE); + if (ftdmchan->span->pendingchans) { + ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan); + } + ftdm_mutex_unlock(ftdmchan->span->mutex); + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_NONBLOCK)) { + /* the channel should not block waiting for state processing */ + goto done; + } + + if (!waitrq) { + /* no waiting was requested */ + goto done; + } + + /* let's wait for the state change to be completed by the signaling stack */ + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_BLOCKING); + + ftdm_mutex_unlock(ftdmchan->mutex); + + status = ftdm_interrupt_wait(ftdmchan->state_completed_interrupt, waitms); + + ftdm_mutex_lock(ftdmchan->mutex); + + if (status != FTDM_SUCCESS) { + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_BLOCKING); + ftdm_log_chan_ex(ftdmchan, file, func, line, + FTDM_LOG_LEVEL_WARNING, "state change from %s to %s was most likely not completed after aprox %dms\n", + ftdm_channel_state2str(ftdmchan->last_state), ftdm_channel_state2str(state), DEFAULT_WAIT_TIME); + ok = 0; + goto done; + } +done: + return ok ? FTDM_SUCCESS : FTDM_FAIL; +} + +FT_DECLARE(int) ftdm_channel_get_state(const ftdm_channel_t *ftdmchan) +{ + int state; + ftdm_channel_lock(ftdmchan); + state = ftdmchan->state; + ftdm_channel_unlock(ftdmchan); + return state; +} + +FT_DECLARE(const char *) ftdm_channel_get_state_str(const ftdm_channel_t *ftdmchan) +{ + const char *state; + ftdm_channel_lock(ftdmchan); + state = ftdm_channel_state2str(ftdmchan->state); + ftdm_channel_unlock(ftdmchan); + return state; +} + +FT_DECLARE(int) ftdm_channel_get_last_state(const ftdm_channel_t *ftdmchan) +{ + int last_state; + ftdm_channel_lock(ftdmchan); + last_state = ftdmchan->last_state; + ftdm_channel_unlock(ftdmchan); + return last_state; +} + +FT_DECLARE(const char *) ftdm_channel_get_last_state_str(const ftdm_channel_t *ftdmchan) +{ + const char *state; + ftdm_channel_lock(ftdmchan); + state = ftdm_channel_state2str(ftdmchan->last_state); + ftdm_channel_unlock(ftdmchan); + return state; +} + +static void write_history_entry(const ftdm_channel_t *fchan, ftdm_stream_handle_t *stream, int i, ftdm_time_t *prevtime) +{ + char func[255]; + char line[255]; + char states[255]; + const char *filename = NULL; + snprintf(states, sizeof(states), "%-5.15s => %-5.15s", ftdm_channel_state2str(fchan->history[i].last_state), ftdm_channel_state2str(fchan->history[i].state)); + snprintf(func, sizeof(func), "[%s]", fchan->history[i].func); + filename = strrchr(fchan->history[i].file, *FTDM_PATH_SEPARATOR); + if (!filename) { + filename = fchan->history[i].file; + } else { + filename++; + } + if (!(*prevtime)) { + *prevtime = fchan->history[i].time; + } + snprintf(line, sizeof(func), "[%s:%d]", filename, fchan->history[i].line); + stream->write_function(stream, "%-30.30s %-30.30s %-30.30s %lums\n", states, func, line, (fchan->history[i].time - *prevtime)); + *prevtime = fchan->history[i].time; +} + +FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan) +{ + uint8_t i = 0; + ftdm_time_t currtime = 0; + ftdm_time_t prevtime = 0; + + ftdm_stream_handle_t stream = { 0 }; + FTDM_STANDARD_STREAM(stream); + if (!fchan->history[0].file) { + stream.write_function(&stream, "-- No state history --\n"); + return stream.data; + } + + stream.write_function(&stream, "%-30.30s %-30.30s %-30.30s %s", + "-- States --", "-- Function --", "-- Location --", "-- Time Offset --\n"); + + for (i = fchan->hindex; i < ftdm_array_len(fchan->history); i++) { + if (!fchan->history[i].file) { + break; + } + write_history_entry(fchan, &stream, i, &prevtime); + } + + for (i = 0; i < fchan->hindex; i++) { + write_history_entry(fchan, &stream, i, &prevtime); + } + + currtime = ftdm_current_time_in_ms(); + + stream.write_function(&stream, "\nTime since last state change: %lums\n", (currtime - prevtime)); + + return stream.data; +} + +FT_DECLARE(ftdm_status_t) ftdm_channel_advance_states(ftdm_channel_t *fchan) +{ + ftdm_channel_state_t state; + + ftdm_assert_return(fchan->span->state_processor, FTDM_FAIL, "Cannot process states without a state processor!\n"); + + while (fchan->state_status == FTDM_STATE_STATUS_NEW) { + state = fchan->state; + ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Executing state processor for %s\n", ftdm_channel_state2str(fchan->state)); + fchan->span->state_processor(fchan); + if (state == fchan->state && fchan->state_status == FTDM_STATE_STATUS_NEW) { + /* if the state did not change and is still NEW, the state status must go to PROCESSED + * otherwise we don't touch it since is a new state and the old state was + * already completed implicitly by the state_processor() function via some internal + * call to ftdm_set_state() */ + fchan->state_status = FTDM_STATE_STATUS_PROCESSED; + } + } + + return FTDM_SUCCESS; +} + +FT_DECLARE(int) ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state) +{ + uint32_t j; + for(j = 1; j <= span->chan_count; j++) { + if (span->channels[j]->state != state || ftdm_test_flag(span->channels[j], FTDM_CHANNEL_STATE_CHANGE)) { + return 0; + } + } + return 1; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/libs/freetdm/src/ftdm_threadmutex.c b/libs/freetdm/src/ftdm_threadmutex.c index b1884ec587..6efa27714c 100644 --- a/libs/freetdm/src/ftdm_threadmutex.c +++ b/libs/freetdm/src/ftdm_threadmutex.c @@ -56,7 +56,11 @@ struct ftdm_interrupt { /* for generic interruption */ HANDLE event; #else - /* for generic interruption */ + /* In theory we could be using thread conditions for generic interruption, + * however, Linux does not have a primitive like Windows WaitForMultipleObjects + * to wait for both thread condition and file descriptors, therefore we decided + * to use a dummy pipe for generic interruption/condition logic + * */ int readfd; int writefd; #endif @@ -243,6 +247,7 @@ FT_DECLARE(ftdm_status_t) _ftdm_mutex_unlock(ftdm_mutex_t *mutex) FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt, ftdm_socket_t device) { + ftdm_status_t status = FTDM_SUCCESS; ftdm_interrupt_t *interrupt = NULL; #ifndef WIN32 int fds[2]; @@ -253,7 +258,7 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt, interrupt = ftdm_calloc(1, sizeof(*interrupt)); if (!interrupt) { ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt memory\n"); - return FTDM_FAIL; + return FTDM_ENOMEM; } interrupt->device = device; @@ -261,11 +266,13 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt, interrupt->event = CreateEvent(NULL, FALSE, FALSE, NULL); if (!interrupt->event) { ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt event\n"); + status = FTDM_ENOMEM; goto failed; } #else if (pipe(fds)) { ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt pipe: %s\n", strerror(errno)); + status = FTDM_FAIL; goto failed; } interrupt->readfd = fds[0]; @@ -287,7 +294,7 @@ failed: #endif ftdm_safe_free(interrupt); } - return FTDM_FAIL; + return status; } #define ONE_BILLION 1000000000 diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h index 2c79822b29..39cbc5ff2b 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftdm_analog.h @@ -37,7 +37,9 @@ typedef enum { FTDM_ANALOG_RUNNING = (1 << 0), - FTDM_ANALOG_CALLERID = (1 << 1) + FTDM_ANALOG_CALLERID = (1 << 1), + FTDM_ANALOG_ANSWER_POLARITY_REVERSE = (1 << 2), + FTDM_ANALOG_HANGUP_POLARITY_REVERSE = (1 << 3) } ftdm_analog_flag_t; #define FTDM_MAX_HOTLINE_STR 20 @@ -47,11 +49,13 @@ struct ftdm_analog_data { uint32_t flags; uint32_t max_dialstr; uint32_t wait_dialtone_timeout; + uint32_t polarity_delay; uint32_t digit_timeout; char hotline[FTDM_MAX_HOTLINE_STR]; }; - +/* Analog flags to be set in the sflags (signaling flags) channel memeber */ +#define AF_POLARITY_REVERSE (1 << 0) static void *ftdm_analog_run(ftdm_thread_t *me, void *obj); typedef struct ftdm_analog_data ftdm_analog_data_t; diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c index f07f48b0d6..818f1c5754 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c @@ -96,6 +96,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call) static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_get_channel_sig_status) { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) { + *status = FTDM_SIG_STATE_DOWN; + return FTDM_SUCCESS; + } *status = FTDM_SIG_STATE_UP; return FTDM_SUCCESS; } @@ -109,7 +113,25 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_get_channel_sig_status) static FIO_SPAN_GET_SIG_STATUS_FUNCTION(analog_get_span_sig_status) { - *status = FTDM_SIG_STATE_UP; + ftdm_iterator_t *citer = NULL; + ftdm_iterator_t *chaniter = ftdm_span_get_chan_iterator(span, NULL); + if (!chaniter) { + ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name); + return FTDM_FAIL; + } + /* if ALL channels are in alarm, report DOWN, UP otherwise. */ + *status = FTDM_SIG_STATE_DOWN; + for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) { + ftdm_channel_t *fchan = ftdm_iterator_current(citer); + ftdm_channel_lock(fchan); + if (!ftdm_test_flag(fchan, FTDM_CHANNEL_IN_ALARM)) { + *status = FTDM_SIG_STATE_UP; + ftdm_channel_unlock(fchan); + break; + } + ftdm_channel_unlock(fchan); + } + ftdm_iterator_free(chaniter); return FTDM_SUCCESS; } @@ -162,6 +184,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span) uint32_t digit_timeout = 10; uint32_t wait_dialtone_timeout = 30000; uint32_t max_dialstr = MAX_DTMF; + uint32_t polarity_delay = 600; const char *var, *val; int *intval; uint32_t flags = FTDM_ANALOG_CALLERID; @@ -214,6 +237,29 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span) } else { flags &= ~FTDM_ANALOG_CALLERID; } + } else if (!strcasecmp(var, "answer_polarity_reverse")) { + if (!(val = va_arg(ap, char *))) { + break; + } + if (ftdm_true(val)) { + flags |= FTDM_ANALOG_ANSWER_POLARITY_REVERSE; + } else { + flags &= ~FTDM_ANALOG_ANSWER_POLARITY_REVERSE; + } + } else if (!strcasecmp(var, "hangup_polarity_reverse")) { + if (!(val = va_arg(ap, char *))) { + break; + } + if (ftdm_true(val)) { + flags |= FTDM_ANALOG_HANGUP_POLARITY_REVERSE; + } else { + flags &= ~FTDM_ANALOG_HANGUP_POLARITY_REVERSE; + } + } else if (!strcasecmp(var, "polarity_delay")) { + if (!(intval = va_arg(ap, int *))) { + break; + } + polarity_delay = *intval; } else if (!strcasecmp(var, "callwaiting")) { if (!(intval = va_arg(ap, int *))) { break; @@ -254,6 +300,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span) analog_data->flags = flags; analog_data->digit_timeout = digit_timeout; analog_data->wait_dialtone_timeout = wait_dialtone_timeout; + analog_data->polarity_delay = polarity_delay; analog_data->max_dialstr = max_dialstr; span->signal_cb = sig_cb; strncpy(analog_data->hotline, hotline, sizeof(analog_data->hotline)); @@ -377,6 +424,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) ftdm_analog_data_t *analog_data = ftdmchan->span->signal_data; ftdm_channel_t *closed_chan; uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = analog_data->wait_dialtone_timeout; + uint32_t answer_on_polarity_counter = 0; ftdm_sigmsg_t sig; ftdm_status_t status; @@ -448,7 +496,12 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) if (ftdmchan->needed_tones[FTDM_TONEMAP_DIAL]) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY); } else { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); + /* do not go up if we're waiting for polarity reversal */ + if (ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)) { + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); + } else { + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); + } } } } @@ -493,8 +546,10 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) if (ftdmchan->type == FTDM_CHAN_TYPE_FXS && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && - (ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE - || ftdmchan->last_state == FTDM_CHANNEL_STATE_RING)) { + (ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING + || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE + || ftdmchan->last_state == FTDM_CHANNEL_STATE_RING + || ftdmchan->last_state == FTDM_CHANNEL_STATE_UP)) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY); } else { ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING; @@ -530,15 +585,37 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) if (done) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE); + ftdm_channel_complete_state(ftdmchan); ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0; } } case FTDM_CHANNEL_STATE_UP: case FTDM_CHANNEL_STATE_RING: + case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: { - ftdm_sleep(interval); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && + ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA && + ftdm_test_sflag(ftdmchan, AF_POLARITY_REVERSE)) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Answering on polarity reverse\n"); + ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE); + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); + answer_on_polarity_counter = state_counter; + } else if (ftdmchan->state == FTDM_CHANNEL_STATE_UP + && ftdm_test_sflag(ftdmchan, AF_POLARITY_REVERSE)){ + /* if this polarity reverse is close to the answer polarity reverse, ignore it */ + if (answer_on_polarity_counter + && (state_counter - answer_on_polarity_counter) > analog_data->polarity_delay) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Hanging up on polarity reverse\n"); + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, + "Not hanging up on polarity reverse, too close to Answer reverse\n"); + } + ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE); + } else { + ftdm_sleep(interval); + } continue; } break; @@ -551,7 +628,6 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) break; } } else { - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE); ftdm_channel_complete_state(ftdmchan); indicate = 0; @@ -591,6 +667,19 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) sig.event_id = FTDM_SIGEVENT_UP; } + if (ftdmchan->type == FTDM_CHAN_TYPE_FXS && + !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && + ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)) { + ftdm_polarity_t polarity = FTDM_POLARITY_REVERSE; + if (ftdmchan->polarity == FTDM_POLARITY_FORWARD) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Reversing polarity on answer\n"); + ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_POLARITY, &polarity); + } else { + /* the polarity may be already reversed if this is the second time we + * answer (ie, due to 2 calls being on the same line) */ + } + } + ftdm_span_send_signal(ftdmchan->span, &sig); continue; } @@ -615,6 +704,22 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) continue; } break; + + case FTDM_CHANNEL_STATE_HANGUP: + /* this state is only used when the user hangup, if the device hang up (onhook) we currently + * go straight to DOWN. If we ever change this (as other signaling modules do) by using this + * state for both user and device hangup, we should check here for the type of hangup since + * some actions (polarity reverse) do not make sense if the device hung up */ + if (ftdmchan->type == FTDM_CHAN_TYPE_FXS && + ftdmchan->last_state == FTDM_CHANNEL_STATE_UP && + ftdm_test_flag(analog_data, FTDM_ANALOG_HANGUP_POLARITY_REVERSE)) { + ftdm_polarity_t polarity = ftdmchan->polarity == FTDM_POLARITY_REVERSE + ? FTDM_POLARITY_FORWARD : FTDM_POLARITY_REVERSE; + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Reversing polarity on hangup\n"); + ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_POLARITY, &polarity); + } + break; + case FTDM_CHANNEL_STATE_DOWN: { sig.event_id = FTDM_SIGEVENT_STOP; @@ -717,7 +822,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) dtmf_offset = strlen(dtmf); last_digit = elapsed; sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT; - sig.raw_data = dtmf; + ftdm_set_string(sig.ev_data.collected.digits, dtmf); if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) { collecting = 0; } @@ -823,6 +928,9 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) done: + closed_chan = ftdmchan; + + ftdm_channel_lock(closed_chan); if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) { ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL); @@ -833,7 +941,8 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) } - closed_chan = ftdmchan; + ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE); + ftdm_channel_close(&ftdmchan); ftdm_channel_command(closed_chan, FTDM_COMMAND_SET_NATIVE_CODEC, NULL); @@ -851,8 +960,11 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) } ftdm_log_chan(closed_chan, FTDM_LOG_DEBUG, "ANALOG CHANNEL %d:%d thread ended.\n", closed_chan->span_id, closed_chan->chan_id); + ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD); + ftdm_channel_unlock(closed_chan); + return NULL; } @@ -879,19 +991,32 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e ftdm_mutex_lock(event->channel->mutex); locked++; + /* MAINTENANCE WARNING: + * 1. Be aware you are working on the locked channel + * 2. We should not be calling ftdm_span_send_signal or ftdm_set_state when there is already a channel thread running + * however, since this is old code I am not changing it now, but new code should adhere to that convention + * otherwise, we have possible races where we compete with the user for state changes, ie, the user requests + * a state change and then we process an event, the state change from the user is pending so our ftdm_set_state + * operation will fail. In cases where we win the race, our state change will be accepted but if a user requests + * a state change before the state change we requested here is processed by the channel thread, we'll end up + * rejecting the user request. + * + * See docs/locking.txt for further information about what guarantees should signaling modules provide when + * locking/unlocking a channel + * */ switch(event->enum_id) { case FTDM_OOB_RING_START: { if (event->channel->type != FTDM_CHAN_TYPE_FXO) { ftdm_log_chan_msg(event->channel, FTDM_LOG_ERROR, "Cannot get a RING_START event on a non-fxo channel, please check your config.\n"); - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN); goto end; } if (!event->channel->ring_count && (event->channel->state == FTDM_CHANNEL_STATE_DOWN && !ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD))) { if (ftdm_test_flag(analog_data, FTDM_ANALOG_CALLERID)) { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID); } else { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RING); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_RING); } event->channel->ring_count = 1; ftdm_mutex_unlock(event->channel->mutex); @@ -909,24 +1034,33 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e } if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN); + if (event->channel->state == FTDM_CHANNEL_STATE_HANGUP && + ftdm_test_flag(event->channel, FTDM_CHANNEL_STATE_CHANGE)) { + /* we do not need to process HANGUP since the device also hangup already */ + ftdm_channel_complete_state(event->channel); + } + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN); + } + if (event->channel->type == FTDM_CHAN_TYPE_FXS) { + /* we always return to forward when the device goes onhook */ + ftdm_polarity_t forward_polarity = FTDM_POLARITY_FORWARD; + ftdm_channel_command(event->channel, FTDM_COMMAND_SET_POLARITY, &forward_polarity); } - } break; case FTDM_OOB_FLASH: { if (event->channel->state == FTDM_CHANNEL_STATE_CALLWAITING) { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP); - ftdm_clear_flag_locked(event->channel, FTDM_CHANNEL_STATE_CHANGE); - ftdm_clear_flag_locked(event->channel->span, FTDM_SPAN_STATE_CHANGE); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP); + ftdm_clear_flag(event->channel->span, FTDM_SPAN_STATE_CHANGE); + ftdm_channel_complete_state(event->channel); event->channel->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0; } ftdm_channel_rotate_tokens(event->channel); if (ftdm_test_flag(event->channel, FTDM_CHANNEL_HOLD) && event->channel->token_count != 1) { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP); } else { sig.event_id = FTDM_SIGEVENT_FLASH; ftdm_span_send_signal(span, &sig); @@ -940,12 +1074,12 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e if (ftdm_test_flag(event->channel, FTDM_CHANNEL_RINGING)) { ftdm_channel_command(event->channel, FTDM_COMMAND_GENERATE_RING_OFF, NULL); } - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP); } else { if(!analog_data->max_dialstr) { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_COLLECT); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_COLLECT); } else { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DIALTONE); } ftdm_mutex_unlock(event->channel->mutex); locked = 0; @@ -957,9 +1091,53 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL); } } - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN); } } + break; + case FTDM_OOB_ALARM_TRAP: + { + sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sig.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN; + ftdm_span_send_signal(span, &sig); + } + break; + case FTDM_OOB_ALARM_CLEAR: + { + sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sig.ev_data.sigstatus.status = FTDM_SIG_STATE_UP; + ftdm_span_send_signal(span, &sig); + } + break; + case FTDM_OOB_POLARITY_REVERSE: + { + if (event->channel->type != FTDM_CHAN_TYPE_FXO) { + ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING, + "Ignoring polarity reversal, this should not happen in non-FXO channels!\n"); + break; + } + if (!ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD) && + ftdm_test_flag(event->channel, FTDM_CHANNEL_OFFHOOK)) { + ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING, + "Forcing onhook in channel not in thread after polarity reversal\n"); + ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL); + break; + } + if (!ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE) + && !ftdm_test_flag(analog_data, FTDM_ANALOG_HANGUP_POLARITY_REVERSE)) { + ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG, + "Ignoring polarity reversal because this channel is not configured for it\n"); + break; + } + if (event->channel->state == FTDM_CHANNEL_STATE_DOWN) { + ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG, + "Ignoring polarity reversal because this channel is down\n"); + break; + } + /* we have a good channel, set the polarity flag and let the channel thread deal with it */ + ftdm_set_sflag(event->channel, AF_POLARITY_REVERSE); + } + break; default: { ftdm_log_chan(event->channel, FTDM_LOG_DEBUG, "Ignoring event [%s] in state [%s]\n", ftdm_oob_event2str(event->enum_id), ftdm_channel_state2str(event->channel->state)); diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c index 886c4a8fec..31c2421b9b 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c +++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c @@ -355,7 +355,6 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) break; } } else { - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE); ftdm_channel_complete_state(ftdmchan); indicate = 0; @@ -467,7 +466,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) dtmf_offset = strlen(dtmf); last_digit = elapsed; sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT; - sig.raw_data = dtmf; + ftdm_set_string(sig.ev_data.collected.digits, dtmf); if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) { collecting = 0; } diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c index 68f0e9e5a4..8be6d579e1 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c @@ -497,7 +497,7 @@ static ftdm_state_map_t isdn_state_map = { * \param ftdmchan Channel to handle * \note This function MUST be called with the channel locked */ -static __inline__ void state_advance(ftdm_channel_t *chan) +static ftdm_status_t state_advance(ftdm_channel_t *chan) { ftdm_libpri_data_t *isdn_data = chan->span->signal_data; q931_call *call = (q931_call *)chan->call_data; @@ -511,27 +511,23 @@ static __inline__ void state_advance(ftdm_channel_t *chan) sig.chan_id = ftdm_channel_get_id(chan); sig.span_id = ftdm_channel_get_span_id(chan); sig.channel = chan; + + ftdm_channel_complete_state(chan); switch (ftdm_channel_get_state(chan)) { case FTDM_CHANNEL_STATE_DOWN: { + ftdm_channel_t *chtmp = chan; chan->call_data = NULL; - ftdm_channel_done(chan); - /* - * Close channel completely, BRI PTMP will thank us - */ - if (ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) { - ftdm_channel_t *chtmp = chan; - if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n", - ftdm_channel_get_span_id(chan), - ftdm_channel_get_id(chan)); - } else { - ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n", - ftdm_channel_get_span_id(chan), - ftdm_channel_get_id(chan)); - } + if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n", + ftdm_channel_get_span_id(chan), + ftdm_channel_get_id(chan)); + } else { + ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n", + ftdm_channel_get_span_id(chan), + ftdm_channel_get_id(chan)); } } break; @@ -631,7 +627,7 @@ static __inline__ void state_advance(ftdm_channel_t *chan) ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan)); /* TODO: set hangup cause? */ ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART); - return; + return FTDM_SUCCESS; } ton = caller_data->dnis.type; @@ -714,6 +710,7 @@ static __inline__ void state_advance(ftdm_channel_t *chan) default: break; } + return FTDM_SUCCESS; } /** @@ -729,13 +726,8 @@ static __inline__ void check_state(ftdm_span_t *span) for (j = 1; j <= ftdm_span_get_chan_count(span); j++) { ftdm_channel_t *chan = ftdm_span_get_channel(span, j); - ftdm_channel_lock(chan); - while (ftdm_test_flag(chan, FTDM_CHANNEL_STATE_CHANGE)) { - ftdm_clear_flag(chan, FTDM_CHANNEL_STATE_CHANGE); - state_advance(chan); - ftdm_channel_complete_state(chan); - } + ftdm_channel_advance_states(chan); ftdm_channel_unlock(chan); } } @@ -1403,8 +1395,7 @@ static int on_dchan_up(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_ev sig.chan_id = ftdm_channel_get_id(chan); sig.channel = chan; sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sig.raw_data = &status; - + sig.ev_data.sigstatus.status = status; ftdm_span_send_signal(span, &sig); } } @@ -1440,7 +1431,7 @@ static int on_dchan_down(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_ sig.chan_id = ftdm_channel_get_id(chan); sig.channel = chan; sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sig.raw_data = &status; + sig.ev_data.sigstatus.status = status; ftdm_span_send_signal(span, &sig); } @@ -1917,6 +1908,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span) span->outgoing_call = isdn_outgoing_call; span->state_map = &isdn_state_map; + span->state_processor = state_advance; span->get_channel_sig_status = isdn_get_channel_sig_status; span->get_span_sig_status = isdn_get_span_sig_status; diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c b/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c index fbe6ca0822..bfb67e4c78 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c @@ -127,9 +127,8 @@ static int __pri_lpwrap_read(struct pri *pri, void *buf, int buflen) } else { ftdm_log(FTDM_LOG_CRIT, "span %d D-READ TIMEOUT\n", spri->span->span_id); } - - ftdm_clear_flag(spri, LPWRAP_PRI_READY); - return -1; + /* we cannot return -1, libpri seems to expect values >= 0 */ + return 0; } spri->errs = 0; res = (int)len; @@ -156,8 +155,8 @@ static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen) if (ftdm_channel_write(spri->dchan, buf, buflen, &len) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "span %d D-WRITE FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error); - ftdm_clear_flag(spri, LPWRAP_PRI_READY); - return -1; + /* we cannot return -1, libpri seems to expect values >= 0 */ + return 0; } #ifdef IODEBUG diff --git a/libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c b/libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c index 27fbe2139f..48a2f012eb 100644 --- a/libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c +++ b/libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c @@ -265,7 +265,7 @@ static ftdm_state_map_t pritap_state_map = { } }; -static __inline__ void state_advance(ftdm_channel_t *ftdmchan) +static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan) { ftdm_status_t status; ftdm_sigmsg_t sig; @@ -278,6 +278,8 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) sig.span_id = ftdmchan->span_id; sig.channel = ftdmchan; + ftdm_channel_complete_state(ftdmchan); + switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_DOWN: { @@ -321,24 +323,20 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) break; } - return; + return FTDM_SUCCESS; } static __inline__ void pritap_check_state(ftdm_span_t *span) { - if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) { - uint32_t j; - ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE); - for(j = 1; j <= span->chan_count; j++) { - if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) { - ftdm_mutex_lock(span->channels[j]->mutex); - ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE); - state_advance(span->channels[j]); - ftdm_channel_complete_state(span->channels[j]); - ftdm_mutex_unlock(span->channels[j]->mutex); - } - } - } + if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) { + uint32_t j; + ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE); + for(j = 1; j <= span->chan_count; j++) { + ftdm_mutex_lock(span->channels[j]->mutex); + ftdm_channel_advance_states(span->channels[j]); + ftdm_mutex_unlock(span->channels[j]->mutex); + } + } } static int pri_io_read(struct pri *pri, void *buf, int buflen) @@ -896,6 +894,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_pritap_configure_span) span->get_span_sig_status = pritap_get_span_sig_status; span->state_map = &pritap_state_map; + span->state_processor = state_advance; return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 14eca429e8..79850a3c1f 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -33,6 +33,7 @@ * Contributors: * * Arnaldo Pereira + * Ricardo Barroetaveña * */ @@ -49,10 +50,6 @@ #include "freetdm.h" #include "private/ftdm_core.h" -/* debug thread count for r2 legs */ -static ftdm_mutex_t* g_thread_count_mutex; -static int32_t g_thread_count = 0; - typedef int openr2_call_status_t; /* when the user stops a span, we clear FTDM_R2_SPAN_STARTED, so that the signaling thread @@ -76,7 +73,6 @@ typedef struct ftdm_r2_call_t { int disconnect_rcvd:1; int ftdm_call_started:1; int protocol_error:1; - ftdm_channel_state_t chanstate; ftdm_size_t dnis_index; ftdm_size_t ani_index; char logname[255]; @@ -171,8 +167,7 @@ static ftdm_hash_t *g_mod_data_hash; /* IO interface for the command API */ static ftdm_io_interface_t g_ftdm_r2_interface; -static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan); -static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan); +static ftdm_status_t ftdm_r2_state_advance(ftdm_channel_t *ftdmchan); /* whether R2 call accept process is pending */ #define IS_ACCEPTING_PENDING(ftdmchan) \ @@ -352,7 +347,6 @@ static void ft_r2_clean_call(ftdm_r2_call_t *call) call->disconnect_rcvd = 0; call->ftdm_call_started = 0; call->protocol_error = 0; - call->chanstate = FTDM_CHANNEL_STATE_DOWN; call->dnis_index = 0; call->ani_index = 0; call->name[0] = 0; @@ -380,11 +374,72 @@ static void ft_r2_answer_call(ftdm_channel_t *ftdmchan) R2CALL(ftdmchan)->answer_pending = 0; } +static __inline__ ftdm_calling_party_category_t ftdm_openr2_cpc_to_r2_ftdm_cpc(openr2_calling_party_category_t cpc) +{ + switch (cpc) { + case OR2_CALLING_PARTY_CATEGORY_UNKNOWN: + return FTDM_CPC_UNKNOWN; + + case OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER: + return FTDM_CPC_ORDINARY; + + case OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER: + return FTDM_CPC_PRIORITY; + + case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_SUBSCRIBER: + return FTDM_CPC_UNKNOWN; + + case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_PRIORITY_SUBSCRIBER: + return FTDM_CPC_UNKNOWN; + + case OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT: + return FTDM_CPC_TEST; + + case OR2_CALLING_PARTY_CATEGORY_PAY_PHONE: + return FTDM_CPC_PAYPHONE; + + case OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL: + return FTDM_CPC_OPERATOR; + } + return FTDM_CPC_INVALID; +} + +static __inline openr2_calling_party_category_t ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdm_calling_party_category_t cpc) +{ + switch (cpc) { + case FTDM_CPC_UNKNOWN: + return OR2_CALLING_PARTY_CATEGORY_UNKNOWN; + + case FTDM_CPC_OPERATOR: + return OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL; + + case FTDM_CPC_ORDINARY: + return OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER; + + case FTDM_CPC_PRIORITY: + return OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER; + + case FTDM_CPC_DATA: + return OR2_CALLING_PARTY_CATEGORY_UNKNOWN; + + case FTDM_CPC_TEST: + return OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT; + + case FTDM_CPC_PAYPHONE: + return OR2_CALLING_PARTY_CATEGORY_PAY_PHONE; + + case FTDM_CPC_INVALID: + return OR2_CALLING_PARTY_CATEGORY_UNKNOWN; + } + return OR2_CALLING_PARTY_CATEGORY_UNKNOWN; +} + /* this function must be called with the chan mutex held! */ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) { openr2_call_status_t callstatus; ftdm_r2_data_t *r2data; + openr2_calling_party_category_t category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER; r2data = ftdmchan->span->signal_data; @@ -397,6 +452,12 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) ft_r2_clean_call(ftdmchan->call_data); + if (ftdmchan->caller_data.cpc == FTDM_CPC_INVALID || ftdmchan->caller_data.cpc == FTDM_CPC_UNKNOWN) { + category = r2data->category; + } else { + category = ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdmchan->caller_data.cpc); + } + /* start io dump */ if (r2data->mf_dump_size) { ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_INPUT_DUMP, &r2data->mf_dump_size); @@ -404,9 +465,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) } callstatus = openr2_chan_make_call(R2CALL(ftdmchan)->r2chan, - ftdmchan->caller_data.cid_num.digits, + ftdmchan->caller_data.cid_num.digits, ftdmchan->caller_data.dnis.digits, - r2data->category); + category, + ftdmchan->caller_data.pres == FTDM_PRES_ALLOWED ? 0 : 1); if (callstatus) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to make call in R2 channel, openr2_chan_make_call failed\n"); @@ -414,7 +476,6 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) } R2CALL(ftdmchan)->ftdm_call_started = 1; - R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING); ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS); @@ -456,19 +517,40 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_channel_sig_status) static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_channel_sig_status) { openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan; + openr2_cas_signal_t rxcas, txcas; + + /* get the current rx and tx cas bits */ + openr2_chan_get_cas(r2chan, &rxcas, &txcas); + + /* if we're already in the state the user asks us to be, we have nothing to do */ + if (status == FTDM_SIG_STATE_SUSPENDED && txcas == OR2_CAS_BLOCK) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in BLOCK state\n"); + return FTDM_SUCCESS; + } + if (status == FTDM_SIG_STATE_UP && txcas == OR2_CAS_IDLE) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in IDLE state\n"); + return FTDM_SUCCESS; + } + + /* set the signaling as requested and send SIGEVENT_SIGSTATUS_CHANGED, if applicable. + * see docs/sigstatus.txt for details */ switch(status) { - case FTDM_SIG_STATE_DOWN: case FTDM_SIG_STATE_SUSPENDED: openr2_chan_set_blocked(r2chan); + if (rxcas == OR2_CAS_IDLE) { + ftdm_r2_set_chan_sig_status(ftdmchan, status); + } break; case FTDM_SIG_STATE_UP: openr2_chan_set_idle(r2chan); + if (rxcas == OR2_CAS_IDLE) { + ftdm_r2_set_chan_sig_status(ftdmchan, status); + } break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status); return FTDM_FAIL; } - ftdm_r2_set_chan_sig_status(ftdmchan, status); return FTDM_SUCCESS; } @@ -484,10 +566,13 @@ static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_span_sig_status) *status = FTDM_SIG_STATE_SUSPENDED; for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) { ftdm_channel_t *fchan = ftdm_iterator_current(citer); + ftdm_channel_lock(fchan); if (ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP)) { *status = FTDM_SIG_STATE_UP; + ftdm_channel_unlock(fchan); break; } + ftdm_channel_unlock(fchan); } ftdm_iterator_free(chaniter); return FTDM_SUCCESS; @@ -497,21 +582,6 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status) { ftdm_iterator_t *chaniter = NULL; ftdm_iterator_t *citer = NULL; - uint32_t span_opr = -1; - - /* we either set the channels to BLOCK or IDLE */ - switch(status) { - case FTDM_SIG_STATE_DOWN: - case FTDM_SIG_STATE_SUSPENDED: - span_opr = 0; - break; - case FTDM_SIG_STATE_UP: - span_opr = 1; - break; - default: - ftdm_log(FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status); - return FTDM_FAIL; - } chaniter = ftdm_span_get_chan_iterator(span, NULL); if (!chaniter) { @@ -521,15 +591,13 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status) /* iterate over all channels, setting them to the requested state */ for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) { ftdm_channel_t *fchan = ftdm_iterator_current(citer); - openr2_chan_t *r2chan = R2CALL(fchan)->r2chan; - if (span_opr == 0) { - openr2_chan_set_blocked(r2chan); - ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel blocked\n"); - } else { - openr2_chan_set_idle(r2chan); - ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel idle\n"); + /* we set channel's state through ftdm_r2_set_channel_sig_status(), since it already takes + * care of notifying the user when appropriate */ + ftdm_channel_lock(fchan); + if ((ftdm_r2_set_channel_sig_status(fchan, status)) != FTDM_SUCCESS) { + ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to set signaling status to %s\n", ftdm_signaling_status2str(status)); } - ftdm_r2_set_chan_sig_status(fchan, status); + ftdm_channel_unlock(fchan); } ftdm_iterator_free(chaniter); return FTDM_SUCCESS; @@ -552,7 +620,7 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan) ftdm_sched_cancel_timer(r2data->sched, r2call->protocol_error_recovery_timer); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Cancelled protocol error recovery timer\n"); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - ftdm_r2_state_advance_all(ftdmchan); + ftdm_channel_advance_states(ftdmchan); } } @@ -586,7 +654,6 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan) ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_OUTPUT_DUMP, &r2data->mf_dump_size); } - R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS); ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLUSH_TX_BUFFERS, NULL); @@ -595,12 +662,14 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan) static void dump_mf(openr2_chan_t *r2chan); /* only called for incoming calls when the ANI, DNIS etc is complete and the user has to decide either to accept or reject the call */ -static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category) +static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, + openr2_calling_party_category_t category, int ani_restricted) { ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); ftdm_r2_data_t *r2data = ftdmchan->span->signal_data; - ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = (%d)\n", ani, dnis, category); + ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = %d, ANI restricted = %s\n", + ani, dnis, category, ani_restricted ? "Yes" : "No"); /* nothing went wrong during call setup, MF has ended, we can and must disable the MF dump */ if (r2data->mf_dump_size) { @@ -615,6 +684,8 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons } else { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); } + ftdmchan->caller_data.cpc = ftdm_openr2_cpc_to_r2_ftdm_cpc(category); + ftdmchan->caller_data.pres = ani_restricted ? FTDM_PRES_RESTRICTED : FTDM_PRES_ALLOWED; } /* @@ -632,12 +703,10 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons static void clear_accept_pending(ftdm_channel_t *fchan) { if (IS_ACCEPTING_PENDING(fchan)) { - ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE); ftdm_channel_complete_state(fchan); } else if (ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE)) { ftdm_log_chan(fchan, FTDM_LOG_CRIT, "State change flag set in state %s, last state = %s\n", ftdm_channel_state2str(fchan->state), ftdm_channel_state2str(fchan->last_state)); - ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE); ftdm_channel_complete_state(fchan); } } @@ -745,7 +814,7 @@ static void ftdm_r2_on_call_end(openr2_chan_t *r2chan) ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); /* in some circumstances openr2 can call on_call_init right after this, so let's advance the state right here */ - ftdm_r2_state_advance_all(ftdmchan); + ftdm_channel_advance_states(ftdmchan); } static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen) @@ -777,7 +846,7 @@ static void ftdm_r2_recover_from_protocol_error(void *data) goto done; } ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - ftdm_r2_state_advance_all(ftdmchan); + ftdm_channel_advance_states(ftdmchan); done: ftdm_channel_unlock(ftdmchan); } @@ -1158,6 +1227,18 @@ static openr2_log_level_t ftdm_r2_loglevel_from_string(const char *level) static ftdm_state_map_t r2_state_map = { { + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_ANY_STATE, FTDM_END}, + {FTDM_CHANNEL_STATE_RESET, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_RESET, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END} + }, { ZSD_INBOUND, ZSM_UNACCEPTABLE, @@ -1209,6 +1290,20 @@ static ftdm_state_map_t r2_state_map = { /* Outbound states */ + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_ANY_STATE, FTDM_END}, + {FTDM_CHANNEL_STATE_RESET, FTDM_END} + }, + + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_RESET, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END} + }, + { ZSD_OUTBOUND, ZSM_UNACCEPTABLE, @@ -1515,10 +1610,14 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling) span->set_channel_sig_status = ftdm_r2_set_channel_sig_status; span->state_map = &r2_state_map; + span->state_processor = ftdm_r2_state_advance; /* use signals queue */ ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE); + /* we can skip states (going straight from RING to UP) */ + ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES); + /* setup the scheduler */ snprintf(schedname, sizeof(schedname), "ftmod_r2_%s", span->name); ftdm_assert(ftdm_sched_create(&r2data->sched, schedname) == FTDM_SUCCESS, "Failed to create schedule!\n"); @@ -1541,10 +1640,10 @@ fail: } /* the channel must be locked when calling this function */ -static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) +static ftdm_status_t ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) { ftdm_sigmsg_t sigev; - int ret; + ftdm_status_t ret; ftdm_r2_call_t *r2call = R2CALL(ftdmchan); openr2_chan_t *r2chan = r2call->r2chan; ftdm_r2_data_t *r2data = ftdmchan->span->signal_data; @@ -1554,172 +1653,173 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) sigev.span_id = ftdmchan->span_id; sigev.channel = ftdmchan; - ret = 0; + ret = FTDM_SUCCESS; - /* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept - * procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this - * function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting - * to complete (the processing is media-bound) - * */ - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) - && (r2call->chanstate != ftdmchan->state)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state)); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state)); - r2call->chanstate = ftdmchan->state; - - if (IS_ACCEPTING_PENDING(ftdmchan)) { - /* - Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting - the call in R2 means sending a tone, then waiting for the acknowledge from the other end, - since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100) - which means during that time the user should not try to perform any operations like answer, hangup or anything - else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block - the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag, - otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first, - if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */ - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state)); - } else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){ - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); - ftdm_channel_complete_state(ftdmchan); - } - - switch (ftdmchan->state) { - - /* starting an incoming call */ - case FTDM_CHANNEL_STATE_COLLECT: - { - uint32_t interval = 0; - ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval); - ftdm_assert(interval != 0, "Invalid interval!"); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval); - openr2_chan_enable_read(r2chan); - } - break; - - /* starting an outgoing call */ - case FTDM_CHANNEL_STATE_DIALING: - { - uint32_t interval = 0; - ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval); - ftdm_assert(interval != 0, "Invalid interval!"); - ftdm_log_chan(ftdmchan, - FTDM_LOG_DEBUG, "Starting processing of outgoing call in channel with interval %d\n", interval); - openr2_chan_enable_read(r2chan); - } - break; - - /* incoming call was offered */ - case FTDM_CHANNEL_STATE_RING: - - /* notify the user about the new call */ - sigev.event_id = FTDM_SIGEVENT_START; - - ftdm_span_send_signal(ftdmchan->span, &sigev); - r2call->ftdm_call_started = 1; - - break; - - /* the call is making progress */ - case FTDM_CHANNEL_STATE_PROGRESS: - case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: - { - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - if (!r2call->accepted) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n"); - ft_r2_accept_call(ftdmchan); - } - } else { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n"); - sigev.event_id = FTDM_SIGEVENT_PROCEED; - ftdm_span_send_signal(ftdmchan->span, &sigev); - - sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA; - ftdm_span_send_signal(ftdmchan->span, &sigev); - } - } - break; - - /* the call was answered */ - case FTDM_CHANNEL_STATE_UP: - { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n"); - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - if (!r2call->accepted) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n"); - // the answering will be done in the on_call_accepted handler - ft_r2_accept_call(ftdmchan); - r2call->answer_pending = 1; - } else { - ft_r2_answer_call(ftdmchan); - } - } else { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n"); - sigev.event_id = FTDM_SIGEVENT_UP; - ftdm_span_send_signal(ftdmchan->span, &sigev); - } - } - break; - - /* just got hangup */ - case FTDM_CHANNEL_STATE_HANGUP: - { - if (!r2call->disconnect_rcvd) { - openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause)); - /* this will disconnect the call, but need to wait for the call end before moving to DOWN */ - openr2_chan_disconnect_call(r2chan, disconnect_cause); - } else if (!r2call->protocol_error) { - /* just ack the hangup, on_call_end will be called by openr2 right after */ - openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING); - } else { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n"); - /* do not set to down yet, give some time for recovery */ - ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100, - ftdm_r2_recover_from_protocol_error, r2chan, &r2call->protocol_error_recovery_timer); - } - } - break; - - case FTDM_CHANNEL_STATE_TERMINATING: - { - /* if the call has not been started yet we must go to HANGUP right here */ - if (!r2call->ftdm_call_started) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); - } else { - openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause)); - /* notify the user of the call terminating and we wait for the user to move us to hangup */ - sigev.event_id = FTDM_SIGEVENT_STOP; - ftdm_span_send_signal(ftdmchan->span, &sigev); - } - } - break; - - /* finished call for good */ - case FTDM_CHANNEL_STATE_DOWN: - { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n"); - ret = 1; - } - break; - - /* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */ - case FTDM_CHANNEL_STATE_RINGING: - { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n"); - } - break; - - default: - { - ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state)); - } - break; - - } + if (IS_ACCEPTING_PENDING(ftdmchan)) { + /* + Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting + the call in R2 means sending a tone, then waiting for the acknowledge from the other end, + since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100) + which means during that time the user should not try to perform any operations like answer, hangup or anything + else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block + the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag, + otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first, + if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state)); + } else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){ + ftdm_channel_complete_state(ftdmchan); } - if (ret) { + switch (ftdmchan->state) { + + /* starting an incoming call */ + case FTDM_CHANNEL_STATE_COLLECT: + { + uint32_t interval = 0; + ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval); + ftdm_assert(interval != 0, "Invalid interval!"); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval); + openr2_chan_enable_read(r2chan); + } + break; + + /* starting an outgoing call */ + case FTDM_CHANNEL_STATE_DIALING: + { + uint32_t interval = 0; + ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval); + ftdm_assert(interval != 0, "Invalid interval!"); + ftdm_log_chan(ftdmchan, + FTDM_LOG_DEBUG, "Starting processing of outgoing call in channel with interval %d\n", interval); + openr2_chan_enable_read(r2chan); + } + break; + + /* incoming call was offered */ + case FTDM_CHANNEL_STATE_RING: + + /* notify the user about the new call */ + sigev.event_id = FTDM_SIGEVENT_START; + + ftdm_span_send_signal(ftdmchan->span, &sigev); + r2call->ftdm_call_started = 1; + + break; + + /* the call is making progress */ + case FTDM_CHANNEL_STATE_PROGRESS: + case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: + { + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + if (!r2call->accepted) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n"); + ft_r2_accept_call(ftdmchan); + } + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n"); + sigev.event_id = FTDM_SIGEVENT_PROCEED; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA; + ftdm_span_send_signal(ftdmchan->span, &sigev); + } + } + break; + + /* the call was answered */ + case FTDM_CHANNEL_STATE_UP: + { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n"); + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + if (!r2call->accepted) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n"); + // the answering will be done in the on_call_accepted handler + ft_r2_accept_call(ftdmchan); + r2call->answer_pending = 1; + } else { + ft_r2_answer_call(ftdmchan); + } + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n"); + sigev.event_id = FTDM_SIGEVENT_UP; + ftdm_span_send_signal(ftdmchan->span, &sigev); + } + } + break; + + /* just got hangup */ + case FTDM_CHANNEL_STATE_HANGUP: + { + if (!r2call->disconnect_rcvd) { + openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause)); + /* this will disconnect the call, but need to wait for the call end before moving to DOWN */ + openr2_chan_disconnect_call(r2chan, disconnect_cause); + } else if (!r2call->protocol_error) { + /* just ack the hangup, on_call_end will be called by openr2 right after */ + openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING); + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n"); + /* do not set to down yet, give some time for recovery */ + ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100, + ftdm_r2_recover_from_protocol_error, r2chan, &r2call->protocol_error_recovery_timer); + } + } + break; + + case FTDM_CHANNEL_STATE_TERMINATING: + { + /* if the call has not been started yet we must go to HANGUP right here */ + if (!r2call->ftdm_call_started) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); + } else { + openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause)); + /* notify the user of the call terminating and we wait for the user to move us to hangup */ + sigev.event_id = FTDM_SIGEVENT_STOP; + ftdm_span_send_signal(ftdmchan->span, &sigev); + } + } + break; + + /* finished call for good */ + case FTDM_CHANNEL_STATE_DOWN: + { + if (ftdmchan->last_state != FTDM_CHANNEL_STATE_RESET) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n"); + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Reset Complete\n"); + } + ret = FTDM_BREAK; + } + break; + + /* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */ + case FTDM_CHANNEL_STATE_RINGING: + { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n"); + } + break; + + /* put the r2 channel back to IDLE, close ftdmchan and set it's state as DOWN */ + case FTDM_CHANNEL_STATE_RESET: + { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RESET indicated, putting the R2 channel back to IDLE\n"); + openr2_chan_set_idle(r2chan); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + } + break; + + default: + { + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state)); + } + break; + } + + if (ret == FTDM_BREAK) { ftdm_channel_t *closed_chan; closed_chan = ftdmchan; ftdm_channel_close(&closed_chan); @@ -1728,20 +1828,6 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) return ret; } -/* the channel must be locked when calling this function */ -static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan) -{ - /* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept - * procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this - * function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting - * to complete (the processing is media-bound) - * */ - while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) - && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) { - ftdm_r2_state_advance(ftdmchan); - } -} - static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) { openr2_chan_t *r2chan = NULL; @@ -1776,10 +1862,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) } for (i = 1, citer = chaniter; citer; citer = ftdm_iterator_next(citer), i++) { ftdmchan = ftdm_iterator_current(citer); + ftdm_channel_lock(ftdmchan); r2chan = R2CALL(ftdmchan)->r2chan; openr2_chan_set_span_id(r2chan, span->span_id); openr2_chan_set_idle(r2chan); openr2_chan_process_cas_signaling(r2chan); + ftdm_channel_unlock(ftdmchan); ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &txqueue_size); } @@ -1861,7 +1949,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) for ( ; citer; citer = ftdm_iterator_next(citer)) { ftdmchan = ftdm_iterator_current(citer); - ftdm_mutex_lock(ftdmchan->mutex); + ftdm_channel_lock(ftdmchan); call = R2CALL(ftdmchan); @@ -1870,12 +1958,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED); - ftdm_r2_state_advance_all(ftdmchan); + ftdm_channel_advance_states(ftdmchan); r2chan = call->r2chan; openr2_chan_process_signaling(r2chan); - ftdm_r2_state_advance_all(ftdmchan); + ftdm_channel_advance_states(ftdmchan); if (!call->accepted) { /* if the call is not accepted we do not want users reading */ @@ -1883,7 +1971,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) ftdm_set_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED); } - ftdm_mutex_unlock(ftdmchan->mutex); + ftdm_channel_unlock(ftdmchan); } } @@ -1891,8 +1979,10 @@ done: citer = ftdm_span_get_chan_iterator(span, chaniter); for ( ; citer; citer = ftdm_iterator_next(citer)) { ftdmchan = ftdm_iterator_current(citer); + ftdm_channel_lock(ftdmchan); r2chan = R2CALL(ftdmchan)->r2chan; openr2_chan_set_blocked(r2chan); + ftdm_channel_unlock(ftdmchan); } ftdm_iterator_free(chaniter); @@ -1947,6 +2037,14 @@ static void __inline__ unblock_channel(ftdm_channel_t *fchan, ftdm_stream_handle ftdm_mutex_unlock(fchan->mutex); } +#define FT_SYNTAX "USAGE:\n" \ +"--------------------------------------------------------------------------------\n" \ +"ftdm r2 status \n" \ +"ftdm r2 loopstats \n" \ +"ftdm r2 block|unblock []\n" \ +"ftdm r2 version\n" \ +"ftdm r2 variants\n" \ +"--------------------------------------------------------------------------------\n" static FIO_API_FUNCTION(ftdm_r2_api) { ftdm_span_t *span = NULL; @@ -2130,14 +2228,6 @@ static FIO_API_FUNCTION(ftdm_r2_api) } if (argc == 1) { - if (!strcasecmp(argv[0], "threads")) { - ftdm_mutex_lock(g_thread_count_mutex); - stream->write_function(stream, "%d R2 channel threads up\n", g_thread_count); - ftdm_mutex_unlock(g_thread_count_mutex); - stream->write_function(stream, "+OK.\n"); - goto done; - } - if (!strcasecmp(argv[0], "version")) { stream->write_function(stream, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision()); stream->write_function(stream, "+OK.\n"); @@ -2163,7 +2253,7 @@ static FIO_API_FUNCTION(ftdm_r2_api) } } - stream->write_function(stream, "-ERR invalid command.\n"); + stream->write_function(stream, "%s", FT_SYNTAX); done: @@ -2192,7 +2282,6 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_r2_init) if (!g_mod_data_hash) { return FTDM_FAIL; } - ftdm_mutex_create(&g_thread_count_mutex); return FTDM_SUCCESS; } @@ -2212,7 +2301,6 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy) } } hashtable_destroy(g_mod_data_hash); - ftdm_mutex_destroy(&g_thread_count_mutex); return FTDM_SUCCESS; } 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 f59b3b8c4f..d0bc14c8d8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c @@ -951,7 +951,6 @@ static void handle_call_answer(ftdm_span_t *span, sangomabc_connection_t *mcon, } } -static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan); static __inline__ void stop_loop(ftdm_channel_t *ftdmchan); /** @@ -1002,7 +1001,7 @@ tryagain: } else if (ftdmchan->state == FTDM_CHANNEL_STATE_IN_LOOP && retry) { retry = 0; stop_loop(ftdmchan); - advance_chan_states(ftdmchan); + ftdm_channel_advance_states(ftdmchan); goto tryagain; } else { ftdm_log(FTDM_LOG_ERROR, "s%dc%d: rejecting incoming call in channel state %s\n", @@ -1267,7 +1266,7 @@ static ftdm_channel_t* event_process_states(ftdm_span_t *span, sangomabc_short_e } ftdm_mutex_lock(ftdmchan->mutex); - advance_chan_states(ftdmchan); + ftdm_channel_advance_states(ftdmchan); return ftdmchan; } @@ -1354,11 +1353,11 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon, } if(ftdmchan != NULL) { - advance_chan_states(ftdmchan); + ftdm_channel_advance_states(ftdmchan); ftdm_mutex_unlock(ftdmchan->mutex); } - return 0; + return 0; } @@ -1366,7 +1365,7 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon, * \brief Handler for channel state change * \param ftdmchan Channel to handle */ -static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan) +static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan) { ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data; sangomabc_connection_t *mcon = &sangoma_boost_data->mcon; @@ -1374,12 +1373,6 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan) ftdm_status_t status; - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); - } else { - return FTDM_SUCCESS; - } - ftdm_assert_return(ftdmchan->last_state != ftdmchan->state, FTDM_FAIL, "Channel state already processed\n"); ftdm_log(FTDM_LOG_DEBUG, "%d:%d PROCESSING STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state)); @@ -1389,6 +1382,8 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan) sig.span_id = ftdmchan->span_id; sig.channel = ftdmchan; + ftdm_channel_complete_state(ftdmchan); + switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_DOWN: { @@ -1640,24 +1635,15 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan) default: break; } - ftdm_channel_complete_state(ftdmchan); return FTDM_SUCCESS; } -static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan) -{ - while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { - state_advance(ftdmchan); - } -} - /** * \brief Initialises outgoing requests array */ static __inline__ void init_outgoing_array(void) { memset(&OUTBOUND_REQUESTS, 0, sizeof(OUTBOUND_REQUESTS)); - } /** @@ -1685,7 +1671,7 @@ static __inline__ void check_state(ftdm_span_t *span) if (susp && span->channels[j]->state != FTDM_CHANNEL_STATE_DOWN) { ftdm_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART); } - state_advance(span->channels[j]); + ftdm_channel_advance_states(span->channels[j]); ftdm_mutex_unlock(span->channels[j]->mutex); } } @@ -1695,7 +1681,7 @@ static __inline__ void check_state(ftdm_span_t *span) * but without taking the chan out of the queue, so check th * flag before advancing the state */ ftdm_mutex_lock(ftdmchan->mutex); - state_advance(ftdmchan); + ftdm_channel_advance_states(ftdmchan); ftdm_mutex_unlock(ftdmchan->mutex); } } @@ -2478,7 +2464,7 @@ static BOOST_SIG_STATUS_CB_FUNCTION(ftdm_boost_sig_status_change) sig.span_id = ftdmchan->span_id; sig.channel = ftdmchan; sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sig.raw_data = &status; + sig.ev_data.sigstatus.status = status; ftdm_span_send_signal(ftdmchan->span, &sig); return; } @@ -2687,6 +2673,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span) span->get_span_sig_status = sangoma_boost_get_span_sig_status; span->set_span_sig_status = sangoma_boost_set_span_sig_status; span->state_map = &boost_state_map; + span->state_processor = state_advance; sangoma_boost_data->mcon.debuglevel = FTDM_LOG_LEVEL_DEBUG; sangoma_boost_data->pcon.debuglevel = FTDM_LOG_LEVEL_DEBUG; ftdm_clear_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c index 982dd4794d..6ddb74d253 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c @@ -31,6 +31,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define _GNU_SOURCE + #if HAVE_NETDB_H #include #endif diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj index e3930d8188..2e7fb82041 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj @@ -40,11 +40,12 @@ Disabled - C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories) + C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true @@ -95,10 +95,11 @@ Level3 EditAndContinue + MultiThreadedDebugDLL freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies) - $(OutDir);C:\Program Files\libsng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories) + $(OutDir);C:\Program Files\sangoma\sng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories) true Console false @@ -110,7 +111,7 @@ Disabled - C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories) + C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) @@ -119,6 +120,7 @@ Level3 ProgramDatabase + MultiThreadedDebugDLL freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies) @@ -135,11 +137,13 @@ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true EnableFastChecks - MultiThreadedDebugDLL + MultiThreadedDLL Level3 ProgramDatabase + C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories) + Disabled true @@ -147,23 +151,27 @@ true true MachineX86 + freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies) + $(OutDir);C:\Program Files\sangoma\sng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories) WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) EnableFastChecks - MultiThreadedDebugDLL + MultiThreadedDLL Level3 ProgramDatabase + C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories) true Windows true true + freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c index 8d619f8c3b..8d6472c054 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c @@ -46,10 +46,9 @@ static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span); static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span); ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event); -static void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftdmchan); static void ftdm_sangoma_isdn_poll_events(ftdm_span_t *span); static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event); -static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan); +static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan); static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event); static void ftdm_sangoma_isdn_wakeup_phy(ftdm_channel_t *dchan); static void ftdm_sangoma_isdn_dchan_set_queue_size(ftdm_channel_t *ftdmchan); @@ -270,13 +269,6 @@ ftdm_state_map_t sangoma_isdn_state_map = { } }; -static __inline__ void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftdmchan) -{ - while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { - ftdm_sangoma_isdn_process_state_change(ftdmchan); - } -} - static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event) { sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data; @@ -457,7 +449,7 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj) while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) { /* double check that this channel has a state change pending */ ftdm_channel_lock(ftdmchan); - ftdm_sangoma_isdn_advance_chan_states(ftdmchan); + ftdm_channel_advance_states(ftdmchan); ftdm_channel_unlock(ftdmchan); } @@ -470,11 +462,11 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj) /* twiddle */ break; case FTDM_FAIL: - ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned error!\n", span->name); + ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned error!\n", span->name); break; default: - ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned with unknown code\n", span->name); + ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned with unknown code\n", span->name); break; } @@ -536,7 +528,7 @@ ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisd break; } ftdm_channel_lock(ftdmchan); - ftdm_sangoma_isdn_advance_chan_states(ftdmchan); + ftdm_channel_advance_states(ftdmchan); return ftdmchan; } @@ -600,13 +592,14 @@ static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_ev sngisdn_process_rst_ind(sngisdn_event); break; } - if(ftdmchan != NULL) { - ftdm_sangoma_isdn_advance_chan_states(ftdmchan); + if (ftdmchan != NULL) { + ftdm_channel_advance_states(ftdmchan); ftdm_channel_unlock(ftdmchan); } } -static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) +/* this function is called with the channel already locked by the core */ +static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) { ftdm_sigmsg_t sigev; ftdm_channel_state_t initial_state; @@ -618,13 +611,12 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) sigev.span_id = ftdmchan->span_id; sigev.channel = ftdmchan; - /*first lock the channel*/ - ftdm_channel_lock(ftdmchan); - /*clear the state change flag...since we might be setting a new state*/ - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); + /* Acknowledge the state change */ + ftdm_channel_complete_state(ftdmchan); + #ifdef FTDM_DEBUG_CHAN_MEMORY if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) { - ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ)==0, "Failed to mprotect"); + ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ) == 0, "Failed to mprotect"); } #endif @@ -879,11 +871,10 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) } #ifdef FTDM_DEBUG_CHAN_MEMORY if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) { - ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE)==0, "Failed to mprotect"); + ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE) == 0, "Failed to mprotect"); } #endif - ftdm_channel_unlock(ftdmchan); - return; + return FTDM_SUCCESS; } static FIO_CHANNEL_SEND_MSG_FUNCTION(ftdm_sangoma_isdn_send_msg) @@ -1098,6 +1089,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config) span->get_span_sig_status = ftdm_sangoma_isdn_get_span_sig_status; span->set_span_sig_status = ftdm_sangoma_isdn_set_span_sig_status; span->state_map = &sangoma_isdn_state_map; + span->state_processor = ftdm_sangoma_isdn_process_state_change; ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE); ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE); ftdm_set_flag(span, FTDM_SPAN_USE_PROCEED_STATE); 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 e63ed16a77..37f5b42f9b 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 @@ -137,8 +137,9 @@ void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d ftdm_assert(raw_data, "Failed to malloc"); memcpy(raw_data, data, data_len); - sigev.raw_data = raw_data; - sigev.raw_data_len = data_len; + sigev.raw.data = raw_data; + sigev.raw.len = data_len; + sigev.raw.autofree = 1; ftdm_span_send_signal(signal_data->ftdm_span, &sigev); } @@ -250,8 +251,9 @@ void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d ftdm_assert(raw_data, "Failed to malloc"); memcpy(raw_data, data, data_len); - sigev.raw_data = raw_data; - sigev.raw_data_len = data_len; + sigev.raw.data = raw_data; + sigev.raw.len = data_len; + sigev.raw.autofree = 1; ftdm_span_send_signal(signal_data->ftdm_span, &sigev); } } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 05a325b913..9016771671 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -46,7 +46,6 @@ ftdm_sngss7_data_t g_ftdm_sngss7_data; /* PROTOTYPES *****************************************************************/ static void *ftdm_sangoma_ss7_run (ftdm_thread_t * me, void *obj); -void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan); static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_event); static ftdm_status_t ftdm_sangoma_ss7_stop (ftdm_span_t * span); @@ -308,9 +307,7 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) ftdm_mutex_lock(ftdmchan->mutex); /* process state changes for this channel until they are all done */ - while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { - ftdm_sangoma_ss7_process_state_change (ftdmchan); - } + ftdm_channel_advance_states(ftdmchan); /* unlock the channel */ ftdm_mutex_unlock (ftdmchan->mutex); @@ -403,9 +400,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev ftdm_mutex_lock(ftdmchan->mutex); /* while there's a state change present on this channel process it */ - while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { - ftdm_sangoma_ss7_process_state_change(ftdmchan); - } + ftdm_channel_advance_states(ftdmchan); /* figure out the type of event and send it to the right handler */ switch (sngss7_event->event_id) { @@ -468,9 +463,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev } /* switch (sngss7_event->event_id) */ /* while there's a state change present on this channel process it */ - while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { - ftdm_sangoma_ss7_process_state_change(ftdmchan); - } + ftdm_channel_advance_states(ftdmchan); /* unlock the channel */ ftdm_mutex_unlock(ftdmchan->mutex); @@ -479,7 +472,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev } /******************************************************************************/ -void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) +ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) { sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; sng_isup_inf_t *isup_intf = NULL; @@ -495,7 +488,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan, "ftmod_sangoma_ss7 processing state %s\n", ftdm_channel_state2str (ftdmchan->state)); /* clear the state change flag...since we might be setting a new state */ - ftdm_clear_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE); + ftdm_channel_complete_state(ftdmchan); /*check what state we are supposed to be in */ switch (ftdmchan->state) { @@ -1212,7 +1205,7 @@ suspend_goto_restart: /**************************************************************************/ }/*switch (ftdmchan->state) */ - return; + return FTDM_SUCCESS; } /******************************************************************************/ @@ -1476,6 +1469,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) span->get_channel_sig_status = ftdm_sangoma_ss7_get_sig_status; span->set_channel_sig_status = ftdm_sangoma_ss7_set_sig_status; span->state_map = &sangoma_ss7_state_map; + span->state_processor = ftdm_sangoma_ss7_process_state_change; span->signal_data = ss7_span_info; /* set the flag to indicate that this span uses channel state change queues */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index fe4b6f45c4..f28547f9fe 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -452,7 +452,7 @@ extern int cmbLinkSetId; /* PROTOTYPES *****************************************************************/ /* in ftmod_sangoma_ss7_main.c */ -void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan); +ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan); /* in ftmod_sangoma_ss7_logger.c */ void handle_sng_log(uint8_t level, char *fmt,...); diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj index b165ac82d3..40d0a73a5b 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj @@ -100,7 +100,7 @@ EditAndContinue - freetdm.lib;libsangoma.lib;%(AdditionalDependencies) + libsangoma.lib;%(AdditionalDependencies) $(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories) true Console @@ -127,7 +127,7 @@ ProgramDatabase - freetdm.lib;libsangoma.lib;%(AdditionalDependencies) + libsangoma.lib;%(AdditionalDependencies) $(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories) true Console @@ -148,7 +148,7 @@ ProgramDatabase - freetdm.lib;libsangoma.lib;%(AdditionalDependencies) + libsangoma.lib;%(AdditionalDependencies) $(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories) true Console @@ -174,7 +174,7 @@ ProgramDatabase - freetdm.lib;libsangoma.lib;%(AdditionalDependencies) + libsangoma.lib;%(AdditionalDependencies) $(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories) true Console diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index 2db4326847..2a203faf8d 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -784,17 +784,27 @@ static FIO_COMMAND_FUNCTION(wanpipe_command) err = sangoma_set_tx_queue_sz(ftdmchan->sockfd, &tdm_api, queue_size); } break; + case FTDM_COMMAND_SET_POLARITY: + { + ftdm_polarity_t polarity = FTDM_COMMAND_OBJ_INT; + err = sangoma_tdm_set_polarity(ftdmchan->sockfd, &tdm_api, polarity); + if (!err) { + ftdmchan->polarity = polarity; + } + } + break; default: err = FTDM_NOTIMPL; break; }; if (err) { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno)); + int myerrno = errno; + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Wanpipe failed to execute command %d: %s\n", command, strerror(myerrno)); + errno = myerrno; return err; } - return FTDM_SUCCESS; } @@ -1224,6 +1234,131 @@ static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms) return FTDM_SUCCESS; } +/** + * \brief Process an event in a channel and set it's OOB event id. The channel must be locked. + * \param fchan Channel in which event occured + * \param event_id Pointer where we save the OOB event id + * \param tdm_api Wanpipe tdm struct that contain the event + * \return FTDM_SUCCESS or FTDM_FAIL + */ +static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, wanpipe_tdm_api_t *tdm_api) +{ + switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type) { + case WP_API_EVENT_LINK_STATUS: + { + switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_link_status) { + case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED: + *event_id = FTDM_OOB_ALARM_CLEAR; + break; + default: + *event_id = FTDM_OOB_ALARM_TRAP; + break; + }; + } + break; + + case WP_API_EVENT_RXHOOK: + { + if (fchan->type == FTDM_CHAN_TYPE_FXS) { + *event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK; + if (*event_id == FTDM_OOB_OFFHOOK) { + if (ftdm_test_flag(fchan, FTDM_CHANNEL_FLASH)) { + ftdm_clear_flag(fchan, FTDM_CHANNEL_FLASH); + ftdm_clear_flag(fchan, FTDM_CHANNEL_WINK); + *event_id = FTDM_OOB_FLASH; + goto event; + } else { + ftdm_set_flag(fchan, FTDM_CHANNEL_WINK); + } + } else { + if (ftdm_test_flag(fchan, FTDM_CHANNEL_WINK)) { + ftdm_clear_flag(fchan, FTDM_CHANNEL_WINK); + ftdm_clear_flag(fchan, FTDM_CHANNEL_FLASH); + *event_id = FTDM_OOB_WINK; + goto event; + } else { + ftdm_set_flag(fchan, FTDM_CHANNEL_FLASH); + } + } + break; + } else { + ftdm_status_t status; + wanpipe_tdm_api_t onhook_tdm_api; + memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api)); + status = sangoma_tdm_txsig_onhook(fchan->sockfd, &onhook_tdm_api); + if (status) { + snprintf(fchan->last_error, sizeof(fchan->last_error), "ONHOOK Failed"); + return FTDM_FAIL; + } + *event_id = onhook_tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP; + } + } + break; + case WP_API_EVENT_RING_DETECT: + { + *event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP; + } + break; + /* + disabled this ones when configuring, we don't need them, do we? + case WP_API_EVENT_RING_TRIP_DETECT: + { + *event_id = tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK; + } + break; + */ + case WP_API_EVENT_RBS: + { + *event_id = FTDM_OOB_CAS_BITS_CHANGE; + fchan->rx_cas_bits = wanpipe_swap_bits(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits); + } + break; + case WP_API_EVENT_DTMF: + { + char tmp_dtmf[2] = { tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 }; + *event_id = FTDM_OOB_NOOP; + + if (tmp_dtmf[0] == 'f') { + ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]); + break; + } + + if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) { + ftdm_set_flag(fchan, FTDM_CHANNEL_MUTE); + } + + if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) { + ftdm_clear_flag(fchan, FTDM_CHANNEL_MUTE); + if (ftdm_test_flag(fchan, FTDM_CHANNEL_INUSE)) { + ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]); + ftdm_channel_queue_dtmf(fchan, tmp_dtmf); + } + } + } + break; + case WP_API_EVENT_ALARM: + { + ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api->wp_tdm_cmd.event.wp_api_event_alarm); + *event_id = FTDM_OOB_ALARM_TRAP; + } + break; + case WP_API_EVENT_POLARITY_REVERSE: + { + ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Got polarity reverse\n"); + *event_id = FTDM_OOB_POLARITY_REVERSE; + } + break; + default: + { + ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type); + *event_id = FTDM_OOB_INVALID; + } + break; + } +event: + return FTDM_SUCCESS; +} + /** * \brief Retrieves an event from a wanpipe channel * \param channel Channel to retrieve event from @@ -1237,8 +1372,9 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event) wanpipe_tdm_api_t tdm_api; ftdm_span_t *span = ftdmchan->span; - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) { ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT); + } memset(&tdm_api, 0, sizeof(tdm_api)); status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api); @@ -1249,115 +1385,11 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event) } ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type); - switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) { - - case WP_TDMAPI_EVENT_LINK_STATUS: - { - switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) { - case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED: - event_id = FTDM_OOB_ALARM_CLEAR; - break; - default: - event_id = FTDM_OOB_ALARM_TRAP; - break; - }; - } - break; - - case WP_TDMAPI_EVENT_RXHOOK: - { - if (ftdmchan->type == FTDM_CHAN_TYPE_FXS) { - event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK; - if (event_id == FTDM_OOB_OFFHOOK) { - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) { - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH); - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK); - event_id = FTDM_OOB_FLASH; - goto event; - } else { - ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_WINK); - } - } else { - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) { - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK); - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH); - event_id = FTDM_OOB_WINK; - goto event; - } else { - ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH); - } - } - break; - } else { - wanpipe_tdm_api_t onhook_tdm_api; - memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api)); - status = sangoma_tdm_txsig_onhook(ftdmchan->sockfd, &onhook_tdm_api); - if (status) { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed"); - return FTDM_FAIL; - } - event_id = onhook_tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP; - } - } - break; - case WP_TDMAPI_EVENT_RING_DETECT: - { - event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP; - } - break; - /* - disabled this ones when configuring, we don't need them, do we? - case WP_TDMAPI_EVENT_RING_TRIP_DETECT: - { - event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK; - } - break; - */ - case WP_TDMAPI_EVENT_RBS: - { - event_id = FTDM_OOB_CAS_BITS_CHANGE; - ftdmchan->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits); - } - break; - case WP_TDMAPI_EVENT_DTMF: - { - char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 }; - event_id = FTDM_OOB_NOOP; - - if (tmp_dtmf[0] == 'f') { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]); - break; - } - - if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) { - ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE); - } - - if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) { - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE); - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]); - ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf); - } - } - } - break; - case WP_TDMAPI_EVENT_ALARM: - { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm); - event_id = FTDM_OOB_ALARM_TRAP; - } - break; - default: - { - ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type); - event_id = FTDM_OOB_INVALID; - } - break; + if ((wanpipe_channel_process_event(ftdmchan, &event_id, &tdm_api)) != FTDM_SUCCESS) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n"); + return FTDM_FAIL; } -event: - ftdmchan->last_event_time = 0; span->event_header.e_type = FTDM_EVENT_OOB; span->event_header.enum_id = event_id; @@ -1419,114 +1451,15 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event) snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno)); return FTDM_FAIL; } - ftdm_log_chan(span->channels[i], FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type); - switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) { - case WP_TDMAPI_EVENT_LINK_STATUS: - { - switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) { - case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED: - event_id = FTDM_OOB_ALARM_CLEAR; - break; - default: - event_id = FTDM_OOB_ALARM_TRAP; - break; - }; - } - break; - - case WP_TDMAPI_EVENT_RXHOOK: - { - if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS) { - event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK; - if (event_id == FTDM_OOB_OFFHOOK) { - if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) { - ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH); - ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK); - event_id = FTDM_OOB_FLASH; - goto event; - } else { - ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_WINK); - } - } else { - if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) { - ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK); - ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH); - event_id = FTDM_OOB_WINK; - goto event; - } else { - ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH); - } - } - continue; - } else { - int err; - ftdm_channel_t *ftdmchan = span->channels[i]; - err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api); - if (err) { - snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "ONHOOK Failed"); - return FTDM_FAIL; - } - event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP; - } - } - break; - case WP_TDMAPI_EVENT_RING_DETECT: - { - event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP; - } - break; - /* - disabled this ones when configuring, we don't need them, do we? - case WP_TDMAPI_EVENT_RING_TRIP_DETECT: - { - event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK; - } - break; - */ - case WP_TDMAPI_EVENT_RBS: - { - event_id = FTDM_OOB_CAS_BITS_CHANGE; - span->channels[i]->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits); - } - break; - case WP_TDMAPI_EVENT_DTMF: - { - char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 }; - event_id = FTDM_OOB_NOOP; - - if (tmp_dtmf[0] == 'f') { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]); - break; - } - - if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) { - ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE); - } - - if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) { - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE); - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]); - ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf); - } - } - } - break; - case WP_TDMAPI_EVENT_ALARM: - { - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm); - event_id = FTDM_OOB_ALARM_TRAP; - } - break; - default: - { - ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type); - event_id = FTDM_OOB_INVALID; - } - break; + ftdm_channel_lock(ftdmchan); + if ((wanpipe_channel_process_event(ftdmchan, &event_id, &tdm_api)) != FTDM_SUCCESS) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process events from channel\n"); + ftdm_channel_unlock(ftdmchan); + return FTDM_FAIL; } + ftdm_channel_unlock(ftdmchan); event: @@ -1538,9 +1471,7 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event) return FTDM_SUCCESS; } } - return FTDM_FAIL; - } /** diff --git a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c index 211bf713b7..5b507bd0b9 100644 --- a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c +++ b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c @@ -52,42 +52,48 @@ static struct { float txgain; } zt_globals; +#if defined(__FreeBSD__) +typedef unsigned long ioctlcmd; +#else +typedef int ioctlcmd; +#endif + /** * \brief General IOCTL codes */ struct ioctl_codes { - int GET_BLOCKSIZE; - int SET_BLOCKSIZE; - int FLUSH; - int SYNC; - int GET_PARAMS; - int SET_PARAMS; - int HOOK; - int GETEVENT; - int IOMUX; - int SPANSTAT; - int MAINT; - int GETCONF; - int SETCONF; - int CONFLINK; - int CONFDIAG; - int GETGAINS; - int SETGAINS; - int SPANCONFIG; - int CHANCONFIG; - int SET_BUFINFO; - int GET_BUFINFO; - int AUDIOMODE; - int ECHOCANCEL; - int HDLCRAWMODE; - int HDLCFCSMODE; - int SPECIFY; - int SETLAW; - int SETLINEAR; - int GETCONFMUTE; - int ECHOTRAIN; - int SETTXBITS; - int GETRXBITS; + ioctlcmd GET_BLOCKSIZE; + ioctlcmd SET_BLOCKSIZE; + ioctlcmd FLUSH; + ioctlcmd SYNC; + ioctlcmd GET_PARAMS; + ioctlcmd SET_PARAMS; + ioctlcmd HOOK; + ioctlcmd GETEVENT; + ioctlcmd IOMUX; + ioctlcmd SPANSTAT; + ioctlcmd MAINT; + ioctlcmd GETCONF; + ioctlcmd SETCONF; + ioctlcmd CONFLINK; + ioctlcmd CONFDIAG; + ioctlcmd GETGAINS; + ioctlcmd SETGAINS; + ioctlcmd SPANCONFIG; + ioctlcmd CHANCONFIG; + ioctlcmd SET_BUFINFO; + ioctlcmd GET_BUFINFO; + ioctlcmd AUDIOMODE; + ioctlcmd ECHOCANCEL; + ioctlcmd HDLCRAWMODE; + ioctlcmd HDLCFCSMODE; + ioctlcmd SPECIFY; + ioctlcmd SETLAW; + ioctlcmd SETLINEAR; + ioctlcmd GETCONFMUTE; + ioctlcmd ECHOTRAIN; + ioctlcmd SETTXBITS; + ioctlcmd GETRXBITS; }; /** @@ -181,6 +187,7 @@ static ftdm_socket_t CONTROL_FD = ZT_INVALID_SOCKET; FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event); FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event); +FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event); /** * \brief Initialises codec, and rx/tx gains @@ -985,6 +992,124 @@ FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event) return k ? FTDM_SUCCESS : FTDM_FAIL; } +/** + * \brief Process an event from a ftdmchan and set the proper OOB event_id. The channel must be locked. + * \param fchan Channel to retrieve event from + * \param event_id Pointer to OOB event id + * \param zt_event_id Zaptel event id + * \return FTDM_SUCCESS or FTDM_FAIL + */ +static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, zt_event_t zt_event_id) +{ + switch(zt_event_id) { + case ZT_EVENT_RINGEROFF: + { + return FTDM_FAIL; + } + break; + case ZT_EVENT_RINGERON: + { + return FTDM_FAIL; + } + break; + case ZT_EVENT_RINGBEGIN: + { + *event_id = FTDM_OOB_RING_START; + } + break; + case ZT_EVENT_ONHOOK: + { + *event_id = FTDM_OOB_ONHOOK; + } + break; + case ZT_EVENT_WINKFLASH: + { + if (fchan->state == FTDM_CHANNEL_STATE_DOWN || fchan->state == FTDM_CHANNEL_STATE_DIALING) { + *event_id = FTDM_OOB_WINK; + } else { + *event_id = FTDM_OOB_FLASH; + } + } + break; + case ZT_EVENT_RINGOFFHOOK: + { + if (fchan->type == FTDM_CHAN_TYPE_FXS || (fchan->type == FTDM_CHAN_TYPE_EM && fchan->state != FTDM_CHANNEL_STATE_UP)) { + ftdm_set_flag_locked(fchan, FTDM_CHANNEL_OFFHOOK); + *event_id = FTDM_OOB_OFFHOOK; + } else if (fchan->type == FTDM_CHAN_TYPE_FXO) { + *event_id = FTDM_OOB_RING_START; + } else { + *event_id = FTDM_OOB_NOOP; + } + } + break; + case ZT_EVENT_ALARM: + { + *event_id = FTDM_OOB_ALARM_TRAP; + } + break; + case ZT_EVENT_NOALARM: + { + *event_id = FTDM_OOB_ALARM_CLEAR; + } + break; + case ZT_EVENT_BITSCHANGED: + { + *event_id = FTDM_OOB_CAS_BITS_CHANGE; + int bits = 0; + int err = ioctl(fchan->sockfd, codes.GETRXBITS, &bits); + if (err) { + return FTDM_FAIL; + } + fchan->rx_cas_bits = bits; + } + break; + default: + { + ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled event %d\n", zt_event_id); + *event_id = FTDM_OOB_INVALID; + } + break; + } + return FTDM_SUCCESS; +} + +/** + * \brief Retrieves an event from a ftdm channel + * \param ftdmchan Channel to retrieve event from + * \param event FreeTDM event to return + * \return Success or failure + */ +FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event) +{ + uint32_t event_id = FTDM_OOB_INVALID; + zt_event_t zt_event_id = 0; + ftdm_span_t *span = ftdmchan->span; + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) { + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT); + } + + if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) { + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event from channel: %s\n", + strerror(errno)); + return FTDM_FAIL; + } + + /* the core already locked the channel for us, so it's safe to call zt_channel_process_event() here */ + if ((zt_channel_process_event(ftdmchan, &event_id, zt_event_id)) != FTDM_SUCCESS) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n"); + return FTDM_FAIL; + } + + ftdmchan->last_event_time = 0; + span->event_header.e_type = FTDM_EVENT_OOB; + span->event_header.enum_id = event_id; + span->event_header.channel = ftdmchan; + *event = &span->event_header; + return FTDM_SUCCESS; +} + /** * \brief Retrieves an event from a ftdmtel span * \param span Span to retrieve event from @@ -997,91 +1122,29 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event) zt_event_t zt_event_id = 0; for(i = 1; i <= span->chan_count; i++) { - if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) { - ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT); - if (ioctl(span->channels[i]->sockfd, codes.GETEVENT, &zt_event_id) == -1) { - snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno)); - return FTDM_FAIL; - } - - switch(zt_event_id) { - case ZT_EVENT_RINGEROFF: - { - return FTDM_FAIL; - } - break; - case ZT_EVENT_RINGERON: - { - return FTDM_FAIL; - } - break; - case ZT_EVENT_RINGBEGIN: - { - event_id = FTDM_OOB_RING_START; - } - break; - case ZT_EVENT_ONHOOK: - { - event_id = FTDM_OOB_ONHOOK; - } - break; - case ZT_EVENT_WINKFLASH: - { - if (span->channels[i]->state == FTDM_CHANNEL_STATE_DOWN || span->channels[i]->state == FTDM_CHANNEL_STATE_DIALING) { - event_id = FTDM_OOB_WINK; - } else { - event_id = FTDM_OOB_FLASH; - } - } - break; - case ZT_EVENT_RINGOFFHOOK: - { - if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS || (span->channels[i]->type == FTDM_CHAN_TYPE_EM && span->channels[i]->state != FTDM_CHANNEL_STATE_UP)) { - ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK); - event_id = FTDM_OOB_OFFHOOK; - } else if (span->channels[i]->type == FTDM_CHAN_TYPE_FXO) { - event_id = FTDM_OOB_RING_START; - } else { - event_id = FTDM_OOB_NOOP; - } - } - break; - case ZT_EVENT_ALARM: - { - event_id = FTDM_OOB_ALARM_TRAP; - } - break; - case ZT_EVENT_NOALARM: - { - event_id = FTDM_OOB_ALARM_CLEAR; - } - break; - case ZT_EVENT_BITSCHANGED: - { - event_id = FTDM_OOB_CAS_BITS_CHANGE; - int bits = 0; - int err = ioctl(span->channels[i]->sockfd, codes.GETRXBITS, &bits); - if (err) { - return FTDM_FAIL; - } - span->channels[i]->rx_cas_bits = bits; - } - break; - default: - { - ftdm_log(FTDM_LOG_WARNING, "Unhandled event %d for %d:%d\n", zt_event_id, span->span_id, i); - event_id = FTDM_OOB_INVALID; - } - break; - } - - span->channels[i]->last_event_time = 0; - span->event_header.e_type = FTDM_EVENT_OOB; - span->event_header.enum_id = event_id; - span->event_header.channel = span->channels[i]; - *event = &span->event_header; - return FTDM_SUCCESS; + ftdm_channel_t *fchan = span->channels[i]; + if (ftdm_test_flag(fchan, FTDM_CHANNEL_EVENT)) { + ftdm_clear_flag(fchan, FTDM_CHANNEL_EVENT); } + if (ioctl(fchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) { + snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno)); + return FTDM_FAIL; + } + + ftdm_channel_lock(fchan); + if ((zt_channel_process_event(fchan, &event_id, zt_event_id)) != FTDM_SUCCESS) { + ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Failed to process event from channel\n"); + ftdm_channel_unlock(fchan); + return FTDM_FAIL; + } + ftdm_channel_unlock(fchan); + + fchan->last_event_time = 0; + span->event_header.e_type = FTDM_EVENT_OOB; + span->event_header.enum_id = event_id; + span->event_header.channel = fchan; + *event = &span->event_header; + return FTDM_SUCCESS; } return FTDM_FAIL; @@ -1146,6 +1209,7 @@ static FIO_WRITE_FUNCTION(zt_write) bytes += 2; } +tryagain: w = write(ftdmchan->sockfd, data, bytes); if (w >= 0) { @@ -1153,6 +1217,17 @@ static FIO_WRITE_FUNCTION(zt_write) return FTDM_SUCCESS; } + if (errno == ELAST) { + zt_event_t zt_event_id = 0; + if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) { + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event after ELAST on write: %s\n", strerror(errno)); + return FTDM_FAIL; + } + /* we should enqueue this event somewhere so it can be retrieved by the user, for now, dropping it to see what it is! */ + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dropping event %d to be able to write data\n", zt_event_id); + goto tryagain; + } + return FTDM_FAIL; } diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 2fd821e5ef..5f61b0e257 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -144,7 +144,9 @@ typedef enum { /*! \brief Hunting direction (when hunting for free channels) */ typedef enum { FTDM_TOP_DOWN, - FTDM_BOTTOM_UP + FTDM_BOTTOM_UP, + FTDM_RR_DOWN, + FTDM_RR_UP, } ftdm_direction_t; /*! \brief I/O channel type */ @@ -265,15 +267,32 @@ typedef enum { #define USER_LAYER1_PROT_STRINGS "V.110", "u-law", "a-law", "Invalid" FTDM_STR2ENUM_P(ftdm_str2ftdm_usr_layer1_prot, ftdm_user_layer1_prot2str, ftdm_user_layer1_prot_t) +/*! Calling Party Category */ +typedef enum { + FTDM_CPC_UNKNOWN, + FTDM_CPC_OPERATOR, + FTDM_CPC_ORDINARY, + FTDM_CPC_PRIORITY, + FTDM_CPC_DATA, + FTDM_CPC_TEST, + FTDM_CPC_PAYPHONE, + FTDM_CPC_INVALID +} ftdm_calling_party_category_t; +#define CALLING_PARTY_CATEGORY_STRINGS "unknown", "operator", "ordinary", "priority", "data-call", "test-call", "payphone", "invalid" +FTDM_STR2ENUM_P(ftdm_str2ftdm_calling_party_category, ftdm_calling_party_category2str, ftdm_calling_party_category_t) + +/*! \brief Digit limit used in DNIS/ANI */ +#define FTDM_DIGITS_LIMIT 25 + /*! \brief Number abstraction */ typedef struct { - char digits[25]; + char digits[FTDM_DIGITS_LIMIT]; uint8_t type; uint8_t plan; } ftdm_number_t; typedef void * ftdm_variable_container_t; - + /*! \brief Caller information */ typedef struct ftdm_caller_data { char cid_date[8]; /*!< Caller ID date */ @@ -282,10 +301,10 @@ typedef struct ftdm_caller_data { ftdm_number_t ani; /*!< ANI (Automatic Number Identification) */ ftdm_number_t dnis; /*!< DNIS (Dialed Number Identification Service) */ ftdm_number_t rdnis; /*!< RDNIS (Redirected Dialed Number Identification Service) */ - char aniII[25]; /*! ANI II */ + char aniII[FTDM_DIGITS_LIMIT]; /*! ANI II */ uint8_t screen; /*!< Screening */ uint8_t pres; /*!< Presentation*/ - char collected[25]; /*!< Collected digits so far */ + char collected[FTDM_DIGITS_LIMIT]; /*!< Collected digits so far */ int hangup_cause; /*!< Hangup cause */ char raw_data[1024]; /*!< Protocol specific raw caller data */ uint32_t raw_data_len; /*!< Raw data length */ @@ -294,12 +313,14 @@ typedef struct ftdm_caller_data { ftdm_bearer_cap_t bearer_capability; /* user information layer 1 protocol */ ftdm_user_layer1_prot_t bearer_layer1; - ftdm_variable_container_t variables; /*! + * Ricardo Barroetaveña + * */ #ifndef __FTDM_CALL_UTILS_H__ @@ -114,5 +120,16 @@ FT_DECLARE(ftdm_status_t) ftdm_set_presentation_ind(const char *string, uint8_t */ FT_DECLARE(ftdm_status_t) ftdm_is_number(const char *number); +/*! + * \brief Set the Calling Party Category from an enum + * + * \param cpc_string string value + * \param target the target to set value to + * + * \retval FTDM_SUCCESS success + * \retval FTDM_FAIL failure + */ +FT_DECLARE(ftdm_status_t) ftdm_set_calling_party_category(const char *string, uint8_t *target); + #endif /* __FTDM_CALL_UTILS_H__ */ diff --git a/libs/freetdm/src/include/ftdm_declare.h b/libs/freetdm/src/include/ftdm_declare.h index bfec448253..88a76930f7 100644 --- a/libs/freetdm/src/include/ftdm_declare.h +++ b/libs/freetdm/src/include/ftdm_declare.h @@ -183,7 +183,16 @@ typedef enum { FTDM_TIMEOUT, /*!< Operation timed out (ie: polling on a device)*/ FTDM_NOTIMPL, /*!< Operation not implemented */ FTDM_BREAK, /*!< Request the caller to perform a break (context-dependant, ie: stop getting DNIS/ANI) */ - FTDM_EINVAL /*!< Invalid argument */ + + /*!< Any new return codes should try to mimc unix style error codes, no need to reinvent */ + /* Remapping some of the codes that were before */ + FTDM_ENOMEM = FTDM_MEMERR, /*!< Memory error */ + FTDM_ETIMEDOUT = FTDM_TIMEOUT, /*!< Operation timedout */ + FTDM_ENOSYS = FTDM_NOTIMPL, /*!< The function is not implemented */ + + FTDM_EINVAL, /*!< Invalid argument */ + FTDM_ECANCELED, /*!< Operation cancelled */ + FTDM_EBUSY, /*!< Device busy */ } ftdm_status_t; /*! \brief FreeTDM bool type. */ diff --git a/libs/freetdm/src/include/ftdm_os.h b/libs/freetdm/src/include/ftdm_os.h index f3ebee9ea2..a4605c3371 100644 --- a/libs/freetdm/src/include/ftdm_os.h +++ b/libs/freetdm/src/include/ftdm_os.h @@ -51,6 +51,9 @@ extern "C" { #include #endif +/*! \brief time data type */ +typedef uint64_t ftdm_time_t; + /*! \brief sleep x amount of milliseconds */ #ifdef __WINDOWS__ #define ftdm_sleep(x) Sleep(x) @@ -114,6 +117,8 @@ FT_DECLARE(char *) ftdm_strdup(const char *str); /*! \brief Duplicate string with limit */ FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen); +/*! \brief Get the current time in milliseconds */ +FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void); #ifdef __cplusplus } /* extern C */ diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 9222da3a42..a5862e5d15 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -143,7 +143,9 @@ extern "C" { \return true value if the object has the flags defined */ #define ftdm_test_flag(obj, flag) ((obj)->flags & flag) +/*!< Physical (IO) module specific flags */ #define ftdm_test_pflag(obj, flag) ((obj)->pflags & flag) +/*!< signaling module specific flags */ #define ftdm_test_sflag(obj, flag) ((obj)->sflags & flag) #define ftdm_set_alarm_flag(obj, flag) (obj)->alarm_flags |= (flag) @@ -190,17 +192,6 @@ extern "C" { #define ftdm_clear_sflag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->sflags &= ~(flag); ftdm_mutex_unlock(obj->mutex); -#define ftdm_set_state(obj, s) ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); \ - -#define ftdm_set_state_locked(obj, s) \ - do { \ - ftdm_channel_lock(obj); \ - ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); \ - ftdm_channel_unlock(obj); \ - } while(0); - -#define ftdm_set_state_r(obj, s, r) r = ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); - #ifdef _MSC_VER /* The while(0) below throws a conditional expression is constant warning */ #pragma warning(disable:4127) @@ -361,15 +352,6 @@ typedef struct { ftdm_mutex_t *mutex; } ftdm_dtmf_debug_t; -typedef struct { - const char *file; - const char *func; - int line; - ftdm_channel_state_t state; - ftdm_channel_state_t last_state; - ftdm_time_t time; -} ftdm_channel_history_entry_t; - typedef enum { FTDM_IOSTATS_ERROR_CRC = (1 << 0), FTDM_IOSTATS_ERROR_FRAME = (1 << 1), @@ -411,7 +393,7 @@ struct ftdm_channel { uint32_t extra_id; ftdm_chan_type_t type; ftdm_socket_t sockfd; - uint32_t flags; + uint64_t flags; uint32_t pflags; uint32_t sflags; ftdm_alarm_flag_t alarm_flags; @@ -422,9 +404,11 @@ struct ftdm_channel { uint32_t native_interval; uint32_t packet_len; ftdm_channel_state_t state; + ftdm_state_status_t state_status; ftdm_channel_state_t last_state; ftdm_channel_state_t init_state; - ftdm_channel_history_entry_t history[10]; + ftdm_channel_indication_t indication; + ftdm_state_history_entry_t history[10]; uint8_t hindex; ftdm_mutex_t *mutex; teletone_dtmf_detect_state_t dtmf_detect; @@ -456,6 +440,7 @@ struct ftdm_channel { ftdm_fsk_data_state_t fsk; uint8_t fsk_buf[80]; uint32_t ring_count; + ftdm_polarity_t polarity; /* Private I/O data. Do not touch unless you are an I/O module */ void *io_data; /* Private signaling data. Do not touch unless you are a signaling module */ @@ -477,6 +462,7 @@ struct ftdm_channel { ftdm_dtmf_debug_t dtmfdbg; ftdm_io_dump_t rxdump; ftdm_io_dump_t txdump; + ftdm_interrupt_t *state_completed_interrupt; /*!< Notify when a state change is completed */ int32_t txdrops; int32_t rxdrops; }; @@ -493,6 +479,7 @@ struct ftdm_span { ftdm_trunk_type_t trunk_type; ftdm_analog_start_type_t start_type; ftdm_signal_type_t signal_type; + uint32_t last_used_index; /* Private signaling data. Do not touch unless you are a signaling module */ void *signal_data; fio_signal_cb_t signal_cb; @@ -513,15 +500,15 @@ struct ftdm_span { ftdm_span_stop_t stop; ftdm_channel_sig_read_t sig_read; ftdm_channel_sig_write_t sig_write; - /* Private I/O data per span. Do not touch unless you are an I/O module */ - void *io_data; + ftdm_channel_state_processor_t state_processor; /*!< This guy is called whenever state processing is required */ + void *io_data; /*!< Private I/O data per span. Do not touch unless you are an I/O module */ char *type; char *dtmf_hangup; size_t dtmf_hangup_len; ftdm_state_map_t *state_map; ftdm_caller_data_t default_caller_data; - ftdm_queue_t *pendingchans; - ftdm_queue_t *pendingsignals; + ftdm_queue_t *pendingchans; /*!< Channels pending of state processing */ + ftdm_queue_t *pendingsignals; /*!< Signals pending from being delivered to the user */ struct ftdm_span *next; }; @@ -568,11 +555,7 @@ FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_checksum(ftdm_fsk_data_state_t *stat FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_sdmf(ftdm_fsk_data_state_t *state, const char *date, char *number); FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, ftdm_fsk_data_state_t *fsk_data, float db_level); -FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line, - ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int wait); - FT_DECLARE(ftdm_status_t) ftdm_span_load_tones(ftdm_span_t *span, const char *mapname); -FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void); FT_DECLARE(ftdm_status_t) ftdm_channel_use(ftdm_channel_t *ftdmchan); @@ -585,8 +568,6 @@ FT_DECLARE(void) print_hex_bytes(uint8_t *data, ftdm_size_t dlen, char *buf, ftd FT_DECLARE_NONSTD(int) ftdm_hash_equalkeys(void *k1, void *k2); FT_DECLARE_NONSTD(uint32_t) ftdm_hash_hashfromstring(void *ky); -FT_DECLARE(ftdm_status_t) ftdm_channel_complete_state(ftdm_channel_t *ftdmchan); - FT_DECLARE(int) ftdm_load_modules(void); FT_DECLARE(ftdm_status_t) ftdm_unload_modules(void); @@ -602,6 +583,7 @@ FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap); FT_DECLARE(ftdm_status_t) ftdm_span_close_all(void); FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan); +FT_DECLARE(void) ftdm_ack_indication(ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication, ftdm_status_t status); /*! * \brief Retrieves an event from the span @@ -702,50 +684,6 @@ static __inline__ void ftdm_abort(void) #endif } -static __inline__ void ftdm_set_state_all(ftdm_span_t *span, ftdm_channel_state_t state) -{ - uint32_t j; - ftdm_mutex_lock(span->mutex); - for(j = 1; j <= span->chan_count; j++) { - if (!FTDM_IS_DCHAN(span->channels[j])) { - ftdm_set_state_locked((span->channels[j]), state); - } - } - ftdm_mutex_unlock(span->mutex); -} - -static __inline__ int ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state) -{ - uint32_t j; - for(j = 1; j <= span->chan_count; j++) { - if (span->channels[j]->state != state || ftdm_test_flag(span->channels[j], FTDM_CHANNEL_STATE_CHANGE)) { - return 0; - } - } - - return 1; -} - -static __inline__ void ftdm_set_flag_all(ftdm_span_t *span, uint32_t flag) -{ - uint32_t j; - ftdm_mutex_lock(span->mutex); - for(j = 1; j <= span->chan_count; j++) { - ftdm_set_flag_locked((span->channels[j]), flag); - } - ftdm_mutex_unlock(span->mutex); -} - -static __inline__ void ftdm_clear_flag_all(ftdm_span_t *span, uint32_t flag) -{ - uint32_t j; - ftdm_mutex_lock(span->mutex); - for(j = 1; j <= span->chan_count; j++) { - ftdm_clear_flag_locked((span->channels[j]), flag); - } - ftdm_mutex_unlock(span->mutex); -} - static __inline__ int16_t ftdm_saturated_add(int16_t sample1, int16_t sample2) { int addres; diff --git a/libs/freetdm/src/include/private/ftdm_m3ua.h b/libs/freetdm/src/include/private/ftdm_m3ua.h deleted file mode 100644 index 1bf830853c..0000000000 --- a/libs/freetdm/src/include/private/ftdm_m3ua.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * ftdm_m3ua.h - * freetdm - * - * Created by Shane Burrell on 4/3/08. - * Copyright 2008 Shane Burrell. All rights reserved. - * - * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -//#include "m3ua_client.h" -#include "freetdm.h" - -#ifdef __cplusplus -extern "C" { -#endif -enum e_sigboost_event_id_values -{ - SIGBOOST_EVENT_CALL_START = 0x80, /*128*/ - SIGBOOST_EVENT_CALL_START_ACK = 0x81, /*129*/ - SIGBOOST_EVENT_CALL_START_NACK = 0x82, /*130*/ - SIGBOOST_EVENT_CALL_START_NACK_ACK = 0x83, /*131*/ - SIGBOOST_EVENT_CALL_ANSWERED = 0x84, /*132*/ - SIGBOOST_EVENT_CALL_STOPPED = 0x85, /*133*/ - SIGBOOST_EVENT_CALL_STOPPED_ACK = 0x86, /*134*/ - SIGBOOST_EVENT_SYSTEM_RESTART = 0x87, /*135*/ - SIGBOOST_EVENT_SYSTEM_RESTART_ACK = 0x88, /*136*/ - /* Following IDs are ss7boost to sangoma_mgd only. */ - SIGBOOST_EVENT_HEARTBEAT = 0x89, /*137*/ - SIGBOOST_EVENT_INSERT_CHECK_LOOP = 0x8a, /*138*/ - SIGBOOST_EVENT_REMOVE_CHECK_LOOP = 0x8b, /*139*/ - SIGBOOST_EVENT_AUTO_CALL_GAP_ABATE = 0x8c, /*140*/ -}; -enum e_sigboost_release_cause_values -{ - SIGBOOST_RELEASE_CAUSE_UNDEFINED = 0, - SIGBOOST_RELEASE_CAUSE_NORMAL = 16, - SIGBOOST_RELEASE_CAUSE_BUSY = 17, - /* probable elimination */ - //SIGBOOST_RELEASE_CAUSE_BUSY = 0x91, /* 145 */ - //SIGBOOST_RELEASE_CAUSE_CALLED_NOT_EXIST = 0x92, /* 146 */ - //SIGBOOST_RELEASE_CAUSE_CIRCUIT_RESET = 0x93, /* 147 */ - //SIGBOOST_RELEASE_CAUSE_NOANSWER = 0x94, /* 148 */ -}; - -enum e_sigboost_call_setup_ack_nack_cause_values -{ - SIGBOOST_CALL_SETUP_NACK_ALL_CKTS_BUSY = 117, /* unused Q.850 value */ - SIGBOOST_CALL_SETUP_NACK_TEST_CKT_BUSY = 118, /* unused Q.850 value */ - SIGBOOST_CALL_SETUP_NACK_INVALID_NUMBER = 28, - /* probable elimination */ - //SIGBOOST_CALL_SETUP_RESERVED = 0x00, - //SIGBOOST_CALL_SETUP_CIRCUIT_RESET = 0x10, - //SIGBOOST_CALL_SETUP_NACK_CKT_START_TIMEOUT = 0x11, - //SIGBOOST_CALL_SETUP_NACK_AUTO_CALL_GAP = 0x17, -}; -typedef enum { - M3UA_SPAN_SIGNALING_M3UA, - M3UA_SPAN_SIGNALING_SS7BOX, - -} M3UA_TSpanSignaling; -#define M3UA_SPAN_STRINGS "M3UA", "SS7BOX" -FTDM_STR2ENUM_P(m3ua_str2span, m3ua_span2str, M3UA_TSpanSignaling) - - - -typedef enum { - FTDM_M3UA_RUNNING = (1 << 0) -} ftdm_m3uat_flag_t; - -/*typedef struct m3ua_data { - m3uac_connection_t mcon; - m3uac_connection_t pcon; - fio_signal_cb_t signal_cb; - uint32_t flags; -} m3ua_data_t; - -*/ -/*typedef struct mu3a_link { - ss7bc_connection_t mcon; - ss7bc_connection_t pcon; - fio_signal_cb_t signal_cb; - uint32_t flags; -} ftdm_m3ua_data_t; -*/ - -ftdm_status_t m3ua_init(ftdm_io_interface_t **zint); -ftdm_status_t m3ua_destroy(void); -ftdm_status_t m3ua_start(ftdm_span_t *span); - -#ifdef __cplusplus -} -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4: - */ - diff --git a/libs/freetdm/src/include/private/ftdm_state.h b/libs/freetdm/src/include/private/ftdm_state.h new file mode 100644 index 0000000000..7de015b72b --- /dev/null +++ b/libs/freetdm/src/include/private/ftdm_state.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2010, Sangoma Technologies + * Moises Silva + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FTDM_STATE_H__ +#define __FTDM_STATE_H__ + +/*! \file + * \brief State handling definitions + * \note Most, if not all of the state handling functions assume you have a lock acquired. Touching the channel + * state is a sensitive matter that requires checks and careful thought and is typically a process that + * is not encapsulated within a single function, therefore the lock must be explicitly acquired by the + * caller (most of the time, signaling modules), process states, set a new state and process it, and + * finally unlock the channel. See docs/locking.txt fore more info + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + FTDM_CHANNEL_STATE_DOWN, + FTDM_CHANNEL_STATE_HOLD, + FTDM_CHANNEL_STATE_SUSPENDED, + FTDM_CHANNEL_STATE_DIALTONE, + FTDM_CHANNEL_STATE_COLLECT, + FTDM_CHANNEL_STATE_RING, + FTDM_CHANNEL_STATE_RINGING, + FTDM_CHANNEL_STATE_BUSY, + FTDM_CHANNEL_STATE_ATTN, + FTDM_CHANNEL_STATE_GENRING, + FTDM_CHANNEL_STATE_DIALING, + FTDM_CHANNEL_STATE_GET_CALLERID, + FTDM_CHANNEL_STATE_CALLWAITING, + FTDM_CHANNEL_STATE_RESTART, + FTDM_CHANNEL_STATE_PROCEED, + FTDM_CHANNEL_STATE_PROGRESS, + FTDM_CHANNEL_STATE_PROGRESS_MEDIA, + FTDM_CHANNEL_STATE_UP, + FTDM_CHANNEL_STATE_IDLE, + FTDM_CHANNEL_STATE_TERMINATING, + FTDM_CHANNEL_STATE_CANCEL, + FTDM_CHANNEL_STATE_HANGUP, + FTDM_CHANNEL_STATE_HANGUP_COMPLETE, + FTDM_CHANNEL_STATE_IN_LOOP, + FTDM_CHANNEL_STATE_RESET, + FTDM_CHANNEL_STATE_INVALID +} ftdm_channel_state_t; +#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \ + "RING", "RINGING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \ + "RESTART", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \ + "HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "RESET", "INVALID" +FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t) + +typedef struct { + const char *file; + const char *func; + int line; + ftdm_channel_state_t state; /*!< Current state (processed or not) */ + ftdm_channel_state_t last_state; /*!< Previous state */ + ftdm_time_t time; /*!< Time the state was set */ + ftdm_time_t end_time; /*!< Time the state processing was completed */ +} ftdm_state_history_entry_t; + +typedef ftdm_status_t (*ftdm_channel_state_processor_t)(ftdm_channel_t *fchan); + +/*! + * \brief Process channel states by invoking the channel state processing routine + * it will keep calling the processing routine while the state status + * is FTDM_STATE_STATUS_NEW, it will not do anything otherwise + */ +FT_DECLARE(ftdm_status_t) ftdm_channel_advance_states(ftdm_channel_t *fchan); + +FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const char *function, int line, ftdm_channel_t *fchan); +#define ftdm_channel_complete_state(obj) _ftdm_channel_complete_state(__FILE__, __FUNCTION__, __LINE__, obj) +FT_DECLARE(int) ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state); + +/*! + * \brief Status of the current channel state + * \note A given state goes thru several status (yes, states for the state!) + * The order is always FTDM_STATE_STATUS_NEW -> FTDM_STATE_STATUS_PROCESSED -> FTDM_STATUS_COMPLETED + * However, is possible to go from NEW -> COMPLETED directly when the signaling module explicitly changes + * the state of the channel in the middle of processing the current state by calling the ftdm_set_state() API + * + * FTDM_STATE_STATUS_NEW - + * Someone just set the state of the channel, either the signaling module or the user (implicitly through a call API). + * This is accomplished by calling ftdm_channel_set_state() which changes the 'state' and 'last_state' memebers of + * the ftdm_channel_t structure. + * + * FTDM_STATE_STATUS_PROCESSED - + * The signaling module did something based on the new state. + * + * This is accomplished via ftdm_channel_advance_states() + * + * When ftdm_channel_advance_states(), at the very least, if the channel has its state in FTDM_STATE_STATUS_NEW, it + * will move to FTDM_STATE_STATUS_PROCESSED, depending on what the signaling module does during the processing + * the state may move to FTDM_STATE_STATUS_COMPLETED right after or wait for a signaling specific event to complete it. + * It is also possible that more state transitions occur during the execution of ftdm_channel_advance_states() if one + * state processing/completion leads to another state change, the function will not return until the chain of events + * lead to a state that is not in FTDM_STATE_STATUS_NEW + * + * FTDM_STATE_STATUS_COMPLETED - + * The signaling module completed the processing of the state and there is nothing further to be done for this state. + * + * This is accomplished either explicitly by the signaling module by calling ftdm_channel_complete_state() or by + * the signaling module implicitly by trying to set the state of the channel to a new state via ftdm_set_state() + * + * When working with blocking channels (FTDM_CHANNEL_NONBLOCK flag not set), the user thread is signaled and unblocked + * so it can continue. + * + * When a state moves to this status is also possible for a signal FTDM_SIGEVENT_INDICATION_COMPLETED to be delivered + * by the core if the state change was associated to an indication requested by the user, + */ +typedef enum { + FTDM_STATE_STATUS_NEW, + FTDM_STATE_STATUS_PROCESSED, + FTDM_STATE_STATUS_COMPLETED, + FTDM_STATE_STATUS_INVALID +} ftdm_state_status_t; +#define CHANNEL_STATE_STATUS_STRINGS "NEW", "PROCESSED", "COMPLETED", "INVALID" +FTDM_STR2ENUM_P(ftdm_str2ftdm_state_status, ftdm_state_status2str, ftdm_state_status_t) + +typedef enum { + ZSM_NONE, + ZSM_UNACCEPTABLE, + ZSM_ACCEPTABLE +} ftdm_state_map_type_t; + +typedef enum { + ZSD_INBOUND, + ZSD_OUTBOUND, +} ftdm_state_direction_t; + +#define FTDM_MAP_NODE_SIZE 512 +#define FTDM_MAP_MAX FTDM_CHANNEL_STATE_INVALID+2 + +struct ftdm_state_map_node { + ftdm_state_direction_t direction; + ftdm_state_map_type_t type; + ftdm_channel_state_t check_states[FTDM_MAP_MAX]; + ftdm_channel_state_t states[FTDM_MAP_MAX]; +}; +typedef struct ftdm_state_map_node ftdm_state_map_node_t; + +struct ftdm_state_map { + ftdm_state_map_node_t nodes[FTDM_MAP_NODE_SIZE]; +}; +typedef struct ftdm_state_map ftdm_state_map_t; + +/*!\brief Set the state for a channel (the channel must be locked when calling this function) + * \note Signaling modules should use ftdm_set_state macro instead + * \note If this function is called with the wait parameter set to a non-zero value, the recursivity + * of the channel lock must be == 1 because the channel will be unlocked/locked when waiting */ +FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *func, int line, + ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int wait); + +/*!\brief Set the state of a channel immediately and implicitly complete the previous state if needed + * \note FTDM_SIGEVENT_INDICATION_COMPLETED will be sent if the state change + * is associated to some indication (ie FTDM_CHANNEL_INDICATE_PROCEED) + * \note The channel must be locked when calling this function + * */ +FT_DECLARE(ftdm_status_t) _ftdm_set_state(const char *file, const char *func, int line, + ftdm_channel_t *fchan, ftdm_channel_state_t state); +#define ftdm_set_state(obj, s) _ftdm_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s); \ + +/*!\brief This macro is deprecated, signaling modules should always lock the channel themselves anyways since they must + * process first the user pending state changes then set a new state before releasing the lock + * this macro is here for backwards compatibility, DO NOT USE IT in new code since it is *always* wrong to set + * a state in a signaling module without checking and processing the current state first (and for that you must lock the channel) + */ +#define ftdm_set_state_locked(obj, s) \ + do { \ + ftdm_channel_lock(obj); \ + ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); \ + ftdm_channel_unlock(obj); \ + } while(0); + +#define ftdm_set_state_r(obj, s, r) r = ftdm_channel_set_state(__FILE__, __FUNCTION__, __LINE__, obj, s, 0); + +#define ftdm_set_state_all(span, state) \ + do { \ + uint32_t _j; \ + ftdm_mutex_lock((span)->mutex); \ + for(_j = 1; _j <= (span)->chan_count; _j++) { \ + if (!FTDM_IS_DCHAN(span->channels[_j])) { \ + ftdm_set_state_locked((span->channels[_j]), state); \ + } \ + } \ + ftdm_mutex_unlock((span)->mutex); \ + } while (0); + +#ifdef __cplusplus +} +#endif + +#endif + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index f03c060e5a..d79835733b 100644 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -69,8 +69,6 @@ extern "C" { #define FTDM_END -1 #define FTDM_ANY_STATE -1 -typedef uint64_t ftdm_time_t; - typedef enum { FTDM_ENDIAN_BIG = 1, FTDM_ENDIAN_LITTLE = -1 @@ -123,6 +121,7 @@ typedef enum { FTDM_STR2ENUM_P(ftdm_str2ftdm_analog_start_type, ftdm_analog_start_type2str, ftdm_analog_start_type_t) typedef enum { + FTDM_OOB_NOOP, FTDM_OOB_ONHOOK, FTDM_OOB_OFFHOOK, FTDM_OOB_WINK, @@ -131,11 +130,11 @@ typedef enum { FTDM_OOB_RING_STOP, FTDM_OOB_ALARM_TRAP, FTDM_OOB_ALARM_CLEAR, - FTDM_OOB_NOOP, FTDM_OOB_CAS_BITS_CHANGE, + FTDM_OOB_POLARITY_REVERSE, FTDM_OOB_INVALID } ftdm_oob_event_t; -#define OOB_STRINGS "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "NOOP", "CAS_BITS_CHANGE", "INVALID" +#define OOB_STRINGS "NOOP", "ONHOOK", "OFFHOOK", "WINK", "FLASH", "RING_START", "RING_STOP", "ALARM_TRAP", "ALARM_CLEAR", "CAS_BITS_CHANGE", "POLARITY_REVERSE", "INVALID" FTDM_STR2ENUM_P(ftdm_str2ftdm_oob_event, ftdm_oob_event2str, ftdm_oob_event_t) /*! \brief Event types */ @@ -169,7 +168,7 @@ typedef enum { typedef enum { FTDM_SPAN_CONFIGURED = (1 << 0), - FTDM_SPAN_READY = (1 << 1), + FTDM_SPAN_STARTED = (1 << 1), FTDM_SPAN_STATE_CHANGE = (1 << 2), FTDM_SPAN_SUSPENDED = (1 << 3), FTDM_SPAN_IN_THREAD = (1 << 4), @@ -203,113 +202,56 @@ typedef enum { FTDM_CHANNEL_FEATURE_IO_STATS = (1<<9), /*!< Channel supports IO statistics (HDLC channels only) */ } ftdm_channel_feature_t; -typedef enum { - FTDM_CHANNEL_STATE_DOWN, - FTDM_CHANNEL_STATE_HOLD, - FTDM_CHANNEL_STATE_SUSPENDED, - FTDM_CHANNEL_STATE_DIALTONE, - FTDM_CHANNEL_STATE_COLLECT, - FTDM_CHANNEL_STATE_RING, - FTDM_CHANNEL_STATE_RINGING, - FTDM_CHANNEL_STATE_BUSY, - FTDM_CHANNEL_STATE_ATTN, - FTDM_CHANNEL_STATE_GENRING, - FTDM_CHANNEL_STATE_DIALING, - FTDM_CHANNEL_STATE_GET_CALLERID, - FTDM_CHANNEL_STATE_CALLWAITING, - FTDM_CHANNEL_STATE_RESTART, - FTDM_CHANNEL_STATE_PROCEED, - FTDM_CHANNEL_STATE_PROGRESS, - FTDM_CHANNEL_STATE_PROGRESS_MEDIA, - FTDM_CHANNEL_STATE_UP, - FTDM_CHANNEL_STATE_IDLE, - FTDM_CHANNEL_STATE_TERMINATING, - FTDM_CHANNEL_STATE_CANCEL, - FTDM_CHANNEL_STATE_HANGUP, - FTDM_CHANNEL_STATE_HANGUP_COMPLETE, - FTDM_CHANNEL_STATE_IN_LOOP, - FTDM_CHANNEL_STATE_RESET, - FTDM_CHANNEL_STATE_INVALID -} ftdm_channel_state_t; -#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \ - "RING", "RINGING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \ - "RESTART", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \ - "HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "RESET", "INVALID" -FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t) +/*!< Channel flags. This used to be an enum but we reached the 32bit limit for enums, is safer this way */ +#define FTDM_CHANNEL_CONFIGURED (1ULL << 0) +#define FTDM_CHANNEL_READY (1ULL << 1) +#define FTDM_CHANNEL_OPEN (1ULL << 2) +#define FTDM_CHANNEL_DTMF_DETECT (1ULL << 3) +#define FTDM_CHANNEL_SUPRESS_DTMF (1ULL << 4) +#define FTDM_CHANNEL_TRANSCODE (1ULL << 5) +#define FTDM_CHANNEL_BUFFER (1ULL << 6) +#define FTDM_CHANNEL_EVENT (1ULL << 7) +#define FTDM_CHANNEL_INTHREAD (1ULL << 8) +#define FTDM_CHANNEL_WINK (1ULL << 9) +#define FTDM_CHANNEL_FLASH (1ULL << 10) +#define FTDM_CHANNEL_STATE_CHANGE (1ULL << 11) +#define FTDM_CHANNEL_HOLD (1ULL << 12) +#define FTDM_CHANNEL_INUSE (1ULL << 13) +#define FTDM_CHANNEL_OFFHOOK (1ULL << 14) +#define FTDM_CHANNEL_RINGING (1ULL << 15) +#define FTDM_CHANNEL_PROGRESS_DETECT (1ULL << 16) +#define FTDM_CHANNEL_CALLERID_DETECT (1ULL << 17) +#define FTDM_CHANNEL_OUTBOUND (1ULL << 18) +#define FTDM_CHANNEL_SUSPENDED (1ULL << 19) +#define FTDM_CHANNEL_3WAY (1ULL << 20) -typedef enum { - FTDM_CHANNEL_CONFIGURED = (1 << 0), - FTDM_CHANNEL_READY = (1 << 1), - FTDM_CHANNEL_OPEN = (1 << 2), - FTDM_CHANNEL_DTMF_DETECT = (1 << 3), - FTDM_CHANNEL_SUPRESS_DTMF = (1 << 4), - FTDM_CHANNEL_TRANSCODE = (1 << 5), - FTDM_CHANNEL_BUFFER = (1 << 6), - FTDM_CHANNEL_EVENT = (1 << 7), - FTDM_CHANNEL_INTHREAD = (1 << 8), - FTDM_CHANNEL_WINK = (1 << 9), - FTDM_CHANNEL_FLASH = (1 << 10), - FTDM_CHANNEL_STATE_CHANGE = (1 << 11), - FTDM_CHANNEL_HOLD = (1 << 12), - FTDM_CHANNEL_INUSE = (1 << 13), - FTDM_CHANNEL_OFFHOOK = (1 << 14), - FTDM_CHANNEL_RINGING = (1 << 15), - FTDM_CHANNEL_PROGRESS_DETECT = (1 << 16), - FTDM_CHANNEL_CALLERID_DETECT = (1 << 17), - FTDM_CHANNEL_OUTBOUND = (1 << 18), - FTDM_CHANNEL_SUSPENDED = (1 << 19), - FTDM_CHANNEL_3WAY = (1 << 20), - FTDM_CHANNEL_PROGRESS = (1 << 21), - FTDM_CHANNEL_MEDIA = (1 << 22), - FTDM_CHANNEL_ANSWERED = (1 << 23), - FTDM_CHANNEL_MUTE = (1 << 24), - FTDM_CHANNEL_USE_RX_GAIN = (1 << 25), - FTDM_CHANNEL_USE_TX_GAIN = (1 << 26), - FTDM_CHANNEL_IN_ALARM = (1 << 27), - FTDM_CHANNEL_SIG_UP = (1 << 28), - FTDM_CHANNEL_USER_HANGUP = (1 << 29), - FTDM_CHANNEL_RX_DISABLED = (1 << 30), - FTDM_CHANNEL_TX_DISABLED = (1 << 31), - /* ok, when we reach 32, we need to move to uint64_t all the flag stuff */ -} ftdm_channel_flag_t; -#if defined(__cplusplus) && defined(WIN32) - // fix C2676 -__inline__ ftdm_channel_flag_t operator|=(ftdm_channel_flag_t a, int32_t b) { - a = (ftdm_channel_flag_t)(a | b); - return a; -} -__inline__ ftdm_channel_flag_t operator&=(ftdm_channel_flag_t a, int32_t b) { - a = (ftdm_channel_flag_t)(a & b); - return a; -} -#endif +/* this 3 flags are really nonsense used by boost module only, as soon + * as we deprecate/delete boost module we can get rid of them + * ================== + * */ +#define FTDM_CHANNEL_PROGRESS (1ULL << 21) +#define FTDM_CHANNEL_MEDIA (1ULL << 22) +#define FTDM_CHANNEL_ANSWERED (1ULL << 23) +/* ================== */ -typedef enum { - ZSM_NONE, - ZSM_UNACCEPTABLE, - ZSM_ACCEPTABLE -} ftdm_state_map_type_t; +#define FTDM_CHANNEL_MUTE (1ULL << 24) +#define FTDM_CHANNEL_USE_RX_GAIN (1ULL << 25) +#define FTDM_CHANNEL_USE_TX_GAIN (1ULL << 26) +#define FTDM_CHANNEL_IN_ALARM (1ULL << 27) +#define FTDM_CHANNEL_SIG_UP (1ULL << 28) +#define FTDM_CHANNEL_USER_HANGUP (1ULL << 29) +#define FTDM_CHANNEL_RX_DISABLED (1ULL << 30) +#define FTDM_CHANNEL_TX_DISABLED (1ULL << 31) +/*!< The user knows about a call in this channel */ +#define FTDM_CHANNEL_CALL_STARTED (1ULL << 32) +/*!< The user wants non-blocking operations in the channel */ +#define FTDM_CHANNEL_NONBLOCK (1ULL << 33) +/*!< There is a pending acknowledge for an indication */ +#define FTDM_CHANNEL_IND_ACK_PENDING (1ULL << 34) +/*!< There is someone blocking in the channel waiting for state completion */ +#define FTDM_CHANNEL_BLOCKING (1ULL << 35) -typedef enum { - ZSD_INBOUND, - ZSD_OUTBOUND, -} ftdm_state_direction_t; - -#define FTDM_MAP_NODE_SIZE 512 -#define FTDM_MAP_MAX FTDM_CHANNEL_STATE_INVALID+2 - -struct ftdm_state_map_node { - ftdm_state_direction_t direction; - ftdm_state_map_type_t type; - ftdm_channel_state_t check_states[FTDM_MAP_MAX]; - ftdm_channel_state_t states[FTDM_MAP_MAX]; -}; -typedef struct ftdm_state_map_node ftdm_state_map_node_t; - -struct ftdm_state_map { - ftdm_state_map_node_t nodes[FTDM_MAP_NODE_SIZE]; -}; -typedef struct ftdm_state_map ftdm_state_map_t; +#include "ftdm_state.h" typedef enum ftdm_channel_hw_link_status { FTDM_HW_LINK_DISCONNECTED = 0, diff --git a/libs/freetdm/src/m3ua/mstm3ua.c b/libs/freetdm/src/m3ua/mstm3ua.c deleted file mode 100644 index 1d8179c58d..0000000000 --- a/libs/freetdm/src/m3ua/mstm3ua.c +++ /dev/null @@ -1,62 +0,0 @@ -/* WARNING WORK IN PROGRESS - * mstm3ua.c - * mstss7d port - * - * Created by Shane Burrell on 2/2/08. - * Copyright 2008 Shane Burrell. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "mstm3ua.h" - - - - - -int build_m3ua_hdr(unsigned char len,unsigned char *bytemsg) - -{ - - *bytemsg++ = M_VERSION_REL1; // 1 Verison - //bytemsg[1] = 0x00; // 2 RESERVED - //bytemsg[2] = M_CLASS_XFER; // 3 Msg Class - //SS7 BOX Kludge - *bytemsg++ = 0x01; // 2 RESERVED - *bytemsg++ = 0x00; // 2 RESERVED - - *bytemsg++ = M_TYPE_DATA ; // 4 Msg Type - - *bytemsg++ = len; // 5 Msg LENGTH 81 32bit field - *bytemsg++ = 0x00; // 6 - *bytemsg++ = 0x00; // 7 - *bytemsg++ = 0x00; // 8 - return(0); - -}; \ No newline at end of file diff --git a/libs/freetdm/src/m3ua/mstm3ua.h b/libs/freetdm/src/m3ua/mstm3ua.h deleted file mode 100644 index 13527dac35..0000000000 --- a/libs/freetdm/src/m3ua/mstm3ua.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * mstm3ua.h - * mstss7d - * - * Created by Shane Burrell on 3/2/08. - * Copyright 2008 Shane Burrell. All rights reserved. - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -typedef unsigned long m3ua_ulong; -typedef unsigned short m3ua_ushort; -typedef unsigned char m3ua_uchar; - -typedef unsigned char u8; -typedef unsigned short u16; /* Note: multi-byte values are little-endian */ -typedef unsigned long u32; - - - - -#define M_TAG_NETWORK_APPEARANCE 1 -#define M_TAG_PROTOCOL_DATA 3 -#define M_TAG_INFO_STRING 4 -#define M_TAG_AFFECTED_DPC 5 -#define M_TAG_ROUTING_CONTEXT 6 -#define M_TAG_DIAGNOSTIC_INFORMATION 7 -#define M_TAG_HEARTBEAT_DATA 8 -#define M_TAG_UNAVAILABILITY_CAUSE 9 -#define M_TAG_REASON 10 -#define M_TAG_TRAFFIC_MODE_TYPE 11 -#define M_TAG_ERROR_CODE 12 -#define M_TAG_STATUS_TYPE 13 -#define M_TAG_CONGESTED_INDICATIONS 14 - -#define M_VERSION_REL1 1 - -#define M_CLASS_MGMT 0x00 -#define M_CLASS_XFER 0x01 -#define M_CLASS_SSNM 0x02 -#define M_CLASS_ASPSM 0x03 -#define M_CLASS_ASPTM 0x04 -#define M_CLASS_RKM 0x09 - -#define M_TYPE_ERR (0|M_CLASS_MGMT - -#define M_TYPE_NTFY (1|M_CLASS_XFER) -#define M_TYPE_DATA (1|M_CLASS_XFER) - -#define M_TYPE_DUNA (1|M_CLASS_SSNM) -#define M_TYPE_DAVA (2|M_CLASS_SSNM) -#define M_TYPE_DUAD (3|M_CLASS_SSNM) -#define M_TYPE_SCON (4|M_CLASS_SSNM) -#define M_TYPE_DUPU (5|M_CLASS_SSNM) - -#define M_TYPE_UP (1|M_CLASS_ASPSM) -#define M_TYPE_DOWN (2|M_CLASS_ASPSM) -#define M_TYPE_BEAT (3|M_CLASS_ASPSM) -#define M_TYPE_UP_ACK (4|M_CLASS_ASPSM) -#define M_TYPE_DOWN_ACK (5|M_CLASS_ASPSM) -#define M_TYPE_BEAT_ACK (6|M_CLASS_ASPSM) - -#define M_TYPE_ACTIVE (1|M_CLASS_ASPTM) -#define M_TYPE_INACTIVE (2|M_CLASS_ASPTM) -#define M_TYPE_ACTIVE_ACK (3|M_CLASS_ASPTM) -#define M_TYPE_INACTIVE_ACK (4|M_CLASS_ASPTM) - -#define M_CLASS_MASK 0xff00 -#define M_TYPE_MASK 0x00ff - diff --git a/libs/freetdm/src/m3ua_client.c b/libs/freetdm/src/m3ua_client.c deleted file mode 100644 index 7608183896..0000000000 --- a/libs/freetdm/src/m3ua_client.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * m3ua_client.c - * freetdm - * - * Created by Shane Burrell on 4/3/08. - * Copyright 2008 Shane Burrell. All rights reserved. - * - * - * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if HAVE_NETDB_H -#include -#endif - -#include "freetdm.h" -#include - - -#ifndef HAVE_GETHOSTBYNAME_R -extern int gethostbyname_r (const char *__name, - struct hostent *__result_buf, - char *__buf, size_t __buflen, - struct hostent **__result, - int *__h_errnop); -#endif - -struct m3uac_map { - uint32_t event_id; - const char *name; -}; - -static struct m3uac_map m3uac_table[] = { - {M3UA_EVENT_CALL_START, "CALL_START"}, - {M3UA_EVENT_CALL_START_ACK, "CALL_START_ACK"}, - {M3UA_EVENT_CALL_START_NACK, "CALL_START_NACK"}, - {M3UA_EVENT_CALL_START_NACK_ACK, "CALL_START_NACK_ACK"}, - {M3UA_EVENT_CALL_ANSWERED, "CALL_ANSWERED"}, - {M3UA_EVENT_CALL_STOPPED, "CALL_STOPPED"}, - {M3UA_EVENT_CALL_STOPPED_ACK, "CALL_STOPPED_ACK"}, - {M3UA_EVENT_SYSTEM_RESTART, "SYSTEM_RESTART"}, - {M3UA_EVENT_SYSTEM_RESTART_ACK, "SYSTEM_RESTART_ACK"}, - {M3UA_EVENT_HEARTBEAT, "HEARTBEAT"}, - {M3UA_EVENT_INSERT_CHECK_LOOP, "LOOP START"}, - {M3UA_EVENT_REMOVE_CHECK_LOOP, "LOOP STOP"} -}; - - - -static int create_conn_socket(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port) -{ - int rc; - struct hostent *result, *local_result; - char buf[512], local_buf[512]; - int err = 0; - - memset(&mcon->remote_hp, 0, sizeof(mcon->remote_hp)); - memset(&mcon->local_hp, 0, sizeof(mcon->local_hp)); - mcon->socket = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); - - ftdm_log(FTDM_LOG_DEBUG, "Creating L=%s:%d R=%s:%d\n", - local_ip,local_port,ip,port); - - if (mcon->socket >= 0) { - int flag; - - flag = 1; - gethostbyname_r(ip, &mcon->remote_hp, buf, sizeof(buf), &result, &err); - gethostbyname_r(local_ip, &mcon->local_hp, local_buf, sizeof(local_buf), &local_result, &err); - if (result && local_result) { - mcon->remote_addr.sin_family = mcon->remote_hp.h_addrtype; - memcpy((char *) &mcon->remote_addr.sin_addr.s_addr, mcon->remote_hp.h_addr_list[0], mcon->remote_hp.h_length); - mcon->remote_addr.sin_port = htons(port); - - mcon->local_addr.sin_family = mcon->local_hp.h_addrtype; - memcpy((char *) &mcon->local_addr.sin_addr.s_addr, mcon->local_hp.h_addr_list[0], mcon->local_hp.h_length); - mcon->local_addr.sin_port = htons(local_port); - - - setsockopt(mcon->socket, IPPROTO_SCTP, SCTP_NODELAY, (char *)&flag, sizeof(int)); - - rc=listen(mcon->socket,100); - if (rc) { - close(mcon->socket); - mcon->socket = -1; - - } - } - } - - ftdm_mutex_create(&mcon->mutex); - - return mcon->socket; -} - -int m3uac_connection_close(m3uac_connection_t *mcon) -{ - if (mcon->socket > -1) { - close(mcon->socket); - } - - ftdm_mutex_lock(mcon->mutex); - ftdm_mutex_unlock(mcon->mutex); - ftdm_mutex_destroy(&mcon->mutex); - memset(mcon, 0, sizeof(*mcon)); - mcon->socket = -1; - - return 0; -} - -int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port) -{ - create_conn_socket(mcon, local_ip, local_port, ip, port); - return mcon->socket; -} - - -int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause) -{ - m3uac_event_t oevent; - int retry = 5; - - m3uac_event_init(&oevent, cmd, chan, span); - oevent.release_cause = cause; - - if (cmd == SIGBOOST_EVENT_SYSTEM_RESTART) { - mcon->rxseq_reset = 1; - mcon->txseq = 0; - mcon->rxseq = 0; - mcon->txwindow = 0; - } - - if (id >= 0) { - oevent.call_setup_id = id; - } - - while (m3uac_connection_write(mcon, &oevent) <= 0) { - if (--retry <= 0) { - ftdm_log(FTDM_LOG_CRIT, "Failed to tx on M3UA socket: %s\n", strerror(errno)); - return -1; - } else { - ftdm_log(FTDM_LOG_WARNING, "Failed to tx on M3UA socket: %s :retry %i\n", strerror(errno), retry); - ftdm_sleep(1); - } - } - - return 0; -} - - - -m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration) -{ - unsigned int fromlen = sizeof(struct sockaddr_in); - int bytes = 0; - - bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, - (struct sockaddr *) &mcon->local_addr, &fromlen); - - if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) { - - if (mcon->rxseq_reset) { - if (mcon->event.event_id == SIGBOOST_EVENT_SYSTEM_RESTART_ACK) { - ftdm_log(FTDM_LOG_DEBUG, "Rx sync ok\n"); - mcon->rxseq = mcon->event.fseqno; - return &mcon->event; - } - errno=EAGAIN; - ftdm_log(FTDM_LOG_DEBUG, "Waiting for rx sync...\n"); - return NULL; - } - - mcon->txwindow = mcon->txseq - mcon->event.bseqno; - mcon->rxseq++; - - if (mcon->rxseq != mcon->event.fseqno) { - ftdm_log(FTDM_LOG_CRIT, "Invalid Sequence Number Expect=%i Rx=%i\n", mcon->rxseq, mcon->event.fseqno); - return NULL; - } - - return &mcon->event; - } else { - if (iteration == 0) { - ftdm_log(FTDM_LOG_CRIT, "Invalid Event length from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event)); - return NULL; - } - } - - return NULL; -} - -m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration) -{ - unsigned int fromlen = sizeof(struct sockaddr_in); - int bytes = 0; - - bytes = recvfrom(mcon->socket, &mcon->event, sizeof(mcon->event), MSG_DONTWAIT, (struct sockaddr *) &mcon->local_addr, &fromlen); - - if (bytes == sizeof(mcon->event) || bytes == (sizeof(mcon->event)-sizeof(uint32_t))) { - return &mcon->event; - } else { - if (iteration == 0) { - ftdm_log(FTDM_LOG_CRIT, "Critical Error: PQ Invalid Event lenght from boost rxlen=%i evsz=%i\n", bytes, sizeof(mcon->event)); - return NULL; - } - } - - return NULL; -} - - -int m3uac_connection_write(m3uac_connection_t *mcon, ss7bc_event_t *event) -{ - int err; - - if (!event || mcon->socket < 0 || !mcon->mutex) { - ftdm_log(FTDM_LOG_DEBUG, "Critical Error: No Event Device\n"); - return -EINVAL; - } - - if (event->span > 16 || event->chan > 31) { - ftdm_log(FTDM_LOG_CRIT, "Critical Error: TX Cmd=%s Invalid Span=%i Chan=%i\n", m3uac_event_id_name(event->event_id), event->span,event->chan); - return -1; - } - - gettimeofday(&event->tv,NULL); - - ftdm_mutex_lock(mcon->mutex); - event->fseqno = mcon->txseq++; - event->bseqno = mcon->rxseq; - err = sendto(mcon->socket, event, sizeof(m3uac_event_t), 0, (struct sockaddr *) &mcon->remote_addr, sizeof(mcon->remote_addr)); - ftdm_mutex_unlock(mcon->mutex); - - if (err != sizeof(m3uac_event_t)) { - err = -1; - } - - ftdm_log(FTDM_LOG_DEBUG, "TX EVENT: %s:(%X) [w%dg%d] Rc=%i CSid=%i Seq=%i Cd=[%s] Ci=[%s]\n", - m3uac_event_id_name(event->event_id), - event->event_id, - event->span+1, - event->chan+1, - event->release_cause, - event->call_setup_id, - event->fseqno, - (event->called_number_digits_count ? (char *) event->called_number_digits : "N/A"), - (event->calling_number_digits_count ? (char *) event->calling_number_digits : "N/A") - ); - - return err; -} - -void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id) -{ - memset(event, 0, sizeof(m3uac_event_t)); - event->event_id = M3UA_EVENT_CALL_START; - - if (calling) { - strncpy((char*)event->calling_number_digits, calling, sizeof(event->calling_number_digits)-1); - event->calling_number_digits_count = strlen(calling); - } - - if (called) { - strncpy((char*)event->called_number_digits, called, sizeof(event->called_number_digits)-1); - event->called_number_digits_count = strlen(called); - } - - event->call_setup_id = setup_id; - -} - -void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span) -{ - memset(event, 0, sizeof(ss7bc_event_t)); - event->event_id = event_id; - event->chan = chan; - event->span = span; -} - -const char *m3uac_event_id_name(uint32_t event_id) -{ - unsigned int x; - const char *ret = NULL; - - for (x = 0 ; x < sizeof(m3uac_table)/sizeof(struct m3uac_map); x++) { - if (m3uac_table[x].event_id == event_id) { - ret = m3uac_table[x].name; - break; - } - } - - return ret; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4: - */ - - diff --git a/libs/freetdm/src/m3ua_client.h b/libs/freetdm/src/m3ua_client.h deleted file mode 100644 index e451156a41..0000000000 --- a/libs/freetdm/src/m3ua_client.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * m3ua_client.h - * freetdm - * - * Created by Shane Burrell on 4/3/08. - * Copyright 2008 Shane Burrell. All rights reserved. - * - * Copyright (c) 2007, Anthony Minessale II, Nenad Corbic - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Fix this for portability -#include -//#include -#include -#include -#include -//#include -#include - -#define MAX_DIALED_DIGITS 31 -#define MAX_CALLING_NAME 31 - -/* Next two defines are used to create the range of values for call_setup_id - * in the t_sigboost structure. - * 0..((CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN) - 1) */ -#define CORE_MAX_SPANS 200 -#define CORE_MAX_CHAN_PER_SPAN 30 -#define MAX_PENDING_CALLS CORE_MAX_SPANS * CORE_MAX_CHAN_PER_SPAN -/* 0..(MAX_PENDING_CALLS-1) is range of call_setup_id below */ -#define SIZE_RDNIS 80 - -//#undef MSGWINDOW -#define MSGWINDOW - - -typedef struct -{ - uint32_t event_id; - uint32_t fseqno; -#ifdef MSGWINDOW - uint32_t bseqno; -#endif - uint16_t call_setup_id; - uint32_t trunk_group; - uint32_t span; - uint32_t chan; - uint8_t called_number_digits_count; - char called_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */ - uint8_t calling_number_digits_count; /* it's an array */ - char calling_number_digits [MAX_DIALED_DIGITS + 1]; /* it's a null terminated string */ - uint8_t release_cause; - struct timeval tv; - /* ref. Q.931 Table 4-11 and Q.951 Section 3 */ - uint8_t calling_number_screening_ind; - uint8_t calling_number_presentation; - char redirection_string [SIZE_RDNIS]; /* it's a null terminated string */ - -} t_m3ua; - -typedef t_m3ua m3uac_event_t; -typedef uint32_t m3uac_event_id_t; - - -typedef struct m3uac_ip_cfg -{ - char local_ip[25]; - int local_port; - char remote_ip[25]; - int remote_port; -}m3uac_ip_cfg_t; - -struct m3uac_connection { - ftdm_socket_t socket; - struct sockaddr_in local_addr; - struct sockaddr_in remote_addr; - m3uac_event_t event; - struct hostent remote_hp; - struct hostent local_hp; - unsigned int flags; - ftdm_mutex_t *mutex; - FILE *log; - unsigned int txseq; - unsigned int rxseq; - unsigned int txwindow; - unsigned int rxseq_reset; - m3uac_ip_cfg_t cfg; - uint32_t hb_elapsed; - int up; -}; - -typedef enum { - MSU_FLAG_EVENT = (1 << 0) -} m3uac_flag_t; - -typedef struct m3uac_connection m3uac_connection_t; - -static inline void sctp_no_nagle(int socket) -{ - //int flag = 1; - //setsockopt(socket, IPPROTO_SCTP, SCTP_NODELAY, (char *) &flag, sizeof(int)); -} - -int m3uac_connection_close(m3uac_connection_t *mcon); -int m3uac_connection_open(m3uac_connection_t *mcon, char *local_ip, int local_port, char *ip, int port); -m3uac_event_t *m3uac_connection_read(m3uac_connection_t *mcon, int iteration); -m3uac_event_t *m3uac_connection_readp(m3uac_connection_t *mcon, int iteration); -int m3uac_connection_write(m3uac_connection_t *mcon, m3uac_event_t *event); -void m3uac_event_init(m3uac_event_t *event, m3uac_event_id_t event_id, int chan, int span); -void m3uac_call_init(m3uac_event_t *event, const char *calling, const char *called, int setup_id); -const char *m3uac_event_id_name(uint32_t event_id); -int m3uac_exec_command(m3uac_connection_t *mcon, int span, int chan, int id, int cmd, int cause); - - - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4: - */ diff --git a/libs/freetdm/src/testm3ua.c b/libs/freetdm/src/testm3ua.c deleted file mode 100644 index 5848470e7a..0000000000 --- a/libs/freetdm/src/testm3ua.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * testm3ua.c - * freetdm - * - * Created by Shane Burrell on 4/8/08. - * Copyright 2008 __MyCompanyName__. All rights reserved. - * - */ - -#include "testm3ua.h" -#include "freetdm.h" -#include "ftdm_m3ua.h" - -static FIO_SIGNAL_CB_FUNCTION(on_signal) -{ - return FTDM_FAIL; -} - -int main(int argc, char *argv[]) -{ - ftdm_span_t *span; - //m3ua_data_t *data; - - ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG); - - if (argc < 5) { - printf("more args needed\n"); - exit(-1); - } - - if (ftdm_global_init() != FTDM_SUCCESS) { - fprintf(stderr, "Error loading FreeTDM\n"); - exit(-1); - } - - printf("FreeTDM loaded\n"); - - if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) { - fprintf(stderr, "Error finding FreeTDM span\n"); - goto done; - } - - - if (ftdm_m3ua_configure_span(span) == FTDM_SUCCESS) { - //data = span->signal_data; - ftdm_m3ua_start(span); - } else { - fprintf(stderr, "Error starting M3UA\n"); - goto done; - } - - //while(ftdm_test_flag(data, FTDM_M3UA_RUNNING)) { - // ftdm_sleep(1 * 1000); - //} - - done: - - ftdm_global_destroy(); - -} diff --git a/libs/freetdm/src/testr2.c b/libs/freetdm/src/testr2.c index 8ac90c59fd..72d98020bc 100644 --- a/libs/freetdm/src/testr2.c +++ b/libs/freetdm/src/testr2.c @@ -2,78 +2,158 @@ #include #include -static int R = 0; -static ftdm_mutex_t *mutex = NULL; +static volatile int running = 0; +static ftdm_mutex_t *the_mutex = NULL; +static ftdm_channel_t *fchan = NULL; +static ftdm_channel_indication_t indication = FTDM_CHANNEL_INDICATE_NONE; static FIO_SIGNAL_CB_FUNCTION(on_r2_signal) { int chanid = ftdm_channel_get_ph_id(sigmsg->channel); - ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), chanid); - return FTDM_SUCCESS; + ftdm_log(FTDM_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", ftdm_signal_event2str(sigmsg->event_id), chanid); + switch (sigmsg->event_id) { + case FTDM_SIGEVENT_START: + { + ftdm_mutex_lock(the_mutex); + if (!fchan) { + fchan = sigmsg->channel; + indication = FTDM_CHANNEL_INDICATE_PROCEED; + } + ftdm_mutex_unlock(the_mutex); + } + break; + case FTDM_SIGEVENT_INDICATION_COMPLETED: + { + ftdm_channel_indication_t ind = FTDM_CHANNEL_INDICATE_NONE; + if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROCEED) { + ftdm_log(FTDM_LOG_DEBUG, "Proceed indication result = %d\n", sigmsg->ev_data.indication_completed.status); + ind = FTDM_CHANNEL_INDICATE_PROGRESS; + } else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROGRESS) { + ftdm_log(FTDM_LOG_DEBUG, "Progress indication result = %d\n", sigmsg->ev_data.indication_completed.status); + ind = FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA; + } else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA) { + ftdm_log(FTDM_LOG_DEBUG, "Progress media indication result = %d\n", sigmsg->ev_data.indication_completed.status); + ind = FTDM_CHANNEL_INDICATE_ANSWER; + } else if (sigmsg->ev_data.indication_completed.indication == FTDM_CHANNEL_INDICATE_ANSWER) { + ftdm_log(FTDM_LOG_DEBUG, "Answer indication result = %d\n", sigmsg->ev_data.indication_completed.status); + } else { + ftdm_log(FTDM_LOG_DEBUG, "Unexpected indication, result = %d\n", sigmsg->ev_data.indication_completed.status); + exit(1); + } + ftdm_mutex_lock(the_mutex); + if (fchan) { + indication = ind; + } + ftdm_mutex_unlock(the_mutex); + } + break; + case FTDM_SIGEVENT_STOP: + { + ftdm_channel_call_hangup(sigmsg->channel); + } + break; + case FTDM_SIGEVENT_RELEASED: + { + ftdm_mutex_lock(the_mutex); + if (fchan && fchan == sigmsg->channel) { + fchan = NULL; + } + ftdm_mutex_unlock(the_mutex); + } + break; + default: + break; + } + return FTDM_SUCCESS; } -static void handle_SIGINT(int sig) +static void stop_test(int sig) { - ftdm_mutex_lock(mutex); - R = 0; - ftdm_mutex_unlock(mutex); - return; + running = 0; } int main(int argc, char *argv[]) { ftdm_span_t *span; - ftdm_mutex_create(&mutex); - - ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG); + ftdm_conf_parameter_t parameters[20]; + + ftdm_mutex_create(&the_mutex); if (argc < 2) { printf("umm no\n"); - exit(-1); + exit(1); } + ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG); + if (ftdm_global_init() != FTDM_SUCCESS) { fprintf(stderr, "Error loading FreeTDM\n"); - exit(-1); + exit(1); } + ftdm_global_configuration(); + printf("FreeTDM loaded\n"); - if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) { - fprintf(stderr, "Error finding FreeTDM span\n"); + if (ftdm_span_find_by_name(argv[1], &span) != FTDM_SUCCESS) { + fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]); goto done; } + /* testing non-blocking operation */ + //ftdm_span_set_blocking_mode(span, FTDM_FALSE); + parameters[0].var = "variant"; + parameters[0].val = "br"; - if (ftdm_configure_span(span, "r2", on_r2_signal, - "variant", "mx", - "max_ani", 10, - "max_dnis", 4, - "logging", "all", - FTDM_TAG_END) == FTDM_SUCCESS) { - + parameters[1].var = "max_ani"; + parameters[1].val = "4"; + parameters[2].var = "max_dnis"; + parameters[2].val = "4"; + + parameters[3].var = "logging"; + parameters[3].val = "all"; + + parameters[4].var = NULL; + parameters[4].val = NULL; + + if (ftdm_configure_span_signaling(span, "r2", on_r2_signal, parameters) == FTDM_SUCCESS) { ftdm_span_start(span); } else { fprintf(stderr, "Error starting R2 span\n"); goto done; } - signal(SIGINT, handle_SIGINT); - ftdm_mutex_lock(mutex); - R = 1; - ftdm_mutex_unlock(mutex); - while(R) { - ftdm_sleep(1 * 1000); + running = 1; + signal(SIGINT, stop_test); + while(running) { + ftdm_sleep(20); + if (fchan && indication != FTDM_CHANNEL_INDICATE_NONE) { + ftdm_channel_t *lchan = NULL; + ftdm_channel_indication_t ind = FTDM_CHANNEL_INDICATE_NONE; + ftdm_time_t start, stop, diff; + + ftdm_mutex_lock(the_mutex); + ind = indication; + indication = FTDM_CHANNEL_INDICATE_NONE; + lchan = fchan; + ftdm_mutex_unlock(the_mutex); + + start = ftdm_current_time_in_ms(); + ftdm_channel_call_indicate(lchan, ind); + stop = ftdm_current_time_in_ms(); + diff = stop - start; + ftdm_log(FTDM_LOG_DEBUG, "Setting indication %s took %llums\n", + ftdm_channel_indication2str(ind), diff); + } } - done: +done: ftdm_global_destroy(); - return 1; - + return 0; } /* For Emacs: diff --git a/libs/iksemel/configure.ac b/libs/iksemel/configure.ac index f7687922c2..1b8af13683 100644 --- a/libs/iksemel/configure.ac +++ b/libs/iksemel/configure.ac @@ -84,7 +84,7 @@ AC_ARG_ENABLE(64, if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then if test "${enable_64}" = "yes"; then CFLAGS="$CFLAGS -m64" - CXXFLAGS="$CXXFLAGS -m64" + CXXFLAGS="$CXXFLAGS -m64 -lgpg-error" fi fi diff --git a/libs/libg722_1/Makefile.am b/libs/libg722_1/Makefile.am index f815fb8ddc..9d885335bb 100644 --- a/libs/libg722_1/Makefile.am +++ b/libs/libg722_1/Makefile.am @@ -15,8 +15,6 @@ ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -## -## $Id: Makefile.am,v 1.6 2008/09/30 14:06:39 steveu Exp $ AM_CFLAGS = $(COMP_VENDOR_CFLAGS) AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS) @@ -26,6 +24,7 @@ noinst_SCRIPTS = g722_1.spec MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = autogen.sh \ + g722_1.pc \ g722_1.spec \ unpack_g722_1_data.sh \ wrapper.xsl \ @@ -50,6 +49,9 @@ SUBDIRS = src $(MAYBE_DOC) $(MAYBE_TESTS) DIST_SUBDIRS = src doc tests test-data +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = g722_1.pc + faq: faq.xml cd faq ; xsltproc ../wrapper.xsl ../faq.xml diff --git a/libs/libg722_1/autogen.sh b/libs/libg722_1/autogen.sh index 96422dbee3..98fb7e4f8a 100755 --- a/libs/libg722_1/autogen.sh +++ b/libs/libg722_1/autogen.sh @@ -16,11 +16,6 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# $Id: autogen.sh,v 1.1.1.1 2008/09/20 09:47:17 steveu Exp $ -# - -UNAME=`uname` if [ "x$UNAME" = "xFreeBSD" ]; then echo "" diff --git a/libs/libg722_1/configure.ac b/libs/libg722_1/configure.ac index 64e276b280..62095ce374 100644 --- a/libs/libg722_1/configure.ac +++ b/libs/libg722_1/configure.ac @@ -15,17 +15,11 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# $Id: configure.ac,v 1.9 2008/10/09 14:17:12 steveu Exp $ # @start 1 AC_INIT -CFLAGS="$CFLAGS $CONFIGURE_CFLAGS" -CXXFLAGS="$CXXFLAGS $CONFIGURE_CXXFLAGS" -LDFLAGS="$LDFLAGS $CONFIGURE_LDFLAGS" - m4_include(config/ax_compiler_vendor.m4) m4_include(config/ax_check_real_file.m4) m4_include(config/ax_fixed_point_machine.m4) @@ -111,6 +105,22 @@ else CXXFLAGS=${CXXFLAGS-"-g -O2"} fi +AC_DEFUN([REMOVE_FROM_VAR],[ + new_val="" + removed=0 + for i in $$1; do + if test "x$i" != "x$2"; then + new_val="$new_val $i" + else + removed=1 + fi + done + if test $removed = "1"; then + echo " removed \"$2\" from $1" + $1=$new_val + fi +]) + AC_C_CONST AC_C_INLINE AC_C_VOLATILE @@ -190,7 +200,7 @@ AC_CHECK_HEADERS([audiofile.h]) AC_LANG([C]) -if test "${build}" = "${host}" +if test "${build}" == "${host}" then case "${host}" in x86_64-*) @@ -270,6 +280,7 @@ sun) COMP_VENDOR_CFLAGS="-native -fast $COMP_VENDOR_CFLAGS" fi COMP_VENDOR_LDFLAGS= + REMOVE_FROM_VAR(CFLAGS, -Xc) ;; *) COMP_VENDOR_CFLAGS="-std=c99 -Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes" @@ -293,20 +304,14 @@ AM_CONDITIONAL([COND_SSE5], [test "$enable_sse5" = yes]) if test "$enable_fixed_point" = "yes" ; then AC_DEFINE([G722_1_USE_FIXED_POINT], [1], [Enable fixed point processing, where possible, instead of floating point]) G722_1_USE_FIXED_POINT="#define G722_1_USE_FIXED_POINT 1" - fixed = "yes" G722_1_VECTORS_FOR_TESTS="fixed" else AX_FIXED_POINT_MACHINE([$host], - [ - AC_DEFINE([G722_1_USE_FIXED_POINT], [1], [Enable fixed point processing, where possible, instead of floating point]) - G722_1_USE_FIXED_POINT="#define G722_1_USE_FIXED_POINT 1" - fixed = "yes" - ], + [AC_DEFINE([G722_1_USE_FIXED_POINT], [1], [Enable fixed point processing, where possible, instead of floating point]) + G722_1_USE_FIXED_POINT="#define G722_1_USE_FIXED_POINT 1"], [G722_1_USE_FIXED_POINT="#undef G722_1_USE_FIXED_POINT"]) G722_1_VECTORS_FOR_TESTS="floating" fi -AM_CONDITIONAL([COND_FIXED], [test "$fixed" = "yes"]) - AX_MISALIGNED_ACCESS_FAILS([$host], [AC_DEFINE([G722_1_MISALIGNED_ACCESS_FAILS], [1], [Do not expect a misaligned memory access to work correctly]) G722_1_MISALIGNED_ACCESS_FAILS="#define G722_1_MISALIGNED_ACCESS_FAILS 1"], @@ -363,6 +368,7 @@ AC_CONFIG_FILES([Makefile src/Makefile src/g722_1.h tests/Makefile + g722_1.pc g722_1.spec]) AC_CONFIG_FILES([tests/regression_tests.sh], [chmod +x tests/regression_tests.sh]) diff --git a/libs/libg722_1/doc/Makefile.am b/libs/libg722_1/doc/Makefile.am index 4e58bbd8b8..a56809d00a 100644 --- a/libs/libg722_1/doc/Makefile.am +++ b/libs/libg722_1/doc/Makefile.am @@ -15,8 +15,6 @@ ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -## -## $Id: Makefile.am,v 1.1.1.1 2008/09/20 09:47:17 steveu Exp $ MAINTAINERCLEANFILES = Makefile.in diff --git a/libs/libg722_1/g722_1.pc.in b/libs/libg722_1/g722_1.pc.in new file mode 100644 index 0000000000..0fc01fbc73 --- /dev/null +++ b/libs/libg722_1/g722_1.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: spandsp +Description: A library for the ITU G.722.1 and G.722.1C audio codecs. +Requires: +Version: @VERSION@ +Libs: -L${libdir} -lg722_1 -lm +Cflags: -I${includedir} diff --git a/libs/libg722_1/g722_1.spec.in b/libs/libg722_1/g722_1.spec.in index db1d06a686..0c2b26dbc3 100644 --- a/libs/libg722_1/g722_1.spec.in +++ b/libs/libg722_1/g722_1.spec.in @@ -47,14 +47,13 @@ rm -rf %{buildroot} %{_libdir}/libg722_1.so.* -%{_datadir}/libg722_1 - %files devel %defattr(-,root,root,-) %doc doc/api %{_includedir}/g722_1.h %{_includedir}/g722_1 %{_libdir}/libg722_1.so +%{_libdir}/pkgconfig/g722_1.pc %post -p /sbin/ldconfig diff --git a/libs/libg722_1/src/Makefile.am b/libs/libg722_1/src/Makefile.am index 1943658d91..8600e920b2 100644 --- a/libs/libg722_1/src/Makefile.am +++ b/libs/libg722_1/src/Makefile.am @@ -15,18 +15,19 @@ ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -## -## $Id: Makefile.am,v 1.10 2008/10/16 15:46:12 steveu Exp $ AM_CFLAGS = $(COMP_VENDOR_CFLAGS) AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS) MAINTAINERCLEANFILES = Makefile.in -EXTRA_DIST = g722_1/version.h.in \ +EXTRA_DIST = make_tables.c \ + g722_1/version.h.in \ libg722_1.dsp \ - libg722_1.sln \ - libg722_1.vcproj \ + libg722_1.2005.sln \ + libg722_1.2008.sln \ + libg722_1.2005.vcproj \ + libg722_1.2008.vcproj \ msvc/gettimeofday.c \ msvc/inttypes.h \ msvc/tgmath.h \ @@ -36,13 +37,16 @@ EXTRA_DIST = g722_1/version.h.in \ msvc/msvcproj.head \ msvc/msvcproj.foot \ msvc/vc8proj.head \ - msvc/vc8proj.foot + msvc/vc8proj.foot \ + msvc/vc9proj.head \ + msvc/vc9proj.foot INCLUDES = -I$(top_builddir) lib_LTLIBRARIES = libg722_1.la -libg722_1_la_SOURCES = bitstream.c \ +libg722_1_la_SOURCES = basop32.c \ + bitstream.c \ coef2sam.c \ common.c \ commonf.c \ @@ -55,11 +59,9 @@ libg722_1_la_SOURCES = bitstream.c \ encoderf.c \ huff_tab.c \ sam2coef.c \ - tables.c + tables.c \ + utilities.c -if COND_FIXED -libg722_1_la_SOURCES += basop32.c -endif libg722_1_la_LDFLAGS = -version-info @G722_1_LT_CURRENT@:@G722_1_LT_REVISION@:@G722_1_LT_AGE@ $(COMP_VENDOR_LDFLAGS) nobase_include_HEADERS = g722_1/g722_1.h \ @@ -76,10 +78,10 @@ noinst_HEADERS = basop32.h \ defs.h \ huff_tab.h \ sam2coef.h \ - tables.h + tables.h \ + utilities.h -noinst_PROGRAMS = make_dct4_tables \ - make_tables +noinst_PROGRAMS = make_dct4_tables dct4.$(OBJEXT): dct4.h @@ -88,6 +90,9 @@ dct4.lo: dct4.h dct4.h: make_dct4_tables$(EXEEXT) ./make_dct4_tables$(EXEEXT) >dct4.h +make_dct4_tables$(EXEEXT): $(top_srcdir)/src/make_dct4_tables.c + $(CC_FOR_BUILD) -o make_dct4_tables$(EXEEXT) $(top_srcdir)/src/make_dct4_tables.c -DHAVE_CONFIG_H -I$(top_builddir)/src -lm + #coef2sam.h: make_tables$(EXEEXT) # ./make_tables$(EXEEXT) coef2sam >coef2samx.h @@ -95,13 +100,15 @@ dct4.h: make_dct4_tables$(EXEEXT) # ./make_tables$(EXEEXT) sam2coef >sam2coefx.h DSP = libg722_1.dsp -VCPROJ = libg722_1.vcproj +VCPROJ8 = libg722_1.2005.vcproj +VCPROJ9 = libg722_1.2008.vcproj WIN32SOURCES = $(libg722_1_la_SOURCES) msvc/gettimeofday.c WIN32HEADERS = $(nobase_include_HEADERS) g722_1.h DSPOUT = | awk '{printf("%s\r\n", $$0)}' >> $(DSP) -VCPROJOUT = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ) +VCPROJOUT8 = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ8) +VCPROJOUT9 = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ9) $(DSP): msvc/msvcproj.head msvc/msvcproj.foot Makefile.am echo "creating $(DSP)" @@ -124,26 +131,38 @@ $(DSP): msvc/msvcproj.head msvc/msvcproj.foot Makefile.am echo "# End Group" $(DSPOUT); \ cat $(srcdir)/msvc/msvcproj.foot $(DSPOUT) ) -$(VCPROJ): msvc/vc8proj.head msvc/vc8proj.foot Makefile.am - echo "creating $(VCPROJ)" - @(cp $(srcdir)/msvc/vc8proj.head $(VCPROJ); \ +$(VCPROJ8): msvc/vc8proj.head msvc/vc8proj.foot Makefile.am + echo "creating $(VCPROJ8)" + @(cp $(srcdir)/msvc/vc8proj.head $(VCPROJ8); \ for file in $(WIN32SOURCES); do \ - echo "" $(VCPROJOUT); \ + myfile=`echo $$file | sed -e 's|/|\\\\|g'`; \ + echo "" $(VCPROJOUT8); \ done; \ - echo "" $(VCPROJOUT); \ + echo "" $(VCPROJOUT8); \ for file in $(WIN32HEADERS); do \ - echo "" $(VCPROJOUT); \ + myfile=`echo $$file | sed -e 's|/|\\\\|g'`; \ + echo "" $(VCPROJOUT8); \ done; \ - cat $(srcdir)/msvc/vc8proj.foot $(VCPROJOUT) ) + cat $(srcdir)/msvc/vc8proj.foot $(VCPROJOUT8) ) + +$(VCPROJ9): msvc/vc9proj.head msvc/vc9proj.foot Makefile.am + echo "creating $(VCPROJ9)" + @(cp $(srcdir)/msvc/vc9proj.head $(VCPROJ9); \ + for file in $(WIN32SOURCES); do \ + myfile=`echo $$file | sed -e 's|/|\\\\|g'`; \ + echo "" $(VCPROJOUT9); \ + done; \ + echo "" $(VCPROJOUT9); \ + for file in $(WIN32HEADERS); do \ + myfile=`echo $$file | sed -e 's|/|\\\\|g'`; \ + echo "" $(VCPROJOUT9); \ + done; \ + cat $(srcdir)/msvc/vc9proj.foot $(VCPROJOUT9) ) + +dist-hook: g722_1/version.h g722_1/version.h: NOWDATE=`date --utc +"%Y%m%d"` ; \ NOWTIME=`date --utc +"%H%M%S"` ; \ sed 's/$$G722_1_RELEASE_DATE/'$$NOWDATE'/;s/$$G722_1_RELEASE_TIME/'$$NOWTIME'/' \ - g722_1/version.h - -dist-hook: - NOWDATE=`date --utc +"%Y%m%d"` ; \ - NOWTIME=`date --utc +"%H%M%S"` ; \ - sed 's/$$G722_1_RELEASE_DATE/'$$NOWDATE'/;s/$$G722_1_RELEASE_TIME/'$$NOWTIME'/' \ - g722_1/version.h + <$(srcdir)/g722_1/version.h.in >$@ diff --git a/libs/libg722_1/src/basop32.c b/libs/libg722_1/src/basop32.c index 54220f4fac..3a51f45eee 100644 --- a/libs/libg722_1/src/basop32.c +++ b/libs/libg722_1/src/basop32.c @@ -9,8 +9,6 @@ * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: basop32.c,v 1.5 2008/09/22 13:08:31 steveu Exp $ */ /*! \file */ @@ -19,9 +17,10 @@ #include #endif +#include + #if defined(G722_1_USE_FIXED_POINT) -#include #include #include diff --git a/libs/libg722_1/src/basop32.h b/libs/libg722_1/src/basop32.h index abc105f35e..36dae35297 100644 --- a/libs/libg722_1/src/basop32.h +++ b/libs/libg722_1/src/basop32.h @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: basop32.h,v 1.3 2008/09/22 13:08:31 steveu Exp $ */ #if !defined(BASOP32_H_DEFINED) @@ -104,14 +102,14 @@ static __inline__ int32_t L_mac(int32_t L_var3, int16_t var1, int16_t var2) } /*- End of function --------------------------------------------------------*/ -int16_t shl(int16_t var1, int16_t var2); /* Short shift left, 1 */ -int16_t shr(int16_t var1, int16_t var2); /* Short shift right, 1 */ -int32_t L_sub(int32_t L_var1, int32_t L_var2); /* Long sub, 2 */ -int32_t L_shl(int32_t L_var1, int16_t var2); /* Long shift left, 2 */ -int32_t L_shr(int32_t L_var1, int16_t var2); /* Long shift right, 2*/ -int16_t norm_s(int16_t var1); /* Short norm, 15 */ -int16_t div_s(int16_t var1, int16_t var2); /* Short division, 18 */ -int16_t norm_l(int32_t L_var1); /* Long norm, 30 */ +int16_t shl(int16_t var1, int16_t var2); /* Short shift left, 1 */ +int16_t shr(int16_t var1, int16_t var2); /* Short shift right, 1 */ +int32_t L_sub(int32_t L_var1, int32_t L_var2); /* Long sub, 2 */ +int32_t L_shl(int32_t L_var1, int16_t var2); /* Long shift left, 2 */ +int32_t L_shr(int32_t L_var1, int16_t var2); /* Long shift right, 2 */ +int16_t norm_s(int16_t var1); /* Short norm, 15 */ +int16_t div_s(int16_t var1, int16_t var2); /* Short division, 18 */ +int16_t norm_l(int32_t L_var1); /* Long norm, 30 */ #endif diff --git a/libs/libg722_1/src/bitstream.c b/libs/libg722_1/src/bitstream.c index ddaabd0edf..016ab8ee45 100644 --- a/libs/libg722_1/src/bitstream.c +++ b/libs/libg722_1/src/bitstream.c @@ -8,8 +8,6 @@ * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: bitstream.c,v 1.2 2008/10/17 13:18:21 steveu Exp $ */ /*! \file */ diff --git a/libs/libg722_1/src/bitstream.h b/libs/libg722_1/src/bitstream.h index 20e386513f..f2cc4b8bce 100644 --- a/libs/libg722_1/src/bitstream.h +++ b/libs/libg722_1/src/bitstream.h @@ -8,8 +8,6 @@ * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: bitstream.h,v 1.2 2008/10/17 13:18:21 steveu Exp $ */ /*! \file */ diff --git a/libs/libg722_1/src/coef2sam.c b/libs/libg722_1/src/coef2sam.c index 38d4943ca8..19f5a211ac 100644 --- a/libs/libg722_1/src/coef2sam.c +++ b/libs/libg722_1/src/coef2sam.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: coef2sam.c,v 1.10 2008/10/02 11:43:54 steveu Exp $ */ /*! \file */ @@ -29,18 +27,16 @@ #include "defs.h" #include "coef2sam.h" +#include "utilities.h" -/************************************************************************************* +/* Convert Reversed MLT (Modulated Lapped Transform) Coefficients to Samples - Purpose: Convert Reversed MLT (Modulated Lapped Transform) Coefficients to Samples - - The "Reversed MLT" is an overlapped block transform which uses even symmetry - on the left, odd symmetry on the right and a Type IV DCT as the block transform. - It is thus similar to a MLT which uses odd symmetry on the left, even symmetry - on the right and a Type IV DST as the block transform. In fact, it is equivalent - to reversing the order of the samples, performing an MLT and then negating all - the even-numbered coefficients. -***************************************************************************/ + The "Reversed MLT" is an overlapped block transform which uses even symmetry + on the left, odd symmetry on the right and a Type IV DCT as the block transform. + It is thus similar to a MLT which uses odd symmetry on the left, even symmetry + on the right and a Type IV DST as the block transform. In fact, it is equivalent + to reversing the order of the samples, performing an MLT and then negating all + the even-numbered coefficients. */ #if defined(G722_1_USE_FIXED_POINT) void rmlt_coefs_to_samples(int16_t coefs[], @@ -73,29 +69,23 @@ void rmlt_coefs_to_samples(int16_t coefs[], new_samples[i] = shl(new_samples[i], mag_shift); } - if (dct_length == DCT_LENGTH) - win = rmlt_to_samples_window; - else - win = max_rmlt_to_samples_window; + win = (dct_length == DCT_LENGTH) ? rmlt_to_samples_window : max_rmlt_to_samples_window; last = half_dct_length - 1; for (i = 0; i < half_dct_length; i++) { /* Get the first half of the windowed samples */ - sum = 0L; - sum = L_mac(sum, win[i], new_samples[last - i]); + sum = L_mult(win[i], new_samples[last - i]); sum = L_mac(sum, win[dct_length - i - 1], old_samples[i]); out_samples[i] = xround(L_shl(sum, 2)); /* Get the second half of the windowed samples */ - sum = 0L; - sum = L_mac(sum, win[half_dct_length + i], new_samples[i]); + sum = L_mult(win[half_dct_length + i], new_samples[i]); sum = L_mac(sum, negate(win[last - i]), old_samples[last - i]); out_samples[half_dct_length + i] = xround(L_shl(sum, 2)); } /* Save the second half of the new samples for next time, when they will be the old samples. */ - for (i = 0; i < half_dct_length; i++) - old_samples[i] = new_samples[half_dct_length + i]; + vec_copyi16(old_samples, &new_samples[half_dct_length], half_dct_length); } /*- End of function --------------------------------------------------------*/ #else @@ -116,10 +106,7 @@ void rmlt_coefs_to_samples(float coefs[], /* Perform a Type IV (inverse) DCT on the coefficients */ dct_type_iv(coefs, new_samples, dct_length); - if (dct_length == DCT_LENGTH) - win = rmlt_to_samples_window; - else - win = max_rmlt_to_samples_window; + win = (dct_length == DCT_LENGTH) ? rmlt_to_samples_window : max_rmlt_to_samples_window; last = half_dct_length - 1; for (i = 0; i < half_dct_length; i++) { @@ -135,8 +122,7 @@ void rmlt_coefs_to_samples(float coefs[], /* Save the second half of the new samples for next time, when they will be the old samples. */ - for (i = 0; i < half_dct_length; i++) - old_samples[i] = new_samples[half_dct_length + i]; + vec_copyf(old_samples, &new_samples[half_dct_length], half_dct_length); } /*- End of function --------------------------------------------------------*/ #endif diff --git a/libs/libg722_1/src/coef2sam.h b/libs/libg722_1/src/coef2sam.h index 731d28ddeb..21590761ea 100644 --- a/libs/libg722_1/src/coef2sam.h +++ b/libs/libg722_1/src/coef2sam.h @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: coef2sam.h,v 1.2 2008/10/02 11:43:54 steveu Exp $ */ #if defined(G722_1_USE_FIXED_POINT) diff --git a/libs/libg722_1/src/common.c b/libs/libg722_1/src/common.c index 46f6595054..b763a8465d 100644 --- a/libs/libg722_1/src/common.c +++ b/libs/libg722_1/src/common.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: common.c,v 1.6 2008/09/30 14:06:39 steveu Exp $ */ /*! \file */ @@ -38,41 +36,7 @@ static void compute_raw_pow_categories(int16_t *power_categories, int16_t number_of_regions, int16_t offset); -/**************************************************************************************** - Function: categorize - - Syntax: void categorize(int16_t number_of_available_bits, - int16_t number_of_regions, - int16_t num_categorization_control_possibilities, - int16_t rms_index, - int16_t power_categories, - int16_t category_balances) - - inputs: number_of_regions - num_categorization_control_possibilities - number_of_available_bits - rms_index[MAX_NUMBER_OF_REGIONS] - - outputs: power_categories[MAX_NUMBER_OF_REGIONS] - category_balances[MAX_NUM_CATEGORIZATION_CONTROL_POSSIBILITIES-1] - - Description: Computes a series of categorizations - - WMOPS: 7kHz | 24kbit | 32kbit - -------|--------------|---------------- - AVG | 0.14 | 0.14 - -------|--------------|---------------- - MAX | 0.15 | 0.15 - -------|--------------|---------------- - - 14kHz | 24kbit | 32kbit | 48kbit - -------|--------------|----------------|---------------- - AVG | 0.42 | 0.45 | 0.48 - -------|--------------|----------------|---------------- - MAX | 0.47 | 0.52 | 0.52 - -------|--------------|----------------|---------------- - -****************************************************************************************/ +/* Compute a series of categorizations */ void categorize(int16_t number_of_available_bits, int16_t number_of_regions, int16_t num_categorization_control_possibilities, @@ -88,10 +52,7 @@ void categorize(int16_t number_of_available_bits, /* At higher bit rates, there is an increase for most categories in average bit consumption per region. We compensate for this by pretending we have fewer available bits. */ - if (number_of_regions == NUMBER_OF_REGIONS) - frame_size = DCT_LENGTH; - else - frame_size = MAX_DCT_LENGTH; + frame_size = (number_of_regions == NUMBER_OF_REGIONS) ? DCT_LENGTH : MAX_DCT_LENGTH; temp = sub(number_of_available_bits, frame_size); if (temp > 0) @@ -114,45 +75,7 @@ void categorize(int16_t number_of_available_bits, } /*- End of function --------------------------------------------------------*/ -/*************************************************************************** - Function: comp_powercat_and_catbalance - - Syntax: void comp_powercat_and_catbalance(int16_t *power_categories, - int16_t *category_balances, - int16_t *rms_index, - int16_t number_of_available_bits, - int16_t number_of_regions, - int16_t num_categorization_control_possibilities, - int16_t offset) - - - inputs: *rms_index - number_of_available_bits - number_of_regions - num_categorization_control_possibilities - offset - - outputs: *power_categories - *category_balances - - - Description: Computes the power_categories and the category balances - - WMOPS: 7kHz | 24kbit | 32kbit - -------|--------------|---------------- - AVG | 0.10 | 0.10 - -------|--------------|---------------- - MAX | 0.11 | 0.11 - -------|--------------|---------------- - - 14kHz | 24kbit | 32kbit | 48kbit - -------|--------------|----------------|---------------- - AVG | 0.32 | 0.35 | 0.38 - -------|--------------|----------------|---------------- - MAX | 0.38 | 0.42 | 0.43 - -------|--------------|----------------|---------------- - -***************************************************************************/ +/* Compute the power_categories and the category balances */ void comp_powercat_and_catbalance(int16_t *power_categories, int16_t *category_balances, int16_t *rms_index, @@ -161,7 +84,6 @@ void comp_powercat_and_catbalance(int16_t *power_categories, int16_t num_categorization_control_possibilities, int16_t offset) { - int16_t expected_number_of_code_bits; int16_t region; int16_t max_region; @@ -190,7 +112,6 @@ void comp_powercat_and_catbalance(int16_t *power_categories, for (region = 0; region < number_of_regions; region++) expected_number_of_code_bits = add(expected_number_of_code_bits, expected_bits_table[power_categories[region]]); - for (region = 0; region < number_of_regions; region++) { max_rate_categories[region] = power_categories[region]; @@ -277,42 +198,16 @@ void comp_powercat_and_catbalance(int16_t *power_categories, } /*- End of function --------------------------------------------------------*/ -/*************************************************************************** - Function: calc_offset - - Syntax: offset=calc_offset(int16_t *rms_index,int16_t number_of_regions,int16_t available_bits) - - input: int16_t *rms_index - int16_t number_of_regions - int16_t available_bits - - output: int16_t offset - - Description: Calculates the the category offset. This is the shift required - To get the most out of the number of available bits. A binary - type search is used to find the offset. - - WMOPS: 7kHz | 24kbit | 32kbit - -------|--------------|---------------- - AVG | 0.04 | 0.04 - -------|--------------|---------------- - MAX | 0.04 | 0.04 - -------|--------------|---------------- - - 14kHz | 24kbit | 32kbit | 48kbit - -------|--------------|----------------|---------------- - AVG | 0.08 | 0.08 | 0.08 - -------|--------------|----------------|---------------- - MAX | 0.09 | 0.09 | 0.09 - -------|--------------|----------------|---------------- - -***************************************************************************/ -int16_t calc_offset(int16_t *rms_index,int16_t number_of_regions,int16_t available_bits) +/* Calculate the the category offset. This is the shift required + To get the most out of the number of available bits. A binary + type search is used to find the offset. */ +int16_t calc_offset(int16_t *rms_index, int16_t number_of_regions, int16_t available_bits) { int16_t answer; int16_t delta; int16_t test_offset; - int16_t region,j; + int16_t region; + int16_t j; int16_t power_cats[MAX_NUMBER_OF_REGIONS]; int16_t bits; int16_t offset; @@ -360,40 +255,9 @@ int16_t calc_offset(int16_t *rms_index,int16_t number_of_regions,int16_t availab } /*- End of function --------------------------------------------------------*/ -/*************************************************************************** - Function: compute_raw_pow_categories - - Syntax: void compute_raw_pow_categories(int16_t *power_categories, - int16_t *rms_index, - int16_t number_of_regions, - int16_t offset) - inputs: *rms_index - number_of_regions - offset - - outputs: *power_categories - - - - Description: This function computes the power categories given the offset - This is kind of redundant since they were already computed - in calc_offset to determine the offset. - - WMOPS: | 24kbit | 32kbit - -------|--------------|---------------- - AVG | 0.01 | 0.01 - -------|--------------|---------------- - MAX | 0.01 | 0.01 - -------|--------------|---------------- - - 14kHz | 24kbit | 32kbit | 48kbit - -------|--------------|----------------|---------------- - AVG | 0.01 | 0.01 | 0.01 - -------|--------------|----------------|---------------- - MAX | 0.01 | 0.01 | 0.01 - -------|--------------|----------------|---------------- - -***************************************************************************/ +/* Compute the power categories given the offset + This is kind of redundant since they were already computed + in calc_offset to determine the offset. */ static void compute_raw_pow_categories(int16_t *power_categories, int16_t *rms_index, int16_t number_of_regions, int16_t offset) { int16_t region; diff --git a/libs/libg722_1/src/commonf.c b/libs/libg722_1/src/commonf.c index dd2050aa1b..d86d1cf3ae 100644 --- a/libs/libg722_1/src/commonf.c +++ b/libs/libg722_1/src/commonf.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: commonf.c,v 1.11 2008/09/30 14:06:39 steveu Exp $ */ /*! \file */ @@ -34,9 +32,7 @@ #if !defined(G722_1_USE_FIXED_POINT) -/**************************************************************************************** - Description: Computes a series of categorizations -****************************************************************************************/ +/* Compute a series of categorizations */ void categorize(int number_of_regions, int number_of_available_bits, int rms_index[MAX_NUMBER_OF_REGIONS], diff --git a/libs/libg722_1/src/dct4.c b/libs/libg722_1/src/dct4.c index cb3a7fde03..9f0a61d6f6 100644 --- a/libs/libg722_1/src/dct4.c +++ b/libs/libg722_1/src/dct4.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C)2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: dct4.c,v 1.8 2008/09/29 16:09:26 steveu Exp $ */ #if defined(HAVE_CONFIG_H) @@ -29,6 +27,7 @@ #include "g722_1/g722_1.h" #include "defs.h" +#include "utilities.h" #if !defined(G722_1_USE_FIXED_POINT) @@ -52,9 +51,7 @@ static const cos_msin_t *cos_msin_table[] = cos_msin_640 }; -/********************************************************************************* - Description: Discrete Cosine Transform, Type IV -*********************************************************************************/ +/* Discrete Cosine Transform, Type IV */ void dct_type_iv(float input[], float output[], int dct_length) { float buffer_a[MAX_DCT_LENGTH]; @@ -64,22 +61,20 @@ void dct_type_iv(float input[], float output[], int dct_length) float *in_ptr_low; float *in_ptr_high; float *next_in_base; - float *out_ptr_low; - float *out_ptr_high; + float *out_ptr; float *next_out_base; float *out_buffer; float *in_buffer; float *buffer_swap; float *fptr0; - const float *fptr2; - const float *core_a; float in_val_low; float in_val_high; float cos_even; float cos_odd; float msin_even; float msin_odd; - float sum; + const float *fptr2; + const float *core_a; const cos_msin_t **table_ptr_ptr; const cos_msin_t *cos_msin_ptr; int set_span; @@ -120,29 +115,24 @@ void dct_type_iv(float input[], float output[], int dct_length) for (sets_left = set_count; sets_left > 0; sets_left--) { /* Set up output pointers for the current set */ - out_ptr_low = next_out_base; + out_ptr = next_out_base; next_out_base += set_span; - out_ptr_high = next_out_base; /* Loop over all the butterflies in the current set */ - do + for (i = 0; i < (set_span >> 1); i++) { in_val_low = *in_ptr++; in_val_high = *in_ptr++; - *out_ptr_low++ = in_val_low + in_val_high; - *--out_ptr_high = in_val_low - in_val_high; + out_ptr[i] = in_val_low + in_val_high; + out_ptr[set_span - 1 - i] = in_val_low - in_val_high; } - while (out_ptr_low < out_ptr_high); } /* Decide which buffers to use as input and output next time. Except for the first time (when the input buffer is the subroutine input) we just alternate the local buffers. */ in_buffer = out_buffer; - if (out_buffer == buffer_a) - out_buffer = buffer_b; - else - out_buffer = buffer_a; + out_buffer = (out_buffer == buffer_a) ? buffer_b : buffer_a; } /* Do dct_size/10 ten-point transforms */ @@ -153,11 +143,8 @@ void dct_type_iv(float input[], float output[], int dct_length) fptr2 = core_a; for (k = 0; k < CORE_SIZE; k++) { - sum = 0; - for (i = 0; i < CORE_SIZE; i++) - sum += fptr0[i]*fptr2[i]; + buffer_swap[k] = vec_dot_prodf(fptr0, fptr2, CORE_SIZE); fptr2 += CORE_SIZE; - buffer_swap[k] = sum; } fptr0 += CORE_SIZE; buffer_swap += CORE_SIZE; @@ -172,14 +159,10 @@ void dct_type_iv(float input[], float output[], int dct_length) { /* Initialization for the loop over sets at the current size */ set_span = dct_length >> set_count_log; - set_count = 1 << set_count_log; next_in_base = in_buffer; - if (set_count_log == 0) - next_out_base = output; - else - next_out_base = out_buffer; - ++table_ptr_ptr; + next_out_base = (set_count_log == 0) ? output : out_buffer; + table_ptr_ptr++; /* Loop over all the sets of this size */ for (sets_left = set_count; sets_left > 0; sets_left--) @@ -187,26 +170,23 @@ void dct_type_iv(float input[], float output[], int dct_length) /* Set up the pointers for the current set */ in_ptr_low = next_in_base; in_ptr_high = in_ptr_low + (set_span >> 1); - next_in_base += set_span; - out_ptr_low = next_out_base; - next_out_base += set_span; - out_ptr_high = next_out_base; + out_ptr = next_out_base; cos_msin_ptr = *table_ptr_ptr; /* Loop over all the butterfly pairs in the current set */ - do + for (i = 0; i < (set_span >> 1); i += 2) { - cos_even = (*cos_msin_ptr).cosine; - msin_even = (*cos_msin_ptr++).minus_sine; - *out_ptr_low++ = cos_even * *in_ptr_low - msin_even * *in_ptr_high; - *--out_ptr_high = msin_even * *in_ptr_low++ + cos_even * *in_ptr_high++; - - cos_odd = (*cos_msin_ptr).cosine; - msin_odd = (*cos_msin_ptr++).minus_sine; - *out_ptr_low++ = cos_odd * *in_ptr_low + msin_odd * *in_ptr_high; - *--out_ptr_high = msin_odd * *in_ptr_low++ - cos_odd * *in_ptr_high++; + cos_even = cos_msin_ptr[i].cosine; + msin_even = cos_msin_ptr[i].minus_sine; + cos_odd = cos_msin_ptr[i + 1].cosine; + msin_odd = cos_msin_ptr[i + 1].minus_sine; + out_ptr[i] = cos_even*in_ptr_low[i] - msin_even*in_ptr_high[i]; + out_ptr[set_span - 1 - i] = msin_even*in_ptr_low[i] + cos_even*in_ptr_high[i]; + out_ptr[i + 1] = cos_odd*in_ptr_low[i + 1] + msin_odd*in_ptr_high[i + 1]; + out_ptr[set_span - 2 - i] = msin_odd*in_ptr_low[i + 1] - cos_odd*in_ptr_high[i + 1]; } - while (out_ptr_low < out_ptr_high); + next_in_base += set_span; + next_out_base += set_span; } /* Swap input and output buffers for next time */ diff --git a/libs/libg722_1/src/dct4_a.c b/libs/libg722_1/src/dct4_a.c index 0f9c90eba0..d4ed1504e1 100644 --- a/libs/libg722_1/src/dct4_a.c +++ b/libs/libg722_1/src/dct4_a.c @@ -6,29 +6,23 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: dct4_a.c,v 1.8 2008/09/30 14:06:39 steveu Exp $ */ -/********************************************************************************* -* Filename: dct_type_iv_a.c -* -* Purpose: Discrete Cosine Transform, Type IV used for MLT -* -* The basis functions are -* -* cos(PI*(t+0.5)*(k+0.5)/block_length) -* -* for time t and basis function number k. Due to the symmetry of the expression -* in t and k, it is clear that the forward and inverse transforms are the same. -* -*********************************************************************************/ +/* Discrete Cosine Transform, Type IV used for MLT + + The basis functions are + + cos(PI*(t+0.5)*(k+0.5)/block_length) + + for time t and basis function number k. Due to the symmetry of the + expression in t and k, it is clear that the forward and inverse transforms + are the same. */ /*! \file */ @@ -47,51 +41,31 @@ #include "dct4_a.h" -/********************************************************************************* - Function: dct_type_iv_a - - Syntax: void dct_type_iv_a (input, output, dct_length) - int16_t input[], output[], dct_length; - - Description: Discrete Cosine Transform, Type IV used for MLT -*********************************************************************************/ - +/* Discrete Cosine Transform, Type IV used for MLT */ void dct_type_iv_a(int16_t input[], int16_t output[], int dct_length) { int16_t buffer_a[MAX_DCT_LENGTH]; int16_t buffer_b[MAX_DCT_LENGTH]; int16_t buffer_c[MAX_DCT_LENGTH]; int16_t *in_ptr; - int16_t *in_ptr_low; - int16_t *in_ptr_high; - int16_t *next_in_base; - int16_t *out_ptr_low; - int16_t *out_ptr_high; - int16_t *next_out_base; - int16_t *out_buffer; + int16_t *out_ptr; int16_t *in_buffer; + int16_t *out_buffer; int16_t *buffer_swap; int16_t in_val_low; int16_t in_val_high; - int16_t out_val_low; - int16_t out_val_high; int16_t in_low_even; int16_t in_low_odd; int16_t in_high_even; int16_t in_high_odd; - int16_t out_low_even; - int16_t out_low_odd; - int16_t out_high_even; - int16_t out_high_odd; int16_t *pair_ptr; int16_t cos_even; int16_t cos_odd; int16_t msin_even; int16_t msin_odd; - int16_t neg_cos_odd; - int16_t neg_msin_even; int32_t sum; int16_t set_span; + int16_t half_span; int16_t set_count; int16_t set_count_log; int16_t pairs_left; @@ -99,15 +73,15 @@ void dct_type_iv_a(int16_t input[], int16_t output[], int dct_length) int16_t i; int16_t k; int16_t index; - const cos_msin_t **table_ptr_ptr; - const cos_msin_t *cos_msin_ptr; int16_t temp; int32_t acca; int16_t dct_length_log; + const cos_msin_t **table_ptr_ptr; + const cos_msin_t *cos_msin_ptr; - /* Do the sum/difference butterflies, the first part of */ - /* converting one N-point transform into N/2 two-point */ - /* transforms, where N = 1 << DCT_LENGTH_LOG. = 64/128 */ + /* Do the sum/difference butterflies, the first part of + converting one N-point transform into N/2 two-point + transforms, where N = 1 << DCT_LENGTH_LOG. = 64/128 */ if (dct_length == DCT_LENGTH) { dct_length_log = DCT_LENGTH_LOG; @@ -123,62 +97,45 @@ void dct_type_iv_a(int16_t input[], int16_t output[], int dct_length) index = 0L; in_buffer = input; out_buffer = buffer_a; - temp = sub(dct_length_log, 2); + temp = dct_length_log - 2; for (set_count_log = 0; set_count_log <= temp; set_count_log++) { - /* Initialization for the loop over sets at the current size */ - /* set_span = 1 << (DCT_LENGTH_LOG - set_count_log); */ - set_span = shr(dct_length, set_count_log); - - set_count = shl(1, set_count_log); + /* Loop over all the sets at the current size */ + set_span = dct_length >> set_count_log; + set_count = 1 << set_count_log; + half_span = set_span >> 1; in_ptr = in_buffer; - next_out_base = out_buffer; + out_ptr = out_buffer; - /* Loop over all the sets of this size */ for (sets_left = set_count; sets_left > 0; sets_left--) { - /* Set up output pointers for the current set */ - out_ptr_low = next_out_base; - next_out_base = next_out_base + set_span; - out_ptr_high = next_out_base; - /* Loop over all the butterflies in the current set */ - do + for (i = 0; i < half_span; i++) { - in_val_low = *in_ptr++; - in_val_high = *in_ptr++; - acca = L_add(in_val_low, in_val_high); - acca = L_shr(acca, 1); - out_val_low = (int16_t) acca; + in_val_low = *in_ptr++; + in_val_high = *in_ptr++; - acca = L_sub(in_val_low, in_val_high); - acca = L_shr(acca, 1); - out_val_high = (int16_t) acca; + acca = L_add(in_val_low, in_val_high); + out_ptr[i] = (int16_t) L_shr(acca, 1); - *out_ptr_low++ = out_val_low; - *--out_ptr_high = out_val_high; + acca = L_sub(in_val_low, in_val_high); + out_ptr[set_span - 1 - i] = (int16_t) L_shr(acca, 1); } - while (out_ptr_low < out_ptr_high); + out_ptr += set_span; } - /* Decide which buffers to use as input and output next time. */ - /* Except for the first time (when the input buffer is the */ - /* subroutine input) we just alternate the local buffers. */ + /* Decide which buffers to use as input and output next time. + Except for the first time (when the input buffer is the + subroutine input) we just alternate the local buffers. */ in_buffer = out_buffer; - if (out_buffer == buffer_a) - out_buffer = buffer_b; - else - out_buffer = buffer_a; + out_buffer = (out_buffer == buffer_a) ? buffer_b : buffer_a; index = add(index, 1); } - /* Do N/2 two-point transforms, */ - /* where N = 1 << DCT_LENGTH_LOG */ + /* Do N/2 two-point transforms, where N = 1 << DCT_LENGTH_LOG */ pair_ptr = in_buffer; buffer_swap = buffer_c; - temp = sub(dct_length_log, 1); - temp = shl(1, temp); - + temp = 1 << (dct_length_log - 1); for (pairs_left = temp; pairs_left > 0; pairs_left--) { for (k = 0; k < CORE_SIZE; k++) @@ -188,7 +145,6 @@ void dct_type_iv_a(int16_t input[], int16_t output[], int dct_length) sum = L_mac(sum, pair_ptr[i], dct_core_a[i][k]); buffer_swap[k] = xround(sum); } - /* Address arithmetic */ pair_ptr += CORE_SIZE; buffer_swap += CORE_SIZE; } @@ -202,77 +158,53 @@ void dct_type_iv_a(int16_t input[], int16_t output[], int dct_length) temp = sub(dct_length_log, 2); for (set_count_log = temp; set_count_log >= 0; set_count_log--) { - /* Initialization for the loop over sets at the current size */ - /* set_span = 1 << (DCT_LENGTH_LOG - set_count_log); */ - set_span = shr(dct_length, set_count_log); - set_count = shl(1, set_count_log); - next_in_base = in_buffer; - next_out_base = (set_count_log == 0) ? output : out_buffer; + /* Loop over all the sets at the current size */ + set_span = dct_length >> set_count_log; + set_count = 1 << set_count_log; + half_span = set_span >> 1; + in_ptr = in_buffer; + out_ptr = (set_count_log == 0) ? output : out_buffer; + cos_msin_ptr = *table_ptr_ptr++; - /* Loop over all the sets of this size */ for (sets_left = set_count; sets_left > 0; sets_left--) { - /* Set up the pointers for the current set */ - in_ptr_low = next_in_base; - temp = shr(set_span, 1); - - /* Address arithmetic */ - in_ptr_high = in_ptr_low + temp; - next_in_base += set_span; - out_ptr_low = next_out_base; - next_out_base += set_span; - out_ptr_high = next_out_base; - cos_msin_ptr = *table_ptr_ptr; - /* Loop over all the butterfly pairs in the current set */ - do + for (i = 0; i < half_span; i += 2) { - /* Address arithmetic */ - in_low_even = *in_ptr_low++; - in_low_odd = *in_ptr_low++; - in_high_even = *in_ptr_high++; - in_high_odd = *in_ptr_high++; - cos_even = cos_msin_ptr[0].cosine; - msin_even = cos_msin_ptr[0].minus_sine; - cos_odd = cos_msin_ptr[1].cosine; - msin_odd = cos_msin_ptr[1].minus_sine; - cos_msin_ptr += 2; + in_low_even = in_ptr[i]; + in_low_odd = in_ptr[i + 1]; + in_high_even = in_ptr[half_span + i]; + in_high_odd = in_ptr[half_span + i + 1]; - sum = 0L; - sum = L_mac(sum, cos_even, in_low_even); - neg_msin_even = negate(msin_even); - sum = L_mac(sum, neg_msin_even, in_high_even); - out_low_even = xround(sum); + cos_even = cos_msin_ptr[i].cosine; + msin_even = cos_msin_ptr[i].minus_sine; + cos_odd = cos_msin_ptr[i + 1].cosine; + msin_odd = cos_msin_ptr[i + 1].minus_sine; - sum = 0L; - sum = L_mac(sum, msin_even,in_low_even); + sum = L_mult(cos_even, in_low_even); + sum = L_mac(sum, -msin_even, in_high_even); + out_ptr[i] = xround(sum); + + sum = L_mult(msin_even,in_low_even); sum = L_mac(sum, cos_even, in_high_even); - out_high_even = xround(sum); + out_ptr[set_span - 1 - i] = xround(sum); - sum = 0L; - sum = L_mac(sum, cos_odd, in_low_odd); + sum = L_mult(cos_odd, in_low_odd); sum = L_mac(sum, msin_odd, in_high_odd); - out_low_odd = xround(sum); + out_ptr[i + 1] = xround(sum); - sum = 0L; - sum = L_mac(sum, msin_odd, in_low_odd); - neg_cos_odd = negate(cos_odd); - sum = L_mac(sum, neg_cos_odd, in_high_odd); - out_high_odd = xround(sum); - - *out_ptr_low++ = out_low_even; - *--out_ptr_high = out_high_even; - *out_ptr_low++ = out_low_odd; - *--out_ptr_high = out_high_odd; + sum = L_mult(msin_odd, in_low_odd); + sum = L_mac(sum, -cos_odd, in_high_odd); + out_ptr[set_span - 2 - i] = xround(sum); } - while (out_ptr_low < out_ptr_high); + in_ptr += set_span; + out_ptr += set_span; } /* Swap input and output buffers for next time */ buffer_swap = in_buffer; in_buffer = out_buffer; out_buffer = buffer_swap; - table_ptr_ptr++; } } /*- End of function --------------------------------------------------------*/ diff --git a/libs/libg722_1/src/dct4_a.h b/libs/libg722_1/src/dct4_a.h index bcc63bf29d..4d4b95c68e 100644 --- a/libs/libg722_1/src/dct4_a.h +++ b/libs/libg722_1/src/dct4_a.h @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: dct4_a.h,v 1.4 2008/09/25 15:56:31 steveu Exp $ */ typedef struct diff --git a/libs/libg722_1/src/dct4_s.c b/libs/libg722_1/src/dct4_s.c index 71151b3f14..c195693cef 100644 --- a/libs/libg722_1/src/dct4_s.c +++ b/libs/libg722_1/src/dct4_s.c @@ -6,29 +6,23 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: dct4_s.c,v 1.8 2008/09/30 14:06:39 steveu Exp $ */ -/******************************************************************************** -* Filename: dct_type_iv_s.c -* -* Purpose: Discrete Cosine Transform, Type IV used for inverse MLT -* -* The basis functions are -* -* cos(PI*(t+0.5)*(k+0.5)/block_length) -* -* for time t and basis function number k. Due to the symmetry of the expression -* in t and k, it is clear that the forward and inverse transforms are the same. -* -*********************************************************************************/ +/* Discrete Cosine Transform, Type IV used for inverse MLT + + The basis functions are + + cos(PI*(t+0.5)*(k+0.5)/block_length) + + for time t and basis function number k. Due to the symmetry of the + expression in t and k, it is clear that the forward and inverse transforms + are the same. */ /*! \file */ @@ -45,67 +39,51 @@ #if defined(G722_1_USE_FIXED_POINT) #include "dct4_s.h" +#include "utilities.h" -/******************************************************************************** - Function: dct_type_iv_s - - Syntax: void dct_type_iv_s (int16_t *input,int16_t *output,int16_t dct_length) - - - Description: Discrete Cosine Transform, Type IV used for inverse MLT -********************************************************************************/ +/* Discrete Cosine Transform, Type IV used for inverse MLT */ void dct_type_iv_s(int16_t input[], int16_t output[], int dct_length) { int16_t buffer_a[MAX_DCT_LENGTH]; int16_t buffer_b[MAX_DCT_LENGTH]; int16_t buffer_c[MAX_DCT_LENGTH]; int16_t *in_ptr; - int16_t *in_ptr_low; - int16_t *in_ptr_high; - int16_t *next_in_base; - int16_t *out_ptr_low; - int16_t *out_ptr_high; - int16_t *next_out_base; - int16_t *out_buffer; + int16_t *out_ptr; int16_t *in_buffer; + int16_t *out_buffer; int16_t *buffer_swap; int16_t in_val_low; int16_t in_val_high; - int16_t out_val_low; - int16_t out_val_high; int16_t in_low_even; int16_t in_low_odd; int16_t in_high_even; int16_t in_high_odd; - int16_t out_low_even; - int16_t out_low_odd; - int16_t out_high_even; - int16_t out_high_odd; int16_t *pair_ptr; int16_t cos_even; int16_t cos_odd; int16_t msin_even; int16_t msin_odd; int16_t set_span; + int16_t half_span; int16_t set_count; int16_t set_count_log; int16_t pairs_left; int16_t sets_left; int16_t i; + int16_t j; int16_t k; int16_t index; int16_t dummy; + int16_t dct_length_log; int32_t sum; + int32_t acca; const cos_msin_t **table_ptr_ptr; const cos_msin_t *cos_msin_ptr; - int32_t acca; - int16_t temp; - int16_t dct_length_log; const int16_t *dither_ptr; - /* Do the sum/difference butterflies, the first part of */ - /* converting one N-point transform into 32 - 10 point transforms */ - /* transforms, where N = 1 << DCT_LENGTH_LOG. */ + /* Do the sum/difference butterflies, the first part of + converting one N-point transform into 32 - 10 point transforms + transforms, where N = 1 << DCT_LENGTH_LOG. */ if (dct_length == DCT_LENGTH) { dct_length_log = DCT_LENGTH_LOG; @@ -122,92 +100,61 @@ void dct_type_iv_s(int16_t input[], int16_t output[], int dct_length) index = 0; i = 0; + j = 0; for (set_count_log = 0; set_count_log <= dct_length_log - 2; set_count_log++) { - /* Initialization for the loop over sets at the current size */ - /* set_span = 1 << (DCT_LENGTH_LOG - set_count_log); */ - set_span = shr(dct_length, set_count_log); - - set_count = shl(1, set_count_log); + /* Loop over all the sets at the current size */ + set_span = dct_length >> set_count_log; + set_count = 1 << set_count_log; + half_span = set_span >> 1; in_ptr = in_buffer; - next_out_base = out_buffer; + out_ptr = out_buffer; - /* Loop over all the sets of this size */ - temp = sub(index, 1); - if (temp < 0) + if (index < 1) { for (sets_left = set_count; sets_left > 0; sets_left--) { - /* Set up output pointers for the current set */ - /* pointer arithmetic */ - out_ptr_low = next_out_base; - next_out_base += set_span; - out_ptr_high = next_out_base; - /* Loop over all the butterflies in the current set */ - do + for (i = 0; i < half_span; i++) { in_val_low = *in_ptr++; in_val_high = *in_ptr++; - /* BEST METHOD OF GETTING RID OF BIAS, BUT COMPUTATIONALLY UNPLEASANT */ - /* ALTERNATIVE METHOD, SMEARS BIAS OVER THE ENTIRE FRAME, COMPUTATIONALLY SIMPLEST. */ - /* IF THIS WORKS, IT'S PREFERABLE */ - - dummy = add(in_val_low, dither_ptr[i++]); + dummy = add(in_val_low, dither_ptr[j++]); acca = L_add(dummy, in_val_high); - out_val_low = (int16_t) L_shr(acca, 1); + out_ptr[i] = (int16_t) L_shr(acca, 1); - dummy = add(in_val_low, dither_ptr[i++]); - acca = L_add(dummy, -in_val_high); - out_val_high = (int16_t) L_shr(acca, 1); - - *out_ptr_low++ = out_val_low; - *--out_ptr_high = out_val_high; - - /* this involves comparison of pointers */ - /* pointer arithmetic */ + dummy = add(in_val_low, dither_ptr[j++]); + acca = L_sub(dummy, in_val_high); + out_ptr[set_span - 1 - i] = (int16_t) L_shr(acca, 1); } - while (out_ptr_low < out_ptr_high); + out_ptr += set_span; } } else { for (sets_left = set_count; sets_left > 0; sets_left--) { - /* Set up output pointers for the current set */ - out_ptr_low = next_out_base; - next_out_base += set_span; - out_ptr_high = next_out_base; - /* Loop over all the butterflies in the current set */ - do + for (i = 0; i < half_span; i++) { in_val_low = *in_ptr++; in_val_high = *in_ptr++; - out_val_low = add(in_val_low, in_val_high); - out_val_high = add(in_val_low, negate(in_val_high)); - - *out_ptr_low++ = out_val_low; - *--out_ptr_high = out_val_high; + out_ptr[i] = add(in_val_low, in_val_high); + out_ptr[set_span - 1 - i] = sub(in_val_low, in_val_high); } - while (out_ptr_low < out_ptr_high); + out_ptr += set_span; } } - /* Decide which buffers to use as input and output next time. */ - /* Except for the first time (when the input buffer is the */ - /* subroutine input) we just alternate the local buffers. */ + /* Decide which buffers to use as input and output next time. + Except for the first time (when the input buffer is the + subroutine input) we just alternate the local buffers. */ in_buffer = out_buffer; - - if (out_buffer == buffer_a) - out_buffer = buffer_b; - else - out_buffer = buffer_a; - - index = add(index, 1); + out_buffer = (out_buffer == buffer_a) ? buffer_b : buffer_a; + index++; } /* Do 32 - 10 point transforms */ @@ -228,8 +175,7 @@ void dct_type_iv_s(int16_t input[], int16_t output[], int dct_length) buffer_swap += CORE_SIZE; } - for (i = 0; i < dct_length; i++) - in_buffer[i] = buffer_c[i]; + vec_copyi16(in_buffer, buffer_c, dct_length); table_ptr_ptr = s_cos_msin_table; @@ -238,90 +184,61 @@ void dct_type_iv_s(int16_t input[], int16_t output[], int dct_length) for (set_count_log = dct_length_log - 2; set_count_log >= 0; set_count_log--) { /* Initialization for the loop over sets at the current size */ - /* set_span = 1 << (DCT_LENGTH_LOG - set_count_log); */ - set_span = shr(dct_length, set_count_log); - - set_count = shl(1, set_count_log); - next_in_base = in_buffer; - if (set_count_log == 0) - next_out_base = output; - else - next_out_base = out_buffer; + set_span = dct_length >> set_count_log; + set_count = 1 << set_count_log; + half_span = set_span >> 1; + in_ptr = in_buffer; + out_ptr = (set_count_log == 0) ? output : out_buffer; + cos_msin_ptr = *table_ptr_ptr++; /* Loop over all the sets of this size */ for (sets_left = set_count; sets_left > 0; sets_left--) { - /* Set up the pointers for the current set */ - in_ptr_low = next_in_base; - temp = shr(set_span, 1); - in_ptr_high = in_ptr_low + temp; - next_in_base += set_span; - out_ptr_low = next_out_base; - next_out_base += set_span; - out_ptr_high = next_out_base; - cos_msin_ptr = *table_ptr_ptr; - /* Loop over all the butterfly pairs in the current set */ - do + for (i = 0; i < half_span; i += 2) { - in_low_even = *in_ptr_low++; - in_low_odd = *in_ptr_low++; - in_high_even = *in_ptr_high++; - in_high_odd = *in_ptr_high++; - cos_even = cos_msin_ptr[0].cosine; - msin_even = cos_msin_ptr[0].minus_sine; - cos_odd = cos_msin_ptr[1].cosine; - msin_odd = cos_msin_ptr[1].minus_sine; - cos_msin_ptr += 2; + in_low_even = in_ptr[i]; + in_low_odd = in_ptr[i + 1]; + in_high_even = in_ptr[half_span + i]; + in_high_odd = in_ptr[half_span + i + 1]; - sum = 0L; - sum = L_mac(sum, cos_even, in_low_even); - sum = L_mac(sum, negate(msin_even), in_high_even); - out_low_even = xround(L_shl(sum, 1)); + cos_even = cos_msin_ptr[i].cosine; + msin_even = cos_msin_ptr[i].minus_sine; + cos_odd = cos_msin_ptr[i + 1].cosine; + msin_odd = cos_msin_ptr[i + 1].minus_sine; - sum = 0L; - sum = L_mac(sum, msin_even, in_low_even); + sum = L_mult(cos_even, in_low_even); + sum = L_mac(sum, -msin_even, in_high_even); + out_ptr[i] = xround(L_shl(sum, 1)); + + sum = L_mult(msin_even, in_low_even); sum = L_mac(sum, cos_even, in_high_even); - out_high_even = xround(L_shl(sum, 1)); + out_ptr[set_span - 1 - i] = xround(L_shl(sum, 1)); - sum = 0L; - sum = L_mac(sum, cos_odd, in_low_odd); + sum = L_mult(cos_odd, in_low_odd); sum = L_mac(sum, msin_odd, in_high_odd); - out_low_odd = xround(L_shl(sum, 1)); + out_ptr[i + 1] = xround(L_shl(sum, 1)); - sum = 0L; - sum = L_mac(sum, msin_odd, in_low_odd); - sum = L_mac(sum, negate(cos_odd), in_high_odd); - out_high_odd = xround(L_shl(sum, 1)); - - *out_ptr_low++ = out_low_even; - *--out_ptr_high = out_high_even; - *out_ptr_low++ = out_low_odd; - *--out_ptr_high = out_high_odd; + sum = L_mult(msin_odd, in_low_odd); + sum = L_mac(sum, -cos_odd, in_high_odd); + out_ptr[set_span - 2 - i] = xround(L_shl(sum, 1)); } - while (out_ptr_low < out_ptr_high); + in_ptr += set_span; + out_ptr += set_span; } /* Swap input and output buffers for next time */ buffer_swap = in_buffer; in_buffer = out_buffer; out_buffer = buffer_swap; - - index = add(index, 1); - table_ptr_ptr++; + index++; } - /* ADD IN BIAS FOR OUTPUT */ + /* Add in bias for output */ if (dct_length == DCT_LENGTH) { - for (i = 0; i < 320; i++) + for (i = 0; i < DCT_LENGTH; i++) { sum = L_add(output[i], syn_bias_7khz[i]); - acca = L_sub(sum, 32767); - if (acca > 0) - sum = 32767L; - acca = L_add(sum, 32768L); - if (acca < 0) - sum = -32768L; - output[i] = (int16_t) sum; + output[i] = saturate(sum); } } } diff --git a/libs/libg722_1/src/dct4_s.h b/libs/libg722_1/src/dct4_s.h index 68040d0659..533be1c7b9 100644 --- a/libs/libg722_1/src/dct4_s.h +++ b/libs/libg722_1/src/dct4_s.h @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: dct4_s.h,v 1.4 2008/09/25 15:56:31 steveu Exp $ */ typedef struct @@ -196,11 +194,9 @@ static const int16_t max_dither[MAX_DCT_LENGTH] = for (index = 0;index < length;index++) { angle = scale * ((double)index + 0.5); - table[index].cosine = (short) (FTOI((18427)* cos(angle))); - table[index].minus_sine = (short) (FTOI((18427)*(-sin(angle)))); + table[index].cosine = (int16_t) (FTOI((18427)* cos(angle))); + table[index].minus_sine = (int16_t) (FTOI((18427)*(-sin(angle)))); } - - ********************************************************************************/ static const cos_msin_t s_cos_msin_2[DCT_LENGTH_DIV_32] = diff --git a/libs/libg722_1/src/decoder.c b/libs/libg722_1/src/decoder.c index 80fcab4d5a..f1db32f282 100644 --- a/libs/libg722_1/src/decoder.c +++ b/libs/libg722_1/src/decoder.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C)2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: decoder.c,v 1.21 2008/11/21 15:30:22 steveu Exp $ */ /*! \file */ @@ -94,9 +92,7 @@ static void decoder(g722_1_decode_state_t *s, int16_t old_decoder_mlt_coefs[], int frame_error_flag); -/*************************************************************************** - Description: Decodes the out_words into mlt coefs using G.722.1 Annex C -***************************************************************************/ +/* Decodes the out_words into MLT coefs using G.722.1 Annex C */ void decoder(g722_1_decode_state_t *s, int16_t number_of_regions, int16_t decoder_mlt_coefs[], @@ -109,11 +105,11 @@ void decoder(g722_1_decode_state_t *s, int16_t absolute_region_power_index[MAX_NUMBER_OF_REGIONS]; int16_t decoder_power_categories[MAX_NUMBER_OF_REGIONS]; int16_t decoder_category_balances[MAX_NUM_CATEGORIZATION_CONTROL_POSSIBILITIES - 1]; - uint16_t categorization_control; int16_t num_categorization_control_bits; int16_t num_categorization_control_possibilities; int16_t number_of_coefs; int16_t number_of_valid_coefs; + uint16_t categorization_control; number_of_valid_coefs = number_of_regions*REGION_SIZE; @@ -184,9 +180,7 @@ void decoder(g722_1_decode_state_t *s, } /*- End of function --------------------------------------------------------*/ -/*************************************************************************** - Description: Recover differential_region_power_index from code bits -***************************************************************************/ +/* Recover differential_region_power_index from code bits */ static void decode_envelope(g722_1_decode_state_t *s, int16_t number_of_regions, int16_t *decoder_region_standard_deviation, @@ -262,7 +256,7 @@ static void decode_envelope(g722_1_decode_state_t *s, while ((i >= 0) && ((temp1 >= 0) || (temp2 > 0))) { i = sub(i, 1); - temp = shr(temp, 1); + temp >>= 1; max_index = sub(max_index, 2); temp1 = sub(temp, 8); temp2 = sub(max_index, 28); @@ -365,12 +359,12 @@ static void decode_vector_quantized_mlt_indices(g722_1_decode_state_t *s, if (g722_1_bitstream_get(&s->bitstream, &(s->code_ptr), 1) == 0) { temp = shl(index, 1); - index = (int16_t) *(decoder_table_ptr + temp); + index = decoder_table_ptr[temp]; } else { temp = shl(index, 1); - index = (int16_t) *(decoder_table_ptr + temp + 1); + index = decoder_table_ptr[temp + 1]; } s->number_of_bits_left--; } @@ -406,7 +400,7 @@ static void decode_vector_quantized_mlt_indices(g722_1_decode_state_t *s, { if ((signs_index & bit) == 0) decoder_mlt_value = negate(decoder_mlt_value); - bit = shr(bit, 1); + bit >>= 1; } *decoder_mlt_ptr++ = decoder_mlt_value; } @@ -440,7 +434,7 @@ static void decode_vector_quantized_mlt_indices(g722_1_decode_state_t *s, if (*decoder_mlt_ptr == 0) { *decoder_mlt_ptr = ((random_word & 1) == 0) ? noifillneg : noifillpos; - random_word = shr(random_word, 1); + random_word >>= 1; } /* pointer arithmetic */ decoder_mlt_ptr++; @@ -451,7 +445,7 @@ static void decode_vector_quantized_mlt_indices(g722_1_decode_state_t *s, if (*decoder_mlt_ptr == 0) { *decoder_mlt_ptr = ((random_word & 1) == 0) ? noifillneg : noifillpos; - random_word = shr(random_word,1); + random_word >>= 1; } /* pointer arithmetic */ decoder_mlt_ptr++; diff --git a/libs/libg722_1/src/decoderf.c b/libs/libg722_1/src/decoderf.c index 761a0cff30..e0e8e61743 100644 --- a/libs/libg722_1/src/decoderf.c +++ b/libs/libg722_1/src/decoderf.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: decoderf.c,v 1.22 2008/11/21 15:30:22 steveu Exp $ */ /*! \file */ @@ -33,6 +31,7 @@ #include "huff_tab.h" #include "tables.h" #include "bitstream.h" +#include "utilities.h" #if !defined(G722_1_USE_FIXED_POINT) @@ -84,12 +83,12 @@ static void decoder(g722_1_decode_state_t *s, int absolute_region_power_index[MAX_NUMBER_OF_REGIONS]; int decoder_power_categories[MAX_NUMBER_OF_REGIONS]; int decoder_category_balances[MAX_NUM_CATEGORIZATION_CONTROL_POSSIBILITIES - 1]; - int rate_control; int num_categorization_control_bits; int num_categorization_control_possibilities; int number_of_coefs; int number_of_valid_coefs; int rmlt_scale_factor; + int rate_control; number_of_valid_coefs = s->number_of_regions*REGION_SIZE; @@ -451,7 +450,7 @@ static void decode_vector_quantized_mlt_indices(g722_1_decode_state_t *s, if (category == NUM_CATEGORIES - 1) { - noifillpos = standard_deviation*0.70711f; + noifillpos = standard_deviation*0.70711; noifillneg = -noifillpos; /* This assumes region_size = 20 */ @@ -555,27 +554,21 @@ static void error_handling(int number_of_coefs, float *decoder_mlt_coefs, float *old_decoder_mlt_coefs) { - int i; - /* If both the current and previous frames are errored, set the mlt coefficients to 0. If only the current frame is errored, repeat the previous frame's MLT coefficients. */ if (*frame_error_flag) { - for (i = 0; i < number_of_valid_coefs; i++) - decoder_mlt_coefs[i] = old_decoder_mlt_coefs[i]; - for (i = 0; i < number_of_valid_coefs; i++) - old_decoder_mlt_coefs[i] = 0.0f; + vec_copyf(decoder_mlt_coefs, old_decoder_mlt_coefs, number_of_valid_coefs); + vec_zerof(old_decoder_mlt_coefs, number_of_valid_coefs); } else { /* Store in case the next frame has errors. */ - for (i = 0; i < number_of_valid_coefs; i++) - old_decoder_mlt_coefs[i] = decoder_mlt_coefs[i]; + vec_copyf(old_decoder_mlt_coefs, decoder_mlt_coefs, number_of_valid_coefs); } /* Zero out the upper 1/8 of the spectrum. */ - for (i = number_of_valid_coefs; i < number_of_coefs; i++) - decoder_mlt_coefs[i] = 0.0f; + vec_zerof(&decoder_mlt_coefs[number_of_valid_coefs], number_of_coefs - number_of_valid_coefs); } /*- End of function --------------------------------------------------------*/ diff --git a/libs/libg722_1/src/defs.h b/libs/libg722_1/src/defs.h index 7a565d0565..9c2c83dd10 100644 --- a/libs/libg722_1/src/defs.h +++ b/libs/libg722_1/src/defs.h @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: defs.h,v 1.16 2008/10/01 15:31:10 steveu Exp $ */ #define MAX(a,b) (a > b ? a : b) diff --git a/libs/libg722_1/src/encoder.c b/libs/libg722_1/src/encoder.c index fef4b44883..054d6b36bd 100644 --- a/libs/libg722_1/src/encoder.c +++ b/libs/libg722_1/src/encoder.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: encoder.c,v 1.26 2008/11/21 15:30:22 steveu Exp $ */ /*! \file */ @@ -32,6 +30,7 @@ #include "huff_tab.h" #include "tables.h" #include "bitstream.h" +#include "utilities.h" #if defined(G722_1_USE_FIXED_POINT) @@ -99,9 +98,8 @@ static void bits_to_words(g722_1_encode_state_t *s, drp_num_bits[number_of_regions] = num_categorization_control_bits; drp_code_bits[number_of_regions] = categorization_control; - bit_count = 0; /* These code bits are right justified. */ - for (region = 0; region <= number_of_regions; region++) + for (bit_count = 0, region = 0; region <= number_of_regions; region++) { g722_1_bitstream_put(&s->bitstream, &out_code, drp_code_bits[region], drp_num_bits[region]); bit_count += drp_num_bits[region]; @@ -247,14 +245,11 @@ void adjust_abs_region_power_index(int16_t *absolute_region_power_index, for (region = 0; region < number_of_regions; region++) { - n = sub(absolute_region_power_index[region], 39); - n = shr(n, 1); + n = sub(absolute_region_power_index[region], 39) >> 1; if (n > 0) { temp = (int16_t) L_mult0(region, REGION_SIZE); - raw_mlt_ptr = &mlt_coefs[temp]; - for (i = 0; i < REGION_SIZE; i++) { acca = L_shl(*raw_mlt_ptr, 16); @@ -264,8 +259,7 @@ void adjust_abs_region_power_index(int16_t *absolute_region_power_index, *raw_mlt_ptr++ = (int16_t) acca; } - temp = sub(absolute_region_power_index[region], shl(n, 1)); - absolute_region_power_index[region] = temp; + absolute_region_power_index[region] = sub(absolute_region_power_index[region], shl(n, 1)); } } } @@ -281,7 +275,6 @@ static int16_t compute_region_powers(int16_t *mlt_coefs, { int16_t *input_ptr; int32_t long_accumulator; - int16_t itemp1; int16_t power_shift; int16_t region; int16_t j; @@ -295,12 +288,8 @@ static int16_t compute_region_powers(int16_t *mlt_coefs, input_ptr = mlt_coefs; for (region = 0; region < number_of_regions; region++) { - long_accumulator = 0; - for (j = 0; j < REGION_SIZE; j++) - { - itemp1 = *input_ptr++; - long_accumulator = L_mac0(long_accumulator, itemp1, itemp1); - } + long_accumulator = vec_dot_prodi16(input_ptr, input_ptr, REGION_SIZE); + input_ptr += REGION_SIZE; power_shift = 0; acca = long_accumulator & 0x7FFF0000L; @@ -348,7 +337,7 @@ static int16_t compute_region_powers(int16_t *mlt_coefs, } /* The MLT is currently scaled too low by the factor - ENCODER_SCALE_FACTOR(=18318)/32768 * (1./sqrt(160). + ENCODER_SCALE_FACTOR(=18318)/32768 * (1.0/sqrt(160). This is the ninth power of 1 over the square root of 2. So later we will add ESF_ADJUSTMENT_TO_RMS_INDEX (now 9) to drp_code_bits[0]. */ @@ -520,7 +509,8 @@ static int16_t vector_huffman(int16_t category, int16_t num_vecs; int16_t kmax; int16_t kmax_plus_one; - int16_t index,signs_index; + int16_t index; + int16_t signs_index; const int16_t *bitcount_table_ptr; const uint16_t *code_table_ptr; int32_t code_bits; diff --git a/libs/libg722_1/src/encoderf.c b/libs/libg722_1/src/encoderf.c index 36a52064f0..2589886aa3 100644 --- a/libs/libg722_1/src/encoderf.c +++ b/libs/libg722_1/src/encoderf.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: encoderf.c,v 1.22 2008/11/21 15:30:22 steveu Exp $ */ /*! \file */ @@ -33,6 +31,7 @@ #include "huff_tab.h" #include "tables.h" #include "bitstream.h" +#include "utilities.h" #if !defined(G722_1_USE_FIXED_POINT) @@ -218,7 +217,6 @@ static int compute_region_powers(int number_of_regions, float *input_ptr; int iterations; float ftemp0; - float ftemp1; int index; int index_min; int index_max; @@ -230,13 +228,9 @@ static int compute_region_powers(int number_of_regions, input_ptr = mlt_coefs; for (region = 0; region < number_of_regions; region++) { - ftemp0 = 0.0f; - for (j = 0; j < REGION_SIZE; j++) - { - ftemp1 = *input_ptr++; - ftemp0 += ftemp1*ftemp1; - } + ftemp0 = vec_dot_prodf(input_ptr, input_ptr, REGION_SIZE); ftemp0 *= REGION_SIZE_INVERSE; + input_ptr += REGION_SIZE; index_min = 0; index_max = REGION_POWER_TABLE_SIZE; @@ -260,7 +254,7 @@ static int compute_region_powers(int number_of_regions, } /* The MLT is currently scaled too low by the factor - ENCODER_SCALE_FACTOR(=18318)/32768 * (1./sqrt(160). + ENCODER_SCALE_FACTOR(=18318)/32768 * (1.0/sqrt(160). This is the ninth power of 1 over the square root of 2. So later we will add ESF_ADJUSTMENT_TO_RMS_INDEX (now 9) to drp_code_bits[0]. */ @@ -448,7 +442,7 @@ static int vector_huffman(int category, number_of_non_zero = 0; for (j = 0; j < vec_dim; j++) { - k = (int) (fabs(*raw_mlt_ptr) * inv_of_step_size_times_std_dev + dead_zone[category]); + k = (int) (fabs(*raw_mlt_ptr)*inv_of_step_size_times_std_dev + dead_zone[category]); if (k != 0) { number_of_non_zero++; @@ -458,12 +452,12 @@ static int vector_huffman(int category, if (k > kmax) k = kmax; } - index = index*(kmax_plus_one) + k; + index = index*kmax_plus_one + k; raw_mlt_ptr++; } - code_bits = *(code_table_ptr + index); - number_of_code_bits = *(bitcount_table_ptr + index) + number_of_non_zero; + code_bits = code_table_ptr[index]; + number_of_code_bits = bitcount_table_ptr[index] + number_of_non_zero; number_of_region_bits += number_of_code_bits; code_bits = (code_bits << number_of_non_zero) + signs_index; diff --git a/libs/libg722_1/src/g722_1.h.in b/libs/libg722_1/src/g722_1.h.in index e4a1e415b1..86c0921a65 100644 --- a/libs/libg722_1/src/g722_1.h.in +++ b/libs/libg722_1/src/g722_1.h.in @@ -7,8 +7,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * $Id: g722_1.h.in,v 1.1.1.1 2008/09/20 09:47:17 steveu Exp $ */ /*! \file */ diff --git a/libs/libg722_1/src/g722_1/g722_1.h b/libs/libg722_1/src/g722_1/g722_1.h index 3408abbf31..6f2a497eb1 100644 --- a/libs/libg722_1/src/g722_1/g722_1.h +++ b/libs/libg722_1/src/g722_1/g722_1.h @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: g722_1.h,v 1.14 2008/10/17 13:18:21 steveu Exp $ */ #if !defined(_G722_1_G722_1_H_) diff --git a/libs/libg722_1/src/g722_1/version.h.in b/libs/libg722_1/src/g722_1/version.h.in index f9c66d0745..e825425ce9 100644 --- a/libs/libg722_1/src/g722_1/version.h.in +++ b/libs/libg722_1/src/g722_1/version.h.in @@ -9,8 +9,6 @@ * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: version.h.in,v 1.2 2008/09/20 16:52:51 steveu Exp $ */ #if !defined(_G722_1_VERSION_H_) diff --git a/libs/libg722_1/src/huff_tab.c b/libs/libg722_1/src/huff_tab.c index 07f5085b35..3583ba30ff 100644 --- a/libs/libg722_1/src/huff_tab.c +++ b/libs/libg722_1/src/huff_tab.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: huff_tab.c,v 1.7 2008/09/30 14:06:40 steveu Exp $ */ /*! \file */ diff --git a/libs/libg722_1/src/huff_tab.h b/libs/libg722_1/src/huff_tab.h index a58b843f5e..3d58962c83 100644 --- a/libs/libg722_1/src/huff_tab.h +++ b/libs/libg722_1/src/huff_tab.h @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: huff_tab.h,v 1.4 2008/09/30 14:06:40 steveu Exp $ */ #define REGION_POWER_STEPSIZE_DB 3.010299957 diff --git a/libs/libg722_1/src/make_dct4_tables.c b/libs/libg722_1/src/make_dct4_tables.c index 015daf355a..ffb4a94063 100644 --- a/libs/libg722_1/src/make_dct4_tables.c +++ b/libs/libg722_1/src/make_dct4_tables.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: make_dct4_tables.c,v 1.2 2008/10/02 11:43:54 steveu Exp $ */ /*! \file */ @@ -29,7 +27,11 @@ #include "g722_1/g722_1.h" +#if defined(PI) +#undef PI +#endif #define PI 3.141592653589793238462 + #include "defs.h" static void set_up_one_table(int length) @@ -99,6 +101,7 @@ int main(int argc, char *argv[]) for (i = 0; i <= length_log; i++) set_up_one_table(dct_size << i); + return 0; } /*- End of function --------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/ diff --git a/libs/libg722_1/src/make_tables.c b/libs/libg722_1/src/make_tables.c index d234d8a8a0..aa6d5cb748 100644 --- a/libs/libg722_1/src/make_tables.c +++ b/libs/libg722_1/src/make_tables.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: make_tables.c,v 1.5 2008/11/21 15:30:22 steveu Exp $ */ /*! \file */ @@ -37,6 +35,7 @@ #undef PI #endif #define PI 3.141592653589793238462 + /* These may have been defined in the main header for the codec, so we clear out any pre-existing definitions here. */ #if defined(ENCODER_SCALE_FACTOR) @@ -124,7 +123,7 @@ static void generate_sam2coef_tables(void) for (i = 0; i < DCT_LENGTH; i++) { angle = (PI/2.0)*((double) i + 0.5)/(double) DCT_LENGTH; - printf(" %.15e,\n", sin(angle)); + printf(" %.15ef,\n", sin(angle)); } printf("};\n\n"); @@ -132,7 +131,7 @@ static void generate_sam2coef_tables(void) for (i = 0; i < MAX_DCT_LENGTH; i++) { angle = (PI/2.0)*((double) i + 0.5)/(double) MAX_DCT_LENGTH; - printf(" %.15le,\n", sin(angle)); + printf(" %.15ef,\n", sin(angle)); } printf("};\n\n"); @@ -180,7 +179,7 @@ static void generate_coef2sam_tables(void) for (i = 0; i < DCT_LENGTH; i++) { angle = (PI/2.0)*((double) i + 0.5)/(double) DCT_LENGTH; - printf(" %.15e,\n", sin(angle)); + printf(" %.15ef,\n", sin(angle)); } printf("};\n\n"); @@ -188,7 +187,7 @@ static void generate_coef2sam_tables(void) for (i = 0; i < MAX_DCT_LENGTH; i++) { angle = (PI/2.0)*((double) i + 0.5)/(double) MAX_DCT_LENGTH; - printf(" %.15e,\n", sin(angle)); + printf(" %.15ef,\n", sin(angle)); } printf("};\n\n"); @@ -218,7 +217,7 @@ int main(int argc, char *argv[]) for (i = 0; i < REGION_POWER_TABLE_SIZE; i++) { value = pow(10.0, 0.10*REGION_POWER_STEPSIZE_DB*(i - REGION_POWER_TABLE_NUM_NEGATIVES)); - printf(" %.15e,\n", sqrt(value)); + printf(" %.15ef,\n", sqrt(value)); } printf("};\n\n"); @@ -226,7 +225,7 @@ int main(int argc, char *argv[]) for (i = 0; i < REGION_POWER_TABLE_SIZE; i++) { value = pow(10.0, 0.10*REGION_POWER_STEPSIZE_DB*(i - REGION_POWER_TABLE_NUM_NEGATIVES)); - printf(" %.15e,\n", 1.0/sqrt(value)); + printf(" %.15ef,\n", 1.0/sqrt(value)); } printf("};\n\n"); @@ -259,14 +258,14 @@ int main(int argc, char *argv[]) printf("const float step_size[NUM_CATEGORIES] =\n{\n"); for (i = 0; i < NUM_CATEGORIES; i++) { - printf(" %.15e,\n", step_size[i]); + printf(" %.15ef,\n", step_size[i]); } printf("};\n\n"); printf("const float step_size_inverse_table[NUM_CATEGORIES] =\n{\n"); for (i = 0; i < NUM_CATEGORIES; i++) { - printf(" %.15e,\n", 1.0/step_size[i]); + printf(" %.15ef,\n", 1.0/step_size[i]); } printf("};\n\n"); @@ -275,7 +274,7 @@ int main(int argc, char *argv[]) for (i = 0; i < REGION_POWER_TABLE_SIZE; i++) { value = pow(10.0, 0.10*REGION_POWER_STEPSIZE_DB*(i - REGION_POWER_TABLE_NUM_NEGATIVES)); - printf(" %.15e,\n", value); + printf(" %.15ef,\n", value); } printf("};\n\n"); @@ -283,9 +282,10 @@ int main(int argc, char *argv[]) for (i = 0; i < REGION_POWER_TABLE_SIZE - 1; i++) { value = (float) pow(10.0, 0.10*REGION_POWER_STEPSIZE_DB*(0.5 + (i - REGION_POWER_TABLE_NUM_NEGATIVES))); - printf(" %.15e,\n", value); + printf(" %.15ef,\n", value); } printf("};\n\n"); + return 0; } /*- End of function --------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/ diff --git a/libs/libg722_1/src/sam2coef.c b/libs/libg722_1/src/sam2coef.c index 50f61d27ce..604c2874c8 100644 --- a/libs/libg722_1/src/sam2coef.c +++ b/libs/libg722_1/src/sam2coef.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: sam2coef.c,v 1.12 2008/10/02 11:43:54 steveu Exp $ */ /*! \file */ @@ -29,17 +27,16 @@ #include "defs.h" #include "sam2coef.h" +#include "utilities.h" -/************************************************************************************ - Purpose: Convert Samples to Reversed MLT (Modulated Lapped Transform) Coefficients +/* Convert Samples to Reversed MLT (Modulated Lapped Transform) Coefficients - The "Reversed MLT" is an overlapped block transform which uses even symmetry - on the left, odd symmetry on the right and a Type IV DCT as the block transform. - It is thus similar to a MLT which uses odd symmetry on the left, even symmetry - on the right and a Type IV DST as the block transform. In fact, it is equivalent - to reversing the order of the samples, performing an MLT and then negating all - the even-numbered coefficients. -***************************************************************************/ + The "Reversed MLT" is an overlapped block transform which uses even symmetry + on the left, odd symmetry on the right and a Type IV DCT as the block transform. + It is thus similar to a MLT which uses odd symmetry on the left, even symmetry + on the right and a Type IV DST as the block transform. In fact, it is equivalent + to reversing the order of the samples, performing an MLT and then negating all + the even-numbered coefficients. */ #if defined(G722_1_USE_FIXED_POINT) int16_t samples_to_rmlt_coefs(const int16_t new_samples[], @@ -62,34 +59,26 @@ int16_t samples_to_rmlt_coefs(const int16_t new_samples[], half_dct_length = dct_length >> 1; - if (dct_length == DCT_LENGTH) - win = samples_to_rmlt_window; - else - win = max_samples_to_rmlt_window; + win = (dct_length == DCT_LENGTH) ? samples_to_rmlt_window : max_samples_to_rmlt_window; /* Get the first half of the windowed samples */ last = half_dct_length - 1; for (i = 0; i < half_dct_length; i++) { - acca = 0L; - acca = L_mac(acca, win[last - i], old_samples[last - i]); + acca = L_mult(win[last - i], old_samples[last - i]); acca = L_mac(acca, win[half_dct_length + i], old_samples[half_dct_length + i]); - temp = xround(acca); - windowed_data[i] = temp; + windowed_data[i] = xround(acca); } /* Get the second half of the windowed samples */ last = dct_length - 1; for (i = 0; i < half_dct_length; i++) { - acca = 0L; - acca = L_mac(acca, win[last - i], new_samples[i]); + acca = L_mult(win[last - i], new_samples[i]); acca = L_mac(acca, negate(win[i]), new_samples[last - i]); - temp = xround(acca); - windowed_data[half_dct_length + i] = temp; + windowed_data[half_dct_length + i] = xround(acca); } /* Save the new samples for next time, when they will be the old samples. */ - for (i = 0; i < dct_length; i++) - old_samples[i] = new_samples[i]; + vec_copyi16(old_samples, new_samples, dct_length); /* Calculate how many bits to shift up the input to the DCT. */ temp1 = 0; @@ -156,10 +145,7 @@ void samples_to_rmlt_coefs(const float new_samples[], half_dct_length = dct_length >> 1; - if (dct_length == DCT_LENGTH) - win = samples_to_rmlt_window; - else - win = max_samples_to_rmlt_window; + win = (dct_length == DCT_LENGTH) ? samples_to_rmlt_window : max_samples_to_rmlt_window; /* Get the first half of the windowed samples. */ last = half_dct_length - 1; for (i = 0; i < half_dct_length; i++) @@ -177,8 +163,7 @@ void samples_to_rmlt_coefs(const float new_samples[], windowed_data[half_dct_length + i] = sum; } /* Save the new samples for next time, when they will be the old samples. */ - for (i = 0; i < dct_length; i++) - old_samples[i] = new_samples[i]; + vec_copyf(old_samples, new_samples, dct_length); /* Perform a Type IV DCT on the windowed data to get the coefficients. */ dct_type_iv(windowed_data, coefs, dct_length); diff --git a/libs/libg722_1/src/sam2coef.h b/libs/libg722_1/src/sam2coef.h index 26f3cbaa02..1df19bb48f 100644 --- a/libs/libg722_1/src/sam2coef.h +++ b/libs/libg722_1/src/sam2coef.h @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: sam2coef.h,v 1.2 2008/10/02 11:43:54 steveu Exp $ */ #if defined(G722_1_USE_FIXED_POINT) diff --git a/libs/libg722_1/src/tables.c b/libs/libg722_1/src/tables.c index 62a0e8d808..a0eed803bf 100644 --- a/libs/libg722_1/src/tables.c +++ b/libs/libg722_1/src/tables.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: tables.c,v 1.11 2008/09/30 14:06:40 steveu Exp $ */ /*! \file */ @@ -65,70 +63,70 @@ const int16_t int_region_standard_deviation_table[REGION_POWER_TABLE_SIZE] = #else const float region_standard_deviation_table[REGION_POWER_TABLE_SIZE] = { - 2.441406247570224e-04f, - 3.452669826719395e-04f, - 4.882812495545411e-04f, - 6.905339654011486e-04f, - 9.765624991900746e-04f, - 1.381067930916839e-03f, - 1.953124998542134e-03f, - 2.762135862062757e-03f, - 3.906249997408239e-03f, - 5.524271724583683e-03f, - 7.812499995464418e-03f, - 1.104854345008369e-02f, - 1.562499999222472e-02f, - 2.209708690200003e-02f, - 3.124999998704119e-02f, - 4.419417380766535e-02f, - 6.249999997926591e-02f, - 8.838834762266132e-02f, - 1.249999999688989e-01f, - 1.767766952599839e-01f, - 2.499999999585318e-01f, - 3.535533905492901e-01f, - 4.999999999585318e-01f, - 7.071067811572251e-01f, - 1.000000000000000e+00f, - 1.414213562431740e+00f, - 2.000000000165873e+00f, - 2.828427125098059e+00f, - 4.000000000663491e+00f, - 5.656854250665278e+00f, - 8.000000001990472e+00f, - 1.131370850226887e+01f, - 1.600000000530792e+01f, - 2.262741700641438e+01f, - 3.200000001326981e+01f, - 4.525483401658204e+01f, - 6.400000003184756e+01f, - 9.050966804067060e+01f, - 1.280000000743110e+02f, - 1.810193360963542e+02f, - 2.560000001698536e+02f, - 3.620386722227349e+02f, - 5.120000003821707e+02f, - 7.240773445055215e+02f, - 1.024000000849268e+03f, - 1.448154689131149e+03f, - 2.048000001868390e+03f, - 2.896309378502505e+03f, - 4.096000004076487e+03f, - 5.792618757485434e+03f, - 8.192000008832390e+03f, - 1.158523751593169e+04f, - 1.638400001902361e+04f, - 2.317047503378509e+04f, - 3.276800004076484e+04f, - 4.634095007141347e+04f, - 6.553600008696507e+04f, - 9.268190015051374e+04f, - 1.310720001848009e+05f, - 1.853638003164007e+05f, - 2.621440003913428e+05f, - 3.707276006635486e+05f, - 5.242880008261676e+05f, - 7.414552013885899e+05f + 2.441406247570224e-04, + 3.452669826719395e-04, + 4.882812495545411e-04, + 6.905339654011486e-04, + 9.765624991900746e-04, + 1.381067930916839e-03, + 1.953124998542134e-03, + 2.762135862062757e-03, + 3.906249997408239e-03, + 5.524271724583683e-03, + 7.812499995464418e-03, + 1.104854345008369e-02, + 1.562499999222472e-02, + 2.209708690200003e-02, + 3.124999998704119e-02, + 4.419417380766535e-02, + 6.249999997926591e-02, + 8.838834762266132e-02, + 1.249999999688989e-01, + 1.767766952599839e-01, + 2.499999999585318e-01, + 3.535533905492901e-01, + 4.999999999585318e-01, + 7.071067811572251e-01, + 1.000000000000000e+00, + 1.414213562431740e+00, + 2.000000000165873e+00, + 2.828427125098059e+00, + 4.000000000663491e+00, + 5.656854250665278e+00, + 8.000000001990472e+00, + 1.131370850226887e+01, + 1.600000000530792e+01, + 2.262741700641438e+01, + 3.200000001326981e+01, + 4.525483401658204e+01, + 6.400000003184756e+01, + 9.050966804067060e+01, + 1.280000000743110e+02, + 1.810193360963542e+02, + 2.560000001698536e+02, + 3.620386722227349e+02, + 5.120000003821707e+02, + 7.240773445055215e+02, + 1.024000000849268e+03, + 1.448154689131149e+03, + 2.048000001868390e+03, + 2.896309378502505e+03, + 4.096000004076487e+03, + 5.792618757485434e+03, + 8.192000008832390e+03, + 1.158523751593169e+04, + 1.638400001902361e+04, + 2.317047503378509e+04, + 3.276800004076484e+04, + 4.634095007141347e+04, + 6.553600008696507e+04, + 9.268190015051374e+04, + 1.310720001848009e+05, + 1.853638003164007e+05, + 2.621440003913428e+05, + 3.707276006635486e+05, + 5.242880008261676e+05, + 7.414552013885899e+05 }; #endif @@ -146,70 +144,70 @@ const int16_t standard_deviation_inverse_table[REGION_POWER_TABLE_SIZE] = #else const float standard_deviation_inverse_table[REGION_POWER_TABLE_SIZE] = { - 4.096000004076488e+03f, - 2.896309378502504e+03f, - 2.048000001868390e+03f, - 1.448154689131149e+03f, - 1.024000000849268e+03f, - 7.240773445055215e+02f, - 5.120000003821708e+02f, - 3.620386722227349e+02f, - 2.560000001698537e+02f, - 1.810193360963542e+02f, - 1.280000000743110e+02f, - 9.050966804067060e+01f, - 6.400000003184756e+01f, - 4.525483401658203e+01f, - 3.200000001326982e+01f, - 2.262741700641438e+01f, - 1.600000000530793e+01f, - 1.131370850226887e+01f, - 8.000000001990474e+00f, - 5.656854250665277e+00f, - 4.000000000663491e+00f, - 2.828427125098059e+00f, - 2.000000000165873e+00f, - 1.414213562431740e+00f, - 1.000000000000000e+00f, - 7.071067811572251e-01f, - 4.999999999585318e-01f, - 3.535533905492901e-01f, - 2.499999999585318e-01f, - 1.767766952599838e-01f, - 1.249999999688989e-01f, - 8.838834762266132e-02f, - 6.249999997926592e-02f, - 4.419417380766535e-02f, - 3.124999998704120e-02f, - 2.209708690200002e-02f, - 1.562499999222472e-02f, - 1.104854345008369e-02f, - 7.812499995464418e-03f, - 5.524271724583683e-03f, - 3.906249997408239e-03f, - 2.762135862062757e-03f, - 1.953124998542134e-03f, - 1.381067930916839e-03f, - 9.765624991900747e-04f, - 6.905339654011486e-04f, - 4.882812495545411e-04f, - 3.452669826719394e-04f, - 2.441406247570224e-04f, - 1.726334913216520e-04f, - 1.220703123683871e-04f, - 8.631674565366727e-05f, - 6.103515617913153e-05f, - 4.315837282325419e-05f, - 3.051757808703478e-05f, - 2.157918640983742e-05f, - 1.525878904225187e-05f, - 1.078959320402385e-05f, - 7.629394520493171e-06f, - 5.394796601564505e-06f, - 3.814697259930213e-06f, - 2.697398300558537e-06f, - 1.907348629806920e-06f, - 1.348699150167414e-06f + 4.096000004076488e+03, + 2.896309378502504e+03, + 2.048000001868390e+03, + 1.448154689131149e+03, + 1.024000000849268e+03, + 7.240773445055215e+02, + 5.120000003821708e+02, + 3.620386722227349e+02, + 2.560000001698537e+02, + 1.810193360963542e+02, + 1.280000000743110e+02, + 9.050966804067060e+01, + 6.400000003184756e+01, + 4.525483401658203e+01, + 3.200000001326982e+01, + 2.262741700641438e+01, + 1.600000000530793e+01, + 1.131370850226887e+01, + 8.000000001990474e+00, + 5.656854250665277e+00, + 4.000000000663491e+00, + 2.828427125098059e+00, + 2.000000000165873e+00, + 1.414213562431740e+00, + 1.000000000000000e+00, + 7.071067811572251e-01, + 4.999999999585318e-01, + 3.535533905492901e-01, + 2.499999999585318e-01, + 1.767766952599838e-01, + 1.249999999688989e-01, + 8.838834762266132e-02, + 6.249999997926592e-02, + 4.419417380766535e-02, + 3.124999998704120e-02, + 2.209708690200002e-02, + 1.562499999222472e-02, + 1.104854345008369e-02, + 7.812499995464418e-03, + 5.524271724583683e-03, + 3.906249997408239e-03, + 2.762135862062757e-03, + 1.953124998542134e-03, + 1.381067930916839e-03, + 9.765624991900747e-04, + 6.905339654011486e-04, + 4.882812495545411e-04, + 3.452669826719394e-04, + 2.441406247570224e-04, + 1.726334913216520e-04, + 1.220703123683871e-04, + 8.631674565366727e-05, + 6.103515617913153e-05, + 4.315837282325419e-05, + 3.051757808703478e-05, + 2.157918640983742e-05, + 1.525878904225187e-05, + 1.078959320402385e-05, + 7.629394520493171e-06, + 5.394796601564505e-06, + 3.814697259930213e-06, + 2.697398300558537e-06, + 1.907348629806920e-06, + 1.348699150167414e-06 }; #endif @@ -241,14 +239,14 @@ const float step_size[NUM_CATEGORIES] = const float step_size_inverse_table[NUM_CATEGORIES] = { - 2.82805443e+00f, - 2.00000000e+00f, - 1.41422713e+00f, - 1.00000000e+00f, - 7.07113564e-01f, - 5.00000000e-01f, - 3.53556782e-01f, - 3.53556782e-01f + 2.82805443e+00, + 2.00000000e+00, + 1.41422713e+00, + 1.00000000e+00, + 7.07113564e-01, + 5.00000000e-01, + 3.53556782e-01, + 3.53556782e-01 }; #endif @@ -279,137 +277,137 @@ const float dead_zone[NUM_CATEGORIES] = #if !defined(G722_1_USE_FIXED_POINT) const float region_power_table[REGION_POWER_TABLE_SIZE] = { - 5.96046448e-08f, - 1.19209290e-07f, - 2.38418579e-07f, - 4.76837158e-07f, - 9.53674316e-07f, - 1.90734863e-06f, - 3.81469727e-06f, - 7.62939453e-06f, - 1.52587891e-05f, - 3.05175781e-05f, - 6.10351562e-05f, - 1.22070312e-04f, - 2.44140625e-04f, - 4.88281250e-04f, - 9.76562500e-04f, - 1.95312500e-03f, - 3.90625000e-03f, - 7.81250000e-03f, - 1.56250000e-02f, - 3.12500000e-02f, - 6.25000000e-02f, - 1.25000000e-01f, - 2.50000000e-01f, - 5.00000000e-01f, - 1.00000000e+00f, - 2.00000000e+00f, - 4.00000000e+00f, - 8.00000000e+00f, - 1.60000000e+01f, - 3.20000000e+01f, - 6.40000000e+01f, - 1.28000000e+02f, - 2.56000000e+02f, - 5.12000000e+02f, - 1.02400000e+03f, - 2.04800000e+03f, - 4.09600000e+03f, - 8.19200000e+03f, - 1.63840000e+04f, - 3.27680000e+04f, - 6.55360000e+04f, - 1.31072000e+05f, - 2.62144000e+05f, - 5.24288000e+05f, - 1.04857600e+06f, - 2.09715200e+06f, - 4.19430400e+06f, - 8.38860800e+06f, - 1.67772160e+07f, - 3.35544320e+07f, - 6.71088640e+07f, - 1.34217728e+08f, - 2.68435456e+08f, - 5.36870912e+08f, - 1.07374182e+09f, - 2.14748365e+09f, - 4.29496730e+09f, - 8.58993459e+09f, - 1.71798692e+10f, - 3.43597384e+10f, - 6.87194767e+10f, - 1.37438953e+11f, - 2.74877907e+11f, - 5.49755814e+11f + 5.96046448e-08, + 1.19209290e-07, + 2.38418579e-07, + 4.76837158e-07, + 9.53674316e-07, + 1.90734863e-06, + 3.81469727e-06, + 7.62939453e-06, + 1.52587891e-05, + 3.05175781e-05, + 6.10351562e-05, + 1.22070312e-04, + 2.44140625e-04, + 4.88281250e-04, + 9.76562500e-04, + 1.95312500e-03, + 3.90625000e-03, + 7.81250000e-03, + 1.56250000e-02, + 3.12500000e-02, + 6.25000000e-02, + 1.25000000e-01, + 2.50000000e-01, + 5.00000000e-01, + 1.00000000e+00, + 2.00000000e+00, + 4.00000000e+00, + 8.00000000e+00, + 1.60000000e+01, + 3.20000000e+01, + 6.40000000e+01, + 1.28000000e+02, + 2.56000000e+02, + 5.12000000e+02, + 1.02400000e+03, + 2.04800000e+03, + 4.09600000e+03, + 8.19200000e+03, + 1.63840000e+04, + 3.27680000e+04, + 6.55360000e+04, + 1.31072000e+05, + 2.62144000e+05, + 5.24288000e+05, + 1.04857600e+06, + 2.09715200e+06, + 4.19430400e+06, + 8.38860800e+06, + 1.67772160e+07, + 3.35544320e+07, + 6.71088640e+07, + 1.34217728e+08, + 2.68435456e+08, + 5.36870912e+08, + 1.07374182e+09, + 2.14748365e+09, + 4.29496730e+09, + 8.58993459e+09, + 1.71798692e+10, + 3.43597384e+10, + 6.87194767e+10, + 1.37438953e+11, + 2.74877907e+11, + 5.49755814e+11 }; const float region_power_table_boundary[REGION_POWER_TABLE_SIZE - 1] = { - 8.42936956e-08f, - 1.68587391e-07f, - 3.37174782e-07f, - 6.74349565e-07f, - 1.34869913e-06f, - 2.69739826e-06f, - 5.39479652e-06f, - 1.07895930e-05f, - 2.15791861e-05f, - 4.31583721e-05f, - 8.63167443e-05f, - 1.72633489e-04f, - 3.45266977e-04f, - 6.90533954e-04f, - 1.38106791e-03f, - 2.76213582e-03f, - 5.52427163e-03f, - 1.10485433e-02f, - 2.20970865e-02f, - 4.41941731e-02f, - 8.83883461e-02f, - 1.76776692e-01f, - 3.53553385e-01f, - 7.07106769e-01f, - 1.41421354e+00f, - 2.82842708e+00f, - 5.65685415e+00f, - 1.13137083e+01f, - 2.26274166e+01f, - 4.52548332e+01f, - 9.05096664e+01f, - 1.81019333e+02f, - 3.62038666e+02f, - 7.24077332e+02f, - 1.44815466e+03f, - 2.89630933e+03f, - 5.79261865e+03f, - 1.15852373e+04f, - 2.31704746e+04f, - 4.63409492e+04f, - 9.26818984e+04f, - 1.85363797e+05f, - 3.70727594e+05f, - 7.41455188e+05f, - 1.48291038e+06f, - 2.96582075e+06f, - 5.93164150e+06f, - 1.18632830e+07f, - 2.37265660e+07f, - 4.74531320e+07f, - 9.49062640e+07f, - 1.89812528e+08f, - 3.79625056e+08f, - 7.59250112e+08f, - 1.51850022e+09f, - 3.03700045e+09f, - 6.07400090e+09f, - 1.21480018e+10f, - 2.42960036e+10f, - 4.85920072e+10f, - 9.71840143e+10f, - 1.94368029e+11f, - 3.88736057e+11f + 8.42936956e-08, + 1.68587391e-07, + 3.37174782e-07, + 6.74349565e-07, + 1.34869913e-06, + 2.69739826e-06, + 5.39479652e-06, + 1.07895930e-05, + 2.15791861e-05, + 4.31583721e-05, + 8.63167443e-05, + 1.72633489e-04, + 3.45266977e-04, + 6.90533954e-04, + 1.38106791e-03, + 2.76213582e-03, + 5.52427163e-03, + 1.10485433e-02, + 2.20970865e-02, + 4.41941731e-02, + 8.83883461e-02, + 1.76776692e-01, + 3.53553385e-01, + 7.07106769e-01, + 1.41421354e+00, + 2.82842708e+00, + 5.65685415e+00, + 1.13137083e+01, + 2.26274166e+01, + 4.52548332e+01, + 9.05096664e+01, + 1.81019333e+02, + 3.62038666e+02, + 7.24077332e+02, + 1.44815466e+03, + 2.89630933e+03, + 5.79261865e+03, + 1.15852373e+04, + 2.31704746e+04, + 4.63409492e+04, + 9.26818984e+04, + 1.85363797e+05, + 3.70727594e+05, + 7.41455188e+05, + 1.48291038e+06, + 2.96582075e+06, + 5.93164150e+06, + 1.18632830e+07, + 2.37265660e+07, + 4.74531320e+07, + 9.49062640e+07, + 1.89812528e+08, + 3.79625056e+08, + 7.59250112e+08, + 1.51850022e+09, + 3.03700045e+09, + 6.07400090e+09, + 1.21480018e+10, + 2.42960036e+10, + 4.85920072e+10, + 9.71840143e+10, + 1.94368029e+11, + 3.88736057e+11 }; #endif diff --git a/libs/libg722_1/src/tables.h b/libs/libg722_1/src/tables.h index bf0aacba61..9b39979f18 100644 --- a/libs/libg722_1/src/tables.h +++ b/libs/libg722_1/src/tables.h @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: tables.h,v 1.7 2008/09/26 17:37:31 steveu Exp $ */ #define REGION_POWER_TABLE_SIZE 64 diff --git a/libs/libg722_1/src/utilities.c b/libs/libg722_1/src/utilities.c new file mode 100644 index 0000000000..71cac6caf4 --- /dev/null +++ b/libs/libg722_1/src/utilities.c @@ -0,0 +1,467 @@ +/* + * g722_1 - a library for the G.722.1 and Annex C codecs + * + * utilities.c + * + * Copyright (C) 2006 Steve Underwood + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include + +#if defined(G722_1_USE_MMX) +#include +#endif +#if defined(G722_1_USE_SSE) +#include +#endif +#if defined(G722_1_USE_SSE2) +#include +#endif +#if defined(G722_1_USE_SSE3) +#include +#include +#endif +#if defined(G722_1_USE_SSE4_1) +#include +#endif +#if defined(G722_1_USE_SSE4_2) +#include +#endif +#if defined(G722_1_USE_SSE4A) +#include +#endif +#if defined(G722_1_USE_SSE5) +#include +#endif + +#include "utilities.h" + +#if defined(G722_1_USE_FIXED_POINT) +void vec_copyi16(int16_t z[], const int16_t x[], int n) +{ + int i; + + for (i = 0; i < n; i++) + z[i] = x[i]; +} +/*- End of function --------------------------------------------------------*/ + +int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n) +{ + int32_t z; + +#if defined(__GNUC__) && defined(G722_1_USE_MMX) +#if defined(__x86_64__) + __asm__ __volatile__( + " emms;\n" + " pxor %%mm0,%%mm0;\n" + " leal -32(%%rsi,%%eax,2),%%edx;\n" /* edx = top - 32 */ + + " cmpl %%rdx,%%rsi;\n" + " ja 1f;\n" + + /* Work in blocks of 16 int16_t's until we are near the end */ + " .p2align 2;\n" + "2:\n" + " movq (%%rdi),%%mm1;\n" + " movq (%%rsi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 8(%%rdi),%%mm1;\n" + " movq 8(%%rsi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 16(%%rdi),%%mm1;\n" + " movq 16(%%rsi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 24(%%rdi),%%mm1;\n" + " movq 24(%%rsi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + + " addl $32,%%rsi;\n" + " addl $32,%%rdi;\n" + " cmpl %%rdx,%%rsi;\n" + " jbe 2b;\n" + + " .p2align 2;\n" + "1:\n" + " addl $24,%%rdx;\n" /* Now edx = top - 8 */ + " cmpl %%rdx,%%rsi;\n" + " ja 3f;\n" + + /* Work in blocks of 4 int16_t's until we are near the end */ + " .p2align 2;\n" + "4:\n" + " movq (%%rdi),%%mm1;\n" + " movq (%%rsi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + + " addl $8,%%rsi;\n" + " addl $8,%%rdi;\n" + " cmpl %%rdx,%%rsi;" + " jbe 4b;\n" + + " .p2align 2;\n" + "3:\n" + " addl $4,%%rdx;\n" /* Now edx = top - 4 */ + " cmpl %%rdx,%%rsi;\n" + " ja 5f;\n" + + /* Work in a block of 2 int16_t's */ + " movd (%%rdi),%%mm1;\n" + " movd (%%rsi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + + " addl $4,%%rsi;\n" + " addl $4,%%rdi;\n" + + " .p2align 2;\n" + "5:\n" + " addl $2,%%rdx;\n" /* Now edx = top - 2 */ + " cmpl %%rdx,%%rsi;\n" + " ja 6f;\n" + + /* Deal with the very last int16_t, when n is odd */ + " movswl (%%rdi),%%eax;\n" + " andl $65535,%%eax;\n" + " movd %%eax,%%mm1;\n" + " movswl (%%rsi),%%eax;\n" + " andl $65535,%%eax;\n" + " movd %%eax,%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + + " .p2align 2;\n" + "6:\n" + /* Merge the pieces of the answer */ + " movq %%mm0,%%mm1;\n" + " punpckhdq %%mm0,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + /* Et voila, eax has the final result */ + " movd %%mm0,%%eax;\n" + + " emms;\n" + : "=a" (z) + : "S" (x), "D" (y), "a" (n) + : "cc" + ); +#else + __asm__ __volatile__( + " emms;\n" + " pxor %%mm0,%%mm0;\n" + " leal -32(%%esi,%%eax,2),%%edx;\n" /* edx = top - 32 */ + + " cmpl %%edx,%%esi;\n" + " ja 1f;\n" + + /* Work in blocks of 16 int16_t's until we are near the end */ + " .p2align 2;\n" + "2:\n" + " movq (%%edi),%%mm1;\n" + " movq (%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 8(%%edi),%%mm1;\n" + " movq 8(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 16(%%edi),%%mm1;\n" + " movq 16(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + " movq 24(%%edi),%%mm1;\n" + " movq 24(%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + + " addl $32,%%esi;\n" + " addl $32,%%edi;\n" + " cmpl %%edx,%%esi;\n" + " jbe 2b;\n" + + " .p2align 2;\n" + "1:\n" + " addl $24,%%edx;\n" /* Now edx = top - 8 */ + " cmpl %%edx,%%esi;\n" + " ja 3f;\n" + + /* Work in blocks of 4 int16_t's until we are near the end */ + " .p2align 2;\n" + "4:\n" + " movq (%%edi),%%mm1;\n" + " movq (%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + + " addl $8,%%esi;\n" + " addl $8,%%edi;\n" + " cmpl %%edx,%%esi;" + " jbe 4b;\n" + + " .p2align 2;\n" + "3:\n" + " addl $4,%%edx;\n" /* Now edx = top - 4 */ + " cmpl %%edx,%%esi;\n" + " ja 5f;\n" + + /* Work in a block of 2 int16_t's */ + " movd (%%edi),%%mm1;\n" + " movd (%%esi),%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + + " addl $4,%%esi;\n" + " addl $4,%%edi;\n" + + " .p2align 2;\n" + "5:\n" + " addl $2,%%edx;\n" /* Now edx = top - 2 */ + " cmpl %%edx,%%esi;\n" + " ja 6f;\n" + + /* Deal with the very last int16_t, when n is odd */ + " movswl (%%edi),%%eax;\n" + " andl $65535,%%eax;\n" + " movd %%eax,%%mm1;\n" + " movswl (%%esi),%%eax;\n" + " andl $65535,%%eax;\n" + " movd %%eax,%%mm2;\n" + " pmaddwd %%mm2,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + + " .p2align 2;\n" + "6:\n" + /* Merge the pieces of the answer */ + " movq %%mm0,%%mm1;\n" + " punpckhdq %%mm0,%%mm1;\n" + " paddd %%mm1,%%mm0;\n" + /* Et voila, eax has the final result */ + " movd %%mm0,%%eax;\n" + + " emms;\n" + : "=a" (z) + : "S" (x), "D" (y), "a" (n) + : "cc" + ); +#endif +#else + int i; + + z = 0; + for (i = 0; i < n; i++) + z += (int32_t) x[i]*(int32_t) y[i]; +#endif + return z; +} +/*- End of function --------------------------------------------------------*/ +#else +#if defined(__GNUC__) && defined(G722_1_USE_SSE2) +void vec_copyf(float z[], const float x[], int n) +{ + int i; + __m128 n1; + + if ((i = n & ~3)) + { + for (i -= 4; i >= 0; i -= 4) + { + n1 = _mm_loadu_ps(x + i); + _mm_storeu_ps(z + i, n1); + } + } + /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ + switch (n & 3) + { + case 3: + z[n - 3] = x[n - 3]; + case 2: + z[n - 2] = x[n - 2]; + case 1: + z[n - 1] = x[n - 1]; + } +} +#else +void vec_copyf(float z[], const float x[], int n) +{ + int i; + + for (i = 0; i < n; i++) + z[i] = x[i]; +} +#endif +/*- End of function --------------------------------------------------------*/ + +#if defined(__GNUC__) && defined(G722_1_USE_SSE2) +void vec_zerof(float z[], int n) +{ + int i; + __m128 n1; + + if ((i = n & ~3)) + { + n1 = _mm_setzero_ps(); + for (i -= 4; i >= 0; i -= 4) + _mm_storeu_ps(z + i, n1); + } + /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ + switch (n & 3) + { + case 3: + z[n - 3] = 0; + case 2: + z[n - 2] = 0; + case 1: + z[n - 1] = 0; + } +} +#else +void vec_zerof(float z[], int n) +{ + int i; + + for (i = 0; i < n; i++) + z[i] = 0.0f; +} +#endif +/*- End of function --------------------------------------------------------*/ + +void vec_subf(float z[], const float x[], const float y[], int n) +{ + int i; + + for (i = 0; i < n; i++) + z[i] = x[i] - y[i]; +} +/*- End of function --------------------------------------------------------*/ + +#if defined(__GNUC__) && defined(G722_1_USE_SSE2) +void vec_mulf(float z[], const float x[], const float y[], int n) +{ + int i; + __m128 n1; + __m128 n2; + __m128 n3; + + if ((i = n & ~3)) + { + for (i -= 4; i >= 0; i -= 4) + { + n1 = _mm_loadu_ps(x + i); + n2 = _mm_loadu_ps(y + i); + n3 = _mm_mul_ps(n1, n2); + _mm_storeu_ps(z + i, n3); + } + } + /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ + switch (n & 3) + { + case 3: + z[n - 3] = x[n - 3]*y[n - 3]; + case 2: + z[n - 2] = x[n - 2]*y[n - 2]; + case 1: + z[n - 1] = x[n - 1]*y[n - 1]; + } +} +#else +void vec_mulf(float z[], const float x[], const float y[], int n) +{ + int i; + + for (i = 0; i < n; i++) + z[i] = x[i]*y[i]; +} +#endif +/*- End of function --------------------------------------------------------*/ + +#if defined(__GNUC__) && defined(G722_1_USE_SSE2) +float vec_dot_prodf(const float x[], const float y[], int n) +{ + int i; + float z; + __m128 n1; + __m128 n2; + __m128 n3; + __m128 n4; + + z = 0.0f; + if ((i = n & ~3)) + { + n4 = _mm_setzero_ps(); //sets sum to zero + for (i -= 4; i >= 0; i -= 4) + { + n1 = _mm_loadu_ps(x + i); + n2 = _mm_loadu_ps(y + i); + n3 = _mm_mul_ps(n1, n2); + n4 = _mm_add_ps(n4, n3); + } + n4 = _mm_add_ps(_mm_movehl_ps(n4, n4), n4); + n4 = _mm_add_ss(_mm_shuffle_ps(n4, n4, 1), n4); + _mm_store_ss(&z, n4); + } + /* Now deal with the last 1 to 3 elements, which don't fill an SSE2 register */ + switch (n & 3) + { + case 3: + z += x[n - 3]*y[n - 3]; + case 2: + z += x[n - 2]*y[n - 2]; + case 1: + z += x[n - 1]*y[n - 1]; + } + return z; +} +#else +float vec_dot_prodf(const float x[], const float y[], int n) +{ + int i; + float z; + + z = 0.0f; + for (i = 0; i < n; i++) + z += x[i]*y[i]; + return z; +} +/*- End of function --------------------------------------------------------*/ +#endif + +void vec_scalar_mulf(float z[], const float x[], float y, int n) +{ + int i; + + for (i = 0; i < n; i++) + z[i] = x[i]*y; +} +/*- End of function --------------------------------------------------------*/ + +void vec_scaled_addf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n) +{ + int i; + + for (i = 0; i < n; i++) + z[i] = x[i]*x_scale + y[i]*y_scale; +} +/*- End of function --------------------------------------------------------*/ + +void vec_scaled_subf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n) +{ + int i; + + for (i = 0; i < n; i++) + z[i] = x[i]*x_scale - y[i]*y_scale; +} +/*- End of function --------------------------------------------------------*/ +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/libg722_1/src/utilities.h b/libs/libg722_1/src/utilities.h new file mode 100644 index 0000000000..9d17103a16 --- /dev/null +++ b/libs/libg722_1/src/utilities.h @@ -0,0 +1,32 @@ +/* + * g722_1 - a library for the G.722.1 and Annex C codecs + * + * utilities.h + * + * Copyright (C) 2006 Steve Underwood + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if !defined(__UTILITIES_H__) +#define __UTILITIES_H__ + +/* Prototypes for some general purpose signal and vector functions */ +#if defined(G722_1_USE_FIXED_POINT) +void vec_copyi16(int16_t z[], const int16_t x[], int n); +int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n); +#else +void vec_copyf(float z[], const float x[], int n); +void vec_zerof(float z[], int n); +void vec_subf(float z[], const float x[], const float y[], int n); +void vec_scalar_mulf(float z[], const float x[], float y, int n); +void vec_mulf(float z[], const float x[], const float y[], int n); +float vec_dot_prodf(const float x[], const float y[], int n); +void vec_scaled_addf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n); +void vec_scaled_subf(float z[], const float x[], float x_scale, const float y[], float y_scale, int n); +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/libg722_1/test-data/Makefile.am b/libs/libg722_1/test-data/Makefile.am index 83ddb94843..0b27a6830d 100644 --- a/libs/libg722_1/test-data/Makefile.am +++ b/libs/libg722_1/test-data/Makefile.am @@ -15,8 +15,6 @@ ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -## -## $Id: Makefile.am,v 1.2 2008/09/20 16:31:19 steveu Exp $ SUBDIRS = itu local diff --git a/libs/libg722_1/test-data/itu/Makefile.am b/libs/libg722_1/test-data/itu/Makefile.am index ae990154c0..df51ad0a07 100644 --- a/libs/libg722_1/test-data/itu/Makefile.am +++ b/libs/libg722_1/test-data/itu/Makefile.am @@ -15,8 +15,6 @@ ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -## -## $Id: Makefile.am,v 1.3 2008/09/23 16:03:04 steveu Exp $ SUBDIRS = diff --git a/libs/libg722_1/test-data/local/Makefile.am b/libs/libg722_1/test-data/local/Makefile.am index a7aca423c5..142fb4cc4e 100644 --- a/libs/libg722_1/test-data/local/Makefile.am +++ b/libs/libg722_1/test-data/local/Makefile.am @@ -15,8 +15,6 @@ ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -## -## $Id: Makefile.am,v 1.3 2008/09/24 16:12:52 steveu Exp $ SUBDIRS = diff --git a/libs/libg722_1/tests/Makefile.am b/libs/libg722_1/tests/Makefile.am index afad2f6433..aec0cecc29 100644 --- a/libs/libg722_1/tests/Makefile.am +++ b/libs/libg722_1/tests/Makefile.am @@ -15,8 +15,6 @@ ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -## -## $Id: Makefile.am,v 1.4 2008/10/19 04:05:02 steveu Exp $ AM_CFLAGS = $(COMP_VENDOR_CFLAGS) AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS) @@ -33,8 +31,8 @@ LIBDIR = -L$(top_builddir)/src noinst_PROGRAMS = g722_1_tests -noinst_HEADERS = itu_bit_stream.c \ +noinst_HEADERS = g192_bit_stream.h \ timing.h -g722_1_tests_SOURCES = g722_1_tests.c itu_bit_stream.c +g722_1_tests_SOURCES = g722_1_tests.c g192_bit_stream.c g722_1_tests_LDADD = $(LIBDIR) -lg722_1 diff --git a/libs/libg722_1/tests/g192_bit_stream.c b/libs/libg722_1/tests/g192_bit_stream.c new file mode 100644 index 0000000000..36a853c6cc --- /dev/null +++ b/libs/libg722_1/tests/g192_bit_stream.c @@ -0,0 +1,177 @@ +/* + * broadvoice - a library for the BroadVoice 16 and 32 codecs + * + * g192_bit_stream.c + * + * Copyright 2008-2009 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*! \file */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "g192_bit_stream.h" + +#if !defined(FALSE) +#define FALSE 0 +#endif +#if !defined(TRUE) +#define TRUE (!FALSE) +#endif + +enum +{ + G192_FRAME_ERASURE = 0x6B20, + G192_FRAME_SYNC_1 = 0x6B21, + G192_FRAME_SYNC_2 = 0x6B22, + G192_FRAME_SYNC_3 = 0x6B23, + G192_FRAME_SYNC_4 = 0x6B24, + G192_FRAME_SYNC_5 = 0x6B25, + G192_FRAME_SYNC_6 = 0x6B26, + G192_FRAME_SYNC_7 = 0x6B27, + G192_FRAME_SYNC_8 = 0x6B28, + G192_FRAME_SYNC_9 = 0x6B29, + G192_FRAME_SYNC_10 = 0x6B2A, + G192_FRAME_SYNC_11 = 0x6B2B, + G192_FRAME_SYNC_12 = 0x6B2C, + G192_FRAME_SYNC_13 = 0x6B2D, + G192_FRAME_SYNC_14 = 0x6B2E, + G192_FRAME_SYNC_15 = 0x6B2F, + G192_HARD_ZERO = 0x7F, + G192_INDETERMINATE = 0x00, + G192_HARD_ONE = 0x81 +}; + +int itu_codec_bitstream_write(const uint8_t out_data[], + int number_of_bits, + int mode, + FILE *fp_bitstream) +{ + int i; + int j; + int bit_count; + int number_of_bytes; + uint8_t packed_word; + int16_t out_array[2 + number_of_bits + 7]; + + number_of_bytes = (number_of_bits + 7)/8; + if (mode == ITU_CODEC_BITSTREAM_PACKED) + { + return fwrite(out_data, 1, number_of_bytes, fp_bitstream); + } + j = 0; + out_array[j++] = G192_FRAME_SYNC_1; + out_array[j++] = number_of_bits; + for (i = 0; i < number_of_bytes; i++) + { + packed_word = out_data[i]; + for (bit_count = 7; bit_count >= 0; bit_count--) + out_array[j++] = ((packed_word >> bit_count) & 1) ? G192_HARD_ONE : G192_HARD_ZERO; + } + + return fwrite(out_array, sizeof(int16_t), number_of_bits + 2, fp_bitstream); +} +/*- End of function --------------------------------------------------------*/ + +int itu_codec_bitstream_read(uint8_t in_data[], + int16_t *erasure, + int number_of_bits, + int mode, + FILE *fp_bitstream) +{ + int i; + int j; + int bit_pos; + int nsamp; + int limit; + int rem; + int len; + int erased_frame; + int16_t packed_word; + int16_t bit; + int16_t in_array[2 + number_of_bits]; + + *erasure = FALSE; + if (mode == ITU_CODEC_BITSTREAM_PACKED) + { + nsamp = fread(in_data, 1, number_of_bits/8, fp_bitstream); + if (nsamp <= 0) + return -1; + return nsamp*8; + } + + nsamp = fread(in_array, sizeof(int16_t), 2, fp_bitstream); + if (nsamp < 2) + return -1; + if (in_array[0] < G192_FRAME_ERASURE || in_array[0] > G192_FRAME_SYNC_15) + { + *erasure = TRUE; + return 0; + } + erased_frame = (in_array[0] == G192_FRAME_ERASURE); + len = in_array[1]; + if (len > number_of_bits) + { + *erasure = TRUE; + return 0; + } + nsamp = fread(in_array, sizeof(int16_t), len, fp_bitstream); + if (nsamp != len) + { + *erasure = TRUE; + return nsamp; + } + + limit = (nsamp + 7)/8; + for (i = 0, j = 0; i < limit; i++) + { + packed_word = 0; + rem = (i == (limit - 1)) ? (limit*8 - nsamp) : 0; + for (bit_pos = 7; bit_pos >= rem; bit_pos--) + { + bit = in_array[j++]; + if (bit >= 0x0001 && bit <= G192_HARD_ZERO) + { + /* Its a zero */ + } + else if (bit >= G192_HARD_ONE && bit <= 0x00FF) + { + /* Its a one */ + packed_word |= (1 << bit_pos); + } + else + { + /* Bad bit */ + *erasure = 1; + } + } + in_data[i] = packed_word; + } + if (erased_frame) + *erasure = TRUE; + return nsamp; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/libg722_1/tests/g192_bit_stream.h b/libs/libg722_1/tests/g192_bit_stream.h new file mode 100644 index 0000000000..1948aa2e80 --- /dev/null +++ b/libs/libg722_1/tests/g192_bit_stream.h @@ -0,0 +1,75 @@ +/* + * broadvoice - a library for the BroadVoice 16 and 32 codecs + * + * g192_bit_stream.h + * + * Copyright 2008-2009 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*! \file */ + +#if !defined(_G192_BIT_STREAM_H_) +#define _G192_BIT_STREAM_H_ + +/*! \page g192_bit_stream_page ITU G.192 codec bit stream handling +\section g192_bit_stream_page_sec_1 What does it do? + +\section g192_bit_stream_page_sec_2 How does it work? +*/ + +enum +{ + ITU_CODEC_BITSTREAM_PACKED = 0, + ITU_CODEC_BITSTREAM_G192 = 1 +}; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! \brief Write a frame of data to an output file. + \param out_data The buffer for the data to be written. + \param number_of_bits The number of bits to be written. + \param mode 0 = continuous, 1 = ITU G.192 codec bitstream format. + \param fp_bitstream The file context to be written to. + \return The number of words written. */ +int itu_codec_bitstream_write(const uint8_t out_data[], + int number_of_bits, + int mode, + FILE *fp_bitstream); + +/*! \brief Read a frame of data from an input file. + \param in_data The buffer for the data to be read. + \param p_erasure Set to TRUE if there is a frame erasure, else set to FALSE. + \param number_of_bits The number of bits to be read. + \param mode 0 = continuous, 1 = ITU G.192 codec bitstream format. + \param fp_bitstream The file context to be read from. + \return The number of words read. */ +int itu_codec_bitstream_read(uint8_t in_data[], + int16_t *p_erasure, + int number_of_bits, + int mode, + FILE *fp_bitstream); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/libg722_1/tests/g722_1_tests.c b/libs/libg722_1/tests/g722_1_tests.c index 9f0b9519f9..7cc6befce1 100644 --- a/libs/libg722_1/tests/g722_1_tests.c +++ b/libs/libg722_1/tests/g722_1_tests.c @@ -6,14 +6,12 @@ * Adapted by Steve Underwood from the reference * code supplied with ITU G.722.1, which is: * - * © 2004 Polycom, Inc. + * (C) 2004 Polycom, Inc. * All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: g722_1_tests.c,v 1.14 2008/11/21 15:30:22 steveu Exp $ */ /*! \file */ @@ -36,7 +34,7 @@ #include #include "timing.h" -#include "itu_bit_stream.h" +#include "g192_bit_stream.h" typedef struct { @@ -227,7 +225,7 @@ static void parse_command_line(char *argv[], coder_control_t *control) } else if (strcasecmp(*argv, "i") == 0) { - control->encoded_format = ITU_CODEC_BITSTREAM_ITU; + control->encoded_format = ITU_CODEC_BITSTREAM_G192; printf("Encoding format = ITU-format bitstream\n"); } else diff --git a/libs/libg722_1/tests/itu_bit_stream.c b/libs/libg722_1/tests/itu_bit_stream.c deleted file mode 100644 index d07ef374eb..0000000000 --- a/libs/libg722_1/tests/itu_bit_stream.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * g722_1 - a library for the G.722.1 and Annex C codecs - * - * itu_bit_stream.c - * - * Adapted by Steve Underwood from the reference - * code supplied with ITU G.722.1, which is: - * - * © 2004 Polycom, Inc. - * All rights reserved. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Id: itu_bit_stream.c,v 1.6 2008/11/21 15:30:22 steveu Exp $ - */ - -/*! \file */ - -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - -#include -#include -#include -#include - -#include "itu_bit_stream.h" - -static const int16_t frame_start = 0x6B21; -static const int16_t erased_frame_start = 0x6B20; -static const int16_t one = 0x0081; -static const int16_t zero = 0x007F; - -void itu_codec_bitstream_write(const uint8_t out_data[], - int number_of_bits, - int mode, - FILE *fp_bitstream) -{ - int i; - int j; - int bit_count; - int number_of_bytes; - uint8_t packed_word; - int16_t out_array[2 + number_of_bits + 7]; - - number_of_bytes = (number_of_bits + 7)/8; - if (mode == ITU_CODEC_BITSTREAM_PACKED) - { - fwrite(out_data, 1, number_of_bytes, fp_bitstream); - return; - } - j = 0; - out_array[j++] = frame_start; - out_array[j++] = number_of_bits; - for (i = 0; i < number_of_bytes; i++) - { - packed_word = out_data[i]; - for (bit_count = 7; bit_count >= 0; bit_count--) - out_array[j++] = ((packed_word >> bit_count) & 1) ? one : zero; - } - - fwrite(out_array, sizeof(int16_t), number_of_bits + 2, fp_bitstream); -} -/*- End of function --------------------------------------------------------*/ - -int itu_codec_bitstream_read(uint8_t in_data[], - int16_t *p_frame_error_flag, - int number_of_bits, - int mode, - FILE *fp_bitstream) -{ - int i; - int j; - int bit_count; - int nsamp; - int len; - int erased_frame; - int16_t packed_word; - int16_t bit; - int16_t in_array[2 + number_of_bits]; - - if (mode == ITU_CODEC_BITSTREAM_PACKED) - return fread(in_data, 1, number_of_bits/8, fp_bitstream)*8; - - nsamp = fread(in_array, sizeof(int16_t), 2, fp_bitstream); - if (nsamp < 2) - return -1; - if (in_array[0] != frame_start && in_array[0] != erased_frame_start) - { - *p_frame_error_flag = 1; - return 0; - } - erased_frame = (in_array[0] == erased_frame_start); - len = in_array[1]; - if (len > number_of_bits) - { - *p_frame_error_flag = 1; - return 0; - } - nsamp = fread(in_array, sizeof(int16_t), len, fp_bitstream); - if (nsamp != len) - { - *p_frame_error_flag = 1; - return nsamp; - } - *p_frame_error_flag = 0; - - for (i = 0, j = 0; i < nsamp/8; i++) - { - packed_word = 0; - bit_count = 7; - while (bit_count >= 0) - { - bit = in_array[j++]; - if (bit == zero) - bit = 0; - else if (bit == one) - bit = 1; - else - { - /* Bad bit */ - bit = 1; - *p_frame_error_flag = 1; - /* printf("read_ITU_format: bit not zero or one: %4x\n", bit); */ - } - packed_word = (packed_word << 1) | bit; - bit_count--; - } - in_data[i] = packed_word; - } - if (erased_frame) - *p_frame_error_flag = 1; - return nsamp; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/libs/libg722_1/tests/regression_tests.sh.in b/libs/libg722_1/tests/regression_tests.sh.in index 6b52213b58..4be36b2008 100644 --- a/libs/libg722_1/tests/regression_tests.sh.in +++ b/libs/libg722_1/tests/regression_tests.sh.in @@ -16,9 +16,6 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# $Id: regression_tests.sh.in,v 1.4 2008/11/21 15:30:22 steveu Exp $ -# STDOUT_DEST=xyzzy STDERR_DEST=xyzzy2 @@ -33,7 +30,7 @@ diff $TMP_FILE ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_enc_out_32000.itu RETVAL=$? if [ $RETVAL != 0 ] then - echo g722_1_tests E failed! + echo g722_1_tests encode failed! exit $RETVAL fi ./g722_1_tests E I 24000 16000 ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_enc_in.pcm $TMP_FILE @@ -41,17 +38,17 @@ diff $TMP_FILE ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_enc_out_24000.itu RETVAL=$? if [ $RETVAL != 0 ] then - echo g722_1_tests E failed! + echo g722_1_tests encode failed! exit $RETVAL fi -echo g722_1_tests E completed OK +echo g722_1_tests encode completed OK ./g722_1_tests D I 24000 16000 ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_enc_out_24000.itu $TMP_FILE diff $TMP_FILE ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_dec_out_24000.pcm RETVAL=$? if [ $RETVAL != 0 ] then - echo g722_1_tests D failed! + echo g722_1_tests decode failed! exit $RETVAL fi ./g722_1_tests D I 32000 16000 ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_enc_out_32000.itu $TMP_FILE @@ -59,7 +56,7 @@ diff $TMP_FILE ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_dec_out_32000.pcm RETVAL=$? if [ $RETVAL != 0 ] then - echo g722_1_tests D failed! + echo g722_1_tests decode failed! exit $RETVAL fi @@ -68,7 +65,7 @@ diff $TMP_FILE ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_dec_out_24000_fe.pcm RETVAL=$? if [ $RETVAL != 0 ] then - echo g722_1_tests D failed! + echo g722_1_tests decode failed! exit $RETVAL fi ./g722_1_tests D I 32000 16000 ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_dec_in_32000_fe.itu $TMP_FILE @@ -76,28 +73,28 @@ diff $TMP_FILE ../test-data/itu/g722_1/$VECTOR_CLASS/g722_1_dec_out_32000_fe.pcm RETVAL=$? if [ $RETVAL != 0 ] then - echo g722_1_tests D failed! + echo g722_1_tests decode failed! exit $RETVAL fi -echo g722_1_tests D completed OK +echo g722_1_tests decode completed OK ./g722_1_tests E I 32000 16000 ../test-data/local/short_wb_voice.wav $TMP_FILE RETVAL=$? if [ $RETVAL != 0 ] then - echo g722_1_tests E failed! + echo g722_1_tests encode failed! exit $RETVAL fi -echo g722_1_tests E completed OK +echo g722_1_tests encode completed OK ./g722_1_tests D I 32000 16000 $TMP_FILE test.au RETVAL=$? if [ $RETVAL != 0 ] then - echo g722_1_tests D failed! + echo g722_1_tests decode failed! exit $RETVAL fi -echo g722_1_tests D completed OK +echo g722_1_tests decode completed OK echo echo All regression tests successfully completed diff --git a/libs/libg722_1/tests/timing.h b/libs/libg722_1/tests/timing.h index 3fb1b3cc74..f95f3b8df1 100644 --- a/libs/libg722_1/tests/timing.h +++ b/libs/libg722_1/tests/timing.h @@ -1,5 +1,5 @@ /* - * SpanDSP - a series of DSP components for telephony + * g722_1 - a library for the G.722.1 and Annex C codecs * * timing.h - Provide access to the Pentium/Athlon TSC timer register * @@ -21,8 +21,6 @@ * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: timing.h,v 1.1 2008/10/17 15:17:39 steveu Exp $ */ #if !defined(_TIMING_H_) diff --git a/libs/libg722_1/unpack_g722_1_data.sh b/libs/libg722_1/unpack_g722_1_data.sh index 75741e0dd1..f8b85f4d30 100755 --- a/libs/libg722_1/unpack_g722_1_data.sh +++ b/libs/libg722_1/unpack_g722_1_data.sh @@ -16,9 +16,6 @@ # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# $Id: unpack_g722_1_data.sh,v 1.2 2008/09/26 12:09:29 steveu Exp $ -# ITUDATA="../../../T-REC-G.722.1-200505-I!!SOFT-ZST-E.zip" diff --git a/libs/openzap/mod_openzap/mod_openzap.c b/libs/openzap/mod_openzap/mod_openzap.c index 8425372ef5..6a75dc85ff 100644 --- a/libs/openzap/mod_openzap/mod_openzap.c +++ b/libs/openzap/mod_openzap/mod_openzap.c @@ -821,7 +821,7 @@ static switch_status_t channel_receive_message_cas(switch_core_session_t *sessio switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_RINGING: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS); } else { zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS); @@ -830,7 +830,7 @@ static switch_status_t channel_receive_message_cas(switch_core_session_t *sessio break; case SWITCH_MESSAGE_INDICATE_PROGRESS: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS); zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA); } else { @@ -841,7 +841,7 @@ static switch_status_t channel_receive_message_cas(switch_core_session_t *sessio break; case SWITCH_MESSAGE_INDICATE_ANSWER: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED); } else { /* lets make the ozmod_r2 module life easier by moving thru each @@ -888,7 +888,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session, switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_RINGING: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS); } else { zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS); @@ -897,7 +897,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session, break; case SWITCH_MESSAGE_INDICATE_PROGRESS: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS); zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_MEDIA); } else { @@ -914,7 +914,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session, break; case SWITCH_MESSAGE_INDICATE_ANSWER: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED); } else { /* Don't skip messages in the ISDN call setup @@ -957,7 +957,7 @@ static switch_status_t channel_receive_message_fxo(switch_core_session_t *sessio switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_PROGRESS: case SWITCH_MESSAGE_INDICATE_ANSWER: - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED); zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS); zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA); @@ -991,7 +991,7 @@ static switch_status_t channel_receive_message_fxs(switch_core_session_t *sessio switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_PROGRESS: case SWITCH_MESSAGE_INDICATE_ANSWER: - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED); zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS); zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA); @@ -1000,7 +1000,7 @@ static switch_status_t channel_receive_message_fxs(switch_core_session_t *sessio } break; case SWITCH_MESSAGE_INDICATE_RINGING: - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { if (!switch_channel_test_flag(channel, CF_ANSWERED) && !switch_channel_test_flag(channel, CF_EARLY_MEDIA) && @@ -1052,7 +1052,7 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_PROGRESS: case SWITCH_MESSAGE_INDICATE_ANSWER: - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { if ((var = switch_channel_get_variable(channel, "openzap_pre_buffer_size"))) { int tmp = atoi(var); if (tmp > -1) { @@ -1327,7 +1327,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi tech_pvt->caller_profile = caller_profile; - switch_channel_set_flag(channel, CF_OUTBOUND); switch_channel_set_state(channel, CS_INIT); if (zap_channel_add_token(zchan, switch_core_session_get_uuid(*new_session), zchan->token_count) != ZAP_SUCCESS) { switch_core_session_destroy(new_session); @@ -1678,7 +1677,9 @@ static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal) switch_clear_flag_locked(tech_pvt, TFLAG_HOLD); } - if (channel_a && channel_b && !switch_channel_test_flag(channel_a, CF_OUTBOUND) && !switch_channel_test_flag(channel_b, CF_OUTBOUND)) { + if (channel_a && channel_b && switch_channel_direction(channel_a) == SWITCH_CALL_DIRECTION_INBOUND && + switch_channel_direction(channel_b) == SWITCH_CALL_DIRECTION_INBOUND) { + cause = SWITCH_CAUSE_ATTENDED_TRANSFER; if (br_a_uuid && br_b_uuid) { switch_ivr_uuid_bridge(br_a_uuid, br_b_uuid); diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index 45387b8585..aba4eef0eb 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -4275,6 +4275,7 @@ static void process_state_iv_eor(t30_state_t *s, const uint8_t *msg, int len) break; case T30_ERR: /* TODO: Continue with the next message if MPS or EOM? */ + s->current_status = T30_ERR_RETRYDCN; s->timer_t5 = 0; send_dcn(s); break; @@ -4319,6 +4320,7 @@ static void process_state_iv_eor_rnr(t30_state_t *s, const uint8_t *msg, int len break; case T30_ERR: /* TODO: Continue with the next message if MPS or EOM? */ + s->current_status = T30_ERR_RETRYDCN; s->timer_t5 = 0; send_dcn(s); break; diff --git a/libs/stfu/stfu.c b/libs/stfu/stfu.c index 547c337278..d2c443a9e7 100644 --- a/libs/stfu/stfu.c +++ b/libs/stfu/stfu.c @@ -33,11 +33,21 @@ # define UINT_MAX 4294967295U #endif +#ifndef UINT16_MAX +# define UINT16_MAX 65535 +#endif + #ifdef _MSC_VER /* warning C4706: assignment within conditional expression*/ #pragma warning(disable: 4706) +/* warning C4996: 'strdup': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _strdup. See online help for details. */ +#pragma warning(disable:4996) #endif +#define least1(_z) (_z ? _z : 1) + +static int stfu_log_level = 7; + struct stfu_queue { struct stfu_frame *array; struct stfu_frame int_frame; @@ -53,13 +63,13 @@ typedef struct stfu_queue stfu_queue_t; struct stfu_instance { struct stfu_queue a_queue; struct stfu_queue b_queue; + struct stfu_queue c_queue; struct stfu_queue *in_queue; struct stfu_queue *out_queue; + struct stfu_queue *old_queue; struct stfu_frame *last_frame; uint32_t cur_ts; - uint32_t cur_seq; uint32_t last_wr_ts; - uint32_t last_wr_seq; uint32_t last_rd_ts; uint32_t samples_per_packet; uint32_t samples_per_second; @@ -76,6 +86,7 @@ struct stfu_instance { uint32_t period_packet_in_count; uint32_t period_packet_out_count; uint32_t period_missing_count; + uint32_t period_need_range; uint32_t period_need_range_avg; uint32_t period_clean_count; @@ -86,25 +97,62 @@ struct stfu_instance { uint32_t session_packet_in_count; uint32_t session_packet_out_count; - uint32_t sync; - + uint32_t sync_out; + uint32_t sync_in; + int32_t ts_offset; + int32_t ts_drift; + int32_t ts_diff; int32_t last_ts_diff; int32_t same_ts; - uint32_t last_seq; - uint32_t period_time; uint32_t decrement_time; uint32_t plc_len; + uint32_t plc_pt; + uint32_t diff; + uint32_t diff_total; + uint8_t ready; + uint8_t debug; + char *name; stfu_n_call_me_t callback; void *udata; }; static void stfu_n_reset_counters(stfu_instance_t *i); +static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...); +static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...); + +stfu_logger_t stfu_log = null_logger; + +int32_t stfu_n_get_drift(stfu_instance_t *i) +{ + return i->ts_drift; +} + +void stfu_global_set_logger(stfu_logger_t logger) +{ + if (logger) { + stfu_log = logger; + } else { + stfu_log = null_logger; + } +} + +void stfu_global_set_default_logger(int level) +{ + if (level < 0 || level > 7) { + level = 7; + } + + stfu_log = default_logger; + stfu_log_level = level; +} + + static stfu_status_t stfu_n_resize_aqueue(stfu_queue_t *queue, uint32_t qlen) { @@ -151,12 +199,27 @@ void stfu_n_destroy(stfu_instance_t **i) if (i && *i) { ii = *i; *i = NULL; + if (ii->name) free(ii->name); free(ii->a_queue.array); free(ii->b_queue.array); + free(ii->c_queue.array); free(ii); } } +void stfu_n_debug(stfu_instance_t *i, const char *name) +{ + if (i->name) free(i->name); + + if (name) { + i->name = strdup(name); + i->debug = 1; + } else { + i->name = strdup("none"); + i->debug = 0; + } +} + void stfu_n_report(stfu_instance_t *i, stfu_report_t *r) { assert(i); @@ -172,7 +235,6 @@ stfu_status_t stfu_n_resize(stfu_instance_t *i, uint32_t qlen) stfu_status_t s; if (i->qlen == i->max_qlen) { - printf("FUCKER1\n"); return STFU_IT_FAILED; } @@ -180,13 +242,14 @@ stfu_status_t stfu_n_resize(stfu_instance_t *i, uint32_t qlen) if (i->qlen < i->max_qlen) { qlen = i->max_qlen; } else { - printf("FUCKER2\n"); return STFU_IT_FAILED; } } if ((s = stfu_n_resize_aqueue(&i->a_queue, qlen)) == STFU_IT_WORKED) { s = stfu_n_resize_aqueue(&i->b_queue, qlen); + s = stfu_n_resize_aqueue(&i->c_queue, qlen); + i->qlen = qlen; i->max_plc = 5; i->last_frame = NULL; @@ -205,11 +268,6 @@ stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_qlen, uint32_t samples_ } memset(i, 0, sizeof(*i)); - -#ifdef DB_JB - printf("INIT %u %u\n", qlen, max_qlen); -#endif - i->qlen = qlen; i->max_qlen = max_qlen; i->orig_qlen = qlen; @@ -217,8 +275,12 @@ stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_qlen, uint32_t samples_ stfu_n_init_aqueue(&i->a_queue, qlen); stfu_n_init_aqueue(&i->b_queue, qlen); + stfu_n_init_aqueue(&i->c_queue, qlen); + i->in_queue = &i->a_queue; i->out_queue = &i->b_queue; + i->old_queue = &i->c_queue; + i->name = strdup("none"); i->max_plc = i->qlen / 2; @@ -232,9 +294,9 @@ stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_qlen, uint32_t samples_ static void stfu_n_reset_counters(stfu_instance_t *i) { -#ifdef DB_JB - printf("COUNTER RESET........\n"); -#endif + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s COUNTER RESET........\n", i->name); + } if (i->callback) { i->callback(i, i->udata); @@ -248,36 +310,44 @@ static void stfu_n_reset_counters(stfu_instance_t *i) i->period_packet_in_count = 0; i->period_packet_out_count = 0; i->period_missing_count = 0; + i->period_need_range = 0; i->period_need_range_avg = 0; + + i->diff = 0; + i->diff_total = 0; + } void stfu_n_reset(stfu_instance_t *i) { -#ifdef DB_JB - printf("RESET\n"); -#endif + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s RESET\n", i->name); + } + + i->ready = 0; i->in_queue = &i->a_queue; i->out_queue = &i->b_queue; + i->old_queue = &i->c_queue; + i->in_queue->array_len = 0; i->out_queue->array_len = 0; i->out_queue->wr_len = 0; i->last_frame = NULL; - i->in_queue->last_jitter = 0; i->out_queue->last_jitter = 0; + stfu_n_reset_counters(i); - - i->last_seq = 0; - + stfu_n_sync(i, 1); + i->cur_ts = 0; - i->cur_seq = 0; i->last_wr_ts = 0; - i->last_wr_seq = 0; i->last_rd_ts = 0; i->miss_count = 0; i->packet_count = 0; + + } stfu_status_t stfu_n_sync(stfu_instance_t *i, uint32_t packets) @@ -286,20 +356,39 @@ stfu_status_t stfu_n_sync(stfu_instance_t *i, uint32_t packets) if (packets > i->qlen) { stfu_n_reset(i); } else { - i->sync = packets; + i->sync_out = packets; + i->sync_in = packets; } return STFU_IT_WORKED; } -stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t seq, uint32_t pt, void *data, size_t datalen, int last) +static void stfu_n_swap(stfu_instance_t *i) +{ + stfu_queue_t *last_in = i->in_queue, *last_out = i->out_queue, *last_old = i->old_queue; + + i->ready = 1; + + i->in_queue = last_out; + i->out_queue = last_old; + i->old_queue = last_in; + + i->in_queue->array_len = 0; + i->out_queue->wr_len = 0; + i->last_frame = NULL; + i->miss_count = 0; + i->in_queue->last_index = 0; + i->out_queue->last_index = 0; + i->out_queue->last_jitter = 0; +} + +stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void *data, size_t datalen, uint32_t timer_ts, int last) { uint32_t index = 0; stfu_frame_t *frame; size_t cplen = 0; - int good_seq = 0, good_ts = 0; - uint32_t min_seq = UINT_MAX, min_ts = UINT_MAX, min_index = 0; + int good_ts = 0; if (!i->samples_per_packet && ts && i->last_rd_ts) { i->ts_diff = ts - i->last_rd_ts; @@ -320,16 +409,35 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t seq, uin } } - if ((seq && seq == i->last_seq + 1) || (i->last_seq > 65500 && seq == 0)) { - good_seq = 1; + if (timer_ts && ts && !i->ts_offset) { + i->ts_offset = timer_ts - ts; } - if ((ts && ts == i->last_rd_ts + i->samples_per_packet) || (i->last_rd_ts > 4294900000 && ts < 5000)) { + i->ts_drift = ts + (i->ts_offset - timer_ts); + + if (i->sync_in) { good_ts = 1; + i->sync_in = 0; + } else { + + if ((ts && ts == i->last_rd_ts + i->samples_per_packet) || (i->last_rd_ts > 4294900000 && ts < 5000)) { + good_ts = 1; + } + + if (i->last_wr_ts) { + if ((ts <= i->last_wr_ts && (i->last_wr_ts != UINT_MAX || ts == i->last_wr_ts))) { + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s TOO LATE !!! %u \n\n\n", i->name, ts); + } + if (i->in_queue->array_len < i->in_queue->array_size) { + i->in_queue->array_len++; + } + return STFU_ITS_TOO_LATE; + } + } } - - if (good_seq || good_ts) { + if (good_ts) { i->period_clean_count++; i->session_clean_count++; } @@ -337,12 +445,12 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t seq, uin i->period_packet_in_count++; i->session_packet_in_count++; - i->period_need_range_avg = i->period_need_range / (i->period_missing_count || 1); + i->period_need_range_avg = i->period_need_range / least1(i->period_missing_count); if (i->period_missing_count > i->qlen * 2) { -#ifdef DB_JB - printf("resize %u %u\n", i->qlen, i->qlen + 1); -#endif + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s resize %u %u\n", i->name, i->qlen, i->qlen + 1); + } stfu_n_resize(i, i->qlen + 1); stfu_n_reset_counters(i); } else { @@ -353,7 +461,24 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t seq, uin } } + + i->diff = 0; + + if (i->last_wr_ts) { + if (ts < 1000 && i->last_wr_ts > (UINT_MAX - 1000)) { + i->diff = abs(((UINT_MAX - i->last_wr_ts) + ts) / i->samples_per_packet); + } else if (ts) { + i->diff = abs(i->last_wr_ts - ts) / i->samples_per_packet; + } + } + + i->diff_total += i->diff; + if ((i->period_packet_in_count > i->period_time)) { + uint32_t avg; + + avg = i->diff_total / least1(i->period_packet_in_count); + i->period_packet_in_count = 0; if (i->period_missing_count == 0 && i->qlen > i->orig_qlen) { @@ -364,68 +489,38 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t seq, uin stfu_n_reset_counters(i); } -#ifdef DB_JB - printf("%u i=%u/%u - g:%u/%u c:%u/%u b:%u - %u/%u - %u %d\n", - i->qlen, i->period_packet_in_count, i->period_time, i->consecutive_good_count, - i->decrement_time, i->period_clean_count, i->decrement_time, i->consecutive_bad_count, - seq, ts, - i->period_missing_count, i->period_need_range_avg); -#endif + + + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "I: %s %u i=%u/%u - g:%u/%u c:%u/%u b:%u - %u:%u - %u %d %u %u %d %d %d\n", i->name, + i->qlen, i->period_packet_in_count, i->period_time, i->consecutive_good_count, + i->decrement_time, i->period_clean_count, i->decrement_time, i->consecutive_bad_count, + ts, ts / i->samples_per_packet, + i->period_missing_count, i->period_need_range_avg, + i->last_wr_ts, ts, i->diff, i->diff_total / least1(i->period_packet_in_count), i->ts_drift); + } if (last || i->in_queue->array_len == i->in_queue->array_size) { - stfu_queue_t *other_queue; - - other_queue = i->in_queue; - i->in_queue = i->out_queue; - i->out_queue = other_queue; - - i->in_queue->array_len = 0; - i->out_queue->wr_len = 0; - i->last_frame = NULL; - i->miss_count = 0; - i->in_queue->last_index = 0; - i->out_queue->last_index = 0; - i->out_queue->last_jitter = 0; + stfu_n_swap(i); } if (last) { return STFU_IM_DONE; } - for(index = 0; index < i->in_queue->array_size; index++) { - - if (i->in_queue->array[index].was_read) { - min_index = index; - break; - } - - if (i->in_queue->array[index].seq < min_seq) { - min_seq = i->in_queue->array[index].seq; - min_index = index; - } - - if (i->in_queue->array[index].ts < min_ts) { - min_ts = i->in_queue->array[index].ts; - min_index = index; - } - } - - index = min_index; - - if (i->in_queue->array_len < i->in_queue->array_size) { - i->in_queue->array_len++; - } - + index = i->in_queue->array_len++; assert(index < i->in_queue->array_size); - frame = &i->in_queue->array[index]; + if (i->in_queue->array_len == i->in_queue->array_size) { + stfu_n_swap(i); + } + if ((cplen = datalen) > sizeof(frame->data)) { cplen = sizeof(frame->data); } - i->last_seq = seq; i->last_rd_ts = ts; i->packet_count++; @@ -433,44 +528,13 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t seq, uin frame->pt = pt; frame->ts = ts; - frame->seq = seq; frame->dlen = cplen; frame->was_read = 0; return STFU_IT_WORKED; } -static int stfu_n_find_any_frame(stfu_instance_t *in, stfu_frame_t **r_frame) -{ - uint32_t i = 0; - stfu_frame_t *frame = NULL; - stfu_queue_t *queue; - - assert(r_frame); - - *r_frame = NULL; - - for (queue = in->out_queue ; queue && queue != in->in_queue ; queue = in->in_queue) { - - for(i = 0; i < queue->real_array_size; i++) { - frame = &queue->array[i]; - if (!frame->was_read) { - *r_frame = frame; - queue->last_index = i; - frame->was_read = 1; - in->period_packet_out_count++; - in->session_packet_out_count++; - return 1; - } - } - - } - - return 0; -} - - -static int stfu_n_find_frame(stfu_instance_t *in, stfu_queue_t *queue, uint32_t ts, uint32_t seq, stfu_frame_t **r_frame) +static int stfu_n_find_any_frame(stfu_instance_t *in, stfu_queue_t *queue, stfu_frame_t **r_frame) { uint32_t i = 0; stfu_frame_t *frame = NULL; @@ -481,8 +545,7 @@ static int stfu_n_find_frame(stfu_instance_t *in, stfu_queue_t *queue, uint32_t for(i = 0; i < queue->real_array_size; i++) { frame = &queue->array[i]; - - if (((seq || in->last_seq) && frame->seq == seq) || frame->ts == ts) { + if (!frame->was_read) { *r_frame = frame; queue->last_index = i; frame->was_read = 1; @@ -492,6 +555,34 @@ static int stfu_n_find_frame(stfu_instance_t *in, stfu_queue_t *queue, uint32_t } } + return 0; +} + + +static int stfu_n_find_frame(stfu_instance_t *in, stfu_queue_t *queue, uint32_t ts, stfu_frame_t **r_frame) +{ + uint32_t i = 0; + stfu_frame_t *frame = NULL; + + if (r_frame) { + *r_frame = NULL; + } + + for(i = 0; i < queue->array_size; i++) { + frame = &queue->array[i]; + + if (frame->ts == ts) { + if (r_frame) { + *r_frame = frame; + queue->last_index = i; + frame->was_read = 1; + in->period_packet_out_count++; + in->session_packet_out_count++; + } + return 1; + } + } + return 0; } @@ -500,48 +591,76 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) stfu_frame_t *rframe = NULL; int found = 0; - if (!i->samples_per_packet || !i->out_queue->array_len) { - //|| ((i->out_queue->wr_len == i->out_queue->array_len) || !i->out_queue->array_len)) { - return NULL; - } - - if (i->cur_ts == 0) { - i->cur_ts = i->out_queue->array[0].ts; - } else { - i->cur_ts += i->samples_per_packet; + if (!i->samples_per_packet) { + return NULL; } - if (i->cur_seq == 0) { - i->cur_seq = i->out_queue->array[0].seq; + if (!i->ready) { + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s XXXSKIP\n", i->name); + } + return NULL; + } + + + if (i->cur_ts == 0 && i->last_wr_ts < 1000) { + uint32_t x = 0; + for (x = 0; x < i->out_queue->array_len; x++) { + if (!i->out_queue->array[x].was_read) { + i->cur_ts = i->out_queue->array[x].ts; + break; + } + if (i->cur_ts == 0) { + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s XXXPUNT\n", i->name); + return NULL; + } + } + } } else { - i->cur_seq++; - /* if we bother using this for anything that doesn't have 16 bit seq, we'll make this a param */ - if (i->cur_seq == 65535) { - i->cur_seq = 0; + i->cur_ts = i->cur_ts + i->samples_per_packet; + } + + found = stfu_n_find_frame(i, i->out_queue, i->cur_ts, &rframe); + + if (found) { + if (i->out_queue->array_len) { + i->out_queue->array_len--; + } + } else { + found = stfu_n_find_frame(i, i->in_queue, i->cur_ts, &rframe); + + if (!found) { + found = stfu_n_find_frame(i, i->old_queue, i->cur_ts, &rframe); } } - if (!(found = stfu_n_find_frame(i, i->out_queue, i->cur_ts, i->cur_seq, &rframe))) { - found = stfu_n_find_frame(i, i->in_queue, i->cur_ts, i->cur_seq, &rframe); + if (i->sync_out) { + if (!found) { + if ((found = stfu_n_find_any_frame(i, i->out_queue, &rframe))) { + i->cur_ts = rframe->ts; + } + + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s SYNC %u %u:%u\n", i->name, i->sync_out, i->cur_ts, i->cur_ts / i->samples_per_packet); + } + + } + i->sync_out = 0; } - if (!found && i->sync) { -#ifdef DB_JB - printf("SYNC %u\n", i->sync); -#endif - if ((found = stfu_n_find_any_frame(i, &rframe))) { - i->cur_seq = rframe->seq; - i->cur_ts = rframe->ts; + if (!i->cur_ts) { + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s NO TS\n", i->name); } - i->sync = 0; + return NULL; } if (!found && i->samples_per_packet) { -#ifdef DB_JB - int y; + uint32_t y; stfu_frame_t *frame = NULL; -#endif + int32_t delay = i->last_rd_ts - i->cur_ts; uint32_t need = abs(i->last_rd_ts - i->cur_ts) / i->samples_per_packet; @@ -550,30 +669,33 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) i->session_missing_count++; i->period_need_range += need; -#ifdef DB_JB - printf("MISSING %u %u %u %u %d %u %d\n", i->cur_seq, i->cur_ts, i->packet_count, i->last_rd_ts, delay, i->qlen, need); -#endif + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s MISSING %u:%u %u %u %d %u %d\n", i->name, + i->cur_ts, i->cur_ts / i->samples_per_packet, i->packet_count, i->last_rd_ts, delay, i->qlen, need); + } if (i->packet_count > i->orig_qlen * 100 && delay > 0 && need > i->qlen && need < (i->qlen + 5)) { i->packet_count = 0; } -#ifdef DB_JB - for(y = 0; y < i->out_queue->array_size; y++) { - if ((y % 5) == 0) printf("\n"); - frame = &i->out_queue->array[y]; - printf("%u:%u\t", frame->seq, frame->ts); - } - printf("\n\n"); + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s ", i->name); + for(y = 0; y < i->out_queue->array_size; y++) { + if ((y % 5) == 0) stfu_log(STFU_LOG_EMERG, "\n%s ", i->name); + frame = &i->out_queue->array[y]; + stfu_log(STFU_LOG_EMERG, "%u:%u\t", frame->ts, frame->ts / i->samples_per_packet); + } + stfu_log(STFU_LOG_EMERG, "\n%s ", i->name); - for(y = 0; y < i->in_queue->array_size; y++) { - if ((y % 5) == 0) printf("\n"); - frame = &i->in_queue->array[y]; - printf("%u:%u\t", frame->seq, frame->ts); + for(y = 0; y < i->in_queue->array_size; y++) { + if ((y % 5) == 0) stfu_log(STFU_LOG_EMERG, "\n%s ", i->name); + frame = &i->in_queue->array[y]; + stfu_log(STFU_LOG_EMERG, "%u:%u\t", frame->ts, frame->ts / i->samples_per_packet); + } + stfu_log(STFU_LOG_EMERG, "\n%s\n\n\n", i->name); + } - printf("\n\n"); -#endif if (delay < 0) { stfu_n_reset(i); @@ -581,14 +703,11 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) } } -#ifdef DB_JB - if (found) { - printf("O: %u:%u %u %d\n", rframe->seq, rframe->ts, rframe->plc, rframe->seq - i->last_seq); - } else { - printf("DATA: %u %u %d %s %d\n", i->packet_count, i->consecutive_good_count, i->out_queue->last_jitter, found ? "found" : "not found", i->qlen); + if (stfu_log != null_logger && i->debug) { + if (found) { + stfu_log(STFU_LOG_EMERG, "%s O: %u:%u %u\n", i->name, rframe->ts, rframe->ts / i->samples_per_packet, rframe->plc); + } } -#endif - if (found) { i->consecutive_good_count++; @@ -602,36 +721,28 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) if (found) { i->last_frame = rframe; - i->out_queue->wr_len++; - i->last_wr_ts = rframe->ts; - i->last_wr_seq = rframe->seq; - i->miss_count = 0; + i->out_queue->wr_len++; + i->last_wr_ts = rframe->ts; + + i->miss_count = 0; if (rframe->dlen) { i->plc_len = rframe->dlen; } + + i->plc_pt = rframe->pt; + } else { i->last_wr_ts = i->cur_ts; - i->last_wr_seq = i->cur_seq; rframe = &i->out_queue->int_frame; rframe->dlen = i->plc_len; - -#if 0 - if (i->last_frame) { - /* poor man's plc.. Copy the last frame, but we flag it so you can use a better one if you wish */ - if (i->miss_count) { - memset(rframe->data, 255, rframe->dlen); - } else { - memcpy(rframe->data, i->last_frame->data, rframe->dlen); - } - } -#endif + rframe->pt = i->plc_pt; rframe->ts = i->cur_ts; - i->miss_count++; - -#ifdef DB_JB - printf("PLC %d %d %ld %u %u\n", i->miss_count, rframe->plc, rframe->dlen, rframe->seq, rframe->ts); -#endif + + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s PLC %d %d %ld %u:%u\n", i->name, + i->miss_count, rframe->plc, rframe->dlen, rframe->ts, rframe->ts / i->samples_per_packet); + } if (i->miss_count > i->max_plc) { stfu_n_reset(i); @@ -639,9 +750,138 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) } } - return rframe; + return rframe; } +#ifdef WIN32 +#ifndef vsnprintf +#define vsnprintf _vsnprintf +#endif +#endif + + +int vasprintf(char **ret, const char *format, va_list ap); + +int stfu_vasprintf(char **ret, const char *fmt, va_list ap) +{ +#if !defined(WIN32) && !defined(__sun) + return vasprintf(ret, fmt, ap); +#else + char *buf; + int len; + size_t buflen; + va_list ap2; + char *tmp = NULL; + +#ifdef _MSC_VER +#if _MSC_VER >= 1500 + /* hack for incorrect assumption in msvc header files for code analysis */ + __analysis_assume(tmp); +#endif + ap2 = ap; +#else + va_copy(ap2, ap); +#endif + + len = vsnprintf(tmp, 0, fmt, ap2); + + if (len > 0 && (buf = malloc((buflen = (size_t) (len + 1)))) != NULL) { + len = vsnprintf(buf, buflen, fmt, ap); + *ret = buf; + } else { + *ret = NULL; + len = -1; + } + + va_end(ap2); + return len; +#endif +} + + + + +int stfu_snprintf(char *buffer, size_t count, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vsnprintf(buffer, count-1, fmt, ap); + if (ret < 0) + buffer[count-1] = '\0'; + va_end(ap); + return ret; +} + +static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...) +{ + if (file && func && line && level && fmt) { + return; + } + return; +} + + + +static const char *LEVEL_NAMES[] = { + "EMERG", + "ALERT", + "CRIT", + "ERROR", + "WARNING", + "NOTICE", + "INFO", + "DEBUG", + NULL +}; + +static const char *cut_path(const char *in) +{ + const char *p, *ret = in; + char delims[] = "/\\"; + char *i; + + for (i = delims; *i; i++) { + p = in; + while ((p = strchr(p, *i)) != 0) { + ret = ++p; + } + } + return ret; +} + + +static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...) +{ + const char *fp; + char *data; + va_list ap; + int ret; + + if (level < 0 || level > 7) { + level = 7; + } + if (level > stfu_log_level) { + return; + } + + fp = cut_path(file); + + va_start(ap, fmt); + + ret = stfu_vasprintf(&data, fmt, ap); + + if (ret != -1) { + fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data); + free(data); + } + + va_end(ap); + +} + + /* For Emacs: * Local Variables: * mode:c diff --git a/libs/stfu/stfu.h b/libs/stfu/stfu.h index d2760b27bc..b92bb3f839 100644 --- a/libs/stfu/stfu.h +++ b/libs/stfu/stfu.h @@ -38,6 +38,8 @@ extern "C" { #include #include #include +#include + #ifdef _MSC_VER #ifndef uint32_t @@ -62,6 +64,85 @@ typedef unsigned long in_addr_t; #endif #include + + +#ifdef WIN32 +#include +#include +typedef SOCKET stfu_socket_t; +typedef unsigned __int64 uint64_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int8 uint8_t; +typedef __int64 int64_t; +typedef __int32 int32_t; +typedef __int16 int16_t; +typedef __int8 int8_t; +typedef intptr_t stfu_ssize_t; +typedef int stfu_filehandle_t; +#define STFU_SOCK_INVALID INVALID_SOCKET +#define strerror_r(num, buf, size) strerror_s(buf, size, num) +#if defined(STFU_DECLARE_STATIC) +#define STFU_DECLARE(type) type __stdcall +#define STFU_DECLARE_NONSTD(type) type __cdecl +#define STFU_DECLARE_DATA +#elif defined(STFU_EXPORTS) +#define STFU_DECLARE(type) __declspec(dllexport) type __stdcall +#define STFU_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define STFU_DECLARE_DATA __declspec(dllexport) +#else +#define STFU_DECLARE(type) __declspec(dllimport) type __stdcall +#define STFU_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define STFU_DECLARE_DATA __declspec(dllimport) +#endif +#else +#define STFU_DECLARE(type) type +#define STFU_DECLARE_NONSTD(type) type +#define STFU_DECLARE_DATA +#include +#include +#include +#include +#include +#include +#include +#define STFU_SOCK_INVALID -1 +typedef int stfu_socket_t; +typedef ssize_t stfu_ssize_t; +typedef int stfu_filehandle_t; +#endif + + +#define STFU_PRE __FILE__, __FUNCTION__, __LINE__ +#define STFU_LOG_LEVEL_DEBUG 7 +#define STFU_LOG_LEVEL_INFO 6 +#define STFU_LOG_LEVEL_NOTICE 5 +#define STFU_LOG_LEVEL_WARNING 4 +#define STFU_LOG_LEVEL_ERROR 3 +#define STFU_LOG_LEVEL_CRIT 2 +#define STFU_LOG_LEVEL_ALERT 1 +#define STFU_LOG_LEVEL_EMERG 0 + +#define STFU_LOG_DEBUG STFU_PRE, STFU_LOG_LEVEL_DEBUG +#define STFU_LOG_INFO STFU_PRE, STFU_LOG_LEVEL_INFO +#define STFU_LOG_NOTICE STFU_PRE, STFU_LOG_LEVEL_NOTICE +#define STFU_LOG_WARNING STFU_PRE, STFU_LOG_LEVEL_WARNING +#define STFU_LOG_ERROR STFU_PRE, STFU_LOG_LEVEL_ERROR +#define STFU_LOG_CRIT STFU_PRE, STFU_LOG_LEVEL_CRIT +#define STFU_LOG_ALERT STFU_PRE, STFU_LOG_LEVEL_ALERT +#define STFU_LOG_EMERG STFU_PRE, STFU_LOG_LEVEL_EMERG +typedef void (*stfu_logger_t)(const char *file, const char *func, int line, int level, const char *fmt, ...); + + +int stfu_vasprintf(char **ret, const char *fmt, va_list ap); + +extern stfu_logger_t stfu_log; + +/*! Sets the logger for libstfu. Default is the null_logger */ +void stfu_global_set_logger(stfu_logger_t logger); +/*! Sets the default log level for libstfu */ +void stfu_global_set_default_logger(int level); + #define STFU_DATALEN 16384 #define STFU_QLEN 300 #define STFU_MAX_TRACK 256 @@ -69,13 +150,13 @@ typedef unsigned long in_addr_t; typedef enum { STFU_IT_FAILED, STFU_IT_WORKED, - STFU_IM_DONE + STFU_IM_DONE, + STFU_ITS_TOO_LATE } stfu_status_t; struct stfu_frame { uint32_t ts; uint32_t pt; - uint32_t seq; uint8_t data[STFU_DATALEN]; size_t dlen; uint8_t was_read; @@ -100,14 +181,16 @@ void stfu_n_report(stfu_instance_t *i, stfu_report_t *r); void stfu_n_destroy(stfu_instance_t **i); stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_qlen, uint32_t samples_per_packet, uint32_t samples_per_second); stfu_status_t stfu_n_resize(stfu_instance_t *i, uint32_t qlen); -stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t seq, uint32_t pt, void *data, size_t datalen, int last); +stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void *data, size_t datalen, uint32_t timer_ts, int last); stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i); void stfu_n_reset(stfu_instance_t *i); stfu_status_t stfu_n_sync(stfu_instance_t *i, uint32_t packets); void stfu_n_call_me(stfu_instance_t *i, stfu_n_call_me_t callback, void *udata); +void stfu_n_debug(stfu_instance_t *i, const char *name); +int32_t stfu_n_get_drift(stfu_instance_t *i); -#define stfu_im_done(i) stfu_n_add_data(i, 0, NULL, 0, 1) -#define stfu_n_eat(i,t,s,p,d,l) stfu_n_add_data(i, t, s, p, d, l, 0) +#define stfu_im_done(i) stfu_n_add_data(i, 0, NULL, 0, 0, 1) +#define stfu_n_eat(i,t,p,d,l,tt) stfu_n_add_data(i, t, p, d, l, tt, 0) #ifdef __cplusplus } diff --git a/libs/win32/libg722_1/libg722_1.vcproj b/libs/win32/libg722_1/libg722_1.vcproj index e3101a22b9..a7a9530d05 100644 --- a/libs/win32/libg722_1/libg722_1.vcproj +++ b/libs/win32/libg722_1/libg722_1.vcproj @@ -342,6 +342,10 @@ RelativePath="..\..\libg722_1\src\tables.c" > + + + + + @@ -143,6 +144,7 @@ + diff --git a/libs/win32/libg722_1/libg722_1.vcxproj.filters b/libs/win32/libg722_1/libg722_1.vcxproj.filters index 855a60fae6..d54ad6e890 100644 --- a/libs/win32/libg722_1/libg722_1.vcxproj.filters +++ b/libs/win32/libg722_1/libg722_1.vcxproj.filters @@ -60,6 +60,9 @@ Source Files + + Source Files + @@ -92,5 +95,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index d6bce5e8bf..e726554d81 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -312,6 +312,8 @@ SWITCH_DECLARE(switch_status_t) switch_channel_caller_extension_masquerade(switc */ SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel_t *channel, switch_caller_extension_t *caller_extension); +SWITCH_DECLARE(void) switch_channel_sort_cid(switch_channel_t *channel, switch_bool_t in); + /*! \brief Retrieve caller extension from a given channel \param channel channel to retrieve extension from diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 840a06c204..bcd3c0aee2 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -246,6 +246,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_close(_Inout_ switch_media */ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all(_In_ switch_core_session_t *session); +SWITCH_DECLARE(switch_status_t) switch_core_media_bug_enumerate(switch_core_session_t *session, switch_stream_handle_t *stream); + /*! \brief Read a frame from the bug \param bug the bug to read from diff --git a/src/include/switch_cpp.h b/src/include/switch_cpp.h index 0ede8e638f..0bd2a8b2b0 100644 --- a/src/include/switch_cpp.h +++ b/src/include/switch_cpp.h @@ -216,6 +216,7 @@ SWITCH_DECLARE(void) consoleCleanLog(char *msg); char *tts_name; char *voice_name; + SWITCH_DECLARE(int) insertFile(const char *file, const char *insert_file, int sample_point); SWITCH_DECLARE(int) answer(); SWITCH_DECLARE(int) preAnswer(); SWITCH_DECLARE(void) hangup(const char *cause = "normal_clearing"); diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index e3e9f665a3..c48a40e6d1 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -234,6 +234,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t * uint32_t max_queue_frames, uint32_t samples_per_packet, uint32_t samples_per_second); +SWITCH_DECLARE(switch_status_t) switch_rtp_debug_jitter_buffer(switch_rtp_t *rtp_session, const char *name); + SWITCH_DECLARE(switch_status_t) switch_rtp_deactivate_jitter_buffer(switch_rtp_t *rtp_session); /*! diff --git a/src/include/switch_types.h b/src/include/switch_types.h index d020775d48..bb5f59865f 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -791,6 +791,7 @@ typedef enum { SWITCH_MESSAGE_INDICATE_UDPTL_MODE, SWITCH_MESSAGE_INDICATE_CLEAR_PROGRESS, SWITCH_MESSAGE_INDICATE_JITTER_BUFFER, + SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH, SWITCH_MESSAGE_INVALID } switch_core_session_message_types_t; @@ -1095,6 +1096,9 @@ typedef enum { CF_BRIDGE_NOWRITE, CF_RECOVERED, CF_JITTERBUFFER, + CF_DIALPLAN, + CF_BLOCK_BROADCAST_UNTIL_MEDIA, + CF_CNG_PLC, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ CF_FLAG_MAX } switch_channel_flag_t; diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index e2a7335226..3360f33fe5 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -622,7 +622,7 @@ SWITCH_DECLARE(unsigned int) switch_separate_string(_In_ char *buf, char delim, SWITCH_DECLARE(unsigned int) switch_separate_string_string(char *buf, char *delim, _Post_count_(return) char **array, unsigned int arraylen); SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str); -SWITCH_DECLARE(char *) switch_strip_spaces(const char *str); +SWITCH_DECLARE(char *) switch_strip_spaces(char *str, switch_bool_t dup); SWITCH_DECLARE(char *) switch_strip_whitespace(const char *str); SWITCH_DECLARE(char *) switch_strip_commas(char *in, char *out, switch_size_t len); SWITCH_DECLARE(char *) switch_strip_nonnumerics(char *in, char *out, switch_size_t len); diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index dba86e3103..8daaace7f3 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -1428,8 +1428,8 @@ SWITCH_STANDARD_API(cond_function) int a_is_num, b_is_num; *expr++ = '\0'; b = expr; - s_a = switch_strip_spaces(a); - s_b = switch_strip_spaces(b); + s_a = switch_strip_spaces(a, SWITCH_TRUE); + s_b = switch_strip_spaces(b, SWITCH_TRUE); a_is_num = switch_is_number(s_a); b_is_num = switch_is_number(s_b); @@ -2226,6 +2226,40 @@ SWITCH_STANDARD_API(uuid_deflect) return SWITCH_STATUS_SUCCESS; } +#define UUID_RECOVERY_REFRESH_SYNTAX " " +SWITCH_STANDARD_API(uuid_recovery_refresh) +{ + switch_core_session_t *tsession = NULL; + char *uuid = NULL, *text = NULL; + + if (!zstr(cmd) && (uuid = strdup(cmd))) { + if ((text = strchr(uuid, ' '))) { + *text++ = '\0'; + } + } + + if (zstr(uuid) || zstr(text)) { + stream->write_function(stream, "-USAGE: %s\n", UUID_RECOVERY_REFRESH_SYNTAX); + } else { + if ((tsession = switch_core_session_locate(uuid))) { + switch_core_session_message_t msg = { 0 }; + + /* Tell the channel to recovery_refresh the call */ + msg.from = __FILE__; + msg.string_arg = text; + msg.message_id = SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH; + switch_core_session_receive_message(tsession, &msg); + stream->write_function(stream, "+OK:%s\n", msg.string_reply); + switch_core_session_rwunlock(tsession); + } else { + stream->write_function(stream, "-ERR No Such Channel %s!\n", uuid); + } + } + + switch_safe_free(uuid); + return SWITCH_STATUS_SUCCESS; +} + #define SCHED_TRANSFER_SYNTAX "[+]