diff --git a/Freeswitch.2008.sln b/Freeswitch.2008.sln index d87a7ecfa7..27c94a2dc4 100644 --- a/Freeswitch.2008.sln +++ b/Freeswitch.2008.sln @@ -1277,11 +1277,9 @@ Global {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|Win32.ActiveCfg = Debug|Win32 {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|Win32.Build.0 = Debug|Win32 {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|x64.ActiveCfg = Debug|x64 - {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Debug|x64.Build.0 = Debug|x64 {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|Win32.ActiveCfg = Release|Win32 {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|Win32.Build.0 = Release|Win32 {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|x64.ActiveCfg = Release|x64 - {1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}.Release|x64.Build.0 = Release|x64 {692F6330-4D87-4C82-81DF-40DB5892636E}.All|Win32.ActiveCfg = Release|x64 {692F6330-4D87-4C82-81DF-40DB5892636E}.All|x64.ActiveCfg = Release|x64 {692F6330-4D87-4C82-81DF-40DB5892636E}.All|x64.Build.0 = Release|x64 @@ -1593,22 +1591,18 @@ Global {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|Win32.ActiveCfg = Debug|Win32 {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|Win32.Build.0 = Debug|Win32 {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|x64.ActiveCfg = Debug|x64 - {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Debug|x64.Build.0 = Debug|x64 {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|Win32.ActiveCfg = Release|Win32 {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|Win32.Build.0 = Release|Win32 {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|x64.ActiveCfg = Release|x64 - {ACFFF684-4D19-4D48-AF12-88EA1D778BDF}.Release|x64.Build.0 = Release|x64 {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|Win32.ActiveCfg = Release|x64 {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|x64.ActiveCfg = Release|x64 {8F992C49-6C51-412F-B2A3-34EAB708EB65}.All|x64.Build.0 = Release|x64 {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|Win32.ActiveCfg = Debug|Win32 {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|Win32.Build.0 = Debug|Win32 {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|x64.ActiveCfg = Debug|x64 - {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Debug|x64.Build.0 = Debug|x64 {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|Win32.ActiveCfg = Release|Win32 {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|Win32.Build.0 = Release|Win32 {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|x64.ActiveCfg = Release|x64 - {8F992C49-6C51-412F-B2A3-34EAB708EB65}.Release|x64.Build.0 = Release|x64 {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.All|Win32.ActiveCfg = Release|x64 {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.All|x64.ActiveCfg = Release|x64 {4043FC6A-9A30-4577-8AD5-9B233C9575D8}.All|x64.Build.0 = Release|x64 @@ -1637,11 +1631,9 @@ Global {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|Win32.ActiveCfg = Debug|Win32 {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|Win32.Build.0 = Debug|Win32 {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|x64.ActiveCfg = Debug|x64 - {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Debug|x64.Build.0 = Debug|x64 {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|Win32.ActiveCfg = Release|Win32 {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|Win32.Build.0 = Release|Win32 {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|x64.ActiveCfg = Release|x64 - {0A6B5EA5-6E9B-4A51-931F-ED25AA87B4DF}.Release|x64.Build.0 = Release|x64 {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|Win32.ActiveCfg = Release|x64 {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|x64.ActiveCfg = Release|x64 {AB91A099-7690-4ECF-8994-E458F4EA1ED4}.All|x64.Build.0 = Release|x64 @@ -1736,11 +1728,9 @@ Global {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|Win32.ActiveCfg = Debug|Win32 {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|Win32.Build.0 = Debug|Win32 {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|x64.ActiveCfg = Debug|x64 - {028C7278-05D7-4E18-82FE-BE231B844F41}.Debug|x64.Build.0 = Debug|x64 {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|Win32.ActiveCfg = Release|Win32 {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|Win32.Build.0 = Release|Win32 {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|x64.ActiveCfg = Release|x64 - {028C7278-05D7-4E18-82FE-BE231B844F41}.Release|x64.Build.0 = Release|x64 {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|Win32.ActiveCfg = Release|x64 {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|x64.ActiveCfg = Release|x64 {D7F1E3F2-A3F4-474C-8555-15122571AF52}.All|x64.Build.0 = Release|x64 @@ -1901,11 +1891,9 @@ Global {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|Win32.ActiveCfg = Debug|Win32 {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|Win32.Build.0 = Debug|Win32 {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|x64.ActiveCfg = Debug|x64 - {36E854E3-CE12-4348-A125-CCF3F9D74813}.Debug|x64.Build.0 = Debug|x64 {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|Win32.ActiveCfg = Release|Win32 {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|Win32.Build.0 = Release|Win32 {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|x64.ActiveCfg = Release|x64 - {36E854E3-CE12-4348-A125-CCF3F9D74813}.Release|x64.Build.0 = Release|x64 {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|Win32.ActiveCfg = Release|x64 {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|x64.ActiveCfg = Release|x64 {7B077E7F-1BE7-4291-AB86-55E527B25CAC}.All|x64.Build.0 = Release|x64 diff --git a/Makefile.am b/Makefile.am index a26346277a..ad04fde392 100644 --- a/Makefile.am +++ b/Makefile.am @@ -267,7 +267,7 @@ src/include/switch_swigable_cpp.h: $(switch_srcdir)/src/include/switch_cpp.h ## ## Applications ## -bin_PROGRAMS = freeswitch fs_cli fs_ivrd +bin_PROGRAMS = freeswitch fs_cli fs_ivrd tone2wav ## ## fs_cli () @@ -281,6 +281,14 @@ fs_cli_CFLAGS += -DHAVE_EDITLINE -I$(switch_srcdir)/libs/libedit/src fs_cli_LDADD = libs/libedit/src/.libs/libedit.a endif +## +## tone2wav () +## +tone2wav_SOURCES = src/tone2wav.c +tone2wav_CFLAGS = $(AM_CFLAGS) +tone2wav_LDFLAGS = $(AM_LDFLAGS) $(CORE_LIBS) +tone2wav_LDADD = libfreeswitch.la + ## ## fs_ivrd () ## diff --git a/bootstrap.sh b/bootstrap.sh index 0ea5cd43d4..4e65c5ca15 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -16,7 +16,7 @@ done BASEDIR=`pwd`; LIBDIR=${BASEDIR}/libs; SUBDIRS="ilbc curl iksemel js js/nsprpub libdingaling libedit libsndfile pcre sofia-sip \ - speex sqlite srtp openzap freetdm spandsp libg722_1 portaudio unimrcp tiff-3.8.2 broadvoice silk"; + speex sqlite srtp openzap freetdm spandsp libg722_1 portaudio unimrcp tiff-3.8.2 broadvoice silk libcodec2"; if [ ! -f modules.conf ]; then cp build/modules.conf.in modules.conf diff --git a/build/modules.conf.in b/build/modules.conf.in index 7730cf2a94..67e1fe62ae 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -39,6 +39,7 @@ codecs/mod_g723_1 codecs/mod_amr #codecs/mod_amrwb #codecs/mod_silk +#codecs/mod_codec2 codecs/mod_g729 codecs/mod_h26x codecs/mod_bv diff --git a/conf/autoload_configs/callcenter.conf.xml b/conf/autoload_configs/callcenter.conf.xml index e764d17f15..117839146c 100644 --- a/conf/autoload_configs/callcenter.conf.xml +++ b/conf/autoload_configs/callcenter.conf.xml @@ -22,15 +22,15 @@ - - - + + + - - + + diff --git a/conf/autoload_configs/sangoma_codec.conf.xml b/conf/autoload_configs/sangoma_codec.conf.xml index da4b8ed643..05d70de0a7 100644 --- a/conf/autoload_configs/sangoma_codec.conf.xml +++ b/conf/autoload_configs/sangoma_codec.conf.xml @@ -8,25 +8,29 @@ --> - + + + + - - - - - - - - - - - - - diff --git a/conf/dialplan/default.xml b/conf/dialplan/default.xml index 8abb8d8348..8bdcfa0da2 100644 --- a/conf/dialplan/default.xml +++ b/conf/dialplan/default.xml @@ -240,7 +240,7 @@ @@ -250,6 +250,7 @@ + @@ -262,7 +263,7 @@ - + diff --git a/conf/dialplan/features.xml b/conf/dialplan/features.xml index 901b3091b7..b85cadc5f7 100644 --- a/conf/dialplan/features.xml +++ b/conf/dialplan/features.xml @@ -11,6 +11,14 @@ + + + + + + + + diff --git a/conf/sip_profiles/internal.xml b/conf/sip_profiles/internal.xml index e4af5cc772..50833bfbec 100644 --- a/conf/sip_profiles/internal.xml +++ b/conf/sip_profiles/internal.xml @@ -116,7 +116,7 @@ - + @@ -226,6 +226,8 @@ + + diff --git a/configure.in b/configure.in index e8b462f54a..de7261266e 100644 --- a/configure.in +++ b/configure.in @@ -904,6 +904,7 @@ AC_CONFIG_FILES([Makefile src/mod/applications/mod_expr/Makefile src/mod/applications/mod_fax/Makefile src/mod/applications/mod_spandsp/Makefile + src/mod/applications/mod_osp/Makefile src/mod/applications/mod_stress/Makefile src/mod/applications/mod_hash/Makefile src/mod/endpoints/mod_portaudio/Makefile @@ -998,6 +999,7 @@ AC_CONFIG_SUBDIRS([libs/spandsp]) AC_CONFIG_SUBDIRS([libs/broadvoice]) AC_CONFIG_SUBDIRS([libs/libg722_1]) AC_CONFIG_SUBDIRS([libs/silk]) +AC_CONFIG_SUBDIRS([libs/libcodec2]) case $host in *-openbsd*) diff --git a/debian/changelog b/debian/changelog index 2aa9e75555..7f4e8d7749 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +freeswitch (1.0.6-1ubuntu1) maverick; urgency=low + + [ Gabriel Gunderson ] + * upgrade: Added mod_callcenter and pulled out Python into its own + package. + + [ Mathieu Parent ] + * Updated Uploaders list + * Updated Standards-Version to 3.9.1 + + -- Mathieu Parent Thu, 23 Sep 2010 15:34:00 +0200 + freeswitch (1.0.4-1ubuntu2) karmic; urgency=low * upgrade: Add more verbosity when building to make it easier to find build diff --git a/debian/control b/debian/control index 8e52e3d6c1..92b4e6ada5 100644 --- a/debian/control +++ b/debian/control @@ -1,10 +1,11 @@ Source: freeswitch Section: comm Priority: extra -Maintainer: Michal Bielicki -Build-Depends: debhelper (>= 5), fakeroot, wget, automake (>=1.9), autoconf, libtool, unixodbc-dev, libasound2-dev, libcurl3-openssl-dev|libcurl4-openssl-dev, libssl-dev, ncurses-dev, libogg-dev, libvorbis-dev, libperl-dev, libgdbm-dev, libdb-dev, libgnutls-dev, libtiff4-dev, python, libx11-dev, uuid-dev +Maintainer: FreeSWITCH developers +Uploaders: Michal Bielicki , Gabriel Gunderson , William King , Mathieu Parent +Build-Depends: debhelper (>= 5), fakeroot, wget, automake (>=1.9), autoconf, libtool, unixodbc-dev, libasound2-dev, libcurl3-openssl-dev|libcurl4-openssl-dev, libssl-dev, ncurses-dev, libogg-dev, libvorbis-dev, libperl-dev, libgdbm-dev, libdb-dev, libgnutls-dev, libtiff4-dev, python-dev, libx11-dev, uuid-dev Homepage: http://freeswitch.org/ -Standards-Version: 3.8.4 +Standards-Version: 3.9.1 Vcs-Svn: http://svn.freeswitch.org/svn/freeswitch/trunk/ Vcs-Browser: http://fisheye.freeswitch.org/browse/FreeSWITCH @@ -86,6 +87,18 @@ Description: Lua engine for FreeSWITCH . This package contains the mod_lua language module. +Package: freeswitch-python +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, freeswitch +Description: Python engine for FreeSWITCH + FreeSWITCH is an open source telephony platform designed to facilitate the + creation of voice and chat driven products scaling from a soft-phone up to a + soft-switch. It can be used as a simple switching engine, a PBX, a media + gateway or a media server to host IVR applications using simple scripts or XML + to control the callflow. + . + This package contains the mod_python language module. + Package: freeswitch-codec-passthru-g7231 Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, freeswitch diff --git a/debian/freeswitch.conffiles b/debian/freeswitch.conffiles index 342ec5fc02..a6f9ce380f 100644 --- a/debian/freeswitch.conffiles +++ b/debian/freeswitch.conffiles @@ -1,5 +1,6 @@ /opt/freeswitch/conf/autoload_configs/acl.conf.xml /opt/freeswitch/conf/autoload_configs/alsa.conf.xml +/opt/freeswitch/conf/autoload_configs/callcenter.conf.xml /opt/freeswitch/conf/autoload_configs/cdr_csv.conf.xml /opt/freeswitch/conf/autoload_configs/cidlookup.conf.xml /opt/freeswitch/conf/autoload_configs/conference.conf.xml @@ -26,7 +27,6 @@ /opt/freeswitch/conf/autoload_configs/pocketsphinx.conf.xml /opt/freeswitch/conf/autoload_configs/portaudio.conf.xml /opt/freeswitch/conf/autoload_configs/post_load_modules.conf.xml -/opt/freeswitch/conf/autoload_configs/python.conf.xml /opt/freeswitch/conf/autoload_configs/rss.conf.xml /opt/freeswitch/conf/autoload_configs/shout.conf.xml /opt/freeswitch/conf/autoload_configs/skinny.conf.xml @@ -43,7 +43,6 @@ /opt/freeswitch/conf/autoload_configs/zeroconf.conf.xml /opt/freeswitch/conf/dialplan/default/00_pizza_demo.xml /opt/freeswitch/conf/dialplan/default/01_example.com.xml -/opt/freeswitch/conf/dialplan/default/99999_enum.xml /opt/freeswitch/conf/dialplan/default.xml /opt/freeswitch/conf/dialplan/features.xml /opt/freeswitch/conf/dialplan/public/00_inbound_did.xml diff --git a/debian/freeswitch.install b/debian/freeswitch.install index 0bf0c156e7..087d167859 100644 --- a/debian/freeswitch.install +++ b/debian/freeswitch.install @@ -6,6 +6,7 @@ opt/freeswitch/bin/gentls_cert opt/freeswitch/bin/scripts/* opt/freeswitch/conf/autoload_configs/acl.conf.xml opt/freeswitch/conf/autoload_configs/alsa.conf.xml +opt/freeswitch/conf/autoload_configs/callcenter.conf.xml opt/freeswitch/conf/autoload_configs/cdr_csv.conf.xml opt/freeswitch/conf/autoload_configs/cidlookup.conf.xml opt/freeswitch/conf/autoload_configs/conference.conf.xml @@ -34,7 +35,6 @@ opt/freeswitch/conf/autoload_configs/openzap.conf.xml opt/freeswitch/conf/autoload_configs/pocketsphinx.conf.xml opt/freeswitch/conf/autoload_configs/portaudio.conf.xml opt/freeswitch/conf/autoload_configs/post_load_modules.conf.xml -opt/freeswitch/conf/autoload_configs/python.conf.xml opt/freeswitch/conf/autoload_configs/rss.conf.xml opt/freeswitch/conf/autoload_configs/shout.conf.xml opt/freeswitch/conf/autoload_configs/skinny.conf.xml @@ -51,7 +51,6 @@ opt/freeswitch/conf/autoload_configs/xml_rpc.conf.xml opt/freeswitch/conf/autoload_configs/zeroconf.conf.xml opt/freeswitch/conf/dialplan/default/00_pizza_demo.xml opt/freeswitch/conf/dialplan/default/01_example.com.xml -opt/freeswitch/conf/dialplan/default/99999_enum.xml opt/freeswitch/conf/dialplan/default.xml opt/freeswitch/conf/dialplan/features.xml opt/freeswitch/conf/dialplan/public/00_inbound_did.xml @@ -113,6 +112,7 @@ opt/freeswitch/conf/zt.conf opt/freeswitch/htdocs/* opt/freeswitch/lib/libfreeswitch*.so* opt/freeswitch/lib/libopenzap*.so* +opt/freeswitch/mod/mod_callcenter.so* opt/freeswitch/mod/mod_cdr_csv.so* opt/freeswitch/mod/mod_celt.so* opt/freeswitch/mod/mod_cidlookup.so* diff --git a/debian/rules b/debian/rules index 05ab4c1bc4..114ad64f34 100755 --- a/debian/rules +++ b/debian/rules @@ -13,7 +13,7 @@ export APPLICATIONS_MODULES=applications/mod_cluechoo applications/mod_commands applications/mod_hash applications/mod_db applications/mod_valet_parking applications/mod_voicemail applications/mod_rss \ applications/mod_spandsp applications/mod_cidlookup applications/mod_curl applications/mod_easyroute \ applications/mod_lcr applications/mod_nibblebill applications/mod_snom \ - applications/mod_spy applications/mod_vmd applications/mod_directory + applications/mod_spy applications/mod_vmd applications/mod_directory applications/mod_callcenter export ASR_TTS_MODULES=asr_tts/mod_tts_commandline export CODECS_MODULES=codecs/mod_ilbc codecs/mod_h26x codecs/mod_speex codecs/mod_siren codecs/mod_celt export DIALPLANS_MODULES=dialplans/mod_dialplan_asterisk dialplans/mod_dialplan_directory dialplans/mod_dialplan_xml @@ -24,11 +24,11 @@ export ENDPOINTS_MODULES=endpoints/mod_dingaling endpoints/mod_portaudio endpoin endpoints/mod_skinny export EVENT_HANDLERS_MODULES=event_handlers/mod_event_multicast event_handlers/mod_event_socket event_handlers/mod_cdr_csv export FORMATS_MODULES=formats/mod_local_stream formats/mod_native_file formats/mod_sndfile formats/mod_tone_stream formats/mod_shout -export LANGUAGES_MODULES=languages/mod_spidermonkey languages/mod_perl languages/mod_lua +export LANGUAGES_MODULES=languages/mod_spidermonkey languages/mod_perl languages/mod_lua languages/mod_python export LOGGERS_MODULES=loggers/mod_console loggers/mod_logfile loggers/mod_syslog export SAY_MODULES=say/mod_say_en say/mod_say_it say/mod_say_de say/mod_say_fr say/mod_say_es say/mod_say_nl say/mod_say_ru export TIMERS_MODULES= -export DISABLED_MODULES=applications/mod_memcache applications/mod_soundtouch directories/mod_ldap languages/mod_java languages/mod_python \ +export DISABLED_MODULES=applications/mod_memcache applications/mod_soundtouch directories/mod_ldap languages/mod_java \ asr_tts/mod_cepstral asr_tts/mod_lumenvox endpoints/mod_wanpipe \ event_handlers/mod_event_test event_handlers/mod_radius_cdr event_handlers/mod_zeroconf export XML_INT_MODULES=xml_int/mod_xml_rpc xml_int/mod_xml_curl xml_int/mod_xml_cdr diff --git a/docs/phrase/phrase_en.xml b/docs/phrase/phrase_en.xml index 65c394cfc8..d519350d35 100644 --- a/docs/phrase/phrase_en.xml +++ b/docs/phrase/phrase_en.xml @@ -395,6 +395,8 @@ + + diff --git a/freeswitch.spec b/freeswitch.spec index 76f9df4fb9..52e6226830 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -1,5 +1,5 @@ -############################################################################################################################### -############################################################################################################################### +###################################################################################################################### +###################################################################################################################### # # spec file for package freeswitch # @@ -26,8 +26,8 @@ # # Maintainer(s): Michal Bielicki 100 #BuildRequires: openldap2-devel @@ -128,11 +128,11 @@ PreReq: %insserv_prereq %fillup_prereq %endif -############################################################################################################################### +###################################################################################################################### # -# Where the packages are going to be built +# Where the packages are going to be built # -############################################################################################################################### +###################################################################################################################### BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %description @@ -155,12 +155,12 @@ Our developers are heavily involved in open source and have donated code and oth other telephony projects including sipXecs, OpenSER, Asterisk, CodeWeaver and OpenPBX. -############################################################################################################################### +###################################################################################################################### # -# Sub Package definitions. Description and Runtime Requirements go here -# What goes into which package is in the files section after the whole build enchilada +# Sub Package definitions. Description and Runtime Requirements go here +# What goes into which package is in the files section after the whole build enchilada # -############################################################################################################################### +###################################################################################################################### %package devel @@ -277,11 +277,11 @@ Requires: %{name} = %{version}-%{release} %description openzap OpenZAP -############################################################################################################################### +###################################################################################################################### # -# Unpack and prepare Source archives, copy stuff around etc .. +# Unpack and prepare Source archives, copy stuff around etc .. # -############################################################################################################################### +###################################################################################################################### %prep %setup -b0 -q @@ -297,11 +297,11 @@ cp %{SOURCE9} libs/ cp %{SOURCE10} libs/ cp %{SOURCE11} libs/ -############################################################################################################################### +###################################################################################################################### # -# Start the Build process +# Start the Build process # -############################################################################################################################### +###################################################################################################################### %build %ifos linux %if 0%{?suse_version} > 1000 && 0%{?suse_version} < 1030 @@ -312,115 +312,115 @@ export QA_RPATHS=$[ 0x0001|0x0002 ] %endif %endif -############################################################################################################################### +###################################################################################################################### # -# Here the modules that will be build get defined +# Here the modules that will be build get defined # -############################################################################################################################### -############################################################################################################################### +###################################################################################################################### +###################################################################################################################### # -# Application Modules +# Application Modules # -############################################################################################################################### -APPLICATION_MODULES_AE="applications/mod_avmd applications/mod_commands applications/mod_conference applications/mod_db applications/mod_directory applications/mod_distributor applications/mod_dptools applications/mod_easyroute applications/mod_enum applications/mod_esf applications/mod_expr applications/mod_callcenter" +###################################################################################################################### +APPLICATION_MODULES_AE="applications/mod_avmd applications/mod_callcenter applications/mod_cluechoo applications/mod_commands applications/mod_conference applications/mod_db applications/mod_directory applications/mod_distributor applications/mod_dptools applications/mod_easyroute applications/mod_enum applications/mod_esf applications/mod_expr" APPLICATION_MODULES_FM="applications/mod_fifo applications/mod_fsv applications/mod_hash applications/mod_lcr applications/mod_limit applications/mod_memcache" -APPLICATION_MODULES_NY=" applications/mod_redis applications/mod_rss applications/mod_soundtouch applications/mod_spandsp applications/mod_stress applications/mod_spy " +APPLICATION_MODULES_NY="applications/mod_nibblebill applications/mod_redis applications/mod_rss applications/mod_soundtouch applications/mod_spandsp applications/mod_stress applications/mod_spy " APPLICATION_MODULES_VZ="applications/mod_valet_parking applications/mod_vmd applications/mod_voicemail" APPLICATIONS_MODULES="$APPLICATION_MODULES_AE $APPLICATION_MODULES_FM $APPLICATION_MODULES_NY $APPLICATION_MODULES_VZ" -############################################################################################################################### +###################################################################################################################### # -# Automatic Speech Recognition and Text To Speech Modules +# Automatic Speech Recognition and Text To Speech Modules # -############################################################################################################################### +###################################################################################################################### ASR_TTS_MODULES="asr_tts/mod_pocketsphinx asr_tts/mod_flite asr_tts/mod_unimrcp" -############################################################################################################################### +###################################################################################################################### # -# Codecs +# Codecs # -############################################################################################################################### +###################################################################################################################### CODECS_MODULES="codecs/mod_ilbc codecs/mod_h26x codecs/mod_speex codecs/mod_celt codecs/mod_siren codecs/mod_bv" -############################################################################################################################### +###################################################################################################################### # -# Dialplan Modules +# Dialplan Modules # -############################################################################################################################### +###################################################################################################################### DIALPLANS_MODULES="dialplans/mod_dialplan_asterisk dialplans/mod_dialplan_directory dialplans/mod_dialplan_xml" -############################################################################################################################### +###################################################################################################################### # -# Directory Modules +# Directory Modules # -############################################################################################################################### +###################################################################################################################### DIRECTORIES_MODULES="" -############################################################################################################################### +###################################################################################################################### # -# Endpoints +# Endpoints # -############################################################################################################################### +###################################################################################################################### ENDPOINTS_MODULES="endpoints/mod_dingaling endpoints/mod_portaudio endpoints/mod_sofia ../../libs/openzap/mod_openzap endpoints/mod_loopback" -############################################################################################################################### +###################################################################################################################### # -# Event Handlers +# Event Handlers # -############################################################################################################################### +###################################################################################################################### EVENT_HANDLERS_MODULES="event_handlers/mod_event_multicast event_handlers/mod_event_socket event_handlers/mod_cdr_csv" -############################################################################################################################### +###################################################################################################################### # -# File and Audio Format Handlers +# File and Audio Format Handlers # -############################################################################################################################### -FORMATS_MODULES="formats/mod_local_stream formats/mod_native_file formats/mod_sndfile formats/mod_tone_stream formats/mod_shout formats/mod_file_string" -############################################################################################################################### +###################################################################################################################### +FORMATS_MODULES="formats/mod_local_stream formats/mod_native_file formats/mod_sndfile formats/mod_portaudio_stream formats/mod_tone_stream formats/mod_shout formats/mod_file_string" +###################################################################################################################### # -# Embedded Languages +# Embedded Languages # -############################################################################################################################### +###################################################################################################################### LANGUAGES_MODULES="languages/mod_lua languages/mod_perl languages/mod_python languages/mod_spidermonkey" -############################################################################################################################### +###################################################################################################################### # -# Logging Modules +# Logging Modules # -############################################################################################################################### +###################################################################################################################### LOGGERS_MODULES="loggers/mod_console loggers/mod_logfile loggers/mod_syslog" -############################################################################################################################### +###################################################################################################################### # -# Passthru Codecs +# Passthru Codecs # -############################################################################################################################### +###################################################################################################################### PASSTHRU_CODEC_MODULES="codecs/mod_amr codecs/mod_amrwb codecs/mod_g723_1 codecs/mod_g729" -############################################################################################################################### +###################################################################################################################### # -# Phrase engine language modules +# Phrase engine language modules # -############################################################################################################################### +###################################################################################################################### SAY_MODULES="say/mod_say_de say/mod_say_en say/mod_say_fr say/mod_say_ru" -############################################################################################################################### +###################################################################################################################### # -# Timers +# Timers # -############################################################################################################################### +###################################################################################################################### TIMERS_MODULES= -############################################################################################################################### +###################################################################################################################### # -# XML Modules +# XML Modules # -############################################################################################################################### +###################################################################################################################### XML_INT_MODULES="xml_int/mod_xml_cdr xml_int/mod_xml_curl xml_int/mod_xml_rpc" -############################################################################################################################### +###################################################################################################################### # -# Create one environment variable out of all the module defs +# Create one environment variable out of all the module defs # -############################################################################################################################### +###################################################################################################################### MYMODULES="$PASSTHRU_CODEC_MODULES $APPLICATIONS_MODULES $CODECS_MODULES $DIALPLANS_MODULES $DIRECTORIES_MODULES $ENDPOINTS_MODULES $ASR_TTS_MODULES $EVENT_HANDLERS_MODULES $FORMATS_MODULES $LANGUAGES_MODULES $LOGGERS_MODULES $SAY_MODULES $TIMERS_MODULES $XML_INT_MODULES" -############################################################################################################################### +###################################################################################################################### # -# Create Modules build list and set variables +# Create Modules build list and set variables # -############################################################################################################################### +###################################################################################################################### export MODULES=$MYMODULES test ! -f modules.conf || rm -f modules.conf @@ -431,11 +431,11 @@ export DESTDIR=%{buildroot}/ export PKG_CONFIG_PATH=/usr/bin/pkg-config:$PKG_CONFIG_PATH export ACLOCAL_FLAGS="-I /usr/share/aclocal" -############################################################################################################################### +###################################################################################################################### # -# Bootstrap, Configure and Build the whole enchilada +# Bootstrap, Configure and Build the whole enchilada # -############################################################################################################################### +###################################################################################################################### if test ! -f Makefile.in then @@ -467,11 +467,11 @@ touch .noversion %{__make} -############################################################################################################################### +###################################################################################################################### # -# Install it and create some required dirs and links +# Install it and create some required dirs and links # -############################################################################################################################### +###################################################################################################################### %install %{__make} DESTDIR=%{buildroot} install @@ -502,11 +502,11 @@ touch .noversion %endif -############################################################################################################################### +###################################################################################################################### # -# Add a freeswitch user with group daemon that will own the whole enchilada +# Add a freeswitch user with group daemon that will own the whole enchilada # -############################################################################################################################### +###################################################################################################################### %pre %ifos linux if ! /usr/bin/id freeswitch &>/dev/null; then @@ -526,11 +526,11 @@ chkconfig --add freeswitch %postun -############################################################################################################################### +###################################################################################################################### # -# On uninstallation get rid of the freeswitch user +# On uninstallation get rid of the freeswitch user # -############################################################################################################################### +###################################################################################################################### %{?run_ldconfig:%run_ldconfig} if [ $1 -eq 0 ]; then userdel freeswitch || %logmsg "User \"freeswitch\" could not be deleted." @@ -540,19 +540,19 @@ fi %{__rm} -rf %{buildroot} %files -############################################################################################################################### +###################################################################################################################### # -# What to install where ... first set default permissions +# What to install where ... first set default permissions # -############################################################################################################################### +###################################################################################################################### %defattr(-,freeswitch,daemon) -############################################################################################################################### +###################################################################################################################### # -# Directories +# Directories # -############################################################################################################################### +###################################################################################################################### # -#################################### Basic Directory Structure ################################################################ +#################################### Basic Directory Structure ####################################################### # %dir %attr(0750, freeswitch, daemon) %{prefix}/conf %dir %attr(0750, freeswitch, daemon) %{prefix}/db @@ -562,7 +562,7 @@ fi %dir %attr(0750, freeswitch, daemon) %{runtimedir} %dir %attr(0750, freeswitch, daemon) %{prefix}/scripts # -#################################### Config Directory Structure ################################################################ +#################################### Config Directory Structure ####################################################### # %dir %attr(0750, freeswitch, daemon) %{prefix}/conf/autoload_configs %dir %attr(0750, freeswitch, daemon) %{prefix}/conf/dialplan @@ -579,7 +579,7 @@ fi %dir %attr(0750, freeswitch, daemon) %{prefix}/conf/sip_profiles/internal %dir %attr(0750, freeswitch, daemon) %{prefix}/conf/skinny_profiles # -#################################### Grammar Directory Structure ################################################################ +#################################### Grammar Directory Structure ##################################################### # %dir %attr(0750, freeswitch, daemon) %{prefix}/grammar/model %dir %attr(0750, freeswitch, daemon) %{prefix}/grammar/model/communicator @@ -587,11 +587,11 @@ fi %ifos linux %config(noreplace) %attr(0644, freeswitch, daemon) /etc/monit.d/freeswitch.monitrc %endif -############################################################################################################################### +###################################################################################################################### # -# Config Files +# Config Files # -############################################################################################################################### +###################################################################################################################### %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/*.tpl %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/*.ttml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/*.xml @@ -650,60 +650,59 @@ fi %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/xml_curl.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/xml_rpc.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/zeroconf.conf.xml -############################################################################################################################### +###################################################################################################################### # -# Dialplans +# Dialplans # -############################################################################################################################### +###################################################################################################################### %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/dialplan/*.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/dialplan/default/*.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/dialplan/public/*.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/dialplan/skinny-patterns/*.xml -############################################################################################################################### +###################################################################################################################### # -# User Directories +# User Directories # -############################################################################################################################### +###################################################################################################################### %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/directory/*.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/directory/default/* -############################################################################################################################### +###################################################################################################################### # -# IVR Menues +# IVR Menues # -############################################################################################################################### +###################################################################################################################### %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/ivr_menus/*.xml -############################################################################################################################### +###################################################################################################################### # -# Sip Profiles +# Sip Profiles # -############################################################################################################################### +###################################################################################################################### %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/sip_profiles/*.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/sip_profiles/internal/*.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/sip_profiles/external/*.xml -############################################################################################################################### +###################################################################################################################### # -# Other Protocol Profiles (skinny, jingle, mrcp) +# Other Protocol Profiles (skinny, jingle, mrcp) # -############################################################################################################################### +###################################################################################################################### %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/skinny_profiles/*.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/jingle_profiles/*.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/mrcp_profiles/*.xml -############################################################################################################################### +###################################################################################################################### # -# Grammar Files +# Grammar Files # -############################################################################################################################### +###################################################################################################################### %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/grammar/default.dic %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/grammar/model/communicator/* %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/grammar/model/wsj1/* -############################################################################################################################### +###################################################################################################################### # -# Other Fíles +# Other Fíles # -############################################################################################################################### +###################################################################################################################### %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/htdocs/* %ifos linux -#/etc/ld.so.conf.d/* /etc/rc.d/init.d/freeswitch /etc/sysconfig/freeswitch %if 0%{?suse_version} > 100 @@ -713,23 +712,25 @@ fi %ifos linux %dir %attr(0750, root, root) /etc/monit.d %endif -############################################################################################################################### +###################################################################################################################### # -# Binaries +# Binaries # -############################################################################################################################### +###################################################################################################################### %attr(0755, freeswitch, daemon) %{prefix}/bin/* %{prefix}/lib/libfreeswitch*.so* -############################################################################################################################### +###################################################################################################################### # -# Modules in Alphabetical Order, please keep them that way.. +# Modules in Alphabetical Order, please keep them that way.. # -############################################################################################################################### +###################################################################################################################### %{prefix}/mod/mod_amrwb.so* %{prefix}/mod/mod_avmd.so* %{prefix}/mod/mod_bv.so* +%{prefix}/mod/mod_callcenter.so* %{prefix}/mod/mod_cdr_csv.so* %{prefix}/mod/mod_celt.so* +%{prefix}/mod/mod_cluechoo.so* %{prefix}/mod/mod_console.so* %{prefix}/mod/mod_commands.so* %{prefix}/mod/mod_conference.so* @@ -747,7 +748,6 @@ fi %{prefix}/mod/mod_event_multicast.so* %{prefix}/mod/mod_event_socket.so* %{prefix}/mod/mod_expr.so* -%{prefix}/mod/mod_callcenter.so* %{prefix}/mod/mod_fifo.so* %{prefix}/mod/mod_file_string.so* %{prefix}/mod/mod_flite.so* @@ -762,8 +762,10 @@ fi %{prefix}/mod/mod_loopback.so* %{prefix}/mod/mod_memcache.so* %{prefix}/mod/mod_native_file.so* +%{prefix}/mod/mod_nibblebill.so* %{prefix}/mod/mod_pocketsphinx.so* %{prefix}/mod/mod_portaudio.so* +%{prefix}/mod/mod_portaudio_stream.so* %{prefix}/mod/mod_redis.so* %{prefix}/mod/mod_rss.so* %{prefix}/mod/mod_shout.so* @@ -784,13 +786,11 @@ fi %{prefix}/mod/mod_xml_cdr.so* %{prefix}/mod/mod_xml_curl.so* %{prefix}/mod/mod_xml_rpc.so* - - -############################################################################################################################### +###################################################################################################################### # -# Package for the developer +# Package for the developer # -############################################################################################################################### +###################################################################################################################### %files devel %defattr(-, freeswitch, daemon) %{prefix}/lib/*.a @@ -799,12 +799,11 @@ fi %{prefix}/mod/*.a %{prefix}/mod/*.la %{prefix}/include/*.h - -############################################################################################################################### +###################################################################################################################### # -# OpenZAP Module for TDM Interaction +# OpenZAP Module for TDM Interaction # -############################################################################################################################### +###################################################################################################################### %files openzap %defattr(-, freeswitch, daemon) %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/tones.conf @@ -817,11 +816,11 @@ fi %{prefix}/mod/mod_openzap.so* %{prefix}/mod/ozmod_*.so* -############################################################################################################################### +###################################################################################################################### # -# Passthru Codec Modules +# Passthru Codec Modules # -############################################################################################################################### +###################################################################################################################### %files codec-passthru-amrwb %defattr(-,freeswitch,daemon) %{prefix}/mod/mod_amrwb.so* @@ -838,12 +837,11 @@ fi %defattr(-,freeswitch,daemon) %{prefix}/mod/mod_g729.so* - -############################################################################################################################### +###################################################################################################################### # -# Embedded Language Modules +# Embedded Language Modules # -############################################################################################################################### +###################################################################################################################### %files spidermonkey %defattr(-,freeswitch,daemon) %{prefix}/mod/mod_spidermonkey*.so* @@ -874,11 +872,11 @@ fi %dir %attr(0750, freeswitch, daemon) %{prefix}/conf/autoload_configs %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/python.conf.xml -############################################################################################################################### +###################################################################################################################### # -# Language Modules +# Language Modules # -############################################################################################################################### +###################################################################################################################### %files lang-en %defattr(-, freeswitch, daemon) %dir %attr(0750, freeswitch, daemon) %{prefix}/conf/lang/en @@ -922,12 +920,17 @@ fi %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/lang/ru/dir/*.xml %{prefix}/mod/mod_say_ru.so* -############################################################################################################################### +###################################################################################################################### # -# Changelog +# Changelog # -############################################################################################################################### +###################################################################################################################### %changelog +* Thu Sep 30 2010 - michal.bielicki@seventhsignal.de +- added mod_nibblebill to standard modules +* Sun Sep 26 2010 - michal.bielicki@seventhsignal.de +- added portaudio_stream module +- some more formating work * Mon Jul 19 2010 - michal.bielicki@seventhsignal.de - new hash module config file added to freeswitch.spec * Mon Jul 19 2010 - michal.bielicki@seventhsignal.de diff --git a/libs/.gitignore b/libs/.gitignore index 24e32c1954..cc42ba4fa4 100644 --- a/libs/.gitignore +++ b/libs/.gitignore @@ -355,6 +355,7 @@ /libsndfile/Cfg/missing /libsndfile/M4/Makefile /libsndfile/M4/Makefile.in +/libsndfile/M4/lt~obsolete.m4 /libsndfile/Makefile /libsndfile/Makefile.in /libsndfile/Octave/Makefile diff --git a/libs/apr/.update b/libs/apr/.update index 097f707e64..d5bc43d9d4 100644 --- a/libs/apr/.update +++ b/libs/apr/.update @@ -1 +1 @@ -Thu Nov 19 09:24:37 EST 2009 +Mon Sep 27 13:15:54 CDT 2010 diff --git a/libs/apr/strings/apr_snprintf.c b/libs/apr/strings/apr_snprintf.c index fe8b382d14..4f59f92c76 100644 --- a/libs/apr/strings/apr_snprintf.c +++ b/libs/apr/strings/apr_snprintf.c @@ -824,7 +824,13 @@ APR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *), * Modifier check. Note that if APR_INT64_T_FMT is "d", * the first if condition is never true. */ - if ((sizeof(APR_INT64_T_FMT) == 4 && + + /* HACK BY FREESWITCH TEAM TO FIX COMPATIBILITY 2010-09-27 */ + if (*fmt == 'l' && *(fmt + 1) == 'l') { + var_type = IS_QUAD; + fmt += 2; + } + else if ((sizeof(APR_INT64_T_FMT) == 4 && fmt[0] == APR_INT64_T_FMT[0] && fmt[1] == APR_INT64_T_FMT[1]) || (sizeof(APR_INT64_T_FMT) == 3 && @@ -843,6 +849,11 @@ APR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *), else if (*fmt == 'l') { var_type = IS_LONG; fmt++; + /* HACK BY FREESWITCH TEAM TO FIX COMPATIBILITY 2010-09-27 */ + if (*fmt == 'l') { + var_type = IS_QUAD; + fmt++; + } } else if (*fmt == 'h') { var_type = IS_SHORT; diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c index 160fe2d759..75a52d6bd2 100644 --- a/libs/esl/src/esl.c +++ b/libs/esl/src/esl.c @@ -36,7 +36,10 @@ #define closesocket(x) close(x) #include #else +#pragma warning (disable:6386) +/* These warnings need to be ignored warning in sdk header */ #include +#pragma warning (default:6386) #endif diff --git a/libs/esl/src/esl_config.c b/libs/esl/src/esl_config.c index 4616356f7f..2e24007799 100644 --- a/libs/esl/src/esl_config.c +++ b/libs/esl/src/esl_config.c @@ -110,7 +110,7 @@ ESL_DECLARE(int) esl_config_next_pair(esl_config_t *cfg, char **var, char **val) *var = *val = NULL; - if (!cfg->path) { + if (!cfg || !cfg->file) { return 0; } diff --git a/libs/esl/src/esl_event.c b/libs/esl/src/esl_event.c index 2e1d8a302a..db7c581ee9 100644 --- a/libs/esl/src/esl_event.c +++ b/libs/esl/src/esl_event.c @@ -513,6 +513,9 @@ ESL_DECLARE(esl_status_t) esl_event_serialize(esl_event_t *event, char **str, es char *encode_buf = NULL; /* used for url encoding of variables to make sure unsafe things stay out of the serialized copy */ int clen = 0; + if (!event || !event->headers) + return ESL_FAIL; + *str = NULL; dlen = blocksize * 2; diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index 33a8b96936..d14013ab9b 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -312,7 +312,7 @@ ftmod_r2_la_LIBADD = $(MYLIB) endif dox doxygen: - cd docs && doxygen $(FT_SRCDIR)/docs/Doxygen.conf + doxygen $(FT_SRCDIR)/docs/Doxygen.conf mod_freetdm/mod_freetdm.$(DYNAMIC_LIB_EXTEN): $(MYLIB) mod_freetdm/mod_freetdm.c cd mod_freetdm && make diff --git a/libs/freetdm/README b/libs/freetdm/README index 2c2119f55b..4ca13d19c9 100644 --- a/libs/freetdm/README +++ b/libs/freetdm/README @@ -1,3 +1,3 @@ -FREETDM (WORK IN PROGRESS) +FreeTDM +http://wiki.freeswitch.org/wiki/FreeTDM -*shrug* diff --git a/libs/freetdm/conf/freetdm.conf b/libs/freetdm/conf/freetdm.conf index 1ea1a9f62a..bbaf1e3687 100644 --- a/libs/freetdm/conf/freetdm.conf +++ b/libs/freetdm/conf/freetdm.conf @@ -1,19 +1,47 @@ -[span wanpipe] -name => FreeTDM -number => 1 +; !! THIS IS A SAMPLE CONFIGURATION ONLY !! + +; refer to http://wiki.freeswitch.org/wiki/FreeTDM for further documentation + +[general] +; whether to launch a thread for CPU usage monitoring +cpu_monitor => no + +; How often (in milliseconds) monitor CPU usage +cpu_monitoring_interval => 1000 + +; At what CPU percentage raise a CPU alarm +cpu_set_alarm_threshold => 80 + +; At what CPU percentage stop the CPU alarm +cpu_reset_alarm_threshold => 70 + +; Which action to take when the CPU alarm is raised +; it can be warn and/or reject calls +; cpu_alarm_action => warn,reject +cpu_alarm_action => warn + +; spans are defined with [span ] +; the span type can either be zt, wanpipe or pika +; the span name can be any unique string +[span wanpipe myWanpipe] + +; valid trunk types are: FXO, FXS, EM, E1, T1, J1, BRI, BRI_PTMP +trunk_type => FXS + +; add FXS channels from 3 to 4 at wanpipe span 1 to this freetdm span fxs-channel => 1:3-4 -[span wanpipe] +[span wanpipe myWanpipe2] +trunk_type => FXO +; This number will be used as DNIS for FXO devices fxo-channel => 1:1-2 -[span zt] -name => FreeTDM -number => 2 +[span zt myZaptelSpan] +number => 9999 fxs-channel => 1 -[span zt] -name => FreeTDM +[span zt mySecondZaptelSpan] +; This number will be used as DNIS for FXO devices number => 2 fxo-channel => 3 - diff --git a/libs/freetdm/conf/freetdm.conf.xml b/libs/freetdm/conf/freetdm.conf.xml index 69bf99a0a0..986074dffb 100644 --- a/libs/freetdm/conf/freetdm.conf.xml +++ b/libs/freetdm/conf/freetdm.conf.xml @@ -1,3 +1,5 @@ + + @@ -5,6 +7,8 @@ + + @@ -24,9 +28,11 @@ - + + + - + @@ -42,4 +48,5 @@ + diff --git a/libs/freetdm/conf/pika.conf b/libs/freetdm/conf/pika.conf index 8cc8d9c11d..78e095205e 100644 --- a/libs/freetdm/conf/pika.conf +++ b/libs/freetdm/conf/pika.conf @@ -1,3 +1,5 @@ +; you dont need this file unless you use PIKA boards + ; each category is a config profile ; to apply the profile append it to a channel def in ; openzap.conf with @ diff --git a/libs/freetdm/conf/tones.conf b/libs/freetdm/conf/tones.conf index 36db1d4d91..155b5fe17e 100644 --- a/libs/freetdm/conf/tones.conf +++ b/libs/freetdm/conf/tones.conf @@ -1,3 +1,5 @@ +; This file is used to generate telephony tones by FreeTDM + [us] generate-dial => v=-7;%(1000,0,350,440) detect-dial => 350,440 diff --git a/libs/freetdm/mkrelease.sh b/libs/freetdm/mkrelease.sh new file mode 100755 index 0000000000..58d176119d --- /dev/null +++ b/libs/freetdm/mkrelease.sh @@ -0,0 +1,64 @@ +#!/bin/bash +INSTALLPREFIX="/usr/local/freetdm" +VERSION="" +NODOCS="NO" + +for i in $* +do + case $i in + --version=*) + VERSION=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` + ;; + --prefix=*) + INSTALLPREFIX=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` + ;; + --nodocs) + NODOCS="YES" + ;; + *) + # unknown option + echo "Unknown option $i" + exit + ;; + esac +done + +if [ "x$VERSION" = "x" ] +then + echo "Provide a version number with --version=" + exit 1 +fi + +if [ ! -d $INSTALLPREFIX ] +then + mkdir -p $INSTALLPREFIX || exit 1 +fi + +make clean +make mod_freetdm-clean +if [ $NODOCS = "NO" ] +then + make dox || exit 1 +fi + +major=$(echo "$VERSION" | cut -d. -f1) +minor=$(echo "$VERSION" | cut -d. -f2) +micro=$(echo "$VERSION" | cut -d. -f3) +release="freetdm-$VERSION" + +echo "Creating $release ($major.$minor.$micro) at $INSTALLPREFIX/$release (directory will be removed if exists already) ... press any key to continue" +read + +mkdir -p $INSTALLPREFIX/$release + +cp -r ./* $INSTALLPREFIX/$release + +find $INSTALLPREFIX/ -name .libs -exec rm -rf {} \; +find $INSTALLPREFIX/ -name .deps -exec rm -rf {} \; +find $INSTALLPREFIX/ -name *.so -exec rm -rf {} \; +find $INSTALLPREFIX/ -name *.lo -exec rm -rf {} \; + + +tar -C $INSTALLPREFIX -czf $INSTALLPREFIX/$release.tar.gz $release/ + + diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index fb85b3515c..3ad4393ab5 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -1404,6 +1404,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session private_t *tech_pvt = NULL; switch_channel_t *channel = NULL; ftdm_iterator_t *iter = NULL; + ftdm_iterator_t *curr = NULL; const char *var_name = NULL; const char *var_value = NULL; uint32_t spanid, chanid; @@ -1515,13 +1516,14 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "freetdm_custom_call_data", "%s", channel_caller_data->raw_data); } /* Add any channel variable to the dial plan */ - iter = ftdm_channel_get_var_iterator(sigmsg->channel); - for ( ; iter; iter = ftdm_iterator_next(iter)) { - ftdm_channel_get_current_var(iter, &var_name, &var_value); + iter = ftdm_channel_get_var_iterator(sigmsg->channel, NULL); + for (curr = iter ; curr; curr = ftdm_iterator_next(curr)) { + ftdm_channel_get_current_var(curr, &var_name, &var_value); snprintf(name, sizeof(name), FREETDM_VAR_PREFIX "%s", var_name); switch_channel_set_variable_printf(channel, name, "%s", var_value); } - + ftdm_iterator_free(iter); + switch_channel_set_state(channel, CS_INIT); if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n"); @@ -2180,9 +2182,8 @@ static void ftdm_logger(const char *file, const char *func, int line, int level, if (switch_vasprintf(&data, fmt, ap) != -1) { switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, (char *)func, line, NULL, level, "%s", data); - free(data); } - + if (data) free(data); va_end(ap); } @@ -2371,6 +2372,121 @@ static int add_profile_parameters(switch_xml_t cfg, const char *profname, ftdm_c return paramindex; } +static void parse_bri_pri_spans(switch_xml_t cfg, switch_xml_t spans) +{ + switch_xml_t myspan, param; + + for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) { + ftdm_status_t zstatus = FTDM_FAIL; + const char *context = "default"; + const char *dialplan = "XML"; + ftdm_conf_parameter_t spanparameters[30]; + char *id = (char *) switch_xml_attr(myspan, "id"); + char *name = (char *) switch_xml_attr(myspan, "name"); + char *configname = (char *) switch_xml_attr(myspan, "cfgprofile"); + ftdm_span_t *span = NULL; + uint32_t span_id = 0; + unsigned paramindex = 0; + + if (!name && !id) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sangoma isdn span missing required attribute 'id' or 'name', skipping ...\n"); + continue; + } + + if (name) { + zstatus = ftdm_span_find_by_name(name, &span); + } else { + if (switch_is_number(id)) { + span_id = atoi(id); + zstatus = ftdm_span_find(span_id, &span); + } + + if (zstatus != FTDM_SUCCESS) { + zstatus = ftdm_span_find_by_name(id, &span); + } + } + + if (zstatus != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); + continue; + } + + if (!span_id) { + span_id = ftdm_span_get_id(span); + } + + memset(spanparameters, 0, sizeof(spanparameters)); + paramindex = 0; + + if (configname) { + paramindex = add_profile_parameters(cfg, configname, spanparameters, ftdm_array_len(spanparameters)); + if (paramindex) { + ftdm_log(FTDM_LOG_DEBUG, "Added %d parameters from profile %s for span %d\n", paramindex, configname, span_id); + } + } + + /* some defaults first */ + SPAN_CONFIG[span_id].limit_backend = "hash"; + SPAN_CONFIG[span_id].limit_reset_event = FTDM_LIMIT_RESET_ON_TIMEOUT; + + for (param = switch_xml_child(myspan, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + + if (ftdm_array_len(spanparameters) == paramindex) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many parameters for ss7 span, ignoring any parameter after %s\n", var); + break; + } + + if (!strcasecmp(var, "context")) { + context = val; + } else if (!strcasecmp(var, "dialplan")) { + dialplan = val; + } else if (!strcasecmp(var, "call_limit_backend")) { + SPAN_CONFIG[span_id].limit_backend = val; + ftdm_log(FTDM_LOG_DEBUG, "Using limit backend %s for span %d\n", SPAN_CONFIG[span_id].limit_backend, span_id); + } else if (!strcasecmp(var, "call_limit_rate")) { + int calls; + int seconds; + if (sscanf(val, "%d/%d", &calls, &seconds) != 2) { + ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); + } else { + if (calls < 1 || seconds < 1) { + ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter value, minimum call limit must be 1 per second\n", var); + } else { + SPAN_CONFIG[span_id].limit_calls = calls; + SPAN_CONFIG[span_id].limit_seconds = seconds; + } + } + } else if (!strcasecmp(var, "call_limit_reset_event")) { + if (!strcasecmp(val, "answer")) { + SPAN_CONFIG[span_id].limit_reset_event = FTDM_LIMIT_RESET_ON_ANSWER; + } else { + ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter value, only accepted event is 'answer'\n", var); + } + } else { + spanparameters[paramindex].var = var; + spanparameters[paramindex].val = val; + paramindex++; + } + } + + if (ftdm_configure_span_signaling(span, + "sangoma_isdn", + on_clear_channel_signal, + spanparameters) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Error configuring Sangoma ISDN FreeTDM span %d\n", span_id); + continue; + } + SPAN_CONFIG[span_id].span = span; + switch_copy_string(SPAN_CONFIG[span_id].context, context, sizeof(SPAN_CONFIG[span_id].context)); + switch_copy_string(SPAN_CONFIG[span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span_id].dialplan)); + switch_copy_string(SPAN_CONFIG[span_id].type, "Sangoma (ISDN)", sizeof(SPAN_CONFIG[span_id].type)); + ftdm_log(FTDM_LOG_DEBUG, "Configured Sangoma ISDN FreeTDM span %d\n", span_id); + ftdm_span_start(span); + } +} + static switch_status_t load_config(void) { const char *cf = "freetdm.conf"; @@ -2381,7 +2497,8 @@ static switch_status_t load_config(void) unsigned boosti = 0; unsigned int i = 0; ftdm_channel_t *fchan = NULL; - unsigned int chancount = 0; + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *curr = NULL; memset(boost_spans, 0, sizeof(boost_spans)); memset(&globals, 0, sizeof(globals)); @@ -2410,116 +2527,12 @@ static switch_status_t load_config(void) } } - if ((spans = switch_xml_child(cfg, "sangoma_pri_spans")) || (spans = switch_xml_child(cfg, "sangoma_bri_spans"))) { - for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) { - ftdm_status_t zstatus = FTDM_FAIL; - const char *context = "default"; - const char *dialplan = "XML"; - ftdm_conf_parameter_t spanparameters[30]; - char *id = (char *) switch_xml_attr(myspan, "id"); - char *name = (char *) switch_xml_attr(myspan, "name"); - char *configname = (char *) switch_xml_attr(myspan, "cfgprofile"); - ftdm_span_t *span = NULL; - uint32_t span_id = 0; - unsigned paramindex = 0; + if ((spans = switch_xml_child(cfg, "sangoma_pri_spans"))) { + parse_bri_pri_spans(cfg, spans); + } - if (!name && !id) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sangoma isdn span missing required attribute 'id' or 'name', skipping ...\n"); - continue; - } - - if (name) { - zstatus = ftdm_span_find_by_name(name, &span); - } else { - if (switch_is_number(id)) { - span_id = atoi(id); - zstatus = ftdm_span_find(span_id, &span); - } - - if (zstatus != FTDM_SUCCESS) { - zstatus = ftdm_span_find_by_name(id, &span); - } - } - - if (zstatus != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name)); - continue; - } - - if (!span_id) { - span_id = ftdm_span_get_id(span); - } - - memset(spanparameters, 0, sizeof(spanparameters)); - paramindex = 0; - - if (configname) { - paramindex = add_profile_parameters(cfg, configname, spanparameters, ftdm_array_len(spanparameters)); - if (paramindex) { - ftdm_log(FTDM_LOG_DEBUG, "Added %d parameters from profile %s for span %d\n", paramindex, configname, span_id); - } - } - - /* some defaults first */ - SPAN_CONFIG[span_id].limit_backend = "hash"; - SPAN_CONFIG[span_id].limit_reset_event = FTDM_LIMIT_RESET_ON_TIMEOUT; - - for (param = switch_xml_child(myspan, "param"); param; param = param->next) { - char *var = (char *) switch_xml_attr_soft(param, "name"); - char *val = (char *) switch_xml_attr_soft(param, "value"); - - if (ftdm_array_len(spanparameters) == paramindex) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many parameters for ss7 span, ignoring any parameter after %s\n", var); - break; - } - - if (!strcasecmp(var, "context")) { - context = val; - } else if (!strcasecmp(var, "dialplan")) { - dialplan = val; - } else if (!strcasecmp(var, "call_limit_backend")) { - SPAN_CONFIG[span_id].limit_backend = val; - ftdm_log(FTDM_LOG_DEBUG, "Using limit backend %s for span %d\n", SPAN_CONFIG[span_id].limit_backend, span_id); - } else if (!strcasecmp(var, "call_limit_rate")) { - int calls; - int seconds; - if (sscanf(val, "%d/%d", &calls, &seconds) != 2) { - ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var); - } else { - if (calls < 1 || seconds < 1) { - ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter value, minimum call limit must be 1 per second\n", var); - } else { - SPAN_CONFIG[span_id].limit_calls = calls; - SPAN_CONFIG[span_id].limit_seconds = seconds; - } - } - } else if (!strcasecmp(var, "call_limit_reset_event")) { - if (!strcasecmp(val, "answer")) { - SPAN_CONFIG[span_id].limit_reset_event = FTDM_LIMIT_RESET_ON_ANSWER; - } else { - ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter value, only accepted event is 'answer'\n", var); - } - } else { - spanparameters[paramindex].var = var; - spanparameters[paramindex].val = val; - paramindex++; - } - } - - if (ftdm_configure_span_signaling(span, - "sangoma_isdn", - on_clear_channel_signal, - spanparameters) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Error configuring Sangoma ISDN FreeTDM span %d\n", span_id); - continue; - } - SPAN_CONFIG[span_id].span = span; - switch_copy_string(SPAN_CONFIG[span_id].context, context, sizeof(SPAN_CONFIG[span_id].context)); - switch_copy_string(SPAN_CONFIG[span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span_id].dialplan)); - switch_copy_string(SPAN_CONFIG[span_id].type, "Sangoma (ISDN)", sizeof(SPAN_CONFIG[span_id].type)); - ftdm_log(FTDM_LOG_DEBUG, "Configured Sangoma ISDN FreeTDM span %d\n", span_id); - ftdm_span_start(span); - } + if ((spans = switch_xml_child(cfg, "sangoma_bri_spans"))) { + parse_bri_pri_spans(cfg, spans); } switch_core_hash_init(&globals.ss7_configs, module_pool); @@ -2769,11 +2782,13 @@ static switch_status_t load_config(void) switch_set_string(SPAN_CONFIG[span_id].dialplan, dialplan); SPAN_CONFIG[span_id].analog_options = analog_options | globals.analog_options; - chancount = ftdm_span_get_chan_count(span); - for (i = 1; i <= chancount; i++) { - fchan = ftdm_span_get_channel(span, i); + chaniter = ftdm_span_get_chan_iterator(span, NULL); + curr = chaniter; + for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { + fchan = ftdm_iterator_current(curr); ftdm_channel_set_private(fchan, &SPAN_CONFIG[span_id].pvts[i]); } + ftdm_iterator_free(chaniter); if (dial_regex) { switch_set_string(SPAN_CONFIG[span_id].dial_regex, dial_regex); @@ -3436,7 +3451,10 @@ void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stre const char *chan_type; const char *state; const char *last_state; + const char *uuid = NULL; + char sessionid[255]; float txgain, rxgain; + switch_core_session_t *session = NULL; ftdm_alarm_flag_t alarmflag; ftdm_caller_data_t *caller_data; ftdm_channel_t *ftdmchan; @@ -3446,6 +3464,7 @@ void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stre return; } + strcpy(sessionid, "(none)"); ftdmchan = ftdm_span_get_channel(span, chan_id); span_id = ftdm_span_get_id(span); @@ -3460,6 +3479,16 @@ void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stre ftdm_channel_get_sig_status(ftdmchan, &sigstatus); ftdm_channel_get_alarms(ftdmchan, &alarmflag); + uuid = ftdm_channel_get_uuid(ftdmchan, 0); + if (!zstr(uuid)) { + if (!(session = switch_core_session_locate(uuid))) { + snprintf(sessionid, sizeof(sessionid), "%s (dead)", uuid); + } else { + snprintf(sessionid, sizeof(sessionid), "%s", uuid); + switch_core_session_rwunlock(session); + } + } + stream->write_function(stream, "span_id: %u\n" "chan_id: %u\n" @@ -3479,7 +3508,8 @@ void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stre "aniII: %s\n" "dnis: %s\n" "rdnis: %s\n" - "cause: %s\n\n", + "cause: %s\n" + "session: %s\n\n", span_id, chan_id, phspan_id, @@ -3498,7 +3528,8 @@ void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stre caller_data->aniII, caller_data->dnis.digits, caller_data->rdnis.digits, - switch_channel_cause2str(caller_data->hangup_cause)); + switch_channel_cause2str(caller_data->hangup_cause), + sessionid); } void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stream) @@ -3581,6 +3612,8 @@ SWITCH_STANDARD_API(ft_function) { char *mycmd = NULL, *argv[10] = { 0 }; int argc = 0; + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *curr = NULL; if (!zstr(cmd) && (mycmd = strdup(cmd))) { argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); @@ -3626,11 +3659,11 @@ SWITCH_STANDARD_API(ft_function) dump_chan_xml(span, chan_id, stream); } } else { - uint32_t j; - uint32_t ccount = ftdm_span_get_chan_count(span); - for (j = 1; j <= ccount; j++) { - dump_chan_xml(span, j, stream); + chaniter = ftdm_span_get_chan_iterator(span, NULL); + for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { + dump_chan_xml(span, ftdm_channel_get_id(ftdm_iterator_current(curr)), stream); } + ftdm_iterator_free(chaniter); } } @@ -3643,15 +3676,20 @@ SWITCH_STANDARD_API(ft_function) if(chan_id > ftdm_span_get_chan_count(span)) { stream->write_function(stream, "-ERR invalid channel\n"); } else { + char *dbgstr = NULL; + ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id); dump_chan(span, chan_id, stream); + dbgstr = ftdm_channel_get_history_str(fchan); + stream->write_function(stream, "%s\n", dbgstr); + ftdm_free(dbgstr); } } else { - uint32_t j; - uint32_t ccount = ftdm_span_get_chan_count(span); stream->write_function(stream, "+OK\n"); - for (j = 1; j <= ccount; j++) { - dump_chan(span, j, stream); + chaniter = ftdm_span_get_chan_iterator(span, NULL); + for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { + dump_chan(span, ftdm_channel_get_id(ftdm_iterator_current(curr)), stream); } + ftdm_iterator_free(chaniter); } } @@ -3972,7 +4010,7 @@ SWITCH_STANDARD_API(ft_function) if (rply) { stream->write_function(stream, "%s", rply); - free(rply); + ftdm_free(rply); } else { stream->write_function(stream, "-ERR Usage: %s\n", FT_SYNTAX); } @@ -4057,8 +4095,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load) ftdm_global_set_logger(ftdm_logger); - ftdm_cpu_monitor_disable(); - + ftdm_global_set_mod_directory(SWITCH_GLOBAL_dirs.mod_dir); + + ftdm_global_set_config_directory(SWITCH_GLOBAL_dirs.conf_dir); + if (ftdm_global_init() != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_ERROR, "Error loading FreeTDM\n"); return SWITCH_STATUS_TERM; diff --git a/libs/freetdm/sample/boost/ftdmstart.c b/libs/freetdm/sample/boost/ftdmstart.c index 972ed43146..bff0664bce 100644 --- a/libs/freetdm/sample/boost/ftdmstart.c +++ b/libs/freetdm/sample/boost/ftdmstart.c @@ -313,13 +313,6 @@ int main(int argc, char *argv[]) /* set the logging level to use */ ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG); - /* this is optional. - * cpu monitor is a default feature in freetdm that launches 1 thread - * to monitor system-wide CPU usage. If it goes above a predefined threshold - * it will stop accepting calls to try to protect the quality of current calls */ - ftdm_cpu_monitor_disable(); - - /* Initialize the FTDM library */ if (ftdm_global_init() != FTDM_SUCCESS) { fprintf(stderr, "Error loading FreeTDM\n"); diff --git a/libs/freetdm/sample/dso/ftdmload.c b/libs/freetdm/sample/dso/ftdmload.c index 5b150d67ed..80bcc02fc0 100644 --- a/libs/freetdm/sample/dso/ftdmload.c +++ b/libs/freetdm/sample/dso/ftdmload.c @@ -134,8 +134,6 @@ int main(int argc, char *argv[]) ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG); - ftdm_cpu_monitor_disable(); - if (ftdm_global_init() != FTDM_SUCCESS) { fprintf(stderr, "Error loading FreeTDM\n"); exit(-1); diff --git a/libs/freetdm/sample/sched/ftdmsched.c b/libs/freetdm/sample/sched/ftdmsched.c index 5cd7d6340a..e6e391ee4b 100644 --- a/libs/freetdm/sample/sched/ftdmsched.c +++ b/libs/freetdm/sample/sched/ftdmsched.c @@ -73,8 +73,6 @@ int main(int argc, char *argv[]) ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG); - ftdm_cpu_monitor_disable(); - if (ftdm_global_init() != FTDM_SUCCESS) { fprintf(stderr, "Error loading FreeTDM\n"); exit(-1); diff --git a/libs/freetdm/src/ftdm_config.c b/libs/freetdm/src/ftdm_config.c index 4ba2e19c67..1b023e93eb 100644 --- a/libs/freetdm/src/ftdm_config.c +++ b/libs/freetdm/src/ftdm_config.c @@ -37,6 +37,27 @@ #include "private/ftdm_core.h" +#ifndef FTDM_MOD_DIR +#define FTDM_MOD_DIR "." +#endif + +#define FTDM_MAX_CONF_DIR 512 + +static char g_ftdm_config_dir[FTDM_MAX_CONF_DIR] = FTDM_CONFIG_DIR; +static char g_ftdm_mod_dir[FTDM_MAX_CONF_DIR] = FTDM_MOD_DIR; + +FT_DECLARE(void) ftdm_global_set_mod_directory(const char *path) +{ + snprintf(g_ftdm_mod_dir, sizeof(g_ftdm_mod_dir), "%s", path); + ftdm_log(FTDM_LOG_DEBUG, "New mod directory: %s\n", g_ftdm_mod_dir); +} + +FT_DECLARE(void) ftdm_global_set_config_directory(const char *path) +{ + snprintf(g_ftdm_config_dir, sizeof(g_ftdm_config_dir), "%s", path); + ftdm_log(FTDM_LOG_DEBUG, "New config directory: %s\n", g_ftdm_config_dir); +} + int ftdm_config_open_file(ftdm_config_t *cfg, const char *file_path) { FILE *f; @@ -46,7 +67,7 @@ int ftdm_config_open_file(ftdm_config_t *cfg, const char *file_path) if (file_path[0] == '/') { path = file_path; } else { - snprintf(path_buf, sizeof(path_buf), "%s%s%s", FTDM_CONFIG_DIR, FTDM_PATH_SEPARATOR, file_path); + snprintf(path_buf, sizeof(path_buf), "%s%s%s", g_ftdm_config_dir, FTDM_PATH_SEPARATOR, file_path); path = path_buf; } @@ -64,7 +85,7 @@ int ftdm_config_open_file(ftdm_config_t *cfg, const char *file_path) int last = -1; char *var, *val; - snprintf(path_buf, sizeof(path_buf), "%s%sfreetdm.conf", FTDM_CONFIG_DIR, FTDM_PATH_SEPARATOR); + snprintf(path_buf, sizeof(path_buf), "%s%sfreetdm.conf", g_ftdm_config_dir, FTDM_PATH_SEPARATOR); path = path_buf; if ((f = fopen(path, "r")) == 0) { @@ -268,13 +289,24 @@ FT_DECLARE(ftdm_status_t) ftdm_conf_node_create(const char *name, ftdm_conf_node if (parent) { /* store who my parent is */ newnode->parent = parent; - /* save any siblings */ - sibling = parent->child; - /* as a newborn I am first */ - parent->child = newnode; - if (sibling) { - /* store a pointer to my next sibling */ - newnode->next = sibling; + + /* arrange them in FIFO order (newnode should be last) */ + if (!parent->child) { + /* we're the first node being added */ + parent->child = newnode; + } else { + if (!parent->last) { + /* we're the second node being added */ + parent->last = newnode; + parent->child->next = newnode; + newnode->prev = parent->child; + } else { + /* we're the third or Nth node to be added */ + sibling = parent->last; + sibling->next = newnode; + parent->last = newnode; + newnode->prev = sibling; + } } } @@ -318,6 +350,26 @@ FT_DECLARE(ftdm_status_t) ftdm_conf_node_destroy(ftdm_conf_node_t *node) return FTDM_SUCCESS; } +FT_DECLARE(char *) ftdm_build_dso_path(const char *name, char *path, ftdm_size_t len) +{ +#ifdef WIN32 + const char *ext = ".dll"; + //const char *EXT = ".DLL"; +#elif defined (MACOSX) || defined (DARWIN) + const char *ext = ".dylib"; + //const char *EXT = ".DYLIB"; +#else + const char *ext = ".so"; + //const char *EXT = ".SO"; +#endif + if (*name == *FTDM_PATH_SEPARATOR) { + snprintf(path, len, "%s%s", name, ext); + } else { + snprintf(path, len, "%s%s%s%s", g_ftdm_mod_dir, FTDM_PATH_SEPARATOR, name, ext); + } + return path; +} + /* For Emacs: * Local Variables: * mode:c diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index b275403c85..99c0c86ed5 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -50,6 +50,7 @@ #endif #include "ftdm_cpu_monitor.h" +#define FORCE_HANGUP_TIMER 3000 #define SPAN_PENDING_CHANS_QUEUE_SIZE 1000 #define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000 #define FTDM_READ_TRACE_INDEX 0 @@ -85,6 +86,7 @@ FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void) } typedef struct { + uint8_t enabled; uint8_t running; uint8_t alarm; uint32_t interval; @@ -102,6 +104,7 @@ static struct { ftdm_mutex_t *mutex; ftdm_mutex_t *span_mutex; ftdm_mutex_t *group_mutex; + ftdm_sched_t *timingsched; uint32_t span_index; uint32_t group_index; uint32_t running; @@ -110,8 +113,6 @@ static struct { cpu_monitor_t cpu_monitor; } globals; -static uint8_t ftdm_cpu_monitor_disabled = 0; - enum ftdm_enum_cpu_alarm_action_flags { FTDM_CPU_ALARM_ACTION_WARN = (1 << 0), @@ -243,6 +244,39 @@ static __inline__ void ftdm_std_free(void *pool, void *ptr) free(ptr); } +static void ftdm_set_echocancel_call_begin(ftdm_channel_t *chan) +{ + ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan); + if (ftdm_channel_test_feature(chan, FTDM_CHANNEL_FEATURE_HWEC)) { + if (ftdm_channel_test_feature(chan, FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE)) { + if (caller_data->bearer_capability != FTDM_BEARER_CAP_64K_UNRESTRICTED) { + ftdm_channel_command(chan, FTDM_COMMAND_ENABLE_ECHOCANCEL, NULL); + } + } else { + if (caller_data->bearer_capability == FTDM_BEARER_CAP_64K_UNRESTRICTED) { + ftdm_channel_command(chan, FTDM_COMMAND_DISABLE_ECHOCANCEL, NULL); + } + } + } +} + +static void ftdm_set_echocancel_call_end(ftdm_channel_t *chan) +{ + ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan); + if (ftdm_channel_test_feature(chan, FTDM_CHANNEL_FEATURE_HWEC)) { + if (ftdm_channel_test_feature(chan, FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE)) { + if (caller_data->bearer_capability != FTDM_BEARER_CAP_64K_UNRESTRICTED) { + ftdm_channel_command(chan, FTDM_COMMAND_DISABLE_ECHOCANCEL, NULL); + } + } else { + if (caller_data->bearer_capability == FTDM_BEARER_CAP_64K_UNRESTRICTED) { + ftdm_channel_command(chan, FTDM_COMMAND_ENABLE_ECHOCANCEL, NULL); + } + } + } +} + + FT_DECLARE_DATA ftdm_memory_handler_t g_ftdm_mem_handler = { /*.pool =*/ NULL, @@ -463,6 +497,7 @@ static ftdm_status_t ftdm_span_destroy(ftdm_span_t *span) status = FTDM_FAIL; } ftdm_safe_free(span->type); + ftdm_safe_free(span->name); ftdm_safe_free(span->dtmf_hangup); } @@ -536,7 +571,7 @@ static void ftdm_span_add(ftdm_span_t *span) } else { globals.spans = span; } - hashtable_insert(globals.span_hash, (void *)span->name, span, HASHTABLE_FLAG_NONE); + hashtable_insert(globals.span_hash, (void *)span->name, span, HASHTABLE_FLAG_FREE_VALUE); ftdm_mutex_unlock(globals.span_mutex); } @@ -1249,6 +1284,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(const char *file, const char *f 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; @@ -1290,6 +1326,16 @@ end: 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); @@ -1747,7 +1793,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t *best_rated = NULL; ftdm_status_t status = FTDM_FAIL; int best_rate = 0; - int may_be_available = 0; *ftdmchan = NULL; @@ -1782,38 +1827,55 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_mutex_lock(check->mutex); + /* The following if's and gotos replace a big if (this || this || this || this) else { nothing; } */ + + /* if it is not a voice channel, nothing else to check to open it */ + if (!FTDM_IS_VOICE_CHANNEL(check)) { + goto openchan; + } + + /* if it's an FXS device with a call active and has callwaiting enabled, we allow to open it twice */ + if (check->type == FTDM_CHAN_TYPE_FXS + && check->token_count == 1 + && ftdm_channel_test_feature(check, FTDM_CHANNEL_FEATURE_CALLWAITING)) { + goto openchan; + } + + /* if channel is available, time to open it */ + if (chan_is_avail(check)) { + goto openchan; + } + + /* not available, but still might be available ... */ calculate_best_rate(check, &best_rated, &best_rate); if (best_rated) { - may_be_available = 1; + goto openchan; } - /* the channel is only allowed to be open if not in use, or, for FXS devices with a call with call waiting enabled */ - if ( - (check->type == FTDM_CHAN_TYPE_FXS - && check->token_count == 1 - && ftdm_channel_test_feature(check, FTDM_CHANNEL_FEATURE_CALLWAITING)) - || - chan_is_avail(check) - || - may_be_available) { - if (!ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) { - status = check->fio->open(check); - if (status == FTDM_SUCCESS) { - ftdm_set_flag(check, FTDM_CHANNEL_OPEN); - } - } else { - status = FTDM_SUCCESS; + /* channel is unavailable, do not open the channel */ + goto unlockchan; + +openchan: + if (!ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) { + status = check->fio->open(check); + if (status == FTDM_SUCCESS) { + ftdm_set_flag(check, FTDM_CHANNEL_OPEN); } - ftdm_set_flag(check, FTDM_CHANNEL_INUSE); - ftdm_set_flag(check, FTDM_CHANNEL_OUTBOUND); - *ftdmchan = check; + } else { + status = FTDM_SUCCESS; } + ftdm_set_flag(check, FTDM_CHANNEL_INUSE); + ftdm_set_flag(check, FTDM_CHANNEL_OUTBOUND); + *ftdmchan = check; +unlockchan: ftdm_mutex_unlock(check->mutex); done: - ftdm_mutex_unlock(globals.mutex); + if (status != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_ERROR, "Failed to open channel %d:%d\n", span_id, chan_id); + } return status; } @@ -1996,11 +2058,17 @@ done: static ftdm_status_t call_hangup(ftdm_channel_t *chan, const char *file, const char *func, int line) { ftdm_set_flag(chan, FTDM_CHANNEL_USER_HANGUP); + + ftdm_set_echocancel_call_end(chan); + if (chan->state != FTDM_CHANNEL_STATE_DOWN) { if (chan->state == FTDM_CHANNEL_STATE_HANGUP) { /* make user's life easier, and just ignore double hangup requests */ return FTDM_SUCCESS; } + 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); } else { /* the signaling stack did not touch the state, @@ -2158,10 +2226,12 @@ done: FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan) { ftdm_status_t status = FTDM_FAIL; - + ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "null channel"); ftdm_assert_return(ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND), FTDM_FAIL, "Call place, but outbound flag not set\n"); + ftdm_set_echocancel_call_begin(ftdmchan); + ftdm_channel_lock(ftdmchan); if (ftdmchan->span->outgoing_call) { @@ -2282,6 +2352,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan) close_dtmf_debug(ftdmchan); #endif ftdm_channel_clear_vars(ftdmchan); + if (ftdmchan->hangup_timer) { + ftdm_sched_cancel_timer(globals.timingsched, ftdmchan->hangup_timer); + } ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN; ftdmchan->state = FTDM_CHANNEL_STATE_DOWN; @@ -3524,16 +3597,56 @@ done: return var; } -FT_DECLARE(ftdm_iterator_t *) ftdm_channel_get_var_iterator(const ftdm_channel_t *ftdmchan) +static ftdm_iterator_t *get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter) { - ftdm_hash_iterator_t *iter = NULL; + int allocated = 0; + if (iter) { + if (iter->type != type) { + ftdm_log(FTDM_LOG_ERROR, "Cannot switch iterator types\n"); + return NULL; + } + allocated = iter->allocated; + memset(iter, 0, sizeof(*iter)); + iter->type = type; + iter->allocated = allocated; + return iter; + } + iter = ftdm_calloc(1, sizeof(*iter)); + if (!iter) { + return NULL; + } + iter->type = type; + iter->allocated = 1; + return iter; +} + +FT_DECLARE(ftdm_iterator_t *) ftdm_channel_get_var_iterator(const ftdm_channel_t *ftdmchan, ftdm_iterator_t *iter) +{ + ftdm_hash_iterator_t *hashiter = NULL; ftdm_channel_lock(ftdmchan); - - iter = ftdmchan->variable_hash == NULL ? NULL : hashtable_first(ftdmchan->variable_hash); - + hashiter = ftdmchan->variable_hash == NULL ? NULL : hashtable_first(ftdmchan->variable_hash); ftdm_channel_unlock(ftdmchan); + + if (hashiter == NULL) { + return NULL; + } + + if (!(iter = get_iterator(FTDM_ITERATOR_VARS, iter))) { + return NULL; + } + iter->pvt.hashiter = hashiter; + return iter; +} + +FT_DECLARE(ftdm_iterator_t *) ftdm_span_get_chan_iterator(const ftdm_span_t *span, ftdm_iterator_t *iter) +{ + if (!(iter = get_iterator(FTDM_ITERATOR_CHANS, iter))) { + return NULL; + } + iter->pvt.chaniter.index = 1; + iter->pvt.chaniter.span = span; return iter; } @@ -3545,11 +3658,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_get_current_var(ftdm_iterator_t *iter, co *var_name = NULL; *var_val = NULL; - if (!iter) { - return FTDM_FAIL; - } + ftdm_assert_return(iter && (iter->type == FTDM_ITERATOR_VARS) && iter->pvt.hashiter, FTDM_FAIL, "Cannot get variable from invalid iterator!\n"); - hashtable_this(iter, &key, NULL, &val); + hashtable_this(iter->pvt.hashiter, &key, NULL, &val); *var_name = key; *var_val = val; @@ -3559,16 +3670,175 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_get_current_var(ftdm_iterator_t *iter, co FT_DECLARE(ftdm_iterator_t *) ftdm_iterator_next(ftdm_iterator_t *iter) { - if (!iter) { - return NULL; + ftdm_assert_return(iter && iter->type, NULL, "Invalid iterator\n"); + + switch (iter->type) { + case FTDM_ITERATOR_VARS: + if (!iter->pvt.hashiter) { + return NULL; + } + iter->pvt.hashiter = hashtable_next(iter->pvt.hashiter); + if (!iter->pvt.hashiter) { + return NULL; + } + return iter; + case FTDM_ITERATOR_CHANS: + ftdm_assert_return(iter->pvt.chaniter.index, NULL, "channel iterator index cannot be zero!\n"); + if (iter->pvt.chaniter.index == iter->pvt.chaniter.span->chan_count) { + return NULL; + } + iter->pvt.chaniter.index++; + return iter; + default: + break; } - return hashtable_next(iter); + + ftdm_assert_return(0, NULL, "Unknown iterator type\n"); + return NULL; +} + +FT_DECLARE(void *) ftdm_iterator_current(ftdm_iterator_t *iter) +{ + const void *key = NULL; + void *val = NULL; + + ftdm_assert_return(iter && iter->type, NULL, "Invalid iterator\n"); + + switch (iter->type) { + case FTDM_ITERATOR_VARS: + hashtable_this(iter->pvt.hashiter, &key, NULL, &val); + /* I decided to return the key instead of the value since the value can be retrieved using the key */ + return (void *)key; + case FTDM_ITERATOR_CHANS: + ftdm_assert_return(iter->pvt.chaniter.index, NULL, "channel iterator index cannot be zero!\n"); + ftdm_assert_return(iter->pvt.chaniter.index <= iter->pvt.chaniter.span->chan_count, NULL, "channel iterator index bigger than span chan count!\n"); + return iter->pvt.chaniter.span->channels[iter->pvt.chaniter.index]; + default: + break; + } + + ftdm_assert_return(0, NULL, "Unknown iterator type\n"); + return NULL; +} + +FT_DECLARE(ftdm_status_t) ftdm_iterator_free(ftdm_iterator_t *iter) +{ + /* it's valid to pass a NULL iterator, do not return failure */ + if (!iter) { + return FTDM_SUCCESS; + } + + if (!iter->allocated) { + memset(iter, 0, sizeof(*iter)); + return FTDM_SUCCESS; + } + + ftdm_assert_return(iter->type, FTDM_FAIL, "Cannot free invalid iterator\n"); + ftdm_safe_free(iter); + + return FTDM_SUCCESS; } static struct { ftdm_io_interface_t *pika_interface; } interfaces; +static void print_channels_by_state(ftdm_stream_handle_t *stream, ftdm_channel_state_t state, int not, int *count) +{ + ftdm_hash_iterator_t *i = NULL; + ftdm_span_t *span; + ftdm_channel_t *fchan = NULL; + ftdm_iterator_t *citer = NULL; + ftdm_iterator_t *curr = NULL; + const void *key = NULL; + void *val = NULL; + + *count = 0; + + ftdm_mutex_lock(globals.mutex); + + for (i = hashtable_first(globals.span_hash); i; i = hashtable_next(i)) { + hashtable_this(i, &key, NULL, &val); + if (!key || !val) { + break; + } + span = val; + citer = ftdm_span_get_chan_iterator(span, NULL); + if (!citer) { + continue; + } + for (curr = citer ; curr; curr = ftdm_iterator_next(curr)) { + fchan = ftdm_iterator_current(curr); + if (not && (fchan->state != state)) { + stream->write_function(stream, "[s%dc%d][%d:%d] in state %s\n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, ftdm_channel_state2str(fchan->state)); + (*count)++; + } else if (!not && (fchan->state == state)) { + stream->write_function(stream, "[s%dc%d][%d:%d] in state %s\n", + fchan->span_id, fchan->chan_id, + fchan->physical_span_id, fchan->physical_chan_id, ftdm_channel_state2str(fchan->state)); + (*count)++; + } + } + ftdm_iterator_free(citer); + } + + ftdm_mutex_unlock(globals.mutex); +} + +static char *handle_core_command(const char *cmd) +{ + char *mycmd = NULL; + int argc = 0; + int count = 0; + int not = 0; + char *argv[10] = { 0 }; + char *state = NULL; + ftdm_channel_state_t i = FTDM_CHANNEL_STATE_INVALID; + ftdm_stream_handle_t stream = { 0 }; + + FTDM_STANDARD_STREAM(stream); + + if (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"); + goto done; + } + + if (!strcasecmp(argv[0], "state")) { + if (argc < 2) { + stream.write_function(&stream, "core state command requires an argument\n"); + goto done; + } + state = argv[1]; + if (argv[1][0] == '!') { + not = 1; + state++; + } + for (i = FTDM_CHANNEL_STATE_DOWN; i < FTDM_CHANNEL_STATE_INVALID; i++) { + if (!strcasecmp(state, ftdm_channel_state2str(i))) { + break; + } + } + if (i == FTDM_CHANNEL_STATE_INVALID) { + stream.write_function(&stream, "invalid state %s\n", state); + goto done; + } + print_channels_by_state(&stream, i, not, &count); + stream.write_function(&stream, "\nTotal channels %s %s: %d\n", not ? "not in state" : "in state", ftdm_channel_state2str(i), count); + } else { + stream.write_function(&stream, "invalid core command %s\n", argv[0]); + } + +done: + ftdm_safe_free(mycmd); + + return stream.data; +} + FT_DECLARE(char *) ftdm_api_execute(const char *cmd) { ftdm_io_interface_t *fio = NULL; @@ -3583,6 +3853,10 @@ FT_DECLARE(char *) ftdm_api_execute(const char *cmd) } type = dup; + + if (!strcasecmp(type, "core")) { + return handle_core_command(cmd); + } ftdm_mutex_lock(globals.mutex); if (!(fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, (void *)type))) { @@ -3884,7 +4158,14 @@ static ftdm_status_t load_config(void) ftdm_log(FTDM_LOG_ERROR, "unknown span variable '%s'\n", var); } } else if (!strncasecmp(cfg.category, "general", 7)) { - if (!strncasecmp(var, "cpu_monitoring_interval", sizeof("cpu_monitoring_interval")-1)) { + if (!strncasecmp(var, "cpu_monitor", sizeof("cpu_monitor")-1)) { + if (!strncasecmp(val, "yes", 3)) { + globals.cpu_monitor.enabled = 1; + if (!globals.cpu_monitor.alarm_action_flags) { + globals.cpu_monitor.alarm_action_flags |= FTDM_CPU_ALARM_ACTION_WARN; + } + } + } else if (!strncasecmp(var, "cpu_monitoring_interval", sizeof("cpu_monitoring_interval")-1)) { if (atoi(val) > 0) { globals.cpu_monitor.interval = atoi(val); } else { @@ -3963,27 +4244,6 @@ static ftdm_status_t process_module_config(ftdm_io_interface_t *fio) return FTDM_SUCCESS; } -FT_DECLARE(char *) ftdm_build_dso_path(const char *name, char *path, ftdm_size_t len) -{ -#ifdef WIN32 - const char *ext = ".dll"; - //const char *EXT = ".DLL"; -#define FTDM_MOD_DIR "." //todo -#elif defined (MACOSX) || defined (DARWIN) - const char *ext = ".dylib"; - //const char *EXT = ".DYLIB"; -#else - const char *ext = ".so"; - //const char *EXT = ".SO"; -#endif - if (*name == *FTDM_PATH_SEPARATOR) { - snprintf(path, len, "%s%s", name, ext); - } else { - snprintf(path, len, "%s%s%s%s", FTDM_MOD_DIR, FTDM_PATH_SEPARATOR, name, ext); - } - return path; -} - FT_DECLARE(ftdm_status_t) ftdm_global_add_io_interface(ftdm_io_interface_t *interface1) { ftdm_status_t ret = FTDM_SUCCESS; @@ -4499,6 +4759,21 @@ FT_DECLARE(ftdm_status_t) ftdm_span_trigger_signals(const ftdm_span_t *span) return FTDM_SUCCESS; } + +static void execute_safety_hangup(void *data) +{ + ftdm_channel_t *fchan = data; + ftdm_channel_lock(fchan); + 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__); + } else { + ftdm_log_chan(fchan, FTDM_LOG_CRIT, "Not performing safety hangup, channel state is %s\n", ftdm_channel_state2str(fchan->state)); + } + ftdm_channel_unlock(fchan); +} + FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) { if (sigmsg->channel) { @@ -4520,11 +4795,15 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t break; case FTDM_SIGEVENT_START: - /* when cleaning up the public API I added this because mod_freetdm.c on_fxs_signal was - * doing it during SIGEVENT_START, but now that flags are private they can't, wonder if - * is needed at all? - * */ - ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_HOLD); + { + ftdm_set_echocancel_call_begin(sigmsg->channel); + + /* when cleaning up the public API I added this because mod_freetdm.c on_fxs_signal was + * doing it during SIGEVENT_START, but now that flags are private they can't, wonder if + * is needed at all? + * */ + ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_HOLD); + } break; case FTDM_SIGEVENT_STOP: @@ -4532,6 +4811,11 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Ignoring SIGEVENT_STOP since user already requested hangup\n"); goto done; } + if (sigmsg->channel->state == FTDM_CHANNEL_STATE_TERMINATING) { + ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Scheduling safety hangup timer\n"); + /* if the user does not move us to hangup in 2 seconds, we will do it ourselves */ + ftdm_sched_timer(globals.timingsched, "safety-hangup", FORCE_HANGUP_TIMER, execute_safety_hangup, sigmsg->channel, &sigmsg->channel->hangup_timer); + } break; default: @@ -4630,12 +4914,6 @@ static void ftdm_cpu_monitor_stop(void) ftdm_interrupt_destroy(&globals.cpu_monitor.interrupt); } -FT_DECLARE(void) ftdm_cpu_monitor_disable(void) -{ - ftdm_cpu_monitor_disabled = 1; -} - - FT_DECLARE(ftdm_status_t) ftdm_global_init(void) { memset(&globals, 0, sizeof(globals)); @@ -4653,6 +4931,14 @@ FT_DECLARE(ftdm_status_t) ftdm_global_init(void) ftdm_mutex_create(&globals.span_mutex); ftdm_mutex_create(&globals.group_mutex); ftdm_sched_global_init(); + if (ftdm_sched_create(&globals.timingsched, "freetdm-master") != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT, "Failed to create master timing schedule context\n"); + return FTDM_FAIL; + } + if (ftdm_sched_free_run(globals.timingsched) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT, "Failed to run master timing schedule context\n"); + return FTDM_FAIL; + } globals.running = 1; return FTDM_SUCCESS; } @@ -4669,8 +4955,9 @@ FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void) ftdm_log(FTDM_LOG_NOTICE, "Modules configured: %d \n", modcount); + globals.cpu_monitor.enabled = 0; globals.cpu_monitor.interval = 1000; - globals.cpu_monitor.alarm_action_flags = FTDM_CPU_ALARM_ACTION_WARN | FTDM_CPU_ALARM_ACTION_REJECT; + globals.cpu_monitor.alarm_action_flags = 0; globals.cpu_monitor.set_alarm_threshold = 80; globals.cpu_monitor.reset_alarm_threshold = 70; @@ -4680,7 +4967,12 @@ FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void) return FTDM_FAIL; } - if (!ftdm_cpu_monitor_disabled) { + if (globals.cpu_monitor.enabled) { + ftdm_log(FTDM_LOG_INFO, "CPU Monitor is running interval:%d lo-thres:%d hi-thres:%d\n", + globals.cpu_monitor.interval, + globals.cpu_monitor.set_alarm_threshold, + globals.cpu_monitor.reset_alarm_threshold); + if (ftdm_cpu_monitor_start() != FTDM_SUCCESS) { return FTDM_FAIL; } @@ -4699,14 +4991,19 @@ FT_DECLARE(uint32_t) ftdm_running(void) FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void) { ftdm_span_t *sp; - uint32_t sanity = 100; time_end(); + /* many freetdm event loops rely on this variable to decide when to stop, do this first */ globals.running = 0; + /* stop the scheduling thread */ + ftdm_free_sched_stop(); + + /* stop the cpu monitor thread */ ftdm_cpu_monitor_stop(); + /* now destroy channels and spans */ globals.span_index = 0; ftdm_span_close_all(); @@ -4731,24 +5028,20 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void) globals.spans = NULL; ftdm_mutex_unlock(globals.span_mutex); + /* destroy signaling and io modules */ ftdm_unload_modules(); - while (ftdm_free_sched_running() && --sanity) { - ftdm_log(FTDM_LOG_DEBUG, "Waiting for schedule thread to finish\n"); - ftdm_sleep(100); - } - - if (!sanity) { - ftdm_log(FTDM_LOG_CRIT, "schedule thread did not stop running, we may crash on shutdown\n"); - } - + /* finally destroy the globals */ ftdm_mutex_lock(globals.mutex); + ftdm_sched_destroy(&globals.timingsched); hashtable_destroy(globals.interface_hash); - hashtable_destroy(globals.module_hash); + hashtable_destroy(globals.module_hash); hashtable_destroy(globals.span_hash); + hashtable_destroy(globals.group_hash); ftdm_mutex_unlock(globals.mutex); ftdm_mutex_destroy(&globals.mutex); ftdm_mutex_destroy(&globals.span_mutex); + ftdm_mutex_destroy(&globals.group_mutex); memset(&globals, 0, sizeof(globals)); return FTDM_SUCCESS; @@ -5071,6 +5364,42 @@ 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; +} + /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftdm_sched.c b/libs/freetdm/src/ftdm_sched.c index 5aacc202bf..a7736ce8a2 100644 --- a/libs/freetdm/src/ftdm_sched.c +++ b/libs/freetdm/src/ftdm_sched.c @@ -34,6 +34,8 @@ #include "private/ftdm_core.h" +typedef struct ftdm_timer ftdm_timer_t; + static struct { ftdm_sched_t *freeruns; ftdm_mutex_t *mutex; @@ -42,6 +44,7 @@ static struct { struct ftdm_sched { char name[80]; + ftdm_timer_id_t currid; ftdm_mutex_t *mutex; ftdm_timer_t *timers; int freerun; @@ -51,6 +54,7 @@ struct ftdm_sched { struct ftdm_timer { char name[80]; + ftdm_timer_id_t id; #ifdef __linux__ struct timeval time; #endif @@ -172,6 +176,24 @@ FT_DECLARE(ftdm_bool_t) ftdm_free_sched_running(void) return sched_globals.running; } +FT_DECLARE(ftdm_bool_t) ftdm_free_sched_stop(void) +{ + /* currently we really dont stop the thread here, we rely on freetdm being shutdown and ftdm_running() to be false + * so the scheduling thread dies and we just wait for it here */ + uint32_t sanity = 100; + while (ftdm_free_sched_running() && --sanity) { + ftdm_log(FTDM_LOG_DEBUG, "Waiting for main schedule thread to finish\n"); + ftdm_sleep(100); + } + + if (!sanity) { + ftdm_log(FTDM_LOG_CRIT, "schedule thread did not stop running, we may crash on shutdown\n"); + return FTDM_FALSE; + } + + return FTDM_TRUE; +} + FT_DECLARE(ftdm_status_t) ftdm_sched_create(ftdm_sched_t **sched, const char *name) { ftdm_sched_t *newsched = NULL; @@ -191,6 +213,7 @@ FT_DECLARE(ftdm_status_t) ftdm_sched_create(ftdm_sched_t **sched, const char *na } ftdm_set_string(newsched->name, name); + newsched->currid = 1; *sched = newsched; ftdm_log(FTDM_LOG_DEBUG, "Created schedule %s\n", name); @@ -219,12 +242,13 @@ FT_DECLARE(ftdm_status_t) ftdm_sched_run(ftdm_sched_t *sched) int rc = -1; void *data; struct timeval now; + ftdm_assert_return(sched != NULL, FTDM_EINVAL, "sched is null!\n"); - ftdm_mutex_lock(sched->mutex); - tryagain: + ftdm_mutex_lock(sched->mutex); + rc = gettimeofday(&now, NULL); if (rc == -1) { ftdm_log(FTDM_LOG_ERROR, "Failed to retrieve time of day\n"); @@ -257,11 +281,16 @@ tryagain: runtimer->prev->next = runtimer->next; } + runtimer->id = 0; ftdm_safe_free(runtimer); + /* avoid deadlocks by releasing the sched lock before triggering callbacks */ + ftdm_mutex_unlock(sched->mutex); + callback(data); /* after calling a callback we must start the scanning again since the - * callback may have added or cancelled timers to the linked list */ + * callback or some other thread may have added or cancelled timers to + * the linked list */ goto tryagain; } } @@ -283,7 +312,7 @@ done: } FT_DECLARE(ftdm_status_t) ftdm_sched_timer(ftdm_sched_t *sched, const char *name, - int ms, ftdm_sched_callback_t callback, void *data, ftdm_timer_t **timer) + int ms, ftdm_sched_callback_t callback, void *data, ftdm_timer_id_t *timerid) { ftdm_status_t status = FTDM_FAIL; #ifdef __linux__ @@ -296,8 +325,8 @@ FT_DECLARE(ftdm_status_t) ftdm_sched_timer(ftdm_sched_t *sched, const char *name ftdm_assert_return(callback != NULL, FTDM_EINVAL, "sched callback is null!\n"); ftdm_assert_return(ms > 0, FTDM_EINVAL, "milliseconds must be bigger than 0!\n"); - if (timer) { - *timer = NULL; + if (timerid) { + *timerid = 0; } rc = gettimeofday(&now, NULL); @@ -312,6 +341,15 @@ FT_DECLARE(ftdm_status_t) ftdm_sched_timer(ftdm_sched_t *sched, const char *name if (!newtimer) { goto done; } + newtimer->id = sched->currid; + sched->currid++; + if (!sched->currid) { + ftdm_log(FTDM_LOG_NOTICE, "Timer id wrap around for sched %s\n", sched->name); + /* we do not want currid to be zero since is an invalid id + * TODO: check that currid does not exists already in the context, it'd be insane + * though, having a timer to live all that time */ + sched->currid++; + } ftdm_set_string(newtimer->name, name); newtimer->callback = callback; @@ -332,9 +370,10 @@ FT_DECLARE(ftdm_status_t) ftdm_sched_timer(ftdm_sched_t *sched, const char *name sched->timers = newtimer; } - if (timer) { - *timer = newtimer; + if (timerid) { + *timerid = newtimer->id; } + status = FTDM_SUCCESS; done: @@ -349,7 +388,7 @@ done: UNREFERENCED_PARAMETER(ms); UNREFERENCED_PARAMETER(callback); UNREFERENCED_PARAMETER(data); - UNREFERENCED_PARAMETER(timer); + UNREFERENCED_PARAMETER(timerid); #endif return status; } @@ -418,53 +457,37 @@ done: return status; } -FT_DECLARE(ftdm_status_t) ftdm_sched_cancel_timer(ftdm_sched_t *sched, ftdm_timer_t **intimer) +FT_DECLARE(ftdm_status_t) ftdm_sched_cancel_timer(ftdm_sched_t *sched, ftdm_timer_id_t timerid) { ftdm_status_t status = FTDM_FAIL; ftdm_timer_t *timer; ftdm_assert_return(sched != NULL, FTDM_EINVAL, "sched is null!\n"); - ftdm_assert_return(intimer != NULL, FTDM_EINVAL, "timer is null!\n"); - ftdm_assert_return(*intimer != NULL, FTDM_EINVAL, "timer is null!\n"); + + if (!timerid) { + return FTDM_SUCCESS; + } ftdm_mutex_lock(sched->mutex); - /* special case where the cancelled timer is the head */ - if (*intimer == sched->timers) { - timer = *intimer; - /* the timer next is the new head (even if that means the new head will be NULL)*/ - sched->timers = timer->next; - /* if there is a new head, clean its prev member */ - if (sched->timers) { - sched->timers->prev = NULL; - } - /* free the old head */ - ftdm_safe_free(timer); - status = FTDM_SUCCESS; - *intimer = NULL; - goto done; - } - - /* look for the timer and destroy it (we know now that is not head, se we start at the next member after head) */ - for (timer = sched->timers->next; timer; timer = timer->next) { - if (timer == *intimer) { + /* look for the timer and destroy it */ + for (timer = sched->timers; timer; timer = timer->next) { + if (timer->id == timerid) { + if (timer == sched->timers) { + /* it's the head timer, put a new head */ + sched->timers = timer->next; + } if (timer->prev) { timer->prev->next = timer->next; } if (timer->next) { timer->next->prev = timer->prev; } - ftdm_log(FTDM_LOG_DEBUG, "cancelled timer %s\n", timer->name); ftdm_safe_free(timer); status = FTDM_SUCCESS; - *intimer = NULL; break; } } -done: - if (status == FTDM_FAIL) { - ftdm_log(FTDM_LOG_ERROR, "Could not find timer %s to cancel it\n", (*intimer)->name); - } ftdm_mutex_unlock(sched->mutex); diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c index ba4049a32f..bb62f07754 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c @@ -1087,10 +1087,17 @@ static void *ftdm_libpri_run(ftdm_thread_t *me, void *obj) got_d = 1; x++; break; + } else { + ftdm_log(FTDM_LOG_ERROR, "failed to open d-channel #%d %d:%d\n", x, span->channels[i]->span_id, span->channels[i]->chan_id); } } } } + + if (!got_d) { + ftdm_log(FTDM_LOG_ERROR, "Failed to get a D-channel in span %d\n", span->span_id); + break; + } if (lpwrap_init_pri(&isdn_data->spri, @@ -1133,7 +1140,9 @@ static void *ftdm_libpri_run(ftdm_thread_t *me, void *obj) } ftdm_log(FTDM_LOG_CRIT, "PRI down on span %d\n", isdn_data->spri.span->span_id); - isdn_data->spri.dchan->state = FTDM_CHANNEL_STATE_DOWN; + if (isdn_data->spri.dchan) { + isdn_data->spri.dchan->state = FTDM_CHANNEL_STATE_DOWN; + } if (!down) { ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART); @@ -1147,7 +1156,7 @@ static void *ftdm_libpri_run(ftdm_thread_t *me, void *obj) ftdm_sleep(5000); } - ftdm_log(FTDM_LOG_DEBUG, "PRI thread ended on span %d\n", isdn_data->spri.span->span_id); + ftdm_log(FTDM_LOG_DEBUG, "PRI thread ended on span %d\n", span->span_id); ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD); ftdm_clear_flag(isdn_data, FTMOD_LIBPRI_RUNNING); diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c b/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c index b286ec1df6..8dfba34ec3 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c @@ -177,7 +177,7 @@ int lpwrap_init_pri(struct lpwrap_pri *spri, ftdm_span_t *span, ftdm_channel_t * spri->dchan = dchan; spri->span = span; - if ((spri->pri = pri_new_cb(spri->dchan->sockfd, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))){ + if (spri->dchan && (spri->pri = pri_new_cb(spri->dchan->sockfd, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))){ unsigned char buf[4] = { 0 }; size_t buflen = sizeof(buf), len = 0; pri_set_debug(spri->pri, debug); 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 9ffd7097a3..08f340dc83 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 @@ -189,7 +189,8 @@ ftdm_state_map_t sangoma_isdn_state_map = { ZSD_OUTBOUND, ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_DIALING, FTDM_END}, - {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_DOWN, FTDM_END} + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, + FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_DOWN, FTDM_END} }, { ZSD_OUTBOUND, @@ -471,10 +472,7 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) case FTDM_CHANNEL_STATE_RING: /* incoming call request */ { ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending incoming call from %s to %s to FTDM core\n", ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.dnis.digits); - ftdm_channel_add_var(ftdmchan, "isdn_specific_var", "1"); - ftdm_channel_add_var(ftdmchan, "isdn_crap", "morecrap"); - ftdm_channel_add_var(ftdmchan, "isdn_stuff", "s"); - ftdm_channel_add_var(ftdmchan, "isdn_d", "asdsadasdasdsad"); + /* we have enough information to inform FTDM of the call*/ sigev.event_id = FTDM_SIGEVENT_START; ftdm_span_send_signal(ftdmchan->span, &sigev); @@ -558,6 +556,9 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) /* We are hangup local call because there was a glare, we are waiting for a RELEASE on this call, before we can process the saved call */ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Waiting for RELEASE on hungup glared call\n"); + } else if (sngisdn_test_flag(sngisdn_info, FLAG_SEND_DISC)) { + /* Remote side sent a PROGRESS message, but cause indicates disconnect or T310 expired*/ + sngisdn_snd_disconnect(ftdmchan); } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Hanging up call upon local request!\n"); @@ -568,16 +569,15 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) if (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALING) { + sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT); + sngisdn_snd_release(ftdmchan, 0); + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) { sng_isdn_set_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN); } - - sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT); - sngisdn_snd_release(ftdmchan, 0); } else { sngisdn_snd_disconnect(ftdmchan); } - } /* now go to the HANGUP complete state */ @@ -691,7 +691,7 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_isdn_outgoing_call) return status; } -static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_sig_status) +static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_chan_sig_status) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) { *status = FTDM_SIG_STATE_UP; @@ -702,17 +702,34 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_sig_status) return FTDM_SUCCESS; } -static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_sig_status) +static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_chan_sig_status) { ftdm_log(FTDM_LOG_ERROR,"Cannot set channel status in this module\n"); return FTDM_NOTIMPL; } +static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_span_sig_status) +{ + if (ftdm_test_flag(span->channels[1], FTDM_CHANNEL_SIG_UP)) { + *status = FTDM_SIG_STATE_UP; + } else { + *status = FTDM_SIG_STATE_DOWN; + } + + return FTDM_SUCCESS; +} + +static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_span_sig_status) +{ + ftdm_log(FTDM_LOG_ERROR,"Cannot set span status in this module\n"); + return FTDM_NOTIMPL; +} + static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span) { ftdm_log(FTDM_LOG_INFO,"Starting span %s:%u.\n",span->name,span->span_id); - if (sng_isdn_stack_activate(span) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_CRIT, "Failed to activate span %s\n", span->name); + if (sng_isdn_stack_start(span) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name); return FTDM_FAIL; } /* clear the monitor thread stop flag */ @@ -731,7 +748,8 @@ static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span) static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span) { - unsigned i; + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *curr = NULL; ftdm_log(FTDM_LOG_INFO, "Stopping span %s\n", span->name); /* throw the STOP_THREAD flag to signal monitor thread stop */ @@ -743,11 +761,19 @@ static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span) ftdm_sleep(10); } - /* FIXME: deconfigure any links, attached to this span */ - /* TODO: Use Moy's channel Iterator when its implemented */ - for (i=1;i<=span->chan_count;i++) { - ftdm_safe_free(span->channels[i]->call_data); + if (sng_isdn_stack_stop(span) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT, "Failed to stop span %s\n", span->name); } + + chaniter = ftdm_span_get_chan_iterator(span, NULL); + for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { + ftdm_safe_free(((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data); + ((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data = NULL; + } + ftdm_iterator_free(chaniter); + + ftdm_sched_destroy(&((sngisdn_span_data_t*)span->signal_data)->sched); + ftdm_queue_destroy(&((sngisdn_span_data_t*)span->signal_data)->event_queue); ftdm_safe_free(span->signal_data); ftdm_log(FTDM_LOG_DEBUG, "Finished stopping span %s\n", span->name); @@ -757,6 +783,9 @@ static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span) static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config) { + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *curr = NULL; + sngisdn_span_data_t *span_data; ftdm_log(FTDM_LOG_INFO, "Configuring ftmod_sangoma_isdn span = %s\n", span->name); @@ -764,13 +793,15 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config) span_data = ftdm_calloc(1, sizeof(sngisdn_span_data_t)); span_data->ftdm_span = span; span->signal_data = span_data; - - unsigned i; - for (i=1;i <= span->chan_count; i++) { + + chaniter = ftdm_span_get_chan_iterator(span, NULL); + for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { sngisdn_chan_data_t *chan_data = ftdm_calloc(1, sizeof(sngisdn_chan_data_t)); - chan_data->ftdmchan = span->channels[i]; - span->channels[i]->call_data = chan_data; + chan_data->ftdmchan = ((ftdm_channel_t*)ftdm_iterator_current(curr)); + ((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data = chan_data; + } + ftdm_iterator_free(chaniter); if (ftmod_isdn_parse_cfg(ftdm_parameters, span) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_ERROR, "Failed to parse configuration\n"); @@ -789,8 +820,10 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config) span->outgoing_call = ftdm_sangoma_isdn_outgoing_call; span->channel_request = NULL; span->signal_cb = sig_cb; - span->get_channel_sig_status = ftdm_sangoma_isdn_get_sig_status; - span->set_channel_sig_status = ftdm_sangoma_isdn_set_sig_status; + span->get_channel_sig_status = ftdm_sangoma_isdn_get_chan_sig_status; + span->set_channel_sig_status = ftdm_sangoma_isdn_set_chan_sig_status; + 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; ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE); ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE); @@ -852,7 +885,7 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_isdn_init) for(i=1;i<=MAX_VARIANTS;i++) { ftdm_mutex_create(&g_sngisdn_data.ccs[i].mutex); } - + /* initalize sng_isdn library */ sng_isdn_init(&g_sngisdn_event_interface); return FTDM_SUCCESS; @@ -920,16 +953,35 @@ static FIO_API_FUNCTION(ftdm_sangoma_isdn_api) if (!strcasecmp(argv[0], "l1_stats")) { ftdm_span_t *span; if (argc < 2) { - ftdm_log(FTDM_LOG_ERROR, "Usage: ftdm sangoma_isdn l1_stats \n"); + stream->write_function(stream, "Usage: ftdm sangoma_isdn l1_stats \n"); status = FTDM_FAIL; goto done; } status = ftdm_span_find_by_name(argv[1], &span); if (FTDM_SUCCESS != status) { - stream->write_function(stream, "-ERR failed to find span by name %s\n", argv[2]); + stream->write_function(stream, "-ERR failed to find span with name %s\n", argv[1]); + /* Return SUCCESS because we do not want to print the general FTDM usage list */ + status = FTDM_SUCCESS; goto done; } - /* TODO: implement PHY stats */ + sngisdn_print_phy_stats(stream, span); + } + + if (!strcasecmp(argv[0], "show_spans")) { + ftdm_span_t *span = NULL; + if (argc == 2) { + status = ftdm_span_find_by_name(argv[1], &span); + if (FTDM_SUCCESS != status) { + stream->write_function(stream, "-ERR failed to find span with name %s\n", argv[1]); + /* Return SUCCESS because we do not want to print the general FTDM usage list */ + status = FTDM_SUCCESS; + goto done; + } + sngisdn_print_span(stream, span); + status = FTDM_SUCCESS; + goto done; + } + sngisdn_print_spans(stream); } if (!strcasecmp(argv[0], "check_ids")) { sngisdn_check_free_ids(); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h index 3f63fbc1d4..ae6c0d92f7 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -68,6 +68,7 @@ typedef enum { FLAG_GLARE = (1 << 6), FLAG_DELAYED_REL = (1 << 7), FLAG_SENT_PROCEED = (1 << 8), + FLAG_SEND_DISC = (1 << 9), } sngisdn_flag_t; @@ -127,6 +128,13 @@ typedef enum { SNGISDN_EVENT_RST_IND, } ftdm_sngisdn_event_id_t; +/* Only timers that can be cancelled are listed here */ +#define SNGISDN_NUM_TIMERS 1 +/* Increase NUM_TIMERS as number of ftdm_sngisdn_timer_t increases */ +typedef enum { + SNGISDN_TIMER_FACILITY = 0, +} ftdm_sngisdn_timer_t; + typedef struct sngisdn_glare_data { int16_t suId; uint32_t suInstId; @@ -148,6 +156,7 @@ typedef struct sngisdn_chan_data { uint8_t globalFlg; sngisdn_glare_data_t glare; + ftdm_timer_id_t timers[SNGISDN_NUM_TIMERS]; } sngisdn_chan_data_t; /* Span specific data */ @@ -165,6 +174,7 @@ typedef struct sngisdn_span_data { uint8_t overlap_dial; uint8_t setup_arb; uint8_t facility; + int8_t facility_timeout; ftdm_sched_t *sched; ftdm_queue_t *event_queue; } sngisdn_span_data_t; @@ -223,8 +233,8 @@ typedef struct sngisdn_cc { ftdm_trunk_type_t trunktype; uint32_t last_suInstId; ftdm_mutex_t *mutex; - sngisdn_chan_data_t *active_spInstIds[MAX_INSTID]; - sngisdn_chan_data_t *active_suInstIds[MAX_INSTID]; + sngisdn_chan_data_t *active_spInstIds[MAX_INSTID+1]; + sngisdn_chan_data_t *active_suInstIds[MAX_INSTID+1]; }sngisdn_cc_t; /* Global sngisdn data */ @@ -233,7 +243,8 @@ typedef struct ftdm_sngisdn_data { uint8_t num_cc; /* 1 ent per switchtype */ struct sngisdn_cc ccs[MAX_VARIANTS+1]; uint8_t num_dchan; - sngisdn_dchan_data_t dchans[MAX_L1_LINKS+1]; + sngisdn_dchan_data_t dchans[MAX_L1_LINKS+1]; + sngisdn_span_data_t *spans[MAX_L1_LINKS+1]; /* spans are indexed by link_id */ }ftdm_sngisdn_data_t; @@ -349,12 +360,16 @@ void sngisdn_set_span_sig_status(ftdm_span_t *ftdmspan, ftdm_signaling_status_t void sngisdn_delayed_release(void* p_sngisdn_info); void sngisdn_delayed_connect(void* p_sngisdn_info); void sngisdn_delayed_disconnect(void* p_sngisdn_info); +void sngisdn_facility_timeout(void* p_sngisdn_info); /* Stack management functions */ ftdm_status_t sng_isdn_stack_cfg(ftdm_span_t *span); -ftdm_status_t sng_isdn_stack_activate(ftdm_span_t *span); - +ftdm_status_t sng_isdn_stack_start(ftdm_span_t *span); +ftdm_status_t sng_isdn_stack_stop(ftdm_span_t *span); +void sngisdn_print_phy_stats(ftdm_stream_handle_t *stream, ftdm_span_t *span); +void sngisdn_print_spans(ftdm_stream_handle_t *stream); +void sngisdn_print_span(ftdm_stream_handle_t *stream, ftdm_span_t *span); #endif /* __FTMOD_SNG_ISDN_H__ */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c index ec44142303..361b389f96 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c @@ -62,7 +62,8 @@ ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span) } break; case FTDM_TRUNK_E1: - if (!strcasecmp(switch_name, "euroisdn") || strcasecmp(switch_name, "etsi")) { + if (!strcasecmp(switch_name, "euroisdn") || + !strcasecmp(switch_name, "etsi")) { signal_data->switchtype = SNGISDN_SWITCH_EUROISDN; } else if (!strcasecmp(switch_name, "qsig")) { signal_data->switchtype = SNGISDN_SWITCH_QSIG; @@ -116,6 +117,8 @@ ftdm_status_t parse_switchtype(const char* switch_name, ftdm_span_t *span) signal_data->span_id = dchan_data->num_spans; dchan_data->spans[signal_data->span_id] = signal_data; + + g_sngisdn_data.spans[signal_data->link_id] = signal_data; ftdm_log(FTDM_LOG_DEBUG, "%s: cc_id:%d dchan_id:%d span_id:%d\n", span->name, signal_data->cc_id, signal_data->dchan_id, signal_data->span_id); @@ -163,6 +166,7 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ signal_data->overlap_dial = SNGISDN_OPT_DEFAULT; signal_data->setup_arb = SNGISDN_OPT_DEFAULT; + signal_data->link_id = span->span_id; span->default_caller_data.bearer_capability = IN_ITC_SPEECH; /* Cannot set default bearer_layer1 yet, as we do not know the switchtype */ @@ -249,11 +253,16 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ ftdm_span_set_bearer_capability(val, &span->default_caller_data.bearer_capability); } else if (!strcasecmp(var, "outbound-bearer_layer1")) { ftdm_span_set_bearer_layer1(val, &span->default_caller_data.bearer_layer1); + } else if (!strcasecmp(var, "facility-timeout")) { + signal_data->facility_timeout = atoi(val); + if (signal_data->facility_timeout < 0) { + signal_data->facility_timeout = 0; + } } else { ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var); } } - signal_data->link_id = span->span_id; + if (signal_data->switchtype == SNGISDN_SWITCH_INVALID) { ftdm_log(FTDM_LOG_ERROR, "%s: switchtype not specified", span->name); return FTDM_FAIL; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c index 7aba6a66ce..5060cb6bba 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c @@ -35,7 +35,6 @@ #include "ftmod_sangoma_isdn.h" - void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status); void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status) @@ -53,23 +52,21 @@ void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status return; } +void sngisdn_set_span_sig_status(ftdm_span_t *span, ftdm_signaling_status_t status) +{ + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *curr = NULL; -void sngisdn_set_span_sig_status(ftdm_span_t *ftdmspan, ftdm_signaling_status_t status) -{ - unsigned i; - /* TODO: use channel iterator once it is implemented */ - - for (i=1;i<=ftdmspan->chan_count;i++) { - sngisdn_set_chan_sig_status(ftdmspan->channels[i], status); + chaniter = ftdm_span_get_chan_iterator(span, NULL); + for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { + sngisdn_set_chan_sig_status(((ftdm_channel_t*)ftdm_iterator_current(curr)), status); } + ftdm_iterator_free(chaniter); return; } - - - /* For Emacs: * Local Variables: * mode:c diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c index f84e018f1e..7f3c4c3d07 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c @@ -193,10 +193,12 @@ ftdm_status_t sng_isdn_stack_cfg_phy_gen(void) ftdm_status_t sng_isdn_stack_cfg_phy_psap(ftdm_span_t *span) { - /*local variables*/ - L1Mngmt cfg; /*configuration structure*/ - Pst pst; /*post structure*/ + ftdm_iterator_t *chaniter; + ftdm_iterator_t *curr; + L1Mngmt cfg; + Pst pst; + S32 d_channel_fd = -1; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; /* initalize the post structure */ @@ -219,20 +221,35 @@ ftdm_status_t sng_isdn_stack_cfg_phy_psap(ftdm_span_t *span) cfg.hdr.elmId.elmntInst1 = signal_data->link_id; - cfg.t.cfg.s.l1PSAP.span = span->channels[1]->physical_span_id; + + /* Find the d-channel */ + chaniter = ftdm_span_get_chan_iterator(span, NULL); + for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { + ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr); + if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) { + d_channel_fd = ftdmchan->sockfd; + break; + } + } + ftdm_iterator_free(chaniter); + + if(d_channel_fd < 0) { + ftdm_log(FTDM_LOG_ERROR, "%s:No d-channels specified\n", span->name); + return FTDM_FAIL; + } + + cfg.t.cfg.s.l1PSAP.sockfd = d_channel_fd; + switch(span->trunk_type) { case FTDM_TRUNK_E1: - cfg.t.cfg.s.l1PSAP.chan = 16; cfg.t.cfg.s.l1PSAP.type = SNG_L1_TYPE_PRI; break; case FTDM_TRUNK_T1: case FTDM_TRUNK_J1: - cfg.t.cfg.s.l1PSAP.chan = 24; cfg.t.cfg.s.l1PSAP.type = SNG_L1_TYPE_PRI; break; case FTDM_TRUNK_BRI: case FTDM_TRUNK_BRI_PTMP: - cfg.t.cfg.s.l1PSAP.chan = 3; cfg.t.cfg.s.l1PSAP.type = SNG_L1_TYPE_BRI; break; default: @@ -608,9 +625,10 @@ ftdm_status_t sng_isdn_stack_cfg_q931_dlsap(ftdm_span_t *span) cfg.hdr.entId.ent = ENTIN; cfg.hdr.entId.inst = S_INST; cfg.hdr.elmId.elmnt = STDLSAP; - + cfg.hdr.response.selector=0; + cfg.t.cfg.s.inDLSAP.sapId = signal_data->link_id; cfg.t.cfg.s.inDLSAP.spId = signal_data->link_id; cfg.t.cfg.s.inDLSAP.swtch = sng_isdn_stack_switchtype(signal_data->switchtype); @@ -656,8 +674,7 @@ ftdm_status_t sng_isdn_stack_cfg_q931_dlsap(ftdm_span_t *span) cfg.t.cfg.s.inDLSAP.ctldInt[1] = 1; } - cfg.t.cfg.s.inDLSAP.numRstInd = 255; - cfg.t.cfg.s.inDLSAP.ackOpt = TRUE; + cfg.t.cfg.s.inDLSAP.numRstInd = 255; cfg.t.cfg.s.inDLSAP.relOpt = TRUE; #ifdef ISDN_SRV cfg.t.cfg.s.inDLSAP.bcas = FALSE; @@ -666,16 +683,19 @@ ftdm_status_t sng_isdn_stack_cfg_q931_dlsap(ftdm_span_t *span) #endif /* ISDN_SRV */ if (signal_data->signalling == SNGISDN_SIGNALING_NET) { + cfg.t.cfg.s.inDLSAP.ackOpt = TRUE; cfg.t.cfg.s.inDLSAP.intType = NETWORK; cfg.t.cfg.s.inDLSAP.clrGlr = FALSE; /* in case of glare, do not clear local call */ cfg.t.cfg.s.inDLSAP.statEnqOpt = TRUE; - if (span->trunk_type == FTDM_TRUNK_BRI || - span->trunk_type == FTDM_TRUNK_BRI_PTMP) { + + if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN || + signal_data->switchtype == SNGISDN_SWITCH_INSNET) { cfg.t.cfg.s.inDLSAP.rstOpt = FALSE; } else { cfg.t.cfg.s.inDLSAP.rstOpt = TRUE; } } else { + cfg.t.cfg.s.inDLSAP.ackOpt = FALSE; cfg.t.cfg.s.inDLSAP.intType = USER; cfg.t.cfg.s.inDLSAP.clrGlr = TRUE; /* in case of glare, clear local call */ cfg.t.cfg.s.inDLSAP.statEnqOpt = FALSE; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c index f92eceda5e..cea8ac0173 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c @@ -38,8 +38,8 @@ void stack_resp_hdr_init(Header *hdr); ftdm_status_t sng_isdn_activate_phy(ftdm_span_t *span); -ftdm_status_t sng_isdn_activate_q921(ftdm_span_t *span); -ftdm_status_t sng_isdn_activate_q931(ftdm_span_t *span); +ftdm_status_t sng_isdn_deactivate_phy(ftdm_span_t *span); + ftdm_status_t sng_isdn_activate_cc(ftdm_span_t *span); ftdm_status_t sng_isdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt); @@ -52,14 +52,23 @@ extern ftdm_sngisdn_data_t g_sngisdn_data; ftdm_status_t sng_isdn_stack_stop(ftdm_span_t *span); -ftdm_status_t sng_isdn_stack_activate(ftdm_span_t *span) +ftdm_status_t sng_isdn_stack_start(ftdm_span_t *span) { sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; - if (sng_isdn_activate_q921(span) != FTDM_SUCCESS) { + + if (sng_isdn_cntrl_q921(span, ABND_ENA, NOTUSED) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack q921\n", span->name); return FTDM_FAIL; } + + /* Try to find an alternative for this */ + /* LAPD will call LdUiDatBndCfm before it received a LdLiMacBndCfm from L1, + so we need to give some time before activating q931, as q931 will send a + LdUiDatConReq when activated, and this requires the Mac SAP to be already + bound first */ + ftdm_sleep(500); + ftdm_log(FTDM_LOG_DEBUG, "%s:Stack q921 activated\n", span->name); if (!g_sngisdn_data.ccs[signal_data->cc_id].activation_done) { g_sngisdn_data.ccs[signal_data->cc_id].activation_done = 1; @@ -70,7 +79,8 @@ ftdm_status_t sng_isdn_stack_activate(ftdm_span_t *span) ftdm_log(FTDM_LOG_DEBUG, "%s:Stack CC activated\n", span->name); } - if (sng_isdn_activate_q931(span) != FTDM_SUCCESS) { + + if (sng_isdn_cntrl_q931(span, ABND_ENA, SAELMNT) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "%s:Failed to activate stack q931\n", span->name); return FTDM_FAIL; } @@ -80,50 +90,72 @@ ftdm_status_t sng_isdn_stack_activate(ftdm_span_t *span) return FTDM_SUCCESS; } -ftdm_status_t sng_isdn_stack_stop(ftdm_span_t *span) +ftdm_status_t sng_isdn_stack_stop(ftdm_span_t *span) { + /* Stop L1 first, so we do not receive any more frames */ + if (sng_isdn_deactivate_phy(span) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT, "%s:Failed to deactivate stack phy\n", span->name); + return FTDM_FAIL; + } + if (sng_isdn_cntrl_q931(span, AUBND_DIS, SAELMNT) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT, "%s:Failed to deactivate stack q931\n", span->name); + return FTDM_FAIL; + } + + if (sng_isdn_cntrl_q921(span, AUBND_DIS, SAELMNT) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_CRIT, "%s:Failed to deactivate stack q921\n", span->name); + return FTDM_FAIL; + } + + ftdm_log(FTDM_LOG_INFO, "%s:Signalling stopped\n", span->name); return FTDM_SUCCESS; } ftdm_status_t sng_isdn_activate_phy(ftdm_span_t *span) +{ + + /* There is no need to start phy, as it will Q921 will send a activate request to phy when it starts */ + + return FTDM_SUCCESS; +} + +ftdm_status_t sng_isdn_deactivate_phy(ftdm_span_t *span) { L1Mngmt cntrl; - Pst pst; + Pst pst; - ftdm_log(FTDM_LOG_ERROR, "%s:PHY control not implemented\n", span->name); - return FTDM_SUCCESS; - /* TODO: phy cntrl not implemented yet */ + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; - sng_isdn_phy_cntrl(&pst, &cntrl); + /* initalize the post structure */ + stack_pst_init(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTL1; + + /* initalize the control structure */ + memset(&cntrl, 0, sizeof(cntrl)); + + /* initalize the control header */ + stack_hdr_init(&cntrl.hdr); + + cntrl.hdr.msgType = TCNTRL; /* configuration */ + cntrl.hdr.entId.ent = ENTL1; /* entity */ + cntrl.hdr.entId.inst = S_INST; /* instance */ + cntrl.hdr.elmId.elmnt = STTSAP; /* SAP Specific cntrl */ + + cntrl.t.cntrl.action = AUBND_DIS; + cntrl.t.cntrl.subAction = SAELMNT; + cntrl.t.cntrl.sapId = signal_data->link_id; + + if (sng_isdn_phy_cntrl(&pst, &cntrl)) { + return FTDM_FAIL; + } return FTDM_SUCCESS; } -ftdm_status_t sng_isdn_activate_q921(ftdm_span_t *span) -{ - ftdm_status_t status; - status = sng_isdn_cntrl_q921(span, ABND_ENA, NOTUSED); - - /* Try to find an alternative for this */ - /* LAPD will call LdUiDatBndCfm before it received a LdLiMacBndCfm from L1, - so we need to give some time before activating q931, as q931 will send a - LdUiDatConReq when activated, and this requires the Mac SAP to be already - bound first */ - - if (status == FTDM_SUCCESS) { - ftdm_sleep(500); - } - return status; -} - -ftdm_status_t sng_isdn_activate_q931(ftdm_span_t *span) -{ - /* TODO: remove this function later, just call sng_isdn_cntrl_q931 directly */ - return sng_isdn_cntrl_q931(span, ABND_ENA, SAELMNT); -} - ftdm_status_t sng_isdn_activate_cc(ftdm_span_t *span) { CcMngmt cntrl;; @@ -167,7 +199,7 @@ ftdm_status_t sng_isdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t tra ftdm_log(FTDM_LOG_INFO, "s%d Disabling q921 trace\n", signal_data->link_id); sngisdn_clear_trace_flag(signal_data, SNGISDN_TRACE_Q921); - if (sng_isdn_cntrl_q921(span, ADISIMM, SAELMNT) != FTDM_SUCCESS) { + if (sng_isdn_cntrl_q921(span, ADISIMM, SATRC) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_ERROR, "s%d Failed to disable q921 trace\n"); } } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c index c3d97e5c5c..b7af8e98c5 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c @@ -78,14 +78,13 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) } sngisdn_info->suInstId = get_unique_suInstId(suId); - sngisdn_info->spInstId = spInstId; + sngisdn_info->spInstId = spInstId; /* If this is a glared call that was previously saved, we moved all the info to the current call, so clear the glared saved data */ - if (sngisdn_info->glare.spInstId == spInstId) { clear_call_glare_data(sngisdn_info); - } + } ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex); g_sngisdn_data.ccs[suId].active_suInstIds[sngisdn_info->suInstId] = sngisdn_info; @@ -105,7 +104,15 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); break; - } + } + +#if 0 + /* Export ftdmchan variables here if we need to */ + ftdm_channel_add_var(ftdmchan, "isdn_specific_var", "1"); + ftdm_channel_add_var(ftdmchan, "isdn_crap", "morecrap"); + ftdm_channel_add_var(ftdmchan, "isdn_stuff", "s"); + ftdm_channel_add_var(ftdmchan, "isdn_d", "asdsadasdasdsad"); +#endif /* Fill in call information */ cpy_calling_num_from_stack(&ftdmchan->caller_data, &conEvnt->cgPtyNmb); cpy_called_num_from_stack(&ftdmchan->caller_data, &conEvnt->cdPtyNmb); @@ -124,14 +131,12 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) } - if (conEvnt->facilityStr.eh.pres) { + if (signal_data->facility == SNGISDN_OPT_TRUE && conEvnt->facilityStr.eh.pres) { /* Verify whether the Caller Name will come in a subsequent FACILITY message */ uint16_t ret_val; - uint8_t facility_str[255]; char retrieved_str[255]; - memcpy(facility_str, (uint8_t*)&conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len); - - ret_val = sng_isdn_retrieve_facility_caller_name(facility_str, conEvnt->facilityStr.facilityStr.len, retrieved_str); + + ret_val = sng_isdn_retrieve_facility_caller_name(conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len, retrieved_str); /* return values for "sng_isdn_retrieve_facility_information_following": If there will be no information following, or fails to decode IE, returns -1 @@ -142,6 +147,11 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) if (ret_val == 1) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Expecting Caller name in FACILITY\n"); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GET_CALLERID); + /* Launch timer in case we never get a FACILITY msg */ + if (signal_data->facility_timeout) { + ftdm_sched_timer(signal_data->sched, "facility_timeout", signal_data->facility_timeout, + sngisdn_facility_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_TIMER_FACILITY]); + } break; } else if (ret_val == 0) { strcpy(ftdmchan->caller_data.cid_name, retrieved_str); @@ -263,6 +273,9 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) /* This is the only valid state we should get a CONNECT ACK on */ /* do nothing */ break; + case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: + /* We just hung up an incoming call right after we sent a CONNECT so ignore this message */ + break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing CONNECT/CONNECT ACK in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); @@ -289,6 +302,8 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event) sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; + CnStEvnt *cnStEvnt = &sngisdn_event->event.cnStEvnt; ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); @@ -302,19 +317,49 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event) suId, suInstId, spInstId, ces); switch(evntType) { + case MI_PROGRESS: + if (signal_data->switchtype == SNGISDN_SWITCH_NI2 && + cnStEvnt->causeDgn[0].eh.pres && cnStEvnt->causeDgn[0].causeVal.pres) { + + switch(cnStEvnt->causeDgn[0].causeVal.val) { + case 17: /* User Busy */ + case 18: /* No User responding */ + case 19: /* User alerting, no answer */ + case 21: /* Call rejected, the called party does not with to accept this call */ + case 27: /* Destination out of order */ + case 31: /* Normal, unspecified */ + case 34: /* Circuit/Channel congestion */ + case 41: /* Temporary failure */ + case 42: /* Switching equipment is experiencing a period of high traffic */ + case 47: /* Resource unavailable */ + case 58: /* Bearer Capability not available */ + case 63: /* Service or option not available */ + case 65: /* Bearer Cap not implemented, not supported */ + case 79: /* Service or option not implemented, unspecified */ + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Cause requires disconnect (cause:%d)\n", cnStEvnt->causeDgn[0].causeVal.val); + ftdmchan->caller_data.hangup_cause = cnStEvnt->causeDgn[0].causeVal.val; + + sngisdn_set_flag(sngisdn_info, FLAG_SEND_DISC); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + goto sngisdn_process_cnst_ind_end; + } + } + /* fall-through */ case MI_ALERTING: case MI_CALLPROC: - case MI_PROGRESS: + switch(ftdmchan->state) { - case FTDM_CHANNEL_STATE_DIALING: - if (evntType == MI_PROGRESS) { + case FTDM_CHANNEL_STATE_DIALING: + if (evntType == MI_PROGRESS || + (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL)) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); } else { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS); } break; case FTDM_CHANNEL_STATE_PROGRESS: - if (evntType == MI_PROGRESS) { + if (evntType == MI_PROGRESS || + (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL)) { ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); } break; @@ -371,6 +416,7 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event) break; } +sngisdn_process_cnst_ind_end: ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; } @@ -638,12 +684,14 @@ void sngisdn_process_flc_ind (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; FacEvnt *facEvnt = &sngisdn_event->event.facEvnt; @@ -653,16 +701,31 @@ void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event) case FTDM_CHANNEL_STATE_GET_CALLERID: /* Update the caller ID Name */ if (facEvnt->facElmt.facStr.pres) { - uint8_t facility_str[255]; - memcpy(facility_str, (uint8_t*)&facEvnt->facElmt.facStr.val, facEvnt->facElmt.facStr.len); char retrieved_str[255]; - if (sng_isdn_retrieve_facility_caller_name(facility_str, facEvnt->facElmt.facStr.len, retrieved_str) != FTDM_SUCCESS) { + + /* return values for "sng_isdn_retrieve_facility_information_following": + If there will be no information following, or fails to decode IE, returns -1 + If there will be no information following, but current FACILITY IE contains a caller name, returns 0 + If there will be information following, returns 1 + */ + + if (sng_isdn_retrieve_facility_caller_name(&facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len, retrieved_str) == 0) { + strcpy(ftdmchan->caller_data.cid_name, retrieved_str); + } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed to retrieve Caller Name from Facility IE\n"); } + if (signal_data->facility_timeout) { + /* Cancel facility timeout */ + ftdm_sched_cancel_timer(signal_data->sched, sngisdn_info->timers[SNGISDN_TIMER_FACILITY]); + } } ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); break; + case FTDM_CHANNEL_STATE_RING: + /* We received the caller ID Name in FACILITY, but its too late, facility-timeout already occurred */ + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "FACILITY received, but we already proceeded with call\n"); + break; default: /* We do not support other FACILITY types for now, so do nothing */ break; @@ -794,6 +857,14 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) break; case 3: switch (ftdmchan->state) { + case FTDM_CHANNEL_STATE_PROGRESS: + /* T310 timer has expired */ + ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val; + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "T310 Timer expired, hanging up call\n"); + sngisdn_set_flag(sngisdn_info, FLAG_SEND_DISC); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + + break; case FTDM_CHANNEL_STATE_UP: /* Remote side is still waiting for our CONNECT message */ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { @@ -821,6 +892,22 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) break; } break; + case 9: /* Remote switch is in "Incoming call proceeding" state */ + switch (ftdmchan->state) { + case FTDM_CHANNEL_STATE_PROGRESS: + case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: + case FTDM_CHANNEL_STATE_GET_CALLERID: + /* Do nothing */ + break; + case FTDM_CHANNEL_STATE_UP: + /* Remote switch missed our CONNECT message, re-send */ + ftdm_sched_timer(((sngisdn_span_data_t*)ftdmchan->span->signal_data)->sched, "delayed_connect", 1, sngisdn_delayed_connect, (void*) sngisdn_info, NULL); + break; + default: + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); + break; + } + break; case 10: /* Remote switch is in active state */ switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_UP: @@ -836,17 +923,6 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) break; } break; - case 9: - switch (ftdmchan->state) { - case FTDM_CHANNEL_STATE_PROGRESS: - case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: - /* Do nothing */ - break; - default: - ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); - break; - } - break; case 22: switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_UP: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c index 6e8e0e81fd..80a85ceec8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c @@ -409,7 +409,7 @@ void sngisdn_snd_connect(ftdm_channel_t *ftdmchan) sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; - if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) { + if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending CONNECT, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId); sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); @@ -450,6 +450,14 @@ void sngisdn_snd_connect(ftdm_channel_t *ftdmchan) cnStEvnt.chanId.chanNmbSlotMap.len = 1; cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id; } + + cnStEvnt.progInd.eh.pres = PRSNT_NODEF; + cnStEvnt.progInd.location.pres = PRSNT_NODEF; + cnStEvnt.progInd.location.val = IN_LOC_USER; + cnStEvnt.progInd.codeStand0.pres = PRSNT_NODEF; + cnStEvnt.progInd.codeStand0.val = IN_CSTD_CCITT; + cnStEvnt.progInd.progDesc.pres = PRSNT_NODEF; + cnStEvnt.progInd.progDesc.val = IN_PD_NOTETEISDN; /* Not end-to-end ISDN */ ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); if (sng_isdn_con_response(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, signal_data->dchan_id, sngisdn_info->ces)) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c index 29cfb2330e..791c6b7d8c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c @@ -45,8 +45,8 @@ void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Co { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); uint8_t bchan_no = 0; - sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_chan_data_t *sngisdn_info = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Ind on unconfigured cc\n"); ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Ind on unconfigured dchan\n"); @@ -96,7 +96,7 @@ void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Co ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex); memcpy(&sngisdn_event->event.conEvnt, conEvnt, sizeof(*conEvnt)); - + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -104,8 +104,8 @@ void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Co void sngisdn_rcv_con_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, int16_t dChan, uint8_t ces) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_chan_data_t *sngisdn_info = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Cfm on unconfigured cc\n"); ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Cfm on unconfigured dchan\n"); @@ -118,6 +118,7 @@ void sngisdn_rcv_con_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, Cn if (!sngisdn_info->spInstId) { ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex); + sngisdn_info->spInstId = spInstId; g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info; ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex); @@ -146,8 +147,8 @@ void sngisdn_rcv_con_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, Cn void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, uint8_t evntType, int16_t dChan, uint8_t ces) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_chan_data_t *sngisdn_info = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Cnst Ind on unconfigured cc\n"); ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Cnst Ind on unconfigured dchan\n"); @@ -160,6 +161,7 @@ void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, C if (!sngisdn_info->spInstId) { ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex); + sngisdn_info->spInstId = spInstId; g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info; ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex); @@ -188,15 +190,15 @@ void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, C memcpy(&sngisdn_event->event.cnStEvnt, cnStEvnt, sizeof(*cnStEvnt)); - ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } void sngisdn_rcv_disc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, DiscEvnt *discEvnt) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_chan_data_t *sngisdn_info = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_assert(spInstId != 0, "Received DISCONNECT with invalid id"); @@ -207,13 +209,6 @@ void sngisdn_rcv_disc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, D ftdm_assert(0, "Inconsistent call states\n"); return; } - - if (!sngisdn_info->spInstId) { - ftdm_mutex_lock(g_sngisdn_data.ccs[suId].mutex); - sngisdn_info->spInstId = spInstId; - g_sngisdn_data.ccs[suId].active_spInstIds[spInstId] = sngisdn_info; - ftdm_mutex_unlock(g_sngisdn_data.ccs[suId].mutex); - } ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received DISCONNECT (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); @@ -229,7 +224,7 @@ void sngisdn_rcv_disc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, D memcpy(&sngisdn_event->event.discEvnt, discEvnt, sizeof(*discEvnt)); - ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -237,21 +232,22 @@ void sngisdn_rcv_disc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, D void sngisdn_rcv_rel_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, RelEvnt *relEvnt) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_chan_data_t *sngisdn_info = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { ftdm_log(FTDM_LOG_CRIT, "Could not find matching call suId:%u suInstId:%u spInstId:%u\n", suId, suInstId, spInstId); - ftdm_assert(0, "Inconsistent call states\n"); + /* It seems that Trillium has a bug where they sometimes send release twice on a call, so do not crash on these for now */ + /* ftdm_assert(0, "Inconsistent call states\n"); */ return; } ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received RELEASE/RELEASE COMPLETE (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_REL_IND; @@ -270,7 +266,7 @@ void sngisdn_rcv_dat_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, In { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -283,7 +279,7 @@ void sngisdn_rcv_dat_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, In ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received DATA IND suId:%u suInstId:%u spInstId:%u\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_DAT_IND; @@ -302,7 +298,7 @@ void sngisdn_rcv_sshl_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, S { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -315,7 +311,7 @@ void sngisdn_rcv_sshl_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, S ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received SSHL IND (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_SSHL_IND; @@ -335,7 +331,7 @@ void sngisdn_rcv_sshl_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, S { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -348,7 +344,7 @@ void sngisdn_rcv_sshl_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, S ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received SSHL CFM (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_SSHL_CFM; @@ -360,14 +356,14 @@ void sngisdn_rcv_sshl_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, S memcpy(&sngisdn_event->event.ssHlEvnt, ssHlEvnt, sizeof(*ssHlEvnt)); - ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } void sngisdn_rcv_rmrt_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, RmRtEvnt *rmRtEvnt, uint8_t action) { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -380,7 +376,7 @@ void sngisdn_rcv_rmrt_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, R ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received RMRT IND (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_RMRT_IND; @@ -392,7 +388,7 @@ void sngisdn_rcv_rmrt_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, R memcpy(&sngisdn_event->event.rmRtEvnt, rmRtEvnt, sizeof(*rmRtEvnt)); - ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -400,7 +396,7 @@ void sngisdn_rcv_rmrt_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, R { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -413,7 +409,7 @@ void sngisdn_rcv_rmrt_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, R ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received RESUME/RETRIEVE CFM (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_RMRT_CFM; @@ -425,7 +421,7 @@ void sngisdn_rcv_rmrt_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, R memcpy(&sngisdn_event->event.rmRtEvnt, rmRtEvnt, sizeof(*rmRtEvnt)); - ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -433,7 +429,7 @@ void sngisdn_rcv_flc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, St { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -446,7 +442,7 @@ void sngisdn_rcv_flc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, St ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received FLOW CONTROL IND (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_FLC_IND; @@ -457,7 +453,7 @@ void sngisdn_rcv_flc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, St memcpy(&sngisdn_event->event.staEvnt, staEvnt, sizeof(*staEvnt)); - ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue(((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->event_queue, sngisdn_event); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -466,7 +462,7 @@ void sngisdn_rcv_fac_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Fa { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -478,7 +474,7 @@ void sngisdn_rcv_fac_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Fa ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received FACILITY IND (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_FAC_IND; @@ -499,7 +495,7 @@ void sngisdn_rcv_sta_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, St { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -512,7 +508,7 @@ void sngisdn_rcv_sta_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, St ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Received STATUS CONFIRM (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_STA_CFM; @@ -532,7 +528,7 @@ void sngisdn_rcv_srv_ind (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; sngisdn_span_data_t *signal_data; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_log(FTDM_LOG_INFO, "Received SERVICE IND (dChan:%d ces:%u)\n", dChan, ces); @@ -540,7 +536,7 @@ void sngisdn_rcv_srv_ind (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { signal_data = g_sngisdn_data.dchans[dChan].spans[i]; sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_SRV_IND; @@ -550,7 +546,7 @@ void sngisdn_rcv_srv_ind (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces sngisdn_event->signal_data = signal_data; memcpy(&sngisdn_event->event.srvEvnt, srvEvnt, sizeof(*srvEvnt)); - ftdm_queue_enqueue((signal_data)->event_queue, sngisdn_event); + ftdm_queue_enqueue((signal_data)->event_queue, sngisdn_event); } ISDN_FUNC_TRACE_EXIT(__FUNCTION__); } @@ -560,8 +556,8 @@ void sngisdn_rcv_srv_cfm (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; - sngisdn_span_data_t *signal_data; - sngisdn_event_data_t *sngisdn_event; + sngisdn_span_data_t *signal_data = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_log(FTDM_LOG_INFO, "Received SERVICE CFM (dChan:%d ces:%u)\n", dChan, ces); @@ -569,7 +565,7 @@ void sngisdn_rcv_srv_cfm (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { signal_data = g_sngisdn_data.dchans[dChan].spans[i]; sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_SRV_CFM; @@ -588,16 +584,17 @@ void sngisdn_rcv_rst_ind (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces { ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; - sngisdn_span_data_t *signal_data; - sngisdn_event_data_t *sngisdn_event; + sngisdn_span_data_t *signal_data = NULL; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_log(FTDM_LOG_INFO, "Received RESTART IND (dChan:%d ces:%u type:%u)\n", dChan, ces, evntType); /* Enqueue the event to each span within the dChan */ for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { signal_data = g_sngisdn_data.dchans[dChan].spans[i]; + sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_RST_IND; @@ -618,7 +615,7 @@ void sngisdn_rcv_rst_cfm (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; sngisdn_span_data_t *signal_data; - sngisdn_event_data_t *sngisdn_event; + sngisdn_event_data_t *sngisdn_event = NULL; ftdm_log(FTDM_LOG_INFO, "Received RESTART CFM (dChan:%d ces:%u type:%u)\n", dChan, ces, evntType); @@ -626,7 +623,7 @@ void sngisdn_rcv_rst_cfm (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { signal_data = g_sngisdn_data.dchans[dChan].spans[i]; sngisdn_event = ftdm_malloc(sizeof(*sngisdn_event)); - ftdm_assert(sngisdn_event, "Failed to allocate memory\n"); + ftdm_assert(sngisdn_event != NULL, "Failed to allocate memory\n"); memset(sngisdn_event, 0, sizeof(*sngisdn_event)); sngisdn_event->event_id = SNGISDN_EVENT_RST_CFM; @@ -645,30 +642,24 @@ void sngisdn_rcv_rst_cfm (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces void sngisdn_rcv_phy_ind(SuId suId, Reason reason) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); if (reason != LL1_REASON_CON_REQ_FAIL) { ftdm_log(FTDM_LOG_INFO, "[SNGISDN PHY] D-chan %d : %s\n", suId, DECODE_LL1_REASON(reason)); } - ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; } void sngisdn_rcv_q921_ind(BdMngmt *status) -{ - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - - unsigned j,k; - ftdm_span_t *ftdmspan = NULL; - - for(j=1;j<=g_sngisdn_data.num_dchan;j++) { - for(k=1;k<=g_sngisdn_data.dchans[j].num_spans;k++) { - if (g_sngisdn_data.dchans[j].spans[k]->link_id == status->t.usta.lnkNmb) { - ftdmspan = (ftdm_span_t*)g_sngisdn_data.dchans[j].spans[k]->ftdm_span; - } - } +{ + ftdm_span_t *ftdmspan; + sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[status->t.usta.lnkNmb]; + if (!signal_data) { + ftdm_log(FTDM_LOG_INFO, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.lnkNmb); + return; } - if (ftdmspan == NULL) { - ftdm_log(FTDM_LOG_WARNING, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.lnkNmb); + ftdmspan = signal_data->ftdm_span; + + if (!ftdmspan) { + ftdm_log(FTDM_LOG_INFO, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.lnkNmb); return; } @@ -699,69 +690,56 @@ void sngisdn_rcv_q921_ind(BdMngmt *status) } break; } - - ISDN_FUNC_TRACE_EXIT(__FUNCTION__) return; } void sngisdn_rcv_q931_ind(InMngmt *status) -{ - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - ftdm_span_t *ftdmspan = NULL; - +{ if (status->t.usta.alarm.cause == 287) { get_memory_info(); return; } - switch (status->t.usta.alarm.category) { - case (LCM_CATEGORY_INTERFACE): - ftdm_log(FTDM_LOG_WARNING, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n", - status->t.usta.suId, - DECODE_LCM_CATEGORY(status->t.usta.alarm.category), - DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, - DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); - - /* clean this up later */ - - switch (status->t.usta.alarm.event) { - case LCM_EVENT_UP: - case LCM_EVENT_DOWN: - { - unsigned j,k; - for(j=1;j<=g_sngisdn_data.num_dchan;j++) { - for(k=1;k<=g_sngisdn_data.dchans[j].num_spans;k++) { - if (g_sngisdn_data.dchans[j].spans[k]->link_id == status->t.usta.suId) { - ftdmspan = (ftdm_span_t*)g_sngisdn_data.dchans[j].spans[k]->ftdm_span; - } - } - } - - if (ftdmspan == NULL) { - ftdm_log(FTDM_LOG_CRIT, "Received q931 LCM EVENT on unconfigured span (suId:%u)\n", status->t.usta.suId); - return; - } - - if (status->t.usta.alarm.event == LCM_EVENT_UP) { - sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_UP); - sng_isdn_set_avail_rate(ftdmspan, SNGISDN_AVAIL_UP); - } else { - sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_DOWN); - sng_isdn_set_avail_rate(ftdmspan, SNGISDN_AVAIL_PWR_SAVING); - } - } - break; + switch (status->t.usta.alarm.event) { + case LCM_EVENT_UP: + case LCM_EVENT_DOWN: + { + ftdm_span_t *ftdmspan; + sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[status->t.usta.suId]; + if (!signal_data) { + ftdm_log(FTDM_LOG_INFO, "Received q921 status on unconfigured span (lnkNmb:%d)\n", status->t.usta.suId); + return; } - break; + ftdmspan = signal_data->ftdm_span; + + if (status->t.usta.alarm.event == LCM_EVENT_UP) { + ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n", + status->t.usta.suId, + DECODE_LCM_CATEGORY(status->t.usta.alarm.category), + DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, + DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); + + sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_UP); + sng_isdn_set_avail_rate(ftdmspan, SNGISDN_AVAIL_UP); + } else { + ftdm_log(FTDM_LOG_WARNING, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n", + status->t.usta.suId, + DECODE_LCM_CATEGORY(status->t.usta.alarm.category), + DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, + DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); + + sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_DOWN); + sng_isdn_set_avail_rate(ftdmspan, SNGISDN_AVAIL_PWR_SAVING); + } + } + break; default: - ftdm_log(FTDM_LOG_DEBUG, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n", - status->t.usta.suId, - DECODE_LCM_CATEGORY(status->t.usta.alarm.category), - DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, - DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); - break; + ftdm_log(FTDM_LOG_WARNING, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n", + status->t.usta.suId, + DECODE_LCM_CATEGORY(status->t.usta.alarm.category), + DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, + DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); } - - + ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; } @@ -907,12 +885,13 @@ void sngisdn_rcv_sng_log(uint8_t level, char *fmt,...) break; case SNG_LOGLEVEL_CRIT: ftdm_log(FTDM_LOG_CRIT, "sng_isdn->%s", data); - /*ftdm_assert(0, "Got an error from stack");*/ + /* ftdm_assert(0, "Got an error from stack"); */ break; default: ftdm_log(FTDM_LOG_INFO, "sng_isdn->%s", data); break; } + ftdm_safe_free(data); return; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c index 29e7994c87..db22fe5ce8 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c @@ -73,8 +73,10 @@ void __inline__ clear_call_glare_data(sngisdn_chan_data_t *sngisdn_info) sngisdn_info->glare.suInstId, sngisdn_info->glare.spInstId, sngisdn_info->suInstId, sngisdn_info->spInstId); - ftdm_mutex_lock(g_sngisdn_data.ccs[sngisdn_info->glare.suId].mutex); - g_sngisdn_data.ccs[sngisdn_info->glare.suId].active_spInstIds[sngisdn_info->glare.spInstId]=NULL; + ftdm_mutex_lock(g_sngisdn_data.ccs[sngisdn_info->glare.suId].mutex); + if (sngisdn_info->glare.spInstId != sngisdn_info->spInstId) { + g_sngisdn_data.ccs[sngisdn_info->glare.suId].active_spInstIds[sngisdn_info->glare.spInstId]=NULL; + } g_sngisdn_data.ccs[sngisdn_info->glare.suId].active_suInstIds[sngisdn_info->glare.suInstId]=NULL; ftdm_mutex_unlock(g_sngisdn_data.ccs[sngisdn_info->glare.suId].mutex); @@ -132,16 +134,22 @@ ftdm_status_t __inline__ get_ftdmchan_by_spInstId(uint8_t cc_id, uint32_t spInst return FTDM_SUCCESS; } -ftdm_status_t sng_isdn_set_avail_rate(ftdm_span_t *ftdmspan, sngisdn_avail_t avail) +ftdm_status_t sng_isdn_set_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail) { - unsigned i; - if (ftdmspan->trunk_type == FTDM_TRUNK_BRI || - ftdmspan->trunk_type == FTDM_TRUNK_BRI_PTMP) { + + if (span->trunk_type == FTDM_TRUNK_BRI || + span->trunk_type == FTDM_TRUNK_BRI_PTMP) { - for(i=1; i<=ftdmspan->chan_count; i++) { - ftdm_log_chan(ftdmspan->channels[i], FTDM_LOG_DEBUG, "Setting availability rate to:%d\n", avail); - ftdmspan->channels[i]->availability_rate = avail; + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *curr = NULL; + + + chaniter = ftdm_span_get_chan_iterator(span, NULL); + for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { + ftdm_log_chan(((ftdm_channel_t*)ftdm_iterator_current(curr)), FTDM_LOG_DEBUG, "Setting availability rate to:%d\n", avail); + ((ftdm_channel_t*)ftdm_iterator_current(curr))->availability_rate = avail; } + ftdm_iterator_free(chaniter); } return FTDM_SUCCESS; } @@ -427,6 +435,24 @@ void sngisdn_delayed_disconnect(void* p_sngisdn_info) return; } +void sngisdn_facility_timeout(void* p_sngisdn_info) +{ + sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*)p_sngisdn_info; + ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; + + ftdm_mutex_lock(ftdmchan->mutex); + if (ftdmchan->state == FTDM_CHANNEL_STATE_GET_CALLERID) { + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Facility timeout reached proceeding with call (suId:%d suInstId:%u spInstId:%u)\n", + signal_data->cc_id, sngisdn_info->spInstId, sngisdn_info->suInstId); + + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } + + ftdm_mutex_unlock(ftdmchan->mutex); + return; +} + ftdm_status_t sngisdn_check_free_ids(void) { unsigned i; @@ -534,6 +560,77 @@ ftdm_user_layer1_prot_t sngisdn_get_usrInfoLyr1Prot_from_user(uint8_t layer1_pro return FTDM_USER_LAYER1_PROT_ULAW; } +void sngisdn_print_phy_stats(ftdm_stream_handle_t *stream, ftdm_span_t *span) +{ + L1Mngmt sts; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; + + memset(&sts, 0, sizeof(sts)); + sng_isdn_phy_stats(signal_data->link_id , &sts); + + stream->write_function(stream, "\n---------------------------------------------------------------------\n"); + stream->write_function(stream, " Span:%s", span->name); + stream->write_function(stream, "\n---------------------------------------------------------------------\n"); + stream->write_function(stream, " Performance Counters"); + stream->write_function(stream, "\n---------------------------------------------------------------------\n"); + stream->write_function(stream, "RX Packets:\t%u\tTX Packets:\t%u\tEvents:%u\n", sts.t.sts.rx_packets, sts.t.sts.tx_packets, sts.t.sts.rx_events); + stream->write_function(stream, "RX Bytes:\t%u\tTX Bytes:\t%u\n\n", sts.t.sts.rx_bytes, sts.t.sts.tx_bytes); + stream->write_function(stream, "TX Queue:\t%u/%u\tRX Queue:\t%u/%u\tEvents Queue:\t%u/%u\n", + sts.t.sts.num_frames_in_tx_queue,sts.t.sts.tx_queue_len, + sts.t.sts.num_frames_in_rx_queue, sts.t.sts.rx_queue_len, + sts.t.sts.rx_events_in_queue, sts.t.sts.event_queue_len); + + stream->write_function(stream, "\n---------------------------------------------------------------------\n"); + stream->write_function(stream, " Errors"); + stream->write_function(stream, "\n---------------------------------------------------------------------\n"); + stream->write_function(stream, "RX Errors:\t%u\tTX Errors:\t%u\n", sts.t.sts.rx_errors, sts.t.sts.tx_errors); + stream->write_function(stream, "RX Dropped:\t%u\tTX Dropped:\t%u\tEvents Dropped:\t%u\n", sts.t.sts.rx_dropped, sts.t.sts.tx_dropped,sts.t.sts.rx_events_dropped); + + + stream->write_function(stream, "\n---------------------------------------------------------------------\n"); + stream->write_function(stream, " RX Errors Details"); + stream->write_function(stream, "\n---------------------------------------------------------------------\n"); + stream->write_function(stream, "CRC:\t\t%u\tFrame:\t\t%u\tOverruns:\t%u\n", sts.t.sts.rx_crc_errors, sts.t.sts.rx_frame_errors, sts.t.sts.rx_over_errors); + stream->write_function(stream, "Fifo:\t\t%u\tAborts:\t\t%u\tMissed:\t\t%u\n", sts.t.sts.rx_fifo_errors, sts.t.sts.rx_hdlc_abort_counter, sts.t.sts.rx_missed_errors); + stream->write_function(stream, "Length:\t\t%u\n", sts.t.sts.rx_length_errors); + + stream->write_function(stream, "\n---------------------------------------------------------------------\n"); + stream->write_function(stream, " TX Errors Details"); + stream->write_function(stream, "\n---------------------------------------------------------------------\n"); + stream->write_function(stream, "Aborted:\t%u\tFifo:\t\t%u\tCarrier:\t%u\n", sts.t.sts.tx_aborted_errors, sts.t.sts.tx_fifo_errors, sts.t.sts.tx_carrier_errors); + return; +} + + +void sngisdn_print_span(ftdm_stream_handle_t *stream, ftdm_span_t *span) +{ + ftdm_signaling_status_t sigstatus; + ftdm_alarm_flag_t alarmbits; + ftdm_channel_t *fchan; + alarmbits = FTDM_ALARM_NONE; + fchan = ftdm_span_get_channel(span, 1); + if (fchan) { + ftdm_channel_get_alarms(fchan, &alarmbits); + } + + ftdm_span_get_sig_status(span, &sigstatus); + stream->write_function(stream, "span:%s physical:%s signalling:%s\n", + span->name, alarmbits ? "ALARMED" : "OK", + ftdm_signaling_status2str(sigstatus)); + return; +} + +void sngisdn_print_spans(ftdm_stream_handle_t *stream) +{ + int i; + for(i=1;i<=MAX_L1_LINKS;i++) { + if (g_sngisdn_data.spans[i]) { + sngisdn_print_span(stream, g_sngisdn_data.spans[i]->ftdm_span); + } + } + return; +} + /* For Emacs: * Local Variables: * mode:c diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c index c8c8bc3dd1..21feb4f8fe 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c @@ -85,35 +85,35 @@ int ft_to_sngss7_cfg_all(void) if (ftmod_ss7_mtp1_gen_config()) { SS7_CRITICAL("MTP1 General configuration FAILED!\n"); - SS7_ASSERT + return 1; } else { SS7_INFO("MTP1 General configuration DONE\n"); } if (ftmod_ss7_mtp2_gen_config()) { SS7_CRITICAL("MTP2 General configuration FAILED!\n"); - SS7_ASSERT + return 1; } else { SS7_INFO("MTP2 General configuration DONE\n"); } if (ftmod_ss7_mtp3_gen_config()) { SS7_CRITICAL("MTP3 General configuration FAILED!\n"); - SS7_ASSERT + return 1; } else { SS7_INFO("MTP3 General configuration DONE\n"); } if (ftmod_ss7_isup_gen_config()) { SS7_CRITICAL("ISUP General configuration FAILED!\n"); - SS7_ASSERT + return 1; } else { SS7_INFO("ISUP General configuration DONE\n"); } if (ftmod_ss7_cc_gen_config()) { SS7_CRITICAL("CC General configuration FAILED!\n"); - SS7_ASSERT + return 1; } else { SS7_INFO("CC General configuration DONE\n"); } @@ -131,7 +131,7 @@ int ft_to_sngss7_cfg_all(void) /* configure mtp1 */ if (ftmod_ss7_mtp1_psap_config(x)) { SS7_CRITICAL("MTP1 PSAP %d configuration FAILED!\n", x); - SS7_ASSERT; + return 1;; } else { SS7_INFO("MTP1 PSAP %d configuration DONE!\n", x); } @@ -139,7 +139,7 @@ int ft_to_sngss7_cfg_all(void) /* configure mtp2 */ if (ftmod_ss7_mtp2_dlsap_config(x)) { SS7_CRITICAL("MTP2 DLSAP %d configuration FAILED!\n",x); - SS7_ASSERT; + return 1;; } else { SS7_INFO("MTP2 DLSAP %d configuration DONE!\n", x); } @@ -147,7 +147,7 @@ int ft_to_sngss7_cfg_all(void) /* configure mtp3 */ if (ftmod_ss7_mtp3_dlsap_config(x)) { SS7_CRITICAL("MTP3 DLSAP %d configuration FAILED!\n", x); - SS7_ASSERT; + return 1;; } else { SS7_INFO("MTP3 DLSAP %d configuration DONE!\n", x); } @@ -166,14 +166,14 @@ int ft_to_sngss7_cfg_all(void) if (ftmod_ss7_mtp3_nsap_config(x)) { SS7_CRITICAL("MTP3 NSAP %d configuration FAILED!\n", x); - SS7_ASSERT + return 1; } else { SS7_INFO("MTP3 NSAP %d configuration DONE!\n", x); } if (ftmod_ss7_isup_nsap_config(x)) { SS7_CRITICAL("ISUP NSAP %d configuration FAILED!\n", x); - SS7_ASSERT + return 1; } else { SS7_INFO("ISUP NSAP %d configuration DONE!\n", x); } @@ -192,7 +192,7 @@ int ft_to_sngss7_cfg_all(void) if (ftmod_ss7_mtp3_linkset_config(x)) { SS7_CRITICAL("MTP3 LINKSET %d configuration FAILED!\n", x); - SS7_ASSERT + return 1; } else { SS7_INFO("MTP3 LINKSET %d configuration DONE!\n", x); } @@ -211,9 +211,9 @@ int ft_to_sngss7_cfg_all(void) if (ftmod_ss7_mtp3_route_config(x)) { SS7_CRITICAL("MTP3 ROUTE %d configuration FAILED!\n", x); - SS7_ASSERT + return 1; } else { - SS7_INFO("MTP3 ROUTE %d configuration DONE!\n"); + SS7_INFO("MTP3 ROUTE %d configuration DONE!\n",x); } /* set the CONFIGURED flag */ @@ -227,9 +227,9 @@ int ft_to_sngss7_cfg_all(void) if (ftmod_ss7_mtp3_route_config(0)) { SS7_CRITICAL("MTP3 ROUTE 0 configuration FAILED!\n"); - SS7_ASSERT + return 1; } else { - SS7_INFO("MTP3 ROUTE %d configuration DONE!\n"); + SS7_INFO("MTP3 ROUTE 0 configuration DONE!\n"); } /* set the CONFIGURED flag */ @@ -244,14 +244,14 @@ int ft_to_sngss7_cfg_all(void) if (ftmod_ss7_isup_isap_config(x)) { SS7_CRITICAL("ISUP ISAP %d configuration FAILED!\n", x); - SS7_ASSERT + return 1; } else { SS7_INFO("ISUP ISAP %d configuration DONE!\n", x); } if (ftmod_ss7_cc_isap_config(x)) { SS7_CRITICAL("CC ISAP %d configuration FAILED!\n", x); - SS7_ASSERT + return 1; } else { SS7_INFO("CC ISAP %d configuration DONE!\n", x); } @@ -270,9 +270,11 @@ int ft_to_sngss7_cfg_all(void) if (ftmod_ss7_isup_intf_config(x)) { SS7_CRITICAL("ISUP INTF %d configuration FAILED!\n", x); - SS7_ASSERT + return 1; } else { SS7_INFO("ISUP INTF %d configuration DONE!\n", x); + /* set the interface to paused */ + sngss7_set_flag(&g_ftdm_sngss7_data.cfg.isupIntf[x], SNGSS7_PAUSED); } /* set the CONFIGURED flag */ @@ -289,7 +291,7 @@ int ft_to_sngss7_cfg_all(void) if ( g_ftdm_sngss7_data.cfg.isupCkt[x].type == 0) { if (ftmod_ss7_isup_ckt_config(x)) { SS7_CRITICAL("ISUP CKT %d configuration FAILED!\n", x); - SS7_ASSERT + return 1; } else { SS7_INFO("ISUP CKT %d configuration DONE!\n", x); } @@ -444,8 +446,8 @@ int ftmod_ss7_mtp3_gen_config(void) cfg.t.cfg.s.snGen.tmr.t21.enb = TRUE; /* t21 - waiting to restart traffic routed through adjacent SP */ cfg.t.cfg.s.snGen.tmr.t21.val = 650; # if (SS7_ANS92 || SS7_ANS88 || SS7_ANS96 || defined(TDS_ROLL_UPGRADE_SUPPORT)) - cfg.t.cfg.s.snGen.t26.enb = TRUE; /* t26 - waiting to repeat traffic restart waiting message for ANSI */ - cfg.t.cfg.s.snGen.t26.val = 600; + cfg.t.cfg.s.snGen.tmr.t26.enb = TRUE; /* t26 - waiting to repeat traffic restart waiting message for ANSI */ + cfg.t.cfg.s.snGen.tmr.t26.val = 600; # endif #endif @@ -644,7 +646,7 @@ int ftmod_ss7_mtp2_dlsap_config(int id) cfg.t.cfg.s.sdDLSAP.memMac.region = S_REG; /* memory region and pool id for MAC */ cfg.t.cfg.s.sdDLSAP.memMac.pool = S_POOL; cfg.t.cfg.s.sdDLSAP.maxOutsFrms = MAX_SD_OUTSTANDING; /* maximum outstanding frames */ - cfg.t.cfg.s.sdDLSAP.errType = SD_ERR_NRM; + cfg.t.cfg.s.sdDLSAP.errType = k->mtp2.errorType; cfg.t.cfg.s.sdDLSAP.t1.enb = TRUE; /* timer 1 - Alignment Ready Timer */ cfg.t.cfg.s.sdDLSAP.t1.val = k->mtp2.t1; cfg.t.cfg.s.sdDLSAP.t2.enb = TRUE; /* timer 2 - Not Aligned Timer */ @@ -744,10 +746,6 @@ int ftmod_ss7_mtp3_dlsap_config(int id) cfg.t.cfg.s.snDLSAP.msgPrior = 0; /* management message priority */ cfg.t.cfg.s.snDLSAP.lnkType = k->mtp3.linkType; /* link type ANSI, ITU, BICI or CHINA */ cfg.t.cfg.s.snDLSAP.upSwtch = k->mtp3.switchType; /* user part switch type */ -# if (SS7_ANS92 || SS7_ANS88 || SS7_ANS96 || SS7_CHINA) - cfg.t.cfg.s.snDLSAP.l2Type = LSN_MTP2_56KBPS; /* layer 2 type - 56kbps MTP2 link, 1.536Mbps MTP2 link or QSAAL link */ - cfg.t.cfg.s.snDLSAP.isCLink = FALSE; /* identifies if the link is a C type link.Required to check if sls has to be rotated.*/ -# endif cfg.t.cfg.s.snDLSAP.maxSLTtry = MAX_SLTM_RETRIES; /* maximun times to retry SLTM */ cfg.t.cfg.s.snDLSAP.p0QLen = 32; /* size of the priority 0 Q */ cfg.t.cfg.s.snDLSAP.p1QLen = 32; /* size of the priority 1 Q */ @@ -775,17 +773,46 @@ int ftmod_ss7_mtp3_dlsap_config(int id) cfg.t.cfg.s.snDLSAP.selector = 0; /* lower layer selector */ cfg.t.cfg.s.snDLSAP.mem.region = S_REG; /* memory region id */ cfg.t.cfg.s.snDLSAP.mem.pool = S_POOL; /* memory pool id */ -#if( SS7_ANS92 || SS7_ANS88 || SS7_ANS96 || SS7_CHINA ) - cfg.t.cfg.s.snDLSAP.dpcLen = DPC24; /* dpc length 24 bits */ -#else - cfg.t.cfg.s.snDLSAP.dpcLen = DPC14; /* dpc length 14 bits */ -#endif cfg.t.cfg.s.snDLSAP.spId = k->mtp3.mtp2Id ;/* service provider id */ -#if (SS7_ITU88 || SS7_CHINA || SS7_TTC || SS7_NTT || SS7_BICI ) - cfg.t.cfg.s.snDLSAP.flushContFlag = FALSE; /* flush continue handling */ -#else - cfg.t.cfg.s.snDLSAP.flushContFlag = TRUE; /* flush continue handling */ -#endif + + switch (k->mtp3.linkType) { + /**************************************************************************/ + case (LSN_SW_ANS): + case (LSN_SW_ANS96): + case (LSN_SW_CHINA): + cfg.t.cfg.s.snDLSAP.dpcLen = DPC24; /* dpc length 24 bits */ + cfg.t.cfg.s.snDLSAP.l2Type = LSN_MTP2_56KBPS; /* layer 2 type - 56kbps MTP2 link, 1.536Mbps MTP2 link or QSAAL link */ + cfg.t.cfg.s.snDLSAP.isCLink = FALSE; /* identifies if the link is a C type link.Required to check if sls has to be rotated.*/ + break; + /**************************************************************************/ + case (LSN_SW_ITU): + cfg.t.cfg.s.snDLSAP.dpcLen = DPC14; /* dpc length 14 bits */ + break; + /**************************************************************************/ + default: + cfg.t.cfg.s.snDLSAP.dpcLen = DPC14; /* dpc length 14 bits */ + break; + /**************************************************************************/ + } /* switch (k->mtp3.linkType) */ + + switch (k->mtp3.linkType) { + /**************************************************************************/ + case (LSN_SW_ANS): + case (LSN_SW_ANS96): + cfg.t.cfg.s.snDLSAP.flushContFlag = TRUE; /* flush continue handling */ + break; + /**************************************************************************/ + case (LSN_SW_ITU): + case (LSN_SW_CHINA): + cfg.t.cfg.s.snDLSAP.flushContFlag = FALSE; /* flush continue handling */ + break; + /**************************************************************************/ + default: + cfg.t.cfg.s.snDLSAP.flushContFlag = FALSE; /* flush continue handling */ + break; + /**************************************************************************/ + } /* switch (k->mtp3.linkType) */ + cfg.t.cfg.s.snDLSAP.tmr.t1.enb = TRUE; /* t1 - delay to avoid missequencing on changeover */ cfg.t.cfg.s.snDLSAP.tmr.t1.val = k->mtp3.t1; cfg.t.cfg.s.snDLSAP.tmr.t2.enb = TRUE; /* t2 - waiting for changeover ack */ @@ -900,7 +927,7 @@ int ftmod_ss7_mtp3_linkset_config(int id) { Pst pst; SnMngmt cfg; - U16 c; + int c; sng_link_set_t *k = &g_ftdm_sngss7_data.cfg.mtpLinkSet[id]; /* initalize the post structure */ @@ -927,12 +954,13 @@ int ftmod_ss7_mtp3_linkset_config(int id) cfg.t.cfg.s.snLnkSet.lnkSetType = k->linkType; /* link type */ cfg.t.cfg.s.snLnkSet.adjDpc = k->apc; /* adjacent DPC */ cfg.t.cfg.s.snLnkSet.nmbActLnkReqd = k->minActive; /* minimum number of active links */ - cfg.t.cfg.s.snLnkSet.nmbCmbLnkSet = 1; /* number of combined link sets */ - for (c = 0; c < LSN_MAXCMBLNK; c++) { - cfg.t.cfg.s.snLnkSet.cmbLnkSet[c].cmbLnkSetId = c+1; + cfg.t.cfg.s.snLnkSet.nmbCmbLnkSet = k->numLinks; /* number of combined link sets */ + for(c = 0; c < k->numLinks;c++) { + cfg.t.cfg.s.snLnkSet.cmbLnkSet[c].cmbLnkSetId = k->links[c]; cfg.t.cfg.s.snLnkSet.cmbLnkSet[c].lnkSetPrior = 0; } + return(sng_cfg_mtp3(&pst, &cfg)); } @@ -1209,12 +1237,12 @@ int ftmod_ss7_isup_ckt_config(int id) cfg.t.cfg.s.siCir.typeCntrl = k->typeCntrl; /* type of control */ cfg.t.cfg.s.siCir.contReq = FALSE; /* continuity check required */ #if (SI_218_COMP || SS7_ANS88 || SS7_ANS92 || SS7_ANS95 || SS7_BELL) - cfg.t.cfg.s.siCir.firstCic =; /* First cic in the circuit group */ - cfg.t.cfg.s.siCir.numCir =; /* Number of circuits in the circuit group */ + cfg.t.cfg.s.siCir.firstCic = 1; /* First cic in the circuit group */ + cfg.t.cfg.s.siCir.numCir = 24; /* Number of circuits in the circuit group */ cfg.t.cfg.s.siCir.nonSS7Con = TRUE; /* connecting to non SS7 network */ - cfg.t.cfg.s.siCir.outTrkGrpN =; /* outgoing trunk group number (For EXM) */ - cfg.t.cfg.s.siCir.cvrTrkClli =; /* Trunk Group number (For CVR validation) */ - cfg.t.cfg.s.siCir.clli =; /* common language location identifier */ + cfg.t.cfg.s.siCir.outTrkGrpN.length = 0; /* outgoing trunk group number (For EXM) */ + cfg.t.cfg.s.siCir.cvrTrkClli.length = 0; /* Trunk Group number (For CVR validation) */ + cfg.t.cfg.s.siCir.clli.length = 0; /* common language location identifier */ #endif cfg.t.cfg.s.siCir.cirTmr.t3.enb = TRUE; /* t3 timer - overload received */ cfg.t.cfg.s.siCir.cirTmr.t3.val = k->t3; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index edb15604e5..6ccc693478 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -48,8 +48,6 @@ static ftdm_status_t handle_print_usuage(ftdm_stream_handle_t *stream); static ftdm_status_t handle_set_function_trace(ftdm_stream_handle_t *stream, int on, int level); static ftdm_status_t handle_set_message_trace(ftdm_stream_handle_t *stream, int on, int level); -static ftdm_status_t handle_set_blocks(ftdm_stream_handle_t *stream, int span, int chan, int verbose); -static ftdm_status_t handle_set_unblks(ftdm_stream_handle_t *stream, int span, int chan, int verbose); static ftdm_status_t handle_set_inhibit(ftdm_stream_handle_t *stream, char *name); static ftdm_status_t handle_set_uninhibit(ftdm_stream_handle_t *stream, char *name); @@ -63,6 +61,21 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, static ftdm_status_t handle_tx_rsc(ftdm_stream_handle_t *stream, int span, int chan, int verbose); static ftdm_status_t handle_tx_grs(ftdm_stream_handle_t *stream, int span, int chan, int range, int verbose); +static ftdm_status_t handle_tx_blo(ftdm_stream_handle_t *stream, int span, int chan, int verbose); +static ftdm_status_t handle_tx_ubl(ftdm_stream_handle_t *stream, int span, int chan, int verbose); + +static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int chan, int range, int verbose); +static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int chan, int range, int verbose); + +static ftdm_status_t handle_activate_link(ftdm_stream_handle_t *stream, char *name); +static ftdm_status_t handle_deactivate_link(ftdm_stream_handle_t *stream, char *name); + +static ftdm_status_t handle_activate_linkset(ftdm_stream_handle_t *stream, char *name); +static ftdm_status_t handle_deactivate_linkset(ftdm_stream_handle_t *stream, char *name); + +static ftdm_status_t handle_tx_lpo(ftdm_stream_handle_t *stream, char *name); +static ftdm_status_t handle_tx_lpr(ftdm_stream_handle_t *stream, char *name); + static ftdm_status_t handle_status_link(ftdm_stream_handle_t *stream, char *name); static ftdm_status_t handle_status_linkset(ftdm_stream_handle_t *stream, char *name); @@ -282,20 +295,12 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha /**********************************************************************/ } /**************************************************************************/ - } else if (!strcasecmp(argv[c], "block")) { + } else if (!strcasecmp(argv[c], "inhibit")) { /**************************************************************************/ if (check_arg_count(argc, 2)) goto handle_cli_error_argc; c++; - if (!strcasecmp(argv[c], "span")) { - /**********************************************************************/ - if (check_arg_count(argc, 5)) goto handle_cli_error_argc; - - if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; - - handle_set_blocks(stream, span, chan, verbose); - /**********************************************************************/ - } else if (!strcasecmp(argv[c], "link")) { + if (!strcasecmp(argv[c], "link")) { /**********************************************************************/ if (check_arg_count(argc, 3)) goto handle_cli_error_argc; c++; @@ -309,7 +314,26 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha /**********************************************************************/ } /**************************************************************************/ - } else if (!strcasecmp(argv[c], "unblock")) { + } else if (!strcasecmp(argv[c], "uninhibit")) { + /**************************************************************************/ + if (check_arg_count(argc, 2)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "link")) { + /**********************************************************************/ + if (check_arg_count(argc, 3)) goto handle_cli_error_argc; + c++; + + handle_set_uninhibit(stream, argv[c]); + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"unblock\" command\n"); + goto handle_cli_error; + /**********************************************************************/ + } + /**************************************************************************/ + } else if (!strcasecmp(argv[c], "blo")) { /**************************************************************************/ if (check_arg_count(argc, 2)) goto handle_cli_error_argc; c++; @@ -320,18 +344,101 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; - handle_set_unblks(stream, span, chan, verbose); - /**********************************************************************/ - } else if (!strcasecmp(argv[c], "link")) { - /**********************************************************************/ - if (check_arg_count(argc, 3)) goto handle_cli_error_argc; - c++; - - handle_set_uninhibit(stream, argv[c]); + handle_tx_blo(stream, span, chan, verbose); /**********************************************************************/ } else { /**********************************************************************/ - stream->write_function(stream, "Unknown \"unblock\" command\n"); + stream->write_function(stream, "Unknown \"block\" command\n"); + goto handle_cli_error; + /**********************************************************************/ + } + /**************************************************************************/ + } else if (!strcasecmp(argv[c], "ubl")) { + /**************************************************************************/ + if (check_arg_count(argc, 2)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "span")) { + /**********************************************************************/ + if (check_arg_count(argc, 5)) goto handle_cli_error_argc; + + if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; + + handle_tx_ubl(stream, span, chan, verbose); + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"ubl\" command\n"); + goto handle_cli_error; + /**********************************************************************/ + } + /**************************************************************************/ + } else if (!strcasecmp(argv[c], "cgb")) { + /**************************************************************************/ + if (check_arg_count(argc, 2)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "span")) { + /**********************************************************************/ + if (check_arg_count(argc, 5)) goto handle_cli_error_argc; + + if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; + c = c + 4; + + if (check_arg_count(argc, 7)) goto handle_cli_error_argc; + + if (!strcasecmp(argv[c], "range")) { + /******************************************************************/ + c++; + range = atoi(argv[c]); + /******************************************************************/ + } else { + /******************************************************************/ + stream->write_function(stream, "Unknown \"cgb range\" command\n"); + goto handle_cli_error; + /******************************************************************/ + } + + handle_tx_cgb(stream, span, chan, range, verbose); + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"cgb\" command\n"); + goto handle_cli_error; + /**********************************************************************/ + } + /**************************************************************************/ + } else if (!strcasecmp(argv[c], "cgu")) { + /**************************************************************************/ + if (check_arg_count(argc, 2)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "span")) { + /**********************************************************************/ + if (check_arg_count(argc, 5)) goto handle_cli_error_argc; + + if (extract_span_chan(argv, c, &span, &chan)) goto handle_cli_error_span_chan; + c = c + 4; + + if (check_arg_count(argc, 7)) goto handle_cli_error_argc; + + if (!strcasecmp(argv[c], "range")) { + /******************************************************************/ + c++; + range = atoi(argv[c]); + /******************************************************************/ + } else { + /******************************************************************/ + stream->write_function(stream, "Unknown \"cgu range\" command\n"); + goto handle_cli_error; + /******************************************************************/ + } + + handle_tx_cgu(stream, span, chan, range, verbose); + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"cgu\" command\n"); goto handle_cli_error; /**********************************************************************/ } @@ -389,7 +496,97 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha stream->write_function(stream, "Unknown \"grs\" command\n"); goto handle_cli_error; /**********************************************************************/ - } + } + /**************************************************************************/ + } else if (!strcasecmp(argv[c], "lpo")) { + /**************************************************************************/ + if (check_arg_count(argc, 2)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "link")) { + /**********************************************************************/ + if (check_arg_count(argc, 3)) goto handle_cli_error_argc; + c++; + + handle_tx_lpo(stream, argv[c]); + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"lpo\" command\n"); + goto handle_cli_error; + /**********************************************************************/ + } + /**************************************************************************/ + } else if (!strcasecmp(argv[c], "lpr")) { + /**************************************************************************/ + if (check_arg_count(argc, 2)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "link")) { + /**********************************************************************/ + if (check_arg_count(argc, 3)) goto handle_cli_error_argc; + c++; + + handle_tx_lpr(stream, argv[c]); + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"lpr\" command\n"); + goto handle_cli_error; + /**********************************************************************/ + } + /**************************************************************************/ + } else if (!strcasecmp(argv[c], "activate")) { + /**************************************************************************/ + if (check_arg_count(argc, 2)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "link")) { + /**********************************************************************/ + if (check_arg_count(argc, 3)) goto handle_cli_error_argc; + c++; + + handle_activate_link(stream, argv[c]); + /**********************************************************************/ + }else if (!strcasecmp(argv[c], "linkset")) { + /**********************************************************************/ + if (check_arg_count(argc, 3)) goto handle_cli_error_argc; + c++; + + handle_activate_linkset(stream, argv[c]); + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"activate\" command\n"); + goto handle_cli_error; + /**********************************************************************/ + } + /**************************************************************************/ + } else if (!strcasecmp(argv[c], "deactivate")) { + /**************************************************************************/ + if (check_arg_count(argc, 2)) goto handle_cli_error_argc; + c++; + + if (!strcasecmp(argv[c], "link")) { + /**********************************************************************/ + if (check_arg_count(argc, 3)) goto handle_cli_error_argc; + c++; + + handle_deactivate_link(stream, argv[c]); + /**********************************************************************/ + }else if (!strcasecmp(argv[c], "linkset")) { + /**********************************************************************/ + if (check_arg_count(argc, 3)) goto handle_cli_error_argc; + c++; + + handle_deactivate_linkset(stream, argv[c]); + /**********************************************************************/ + } else { + /**********************************************************************/ + stream->write_function(stream, "Unknown \"deactivate\" command\n"); + goto handle_cli_error; + /**********************************************************************/ + } /**************************************************************************/ } else { /**************************************************************************/ @@ -433,10 +630,22 @@ static ftdm_status_t handle_print_usuage(ftdm_stream_handle_t *stream) stream->write_function(stream, "ftdm ss7 show inreset span X chan Y\n"); stream->write_function(stream, "\n"); stream->write_function(stream, "Ftmod_sangoma_ss7 circuit control:\n"); - stream->write_function(stream, "ftdm ss7 block span X chan Y\n"); - stream->write_function(stream, "ftdm ss7 unblk span X chan Y\n"); + stream->write_function(stream, "ftdm ss7 blo span X chan Y\n"); + stream->write_function(stream, "ftdm ss7 ubl span X chan Y\n"); stream->write_function(stream, "ftdm ss7 rsc span X chan Y\n"); stream->write_function(stream, "ftdm ss7 grs span X chan Y range Z\n"); + stream->write_function(stream, "ftdm ss7 cgb span X chan Y range Z\n"); + stream->write_function(stream, "ftdm ss7 cgu span X chan Y range Z\n"); + stream->write_function(stream, "\n"); + stream->write_function(stream, "Ftmod_sangoma_ss7 link control:\n"); + stream->write_function(stream, "ftdm ss7 inhibit link X\n"); + stream->write_function(stream, "ftdm ss7 uninhibit link X\n"); + stream->write_function(stream, "ftdm ss7 activate link X\n"); + stream->write_function(stream, "ftdm ss7 deactivate link X\n"); + stream->write_function(stream, "ftdm ss7 activate linkset X\n"); + stream->write_function(stream, "ftdm ss7 deactivate linkset X\n"); + stream->write_function(stream, "ftdm ss7 lpo link X\n"); + stream->write_function(stream, "ftdm ss7 lpr link X\n"); stream->write_function(stream, "\n"); return FTDM_SUCCESS; @@ -811,87 +1020,100 @@ static ftdm_status_t handle_show_blocks(ftdm_stream_handle_t *stream, int span, /******************************************************************************/ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, int chan, int verbose) { - int x; - sngss7_chan_data_t *ss7_info; - ftdm_channel_t *ftdmchan; - int lspan; - int lchan; - ftdm_signaling_status_t sigstatus = FTDM_SIG_STATE_DOWN; + int x; + sngss7_chan_data_t *ss7_info; + ftdm_channel_t *ftdmchan; + int lspan; + int lchan; + ftdm_signaling_status_t sigstatus = FTDM_SIG_STATE_DOWN; + sng_isup_ckt_t *ckt; x=1; while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { - if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == VOICE) { - ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; - ftdmchan = ss7_info->ftdmchan; + /* extract the circuit to make it easier to work with */ + ckt = &g_ftdm_sngss7_data.cfg.isupCkt[x]; /* if span == 0 then all spans should be printed */ if (span == 0) { - lspan = ftdmchan->physical_span_id; + lspan = ckt->span; } else { lspan = span; } /* if chan == 0 then all chans should be printed */ if (chan == 0) { - lchan = ftdmchan->physical_chan_id; + lchan = ckt->chan; } else { lchan = chan; } - if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { - /* grab the signaling_status */ - ftdm_channel_get_sig_status(ftdmchan, &sigstatus); + /* check if this circuit is one of the circuits we're interested in */ + if ((ckt->span == lspan) && (ckt->chan == lchan)) { + if (ckt->type == HOLE) { + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|NOT USED\n", + ckt->span, + ckt->chan, + ckt->cic); + } else if (ckt->type == SIG) { + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|SIGNALING LINK\n", + ckt->span, + ckt->chan, + ckt->cic); + } else { + ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + ftdmchan = ss7_info->ftdmchan; - stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|sig_status=%s|state=%s|", - ftdmchan->physical_span_id, - ftdmchan->physical_chan_id, - ss7_info->circuit->cic, - ftdm_signaling_status2str(sigstatus), - ftdm_channel_state2str(ftdmchan->state)); - - if((sngss7_test_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX)) || (sngss7_test_flag(ss7_info, FLAG_GRP_MN_BLOCK_TX))) { - stream->write_function(stream, "l_mn=Y|"); - }else { - stream->write_function(stream, "l_mn=N|"); - } - - if((sngss7_test_flag(ss7_info, FLAG_CKT_MN_BLOCK_RX)) || (sngss7_test_flag(ss7_info, FLAG_GRP_MN_BLOCK_RX))) { - stream->write_function(stream, "r_mn=Y|"); - }else { - stream->write_function(stream, "r_mn=N|"); - } - - if(sngss7_test_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX)) { - stream->write_function(stream, "l_hw=Y|"); - }else { - stream->write_function(stream, "l_hw=N|"); - } - - if(sngss7_test_flag(ss7_info, FLAG_GRP_HW_BLOCK_RX)) { - stream->write_function(stream, "r_hw=Y|"); - }else { - stream->write_function(stream, "r_hw=N|"); - } - - if(sngss7_test_flag(ss7_info, FLAG_CKT_LC_BLOCK_RX)) { - stream->write_function(stream, "l_mngmt=Y|"); - }else { - stream->write_function(stream, "l_mngmt=N|"); - } - - if(sngss7_test_flag(ss7_info, FLAG_CKT_UCIC_BLOCK)) { - stream->write_function(stream, "l_ucic=Y|"); - }else { - stream->write_function(stream, "l_ucic=N|"); - } - - stream->write_function(stream, "flags=0x%X",ss7_info->flags); - - stream->write_function(stream, "\n"); + /* grab the signaling_status */ + ftdm_channel_get_sig_status(ftdmchan, &sigstatus); + + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|sig_status=%s|state=%s|", + ckt->span, + ckt->chan, + ckt->cic, + ftdm_signaling_status2str(sigstatus), + ftdm_channel_state2str(ftdmchan->state)); + + if((sngss7_test_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX)) || (sngss7_test_flag(ss7_info, FLAG_GRP_MN_BLOCK_TX))) { + stream->write_function(stream, "l_mn=Y|"); + }else { + stream->write_function(stream, "l_mn=N|"); + } + + if((sngss7_test_flag(ss7_info, FLAG_CKT_MN_BLOCK_RX)) || (sngss7_test_flag(ss7_info, FLAG_GRP_MN_BLOCK_RX))) { + stream->write_function(stream, "r_mn=Y|"); + }else { + stream->write_function(stream, "r_mn=N|"); + } + + if(sngss7_test_flag(ss7_info, FLAG_GRP_HW_BLOCK_TX)) { + stream->write_function(stream, "l_hw=Y|"); + }else { + stream->write_function(stream, "l_hw=N|"); + } + + if(sngss7_test_flag(ss7_info, FLAG_GRP_HW_BLOCK_RX)) { + stream->write_function(stream, "r_hw=Y|"); + }else { + stream->write_function(stream, "r_hw=N|"); + } + + if(sngss7_test_flag(ss7_info, FLAG_CKT_LC_BLOCK_RX)) { + stream->write_function(stream, "l_mngmt=Y|"); + }else { + stream->write_function(stream, "l_mngmt=N|"); + } + + if(sngss7_test_flag(ss7_info, FLAG_CKT_UCIC_BLOCK)) { + stream->write_function(stream, "l_ucic=Y|"); + }else { + stream->write_function(stream, "l_ucic=N|"); + } + + stream->write_function(stream, "flags=0x%X",ss7_info->flags); + + stream->write_function(stream, "\n"); + } /* if ( hole, sig, voice) */ } /* if ( span and chan) */ - - } /* if ( cic != 0) */ - /* go the next circuit */ x++; } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ @@ -899,7 +1121,7 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, return FTDM_SUCCESS; } /******************************************************************************/ -static ftdm_status_t handle_set_blocks(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +static ftdm_status_t handle_tx_blo(ftdm_stream_handle_t *stream, int span, int chan, int verbose) { int x; sngss7_chan_data_t *ss7_info; @@ -934,7 +1156,12 @@ static ftdm_status_t handle_set_blocks(ftdm_stream_handle_t *stream, int span, i /* check if there is a pending state change|give it a bit to clear */ if (check_for_state_change(ftdmchan)) { SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); + /* check if we need to die */ SS7_ASSERT; + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + /* move to the next channel */ + continue; } else { /* throw the ckt block flag */ sngss7_set_flag(ss7_info, FLAG_CKT_MN_BLOCK_TX); @@ -960,7 +1187,7 @@ static ftdm_status_t handle_set_blocks(ftdm_stream_handle_t *stream, int span, i } /******************************************************************************/ -static ftdm_status_t handle_set_unblks(ftdm_stream_handle_t *stream, int span, int chan, int verbose) +static ftdm_status_t handle_tx_ubl(ftdm_stream_handle_t *stream, int span, int chan, int verbose) { int x; sngss7_chan_data_t *ss7_info; @@ -995,7 +1222,12 @@ static ftdm_status_t handle_set_unblks(ftdm_stream_handle_t *stream, int span, i /* check if there is a pending state change|give it a bit to clear */ if (check_for_state_change(ftdmchan)) { SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); + /* check if we need to die */ SS7_ASSERT; + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + /* move to the next channel */ + continue; } else { /* throw the ckt block flag */ sngss7_set_flag(ss7_info, FLAG_CKT_MN_UNBLK_TX); @@ -1154,17 +1386,17 @@ static ftdm_status_t handle_set_uninhibit(ftdm_stream_handle_t *stream, char *na /******************************************************************************/ static ftdm_status_t handle_tx_rsc(ftdm_stream_handle_t *stream, int span, int chan, int verbose) { - int x; - sngss7_chan_data_t *ss7_info; - ftdm_channel_t *ftdmchan; - int lspan; - int lchan; + int x; + sngss7_chan_data_t *sngss7_info; + ftdm_channel_t *ftdmchan; + int lspan; + int lchan; x=1; while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == VOICE) { - ss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; - ftdmchan = ss7_info->ftdmchan; + sngss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + ftdmchan = sngss7_info->ftdmchan; /* if span == 0 then all spans should be printed */ if (span == 0) { @@ -1181,27 +1413,31 @@ static ftdm_status_t handle_tx_rsc(ftdm_stream_handle_t *stream, int span, int c } if ((ftdmchan->physical_span_id == lspan) && (ftdmchan->physical_chan_id == lchan)) { - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change|give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", ss7_info->circuit->cic); - SS7_ASSERT; - } else { - /* throw the ckt block flag */ - sngss7_set_flag(ss7_info, FLAG_RESET_TX); + /* throw the reset flag */ + sngss7_set_flag(sngss7_info, FLAG_RESET_TX); - /* set the channel to suspended state */ + switch (ftdmchan->state) { + /**************************************************************************/ + case FTDM_CHANNEL_STATE_RESTART: + /* go to idle so that we can redo the restart state*/ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE); + break; + /**************************************************************************/ + default: + /* set the state of the channel to restart...the rest is done by the chan monitor */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + break; + /**************************************************************************/ } - + /* unlock the channel again before we exit */ ftdm_mutex_unlock(ftdmchan->mutex); - } /* if ( span and chan) */ - } /* if ( cic != 0) */ + } /* if ( cic == voice) */ /* go the next circuit */ x++; @@ -1240,7 +1476,12 @@ static ftdm_status_t handle_tx_grs(ftdm_stream_handle_t *stream, int span, int c /* check if there is a pending state change|give it a bit to clear */ if (check_for_state_change(ftdmchan)) { SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); + /* check if we need to die */ SS7_ASSERT; + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + /* move to the next channel */ + continue; } else { /* throw the grp reset flag */ sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_TX); @@ -1270,6 +1511,355 @@ static ftdm_status_t handle_tx_grs(ftdm_stream_handle_t *stream, int span, int c return FTDM_SUCCESS; } +/******************************************************************************/ +static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int chan, int range, int verbose) +{ + int x; + sngss7_chan_data_t *sngss7_info; + ftdm_channel_t *ftdmchan; + ftdm_channel_t *main_chan = NULL; + sngss7_span_data_t *sngss7_span; + int byte = 0; + int bit = 0; + ftdm_sigmsg_t sigev; + + memset (&sigev, 0, sizeof (sigev)); + + + if (range > 31) { + stream->write_function(stream, "Invalid range value %d", range); + return FTDM_SUCCESS; + } + + x=1; + while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == VOICE) { + + /* extract the channel and span info for this circuit */ + sngss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + ftdmchan = sngss7_info->ftdmchan; + sngss7_span = ftdmchan->span->mod_data; + + /* check if this circuit is part of the block */ + if ((ftdmchan->physical_span_id == span) && + ((ftdmchan->physical_chan_id >= chan) && (ftdmchan->physical_chan_id < (chan+range)))) { + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* throw the grp maint. block flag */ + sngss7_set_flag(sngss7_info, FLAG_GRP_MN_BLOCK_TX); + + /* bring the sig status down */ + sigev.chan_id = ftdmchan->chan_id; + sigev.span_id = ftdmchan->span_id; + sigev.channel = ftdmchan; + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.sigstatus = FTDM_SIG_STATE_DOWN; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + /* if this is the first channel in the range */ + if (ftdmchan->physical_chan_id == chan) { + /* attach the cgb information */ + main_chan = ftdmchan; + sngss7_span->tx_cgb.circuit = sngss7_info->circuit->id; + sngss7_span->tx_cgb.range = range-1; + sngss7_span->tx_cgb.type = 0; /* maintenace block */ + } /* if (ftdmchan->physical_chan_id == chan) */ + + /* update the status field */ + sngss7_span->tx_cgb.status[byte] = (sngss7_span->tx_cgb.status[byte] | (1 << bit)); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + } /* if ( span and chan) */ + } /* if ( cic == voice) */ + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + + /* send the circuit group block */ + ft_to_sngss7_cgb(main_chan); + + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int chan, int range, int verbose) +{ + int x; + sngss7_chan_data_t *sngss7_info; + ftdm_channel_t *ftdmchan; + ftdm_channel_t *main_chan = NULL; + sngss7_span_data_t *sngss7_span; + int byte = 0; + int bit = 0; + ftdm_sigmsg_t sigev; + + memset (&sigev, 0, sizeof (sigev)); + + + if (range > 31) { + stream->write_function(stream, "Invalid range value %d", range); + return FTDM_SUCCESS; + } + + x=1; + while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == VOICE) { + + /* extract the channel and span info for this circuit */ + sngss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + ftdmchan = sngss7_info->ftdmchan; + sngss7_span = ftdmchan->span->mod_data; + + /* check if this circuit is part of the block */ + if ((ftdmchan->physical_span_id == span) && + ((ftdmchan->physical_chan_id >= chan) && (ftdmchan->physical_chan_id < (chan+range)))) { + + /* now that we have the right channel...put a lock on it so no-one else can use it */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* throw the grp maint. block flag */ + sngss7_clear_flag(sngss7_info, FLAG_GRP_MN_BLOCK_TX); + + /* bring the sig status up */ + sigev.chan_id = ftdmchan->chan_id; + sigev.span_id = ftdmchan->span_id; + sigev.channel = ftdmchan; + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.sigstatus = FTDM_SIG_STATE_UP; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + /* if this is the first channel in the range */ + if (ftdmchan->physical_chan_id == chan) { + /* attach the cgb information */ + main_chan = ftdmchan; + sngss7_span->tx_cgu.circuit = sngss7_info->circuit->id; + sngss7_span->tx_cgu.range = range-1; + sngss7_span->tx_cgu.type = 0; /* maintenace block */ + } /* if (ftdmchan->physical_chan_id == chan) */ + + /* update the status field */ + sngss7_span->tx_cgu.status[byte] = (sngss7_span->tx_cgu.status[byte] | (1 << bit)); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + } /* if ( span and chan) */ + } /* if ( cic == voice) */ + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + + /* send the circuit group block */ + ft_to_sngss7_cgu(main_chan); + + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_activate_link(ftdm_stream_handle_t *stream, char *name) +{ + int x = 0; + + /* find the link request by it's name */ + x = 1; + while(g_ftdm_sngss7_data.cfg.mtpLink[x].id != 0) { + if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtpLink[x].name, name)) { + + /* send the uninhibit request */ + if (ftmod_ss7_activate_mtplink(x)) { + stream->write_function(stream, "Failed to activate link=%s\n", name); + return FTDM_FAIL; + } + + /* print the new status of the link */ + handle_status_link(stream, &name[0]); + goto success; + } + + /* move to the next link */ + x++; + } /* while (id != 0) */ + + stream->write_function(stream, "Could not find link=%s\n", name); + +success: + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_deactivate_link(ftdm_stream_handle_t *stream, char *name) +{ + int x = 0; + + /* find the link request by it's name */ + x = 1; + while(g_ftdm_sngss7_data.cfg.mtpLink[x].id != 0) { + if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtpLink[x].name, name)) { + + /* send the deactivate request */ + if (ftmod_ss7_deactivate2_mtplink(x)) { + stream->write_function(stream, "Failed to deactivate link=%s\n", name); + return FTDM_FAIL; + } + + /* print the new status of the link */ + handle_status_link(stream, &name[0]); + goto success; + } + + /* move to the next link */ + x++; + } /* while (id != 0) */ + + stream->write_function(stream, "Could not find link=%s\n", name); + +success: + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_activate_linkset(ftdm_stream_handle_t *stream, char *name) +{ + int x = 0; + + /* find the linkset request by it's name */ + x = 1; + while(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id != 0) { + if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name, name)) { + + /* send the activate request */ + if (ftmod_ss7_activate_mtplinkSet(x)) { + stream->write_function(stream, "Failed to activate linkset=%s\n", name); + return FTDM_FAIL; + } + + /* print the new status of the linkset */ + handle_status_linkset(stream, &name[0]); + goto success; + } + + /* move to the next linkset */ + x++; + } /* while (id != 0) */ + + stream->write_function(stream, "Could not find linkset=%s\n", name); + +success: + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_deactivate_linkset(ftdm_stream_handle_t *stream, char *name) +{ + int x = 0; + + /* find the linkset request by it's name */ + x = 1; + while(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id != 0) { + if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name, name)) { + + /* send the deactivate request */ + if (ftmod_ss7_deactivate2_mtplinkSet(x)) { + stream->write_function(stream, "Failed to deactivate linkset=%s\n", name); + return FTDM_FAIL; + } + + /* print the new status of the linkset */ + handle_status_linkset(stream, &name[0]); + goto success; + } + + /* move to the next linkset */ + x++; + } /* while (id != 0) */ + + stream->write_function(stream, "Could not find linkset=%s\n", name); + +success: + return FTDM_SUCCESS; +} + +/******************************************************************************/ + +static ftdm_status_t handle_tx_lpo(ftdm_stream_handle_t *stream, char *name) +{ + int x = 0; + + /* find the link request by it's name */ + x = 1; + while(g_ftdm_sngss7_data.cfg.mtpLink[x].id != 0) { + if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtpLink[x].name, name)) { + + /* send the uninhibit request */ + if (ftmod_ss7_lpo_mtplink(x)) { + stream->write_function(stream, "Failed set LPO link=%s\n", name); + return FTDM_FAIL; + } + + /* print the new status of the link */ + handle_status_link(stream, &name[0]); + goto success; + } + + /* move to the next link */ + x++; + } /* while (id != 0) */ + + stream->write_function(stream, "Could not find link=%s\n", name); + +success: + return FTDM_SUCCESS; +} + +/******************************************************************************/ +static ftdm_status_t handle_tx_lpr(ftdm_stream_handle_t *stream, char *name) +{ + int x = 0; + + /* find the link request by it's name */ + x = 1; + while(g_ftdm_sngss7_data.cfg.mtpLink[x].id != 0) { + if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtpLink[x].name, name)) { + + /* send the uninhibit request */ + if (ftmod_ss7_lpr_mtplink(x)) { + stream->write_function(stream, "Failed set LPR link=%s\n", name); + return FTDM_FAIL; + } + + /* print the new status of the link */ + handle_status_link(stream, &name[0]); + goto success; + } + + /* move to the next link */ + x++; + } /* while (id != 0) */ + + stream->write_function(stream, "Could not find link=%s\n", name); + +success: + return FTDM_SUCCESS; +} + /******************************************************************************/ static ftdm_status_t extract_span_chan(char *argv[10], int pos, int *span, int *chan) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c index 52b3860375..87733dd594 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c @@ -50,6 +50,17 @@ static int ftmod_ss7_enable_mtpLinkSet(int lnkSetId); int ftmod_ss7_inhibit_mtplink(uint32_t id); int ftmod_ss7_uninhibit_mtplink(uint32_t id); + +int ftmod_ss7_activate_mtplink(uint32_t id); +int ftmod_ss7_deactivate_mtplink(uint32_t id); +int ftmod_ss7_deactivate2_mtplink(uint32_t id); + +int ftmod_ss7_activate_mtplinkSet(uint32_t id); +int ftmod_ss7_deactivate_mtplinkSet(uint32_t id); +int ftmod_ss7_deactivate2_mtplinkSet(uint32_t id); + +int ftmod_ss7_lpo_mtplink(uint32_t id); +int ftmod_ss7_lpr_mtplink(uint32_t id); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -64,7 +75,7 @@ int ft_to_sngss7_activate_all(void) if (ftmod_ss7_enable_isap(x)) { SS7_CRITICAL("ISAP %d Enable: NOT OK\n", x); - SS7_ASSERT; + return 1; } else { SS7_INFO("ISAP %d Enable: OK\n", x); } @@ -83,7 +94,7 @@ int ft_to_sngss7_activate_all(void) if (ftmod_ss7_enable_nsap(x)) { SS7_CRITICAL("NSAP %d Enable: NOT OK\n", x); - SS7_ASSERT; + return 1; } else { SS7_INFO("NSAP %d Enable: OK\n", x); } @@ -102,7 +113,7 @@ int ft_to_sngss7_activate_all(void) if (ftmod_ss7_enable_mtpLinkSet(x)) { SS7_CRITICAL("LinkSet \"%s\" Enable: NOT OK\n", g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name); - SS7_ASSERT; + return 1; } else { SS7_INFO("LinkSet \"%s\" Enable: OK\n", g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name); } @@ -271,6 +282,248 @@ int ftmod_ss7_uninhibit_mtplink(uint32_t id) return (sng_cntrl_mtp3(&pst, &cntrl)); } +/******************************************************************************/ +int ftmod_ss7_activate_mtplink(uint32_t id) +{ + SnMngmt cntrl; + Pst pst; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTSN; + + /* initalize the control structure */ + memset(&cntrl, 0x0, sizeof(SnMngmt)); + + /* initalize the control header */ + smHdrInit(&cntrl.hdr); + + cntrl.hdr.msgType = TCNTRL; /* this is a control request */ + cntrl.hdr.entId.ent = ENTSN; + cntrl.hdr.entId.inst = S_INST; + cntrl.hdr.elmId.elmnt = STDLSAP; + cntrl.hdr.elmId.elmntInst1 = g_ftdm_sngss7_data.cfg.mtpLink[id].id; + + cntrl.t.cntrl.action = AENA; /* Activate */ + cntrl.t.cntrl.subAction = SAELMNT; /* specificed element */ + + return (sng_cntrl_mtp3(&pst, &cntrl)); +} + +/******************************************************************************/ +int ftmod_ss7_deactivate_mtplink(uint32_t id) +{ + SnMngmt cntrl; + Pst pst; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTSN; + + /* initalize the control structure */ + memset(&cntrl, 0x0, sizeof(SnMngmt)); + + /* initalize the control header */ + smHdrInit(&cntrl.hdr); + + cntrl.hdr.msgType = TCNTRL; /* this is a control request */ + cntrl.hdr.entId.ent = ENTSN; + cntrl.hdr.entId.inst = S_INST; + cntrl.hdr.elmId.elmnt = STDLSAP; + cntrl.hdr.elmId.elmntInst1 = g_ftdm_sngss7_data.cfg.mtpLink[id].id; + + cntrl.t.cntrl.action = ADISIMM; /* Deactivate */ + cntrl.t.cntrl.subAction = SAELMNT; /* specificed element */ + + return (sng_cntrl_mtp3(&pst, &cntrl)); +} + +/******************************************************************************/ +int ftmod_ss7_deactivate2_mtplink(uint32_t id) +{ + SnMngmt cntrl; + Pst pst; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTSN; + + /* initalize the control structure */ + memset(&cntrl, 0x0, sizeof(SnMngmt)); + + /* initalize the control header */ + smHdrInit(&cntrl.hdr); + + cntrl.hdr.msgType = TCNTRL; /* this is a control request */ + cntrl.hdr.entId.ent = ENTSN; + cntrl.hdr.entId.inst = S_INST; + cntrl.hdr.elmId.elmnt = STDLSAP; + cntrl.hdr.elmId.elmntInst1 = g_ftdm_sngss7_data.cfg.mtpLink[id].id; + + cntrl.t.cntrl.action = ADISIMM_L2; /* Deactivate...layer 2 only */ + cntrl.t.cntrl.subAction = SAELMNT; /* specificed element */ + + return (sng_cntrl_mtp3(&pst, &cntrl)); +} + +/******************************************************************************/ +int ftmod_ss7_activate_mtplinkSet(uint32_t id) +{ + SnMngmt cntrl; + Pst pst; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTSN; + + /* initalize the control structure */ + memset(&cntrl, 0x0, sizeof(SnMngmt)); + + /* initalize the control header */ + smHdrInit(&cntrl.hdr); + + cntrl.hdr.msgType = TCNTRL; /* this is a control request */ + cntrl.hdr.entId.ent = ENTSN; + cntrl.hdr.entId.inst = S_INST; + cntrl.hdr.elmId.elmnt = STLNKSET; + cntrl.hdr.elmId.elmntInst1 = g_ftdm_sngss7_data.cfg.mtpLinkSet[id].id; + + cntrl.t.cntrl.action = AACTLNKSET; /* Activate */ + cntrl.t.cntrl.subAction = SAELMNT; /* specificed element */ + + return (sng_cntrl_mtp3(&pst, &cntrl)); +} + +/******************************************************************************/ +int ftmod_ss7_deactivate_mtplinkSet(uint32_t id) +{ + SnMngmt cntrl; + Pst pst; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTSN; + + /* initalize the control structure */ + memset(&cntrl, 0x0, sizeof(SnMngmt)); + + /* initalize the control header */ + smHdrInit(&cntrl.hdr); + + cntrl.hdr.msgType = TCNTRL; /* this is a control request */ + cntrl.hdr.entId.ent = ENTSN; + cntrl.hdr.entId.inst = S_INST; + cntrl.hdr.elmId.elmnt = STLNKSET; + cntrl.hdr.elmId.elmntInst1 = g_ftdm_sngss7_data.cfg.mtpLinkSet[id].id; + + cntrl.t.cntrl.action = ADEACTLNKSET; /* Activate */ + cntrl.t.cntrl.subAction = SAELMNT; /* specificed element */ + + return (sng_cntrl_mtp3(&pst, &cntrl)); +} + +/******************************************************************************/ +int ftmod_ss7_deactivate2_mtplinkSet(uint32_t id) +{ + SnMngmt cntrl; + Pst pst; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTSN; + + /* initalize the control structure */ + memset(&cntrl, 0x0, sizeof(SnMngmt)); + + /* initalize the control header */ + smHdrInit(&cntrl.hdr); + + cntrl.hdr.msgType = TCNTRL; /* this is a control request */ + cntrl.hdr.entId.ent = ENTSN; + cntrl.hdr.entId.inst = S_INST; + cntrl.hdr.elmId.elmnt = STLNKSET; + cntrl.hdr.elmId.elmntInst1 = g_ftdm_sngss7_data.cfg.mtpLinkSet[id].id; + + cntrl.t.cntrl.action = ADEACTLNKSET_L2; /* Activate */ + cntrl.t.cntrl.subAction = SAELMNT; /* specificed element */ + + return (sng_cntrl_mtp3(&pst, &cntrl)); +} + +/******************************************************************************/ +int ftmod_ss7_lpo_mtplink(uint32_t id) +{ + SnMngmt cntrl; + Pst pst; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTSN; + + /* initalize the control structure */ + memset(&cntrl, 0x0, sizeof(SnMngmt)); + + /* initalize the control header */ + smHdrInit(&cntrl.hdr); + + cntrl.hdr.msgType = TCNTRL; /* this is a control request */ + cntrl.hdr.entId.ent = ENTSN; + cntrl.hdr.entId.inst = S_INST; + cntrl.hdr.elmId.elmnt = STDLSAP; + cntrl.hdr.elmId.elmntInst1 = g_ftdm_sngss7_data.cfg.mtpLink[id].id; + + cntrl.t.cntrl.action = ACTION_LPO; /* Activate */ + cntrl.t.cntrl.subAction = SAELMNT; /* specificed element */ + + return (sng_cntrl_mtp3(&pst, &cntrl)); +} + +/******************************************************************************/ +int ftmod_ss7_lpr_mtplink(uint32_t id) +{ + SnMngmt cntrl; + Pst pst; + + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTSN; + + /* initalize the control structure */ + memset(&cntrl, 0x0, sizeof(SnMngmt)); + + /* initalize the control header */ + smHdrInit(&cntrl.hdr); + + cntrl.hdr.msgType = TCNTRL; /* this is a control request */ + cntrl.hdr.entId.ent = ENTSN; + cntrl.hdr.entId.inst = S_INST; + cntrl.hdr.elmId.elmnt = STDLSAP; + cntrl.hdr.elmId.elmntInst1 = g_ftdm_sngss7_data.cfg.mtpLink[id].id; + + cntrl.t.cntrl.action = ACTION_LPR; /* Activate */ + cntrl.t.cntrl.subAction = SAELMNT; /* specificed element */ + + return (sng_cntrl_mtp3(&pst, &cntrl)); +} + +/******************************************************************************/ + /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index f0cfa0237a..ac7a61646f 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -71,6 +71,8 @@ ftdm_status_t handle_ubl_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdm_status_t handle_local_blk(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); ftdm_status_t handle_local_ubl(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); ftdm_status_t handle_ucic(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -80,6 +82,9 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_chan_data_t *sngss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; + char nadi[2]; + + memset(nadi, '\0', sizeof(nadi)); /* get the ftdmchan and ss7_chan_data from the circuit */ if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { @@ -88,21 +93,13 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - if (sngss7_test_flag(sngss7_info, FLAG_GLARE)) { - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx IAM (glare detected on circuit)\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx IAM (glare)\n", sngss7_info->circuit->cic); } else { - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx IAM\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx IAM\n", sngss7_info->circuit->cic); } /* check if the circuit has a remote block */ @@ -210,7 +207,8 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ } /* add any special variables for the dialplan */ - /*ftdm_channel_add_var(ftdmchan, "ss7_stuff", "s");*/ + sprintf(nadi, "%d", siConEvnt->cgPtyNum.natAddrInd.val); + ftdm_channel_add_var(ftdmchan, "ss7_nadi", nadi); /* set the state of the channel to collecting...the rest is done by the chan monitor */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); @@ -281,21 +279,13 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - } - switch (evntType) { /**************************************************************************/ case (ADDRCMPLT): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx ACM\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx ACM\n", sngss7_info->circuit->cic); switch (ftdmchan->state) { /**********************************************************************/ case FTDM_CHANNEL_STATE_DIALING: @@ -316,115 +306,115 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ } /* switch (ftdmchan->state) */ /**************************************************************************/ case (MODIFY): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx MODIFY\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx MODIFY\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (MODCMPLT): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx MODIFY-COMPLETE\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx MODIFY-COMPLETE\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (MODREJ): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx MODIFY-REJECT\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx MODIFY-REJECT\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (PROGRESS): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CPG\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CPG\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (FRWDTRSFR): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx FOT\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx FOT\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (INFORMATION): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx INF\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx INF\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (INFORMATREQ): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx INR\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx INR\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (SUBSADDR): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx SAM\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx SAM\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (EXIT): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx EXIT\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx EXIT\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (NETRESMGT): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx NRM\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx NRM\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (IDENTREQ): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx IDR\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx IDR\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (IDENTRSP): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx IRS\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx IRS\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (MALCLLPRNT): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx MALICIOUS CALL\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx MALICIOUS CALL\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (CHARGE): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CRG\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CRG\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (TRFFCHGE): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CRG-TARIFF\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CRG-TARIFF\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (CHARGEACK): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CRG-ACK\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CRG-ACK\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (CALLOFFMSG): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CALL-OFFER\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CALL-OFFER\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (LOOPPRVNT): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx LOP\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx LOP\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (TECT_TIMEOUT): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx ECT-Timeout\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx ECT-Timeout\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (RINGSEND): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx RINGING-SEND\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx RINGING-SEND\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (CALLCLEAR): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CALL-LINE Clear\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CALL-LINE Clear\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (PRERELEASE): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx PRI\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx PRI\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (APPTRANSPORT): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx APM\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx APM\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (OPERATOR): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx OPERATOR\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx OPERATOR\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (METPULSE): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx METERING-PULSE\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx METERING-PULSE\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (CLGPTCLR): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CALLING_PARTY_CLEAR\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CALLING_PARTY_CLEAR\n", sngss7_info->circuit->cic); break; /**************************************************************************/ case (SUBDIRNUM): - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx SUB-DIR\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx SUB-DIR\n", sngss7_info->circuit->cic); break; /**************************************************************************/ default: - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Unknown Msg\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Unknown Msg\n", sngss7_info->circuit->cic); break; /**************************************************************************/ } @@ -451,25 +441,16 @@ ftdm_status_t handle_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - - /* check whether the ftdm channel is in a state to accept a call */ switch (ftdmchan->state) { /**************************************************************************/ case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx ANM\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx ANM\n", sngss7_info->circuit->cic); /* go to UP */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); @@ -478,7 +459,7 @@ ftdm_status_t handle_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ /**************************************************************************/ case FTDM_CHANNEL_STATE_DIALING: - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CON\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CON\n", sngss7_info->circuit->cic); /* go to UP */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); @@ -487,7 +468,7 @@ ftdm_status_t handle_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ /**************************************************************************/ default: /* incorrect state...reset the CIC */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx ANM/CON\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx ANM/CON\n", sngss7_info->circuit->cic); /* throw the TX reset flag */ sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_TX); @@ -521,18 +502,12 @@ ftdm_status_t handle_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx REL\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx REL cause=%d\n", + sngss7_info->circuit->cic, + siRelEvnt->causeDgn.causeVal.val); /* check whether the ftdm channel is in a state to release a call */ switch (ftdmchan->state) { @@ -610,18 +585,10 @@ ftdm_status_t handle_rel_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx RLC\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx RLC\n", sngss7_info->circuit->cic); /* check whether the ftdm channel is in a state to accept a call */ switch (ftdmchan->state) { @@ -669,18 +636,10 @@ ftdm_status_t handle_dat_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx DATA IND\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx DATA IND\n", sngss7_info->circuit->cic); /* unlock the channel */ ftdm_mutex_unlock(ftdmchan->mutex); @@ -704,18 +663,10 @@ ftdm_status_t handle_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx FAC\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx FAC\n", sngss7_info->circuit->cic); /* unlock the channel */ ftdm_mutex_unlock(ftdmchan->mutex); @@ -739,18 +690,10 @@ ftdm_status_t handle_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx FAC-CON\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx FAC-CON\n", sngss7_info->circuit->cic); /* unlock the channel */ ftdm_mutex_unlock(ftdmchan->mutex); @@ -774,18 +717,10 @@ ftdm_status_t handle_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t cir return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx USER-USER msg\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx USER-USER msg\n", sngss7_info->circuit->cic); /* unlock the channel */ ftdm_mutex_unlock(ftdmchan->mutex); @@ -812,217 +747,217 @@ ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ switch (evntType) { /**************************************************************************/ case SIT_STA_REATTEMPT: /* reattempt indication */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Reattempt indication\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Reattempt indication\n", sngss7_info->circuit->cic); handle_reattempt(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_ERRORIND: /* error indication */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Error indication\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Error indication\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_CONTCHK: /* continuity check */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx COT start\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx COT start\n", sngss7_info->circuit->cic); handle_cot_start(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CONTREP: /* continuity report */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx COT report\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx COT report\n", sngss7_info->circuit->cic); handle_cot(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_STPCONTIN: /* stop continuity */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx COT stop\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx COT stop\n", sngss7_info->circuit->cic); handle_cot_stop(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CGQRYRSP: /* circuit grp query response from far end forwarded to upper layer by ISUP */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CQM\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CQM\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_CONFUSION: /* confusion */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CFN\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CFN\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_LOOPBACKACK: /* loop-back acknowledge */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx LPA\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx LPA\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_CIRRSRVREQ: /* circuit reservation request */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Ckt Resveration req\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Ckt Resveration req\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_CIRRSRVACK: /* circuit reservation acknowledgement */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Ckt Res ack\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Ckt Res ack\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_CIRBLOREQ: /* circuit blocking request */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx BLO\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx BLO\n", sngss7_info->circuit->cic); handle_blo_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CIRBLORSP: /* circuit blocking response */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx BLA\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx BLA\n", sngss7_info->circuit->cic); handle_blo_rsp(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CIRUBLREQ: /* circuit unblocking request */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx UBL\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx UBL\n", sngss7_info->circuit->cic); handle_ubl_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CIRUBLRSP: /* circuit unblocking response */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx UBA\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx UBA\n", sngss7_info->circuit->cic); handle_ubl_rsp(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CIRRESREQ: /* circuit reset request - RSC */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx RSC\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx RSC\n", sngss7_info->circuit->cic); handle_rsc_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CIRLOCRES: /* reset initiated locally by the software */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Local RSC\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Local RSC\n", sngss7_info->circuit->cic); handle_local_rsc_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CIRRESRSP: /* circuit reset response */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx RSC-RLC\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx RSC-RLC\n", sngss7_info->circuit->cic); handle_rsc_rsp(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CGBREQ: /* CGB request */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CGB\n"); - SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CGB\n", sngss7_info->circuit->cic); + handle_cgb_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CGUREQ: /* CGU request */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CGU\n"); - SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CGU\n", sngss7_info->circuit->cic); + handle_cgu_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CGQRYREQ: /* circuit group query request */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CQM\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CQM\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_CGBRSP: /* mntc. oriented CGB response */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx mntc CGB\n"); - SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx mntc CGB\n", sngss7_info->circuit->cic); + /*handle_cgb_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);*/ break; /**************************************************************************/ case SIT_STA_CGURSP: /* mntc. oriented CGU response */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx mntc CGU\n"); - SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx mntc CGU\n", sngss7_info->circuit->cic); + /*SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType));*/ break; /**************************************************************************/ case SIT_STA_GRSREQ: /* circuit group reset request */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx GRS\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx GRS\n", sngss7_info->circuit->cic); handle_grs_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CIRUNEQPD: /* circuit unequipped indication */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx UCIC\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx UCIC\n", sngss7_info->circuit->cic); handle_ucic(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_GRSRSP: /* circuit group reset response */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx GRA\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx GRA\n", sngss7_info->circuit->cic); handle_grs_rsp(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_PAUSEIND: /* pause indication */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx SUS\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx SUS\n", sngss7_info->circuit->cic); handle_pause(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_RESUMEIND: /* resume indication */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx RES\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx RES\n", sngss7_info->circuit->cic); handle_resume(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_USRPARTA: /* user part available */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx UPA\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx UPA\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_RMTUSRUNAV: /* remote user not available */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Remote User not Available\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Remote User not Available\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_MTPCONG0: /* congestion indication level 0 */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Congestion L0\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Congestion L0\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_MTPCONG1: /* congestion indication level 1 */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Congestion L1\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Congestion L1\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_MTPCONG2: /* congestion indication level 2 */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Congestion L2\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Congestion L2\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_MTPCONG3: /* congestion indication level 3 */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Congestion L3\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Congestion L3\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_MTPSTPCONG: /* stop congestion indication level 0 */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Stop Congestion\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Stop Congestion\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_CIRLOCALBLOIND: /* Mngmt local blocking */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Local BLO\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Local BLO\n", sngss7_info->circuit->cic); handle_local_blk(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_CIRLOCALUBLIND: /* Mngmt local unblocking */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Local UBL\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Local UBL\n", sngss7_info->circuit->cic); handle_local_ubl(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ case SIT_STA_OVERLOAD: /* Overload */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Overload\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Overload\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_LMCGBREQ: /* when LM requests ckt grp blocking */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx LM CGB\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx LM CGB\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_LMCGUREQ: /* when LM requests ckt grp unblocking */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx LM CGU\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx LM CGU\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_LMGRSREQ: /* when LM requests ckt grp reset */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx LM RSC\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx LM RSC\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_CGBINFOIND: /* circuit grp blking ind , no resp req */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx CGB no resp req\n"); - SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + /*SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CGB no resp req\n", sngss7_info->circuit->cic);*/ +/* handle_cgb_req(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt);*/ break; /**************************************************************************/ case SIT_STA_LMCQMINFOREQ: /* when LM requests ckt grp query */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx LM CQM\n"); - SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx LM CQM\n", sngss7_info->circuit->cic); +// SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ case SIT_STA_CIRLOCGRS: /* group reset initiated locally by the software */ - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Rx Local GRS\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Local GRS\n", sngss7_info->circuit->cic); SS7_WARN(" %s indication not currently supported\n", DECODE_LCC_EVENT(evntType)); break; /**************************************************************************/ @@ -1051,17 +986,9 @@ ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t ci return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - if (sngss7_test_flag(sngss7_info, FLAG_GLARE)) { /* the glare flag is already up so it was caught ... do nothing */ SS7_DEBUG_CHAN(ftdmchan, "Glare flag is already up...nothing to do!%s\n", " "); @@ -1100,8 +1027,11 @@ ftdm_status_t handle_pause(uint32_t suInstId, uint32_t spInstId, uint32_t circui int infId; int i; - /* extract the affect infId from the circuit structure */ + /* extract the affected infId from the circuit structure */ infId = g_ftdm_sngss7_data.cfg.isupCkt[circuit].infId; + + /* set the interface to paused */ + sngss7_set_flag(&g_ftdm_sngss7_data.cfg.isupIntf[infId], SNGSS7_PAUSED); /* go through all the circuits now and find any other circuits on this infId */ i = 1; @@ -1121,21 +1051,11 @@ ftdm_status_t handle_pause(uint32_t suInstId, uint32_t spInstId, uint32_t circui /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - i++; - SS7_ASSERT; - }; - /* check if the circuit is fully started */ if (ftdm_test_flag(ftdmchan->span, FTDM_SPAN_IN_THREAD)) { + SS7_DEBUG_CHAN(ftdmchan, "Rx PAUSE%s\n", ""); /* set the pause flag on the channel */ sngss7_set_flag(sngss7_info, FLAG_INFID_PAUSED); - - /* set the statet o SUSPENDED to bring the sig status down */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } /* unlock the channel again before we exit */ @@ -1165,6 +1085,9 @@ ftdm_status_t handle_resume(uint32_t suInstId, uint32_t spInstId, uint32_t circu /* extract the affect infId from the circuit structure */ infId = g_ftdm_sngss7_data.cfg.isupCkt[circuit].infId; + /* set the interface to resumed */ + sngss7_clear_flag(&g_ftdm_sngss7_data.cfg.isupIntf[infId], SNGSS7_PAUSED); + /* go through all the circuits now and find any other circuits on this infId */ i = 1; while (g_ftdm_sngss7_data.cfg.isupCkt[i].id != 0) { @@ -1183,24 +1106,15 @@ ftdm_status_t handle_resume(uint32_t suInstId, uint32_t spInstId, uint32_t circu /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - i++; - SS7_ASSERT; - }; - /* only resume if we are paused */ if (sngss7_test_flag(sngss7_info, FLAG_INFID_PAUSED)) { + SS7_DEBUG_CHAN(ftdmchan, "Rx RESUME%s\n", ""); + /* set the resume flag on the channel */ sngss7_set_flag(sngss7_info, FLAG_INFID_RESUME); /* clear the paused flag */ sngss7_clear_flag(sngss7_info, FLAG_INFID_PAUSED); - - /* set the statet to SUSPENDED to bring the sig status up */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); } /* unlock the channel again before we exit */ @@ -1232,17 +1146,9 @@ ftdm_status_t handle_cot_start(uint32_t suInstId, uint32_t spInstId, uint32_t ci return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - /* open the channel if it is not open */ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) { if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { @@ -1290,17 +1196,9 @@ ftdm_status_t handle_cot_stop(uint32_t suInstId, uint32_t spInstId, uint32_t cir return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - /* tell the core to stop looping the channel */ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_LOOP, NULL); @@ -1351,17 +1249,9 @@ ftdm_status_t handle_blo_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - /* check if the circuit is already blocked or not */ if (sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX)) { SS7_WARN("Received BLO on circuit that is already blocked!\n"); @@ -1395,17 +1285,9 @@ ftdm_status_t handle_blo_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - /* KONRAD FIX ME */ /* unlock the channel again before we exit */ @@ -1430,17 +1312,9 @@ ftdm_status_t handle_ubl_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - /* check if the channel is blocked */ if (!(sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX))) { SS7_WARN("Received UBL on circuit that is not blocked!\n"); @@ -1477,17 +1351,9 @@ ftdm_status_t handle_ubl_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - /* KONRAD FIX ME */ /* unlock the channel again before we exit */ @@ -1512,17 +1378,9 @@ ftdm_status_t handle_rsc_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - /* throw the reset flag */ sngss7_set_flag(sngss7_info, FLAG_RESET_RX); @@ -1565,17 +1423,9 @@ ftdm_status_t handle_local_rsc_req(uint32_t suInstId, uint32_t spInstId, uint32_ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - /* throw the reset flag */ sngss7_set_flag(sngss7_info, FLAG_RESET_RX); @@ -1618,17 +1468,9 @@ ftdm_status_t handle_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - switch (ftdmchan->state) { /**********************************************************************/ case FTDM_CHANNEL_STATE_RESTART: @@ -1694,7 +1536,7 @@ ftdm_status_t handle_grs_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdm_channel_t *ftdmchan = NULL; sngss7_span_data_t *sngss7_span = NULL; int range; - int x; + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); @@ -1711,57 +1553,12 @@ ftdm_status_t handle_grs_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* loop over the cics starting from circuit until range+1 */ - for (x = circuit; x < (circuit + range + 1); x++) { - /* grab the circuit in question */ - if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); - break; - } - - /* now that we have the right channel...put a lock on it so no-one else can use it */ - ftdm_mutex_lock(ftdmchan->mutex); - - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_ASSERT; - }; + /* fill in the span structure for this circuit */ + sngss7_span = ftdmchan->span->mod_data; + sngss7_span->rx_grs.circuit = circuit; + sngss7_span->rx_grs.range = range; - /* fill in the span structure for this circuit */ - sngss7_span = ftdmchan->span->mod_data; - sngss7_span->rx_grs.circuit = circuit; - sngss7_span->rx_grs.range = range; - - SS7_INFO_CHAN(ftdmchan, "Rx GRS (%d:%d)\n", - g_ftdm_sngss7_data.cfg.isupCkt[circuit].cic, - (g_ftdm_sngss7_data.cfg.isupCkt[circuit].cic + range)); - - /* flag the channel as having received a reset */ - sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_RX); - - switch (ftdmchan->state) { - /**************************************************************************/ - case FTDM_CHANNEL_STATE_RESTART: - - /* go to idle so that we can redo the restart state*/ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE); - - break; - /**************************************************************************/ - default: - - /* set the state of the channel to restart...the rest is done by the chan monitor */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); - break; - /**************************************************************************/ - } - - /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); - - } + /* the reset will be started in the main thread by "check_if_rx_grs_started" */ SS7_FUNC_TRACE_EXIT(__FUNCTION__); return FTDM_SUCCESS; @@ -1772,10 +1569,16 @@ ftdm_status_t handle_grs_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ { SS7_FUNC_TRACE_ENTER(__FUNCTION__); - sngss7_chan_data_t *sngss7_info = NULL; - ftdm_channel_t *ftdmchan = NULL; + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + sngss7_span_data_t *sngss7_span = NULL; int range; - int x; + + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } /* extract the range value from the event structure */ if ((siStaEvnt->rangStat.eh.pres == PRSNT_NODEF) && (siStaEvnt->rangStat.range.pres == PRSNT_NODEF)) { @@ -1786,77 +1589,20 @@ ftdm_status_t handle_grs_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ return FTDM_FAIL; } - /* go through all the circuits in the range */ - for ( x = circuit; x < (circuit + range + 1); x++) { + /* fill in the span structure for this circuit */ + sngss7_span = ftdmchan->span->mod_data; + sngss7_span->rx_gra.circuit = circuit; + sngss7_span->rx_gra.range = range; - /* grab the circuit in question */ - if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); - break; - } + /* check if there is a cause value in the GRA */ + if ((siStaEvnt != NULL) && + (siStaEvnt->causeDgn.eh.pres == PRSNT_NODEF) && + (siStaEvnt->causeDgn.causeVal.pres == PRSNT_NODEF)) { - /* now that we have the right channel...put a lock on it so no-one else can use it */ - ftdm_mutex_lock(ftdmchan->mutex); + sngss7_span->rx_gra.cause = siStaEvnt->causeDgn.causeVal.val; + } - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_ASSERT; - }; - - SS7_INFO_CHAN(ftdmchan, "Rx GRA (%d:%d)\n", - g_ftdm_sngss7_data.cfg.isupCkt[circuit].cic, - (g_ftdm_sngss7_data.cfg.isupCkt[circuit].cic + range)); - - switch (ftdmchan->state) { - /**********************************************************************/ - case FTDM_CHANNEL_STATE_RESTART: - - /* throw the FLAG_RESET_TX_RSP to indicate we have acknowledgement from the remote side */ - sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP); - - /* go to DOWN */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - - break; - /**********************************************************************/ - case FTDM_CHANNEL_STATE_DOWN: - - /* do nothing, just drop the message */ - SS7_DEBUG("Receveived GRA in down state, dropping\n"); - - break; - /**********************************************************************/ - case FTDM_CHANNEL_STATE_TERMINATING: - case FTDM_CHANNEL_STATE_HANGUP: - case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: - - /* throw the FLAG_RESET_TX_RSP to indicate we have acknowledgement from the remote side */ - sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP); - - break; - /**********************************************************************/ - default: - /* ITU Q764-2.9.5.1.c -> release the circuit */ - if ((siStaEvnt != NULL) && - (siStaEvnt->causeDgn.eh.pres ==PRSNT_NODEF) && - (siStaEvnt->causeDgn.causeVal.pres == PRSNT_NODEF)) { - ftdmchan->caller_data.hangup_cause = siStaEvnt->causeDgn.causeVal.val; - } else { - ftdmchan->caller_data.hangup_cause = 98; /* Message not compatiable with call state */ - } - - /* go to terminating to hang up the call */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); - break; - /**********************************************************************/ - } - - /* unlock the channel again before we exit */ - ftdm_mutex_unlock(ftdmchan->mutex); - - } /* for (( x = 0; x < (circuit + range); x++) */ + /* the reset will be started in the main thread by "check_if_rx_gra_started" */ SS7_FUNC_TRACE_EXIT(__FUNCTION__); return FTDM_SUCCESS; @@ -1877,17 +1623,9 @@ ftdm_status_t handle_local_blk(uint32_t suInstId, uint32_t spInstId, uint32_t ci return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - /* check if the circuit is already blocked or not */ if (sngss7_test_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX)) { SS7_WARN("Received local BLO on circuit that is already blocked!\n"); @@ -1921,17 +1659,9 @@ ftdm_status_t handle_local_ubl(uint32_t suInstId, uint32_t spInstId, uint32_t ci return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - /* check if the circuit is already blocked or not */ if (sngss7_test_flag(sngss7_info, FLAG_CKT_LC_UNBLK_RX)) { SS7_WARN("Received local UBL on circuit that is already unblocked!\n"); @@ -1965,17 +1695,9 @@ ftdm_status_t handle_ucic(uint32_t suInstId, uint32_t spInstId, uint32_t circuit return FTDM_FAIL; } - /* now that we have the right channel...put a lock on it so no-one else can use it */ + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* check if there is a pending state change, give it a bit to clear */ - if (check_for_state_change(ftdmchan)) { - SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); - SS7_ASSERT; - }; - /* throw the ckt block flag */ sngss7_set_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK); @@ -1989,6 +1711,277 @@ ftdm_status_t handle_ucic(uint32_t suInstId, uint32_t spInstId, uint32_t circuit return FTDM_SUCCESS; } +/******************************************************************************/ +ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + sngss7_span_data_t *sngss7_span = NULL; + ftdm_channel_t *ftdmchan = NULL; + int range; + uint8_t status[255]; + int blockType = 0; + int byte = 0; + int bit = 0; + int x; + ftdm_sigmsg_t sigev; + + memset(&sigev, 0, sizeof (sigev)); + memset(&status[0], '\0', sizeof(status)); + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* grab the span info */ + sngss7_span = ftdmchan->span->mod_data; + + /* figure out what type of block needs to be applied */ + if ((siStaEvnt->cgsmti.eh.pres == PRSNT_NODEF) && (siStaEvnt->cgsmti.typeInd.pres == PRSNT_NODEF)) { + blockType = siStaEvnt->cgsmti.typeInd.val; + } else { + SS7_ERROR("Received CGB with no circuit group supervision value on CIC = %d\n", sngss7_info->circuit->cic); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* pull out the range value */ + if ((siStaEvnt->rangStat.eh.pres == PRSNT_NODEF) && (siStaEvnt->rangStat.range.pres == PRSNT_NODEF)) { + range = siStaEvnt->rangStat.range.val; + } else { + SS7_ERROR("Received CGB with no range value on CIC = %d\n", sngss7_info->circuit->cic); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* pull out the status field */ + if ((siStaEvnt->rangStat.eh.pres == PRSNT_NODEF) && (siStaEvnt->rangStat.status.pres == PRSNT_NODEF)) { + for (x = 0; x < siStaEvnt->rangStat.status.len; x++) { + status[x] = siStaEvnt->rangStat.status.val[x]; + } + } else { + SS7_ERROR("Received CGB with no status value on CIC = %d\n", sngss7_info->circuit->cic); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* save the circuit, range and status */ + sngss7_span->rx_cgb.circuit = circuit; + sngss7_span->rx_cgb.range = range; + sngss7_span->rx_cgb.type = blockType; + for (x = 0; x < siStaEvnt->rangStat.status.len; x++) { + sngss7_span->rx_cgb.status[x] = status[x]; + } + + /* loop over the cics starting from circuit until range+1 */ + for (x = circuit; x < (circuit + range + 1); x++) { + /* confirm this is a voice channel */ + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != VOICE) continue; + + /* grab the circuit in question */ + if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); + break; + } + + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + +#if 0 + SS7_ERROR("KONRAD -> circuit=%d, byte=%d, bit=%d, status[byte]=%d, math=%d\n", + x, + byte, + bit, + status[byte], + (status[byte] & (1 << bit))); +#endif + if (status[byte] & (1 << bit)) { + switch (blockType) { + /**********************************************************************/ + case 0: /* maintenance oriented */ + sngss7_set_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + break; + /**********************************************************************/ + case 1: /* hardware failure oriented */ + sngss7_set_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + break; + /**********************************************************************/ + case 2: /* reserved for national use */ + break; + /**********************************************************************/ + default: + break; + /**********************************************************************/ + } /* switch (blockType) */ + } + + sigev.chan_id = ftdmchan->chan_id; + sigev.span_id = ftdmchan->span_id; + sigev.channel = ftdmchan; + + /* bring the sig status down */ + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.sigstatus = FTDM_SIG_STATE_DOWN; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + + } /* for (x = circuit; x < (circuit + range + 1); x++) */ + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + ft_to_sngss7_cgba(ftdmchan); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + sngss7_span_data_t *sngss7_span = NULL; + ftdm_channel_t *ftdmchan = NULL; + int range; + uint8_t status[255]; + int blockType = 0; + int byte = 0; + int bit = 0; + int x; + ftdm_sigmsg_t sigev; + + memset(&sigev, 0, sizeof (sigev)); + memset(&status[0], '\0', sizeof(status)); + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* grab the span info */ + sngss7_span = ftdmchan->span->mod_data; + + /* figure out what type of block needs to be applied */ + if ((siStaEvnt->cgsmti.eh.pres == PRSNT_NODEF) && (siStaEvnt->cgsmti.typeInd.pres == PRSNT_NODEF)) { + blockType = siStaEvnt->cgsmti.typeInd.val; + } else { + SS7_ERROR("Received CGU with no circuit group supervision value on CIC = %d\n", sngss7_info->circuit->cic); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* pull out the range value */ + if ((siStaEvnt->rangStat.eh.pres == PRSNT_NODEF) && (siStaEvnt->rangStat.range.pres == PRSNT_NODEF)) { + range = siStaEvnt->rangStat.range.val; + } else { + SS7_ERROR("Received CGU with no range value on CIC = %d\n", sngss7_info->circuit->cic); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* pull out the status field */ + if ((siStaEvnt->rangStat.eh.pres == PRSNT_NODEF) && (siStaEvnt->rangStat.status.pres == PRSNT_NODEF)) { + for (x = 0; x < siStaEvnt->rangStat.status.len; x++) { + status[x] = siStaEvnt->rangStat.status.val[x]; + } + } else { + SS7_ERROR("Received CGU with no status value on CIC = %d\n", sngss7_info->circuit->cic); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* save the circuit, range and status */ + sngss7_span->rx_cgu.circuit = circuit; + sngss7_span->rx_cgu.range = range; + sngss7_span->rx_cgu.type = blockType; + for (x = 0; x < siStaEvnt->rangStat.status.len; x++) { + sngss7_span->rx_cgu.status[x] = status[x]; + } + + /* loop over the cics starting from circuit until range+1 */ + for (x = circuit; x < (circuit + range + 1); x++) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type != VOICE) continue; + /* grab the circuit in question */ + if (extract_chan_data(x, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", x); + break; + } + + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + + if (status[byte] & (1 << bit)) { + switch (blockType) { + /**********************************************************************/ + case 0: /* maintenance oriented */ + sngss7_clear_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX); + break; + /**********************************************************************/ + case 1: /* hardware failure oriented */ + sngss7_clear_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX); + break; + /**********************************************************************/ + case 2: /* reserved for national use */ + break; + /**********************************************************************/ + default: + break; + /**********************************************************************/ + } /* switch (blockType) */ + } /* if (status[byte] & (1 << bit)) */ + + sigev.chan_id = ftdmchan->chan_id; + sigev.span_id = ftdmchan->span_id; + sigev.channel = ftdmchan; + + /* bring the sig status down */ + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.sigstatus = FTDM_SIG_STATE_UP; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + + } /* for (x = circuit; x < (circuit + range + 1); x++) */ + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + ft_to_sngss7_cgua(ftdmchan); + + return FTDM_SUCCESS; +} /******************************************************************************/ /* For Emacs: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c index b666f726a1..3f507d6648 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c @@ -109,6 +109,10 @@ void handle_sng_mtp1_alarm(Pst *pst, L1Mngmt *sta) /******************************************************************************/ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) { + char buf[50]; + int x = 1; + + memset(buf, '\0', sizeof(buf)); switch (sta->t.usta.alarm.category) { /**************************************************************************/ @@ -126,23 +130,39 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) case (LSD_EVENT_REMOTE_CONG_END): case (LSD_EVENT_RX_REMOTE_SIPO): + /* find the name for the sap in question */ + x = 1; + while (g_ftdm_sngss7_data.cfg.mtpLink[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == sta->t.usta.evntParm[0]) { + break; + } + x++; + } + + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == 0) { + sprintf(buf, "[SAPID:%d]", sta->t.usta.evntParm[0]); + } else { + sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtpLink[x].name); + } + + switch (sta->t.usta.alarm.cause) { /******************************************************************/ case (LCM_CAUSE_UNKNOWN): - ftdm_log(FTDM_LOG_ERROR,"[MTP2][SAPID:%d] %s\n", - sta->t.usta.evntParm[0], + ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s\n", + buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event)); break; /******************************************************************/ case (LCM_CAUSE_MGMT_INITIATED): - ftdm_log(FTDM_LOG_ERROR,"[MTP2][SAPID:%d][MGMT] %s\n", - sta->t.usta.evntParm[0], + ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s[MGMT] %s\n", + buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event)); break; /******************************************************************/ default: - ftdm_log(FTDM_LOG_ERROR,"[MTP2][SAPID:%d] %s (***unknown cause***)\n", - sta->t.usta.evntParm[0], + ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s (***unknown cause***)\n", + buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event)); break; /******************************************************************/ @@ -150,23 +170,71 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) break; /**********************************************************************/ case (LSD_EVENT_PROT_ERR): - ftdm_log(FTDM_LOG_ERROR,"[MTP2][SAPID:%d] %s : %s\n", - sta->t.usta.evntParm[0], + + /* find the name for the sap in question */ + x = 1; + while (g_ftdm_sngss7_data.cfg.mtpLink[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == sta->t.usta.evntParm[0]) { + break; + } + x++; + } + + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == 0) { + sprintf(buf, "[SAPID:%d]", sta->t.usta.evntParm[0]); + } else { + sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtpLink[x].name); + } + + ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : %s\n", + buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_LSD_CAUSE(sta->t.usta.alarm.cause)); break; /**********************************************************************/ case (LSD_EVENT_ALIGN_LOST): - ftdm_log(FTDM_LOG_ERROR,"[MTP2][SAPID:%d] %s : %s\n", - sta->t.usta.evntParm[0], + + /* find the name for the sap in question */ + x = 1; + while (g_ftdm_sngss7_data.cfg.mtpLink[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == sta->t.usta.evntParm[0]) { + break; + } + x++; + } + + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == 0) { + sprintf(buf, "[SAPID:%d]", sta->t.usta.evntParm[0]); + } else { + sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtpLink[x].name); + } + + ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : %s\n", + buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_DISC_REASON(sta->t.usta.evntParm[1])); break; /**********************************************************************/ case (LSD_EVENT_RTB_FULL): case (LSD_EVENT_RTB_FULL_OVER): - ftdm_log(FTDM_LOG_ERROR,"[MTP2][SAPID:%d] %s : RTB Queue Len(%d)|Oldest BSN(%d)|Tx Queue Len(%d)|Outstanding Frames(%d)\n", - sta->t.usta.evntParm[0], + + /* find the name for the sap in question */ + x = 1; + while (g_ftdm_sngss7_data.cfg.mtpLink[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == sta->t.usta.evntParm[0]) { + break; + } + x++; + } + + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == 0) { + sprintf(buf, "[SAPID:%d]", sta->t.usta.evntParm[0]); + } else { + sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtpLink[x].name); + } + + ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : RTB Queue Len(%d)|Oldest BSN(%d)|Tx Queue Len(%d)|Outstanding Frames(%d)\n", + buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), sta->t.usta.evntParm[1], sta->t.usta.evntParm[2], @@ -175,15 +243,47 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) break; /**********************************************************************/ case (LSD_EVENT_NEG_ACK): - ftdm_log(FTDM_LOG_ERROR,"[MTP2][SAPID:%d] %s : RTB Queue Len(%d)\n", - sta->t.usta.evntParm[0], + + /* find the name for the sap in question */ + x = 1; + while (g_ftdm_sngss7_data.cfg.mtpLink[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == sta->t.usta.evntParm[0]) { + break; + } + x++; + } + + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == 0) { + sprintf(buf, "[SAPID:%d]", sta->t.usta.evntParm[0]); + } else { + sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtpLink[x].name); + } + + ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : RTB Queue Len(%d)\n", + buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), sta->t.usta.evntParm[1]); break; /**********************************************************************/ case (LSD_EVENT_DAT_CFM_SDT): - ftdm_log(FTDM_LOG_ERROR,"[MTP2][SAPID:%d] %s : %d\n", - sta->t.usta.evntParm[0], + + /* find the name for the sap in question */ + x = 1; + while (g_ftdm_sngss7_data.cfg.mtpLink[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == sta->t.usta.evntParm[0]) { + break; + } + x++; + } + + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == 0) { + sprintf(buf, "[SAPID:%d]", sta->t.usta.evntParm[0]); + } else { + sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtpLink[x].name); + } + + ftdm_log(FTDM_LOG_ERROR,"[MTP2]%s %s : %d\n", + buf, DECODE_LSD_EVENT(sta->t.usta.alarm.event), DECODE_DISC_REASON(sta->t.usta.evntParm[1])); break; @@ -251,15 +351,35 @@ void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta) /******************************************************************************/ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) { + char buf[50]; + int x = 1; + + memset(buf, '\0', sizeof(buf)); switch (sta->hdr.elmId.elmnt) { /**************************************************************************/ case (STDLSAP): + + /* find the name for the sap in question */ + x = 1; + while (g_ftdm_sngss7_data.cfg.mtpLink[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == sta->hdr.elmId.elmntInst1) { + break; + } + x++; + } + + if (g_ftdm_sngss7_data.cfg.mtpLink[x].id == 0) { + sprintf(buf, "[SAPID:%d]", sta->hdr.elmId.elmntInst1); + } else { + sprintf(buf, "[%s]", g_ftdm_sngss7_data.cfg.mtpLink[x].name); + } + switch (sta->t.usta.alarm.event) { /**********************************************************************/ case (LSN_EVENT_INV_OPC_OTHER_END): - ftdm_log(FTDM_LOG_ERROR,"[MTP3][SAPID:%d] %s : %s : OPC(0x%X%X%X%X)\n", - sta->hdr.elmId.elmntInst1, + ftdm_log(FTDM_LOG_ERROR,"[MTP3]%s %s : %s : OPC(0x%X%X%X%X)\n", + buf, DECODE_LSN_EVENT(sta->t.usta.alarm.event), DECODE_LSN_CAUSE(sta->t.usta.alarm.cause), sta->t.usta.evntParm[3], @@ -269,16 +389,16 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) break; /**********************************************************************/ case (LSN_EVENT_INV_SLC_OTHER_END): - ftdm_log(FTDM_LOG_ERROR,"[MTP3][SAPID:%d] %s : %s : SLC(%d)\n", - sta->hdr.elmId.elmntInst1, + ftdm_log(FTDM_LOG_ERROR,"[MTP3]%s %s : %s : SLC(%d)\n", + buf, DECODE_LSN_EVENT(sta->t.usta.alarm.event), DECODE_LSN_CAUSE(sta->t.usta.alarm.cause), sta->t.usta.evntParm[0]); break; /**********************************************************************/ default: - ftdm_log(FTDM_LOG_ERROR,"[MTP3][SAPID:%d] %s(%d) : %s(%d)\n", - sta->hdr.elmId.elmntInst1, + ftdm_log(FTDM_LOG_ERROR,"[MTP3]%s %s(%d) : %s(%d)\n", + buf, DECODE_LSN_EVENT(sta->t.usta.alarm.event), sta->t.usta.alarm.event, DECODE_LSN_CAUSE(sta->t.usta.alarm.cause), @@ -303,13 +423,53 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta) break; /**************************************************************************/ case (STROUT): - ftdm_log(FTDM_LOG_ERROR,"[MTP3][DPC:0x%d%d%d%d] %s : %s\n", - sta->t.usta.evntParm[0], - sta->t.usta.evntParm[1], - sta->t.usta.evntParm[2], - sta->t.usta.evntParm[3], - DECODE_LSN_EVENT(sta->t.usta.alarm.event), - DECODE_LSN_CAUSE(sta->t.usta.alarm.cause)); + switch (sta->t.usta.alarm.event) { + /**********************************************************************/ + case (LSN_EVENT_RX_TRANSFER_MSG): + switch (sta->t.usta.evntParm[5]) { + /******************************************************************/ + case (0x23): + ftdm_log(FTDM_LOG_INFO,"[MTP3] Rx SNM TFC\n"); + break; + /******************************************************************/ + case (0x34): + ftdm_log(FTDM_LOG_INFO,"[MTP3] Rx SNM TFR\n"); + break; + /******************************************************************/ + case (0x54): + ftdm_log(FTDM_LOG_INFO,"[MTP3] Rx SNM TFA\n"); + break; + /******************************************************************/ + case (0x14): + ftdm_log(FTDM_LOG_INFO,"[MTP3] Rx SNM TFP\n"); + break; + /******************************************************************/ + case (0x24): + ftdm_log(FTDM_LOG_INFO,"[MTP3] Rx SNM TFP (cluster)\n"); + break; + /******************************************************************/ + case (0x64): + ftdm_log(FTDM_LOG_INFO,"[MTP3] Rx SNM TFA (cluster)\n"); + break; + /******************************************************************/ + case (0x44): + ftdm_log(FTDM_LOG_INFO,"[MTP3] Rx SNM TFR (cluster)\n"); + break; + /******************************************************************/ + } /* switch (sta->t.usta.evntParm[5]) */ + break; + /**********************************************************************/ + default: + ftdm_log(FTDM_LOG_ERROR,"[MTP3][DPC:0x%d%d%d%d] %s : %s\n", + sta->t.usta.evntParm[0], + sta->t.usta.evntParm[1], + sta->t.usta.evntParm[2], + sta->t.usta.evntParm[3], + DECODE_LSN_EVENT(sta->t.usta.alarm.event), + DECODE_LSN_CAUSE(sta->t.usta.alarm.cause)); + break; + /**********************************************************************/ + } /* switch (sta->t.usta.alarm.event) */ break; /**************************************************************************/ default: @@ -336,6 +496,12 @@ void handle_sng_isup_alarm(Pst *pst, SiMngmt *sta) /* initalize the msg variable to NULLs */ memset(&msg[0], '\0', sizeof(&msg)); + /* if the event is REMOTE/LOCAL we don't need to print these */ + if ((sta->t.usta.alarm.event == LSI_EVENT_REMOTE) || + (sta->t.usta.alarm.event == LSI_EVENT_LOCAL)) { + return; + } + /* point p to the first spot in msg */ p = &msg[0]; @@ -568,6 +734,8 @@ void handle_sng_isup_alarm(Pst *pst, SiMngmt *sta) DECODE_LSI_EVENT(sta->t.usta.alarm.event), DECODE_LSI_CAUSE(sta->t.usta.alarm.cause)); + return; + } /* handle_isup_alarm */ /******************************************************************************/ 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 66efe1ab12..fc14d04c80 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,7 @@ ftdm_sngss7_data_t g_ftdm_sngss7_data; /* PROTOTYPES *****************************************************************/ static void *ftdm_sangoma_ss7_run (ftdm_thread_t * me, void *obj); -static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan); +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); @@ -272,10 +272,8 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) ftdm_interrupt_t *ftdm_sangoma_ss7_int[2]; ftdm_span_t *ftdmspan = (ftdm_span_t *) obj; ftdm_channel_t *ftdmchan = NULL; - sngss7_chan_data_t *sngss7_info = NULL; sngss7_event_data_t *sngss7_event = NULL; sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->mod_data; - int i; ftdm_log (FTDM_LOG_INFO, "ftmod_sangoma_ss7 monitor thread for span=%u started.\n", ftdmspan->span_id); @@ -344,73 +342,22 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj) /**********************************************************************/ } /* switch ((ftdm_interrupt_wait(ftdm_sangoma_ss7_int, 100))) */ - /* extract the span data structure */ - sngss7_span = (sngss7_span_data_t *)ftdmspan->mod_data; + /* check if there is a GRA to proccess on the span */ + if (sngss7_span->rx_gra.range > 0) { + check_if_rx_gra_started(ftdmspan); + } /* if (sngss7->span->rx_gra.range > 0) */ /* check if there is a GRS being processed on the span */ if (sngss7_span->rx_grs.range > 0) { - ftdm_log(FTDM_LOG_DEBUG, "Found Rx GRS on span %d...checking circuits\n", ftdmspan->span_id); - /*SS7_DEBUG("Found Rx GRS on span %d...checking circuits\n", ftdmspan->span_id);*/ + /* check if the rx_grs has started */ + check_if_rx_grs_started(ftdmspan); - /* check all the circuits in the range to see if they are done resetting */ - for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { + /* check if the rx_grs has cleared */ + check_if_rx_grs_processed(ftdmspan); + } /* if (sngss7_span->rx_grs.range > 0) */ - /* extract the channel in question */ - if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i); - SS7_ASSERT; - } - - /* lock the channel */ - ftdm_mutex_lock(ftdmchan->mutex); - - /* check if there is a state change pending on the channel */ - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { - /* check the state to the GRP_RESET_RX_DN flag */ - if (!sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_RX_DN)) { - /* this channel is still resetting...do nothing */ - goto GRS_UNLOCK_ALL; - } /* if (!sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_RX_DN)) */ - } else { - /* state change pending */ - goto GRS_UNLOCK_ALL; - } - } /* for ( i = circuit; i < (circuit + range + 1); i++) */ - - SS7_DEBUG("All circuits out of reset for GRS: circuit=%d, range=%d\n", - sngss7_span->rx_grs.circuit, - sngss7_span->rx_grs.range); - - /* check all the circuits in the range to see if they are done resetting */ - for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { - - /* extract the channel in question */ - if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n",i); - SS7_ASSERT; - } - - /* throw the GRP reset flag complete flag */ - sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_RX_CMPLT); - - /* move the channel to the down state */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - - } /* for ( i = circuit; i < (circuit + range + 1); i++) */ - -GRS_UNLOCK_ALL: - for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { - /* extract the channel in question */ - if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { - SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i); - SS7_ASSERT; - } - - /* unlock the channel */ - ftdm_mutex_unlock(ftdmchan->mutex); - } - - } /* if (ftdmspan->grs.range > 0) */ + /* check each channel on the span to see if there is an un-procressed SUS/RES flag */ + check_for_res_sus_flag(ftdmspan); } /* master while loop */ /* clear the IN_THREAD flag so that we know the thread is done */ @@ -513,11 +460,11 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev } /******************************************************************************/ -static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) +void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) { - ftdm_sigmsg_t sigev; sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; int i = 0; + ftdm_sigmsg_t sigev; memset (&sigev, 0, sizeof (sigev)); @@ -544,10 +491,13 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) i++; } - /* check if the end of pulsing character has arrived or the right number of digits */ - if (ftdmchan->caller_data.dnis.digits[i] == 0xF) { + /* check if the end of pulsing (ST) character has arrived or the right number of digits */ + if (ftdmchan->caller_data.dnis.digits[i-1] == 'F') { SS7_DEBUG_CHAN(ftdmchan, "Received the end of pulsing character %s\n", ""); + /* remove the ST */ + ftdmchan->caller_data.dnis.digits[i-1] = '\0'; + /*now go to the RING state */ ftdm_set_state_locked (ftdmchan, FTDM_CHANNEL_STATE_RING); @@ -569,7 +519,7 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) sngss7_info->t35.beat, sngss7_info->t35.callback, &sngss7_info->t35, - &sngss7_info->t35.heartbeat_timer)) { + &sngss7_info->t35.hb_timer_id)) { SS7_ERROR ("Unable to schedule timer, hanging up call!\n"); @@ -594,8 +544,8 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } /* kill t35 if active */ - if (sngss7_info->t35.heartbeat_timer) { - ftdm_sched_cancel_timer (sngss7_info->t35.sched,&sngss7_info->t35.heartbeat_timer); + if (sngss7_info->t35.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t35.sched, sngss7_info->t35.hb_timer_id); } SS7_DEBUG_CHAN(ftdmchan, "Sending incoming call from %s to %s to FTDM core\n", @@ -785,14 +735,19 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /**************************************************************************/ case FTDM_CHANNEL_STATE_DOWN: /*the call is finished and removed */ + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { + SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); + break; + } + /* check if there is a reset response that needs to be sent */ if (sngss7_test_flag (sngss7_info, FLAG_RESET_RX)) { /* send a RSC-RLC */ ft_to_sngss7_rsca (ftdmchan); /* clear the reset flag */ - sngss7_clear_flag (sngss7_info, FLAG_RESET_RX); - } + clear_rx_rsc_flags(sngss7_info); + } /* if (sngss7_test_flag (sngss7_info, FLAG_RESET_RX)) */ /* check if there was a GRS that needs a GRA */ if ((sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_RX)) && @@ -814,27 +769,24 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } /* clear the grp reset flag */ - sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_RX); - sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_RX_DN); - sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_RX_CMPLT); - + clear_rx_grs_flags(sngss7_info); }/* if ( sngss7_test_flag ( sngss7_info, FLAG_GRP_RESET_RX ) ) */ /* check if we got the reset response */ if (sngss7_test_flag(sngss7_info, FLAG_RESET_TX_RSP)) { /* clear the reset flag */ - sngss7_clear_flag(sngss7_info, FLAG_RESET_TX_RSP); - sngss7_clear_flag(sngss7_info, FLAG_RESET_SENT); - sngss7_clear_flag(sngss7_info, FLAG_RESET_TX); - } + clear_tx_rsc_flags(sngss7_info); + } /* if (sngss7_test_flag(sngss7_info, FLAG_RESET_TX_RSP)) */ if (sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP)) { /* clear the reset flag */ - sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP); - sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_TX); - sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_BASE); - sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_SENT); - } + clear_tx_grs_flags(sngss7_info); + + /* clean out the spans GRA structure */ + sngss7_span_data_t *span = ftdmchan->span->mod_data; + span->rx_gra.circuit = 0; + span->rx_gra.range = 0; + } /* if (sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP)) */ /* check if we came from reset (aka we just processed a reset) */ if ((ftdmchan->last_state == FTDM_CHANNEL_STATE_RESTART) || @@ -846,16 +798,25 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) !(sngss7_test_flag (sngss7_info, FLAG_GRP_RESET_TX)) && !(sngss7_test_flag (sngss7_info, FLAG_GRP_RESET_RX))) { - /* check if the sig status is down, and bring it up if it isn't */ - if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) { - SS7_DEBUG_CHAN(ftdmchan,"All reset flags cleared %s\n", ""); - /* all flags are down so we can bring up the sig status */ - sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_UP; - ftdm_span_send_signal (ftdmchan->span, &sigev); - } + /* now check if there is an active block */ + if (!(sngss7_test_flag(sngss7_info, FLAG_CKT_LC_BLOCK_RX)) && + !(sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX)) && + !(sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX)) && + !(sngss7_test_flag(sngss7_info, FLAG_GRP_HW_BLOCK_RX)) && + !(sngss7_test_flag(sngss7_info, FLAG_GRP_HW_BLOCK_TX)) && + !(sngss7_test_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX)) && + !(sngss7_test_flag(sngss7_info, FLAG_GRP_MN_BLOCK_TX))) { + + /* check if the sig status is down, and bring it up if it isn't */ + if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) { + SS7_DEBUG_CHAN(ftdmchan,"All reset flags cleared %s\n", ""); + /* all flags are down so we can bring up the sig status */ + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.sigstatus = FTDM_SIG_STATE_UP; + ftdm_span_send_signal (ftdmchan->span, &sigev); + } /* if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) */ + } /* if !blocked */ } else { - SS7_DEBUG_CHAN(ftdmchan,"Reset flags present (0x%X)\n", sngss7_info->flags); /* there is still another reset pending so go back to reset*/ @@ -864,8 +825,8 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } /* if ((ftdmchan->last_state == FTDM_CHANNEL_STATE_RESTART) */ /* check if t35 is active */ - if (sngss7_info->t35.heartbeat_timer) { - ftdm_sched_cancel_timer (sngss7_info->t35.sched, &sngss7_info->t35.heartbeat_timer); + if (sngss7_info->t35.hb_timer_id) { + ftdm_sched_cancel_timer (sngss7_info->t35.sched, sngss7_info->t35.hb_timer_id); } /* clear all of the call specific data store in the channel structure */ @@ -1012,34 +973,52 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"Current flags: 0x%X\n", sngss7_info->flags); /**********************************************************************/ - if (sngss7_test_flag (sngss7_info, FLAG_INFID_PAUSED)) { - SS7_DEBUG_CHAN(ftdmchan, "Processing PAUSE flag %s\n", ""); - - /* bring the channel signaling status to down */ - sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_DOWN; - ftdm_span_send_signal (ftdmchan->span, &sigev); + if (sngss7_test_flag(sngss7_info, FLAG_INFID_RESUME)) { + SS7_DEBUG_CHAN(ftdmchan, "Processing RESUME%s\n", ""); - /* check the last state and return to it to allow the call to finish */ - goto suspend_goto_last; - } - - if (sngss7_test_flag (sngss7_info, FLAG_INFID_RESUME)) { - SS7_DEBUG_CHAN(ftdmchan, "Processing RESUME flag %s\n", ""); - - /* the reset flag is set for the first channel in the span at handle_resume */ - - /* clear the resume flag */ + /* clear the RESUME flag */ sngss7_clear_flag(sngss7_info, FLAG_INFID_RESUME); - /* go to restart state */ - goto suspend_goto_last; - } + /* if there are any resets present */ + if ((sngss7_test_flag (sngss7_info, FLAG_RESET_TX)) || + (sngss7_test_flag (sngss7_info, FLAG_RESET_RX)) || + (sngss7_test_flag (sngss7_info, FLAG_GRP_RESET_TX)) || + (sngss7_test_flag (sngss7_info, FLAG_GRP_RESET_RX))) { + /* go back to the reset state */ + goto suspend_goto_restart; + } else { + + /* bring the sig status back up */ + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.sigstatus = FTDM_SIG_STATE_UP; + ftdm_span_send_signal(ftdmchan->span, &sigev); + } + + /* go back to the last state */ + goto suspend_goto_last; + } /* if (sngss7_test_flag(sngss7_info, FLAG_INFID_RESUME)) */ + + if (sngss7_test_flag(sngss7_info, FLAG_INFID_PAUSED)) { + SS7_DEBUG_CHAN(ftdmchan, "Processing PAUSE%s\n", ""); + + /* bring the sig status down */ + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.sigstatus = FTDM_SIG_STATE_DOWN; + ftdm_span_send_signal(ftdmchan->span, &sigev); + + /* go back to the last state */ + goto suspend_goto_last; + } /* if (sngss7_test_flag(sngss7_info, FLAG_INFID_PAUSED)) { */ /**********************************************************************/ if (sngss7_test_flag (sngss7_info, FLAG_CKT_MN_BLOCK_RX)) { SS7_DEBUG_CHAN(ftdmchan, "Processing CKT_MN_BLOCK_RX flag %s\n", ""); + /* bring the sig status down */ + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.sigstatus = FTDM_SIG_STATE_DOWN; + ftdm_span_send_signal(ftdmchan->span, &sigev); + /* send a BLA */ ft_to_sngss7_bla (ftdmchan); @@ -1053,6 +1032,11 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the unblock flag */ sngss7_clear_flag (sngss7_info, FLAG_CKT_MN_UNBLK_RX); + /* bring the sig status up */ + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.sigstatus = FTDM_SIG_STATE_UP; + ftdm_span_send_signal(ftdmchan->span, &sigev); + /* send a uba */ ft_to_sngss7_uba (ftdmchan); @@ -1064,6 +1048,11 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) if (sngss7_test_flag (sngss7_info, FLAG_CKT_MN_BLOCK_TX)) { SS7_DEBUG_CHAN(ftdmchan, "Processing CKT_MN_BLOCK_TX flag %s\n", ""); + /* bring the sig status down */ + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.sigstatus = FTDM_SIG_STATE_DOWN; + ftdm_span_send_signal(ftdmchan->span, &sigev); + /* send a blo */ ft_to_sngss7_blo (ftdmchan); @@ -1077,6 +1066,11 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* clear the unblock flag */ sngss7_clear_flag (sngss7_info, FLAG_CKT_MN_UNBLK_TX); + /* bring the sig status up */ + sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sigev.sigstatus = FTDM_SIG_STATE_UP; + ftdm_span_send_signal(ftdmchan->span, &sigev); + /* send a ubl */ ft_to_sngss7_ubl (ftdmchan); @@ -1117,14 +1111,10 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) ftdm_span_send_signal (ftdmchan->span, &sigev); /* remove any reset flags */ - sngss7_clear_flag (sngss7_info, FLAG_GRP_RESET_TX_RSP); - sngss7_clear_flag (sngss7_info, FLAG_GRP_RESET_TX); - sngss7_clear_flag (sngss7_info, FLAG_RESET_TX_RSP); - sngss7_clear_flag (sngss7_info, FLAG_RESET_TX); - sngss7_clear_flag (sngss7_info, FLAG_RESET_SENT); - sngss7_clear_flag (sngss7_info, FLAG_GRP_RESET_RX); - sngss7_clear_flag (sngss7_info, FLAG_RESET_RX); - sngss7_clear_flag (sngss7_info, FLAG_GRP_RESET_BASE); + clear_rx_grs_flags(sngss7_info); + clear_tx_grs_flags(sngss7_info); + clear_rx_rsc_flags(sngss7_info); + clear_tx_rsc_flags(sngss7_info); /* bring the channel down */ goto suspend_goto_last; @@ -1133,8 +1123,14 @@ static void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) if (sngss7_test_flag (sngss7_info, FLAG_CKT_UCIC_UNBLK)) { SS7_DEBUG_CHAN(ftdmchan, "Processing CKT_UCIC_UNBLK flag %s\n", "");; - /* throw the channel into reset from our side since it is already in reset from the remote side */ - sngss7_set_flag (sngss7_info, FLAG_RESET_TX); + /* remove the UCIC block flag */ + sngss7_clear_flag(sngss7_info, FLAG_CKT_UCIC_BLOCK); + + /* remove the UCIC unblock flag */ + sngss7_clear_flag(sngss7_info, FLAG_CKT_UCIC_UNBLK); + + /* throw the channel into reset to sync states */ + sngss7_set_flag(sngss7_info, FLAG_RESET_TX); /* bring the channel into restart again */ goto suspend_goto_restart; @@ -1182,9 +1178,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_ss7_outgoing_call) /* check if there is a pending state change, give it a bit to clear */ if (check_for_state_change(ftdmchan)) { SS7_ERROR("Failed to wait for pending state change on CIC = %d\n", sngss7_info->circuit->cic); - ftdm_mutex_unlock(ftdmchan->mutex); - SS7_FUNC_TRACE_EXIT(__FUNCTION__); + /* check if we need to die */ SS7_ASSERT; + /* end the request */ + goto outgoing_fail; }; /* check if the channel sig state is UP */ @@ -1295,6 +1292,7 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) ftdm_channel_t *ftdmchan = NULL; sngss7_chan_data_t *sngss7_info = NULL; sngss7_span_data_t *sngss7_span = NULL; + sng_isup_inf_t *sngss7_intf = NULL; int x; @@ -1304,15 +1302,26 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) for (x = 1; x < (span->chan_count + 1); x++) { /* extract the channel structure and sngss7 channel data */ ftdmchan = span->channels[x]; + if (ftdmchan->call_data == NULL) continue; sngss7_info = ftdmchan->call_data; sngss7_span = ftdmchan->span->mod_data; + sngss7_intf = &g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId]; + /* lock the channel */ ftdm_mutex_lock(ftdmchan->mutex); - /* throw the pause flag */ - sngss7_set_flag(sngss7_info, FLAG_INFID_PAUSED); - + /* check if the interface is paused or resumed */ + if (sngss7_test_flag(sngss7_intf, SNGSS7_PAUSED)) { + /* throw the pause flag */ + sngss7_clear_flag(sngss7_info, FLAG_INFID_RESUME); + sngss7_set_flag(sngss7_info, FLAG_INFID_PAUSED); + } else { + /* throw the pause flag */ + sngss7_clear_flag(sngss7_info, FLAG_INFID_PAUSED); + sngss7_set_flag(sngss7_info, FLAG_INFID_RESUME); + } +#if 0 /* throw the grp reset flag */ sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_TX); if (x == 1) { @@ -1320,7 +1329,10 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) sngss7_span->tx_grs.circuit = sngss7_info->circuit->id; sngss7_span->tx_grs.range = span->chan_count -1; } - +#else + /* throw the channel into reset */ + sngss7_set_flag(sngss7_info, FLAG_RESET_TX); +#endif /* throw the channel to suspend */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); @@ -1446,6 +1458,9 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config) static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_ss7_init) { /*this function is called by the FT-core to load the signaling module */ + uint32_t major = 0; + uint32_t minor = 0; + uint32_t build = 0; ftdm_log (FTDM_LOG_INFO, "Loading ftmod_sangoma_ss7...\n"); @@ -1454,6 +1469,8 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_ss7_init) sngss7_id = 0; + cmbLinkSetId = 1; + /* initalize the global gen_config flag */ g_ftdm_sngss7_data.gen_config = 0; @@ -1493,6 +1510,10 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_ss7_init) /* initalize sng_ss7 library */ sng_isup_init (&sng_event); + /* print the version of the library being used */ + sng_isup_version(&major, &minor, &build); + SS7_INFO("Loaded LibSng-SS7 %d.%d.%d\n", major, minor, build); + /* crash on assert fail */ ftdm_global_set_crash_policy (FTDM_CRASH_ON_ASSERT); 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 050f59e00e..d44815df0f 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 @@ -79,7 +79,8 @@ typedef enum { typedef enum { CONFIGURED = (1 << 0), - ACTIVE = (1 << 1) + ACTIVE = (1 << 1), + SNGSS7_PAUSED = (1 << 7) } sng_flag_t; typedef struct sng_mtp_link { @@ -139,7 +140,6 @@ typedef struct sng_mtp_link { uint32_t t23; uint32_t t24; uint32_t t25; - uint32_t t26; uint32_t t27; uint32_t t28; uint32_t t29; @@ -163,6 +163,8 @@ typedef struct sng_link_set { uint32_t flags; uint32_t apc; uint32_t linkType; + uint32_t switchType; + uint32_t ssf; uint32_t minActive; uint32_t numLinks; uint32_t links[16]; @@ -174,9 +176,11 @@ typedef struct sng_route { uint32_t flags; uint32_t dpc; uint32_t cmbLinkSetId; + uint32_t linkSetId; uint32_t linkType; uint32_t switchType; uint32_t ssf; + uint32_t nwId; uint32_t isSTP; uint32_t t6; uint32_t t8; @@ -188,6 +192,7 @@ typedef struct sng_route { uint32_t t19; uint32_t t21; uint32_t t25; + uint32_t t26; } sng_route_t; typedef struct sng_isup_intf { @@ -312,7 +317,7 @@ typedef struct ftdm_sngss7_data { }ftdm_sngss7_data_t; typedef struct sngss7_timer_data { - ftdm_timer_t *heartbeat_timer; + ftdm_timer_id_t hb_timer_id; int beat; int counter; ftdm_sched_callback_t callback; @@ -329,6 +334,9 @@ typedef struct sngss7_glare_data { typedef struct sngss7_group_data { uint32_t circuit; uint32_t range; + uint8_t status[255]; + uint8_t type; + uint8_t cause; }sngss7_group_data_t; typedef struct sngss7_chan_data { @@ -347,7 +355,12 @@ typedef struct sngss7_chan_data { typedef struct sngss7_span_data { ftdm_sched_t *sched; sngss7_group_data_t rx_grs; + sngss7_group_data_t rx_gra; sngss7_group_data_t tx_grs; + sngss7_group_data_t rx_cgb; + sngss7_group_data_t tx_cgb; + sngss7_group_data_t rx_cgu; + sngss7_group_data_t tx_cgu; ftdm_queue_t *event_queue; }sngss7_span_data_t; @@ -376,8 +389,8 @@ typedef struct sngss7_event_data typedef enum { - FLAG_RESET_RX = (1 << 0), - FLAG_RESET_TX = (1 << 1), + FLAG_RESET_RX = (1 << 0), + FLAG_RESET_TX = (1 << 1), FLAG_RESET_SENT = (1 << 2), FLAG_RESET_TX_RSP = (1 << 3), FLAG_GRP_RESET_RX = (1 << 4), @@ -387,27 +400,25 @@ typedef enum { FLAG_GRP_RESET_TX = (1 << 8), FLAG_GRP_RESET_SENT = (1 << 9), FLAG_GRP_RESET_TX_RSP = (1 << 10), - FLAG_REMOTE_REL = (1 << 11), - FLAG_LOCAL_REL = (1 << 12), - FLAG_GLARE = (1 << 13), - FLAG_INFID_RESUME = (1 << 14), - FLAG_INFID_PAUSED = (1 << 15), + FLAG_REMOTE_REL = (1 << 11), + FLAG_LOCAL_REL = (1 << 12), + FLAG_GLARE = (1 << 13), + FLAG_INFID_RESUME = (1 << 14), + FLAG_INFID_PAUSED = (1 << 15), FLAG_CKT_UCIC_BLOCK = (1 << 16), FLAG_CKT_UCIC_UNBLK = (1 << 17), FLAG_CKT_LC_BLOCK_RX = (1 << 18), FLAG_CKT_LC_UNBLK_RX = (1 << 19), FLAG_CKT_MN_BLOCK_RX = (1 << 20), - FLAG_CKT_MN_BLOCK_TX = (1 << 21), - FLAG_CKT_MN_UNBLK_RX = (1 << 22), + FLAG_CKT_MN_UNBLK_RX = (1 << 21), + FLAG_CKT_MN_BLOCK_TX = (1 << 22), FLAG_CKT_MN_UNBLK_TX = (1 << 23), FLAG_GRP_HW_BLOCK_RX = (1 << 24), FLAG_GRP_HW_BLOCK_TX = (1 << 25), FLAG_GRP_MN_BLOCK_RX = (1 << 26), FLAG_GRP_MN_BLOCK_TX = (1 << 27), - FLAG_GRP_HW_UNBLK_RX = (1 << 28), - FLAG_GRP_HW_UNBLK_TX = (1 << 29), - FLAG_GRP_MN_UNBLK_RX = (1 << 30), - FLAG_GRP_MN_UNBLK_TX = (1 << 31) + FLAG_GRP_HW_UNBLK_TX = (1 << 28), + FLAG_GRP_MN_UNBLK_TX = (1 << 29) } flag_t; /******************************************************************************/ @@ -415,9 +426,14 @@ typedef enum { extern ftdm_sngss7_data_t g_ftdm_sngss7_data; extern uint32_t sngss7_id; extern ftdm_sched_t *sngss7_sched; +extern int cmbLinkSetId; /******************************************************************************/ /* PROTOTYPES *****************************************************************/ +/* in ftmod_sangoma_ss7_main.c */ +void 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,...); void handle_sng_mtp1_alarm(Pst *pst, L1Mngmt *sta); void handle_sng_mtp2_alarm(Pst *pst, SdMngmt *sta); @@ -425,6 +441,7 @@ void handle_sng_mtp3_alarm(Pst *pst, SnMngmt *sta); void handle_sng_isup_alarm(Pst *pst, SiMngmt *sta); void handle_sng_cc_alarm(Pst *pst, CcMngmt *sta); +/* in ftmod_sangoma_ss7_cfg.c */ int ft_to_sngss7_cfg_all(void); int ftmod_ss7_mtp1_gen_config(void); int ftmod_ss7_mtp2_gen_config(void); @@ -443,14 +460,26 @@ int ftmod_ss7_isup_ckt_config(int id); int ftmod_ss7_isup_isap_config(int id); int ftmod_ss7_cc_isap_config(int id); +/* in ftmod_sangoma_ss7_cntrl.c */ +int ft_to_sngss7_activate_all(void); + int ftmod_ss7_inhibit_mtplink(uint32_t id); int ftmod_ss7_uninhibit_mtplink(uint32_t id); +int ftmod_ss7_activate_mtplink(uint32_t id); +int ftmod_ss7_deactivate_mtplink(uint32_t id); +int ftmod_ss7_deactivate2_mtplink(uint32_t id); +int ftmod_ss7_activate_mtplinkSet(uint32_t id); +int ftmod_ss7_deactivate_mtplinkSet(uint32_t id); +int ftmod_ss7_deactivate2_mtplinkSet(uint32_t id); +int ftmod_ss7_lpo_mtplink(uint32_t id); +int ftmod_ss7_lpr_mtplink(uint32_t id); +/* in ftmod_sangoma_ss7_sta.c */ int ftmod_ss7_mtplink_sta(uint32_t id, SnMngmt *cfm); int ftmod_ss7_mtplinkSet_sta(uint32_t id, SnMngmt *cfm); -int ft_to_sngss7_activate_all(void); +/* in ftmod_sangoma_ss7_out.c */ void ft_to_sngss7_iam(ftdm_channel_t *ftdmchan); void ft_to_sngss7_acm(ftdm_channel_t *ftdmchan); void ft_to_sngss7_anm(ftdm_channel_t *ftdmchan); @@ -465,7 +494,12 @@ void ft_to_sngss7_uba(ftdm_channel_t *ftdmchan); void ft_to_sngss7_lpa(ftdm_channel_t *ftdmchan); void ft_to_sngss7_gra(ftdm_channel_t *ftdmchan); void ft_to_sngss7_grs(ftdm_channel_t *ftdmchan); +void ft_to_sngss7_cgba(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_cgua(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_cgb(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_cgu(ftdm_channel_t * ftdmchan); +/* in ftmod_sangoma_ss7_in.c */ void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); void sngss7_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt); void sngss7_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt); @@ -478,6 +512,7 @@ void sngss7_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); void sngss7_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit); +/* in ftmod_sangoma_ss7_handle.c */ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt); ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiCnStEvnt *siCnStEvnt, uint8_t evntType); ftdm_status_t handle_con_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt); @@ -508,6 +543,13 @@ ftdm_status_t handle_local_blk(uint32_t suInstId, uint32_t spInstId, uint32_t ci ftdm_status_t handle_local_ubl(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); ftdm_status_t handle_ucic(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); +/* in ftmod_sangoma_ss7_xml.c */ +int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span); + +/* in ftmod_sangoma_ss7_cli.c */ +ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const char *data); + +/* in ftmod_sangoma_ss7_support.c */ uint8_t copy_cgPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum); uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum); uint8_t copy_cdPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum); @@ -519,11 +561,19 @@ int check_for_reset(sngss7_chan_data_t *sngss7_info); ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan); unsigned long get_unique_id(void); -int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span); +ftdm_status_t check_if_rx_grs_started(ftdm_span_t *ftdmspan); +ftdm_status_t check_if_rx_grs_processed(ftdm_span_t *ftdmspan); +ftdm_status_t check_if_rx_gra_started(ftdm_span_t *ftdmspan); +ftdm_status_t check_for_res_sus_flag(ftdm_span_t *ftdmspan); +ftdm_status_t clear_rx_grs_flags(sngss7_chan_data_t *sngss7_info); +ftdm_status_t clear_tx_grs_flags(sngss7_chan_data_t *sngss7_info); +ftdm_status_t clear_rx_rsc_flags(sngss7_chan_data_t *sngss7_info); +ftdm_status_t clear_tx_rsc_flags(sngss7_chan_data_t *sngss7_info); + + +/* in ftmod_sangoma_ss7_timers.c */ void handle_isup_t35(void *userdata); - -ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const char *data); /******************************************************************************/ /* MACROS *********************************************************************/ @@ -654,7 +704,14 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha #define sngss7_clear_flag(obj, flag) ((obj)->flags &= ~(flag)) #define sngss7_set_flag(obj, flag) ((obj)->flags |= (flag)) -# define SS7_ASSERT *(int*)0=0; +#ifdef SS7_PRODUCTION +# define SS7_ASSERT \ + SS7_INFO_CHAN(ftdmchan,"Production Mode, continuing%s\n", ""); +#else +# define SS7_ASSERT \ + SS7_ERROR_CHAN(ftdmchan, "Debugging Mode, ending%s\n", ""); \ + *(int*)0=0; +#endif /******************************************************************************/ /******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 4fac251c17..8b3f9d8424 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -42,24 +42,30 @@ /******************************************************************************/ /* PROTOTYPES *****************************************************************/ -void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_anm (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_rlc (ftdm_channel_t * ftdmchan); +void ft_to_sngss7_iam(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_acm(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_anm(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_rel(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_rlc(ftdm_channel_t * ftdmchan); -void ft_to_sngss7_rsc (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_rsca (ftdm_channel_t * ftdmchan); +void ft_to_sngss7_rsc(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_rsca(ftdm_channel_t * ftdmchan); -void ft_to_sngss7_blo (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_bla (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_ubl (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_uba (ftdm_channel_t * ftdmchan); +void ft_to_sngss7_blo(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_bla(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_ubl(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_uba(ftdm_channel_t * ftdmchan); -void ft_to_sngss7_lpa (ftdm_channel_t * ftdmchan); +void ft_to_sngss7_lpa(ftdm_channel_t * ftdmchan); -void ft_to_sngss7_gra (ftdm_channel_t * ftdmchan); -void ft_to_sngss7_grs (ftdm_channel_t * ftdmchan); +void ft_to_sngss7_gra(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_grs(ftdm_channel_t * ftdmchan); + +void ft_to_sngss7_cgb(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_cgu(ftdm_channel_t * ftdmchan); + +void ft_to_sngss7_cgba(ftdm_channel_t * ftdmchan); +void ft_to_sngss7_cgua(ftdm_channel_t * ftdmchan); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -67,8 +73,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) { SS7_FUNC_TRACE_ENTER (__FUNCTION__); - sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;; - SiConEvnt iam; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;; + const char *nadi = NULL; + SiConEvnt iam; sngss7_info->suInstId = get_unique_id (); sngss7_info->spInstId = 0; @@ -98,7 +105,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) iam.fwdCallInd.isdnUsrPrtInd.pres = PRSNT_NODEF; iam.fwdCallInd.isdnUsrPrtInd.val = ISUP_USED; iam.fwdCallInd.isdnUsrPrtPrfInd.pres = PRSNT_NODEF; - iam.fwdCallInd.isdnUsrPrtPrfInd.val = PREF_REQAW; + iam.fwdCallInd.isdnUsrPrtPrfInd.val = PREF_PREFAW; iam.fwdCallInd.isdnAccInd.pres = PRSNT_NODEF; iam.fwdCallInd.isdnAccInd.val = ISDNACC_ISDN; iam.fwdCallInd.sccpMethInd.pres = PRSNT_NODEF; @@ -113,21 +120,89 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) iam.txMedReq.eh.pres = PRSNT_NODEF; iam.txMedReq.trMedReq.pres = PRSNT_NODEF; iam.txMedReq.trMedReq.val = ftdmchan->caller_data.bearer_capability; + + if ((g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].switchType == LSI_SW_ANS88) || + (g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].switchType == LSI_SW_ANS92) || + (g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].switchType == LSI_SW_ANS95)) { + + /* include only if we're running ANSI */ + iam.fwdCallInd.transCallNInd.pres = PRSNT_NODEF; + iam.fwdCallInd.transCallNInd.val = 0x0; + + iam.usrServInfoA.eh.pres = PRSNT_NODEF; + + iam.usrServInfoA.infoTranCap.pres = PRSNT_NODEF; + switch (ftdmchan->caller_data.bearer_capability) { + /**********************************************************************/ + case (FTDM_BEARER_CAP_SPEECH): + iam.usrServInfoA.infoTranCap.val = 0x0; /* speech as per ATIS-1000113.3.2005 */ + break; + /**********************************************************************/ + case (FTDM_BEARER_CAP_64K_UNRESTRICTED): + iam.usrServInfoA.infoTranCap.val = 0x8; /* unrestricted digital as per ATIS-1000113.3.2005 */ + break; + /**********************************************************************/ + case (FTDM_BEARER_CAP_3_1KHZ_AUDIO): + iam.usrServInfoA.infoTranCap.val = 0x10; /* 3.1kHz audio as per ATIS-1000113.3.2005 */ + break; + /**********************************************************************/ + default: + SS7_ERROR_CHAN(ftdmchan, "Unknown Bearer capability falling back to speech%s\n", " "); + iam.usrServInfoA.infoTranCap.val = 0x0; /* speech as per ATIS-1000113.3.2005 */ + break; + /**********************************************************************/ + } /* switch (ftdmchan->caller_data.bearer_capability) */ + + iam.usrServInfoA.cdeStand.pres = PRSNT_NODEF; + iam.usrServInfoA.cdeStand.val = 0x0; /* ITU-T standardized coding */ + iam.usrServInfoA.tranMode.pres = PRSNT_NODEF; + iam.usrServInfoA.tranMode.val = 0x0; /* circuit mode */ + iam.usrServInfoA.infoTranRate0.pres = PRSNT_NODEF; + iam.usrServInfoA.infoTranRate0.val = 0x10; /* 64kbps origination to destination */ + iam.usrServInfoA.infoTranRate1.pres = PRSNT_NODEF; + iam.usrServInfoA.infoTranRate1.val = 0x10; /* 64kbps destination to origination */ + iam.usrServInfoA.chanStruct.pres = PRSNT_NODEF; + iam.usrServInfoA.chanStruct.val = 0x1; /* 8kHz integrity */ + iam.usrServInfoA.config.pres = PRSNT_NODEF; + iam.usrServInfoA.config.val = 0x0; /* point to point configuration */ + iam.usrServInfoA.establish.pres = PRSNT_NODEF; + iam.usrServInfoA.establish.val = 0x0; /* on demand */ + iam.usrServInfoA.symmetry.pres = PRSNT_NODEF; + iam.usrServInfoA.symmetry.val = 0x0; /* bi-directional symmetric */ + iam.usrServInfoA.usrInfLyr1Prot.pres = PRSNT_NODEF; + iam.usrServInfoA.usrInfLyr1Prot.val = 0x2; /* G.711 ulaw */ + iam.usrServInfoA.rateMultiplier.pres = PRSNT_NODEF; + iam.usrServInfoA.rateMultiplier.val = 0x1; /* 1x rate multipler */ + } /* if ANSI */ /* copy down the called number information */ copy_cdPtyNum_to_sngss7 (&ftdmchan->caller_data, &iam.cdPtyNum); /* copy down the calling number information */ - copy_cgPtyNum_to_sngss7 (&ftdmchan->caller_data, &iam.cgPtyNum); + copy_cgPtyNum_to_sngss7 (&ftdmchan->caller_data, &iam.cgPtyNum); + + /* check if the user would like a custom NADI value for the calling Pty Num */ + nadi = ftdm_channel_get_var(ftdmchan, "ss7_nadi"); + if ((nadi != NULL) && (*nadi)) { + SS7_DEBUG_CHAN(ftdmchan,"Found user supplied NADI value \"%s\"\n", nadi); + iam.cgPtyNum.natAddrInd.val = atoi(nadi); + } else { + SS7_DEBUG_CHAN(ftdmchan,"No user supplied NADI value found, using \"3\" %s\n", " "); + iam.cgPtyNum.natAddrInd.val = 0x03; + } + sng_cc_con_request (sngss7_info->spId, sngss7_info->suInstId, sngss7_info->spInstId, sngss7_info->circuit->id, &iam, 0); - - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx IAM\n"); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx IAM clg = \"%s\", cld = \"%s\"\n", + sngss7_info->circuit->cic, + ftdmchan->caller_data.cid_num.digits, + ftdmchan->caller_data.dnis.digits); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -144,29 +219,29 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) memset (&acm, 0x0, sizeof (acm)); /* fill in the needed information for the ACM */ - acm.bckCallInd.eh.pres = PRSNT_NODEF; - acm.bckCallInd.chrgInd.pres = PRSNT_NODEF; - acm.bckCallInd.chrgInd.val = 0x00; - acm.bckCallInd.cadPtyStatInd.pres = PRSNT_NODEF; - acm.bckCallInd.cadPtyStatInd.val = 0x01; - acm.bckCallInd.cadPtyCatInd.pres = PRSNT_NODEF; - acm.bckCallInd.cadPtyCatInd.val = 0x00; - acm.bckCallInd.end2EndMethInd.pres = PRSNT_NODEF; - acm.bckCallInd.end2EndMethInd.val = 0x00; - acm.bckCallInd.intInd.pres = PRSNT_NODEF; - acm.bckCallInd.intInd.val = 0x00; - acm.bckCallInd.end2EndInfoInd.pres = PRSNT_NODEF; - acm.bckCallInd.end2EndInfoInd.val = 0x00; - acm.bckCallInd.isdnUsrPrtInd.pres = PRSNT_NODEF; - acm.bckCallInd.isdnUsrPrtInd.val = 0x0; - acm.bckCallInd.holdInd.pres = PRSNT_NODEF; - acm.bckCallInd.holdInd.val = 0x00; - acm.bckCallInd.isdnAccInd.pres = PRSNT_NODEF; - acm.bckCallInd.isdnAccInd.val = 0x0; - acm.bckCallInd.echoCtrlDevInd.pres = PRSNT_NODEF; - acm.bckCallInd.echoCtrlDevInd.val = 0x0; - acm.bckCallInd.sccpMethInd.pres = PRSNT_NODEF; - acm.bckCallInd.sccpMethInd.val = 0x00; + acm.bckCallInd.eh.pres = PRSNT_NODEF; + acm.bckCallInd.chrgInd.pres = PRSNT_NODEF; + acm.bckCallInd.chrgInd.val = CHRG_CHRG; + acm.bckCallInd.cadPtyStatInd.pres = PRSNT_NODEF; + acm.bckCallInd.cadPtyStatInd.val = 0x01; + acm.bckCallInd.cadPtyCatInd.pres = PRSNT_NODEF; + acm.bckCallInd.cadPtyCatInd.val = CADCAT_ORDSUBS; + acm.bckCallInd.end2EndMethInd.pres = PRSNT_NODEF; + acm.bckCallInd.end2EndMethInd.val = E2EMTH_NOMETH; + acm.bckCallInd.intInd.pres = PRSNT_NODEF; + acm.bckCallInd.intInd.val = INTIND_NOINTW; + acm.bckCallInd.end2EndInfoInd.pres = PRSNT_NODEF; + acm.bckCallInd.end2EndInfoInd.val = E2EINF_NOINFO; + acm.bckCallInd.isdnUsrPrtInd.pres = PRSNT_NODEF; + acm.bckCallInd.isdnUsrPrtInd.val = ISUP_USED; + acm.bckCallInd.holdInd.pres = PRSNT_NODEF; + acm.bckCallInd.holdInd.val = HOLD_NOTREQD; + acm.bckCallInd.isdnAccInd.pres = PRSNT_NODEF; + acm.bckCallInd.isdnAccInd.val = ISDNACC_NONISDN; + acm.bckCallInd.echoCtrlDevInd.pres = PRSNT_NODEF; + acm.bckCallInd.echoCtrlDevInd.val = 0x1; /* ec device present */ + acm.bckCallInd.sccpMethInd.pres = PRSNT_NODEF; + acm.bckCallInd.sccpMethInd.val = SCCPMTH_NOIND; /* send the ACM request to LibSngSS7 */ sng_cc_con_status (1, @@ -176,7 +251,7 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) &acm, ADDRCMPLT); - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx ACM\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx ACM\n", sngss7_info->circuit->cic); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -200,7 +275,7 @@ void ft_to_sngss7_anm (ftdm_channel_t * ftdmchan) &anm, 5); - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx ANM\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx ANM\n", sngss7_info->circuit->cic); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -233,7 +308,9 @@ void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan) sngss7_info->circuit->id, &rel); - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx REL\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx REL cause=%d \n", + sngss7_info->circuit->cic, + ftdmchan->caller_data.hangup_cause ); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -256,7 +333,7 @@ void ft_to_sngss7_rlc (ftdm_channel_t * ftdmchan) sngss7_info->circuit->id, &rlc); - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx RLC\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx RLC\n", sngss7_info->circuit->cic); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -277,7 +354,7 @@ void ft_to_sngss7_rsc (ftdm_channel_t * ftdmchan) SIT_STA_CIRRESREQ, NULL); - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx RSC\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx RSC\n", sngss7_info->circuit->cic); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -298,7 +375,7 @@ void ft_to_sngss7_rsca (ftdm_channel_t * ftdmchan) SIT_STA_CIRRESRSP, NULL); - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx RSC-RLC\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx RSC-RLC\n", sngss7_info->circuit->cic); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -319,7 +396,7 @@ void ft_to_sngss7_blo (ftdm_channel_t * ftdmchan) SIT_STA_CIRBLOREQ, NULL); - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx BLO\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx BLO\n", sngss7_info->circuit->cic); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -340,7 +417,7 @@ void ft_to_sngss7_bla (ftdm_channel_t * ftdmchan) SIT_STA_CIRBLORSP, NULL); - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx BLA\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx BLA\n", sngss7_info->circuit->cic); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -362,7 +439,7 @@ ft_to_sngss7_ubl (ftdm_channel_t * ftdmchan) SIT_STA_CIRUBLREQ, NULL); - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx UBL\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx UBL\n", sngss7_info->circuit->cic); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -383,7 +460,7 @@ void ft_to_sngss7_uba (ftdm_channel_t * ftdmchan) SIT_STA_CIRUBLRSP, NULL); - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx UBA\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx UBA\n", sngss7_info->circuit->cic); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -404,7 +481,7 @@ void ft_to_sngss7_lpa (ftdm_channel_t * ftdmchan) SIT_STA_LOOPBACKACK, NULL); - SS7_MSG_TRACE(ftdmchan, sngss7_info, "Tx LPA\n"); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx LPA\n", sngss7_info->circuit->cic); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; @@ -445,7 +522,8 @@ void ft_to_sngss7_gra (ftdm_channel_t * ftdmchan) SIT_STA_GRSRSP, &gra); - SS7_INFO_CHAN(ftdmchan, "Tx GRA (%d:%d)\n", + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx GRA (%d:%d)\n", + sngss7_info->circuit->cic, sngss7_info->circuit->cic, (sngss7_info->circuit->cic + sngss7_span->rx_grs.range)); @@ -463,7 +541,7 @@ void ft_to_sngss7_grs (ftdm_channel_t * ftdmchan) SiStaEvnt grs; - memset (&grs, 0x0, sizeof (grs)); + memset (&grs, 0x0, sizeof(grs)); grs.rangStat.eh.pres = PRSNT_NODEF; grs.rangStat.range.pres = PRSNT_NODEF; @@ -477,7 +555,8 @@ void ft_to_sngss7_grs (ftdm_channel_t * ftdmchan) SIT_STA_GRSREQ, &grs); - SS7_INFO_CHAN(ftdmchan, "Tx GRS (%d:%d)\n", + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx GRS (%d:%d)\n", + sngss7_info->circuit->cic, sngss7_info->circuit->cic, (sngss7_info->circuit->cic + sngss7_span->tx_grs.range)); @@ -485,6 +564,205 @@ void ft_to_sngss7_grs (ftdm_channel_t * ftdmchan) return; } +/******************************************************************************/ +void ft_to_sngss7_cgba(ftdm_channel_t * ftdmchan) +{ + SS7_FUNC_TRACE_ENTER (__FUNCTION__); + + sngss7_span_data_t *sngss7_span = ftdmchan->span->mod_data; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + int x = 0; + + SiStaEvnt cgba; + + memset (&cgba, 0x0, sizeof(cgba)); + + /* fill in the circuit group supervisory message */ + cgba.cgsmti.eh.pres = PRSNT_NODEF; + cgba.cgsmti.typeInd.pres = PRSNT_NODEF; + cgba.cgsmti.typeInd.val = sngss7_span->rx_cgb.type; + + cgba.rangStat.eh.pres = PRSNT_NODEF; + /* fill in the range */ + cgba.rangStat.range.pres = PRSNT_NODEF; + cgba.rangStat.range.val = sngss7_span->rx_cgb.range; + /* fill in the status */ + cgba.rangStat.status.pres = PRSNT_NODEF; + cgba.rangStat.status.len = ((sngss7_span->rx_cgb.range + 1) >> 3) + (((sngss7_span->rx_cgb.range + 1) & 0x07) ? 1 : 0); + for(x = 0; x < cgba.rangStat.status.len; x++){ + cgba.rangStat.status.val[x] = sngss7_span->rx_cgb.status[x]; + } + + sng_cc_sta_request (1, + 0, + 0, + sngss7_span->rx_cgb.circuit, + 0, + SIT_STA_CGBRSP, + &cgba); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx CGBA (%d:%d)\n", + sngss7_info->circuit->cic, + sngss7_info->circuit->cic, + (sngss7_info->circuit->cic + sngss7_span->rx_cgb.range)); + + /* clean out the saved data */ + memset(&sngss7_span->rx_cgb, 0x0, sizeof(sngss7_group_data_t)); + + SS7_FUNC_TRACE_EXIT (__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_cgua(ftdm_channel_t * ftdmchan) +{ + SS7_FUNC_TRACE_ENTER (__FUNCTION__); + + sngss7_span_data_t *sngss7_span = ftdmchan->span->mod_data; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + int x = 0; + + SiStaEvnt cgua; + + memset (&cgua, 0x0, sizeof(cgua)); + + /* fill in the circuit group supervisory message */ + cgua.cgsmti.eh.pres = PRSNT_NODEF; + cgua.cgsmti.typeInd.pres = PRSNT_NODEF; + cgua.cgsmti.typeInd.val = sngss7_span->rx_cgu.type; + + cgua.rangStat.eh.pres = PRSNT_NODEF; + /* fill in the range */ + cgua.rangStat.range.pres = PRSNT_NODEF; + cgua.rangStat.range.val = sngss7_span->rx_cgu.range; + /* fill in the status */ + cgua.rangStat.status.pres = PRSNT_NODEF; + cgua.rangStat.status.len = ((sngss7_span->rx_cgu.range + 1) >> 3) + (((sngss7_span->rx_cgu.range + 1) & 0x07) ? 1 : 0); + for(x = 0; x < cgua.rangStat.status.len; x++){ + cgua.rangStat.status.val[x] = sngss7_span->rx_cgu.status[x]; + } + + sng_cc_sta_request (1, + 0, + 0, + sngss7_span->rx_cgu.circuit, + 0, + SIT_STA_CGURSP, + &cgua); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx CGUA (%d:%d)\n", + sngss7_info->circuit->cic, + sngss7_info->circuit->cic, + (sngss7_info->circuit->cic + sngss7_span->rx_cgu.range)); + + /* clean out the saved data */ + memset(&sngss7_span->rx_cgu, 0x0, sizeof(sngss7_group_data_t)); + + SS7_FUNC_TRACE_EXIT (__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_cgb(ftdm_channel_t * ftdmchan) +{ + SS7_FUNC_TRACE_ENTER (__FUNCTION__); + + sngss7_span_data_t *sngss7_span = ftdmchan->span->mod_data; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + SiStaEvnt cgb; + int x = 0; + + + memset (&cgb, 0x0, sizeof(cgb)); + + /* fill in the circuit group supervisory message */ + cgb.cgsmti.eh.pres = PRSNT_NODEF; + cgb.cgsmti.typeInd.pres = PRSNT_NODEF; + cgb.cgsmti.typeInd.val = sngss7_span->tx_cgb.type; + + /* fill in the range */ + cgb.rangStat.eh.pres = PRSNT_NODEF; + cgb.rangStat.range.pres = PRSNT_NODEF; + cgb.rangStat.range.val = sngss7_span->tx_cgb.range; + + /* fill in the status */ + cgb.rangStat.status.pres = PRSNT_NODEF; + cgb.rangStat.status.len = ((sngss7_span->tx_cgb.range + 1) >> 3) + (((sngss7_span->tx_cgb.range + 1) & 0x07) ? 1 : 0); + for(x = 0; x < cgb.rangStat.status.len; x++){ + cgb.rangStat.status.val[x] = sngss7_span->tx_cgb.status[x]; + } + + sng_cc_sta_request (1, + 0, + 0, + sngss7_span->tx_cgb.circuit, + 0, + SIT_STA_CGBREQ, + &cgb); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx CGB (%d:%d)\n", + sngss7_info->circuit->cic, + sngss7_info->circuit->cic, + (sngss7_info->circuit->cic + sngss7_span->tx_cgb.range)); + + /* clean out the saved data */ + memset(&sngss7_span->tx_cgb, 0x0, sizeof(sngss7_group_data_t)); + + SS7_FUNC_TRACE_EXIT (__FUNCTION__); + return; +} + +/******************************************************************************/ +void ft_to_sngss7_cgu(ftdm_channel_t * ftdmchan) +{ + SS7_FUNC_TRACE_ENTER (__FUNCTION__); + + sngss7_span_data_t *sngss7_span = ftdmchan->span->mod_data; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + SiStaEvnt cgu; + int x = 0; + + + memset (&cgu, 0x0, sizeof(cgu)); + + /* fill in the circuit group supervisory message */ + cgu.cgsmti.eh.pres = PRSNT_NODEF; + cgu.cgsmti.typeInd.pres = PRSNT_NODEF; + cgu.cgsmti.typeInd.val = sngss7_span->tx_cgu.type; + + /* fill in the range */ + cgu.rangStat.eh.pres = PRSNT_NODEF; + cgu.rangStat.range.pres = PRSNT_NODEF; + cgu.rangStat.range.val = sngss7_span->tx_cgu.range; + + /* fill in the status */ + cgu.rangStat.status.pres = PRSNT_NODEF; + cgu.rangStat.status.len = ((sngss7_span->tx_cgu.range + 1) >> 3) + (((sngss7_span->tx_cgu.range + 1) & 0x07) ? 1 : 0); + for(x = 0; x < cgu.rangStat.status.len; x++){ + cgu.rangStat.status.val[x] = sngss7_span->tx_cgu.status[x]; + } + + sng_cc_sta_request (1, + 0, + 0, + sngss7_span->tx_cgu.circuit, + 0, + SIT_STA_CGUREQ, + &cgu); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx CGU (%d:%d)\n", + sngss7_info->circuit->cic, + sngss7_info->circuit->cic, + (sngss7_info->circuit->cic + sngss7_span->tx_cgu.range)); + + /* clean out the saved data */ + memset(&sngss7_span->tx_cgu, 0x0, sizeof(sngss7_group_data_t)); + + SS7_FUNC_TRACE_EXIT (__FUNCTION__); + return; +} + + /******************************************************************************/ /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sta.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sta.c index 305e1a50f5..d238462046 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sta.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sta.c @@ -68,7 +68,7 @@ int ftmod_ss7_mtplinkSet_sta(uint32_t id, SnMngmt *cfm) sta.hdr.elmId.elmnt = STLNKSET; sta.hdr.elmId.elmntInst1 = g_ftdm_sngss7_data.cfg.mtpLinkSet[id].id; - sta.hdr.elmId.elmntInst2 = 1; + sta.hdr.elmId.elmntInst2 = g_ftdm_sngss7_data.cfg.mtpLinkSet[id].links[0]; return(sng_sta_mtp3(&sta, cfm)); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 97957f3c82..dfa174e85a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -57,6 +57,15 @@ unsigned long get_unique_id(void); ftdm_status_t extract_chan_data(uint32_t circuit, sngss7_chan_data_t **sngss7_info, ftdm_channel_t **ftdmchan); +ftdm_status_t check_if_rx_grs_started(ftdm_span_t *ftdmspan); +ftdm_status_t check_if_rx_grs_processed(ftdm_span_t *ftdmspan); +ftdm_status_t check_if_rx_gra_started(ftdm_span_t *ftdmspan); +ftdm_status_t check_for_res_sus_flag(ftdm_span_t *ftdmspan); + +ftdm_status_t clear_rx_grs_flags(sngss7_chan_data_t *sngss7_info); +ftdm_status_t clear_tx_grs_flags(sngss7_chan_data_t *sngss7_info); +ftdm_status_t clear_rx_rsc_flags(sngss7_chan_data_t *sngss7_info); +ftdm_status_t clear_tx_rsc_flags(sngss7_chan_data_t *sngss7_info); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -72,9 +81,10 @@ uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum) int k; int j; int flag; + int odd; char tmp[2]; - unsigned char lower; - unsigned char upper; + uint8_t lower; + uint8_t upper; /**************************************************************************/ cgPtyNum->eh.pres = PRSNT_NODEF; @@ -104,81 +114,73 @@ uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum) k = 0; j = 0; flag = 0; + odd = 0; + upper = 0x0; + lower = 0x0; while (1) { + /* grab a digit from the ftdm digits */ tmp[0] = ftdm->cid_num.digits[k]; + /* check if the digit is a number and that is not null */ + while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) { + /* move on to the next value */ + k++; + tmp[0] = ftdm->cid_num.digits[k]; + } /* while(!(isdigit(tmp))) */ + + /* check if tmp is null or a digit */ if (tmp[0] != '\0') { - if (isdigit(tmp[0])) { - lower = atoi(&tmp[0]); + /* push it into the lower nibble */ + lower = atoi(&tmp[0]); + /* move to the next digit */ + k++; + /* grab a digit from the ftdm digits */ + tmp[0] = ftdm->cid_num.digits[k]; + + /* check if the digit is a number and that is not null */ + while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) { k++; tmp[0] = ftdm->cid_num.digits[k]; - } else { - while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) { - k++; - tmp[0] = ftdm->cid_num.digits[k]; - } /* while(!(isdigit(tmp))) */ + } /* while(!(isdigit(tmp))) */ - if (tmp[0] != '\0') { - lower = atoi(&tmp[0]); - k++; - tmp[0] = ftdm->cid_num.digits[k]; - } else { - flag = 1; - lower = 0xf; - } /* if (tmp != '\0') */ - } /* (isdigit(tmp)) */ - } else { - flag = 1; - lower = 0xf; - } /* if (tmp != '\0') */ - - tmp[0] = ftdm->cid_num.digits[k]; - - if (tmp[0] != '\0') { - if (isdigit(tmp[0])) { + /* check if tmp is null or a digit */ + if (tmp[0] != '\0') { + /* push the digit into the upper nibble */ upper = (atoi(&tmp[0])) << 4; } else { - while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) { - k++; - tmp[0] = ftdm->cid_num.digits[k]; - } /* while(!(isdigit(tmp))) */ - - if (tmp[0] != '\0') { - upper = (atoi(&tmp[0])) << 4; - k++; - } else { - flag = 1; - upper = 0xf; - } /* if (tmp != '\0') */ - } /* if (isdigit(tmp)) */ - } else { - if (flag == 1) { + /* there is no upper ... fill in 0 */ upper = 0x0; - } else { + /* throw the odd flag */ + odd = 1; + /* throw the end flag */ flag = 1; - upper = 0xf; - } /* if (flag == 1) */ - } /* if (tmp != '\0') */ + } /* if (tmp != '\0') */ + } else { + /* keep the odd flag down */ + odd = 0; + /* throw the flag */ + flag = 1; + } + /* push the digits into the trillium structure */ cgPtyNum->addrSig.val[j] = upper | lower; + /* increment the trillium pointer */ j++; - if (flag) { - break; - } else { - k++; - } + /* if the flag is up we're through all the digits */ + if (flag) break; + + /* move to the next digit */ + k++; } /* while(1) */ cgPtyNum->addrSig.len = j; /**************************************************************************/ cgPtyNum->oddEven.pres = PRSNT_NODEF; - - cgPtyNum->oddEven.val = ((cgPtyNum->addrSig.val[j] >> 4) == 0x0 ) ? 0x01 : 0x00; - + cgPtyNum->oddEven.val = odd; /**************************************************************************/ return 0; } @@ -196,9 +198,10 @@ uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum) int k; int j; int flag; + int odd; char tmp[2]; - unsigned char lower; - unsigned char upper; + uint8_t lower; + uint8_t upper; /**************************************************************************/ cdPtyNum->eh.pres = PRSNT_NODEF; @@ -217,77 +220,74 @@ uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum) /* atoi will search through memory starting from the pointer it is given until * it finds the \0...since tmp is on the stack it will start going through the * possibly causing corruption. Hard code a \0 to prevent this - */ + */ /* dnis */ tmp[1] = '\0'; k = 0; j = 0; flag = 0; + odd = 0; + upper = 0x0; + lower = 0x0; while (1) { + /* grab a digit from the ftdm digits */ tmp[0] = ftdm->dnis.digits[k]; + /* check if the digit is a number and that is not null */ + while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) { + /* move on to the next value */ + k++; + tmp[0] = ftdm->dnis.digits[k]; + } /* while(!(isdigit(tmp))) */ + + /* check if tmp is null or a digit */ if (tmp[0] != '\0') { - if (isdigit(tmp[0])) { - lower = atoi(&tmp[0]); + /* push it into the lower nibble */ + lower = atoi(&tmp[0]); + /* move to the next digit */ + k++; + /* grab a digit from the ftdm digits */ + tmp[0] = ftdm->dnis.digits[k]; + + /* check if the digit is a number and that is not null */ + while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) { k++; tmp[0] = ftdm->dnis.digits[k]; - } else { - while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) { - k++; - tmp[0] = ftdm->dnis.digits[k]; - } /* while(!(isdigit(tmp))) */ + } /* while(!(isdigit(tmp))) */ - if (tmp[0] != '\0') { - lower = atoi(&tmp[0]); - k++; - tmp[0] = ftdm->dnis.digits[k]; - } else { - flag = 1; - lower = 0xf; - } /* if (tmp != '\0') */ - } /* (isdigit(tmp)) */ - } else { - flag = 1; - lower = 0xf; - } /* if (tmp != '\0') */ - - tmp[0] = ftdm->dnis.digits[k]; - - if (tmp[0] != '\0') { - if (isdigit(tmp[0])) { + /* check if tmp is null or a digit */ + if (tmp[0] != '\0') { + /* push the digit into the upper nibble */ upper = (atoi(&tmp[0])) << 4; } else { - while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) { - k++; - tmp[0] = ftdm->dnis.digits[k]; - } /* while(!(isdigit(tmp))) */ - - if (tmp[0] != '\0') { - upper = (atoi(&tmp[0])) << 4; - k++; - } else { - flag = 1; - upper = 0xf; - } /* if (tmp != '\0') */ - } /* if (isdigit(tmp)) */ - } else { - if (flag == 1) { - upper = 0x0; - } else { + /* there is no upper ... fill in ST */ + upper = 0xF; + /* throw the odd flag */ + odd = 1; + /* throw the end flag */ flag = 1; - upper = 0xf; - } /* if (flag == 1) */ - } /* if (tmp != '\0') */ + } /* if (tmp != '\0') */ + } else { + /* keep the odd flag down */ + odd = 1; + /* need to add the ST */ + lower = 0xF; + upper = 0x0; + /* throw the flag */ + flag = 1; + } + /* push the digits into the trillium structure */ cdPtyNum->addrSig.val[j] = upper | lower; + /* increment the trillium pointer */ j++; - if (flag) { - break; - } else { - k++; - } + /* if the flag is up we're through all the digits */ + if (flag) break; + + /* move to the next digit */ + k++; } /* while(1) */ cdPtyNum->addrSig.len = j; @@ -295,7 +295,7 @@ uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum) /**************************************************************************/ cdPtyNum->oddEven.pres = PRSNT_NODEF; - cdPtyNum->oddEven.val = ((cdPtyNum->addrSig.val[j] >> 4) == 0x0 ) ? 0x01 : 0x00; + cdPtyNum->oddEven.val = odd; /**************************************************************************/ return 0; @@ -313,9 +313,9 @@ uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven) j = 0; for (i = 0; i < str.len; i++) { - sprintf(&ftdm[j], "%d", (str.val[i] & 0x0F)); + sprintf(&ftdm[j], "%X", (str.val[i] & 0x0F)); j++; - sprintf(&ftdm[j], "%d", ((str.val[i] & 0xF0) >> 4)); + sprintf(&ftdm[j], "%X", ((str.val[i] & 0xF0) >> 4)); j++; } @@ -325,6 +325,8 @@ uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven) } else { ftdm[j] = '\0'; } + + } else { SS7_ERROR("Asked to copy tknStr that is not present!\n"); return 1; @@ -450,6 +452,353 @@ unsigned long get_unique_id(void) return(sngss7_id); } +/******************************************************************************/ +ftdm_status_t check_if_rx_grs_started(ftdm_span_t *ftdmspan) +{ + ftdm_channel_t *ftdmchan = NULL; + sngss7_chan_data_t *sngss7_info = NULL; + sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->mod_data; + int i; + + for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { + + /* extract the channel in question */ + if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i); + continue; + } + + /* check if the GRP_RESET_RX flag is already up */ + if (sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_RX)) { + /* we have already processed this channel...move along */ + continue; + } + + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* clear up any pending state changes */ + while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { + ftdm_sangoma_ss7_process_state_change (ftdmchan); + } + + SS7_INFO_CHAN(ftdmchan, "Rx GRS (%d:%d)\n", + g_ftdm_sngss7_data.cfg.isupCkt[sngss7_span->rx_grs.circuit].cic, + (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_span->rx_grs.circuit].cic + sngss7_span->rx_grs.range)); + + /* flag the channel as having received a reset */ + sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_RX); + + switch (ftdmchan->state) { + /**************************************************************************/ + case FTDM_CHANNEL_STATE_RESTART: + + /* go to idle so that we can redo the restart state*/ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE); + + break; + /**************************************************************************/ + default: + + /* set the state of the channel to restart...the rest is done by the chan monitor */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + break; + /**************************************************************************/ + } /* switch (ftdmchan->state) */ + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + } /* for (chans in GRS */ + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +ftdm_status_t check_if_rx_grs_processed(ftdm_span_t *ftdmspan) +{ + ftdm_channel_t *ftdmchan = NULL; + sngss7_chan_data_t *sngss7_info = NULL; + sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->mod_data; + int i; + int byte = 0; + int bit = 0; + + + ftdm_log(FTDM_LOG_DEBUG, "Found Rx GRS on span %d...checking circuits\n", ftdmspan->span_id); + + /* check all the circuits in the range to see if they are done resetting */ + for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { + + /* extract the channel in question */ + if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i); + continue; + } + + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* check if there is a state change pending on the channel */ + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { + /* check the state to the GRP_RESET_RX_DN flag */ + if (!sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_RX_DN)) { + /* this channel is still resetting...do nothing */ + goto GRS_UNLOCK_ALL; + } /* if (!sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_RX_DN)) */ + } else { + /* state change pending */ + goto GRS_UNLOCK_ALL; + } + } /* for ( i = circuit; i < (circuit + range + 1); i++) */ + + SS7_DEBUG("All circuits out of reset for GRS: circuit=%d, range=%d\n", + sngss7_span->rx_grs.circuit, + sngss7_span->rx_grs.range); + + /* check all the circuits in the range to see if they are done resetting */ + for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { + + /* extract the channel in question */ + if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n",i); + /* check if we need to die */ + SS7_ASSERT; + /* move along */ + continue; + } + + /* throw the GRP reset flag complete flag */ + sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_RX_CMPLT); + + /* move the channel to the down state */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + + /* update the status map if the ckt is in blocked state */ + if ((sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_RX)) || + (sngss7_test_flag(sngss7_info, FLAG_CKT_MN_BLOCK_TX)) || + (sngss7_test_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX)) || + (sngss7_test_flag(sngss7_info, FLAG_GRP_MN_BLOCK_RX))) { + + sngss7_span->rx_grs.status[byte] = (sngss7_span->rx_grs.status[byte] | (1 << bit)); + } /* if blocked */ + + /* update the bit and byte counter*/ + bit ++; + if (bit == 8) { + byte++; + bit = 0; + } + } /* for ( i = circuit; i < (circuit + range + 1); i++) */ + +GRS_UNLOCK_ALL: + for ( i = sngss7_span->rx_grs.circuit; i < (sngss7_span->rx_grs.circuit + sngss7_span->rx_grs.range + 1); i++) { + /* extract the channel in question */ + if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i); + continue; + } + + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + } + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +ftdm_status_t check_if_rx_gra_started(ftdm_span_t *ftdmspan) +{ + ftdm_channel_t *ftdmchan = NULL; + sngss7_chan_data_t *sngss7_info = NULL; + sngss7_span_data_t *sngss7_span = (sngss7_span_data_t *)ftdmspan->mod_data; + int i; + + for ( i = sngss7_span->rx_gra.circuit; i < (sngss7_span->rx_gra.circuit + sngss7_span->rx_gra.range + 1); i++) { + + /* extract the channel in question */ + if (extract_chan_data(i, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", i); + continue; + } + + /* check if the channel is already procoessing the GRA */ + if (sngss7_test_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP)) { + /* move along */ + continue; + } + + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + + /* clear up any pending state changes */ + while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { + ftdm_sangoma_ss7_process_state_change (ftdmchan); + } + + SS7_INFO_CHAN(ftdmchan, "Rx GRA (%d:%d)\n", + g_ftdm_sngss7_data.cfg.isupCkt[sngss7_span->rx_gra.circuit].cic, + (g_ftdm_sngss7_data.cfg.isupCkt[sngss7_span->rx_gra.circuit].cic + sngss7_span->rx_gra.range)); + + switch (ftdmchan->state) { + /**********************************************************************/ + case FTDM_CHANNEL_STATE_RESTART: + + /* throw the FLAG_RESET_TX_RSP to indicate we have acknowledgement from the remote side */ + sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP); + + /* go to DOWN */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + + break; + /**********************************************************************/ + case FTDM_CHANNEL_STATE_DOWN: + + /* do nothing, just drop the message */ + SS7_DEBUG("Receveived GRA in down state, dropping\n"); + + break; + /**********************************************************************/ + case FTDM_CHANNEL_STATE_TERMINATING: + case FTDM_CHANNEL_STATE_HANGUP: + case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: + + /* throw the FLAG_RESET_TX_RSP to indicate we have acknowledgement from the remote side */ + sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP); + + break; + /**********************************************************************/ + default: + /* ITU Q764-2.9.5.1.c -> release the circuit */ + if (sngss7_span->rx_gra.cause != 0) { + ftdmchan->caller_data.hangup_cause = sngss7_span->rx_gra.cause; + } else { + ftdmchan->caller_data.hangup_cause = 98; /* Message not compatiable with call state */ + } + + /* go to terminating to hang up the call */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + break; + /**********************************************************************/ + } + + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + + } /* for ( circuits in request */ + + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +ftdm_status_t check_for_res_sus_flag(ftdm_span_t *ftdmspan) +{ + ftdm_channel_t *ftdmchan = NULL; + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_sigmsg_t sigev; + int x; + + for (x = 1; x < (ftdmspan->chan_count + 1); x++) { + + /* extract the channel structure and sngss7 channel data */ + ftdmchan = ftdmspan->channels[x]; + + /* if the call data is NULL move on */ + if (ftdmchan->call_data == NULL) continue; + + sngss7_info = ftdmchan->call_data; + + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + + memset (&sigev, 0, sizeof (sigev)); + + sigev.chan_id = ftdmchan->chan_id; + sigev.span_id = ftdmchan->span_id; + sigev.channel = ftdmchan; + + /* if we have the PAUSED flag and the sig status is still UP */ + if ((sngss7_test_flag(sngss7_info, FLAG_INFID_PAUSED)) && + (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP))) { + + /* clear up any pending state changes */ + while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { + ftdm_sangoma_ss7_process_state_change (ftdmchan); + } + + /* throw the channel into SUSPENDED to process the flag */ + /* after doing this once the sig status will be down */ + ftdm_set_state_locked (ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } + + /* if the RESUME flag is up go to SUSPENDED to process the flag */ + /* after doing this the flag will be cleared */ + if (sngss7_test_flag(sngss7_info, FLAG_INFID_RESUME)) { + + /* clear up any pending state changes */ + while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) { + ftdm_sangoma_ss7_process_state_change (ftdmchan); + } + + /* got SUSPENDED state to clear the flag */ + ftdm_set_state_locked (ftdmchan, FTDM_CHANNEL_STATE_SUSPENDED); + } + + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + + } /* for (x = 1; x < (span->chan_count + 1); x++) */ + + /* signal the core that sig events are queued for processing */ + ftdm_span_trigger_signals(ftdmspan); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +ftdm_status_t clear_rx_grs_flags(sngss7_chan_data_t *sngss7_info) +{ + /* clear all the flags related to an incoming GRS */ + sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_RX); + sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_RX_DN); + sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_RX_CMPLT); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +ftdm_status_t clear_tx_grs_flags(sngss7_chan_data_t *sngss7_info) +{ + /* clear all the flags related to an outgoing GRS */ + sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_BASE); + sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_TX); + sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_SENT); + sngss7_clear_flag(sngss7_info, FLAG_GRP_RESET_TX_RSP); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +ftdm_status_t clear_rx_rsc_flags(sngss7_chan_data_t *sngss7_info) +{ + /* clear all the flags related to an incoming RSC */ + sngss7_clear_flag(sngss7_info, FLAG_RESET_RX); + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +ftdm_status_t clear_tx_rsc_flags(sngss7_chan_data_t *sngss7_info) +{ + /* clear all the flags related to an outgoing RSC */ + sngss7_clear_flag(sngss7_info, FLAG_RESET_TX); + sngss7_clear_flag(sngss7_info, FLAG_RESET_SENT); + sngss7_clear_flag(sngss7_info, FLAG_RESET_TX_RSP); + + return FTDM_SUCCESS; +} + /******************************************************************************/ /******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c index 5185ffcc62..75b32d6892 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c @@ -64,7 +64,7 @@ void handle_isup_t35(void *userdata) sngss7_set_flag(sngss7_info, FLAG_LOCAL_REL); /* hang up on timer expiry */ - ftdmchan->caller_data.hangup_cause = 102; + ftdmchan->caller_data.hangup_cause = 28; /* end the call */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index aa639d1c3a..bd1be4b6a4 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -46,6 +46,8 @@ typedef struct sng_timeslot int gap; int hole; }sng_timeslot_t; + +int cmbLinkSetId; /******************************************************************************/ /* PROTOTYPES *****************************************************************/ @@ -343,11 +345,11 @@ static int ftmod_ss7_parse_mtp_linkset(ftdm_conf_node_t *mtp_linkset) /**********************************************************************/ } else if (!strcasecmp(parm->var, "apc")) { mtpLinkSet.apc = atoi(parm->val); - SS7_DEBUG("\tFoundmtpLinkSet->apc = %d\n", mtpLinkSet.apc); + SS7_DEBUG("\tFound mtpLinkSet->apc = %d\n", mtpLinkSet.apc); /**********************************************************************/ } else if (!strcasecmp(parm->var, "minActive")) { mtpLinkSet.minActive = atoi(parm->val); - SS7_DEBUG("\tFoundmtpLinkSet->minActive = %d\n", mtpLinkSet.minActive); + SS7_DEBUG("\tFound mtpLinkSet->minActive = %d\n", mtpLinkSet.minActive); /**********************************************************************/ } else { SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val); @@ -385,8 +387,6 @@ static int ftmod_ss7_parse_mtp_linkset(ftdm_conf_node_t *mtp_linkset) if (count < 1 || count > 15 ) { SS7_ERROR("Invalid number of mtp_links found (%d)\n", count); return FTDM_FAIL; - } else { - mtpLinkSet.numLinks = count; } /* now we need to see if this linkset exists already or not and grab an Id */ @@ -418,8 +418,7 @@ static int ftmod_ss7_parse_mtp_linkset(ftdm_conf_node_t *mtp_linkset) mtpLink[i].mtp3.apc = mtpLinkSet.apc; mtpLink[i].mtp3.linkSetId = mtpLinkSet.id; - /* fill in the mtplink structure */ - mtpLinkSet.links[count] = ftmod_ss7_fill_in_mtpLink(&mtpLink[i]); + ftmod_ss7_fill_in_mtpLink(&mtpLink[i]); /* increment the links counter */ count++; @@ -428,6 +427,10 @@ static int ftmod_ss7_parse_mtp_linkset(ftdm_conf_node_t *mtp_linkset) i++; } + mtpLinkSet.linkType = mtpLink[0].mtp3.linkType; + mtpLinkSet.switchType = mtpLink[0].mtp3.switchType; + mtpLinkSet.ssf = mtpLink[0].mtp3.ssf; + ftmod_ss7_fill_in_mtpLinkSet(&mtpLinkSet); return FTDM_SUCCESS; @@ -497,27 +500,27 @@ static int ftmod_ss7_parse_mtp_link(ftdm_conf_node_t *mtp_link, sng_mtp_link_t * if (!strcasecmp(parm->val, "itu92")) { mtpLink->mtp2.linkType = LSD_SW_ITU92; mtpLink->mtp3.linkType = LSN_SW_ITU; - SS7_DEBUG("\tFoundmtpLink->linkType = \"ITU92\"\n"); + SS7_DEBUG("\tFound mtpLink->linkType = \"ITU92\"\n"); } else if (!strcasecmp(parm->val, "itu88")) { mtpLink->mtp2.linkType = LSD_SW_ITU88; mtpLink->mtp3.linkType = LSN_SW_ITU; - SS7_DEBUG("\tFoundmtpLink->linkType = \"ITU88\"\n"); + SS7_DEBUG("\tFound mtpLink->linkType = \"ITU88\"\n"); } else if (!strcasecmp(parm->val, "ansi96")) { mtpLink->mtp2.linkType = LSD_SW_ANSI92; mtpLink->mtp3.linkType = LSN_SW_ANS96; - SS7_DEBUG("\tFoundmtpLink->linkType = \"ANSI96\"\n"); + SS7_DEBUG("\tFound mtpLink->linkType = \"ANSI96\"\n"); } else if (!strcasecmp(parm->val, "ansi92")) { mtpLink->mtp2.linkType = LSD_SW_ANSI92; mtpLink->mtp3.linkType = LSN_SW_ANS; - SS7_DEBUG("\tFoundmtpLink->linkType = \"ANSI92\"\n"); + SS7_DEBUG("\tFound mtpLink->linkType = \"ANSI92\"\n"); } else if (!strcasecmp(parm->val, "ansi88")) { mtpLink->mtp2.linkType = LSD_SW_ANSI88; mtpLink->mtp3.linkType = LSN_SW_ANS; - SS7_DEBUG("\tFoundmtpLink->linkType = \"ANSI88\"\n"); + SS7_DEBUG("\tFound mtpLink->linkType = \"ANSI88\"\n"); } else if (!strcasecmp(parm->val, "etsi")) { mtpLink->mtp2.linkType = LSD_SW_ITU92; mtpLink->mtp3.linkType = LSN_SW_ITU; - SS7_DEBUG("\tFoundmtpLink->linkType = \"ETSI\"\n"); + SS7_DEBUG("\tFound mtpLink->linkType = \"ETSI\"\n"); } else { SS7_ERROR("\tFound an invalid linktype of \"%s\"!\n", parm->val); return FTDM_FAIL; @@ -526,31 +529,40 @@ static int ftmod_ss7_parse_mtp_link(ftdm_conf_node_t *mtp_link, sng_mtp_link_t * } else if (!strcasecmp(parm->var, "switchType")) { if (!strcasecmp(parm->val, "itu97")) { mtpLink->mtp3.switchType = LSI_SW_ITU97; - SS7_DEBUG("\tFoundmtpLink->switchType = \"ITU97\"\n"); + SS7_DEBUG("\tFound mtpLink->switchType = \"ITU97\"\n"); } else if (!strcasecmp(parm->val, "itu88")) { mtpLink->mtp3.switchType = LSI_SW_ITU; - SS7_DEBUG("\tFoundmtpLink->switchType = \"ITU88\"\n"); + SS7_DEBUG("\tFound mtpLink->switchType = \"ITU88\"\n"); } else if (!strcasecmp(parm->val, "itu92")) { mtpLink->mtp3.switchType = LSI_SW_ITU; - SS7_DEBUG("\tFoundmtpLink->switchType = \"ITU92\"\n"); + SS7_DEBUG("\tFound mtpLink->switchType = \"ITU92\"\n"); } else if (!strcasecmp(parm->val, "itu00")) { mtpLink->mtp3.switchType = LSI_SW_ITU2000; - SS7_DEBUG("\tFoundmtpLink->switchType = \"ITU00\"\n"); + SS7_DEBUG("\tFound mtpLink->switchType = \"ITU00\"\n"); } else if (!strcasecmp(parm->val, "ETSIV2")) { mtpLink->mtp3.switchType = LSI_SW_ETSI; - SS7_DEBUG("\tFoundmtpLink->switchType = \"ETSIV2\"\n"); + SS7_DEBUG("\tFound mtpLink->switchType = \"ETSIV2\"\n"); } else if (!strcasecmp(parm->val, "ETSIV3")) { mtpLink->mtp3.switchType = LSI_SW_ETSIV3; - SS7_DEBUG("\tFoundmtpLink->switchType = \"ETSIV3\"\n"); + SS7_DEBUG("\tFound mtpLink->switchType = \"ETSIV3\"\n"); } else if (!strcasecmp(parm->val, "UK")) { mtpLink->mtp3.switchType = LSI_SW_UK; - SS7_DEBUG("\tFoundmtpLink->switchType = \"UK\"\n"); + SS7_DEBUG("\tFound mtpLink->switchType = \"UK\"\n"); } else if (!strcasecmp(parm->val, "RUSSIA")) { mtpLink->mtp3.switchType = LSI_SW_RUSSIA; - SS7_DEBUG("\tFoundmtpLink->switchType = \"RUSSIA\"\n"); + SS7_DEBUG("\tFound mtpLink->switchType = \"RUSSIA\"\n"); } else if (!strcasecmp(parm->val, "INDIA")) { mtpLink->mtp3.switchType = LSI_SW_INDIA; - SS7_DEBUG("\tFoundmtpLink->switchType = \"INDIA\"\n"); + SS7_DEBUG("\tFound mtpLink->switchType = \"INDIA\"\n"); + } else if (!strcasecmp(parm->val, "ansi88")) { + mtpLink->mtp3.switchType = LSI_SW_ANS88; + SS7_DEBUG("\tFound mtpLink->switchType = \"ANSI88\"\n"); + } else if (!strcasecmp(parm->val, "ansi92")) { + mtpLink->mtp3.switchType = LSI_SW_ANS92; + SS7_DEBUG("\tFound mtpLink->switchType = \"ANSI92\"\n"); + } else if (!strcasecmp(parm->val, "ansi95")) { + mtpLink->mtp3.switchType = LSI_SW_ANS95; + SS7_DEBUG("\tFound mtpLink->switchType = \"ANSI95\"\n"); } else { SS7_ERROR("\tFound an invalid linktype of \"%s\"!\n", parm->val); return FTDM_FAIL; @@ -568,7 +580,7 @@ static int ftmod_ss7_parse_mtp_link(ftdm_conf_node_t *mtp_link, sng_mtp_link_t * /**********************************************************************/ } else if (!strcasecmp(parm->var, "slc")) { mtpLink->mtp3.slc = atoi(parm->val); - SS7_DEBUG("\tFoundmtpLink->slc = \"%d\"\n",mtpLink->mtp3.slc); + SS7_DEBUG("\tFound mtpLink->slc = \"%d\"\n",mtpLink->mtp3.slc); /**********************************************************************/ } else { SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val); @@ -649,14 +661,17 @@ static int ftmod_ss7_parse_mtp_route(ftdm_conf_node_t *mtp_route) /* check if the name matches */ if (!strcasecmp((char *)g_ftdm_sngss7_data.cfg.mtpLinkSet[x].name, parm->val)) { - /* grab the mtpLink id value first*/ - int id = g_ftdm_sngss7_data.cfg.mtpLinkSet[x].links[0]; - /* now, harvest the required infomormation from the global structure */ - mtpRoute.linkType = g_ftdm_sngss7_data.cfg.mtpLink[id].mtp3.linkType; - mtpRoute.switchType = g_ftdm_sngss7_data.cfg.mtpLink[id].mtp3.switchType; - mtpRoute.ssf = g_ftdm_sngss7_data.cfg.mtpLink[id].mtp3.ssf; - mtpRoute.cmbLinkSetId = g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id; + mtpRoute.linkType = g_ftdm_sngss7_data.cfg.mtpLinkSet[x].linkType; + mtpRoute.switchType = g_ftdm_sngss7_data.cfg.mtpLinkSet[x].switchType; + mtpRoute.ssf = g_ftdm_sngss7_data.cfg.mtpLinkSet[x].ssf; + mtpRoute.linkSetId = g_ftdm_sngss7_data.cfg.mtpLinkSet[x].id; + cmbLinkSetId++; + mtpRoute.cmbLinkSetId = cmbLinkSetId; + + /* update the linkset with the new cmbLinkSet value */ + g_ftdm_sngss7_data.cfg.mtpLinkSet[x].numLinks++; + g_ftdm_sngss7_data.cfg.mtpLinkSet[x].links[g_ftdm_sngss7_data.cfg.mtpLinkSet[x].numLinks-1] = mtpRoute.cmbLinkSetId; break; } x++; @@ -692,9 +707,11 @@ static int ftmod_ss7_parse_mtp_route(ftdm_conf_node_t *mtp_route) parm = parm + 1; } + ftmod_ss7_fill_in_nsap(&mtpRoute); + ftmod_ss7_fill_in_mtp3_route(&mtpRoute); - ftmod_ss7_fill_in_nsap(&mtpRoute); + return FTDM_SUCCESS; } @@ -738,7 +755,6 @@ static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) int num_parms = isup_interface->n_parameters; int i; int linkSetId; - int linkId; memset(&sng_isup, 0x0, sizeof(sng_isup)); memset(&sng_isap, 0x0, sizeof(sng_isap)); @@ -772,36 +788,25 @@ static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) /* check if the name matches */ if (!strcasecmp((char *)g_ftdm_sngss7_data.cfg.mtpRoute[x].name, parm->val)) { - /* now, harvest the required information from the global structure */ sng_isup.mtpRouteId = g_ftdm_sngss7_data.cfg.mtpRoute[x].id; sng_isup.dpc = g_ftdm_sngss7_data.cfg.mtpRoute[x].dpc; sng_isup.switchType = g_ftdm_sngss7_data.cfg.mtpRoute[x].switchType; sng_isap.switchType = g_ftdm_sngss7_data.cfg.mtpRoute[x].switchType; - /* find the nwID from the nsap */ - int y = 1; - while (g_ftdm_sngss7_data.cfg.nsap[y].id != 0) { - - if ((g_ftdm_sngss7_data.cfg.nsap[y].linkType == g_ftdm_sngss7_data.cfg.mtpRoute[x].linkType) && - (g_ftdm_sngss7_data.cfg.nsap[y].switchType == g_ftdm_sngss7_data.cfg.mtpRoute[x].switchType) && - (g_ftdm_sngss7_data.cfg.nsap[y].ssf == g_ftdm_sngss7_data.cfg.mtpRoute[x].ssf)) { - + /* find the NSAP corresponding to this switchType and SSF */ + int z = 1; + while (g_ftdm_sngss7_data.cfg.nsap[z].id != 0) { + if ((g_ftdm_sngss7_data.cfg.nsap[z].linkType == g_ftdm_sngss7_data.cfg.mtpRoute[x].linkType) && + (g_ftdm_sngss7_data.cfg.nsap[z].switchType == g_ftdm_sngss7_data.cfg.mtpRoute[x].switchType) && + (g_ftdm_sngss7_data.cfg.nsap[z].ssf == g_ftdm_sngss7_data.cfg.mtpRoute[x].ssf)) { + sng_isup.nwId = g_ftdm_sngss7_data.cfg.nsap[z].nwId; /* we have a match so break out of this loop */ break; } /* move on to the next one */ - y++; - } /* while (g_ftdm_sngss7_data.cfg.mtp3_isup[y].id != 0) */ - - /* check how we exited the last while loop */ - if (g_ftdm_sngss7_data.cfg.nsap[y].id == 0) { - SS7_ERROR("\tFailed to find the nwID for = \"%s\"!\n", parm->val); - return FTDM_FAIL; - } else { - sng_isup.nwId = g_ftdm_sngss7_data.cfg.nsap[y].nwId; + z++; } - break; } x++; @@ -846,10 +851,15 @@ static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) } /* trickle down the SPC to all sub entities */ - linkSetId = g_ftdm_sngss7_data.cfg.mtpRoute[sng_isup.mtpRouteId].cmbLinkSetId; - for (i = 0; i < g_ftdm_sngss7_data.cfg.mtpLinkSet[linkSetId].numLinks; i ++) { - linkId = g_ftdm_sngss7_data.cfg.mtpLinkSet[linkSetId].links[i]; - g_ftdm_sngss7_data.cfg.mtpLink[linkId].mtp3.spc = g_ftdm_sngss7_data.cfg.spc; + linkSetId = g_ftdm_sngss7_data.cfg.mtpRoute[sng_isup.mtpRouteId].linkSetId; + + i = 1; + while (g_ftdm_sngss7_data.cfg.mtpLink[i].id != 0) { + if (g_ftdm_sngss7_data.cfg.mtpLink[i].mtp3.linkSetId == linkSetId) { + g_ftdm_sngss7_data.cfg.mtpLink[i].mtp3.spc = g_ftdm_sngss7_data.cfg.spc; + } + + i++; } ftmod_ss7_fill_in_isap(&sng_isap); @@ -858,8 +868,6 @@ static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) ftmod_ss7_fill_in_isup_interface(&sng_isup); - g_ftdm_sngss7_data.cfg.isap[sng_isap.id].spId = sng_isup.id; - return FTDM_SUCCESS; } @@ -957,7 +965,7 @@ static int ftmod_ss7_fill_in_mtpLink(sng_mtp_link_t *mtpLink) if ( mtpLink->mtp2.t7 != 0 ) { g_ftdm_sngss7_data.cfg.mtpLink[i].mtp2.t7 = mtpLink->mtp2.t7; }else { - g_ftdm_sngss7_data.cfg.mtpLink[i].mtp2.t7 = 20; + g_ftdm_sngss7_data.cfg.mtpLink[i].mtp2.t7 = 40; } if (mtpLink->mtp3.t1 != 0) { @@ -1057,21 +1065,19 @@ static int ftmod_ss7_fill_in_mtpLink(sng_mtp_link_t *mtpLink) /******************************************************************************/ static int ftmod_ss7_fill_in_mtpLinkSet(sng_link_set_t *mtpLinkSet) { - int count; int i = mtpLinkSet->id; strcpy((char *)g_ftdm_sngss7_data.cfg.mtpLinkSet[i].name, (char *)mtpLinkSet->name); g_ftdm_sngss7_data.cfg.mtpLinkSet[i].id = mtpLinkSet->id; g_ftdm_sngss7_data.cfg.mtpLinkSet[i].apc = mtpLinkSet->apc; - g_ftdm_sngss7_data.cfg.mtpLinkSet[i].linkType = g_ftdm_sngss7_data.cfg.mtpLink[1].mtp3.linkType; /* KONRAD FIX ME */ + g_ftdm_sngss7_data.cfg.mtpLinkSet[i].linkType = mtpLinkSet->linkType; + g_ftdm_sngss7_data.cfg.mtpLinkSet[i].switchType = mtpLinkSet->switchType; + g_ftdm_sngss7_data.cfg.mtpLinkSet[i].ssf = mtpLinkSet->ssf; + + /* these values are filled in as we find routes and start allocating cmbLinkSetIds */ g_ftdm_sngss7_data.cfg.mtpLinkSet[i].minActive = mtpLinkSet->minActive; - g_ftdm_sngss7_data.cfg.mtpLinkSet[i].numLinks = mtpLinkSet->numLinks; - - for (count = 0; count < mtpLinkSet->numLinks; count++) { - g_ftdm_sngss7_data.cfg.mtpLinkSet[i].links[count] = mtpLinkSet->links[count]; - } - + g_ftdm_sngss7_data.cfg.mtpLinkSet[i].numLinks = 0; return 0; } @@ -1083,8 +1089,7 @@ static int ftmod_ss7_fill_in_mtp3_route(sng_route_t *mtp3_route) /* go through all the existing routes and see if we find a match */ i = 1; while (g_ftdm_sngss7_data.cfg.mtpRoute[i].id != 0) { - if (g_ftdm_sngss7_data.cfg.mtpRoute[i].dpc == mtp3_route->dpc) { - + if (!strcasecmp(g_ftdm_sngss7_data.cfg.mtpRoute[i].name, mtp3_route->name)) { /* we have a match so break out of this loop */ break; } @@ -1106,8 +1111,10 @@ static int ftmod_ss7_fill_in_mtp3_route(sng_route_t *mtp3_route) g_ftdm_sngss7_data.cfg.mtpRoute[i].dpc = mtp3_route->dpc; g_ftdm_sngss7_data.cfg.mtpRoute[i].linkType = mtp3_route->linkType; g_ftdm_sngss7_data.cfg.mtpRoute[i].switchType = mtp3_route->switchType; - g_ftdm_sngss7_data.cfg.mtpRoute[i].cmbLinkSetId = 1; /* mtp3_route->cmbLinkSetId;*/ + g_ftdm_sngss7_data.cfg.mtpRoute[i].cmbLinkSetId = mtp3_route->cmbLinkSetId; g_ftdm_sngss7_data.cfg.mtpRoute[i].isSTP = mtp3_route->isSTP; + g_ftdm_sngss7_data.cfg.mtpRoute[i].nwId = mtp3_route->nwId; + g_ftdm_sngss7_data.cfg.mtpRoute[i].linkSetId = mtp3_route->linkSetId; g_ftdm_sngss7_data.cfg.mtpRoute[i].ssf = mtp3_route->ssf; if (mtp3_route->t6 != 0) { g_ftdm_sngss7_data.cfg.mtpRoute[i].t6 = mtp3_route->t6; @@ -1159,6 +1166,11 @@ static int ftmod_ss7_fill_in_mtp3_route(sng_route_t *mtp3_route) } else { g_ftdm_sngss7_data.cfg.mtpRoute[i].t25 = 100; } + if (mtp3_route->t26 != 0) { + g_ftdm_sngss7_data.cfg.mtpRoute[i].t26 = mtp3_route->t26; + } else { + g_ftdm_sngss7_data.cfg.mtpRoute[i].t26 = 100; + } return 0; } @@ -1184,15 +1196,17 @@ static int ftmod_ss7_fill_in_nsap(sng_route_t *mtp3_route) if (g_ftdm_sngss7_data.cfg.nsap[i].id == 0) { g_ftdm_sngss7_data.cfg.nsap[i].id = i; + mtp3_route->nwId = i; SS7_DEBUG("found new mtp3_isup interface, id is = %d\n", g_ftdm_sngss7_data.cfg.nsap[i].id); } else { g_ftdm_sngss7_data.cfg.nsap[i].id = i; + mtp3_route->nwId = i; SS7_DEBUG("found existing mtp3_isup interface, id is = %d\n", g_ftdm_sngss7_data.cfg.nsap[i].id); } g_ftdm_sngss7_data.cfg.nsap[i].spId = g_ftdm_sngss7_data.cfg.nsap[i].id; g_ftdm_sngss7_data.cfg.nsap[i].suId = g_ftdm_sngss7_data.cfg.nsap[i].id; - g_ftdm_sngss7_data.cfg.nsap[i].nwId = g_ftdm_sngss7_data.cfg.nsap[i].id; + g_ftdm_sngss7_data.cfg.nsap[i].nwId = mtp3_route->nwId; g_ftdm_sngss7_data.cfg.nsap[i].linkType = mtp3_route->linkType; g_ftdm_sngss7_data.cfg.nsap[i].switchType = mtp3_route->switchType; g_ftdm_sngss7_data.cfg.nsap[i].ssf = mtp3_route->ssf; @@ -1208,7 +1222,7 @@ static int ftmod_ss7_fill_in_isup_interface(sng_isup_inf_t *sng_isup) /* go through all the existing interfaces and see if we find a match */ i = 1; while (g_ftdm_sngss7_data.cfg.isupIntf[i].id != 0) { - if (g_ftdm_sngss7_data.cfg.isupIntf[i].nwId == sng_isup->nwId) { + if (!strcasecmp(g_ftdm_sngss7_data.cfg.isupIntf[i].name, sng_isup->name)) { /* we have a match so break out of this loop */ break; @@ -1381,7 +1395,8 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap) } g_ftdm_sngss7_data.cfg.isap[i].id = sng_isap->id; - g_ftdm_sngss7_data.cfg.isap[i].suId = 1; /*KONRAD FIX ME */ + g_ftdm_sngss7_data.cfg.isap[i].suId = sng_isap->id; + g_ftdm_sngss7_data.cfg.isap[i].spId = sng_isap->id; g_ftdm_sngss7_data.cfg.isap[i].switchType = sng_isap->switchType; g_ftdm_sngss7_data.cfg.isap[i].ssf = sng_isap->ssf; @@ -1458,7 +1473,7 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap) if (sng_isap->tex != 0) { g_ftdm_sngss7_data.cfg.isap[i].tex = sng_isap->tex; } else { - g_ftdm_sngss7_data.cfg.isap[i].tex = 10; + g_ftdm_sngss7_data.cfg.isap[i].tex = 1000; } if (sng_isap->tcrm != 0) { g_ftdm_sngss7_data.cfg.isap[i].tcrm = sng_isap->tcrm; @@ -1499,7 +1514,9 @@ static int ftmod_ss7_fill_in_self_route(int spc, int linkType, int switchType, i SS7_DEBUG("found existing mtp3 self route\n"); return FTDM_SUCCESS; } else { - SS7_ERROR("found new mtp3 self route but it does not much the route already configured\n"); + SS7_ERROR("found new mtp3 self route but it does not match the route already configured (dpc=%d:spc=%d)\n", + g_ftdm_sngss7_data.cfg.mtpRoute[0].dpc, + spc); return FTDM_FAIL; } @@ -1583,11 +1600,10 @@ static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, g_ftdm_sngss7_data.cfg.isupCkt[x].chan = count; if (timeslot.siglink) { g_ftdm_sngss7_data.cfg.isupCkt[x].type = SIG; - } else if (timeslot.hole) { - g_ftdm_sngss7_data.cfg.isupCkt[x].type = HOLE; } else { - g_ftdm_sngss7_data.cfg.isupCkt[x].type = VOICE; + g_ftdm_sngss7_data.cfg.isupCkt[x].type = HOLE; } + if (timeslot.channel) { g_ftdm_sngss7_data.cfg.isupCkt[x].cic = cicbase; cicbase++; @@ -1608,6 +1624,10 @@ static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, g_ftdm_sngss7_data.cfg.isupCkt[x].obj = ss7_info; } /* if (g_ftdm_sngss7_data.cfg.isupCkt[x].id == 0) */ + + /* increment the span channel count */ + count++; + } else { /* if ((timeslot.siglink) || (timeslot.gap)) */ /* find the ftdm the channel structure for this channel*/ i = 1; diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index be99f94aff..23463e9088 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -280,6 +280,25 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_DTMF_DETECT); dtmf = "hardware"; } + + err = sangoma_tdm_get_hw_ec(chan->sockfd, &tdm_api); + if (err > 0) { + ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_HWEC); + } + +#ifdef WP_API_FEATURE_HWEC_PERSIST + err = sangoma_tdm_get_hwec_persist_status(chan->sockfd, &tdm_api); + if (err == 0) { + ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE); + } +#else + if (span->trunk_type == FTDM_TRUNK_BRI || span->trunk_type == FTDM_TRUNK_BRI_PTMP) { + ftdm_log(FTDM_LOG_WARNING, "WP_API_FEATURE_HWEC_PERSIST feature is not supported \ + with your version of libsangoma, you should update your Wanpipe drivers\n"); + + } +#endif + } #ifdef LIBSANGOMA_VERSION @@ -598,18 +617,33 @@ static FIO_COMMAND_FUNCTION(wanpipe_command) break; case FTDM_COMMAND_ENABLE_ECHOCANCEL: { +#ifdef WP_API_FEATURE_EC_CHAN_STAT + err=sangoma_tdm_get_hwec_chan_status(ftdmchan->sockfd, &tdm_api); + if (err > 0) { + /* Hardware echo canceller already enabled */ + err = 0; + break; + } +#endif err=sangoma_tdm_enable_hwec(ftdmchan->sockfd, &tdm_api); if (err) { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Enable Failed"); + snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Enable Failed"); return FTDM_FAIL; } } break; case FTDM_COMMAND_DISABLE_ECHOCANCEL: { +#ifdef WP_API_FEATURE_EC_CHAN_STAT + err=sangoma_tdm_get_hwec_chan_status(ftdmchan->sockfd, &tdm_api); + if (!err) { + /* Hardware echo canceller already disabled */ + break; + } +#endif err=sangoma_tdm_disable_hwec(ftdmchan->sockfd, &tdm_api); if (err) { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Disable Failed"); + snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Disable Failed"); 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 c4ba3ae749..ae9398418a 100644 --- a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c +++ b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c @@ -170,8 +170,8 @@ static const char *chanpath = NULL; static const char dahdi_ctlpath[] = "/dev/dahdi/ctl"; static const char dahdi_chanpath[] = "/dev/dahdi/channel"; -static const char zt_ctlpath[] = "/dev/ftdm/ctl"; -static const char zt_chanpath[] = "/dev/ftdm/channel"; +static const char zt_ctlpath[] = "/dev/zap/ctl"; +static const char zt_chanpath[] = "/dev/zap/channel"; static ftdm_socket_t CONTROL_FD = ZT_INVALID_SOCKET; @@ -974,7 +974,7 @@ FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event) */ FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event) { - uint32_t i, event_id = 0; + uint32_t i, event_id = FTDM_OOB_INVALID; zt_event_t zt_event_id = 0; for(i = 1; i <= span->chan_count; i++) { @@ -1022,6 +1022,8 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event) 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; diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 0437e02e51..1efe459032 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -386,7 +386,7 @@ typedef struct ftdm_conf_parameter { } ftdm_conf_parameter_t; /*! \brief Opaque general purpose iterator */ -typedef void ftdm_iterator_t; +typedef struct ftdm_iterator ftdm_iterator_t; /*! \brief Channel commands that can be executed through ftdm_channel_command() */ typedef enum { @@ -667,9 +667,6 @@ FT_DECLARE(ftdm_status_t) ftdm_span_set_sig_status(ftdm_span_t *span, ftdm_signa /*! \brief Get span signaling status (ie: whether protocol layer is up or down) */ FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signaling_status_t *status); -/*! \brief Get span signaling status (ie: whether protocol layer is up or down) */ -FT_DECLARE(void) ftdm_channel_clear_detected_tones(ftdm_channel_t *ftdmchan); - /*! * \brief Set user private data in the channel * @@ -1032,8 +1029,19 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_add_var(ftdm_channel_t *ftdmchan, const c FT_DECLARE(const char *) ftdm_channel_get_var(ftdm_channel_t *ftdmchan, const char *var_name); /*! \brief Get an iterator to iterate over the channel variables - * \note The iterator pointer returned is only valid while the channel is open and it'll be destroyed when the channel is closed. */ -FT_DECLARE(ftdm_iterator_t *) ftdm_channel_get_var_iterator(const ftdm_channel_t *ftdmchan); + * \param ftdmchan The channel structure containing the variables + * \param iter Optional iterator. You can reuse an old iterator (not previously freed) to avoid the extra allocation of a new iterator. + * \note The iterator pointer returned is only valid while the channel is open and it'll be destroyed when the channel is closed. + * This iterator is completely non-thread safe, if you are adding variables or removing variables while iterating + * results are unpredictable + */ +FT_DECLARE(ftdm_iterator_t *) ftdm_channel_get_var_iterator(const ftdm_channel_t *ftdmchan, ftdm_iterator_t *iter); + +/*! \brief Get iterator current value (depends on the iterator type) + * \note Channel iterators return a pointer to ftdm_channel_t + * Variable iterators return a pointer to the variable name (not the variable value) + */ +FT_DECLARE(void *) ftdm_iterator_current(ftdm_iterator_t *iter); /*! \brief Get variable name and value for the current iterator position */ FT_DECLARE(ftdm_status_t) ftdm_channel_get_current_var(ftdm_iterator_t *iter, const char **var_name, const char **var_val); @@ -1041,6 +1049,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_get_current_var(ftdm_iterator_t *iter, co /*! \brief Advance iterator */ FT_DECLARE(ftdm_iterator_t *) ftdm_iterator_next(ftdm_iterator_t *iter); +/*! \brief Free iterator + * \note You must free an iterator after using it unless you plan to reuse it + */ +FT_DECLARE(ftdm_status_t) ftdm_iterator_free(ftdm_iterator_t *iter); + /*! \brief Get the span pointer associated to the channel */ FT_DECLARE(ftdm_span_t *) ftdm_channel_get_span(const ftdm_channel_t *ftdmchan); @@ -1144,6 +1157,12 @@ FT_DECLARE(uint32_t) ftdm_span_get_id(const ftdm_span_t *span); /*! \brief Get the span name */ FT_DECLARE(const char *) ftdm_span_get_name(const ftdm_span_t *span); +/*! \brief Get iterator for the span channels + * \param span The span containing the channels + * \param iter Optional iterator. You can reuse an old iterator (not previously freed) to avoid the extra allocation of a new iterator. + */ +FT_DECLARE(ftdm_iterator_t *) ftdm_span_get_chan_iterator(const ftdm_span_t *span, ftdm_iterator_t *iter); + /*! * \brief Execute a text command. The text command output will be returned and must be free'd * @@ -1154,16 +1173,6 @@ FT_DECLARE(const char *) ftdm_span_get_name(const ftdm_span_t *span); */ FT_DECLARE(char *) ftdm_api_execute(const char *cmd); -/*! - * \brief Disables CPU monitoring - * - * \note CPU monitoring is enabled by default. This means a thread will be launched at startup (ftdm_global_init) - * with the sole purpose of monitoring system-wide CPU usage. If the CPU usage raises above a defined - * threshold, no new calls will be accepted (neither incoming or outgoing) - * - */ -FT_DECLARE(void) ftdm_cpu_monitor_disable(void); - /*! * \brief Create a configuration node * @@ -1255,7 +1264,13 @@ FT_DECLARE(const char *) ftdm_channel_get_state_str(const ftdm_channel_t *channe /*! \brief For display debugging purposes you can display this string which describes the last channel internal state */ FT_DECLARE(const char *) ftdm_channel_get_last_state_str(const ftdm_channel_t *channel); -/*! \brief For display debugging purposes you can display this string which describes the last channel internal state */ +/*! \brief For display debugging purposes you can display this string which describes the history of the channel + * \param channel The channel to get the history from + * \return History string for the channel. You must free the string with ftdm_free + */ +FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *channel); + +/*! \brief Initialize channel state for an outgoing call */ FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan); /*! \brief Initialize the library */ @@ -1279,6 +1294,12 @@ FT_DECLARE(void) ftdm_global_set_logger(ftdm_logger_t logger); /*! \brief Set the default logger level */ FT_DECLARE(void) ftdm_global_set_default_logger(int level); +/*! \brief Set the directory to look for modules */ +FT_DECLARE(void) ftdm_global_set_mod_directory(const char *path); + +/*! \brief Set the directory to look for configs */ +FT_DECLARE(void) ftdm_global_set_config_directory(const char *path); + /*! \brief Check if the FTDM library is initialized and running */ FT_DECLARE(ftdm_bool_t) ftdm_running(void); diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 74bea8148c..8bdbdd60f8 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -356,6 +356,15 @@ typedef struct { } ftdm_dtmf_debug_t; #endif +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; + /* 2^8 table size, one for each byte (sample) value */ #define FTDM_GAINS_TABLE_SIZE 256 struct ftdm_channel { @@ -381,6 +390,8 @@ struct ftdm_channel { ftdm_channel_state_t state; ftdm_channel_state_t last_state; ftdm_channel_state_t init_state; + ftdm_channel_history_entry_t history[10]; + uint8_t hindex; ftdm_mutex_t *mutex; teletone_dtmf_detect_state_t dtmf_detect; uint32_t buffer_delay; @@ -425,6 +436,7 @@ struct ftdm_channel { float txgain; int availability_rate; void *user_private; + ftdm_timer_id_t hangup_timer; #ifdef FTDM_DEBUG_DTMF ftdm_dtmf_debug_t dtmfdbg; #endif @@ -583,6 +595,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, cons /* dequeue pending signals and notify the user via the span signal callback */ FT_DECLARE(ftdm_status_t) ftdm_span_trigger_signals(const ftdm_span_t *span); +/*! \brief clear the tone detector state */ +FT_DECLARE(void) ftdm_channel_clear_detected_tones(ftdm_channel_t *ftdmchan); + + /*! \brief Assert condition */ @@ -619,6 +635,9 @@ FT_DECLARE(ftdm_status_t) ftdm_span_trigger_signals(const ftdm_span_t *span); #define ftdm_log_chan(fchan, level, format, ...) ftdm_log(level, "[s%dc%d][%d:%d] " format, fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, __VA_ARGS__) #define ftdm_log_chan_msg(fchan, level, msg) ftdm_log(level, "[s%dc%d][%d:%d] " msg, fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id) +#define ftdm_span_lock(span) ftdm_mutex_lock(span->mutex) +#define ftdm_span_unlock(span) ftdm_mutex_unlock(span->mutex) + FT_DECLARE_DATA extern const char *FTDM_LEVEL_NAMES[9]; static __inline__ void ftdm_abort(void) diff --git a/libs/freetdm/src/include/private/ftdm_sched.h b/libs/freetdm/src/include/private/ftdm_sched.h index 0951d050a7..c1818d8bb5 100644 --- a/libs/freetdm/src/include/private/ftdm_sched.h +++ b/libs/freetdm/src/include/private/ftdm_sched.h @@ -44,8 +44,8 @@ extern "C" { #define FTDM_MICROSECONDS_PER_SECOND 1000000 typedef struct ftdm_sched ftdm_sched_t; -typedef struct ftdm_timer ftdm_timer_t; typedef void (*ftdm_sched_callback_t)(void *data); +typedef uint64_t ftdm_timer_id_t; /*! \brief Create a new scheduling context */ FT_DECLARE(ftdm_status_t) ftdm_sched_create(ftdm_sched_t **sched, const char *name); @@ -62,18 +62,22 @@ FT_DECLARE(ftdm_status_t) ftdm_sched_free_run(ftdm_sched_t *sched); * \param name Timer name, typically unique but is not required to be unique, any null terminated string is fine (required) * \param callback The callback to call upon timer expiration (required) * \param data Optional data to pass to the callback - * \param timer The timer that was created, it can be NULL if you dont care, - * but you need this if you want to be able to cancel the timer with ftdm_sched_cancel_timer + * \param timer Timer id pointer to store the id of the newly created timer. It can be null + * if you do not need to know the id, but you need this if you want to be able + * to cancel the timer with ftdm_sched_cancel_timer */ FT_DECLARE(ftdm_status_t) ftdm_sched_timer(ftdm_sched_t *sched, const char *name, - int ms, ftdm_sched_callback_t callback, void *data, ftdm_timer_t **timer); + int ms, ftdm_sched_callback_t callback, void *data, ftdm_timer_id_t *timer); /*! * \brief Cancel the timer + * Note that there is a race between cancelling and triggering a timer. + * By the time you call this function the timer may be about to be triggered. + * This is specially true with timers in free run schedule. * \param sched The scheduling context (required) * \param timer The timer to cancel (required) */ -FT_DECLARE(ftdm_status_t) ftdm_sched_cancel_timer(ftdm_sched_t *sched, ftdm_timer_t **timer); +FT_DECLARE(ftdm_status_t) ftdm_sched_cancel_timer(ftdm_sched_t *sched, ftdm_timer_id_t timer); /*! \brief Destroy the context and all of the scheduled timers in it */ FT_DECLARE(ftdm_status_t) ftdm_sched_destroy(ftdm_sched_t **sched); @@ -91,6 +95,9 @@ FT_DECLARE(ftdm_status_t) ftdm_sched_global_init(void); /*! \brief Checks if the main scheduling thread is running */ FT_DECLARE(ftdm_bool_t) ftdm_free_sched_running(void); +/*! \brief Stop the main scheduling thread (if running) */ +FT_DECLARE(ftdm_bool_t) ftdm_free_sched_stop(void); + #ifdef __cplusplus } #endif diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index d8e8b5c2e6..bddefd9be6 100644 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -191,6 +191,8 @@ typedef enum { FTDM_CHANNEL_FEATURE_CALLERID = (1 << 4), /*!< Channel can detect caller id (read-only) */ FTDM_CHANNEL_FEATURE_PROGRESS = (1 << 5), /*!< Channel can detect inband progress (read-only) */ FTDM_CHANNEL_FEATURE_CALLWAITING = (1 << 6), /*!< Channel will allow call waiting (ie: FXS devices) (read/write) */ + FTDM_CHANNEL_FEATURE_HWEC = (1<<7), /*!< Channel has a hardware echo canceller */ + FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE = (1<<8), /*!< hardware echo canceller is disabled when there are no calls on this channel */ } ftdm_channel_feature_t; typedef enum { @@ -322,9 +324,15 @@ struct ftdm_conf_node { /* first node child */ struct ftdm_conf_node *child; + /* last node child */ + struct ftdm_conf_node *last; + /* next node sibling */ struct ftdm_conf_node *next; + /* prev node sibling */ + struct ftdm_conf_node *prev; + /* my parent if any */ struct ftdm_conf_node *parent; }; @@ -366,6 +374,23 @@ typedef ftdm_status_t (*ftdm_span_start_t)(ftdm_span_t *span); typedef ftdm_status_t (*ftdm_span_stop_t)(ftdm_span_t *span); typedef ftdm_status_t (*ftdm_channel_sig_read_t)(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size); +typedef enum { + FTDM_ITERATOR_VARS = 1, + FTDM_ITERATOR_CHANS, +} ftdm_iterator_type_t; + +struct ftdm_iterator { + ftdm_iterator_type_t type; + unsigned int allocated:1; + union { + struct { + uint32_t index; + const ftdm_span_t *span; + } chaniter; + ftdm_hash_iterator_t *hashiter; + } pvt; +}; + #ifdef __cplusplus } #endif diff --git a/libs/freetdm/src/libteletone_generate.c b/libs/freetdm/src/libteletone_generate.c index 089268bc7b..7f37b7a258 100644 --- a/libs/freetdm/src/libteletone_generate.c +++ b/libs/freetdm/src/libteletone_generate.c @@ -267,7 +267,7 @@ TELETONE_API(int) teletone_mux_tones(teletone_generation_session_t *ts, teletone ts->samples * 2); } } - return ts->samples; + return ts->samples / ts->channels; } TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cmd) diff --git a/libs/libcodec2/.update b/libs/libcodec2/.update new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libcodec2/AUTHORS b/libs/libcodec2/AUTHORS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libcodec2/COPYING b/libs/libcodec2/COPYING new file mode 100644 index 0000000000..4362b49151 --- /dev/null +++ b/libs/libcodec2/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/libs/libcodec2/ChangeLog b/libs/libcodec2/ChangeLog new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libcodec2/INSTALL b/libs/libcodec2/INSTALL new file mode 100644 index 0000000000..23e5f25d0e --- /dev/null +++ b/libs/libcodec2/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). Here is a another example: + + /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/libs/libcodec2/Makefile.am b/libs/libcodec2/Makefile.am new file mode 100644 index 0000000000..a1820f9162 --- /dev/null +++ b/libs/libcodec2/Makefile.am @@ -0,0 +1,98 @@ +AM_CFLAGS = -Isrc -Wall -lm +AUTOMAKE_OPTS = gnu +NAME = libcodec2 +AM_CPPFLAGS = $(AM_CFLAGS) + +EXTRA_DIST = pitch/hts1a.p \ +pitch/hts2a.p \ +octave/glottal.m \ +octave/lsp_pdf.m \ +octave/phase.m \ +octave/pl2.m \ +octave/plinterp.m \ +octave/plnlp.m \ +octave/plpitch.m \ +octave/postfilter.m \ +octave/load_raw.m \ +octave/phase2.m \ +octave/pitch_test.m \ +octave/plamp.m \ +octave/pl.m \ +octave/plphase.m \ +octave/png.m \ +octave/pulse.m \ +raw/b0067.raw \ +raw/forig_speex_8k.raw \ +raw/hts1.raw \ +raw/hts2.raw \ +raw/mmt1.raw \ +raw/morig_speex_8k.raw \ +raw/f2400.raw \ +raw/hts1a_g729a.raw \ +raw/hts2a_g729a.raw \ +raw/hts.raw \ +raw/mmt1_speex_8k.raw \ +raw/forig_g729a.raw \ +raw/hts1a_gsm13k.raw \ +raw/hts2a_gsm13k.raw \ +raw/m2400.raw \ +raw/morig_g729a.raw \ +raw/forig_gsm13k.raw \ +raw/hts1a.raw \ +raw/hts2a.raw \ +raw/mmt1_g729a.raw \ +raw/morig_gsm13k.raw \ +raw/forig.raw \ +raw/hts1a_speex_8k.raw \ +raw/hts2a_speex_8k.raw \ +raw/mmt1_gsm13k.raw \ +raw/morig.raw \ +script/menu.sh \ +script/playraw.sh \ +script/raw2wav.sh \ +script/wav2raw.sh \ +wav/f2400.wav \ +wav/hts1a_c2_v0.1.wav \ +wav/hts1a.wav \ +wav/hts2a_speex_8k.wav \ +wav/mmt1_speex_8k.wav \ +wav/morig.wav \ +wav/forig_speex_8k.wav \ +wav/hts1a_g729a.wav \ +wav/hts2a_c2_v0.1.wav \ +wav/hts2a.wav \ +wav/mmt1.wav \ +wav/forig.wav \ +wav/hts1a_speex_8k.wav \ +wav/hts2a_g729a.wav \ +wav/m2400.wav \ +wav/morig_speex_8k.wav \ +src/globals.c \ +doc/A_m.gif \ +doc/omega_0.gif \ +doc/phi_m.gif \ +doc/s_n.gif \ +doc/s_n.txt \ +unittest/lsp2.txt \ +unittest/lsp7.txt \ +unittest/lspd78.txt \ +unittest/lsp3.txt \ +unittest/lsp8.txt \ +unittest/lspd910.txt \ +unittest/lsp4.txt \ +unittest/lsp9.txt \ +unittest/lsp10.txt \ +unittest/lsp5.txt \ +unittest/lspd123.txt \ +unittest/lsp1.txt \ +unittest/lsp6.txt \ +unittest/lspd456.txt \ +src/codeall.sh \ +src/fq20.sh \ +src/listen1.sh \ +src/listen.sh \ +src/listensim.sh \ +src/sim.sh + + +SUBDIRS = src unittest diff --git a/libs/libcodec2/NEWS b/libs/libcodec2/NEWS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libcodec2/README b/libs/libcodec2/README new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libcodec2/configure.gnu b/libs/libcodec2/configure.gnu new file mode 100644 index 0000000000..c78238de46 --- /dev/null +++ b/libs/libcodec2/configure.gnu @@ -0,0 +1,4 @@ +#! /bin/sh +srcpath=$(dirname $0 2>/dev/null ) || srcpath="." +$srcpath/configure "$@" --disable-shared --with-pic + diff --git a/libs/libcodec2/configure.in b/libs/libcodec2/configure.in new file mode 100644 index 0000000000..378ef5f2b9 --- /dev/null +++ b/libs/libcodec2/configure.in @@ -0,0 +1,26 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.59]) +AC_INIT(libcodec2, 1.0, david@rowetel.com) +AM_INIT_AUTOMAKE(libcodec2,1.0) + +# Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL + +# Checks for libraries. +# FIXME: Replace `main' with a function in `-lm': +AC_CHECK_LIB([m], [main]) + +# Checks for header files. +AC_CHECK_HEADERS([stdlib.h string.h]) + +# Checks for typedefs, structures, and compiler characteristics. + +# Checks for library functions. +AC_FUNC_MALLOC +AC_CHECK_FUNCS([floor pow sqrt]) + +AC_CONFIG_FILES([Makefile src/Makefile unittest/Makefile]) +AC_OUTPUT diff --git a/libs/libcodec2/doc/A_m.gif b/libs/libcodec2/doc/A_m.gif new file mode 100644 index 0000000000..47b89bd6c9 Binary files /dev/null and b/libs/libcodec2/doc/A_m.gif differ diff --git a/libs/libcodec2/doc/omega_0.gif b/libs/libcodec2/doc/omega_0.gif new file mode 100644 index 0000000000..02877e09d7 Binary files /dev/null and b/libs/libcodec2/doc/omega_0.gif differ diff --git a/libs/libcodec2/doc/phi_m.gif b/libs/libcodec2/doc/phi_m.gif new file mode 100644 index 0000000000..3f2fd57e52 Binary files /dev/null and b/libs/libcodec2/doc/phi_m.gif differ diff --git a/libs/libcodec2/doc/s_n.gif b/libs/libcodec2/doc/s_n.gif new file mode 100644 index 0000000000..c739ab4de1 Binary files /dev/null and b/libs/libcodec2/doc/s_n.gif differ diff --git a/libs/libcodec2/doc/s_n.txt b/libs/libcodec2/doc/s_n.txt new file mode 100644 index 0000000000..fec16b3a31 --- /dev/null +++ b/libs/libcodec2/doc/s_n.txt @@ -0,0 +1 @@ +s(n)=A_1cos(\omega_0+\phi_1)+A_2cos(2\omega_0+\phi_2)+...+A_Lcos(L\omega_0+\phi_L) diff --git a/libs/libcodec2/octave/glottal.m b/libs/libcodec2/octave/glottal.m new file mode 100644 index 0000000000..2b823c37e3 --- /dev/null +++ b/libs/libcodec2/octave/glottal.m @@ -0,0 +1,25 @@ +% glottal.m +% David Rowe 12 Sep 2009 +% Matlab script to generate the phase spectra of a glottal pulse + +% lpc10 pulse from spandsp. When the file glottal.c was used as a part of the +% excitation phase component in phase.c, phase_synth_zero_order(), no difference +% in speech quality was apparent. So left out of code for now. + +sh=12 +kexc = [ 8, -16, 26, -48, 86, -162, 294, -502, 718, -728, 184 672, -610, -672, 184, 728, 718, 502, 294, 162, 86, 48, 26, 16, 8]; +kexc = shift(kexc,sh); +kexc = [kexc(1:sh) zeros(1,512-25) kexc(sh+1:25)]; +figure(1) +plot(kexc) +figure(2) +G = fft(kexc); +plot((1:256)*(4000/256),unwrap(angle(G(1:256)))) + +f=fopen("glottal.c","wt"); +fprintf(f,"float glottal[]={\n"); +for m=1:255 + fprintf(f," %f,\n",angle(G(m))); +endfor +fprintf(f," %f};\n",angle(G(256))); +fclose(f); diff --git a/libs/libcodec2/octave/load_raw.m b/libs/libcodec2/octave/load_raw.m new file mode 100644 index 0000000000..1f7868d42c --- /dev/null +++ b/libs/libcodec2/octave/load_raw.m @@ -0,0 +1,8 @@ +% load_raw.m +% David Rowe 7 Oct 2009 + +function s = load_raw(fn) + fs=fopen(fn,"rb"); + s = fread(fs,Inf,"short"); + plot(s) +endfunction diff --git a/libs/libcodec2/octave/lsp_pdf.m b/libs/libcodec2/octave/lsp_pdf.m new file mode 100644 index 0000000000..6617066e3d --- /dev/null +++ b/libs/libcodec2/octave/lsp_pdf.m @@ -0,0 +1,50 @@ +% lsp_pdf.m +% David Rowe 2 Oct 2009 +% Plots histograms (PDF estimates) of LSP training data + +function lsp_pdf(lsp) + [r,c] = size(lsp); + + % LSPs + + figure(3); + clf; + [x,y] = hist(lsp(:,1),100); + plot(y*4000/pi,x,";1;"); + hold on; + for i=2:c + [x,y] = hist(lsp(:,i),100); + legend = sprintf(";%d;",i); + plot(y*4000/pi,x,legend); + endfor + hold off; + grid; + + % LSP differences + + figure(4); + clf; + subplot(211) + [x,y] = hist(lsp(:,1),100); + plot(y,x,";1;"); + hold on; + for i=2:5 + [x,y] = hist(lsp(:,i) - lsp(:,i-1),100); + legend = sprintf(";%d;",i); + plot(y,x,legend); + endfor + hold off; + grid; + + subplot(212) + [x,y] = hist(lsp(:,6)-lsp(:,5),100); + plot(y,x,";6;"); + hold on; + for i=7:c + [x,y] = hist(lsp(:,i) - lsp(:,i-1),100); + legend = sprintf(";%d;",i); + plot(y,x,legend); + endfor + hold off; + grid; +endfunction diff --git a/libs/libcodec2/octave/phase.m b/libs/libcodec2/octave/phase.m new file mode 100644 index 0000000000..f973590345 --- /dev/null +++ b/libs/libcodec2/octave/phase.m @@ -0,0 +1,56 @@ +% phase.m +% David Rowe August 2009 +% experiments with phase for sinusoidal codecs + +function phase(samname, F0, png) + Wo=2*pi*F0/8000; + P=2*pi/Wo; + L = floor(pi/Wo); + Nsam = 16000; + N = 80; + F = Nsam/N; + A = 10000/L; + phi = zeros(1,L); + s = zeros(1,Nsam); + + for m=floor(L/2):L + phi_off(m) = -m*Wo*8; + end + + for f=1:F + phi(1) = phi(1) + Wo*N; + phi(1) = mod(phi(1),2*pi); + + for m=1:L + phi(m) = m*phi(1); + end + + x = zeros(1,N); + for m=1:L + x = x + A*cos(m*Wo*(0:(N-1)) + phi(m)); + endfor + s((f-1)*N+1:f*N) = x; + endfor + + figure(1); + clf; + plot(s(1:250)); + + fs=fopen(samname,"wb"); + fwrite(fs,s,"short"); + fclose(fs); + + if (nargin == 3) + % small image to fit blog + + __gnuplot_set__ terminal png size 450,300 + ss = sprintf("__gnuplot_set__ output \"%s.png\"", samname); + eval(ss) + replot; + + % for some reason I need this to stop large plot getting wiped + __gnuplot_set__ output "/dev/null" + endif + +endfunction + diff --git a/libs/libcodec2/octave/phase2.m b/libs/libcodec2/octave/phase2.m new file mode 100644 index 0000000000..ea58dcbe11 --- /dev/null +++ b/libs/libcodec2/octave/phase2.m @@ -0,0 +1,50 @@ +% phase2.m +% David Rowe Sep 2009 +% experiments with phase for sinusoidal codecs, looking at phase +% of excitation with real Am samples from hts1 + +function phase2(samname, png) + N = 16000; + + f=45; + model = load("../src/hts1a_model.txt"); + phase = load("../src/hts1a_phase_phase.txt"); + Wo = model(f,1); + P=2*pi/Wo; + L = model(f,2); + A = model(f,3:(L+2)); + phi = phase(f,1:L); + phi = zeros(1,L); + for m=L/2:L + phi(m) = 2*pi*rand(1,1); + end + + s = zeros(1,N); + + for m=1:L + s_m = A(m)*cos(m*Wo*(0:(N-1)) + phi(m)); + s = s + s_m; + endfor + + figure(1); + clf; + plot(s(1:250)); + + fs=fopen(samname,"wb"); + fwrite(fs,s,"short"); + fclose(fs); + + if (nargin == 2) + % small image to fit blog + + __gnuplot_set__ terminal png size 450,300 + ss = sprintf("__gnuplot_set__ output \"%s.png\"", samname); + eval(ss) + replot; + + % for some reason I need this to stop large plot getting wiped + __gnuplot_set__ output "/dev/null" + endif + +endfunction + diff --git a/libs/libcodec2/octave/pitch_test.m b/libs/libcodec2/octave/pitch_test.m new file mode 100644 index 0000000000..3fe0d1ad66 --- /dev/null +++ b/libs/libcodec2/octave/pitch_test.m @@ -0,0 +1,39 @@ +% pitch_test.m +% David Rowe Sep 2009 +% Constructs a sequence to test the pitch estimator + +function pitch_test(samname) + M=320; + F=200; + + fs=fopen(samname,"wb"); + + f0 = 100; + for f=1:200 + Wo=2*pi*f0/8000; + P=2*pi/Wo; + L = floor(pi/Wo); + A = 10000/L; + phi = zeros(1,L); + s = zeros(1,M); + + for m=1:L + s = s + A*cos(m*Wo*(0:(M-1)) + phi(m)); + endfor + + figure(1); + clf; + plot(s); + + fwrite(fs,s,"short"); + + f0 = f0 + 5; + if (f0 > 400) + f0 = 100; + endif + endfor + + fclose(fs); + +endfunction + diff --git a/libs/libcodec2/octave/pl.m b/libs/libcodec2/octave/pl.m new file mode 100644 index 0000000000..49968961d4 --- /dev/null +++ b/libs/libcodec2/octave/pl.m @@ -0,0 +1,42 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 + +function pl(samname1, start_sam, end_sam, pngname) + + fs=fopen(samname1,"rb"); + s=fread(fs,Inf,"short"); + + st = 1; + en = length(s); + if (nargin >= 2) + st = start_sam; + endif + if (nargin >= 3) + en = end_sam; + endif + + figure(1); + clf; + plot(s(st:en)); + axis([1 en-st min(s) max(s)]); + + if (nargin == 4) + + % small image + + __gnuplot_set__ terminal png size 420,300 + ss = sprintf("__gnuplot_set__ output \"%s.png\"", pngname); + eval(ss) + replot; + + % larger image + + __gnuplot_set__ terminal png size 800,600 + ss = sprintf("__gnuplot_set__ output \"%s_large.png\"", pngname); + eval(ss) + replot; + + endif + +endfunction diff --git a/libs/libcodec2/octave/pl2.m b/libs/libcodec2/octave/pl2.m new file mode 100644 index 0000000000..6e6d37aab8 --- /dev/null +++ b/libs/libcodec2/octave/pl2.m @@ -0,0 +1,50 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 + +function pl2(samname1, samname2, start_sam, end_sam, pngname) + + fs1=fopen(samname1,"rb"); + s1=fread(fs1,Inf,"short"); + fs2=fopen(samname2,"rb"); + s2=fread(fs2,Inf,"short"); + + st = 1; + en = length(s1); + if (nargin >= 3) + st = start_sam; + endif + if (nargin >= 4) + en = end_sam; + endif + + figure(1); + clf; + subplot(211); + l1 = strcat("r;",samname1,";"); + plot(s1(st:en), l1); + axis([1 en-st min(s1(st:en)) max(s1(st:en))]); + subplot(212); + l2 = strcat("r;",samname2,";"); + plot(s2(st:en),l2); + axis([1 en-st min(s1(st:en)) max(s1(st:en))]); + + if (nargin == 5) + + % small image + + __gnuplot_set__ terminal png size 420,300 + s = sprintf("__gnuplot_set__ output \"%s.png\"", pngname); + eval(s) + replot; + + % larger image + + __gnuplot_set__ terminal png size 800,600 + s = sprintf("__gnuplot_set__ output \"%s_large.png\"", pngname); + eval(s) + replot; + + endif + +endfunction diff --git a/libs/libcodec2/octave/plamp.m b/libs/libcodec2/octave/plamp.m new file mode 100644 index 0000000000..892830f032 --- /dev/null +++ b/libs/libcodec2/octave/plamp.m @@ -0,0 +1,166 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plot ampltiude modelling information from dump files. + +function plamp(samname, f) + + sn_name = strcat(samname,"_sn.txt"); + Sn = load(sn_name); + + sw_name = strcat(samname,"_sw.txt"); + Sw = load(sw_name); + + sw__name = strcat(samname,"_sw_.txt"); + if (file_in_path(".",sw__name)) + Sw_ = load(sw__name); + endif + + model_name = strcat(samname,"_model.txt"); + model = load(model_name); + + modelq_name = strcat(samname,"_qmodel.txt"); + if (file_in_path(".",modelq_name)) + modelq = load(modelq_name); + endif + + pw_name = strcat(samname,"_pw.txt"); + if (file_in_path(".",pw_name)) + Pw = load(pw_name); + endif + + lsp_name = strcat(samname,"_lsp.txt"); + if (file_in_path(".",lsp_name)) + lsp = load(lsp_name); + endif + + phase_name = strcat(samname,"_phase.txt"); + if (file_in_path(".",phase_name)) + phase = load(phase_name); + endif + + phase_name_ = strcat(samname,"_phase_.txt"); + if (file_in_path(".",phase_name_)) + phase_ = load(phase_name_); + endif + + snr_name = strcat(samname,"_snr.txt"); + if (file_in_path(".",snr_name)) + snr = load(snr_name); + endif + + k = ' '; + do + figure(1); + clf; +% s = [ Sn(2*(f-2)-1,:) Sn(2*(f-2),:) ]; + s = [ Sn(2*f-1,:) Sn(2*f,:) ]; + plot(s); + axis([1 length(s) -20000 20000]); + + figure(2); + Wo = model(f,1); + L = model(f,2); + Am = model(f,3:(L+2)); + plot((1:L)*Wo*4000/pi, 20*log10(Am),";Am;r"); + axis([1 4000 -10 80]); + hold on; +% plot((0:255)*4000/256, Sw(f-2,:),";Sw;"); + plot((0:255)*4000/256, Sw(f,:),";Sw;"); + + if (file_in_path(".",modelq_name)) + Amq = modelq(f,3:(L+2)); + plot((1:L)*Wo*4000/pi, 20*log10(Amq),";Amq;g" ); + if (file_in_path(".",pw_name)) + plot((0:255)*4000/256, 10*log10(Pw(f,:)),";Pw;c"); + endif + signal = Am * Am'; + noise = (Am-Amq) * (Am-Amq)'; + snr1 = 10*log10(signal/noise); + Am_err_label = sprintf(";Am error SNR %4.2f dB;m",snr1); + plot((1:L)*Wo*4000/pi, 20*log10(Amq) - 20*log10(Am), Am_err_label); + endif + + if (file_in_path(".",snr_name)) + snr_label = sprintf(";phase SNR %4.2f dB;",snr(f)); + plot(1,1,snr_label); + endif + + % phase model - determine SNR and error spectrum for phase model 1 + + if (file_in_path(".",phase_name_)) + orig = Am.*exp(j*phase(f,1:L)); + synth = Am.*exp(j*phase_(f,1:L)); + signal = orig * orig'; + noise = (orig-synth) * (orig-synth)'; + snr_phase = 10*log10(signal/noise); + + phase_err_label = sprintf(";phase_err SNR %4.2f dB;",snr_phase); + plot((1:L)*Wo*4000/pi, 20*log10(orig-synth), phase_err_label); + endif + + if (file_in_path(".",lsp_name)) + for l=1:10 + plot([lsp(f,l)*4000/pi lsp(f,l)*4000/pi], [60 80], 'r'); + endfor + endif + + hold off; + + if (file_in_path(".",phase_name)) + figure(3); + plot((1:L)*Wo*4000/pi, phase(f,1:L), ";phase;"); + axis; + if (file_in_path(".",phase_name_)) + hold on; + plot((1:L)*Wo*4000/pi, phase_(f,1:L), ";phase_;"); + hold off; + endif + figure(2); + endif + + % autocorrelation function to research voicing est + + %M = length(s); + %sw = s .* hanning(M)'; + %for k=0:159 + % R(k+1) = sw(1:320-k) * sw(1+k:320)'; + %endfor + %figure(4); + %R_label = sprintf(";R(k) %3.2f;",max(R(20:159))/R(1)); + %plot(R/R(1),R_label); + %grid + + % interactive menu + + printf("\rframe: %d menu: n-next b-back p-png q-quit ", f); + fflush(stdout); + k = kbhit(); + if (k == 'n') + f = f + 1; + endif + if (k == 'b') + f = f - 1; + endif + + % optional print to PNG + + if (k == 'p') + figure(1); + pngname = sprintf("%s_%d_sn.png",samname,f); + print(pngname, '-dpng', "-S500,500") + pngname = sprintf("%s_%d_sn_large.png",samname,f); + print(pngname, '-dpng', "-S800,600") + + figure(2); + pngname = sprintf("%s_%d_sw.png",samname,f); + print(pngname, '-dpng', "-S500,500") + pngname = sprintf("%s_%d_sw_large.png",samname,f); + print(pngname, '-dpng', "-S800,600") + endif + + until (k == 'q') + printf("\n"); + +endfunction diff --git a/libs/libcodec2/octave/plinterp.m b/libs/libcodec2/octave/plinterp.m new file mode 100644 index 0000000000..794a0853b2 --- /dev/null +++ b/libs/libcodec2/octave/plinterp.m @@ -0,0 +1,11 @@ +load ../unittest/tinterp_prev.txt; +load ../unittest/tinterp_interp.txt; +load ../unittest/tinterp_next.txt; + +clf; +plot(tinterp_prev(:,1), 20.0*log10(tinterp_prev(:,2)),";prev;") +hold on; +plot(tinterp_interp(:,1), 20.0*log10(tinterp_interp(:,2)),'g+-;interp;') +plot(tinterp_next(:,1), 20.0*log10(tinterp_next(:,2)),'ro-;next;') +hold off; +axis([0 pi 0 80]) diff --git a/libs/libcodec2/octave/plnlp.m b/libs/libcodec2/octave/plnlp.m new file mode 100644 index 0000000000..01b493113b --- /dev/null +++ b/libs/libcodec2/octave/plnlp.m @@ -0,0 +1,134 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plot NLP states from dump files. + +function plnlp(samname, f) + + sn_name = strcat(samname,"_sn.txt"); + Sn = load(sn_name); + + sw_name = strcat(samname,"_sw.txt"); + Sw = load(sw_name); + + fw_name = strcat(samname,"_fw.txt"); + if (file_in_path(".",fw_name)) + fw = load(fw_name); + endif + + e_name = strcat(samname,"_e.txt"); + if (file_in_path(".",e_name)) + e = load(e_name); + endif + + p_name = strcat(samname,".p"); + if (file_in_path(".",p_name)) + p = load(p_name); + endif + + sq_name = strcat(samname,"_sq.txt"); + if (file_in_path(".",sq_name)) + sq = load(sq_name); + endif + + dec_name = strcat(samname,"_dec.txt"); + if (file_in_path(".",dec_name)) + dec = load(dec_name); + endif + + do + figure(1); + clf; + s = [ Sn(2*f-1,:) Sn(2*f,:) ]; + plot(s, ";Sn;"); + grid + axis([1 length(s) -20000 20000]); + + figure(2); + plot((0:255)*4000/256, Sw(f,:),";Sw;"); + grid + axis([1 4000 -10 80]); + hold on; + + f0 = 8000/p(f); + Wo = 2*pi/p(f); + L = floor(pi/Wo); + f0_label = sprintf("b;P=%3.1f F0=%3.0f;",p(f),f0); + for m=1:L-1 + plot([ m*Wo*4000/pi m*Wo*4000/pi], [10 60], 'b'); + endfor + plot([ L*Wo*4000/pi L*Wo*4000/pi], [10 60], f0_label); + + hold off; + + if (file_in_path(".",fw_name)) + figure(3); + if (file_in_path(".",e_name)) + subplot(211); + endif + plot((0:255)*800/256, fw(f,:)/max(fw(f,:)), ";Fw;"); + axis([1 400 0 1]); + if (file_in_path(".",e_name)) + subplot(212); + e_concat = [ e(2*f-1,:) e(2*f,:) ]; + plot(e_concat(1:400)/max(e_concat(1:400)), "+;MBE E(f);"); + axis([1 400 0 1]); + endif + endif + + if (file_in_path(".",sq_name)) + figure(4); + sq_concat = [ sq(2*f-1,:) sq(2*f,:) ]; + axis + plot(sq_concat, ";sq;"); + endif + + if (file_in_path(".",dec_name)) + figure(5); + plot(dec(f,:), ";dec;"); + endif + + figure(2); + + % interactive menu + + printf("\rframe: %d menu: n-next b-back p-png q-quit ", f); + fflush(stdout); + k = kbhit(); + if (k == 'n') + f = f + 1; + endif + if (k == 'b') + f = f - 1; + endif + + % optional print to PNG + + if (k == 'p') + + pngname = sprintf("%s_%d",samname,f); + + % small image + + __gnuplot_set__ terminal png size 420,300 + ss = sprintf("__gnuplot_set__ output \"%s.png\"", pngname); + eval(ss) + replot; + + % larger image + + __gnuplot_set__ terminal png size 800,600 + ss = sprintf("__gnuplot_set__ output \"%s_large.png\"", pngname); + eval(ss) + replot; + + % for some reason I need this to stop large plot getting wiped + __gnuplot_set__ output "/dev/null" + + endif + + until (k == 'q') + printf("\n"); + +endfunction diff --git a/libs/libcodec2/octave/plphase.m b/libs/libcodec2/octave/plphase.m new file mode 100644 index 0000000000..9e61185676 --- /dev/null +++ b/libs/libcodec2/octave/plphase.m @@ -0,0 +1,198 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plot phase modelling information from dump files. + +function plphase(samname, f) + + sn_name = strcat(samname,"_sn.txt"); + Sn = load(sn_name); + + sw_name = strcat(samname,"_sw.txt"); + Sw = load(sw_name); + + model_name = strcat(samname,"_model.txt"); + model = load(model_name); + + sw__name = strcat(samname,"_sw_.txt"); + if (file_in_path(".",sw__name)) + Sw_ = load(sw__name); + endif + + pw_name = strcat(samname,"_pw.txt"); + if (file_in_path(".",pw_name)) + Pw = load(pw_name); + endif + + ak_name = strcat(samname,"_ak.txt"); + if (file_in_path(".",ak_name)) + ak = load(ak_name); + endif + + phase_name = strcat(samname,"_phase.txt"); + if (file_in_path(".",phase_name)) + phase = load(phase_name); + endif + + phase_name_ = strcat(samname,"_phase_.txt"); + if (file_in_path(".",phase_name_)) + phase_ = load(phase_name_); + endif + + snr_name = strcat(samname,"_snr.txt"); + if (file_in_path(".",snr_name)) + snr = load(snr_name); + endif + + sn_name_ = strcat(samname,".raw"); + if (file_in_path(".",sn_name_)) + fs_ = fopen(sn_name_,"rb"); + sn_ = fread(fs_,Inf,"short"); + endif + + k = ' '; + do + figure(1); + clf; + s = [ Sn(2*f-1,:) Sn(2*f,:) ]; + plot(s); + grid; + axis([1 length(s) -20000 20000]); + if (k == 'p') + pngname = sprintf("%s_%d_sn",samname,f); + png(pngname); + endif + + figure(2); + Wo = model(f,1); + L = model(f,2); + Am = model(f,3:(L+2)); + plot((1:L)*Wo*4000/pi, 20*log10(Am),"r;Am;"); + axis([1 4000 -10 80]); + hold on; + plot((0:255)*4000/256, Sw(f,:),";Sw;"); + grid; + + if (file_in_path(".",sw__name)) + plot((0:255)*4000/256, Sw_(f,:),"g;Sw_;"); + endif + + if (file_in_path(".",pw_name)) + plot((0:255)*4000/256, 10*log10(Pw(f,:)),";Pw;"); + endif + + if (file_in_path(".",snr_name)) + snr_label = sprintf(";phase SNR %4.2f dB;",snr(f)); + plot(1,1,snr_label); + endif + + % phase model - determine SNR and error spectrum for phase model 1 + + if (file_in_path(".",phase_name_)) + orig = Am.*exp(j*phase(f,1:L)); + synth = Am.*exp(j*phase_(f,1:L)); + signal = orig * orig'; + noise = (orig-synth) * (orig-synth)'; + snr_phase = 10*log10(signal/noise); + + phase_err_label = sprintf("g;phase_err SNR %4.2f dB;",snr_phase); + plot((1:L)*Wo*4000/pi, 20*log10(orig-synth), phase_err_label); + endif + + hold off; + if (k == 'p') + pngname = sprintf("%s_%d_sw",samname,f); + png(pngname); + endif + + if (file_in_path(".",phase_name)) + figure(3); + plot((1:L)*Wo*4000/pi, phase(f,1:L)*180/pi, "-o;phase;"); + axis; + if (file_in_path(".", phase_name_)) + hold on; + plot((1:L)*Wo*4000/pi, phase_(f,1:L)*180/pi, "g;phase_;"); + grid + hold off; + endif + if (k == 'p') + pngname = sprintf("%s_%d_phase",samname,f); + png(pngname); + endif + endif + + % synthesised speech + + if (file_in_path(".",sn_name_)) + figure(4); + s_ = sn_((f-3)*80+1:(f+1)*80); + plot(s_); + axis([1 length(s_) -20000 20000]); + if (k == 'p') + pngname = sprintf("%s_%d_sn_",samname,f) + png(pngname); + endif + endif + + if (file_in_path(".",ak_name)) + figure(5); + axis; + akw = ak(f,:); + weight = 1.0 .^ (0:length(akw)-1); + akw = akw .* weight; + H = 1./fft(akw,8000); + subplot(211); + plot(20*log10(abs(H(1:4000))),";LPC mag spec;"); + grid; + subplot(212); + plot(angle(H(1:4000))*180/pi,";LPC phase spec;"); + grid; + if (k == 'p') + % stops multimode errors from gnuplot, I know not why... + figure(2); + figure(5); + + pngname = sprintf("%s_%d_lpc",samname,f); + png(pngname); + endif + endif + + + % autocorrelation function to research voicing est + + %M = length(s); + %sw = s .* hanning(M)'; + %for k=0:159 + % R(k+1) = sw(1:320-k) * sw(1+k:320)'; + %endfor + %figure(4); + %R_label = sprintf(";R(k) %3.2f;",max(R(20:159))/R(1)); + %plot(R/R(1),R_label); + %grid + + figure(2); + + % interactive menu + + printf("\rframe: %d menu: n-next b-back p-png q-quit ", f); + fflush(stdout); + k = kbhit(); + if (k == 'n') + f = f + 1; + endif + if (k == 'b') + f = f - 1; + endif + + % optional print to PNG + + if (k == 'p') + pngname = sprintf("%s_%d",samname,f); + png(pngname); + endif + + until (k == 'q') + printf("\n"); + +endfunction diff --git a/libs/libcodec2/octave/plpitch.m b/libs/libcodec2/octave/plpitch.m new file mode 100644 index 0000000000..69ad533890 --- /dev/null +++ b/libs/libcodec2/octave/plpitch.m @@ -0,0 +1,36 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% plpitch.m +% Plots two pitch tracks on top of each other, used for comparing pitch +% estimators + +function plpitch(pitch1_name, pitch2_name, start_fr, end_fr) + + pitch1 = load(pitch1_name); + pitch2 = load(pitch2_name); + + st = 1; + en = length(pitch1); + if (nargin >= 3) + st = start_fr; + endif + if (nargin >= 4) + en = end_fr; + endif + + figure(1); + clf; + l1 = strcat("r;",pitch1_name,";") + l1 + st + en + plot(pitch1(st:en), l1); + axis([1 en-st 20 160]); + l2 = strcat("g;",pitch2_name,";"); + hold on; + plot(pitch2(st:en),l2); + hold off; +endfunction + diff --git a/libs/libcodec2/octave/png.m b/libs/libcodec2/octave/png.m new file mode 100644 index 0000000000..09a79968c6 --- /dev/null +++ b/libs/libcodec2/octave/png.m @@ -0,0 +1,25 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Replot current plot as a png, generates small and large versions + +function png(pngname) + % small image + + __gnuplot_set__ terminal png size 420,300 + ss = sprintf("__gnuplot_set__ output \"%s.png\"", pngname); + eval(ss) + replot; + + % larger image + + __gnuplot_set__ terminal png size 800,600 + ss = sprintf("__gnuplot_set__ output \"%s_large.png\"", pngname); + eval(ss) + replot; + + % for some reason I need this to stop large plot getting wiped + __gnuplot_set__ output "/dev/null" + +endfunction diff --git a/libs/libcodec2/octave/postfilter.m b/libs/libcodec2/octave/postfilter.m new file mode 100644 index 0000000000..84f7dfc773 --- /dev/null +++ b/libs/libcodec2/octave/postfilter.m @@ -0,0 +1,24 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plot postfilter doing its thing + +function postfilter(samname) + p = load(samname); + figure(1); + plot(p(:,1),";energy;"); + hold on; + plot(p(:,2),";bg_est;"); + hold off; + grid; + pngname=sprintf("%s_postfilter_1", samname); + png(pngname); + + figure(2); + plot(p(:,3),";% unvoiced;"); + grid; + pngname=sprintf("%s_postfilter_2", samname); + png(pngname); +endfunction + diff --git a/libs/libcodec2/octave/pulse.m b/libs/libcodec2/octave/pulse.m new file mode 100644 index 0000000000..223389e777 --- /dev/null +++ b/libs/libcodec2/octave/pulse.m @@ -0,0 +1,37 @@ +% pulse.m +% David Rowe August 2009 +% +% Experiments with human pulse perception for sinusoidal codecs + +function pulse(samname) + + A = 1000; + K = 16000; + N = 80; + frames = K/N; + s = zeros(1,K); + + for f=1:frames + % lets try placing np random pulses in every frame + + P = 20 + (160-20)*rand(1,1); + Wo = 2*pi/P; + L = floor(pi/Wo); + sf = zeros(1,N); + for m=1:L/2:L + pos = floor(rand(1,1)*N)+1; + %pos = 50; + for l=m:m+L/2-1 + sf = sf + A*cos(l*Wo*((f-1)*N+1:f*N) - pos*l*Wo); + endfor + endfor + s((f-1)*N+1:f*N) = sf; + endfor + + plot(s(1:250)); + + fs=fopen(samname,"wb"); + fwrite(fs,s,"short"); + fclose(fs); +endfunction + diff --git a/libs/libcodec2/pitch/hts1a.p b/libs/libcodec2/pitch/hts1a.p new file mode 100644 index 0000000000..c11b8e90fc --- /dev/null +++ b/libs/libcodec2/pitch/hts1a.p @@ -0,0 +1,298 @@ +111.627907 +97.959183 +97.959183 +97.959183 +87.272736 +78.048775 +112.280701 +120.000008 +61.538464 +68.817207 +84.210526 +90.140846 +90.140846 +90.140846 +101.587303 +80.000000 +72.727272 +95.522392 +90.140846 +90.140846 +101.587303 +90.140846 +85.333336 +86.486488 +91.428574 +91.428574 +91.428574 +91.428574 +91.428574 +90.140846 +86.486488 +86.486488 +85.333336 +85.333336 +85.333336 +81.012657 +74.418610 +71.111115 +71.111115 +71.111115 +71.111115 +68.085106 +68.085106 +67.368423 +67.368423 +70.329674 +70.329674 +70.329674 +71.111115 +74.418610 +74.418610 +75.294121 +79.012352 +85.333336 +96.969704 +111.627907 +111.627907 +120.000008 +111.627907 +104.347832 +104.347832 +97.959183 +104.347832 +104.347832 +104.347832 +104.347832 +104.347832 +104.347832 +104.347832 +104.347832 +97.959183 +97.959183 +112.280701 +112.280701 +96.969704 +96.969704 +96.969704 +110.344841 +104.347832 +97.959183 +97.959183 +104.347832 +97.959183 +104.347832 +120.000008 +104.347832 +120.000008 +120.000008 +97.959183 +83.116882 +75.294121 +71.910118 +71.910110 +71.910110 +71.910110 +75.294121 +76.190483 +80.000008 +80.000008 +84.210526 +85.333336 +90.140846 +101.587303 +108.474571 +104.347832 +120.000008 +120.000008 +104.347832 +104.347832 +71.111115 +88.888893 +75.294121 +111.627907 +120.000008 +120.000008 +97.959183 +111.627907 +111.627907 +111.627907 +97.959183 +92.307693 +92.307693 +92.307693 +92.307693 +120.000008 +111.627907 +111.627907 +86.486488 +85.333336 +85.333336 +90.140846 +95.522392 +101.587311 +101.587311 +104.918037 +104.347832 +104.347832 +111.627907 +120.000008 +97.959183 +104.347832 +111.627907 +88.888893 +80.000000 +81.012657 +85.333336 +85.333336 +86.486488 +91.428574 +90.140846 +91.428574 +96.969704 +96.969704 +95.522392 +95.522392 +95.522392 +96.969704 +96.969704 +98.461533 +104.918022 +97.959183 +97.959183 +97.959183 +104.347832 +120.000008 +120.000008 +92.307693 +92.307693 +77.108429 +79.012344 +75.294121 +75.294121 +76.190483 +76.190483 +80.000008 +81.012657 +85.333336 +85.333336 +85.333336 +85.333336 +85.333336 +90.140846 +90.140846 +91.428574 +96.969704 +98.461533 +120.000008 +120.000008 +104.347832 +97.959183 +97.959183 +104.918037 +120.000008 +120.000008 +120.000008 +104.347832 +92.307693 +72.727272 +72.727272 +76.190483 +84.210533 +88.888901 +120.000008 +104.347832 +120.000008 +120.000008 +111.627907 +92.307693 +97.959183 +97.959183 +111.627907 +120.000008 +120.000008 +97.959183 +97.959183 +104.347832 +104.347832 +104.347832 +111.627907 +120.000008 +97.959183 +104.347832 +97.959183 +97.959183 +84.210526 +94.117653 +96.969704 +110.344841 +120.000008 +97.959183 +97.959183 +104.347832 +97.959183 +104.347832 +97.959183 +97.959183 +111.627907 +120.000008 +92.307693 +92.307693 +98.461533 +98.461533 +104.918022 +111.627907 +111.627907 +92.307693 +97.959183 +92.307693 +92.307693 +92.307693 +92.307693 +92.307693 +57.657658 +90.140846 +90.140846 +95.522392 +101.587311 +101.587311 +108.474586 +111.627907 +97.959183 +111.627907 +120.000008 +92.307693 +74.418610 +74.418610 +74.418610 +74.418610 +76.190483 +72.727280 +76.190483 +76.190483 +69.565224 +66.666672 +54.700855 +56.637169 +56.637169 +71.910110 +90.140846 +90.140846 +72.727272 +72.727272 +72.727272 +72.727272 +55.172413 +57.142857 +55.172413 +90.140846 +95.522392 +101.587311 +101.587311 +71.910110 +74.418610 +46.376812 +40.000000 +95.522392 +0 +0 diff --git a/libs/libcodec2/pitch/hts2a.p b/libs/libcodec2/pitch/hts2a.p new file mode 100644 index 0000000000..20e2680487 --- /dev/null +++ b/libs/libcodec2/pitch/hts2a.p @@ -0,0 +1,300 @@ + 0.0000000e+000 + 9.2753623e+001 + 5.4237288e+001 + 8.5906040e+001 + 7.0329670e+001 + 5.5652174e+001 + 5.4237288e+001 + 5.4935622e+001 + 5.4700855e+001 + 7.5739645e+001 + 7.3563218e+001 + 1.2307692e+002 + 1.1428571e+002 + 7.3563218e+001 + 7.7108434e+001 + 1.8550725e+002 + 1.2673267e+002 + 1.0847458e+002 + 7.8527607e+001 + 8.8888889e+001 + 8.3116883e+001 + 8.1012658e+001 + 1.0756303e+002 + 1.3061224e+002 + 4.8301887e+001 + 4.7940075e+001 + 4.8120301e+001 + 4.9230769e+001 + 4.9420849e+001 + 4.6886447e+001 + 4.2953020e+001 + 3.9263804e+001 + 3.7869822e+001 + 3.5457064e+001 + 3.4224599e+001 + 3.3333333e+001 + 3.2820513e+001 + 3.2000000e+001 + 3.1295844e+001 + 2.9906542e+001 + 2.9493088e+001 + 2.9090909e+001 + 2.8699552e+001 + 2.8131868e+001 + 2.7826087e+001 + 2.7826087e+001 + 2.7826087e+001 + 2.8193833e+001 + 2.7467811e+001 + 2.6890756e+001 + 5.4468085e+001 + 5.4237288e+001 + 6.4974619e+001 + 1.0756303e+002 + 8.8888889e+001 + 1.0406504e+002 + 4.4599303e+001 + 5.4468085e+001 + 3.6260623e+001 + 3.6260623e+001 + 8.1012658e+001 + 7.0329670e+001 + 1.2929293e+002 + 9.9224806e+001 + 4.3097643e+001 + 4.4137931e+001 + 4.5714286e+001 + 4.7407407e+001 + 4.8301887e+001 + 4.9230769e+001 + 4.9420849e+001 + 5.0996016e+001 + 5.1405622e+001 + 5.1405622e+001 + 5.2244898e+001 + 5.2459016e+001 + 5.2459016e+001 + 5.2244898e+001 + 5.3333333e+001 + 5.2459016e+001 + 5.2244898e+001 + 5.1405622e+001 + 5.1405622e+001 + 5.1200000e+001 + 5.0996016e+001 + 5.0196078e+001 + 4.9230769e+001 + 4.9230769e+001 + 4.9230769e+001 + 4.9420849e+001 + 4.9230769e+001 + 4.9042146e+001 + 9.8461538e+001 + 1.0158730e+002 + 5.1821862e+001 + 9.0140845e+001 + 1.0491803e+002 + 1.4382022e+002 + 5.2459016e+001 + 5.2459016e+001 + 1.2929293e+002 + 1.6410256e+002 + 8.0000000e+001 + 7.3563218e+001 + 1.0158730e+002 + 9.9224806e+001 + 4.9042146e+001 + 4.9042146e+001 + 4.9042146e+001 + 5.9259259e+001 + 1.4382022e+002 + 7.2316384e+001 + 1.0847458e+002 + 1.1228070e+002 + 1.6202532e+002 + 8.1528662e+001 + 7.2727273e+001 + 1.8550725e+002 + 6.0093897e+001 + 1.0847458e+002 + 8.9510490e+001 + 7.1508380e+001 + 4.0125392e+001 + 4.0634921e+001 + 4.0634921e+001 + 4.0251572e+001 + 4.0506329e+001 + 4.3986254e+001 + 4.0506329e+001 + 9.8461538e+001 + 5.6140351e+001 + 6.5641026e+001 + 5.4237288e+001 + 1.1636364e+002 + 3.4316354e+001 + 3.4972678e+001 + 3.7758112e+001 + 4.0634921e+001 + 4.0506329e+001 + 4.1290323e+001 + 4.2524917e+001 + 4.3389831e+001 + 4.4599303e+001 + 4.4912281e+001 + 4.6545455e+001 + 4.7232472e+001 + 4.8301887e+001 + 4.9230769e+001 + 4.9420849e+001 + 5.0393701e+001 + 5.1405622e+001 + 5.3333333e+001 + 5.3112033e+001 + 1.1034483e+002 + 9.7709924e+001 + 1.4382022e+002 + 5.0996016e+001 + 5.1821862e+001 + 5.0996016e+001 + 5.2032520e+001 + 5.3112033e+001 + 5.3556485e+001 + 5.4468085e+001 + 5.5652174e+001 + 5.4700855e+001 + 5.4700855e+001 + 5.4935622e+001 + 5.4700855e+001 + 5.4700855e+001 + 5.4468085e+001 + 5.4468085e+001 + 5.4468085e+001 + 5.4468085e+001 + 5.3333333e+001 + 5.1405622e+001 + 5.0996016e+001 + 5.0000000e+001 + 4.8120301e+001 + 4.8669202e+001 + 4.7058824e+001 + 4.6376812e+001 + 4.5070423e+001 + 4.4912281e+001 + 4.4137931e+001 + 4.2809365e+001 + 4.2666667e+001 + 4.2105263e+001 + 4.1423948e+001 + 4.1290323e+001 + 4.1290323e+001 + 4.1290323e+001 + 4.0634921e+001 + 4.0634921e+001 + 4.0634921e+001 + 4.0634921e+001 + 4.0764331e+001 + 4.1423948e+001 + 4.2953020e+001 + 4.5551601e+001 + 1.7534247e+002 + 4.7232472e+001 + 1.3763441e+002 + 1.3061224e+002 + 4.5551601e+001 + 4.3686007e+001 + 4.8669202e+001 + 9.4117647e+001 + 8.1012658e+001 + 1.1228070e+002 + 1.3617021e+002 + 4.3097643e+001 + 4.3835616e+001 + 4.6376812e+001 + 4.6545455e+001 + 4.6043165e+001 + 4.8301887e+001 + 4.9042146e+001 + 4.9420849e+001 + 5.1200000e+001 + 5.1405622e+001 + 5.2244898e+001 + 1.2929293e+002 + 1.2929293e+002 + 1.5238095e+002 + 1.5238095e+002 + 1.3913043e+002 + 9.0140845e+001 + 1.0940171e+002 + 9.0140845e+001 + 1.2307692e+002 + 8.9510490e+001 + 6.9565217e+001 + 7.3142857e+001 + 1.1034483e+002 + 7.8048780e+001 + 7.2727273e+001 + 1.0078740e+002 + 1.0940171e+002 + 1.1743119e+002 + 8.7074830e+001 + 1.8550725e+002 + 6.5306122e+001 + 1.3617021e+002 + 5.2674897e+001 + 1.0940171e+002 + 1.5238095e+002 + 1.4065934e+002 + 1.0756303e+002 + 1.0406504e+002 + 5.0793651e+001 + 4.9420849e+001 + 4.4444444e+001 + 7.0329670e+001 + 7.2727273e+001 + 7.4418605e+001 + 1.1636364e+002 + 1.0406504e+002 + 1.2307692e+002 + 1.2549020e+002 + 1.7297297e+002 + 4.5878136e+001 + 4.9805447e+001 + 6.2745098e+001 + 9.2086331e+001 + 9.1428571e+001 + 5.7142857e+001 + 4.8484848e+001 + 4.1157556e+001 + 2.2857143e+001 + 3.0046948e+001 + 9.4814815e+001 + 5.7918552e+001 + 9.0140845e+001 + 7.4418605e+001 + 7.4418605e+001 + 5.4700855e+001 + 9.5522388e+001 + 7.4853801e+001 + 9.4117647e+001 + 9.5522388e+001 + 9.9224806e+001 + 8.1012658e+001 + 1.1851852e+002 + 6.8817204e+001 + 8.5906040e+001 + 6.7015707e+001 + 4.3537415e+001 + 6.5306122e+001 + 3.1295844e+001 + 7.5739645e+001 + 6.2135922e+001 + 9.9224806e+001 + 5.7657658e+001 + 5.2244898e+001 + 5.8447489e+001 + 0.0000000e+000 + 0.0000000e+000 + 0.0000000e+000 + 0.0000000e+000 + 0.0000000e+000 diff --git a/libs/libcodec2/raw/b0067.raw b/libs/libcodec2/raw/b0067.raw new file mode 100644 index 0000000000..3aea9cdaaa Binary files /dev/null and b/libs/libcodec2/raw/b0067.raw differ diff --git a/libs/libcodec2/raw/f2400.raw b/libs/libcodec2/raw/f2400.raw new file mode 100644 index 0000000000..5f4427f2fb Binary files /dev/null and b/libs/libcodec2/raw/f2400.raw differ diff --git a/libs/libcodec2/raw/forig.raw b/libs/libcodec2/raw/forig.raw new file mode 100644 index 0000000000..4ba294d788 Binary files /dev/null and b/libs/libcodec2/raw/forig.raw differ diff --git a/libs/libcodec2/raw/forig_g729a.raw b/libs/libcodec2/raw/forig_g729a.raw new file mode 100644 index 0000000000..fbca567b24 Binary files /dev/null and b/libs/libcodec2/raw/forig_g729a.raw differ diff --git a/libs/libcodec2/raw/forig_gsm13k.raw b/libs/libcodec2/raw/forig_gsm13k.raw new file mode 100644 index 0000000000..71cbe6f6de Binary files /dev/null and b/libs/libcodec2/raw/forig_gsm13k.raw differ diff --git a/libs/libcodec2/raw/forig_speex_8k.raw b/libs/libcodec2/raw/forig_speex_8k.raw new file mode 100644 index 0000000000..e95302ef59 Binary files /dev/null and b/libs/libcodec2/raw/forig_speex_8k.raw differ diff --git a/libs/libcodec2/raw/hts.raw b/libs/libcodec2/raw/hts.raw new file mode 100644 index 0000000000..79f869add1 Binary files /dev/null and b/libs/libcodec2/raw/hts.raw differ diff --git a/libs/libcodec2/raw/hts1.raw b/libs/libcodec2/raw/hts1.raw new file mode 100644 index 0000000000..3369387e09 Binary files /dev/null and b/libs/libcodec2/raw/hts1.raw differ diff --git a/libs/libcodec2/raw/hts1a.raw b/libs/libcodec2/raw/hts1a.raw new file mode 100644 index 0000000000..7332f936e4 Binary files /dev/null and b/libs/libcodec2/raw/hts1a.raw differ diff --git a/libs/libcodec2/raw/hts1a_g729a.raw b/libs/libcodec2/raw/hts1a_g729a.raw new file mode 100644 index 0000000000..130f1ddcb1 Binary files /dev/null and b/libs/libcodec2/raw/hts1a_g729a.raw differ diff --git a/libs/libcodec2/raw/hts1a_gsm13k.raw b/libs/libcodec2/raw/hts1a_gsm13k.raw new file mode 100644 index 0000000000..dd102f59c6 Binary files /dev/null and b/libs/libcodec2/raw/hts1a_gsm13k.raw differ diff --git a/libs/libcodec2/raw/hts1a_speex_8k.raw b/libs/libcodec2/raw/hts1a_speex_8k.raw new file mode 100644 index 0000000000..9289e1c923 Binary files /dev/null and b/libs/libcodec2/raw/hts1a_speex_8k.raw differ diff --git a/libs/libcodec2/raw/hts2.raw b/libs/libcodec2/raw/hts2.raw new file mode 100644 index 0000000000..0bb9df1028 Binary files /dev/null and b/libs/libcodec2/raw/hts2.raw differ diff --git a/libs/libcodec2/raw/hts2a.raw b/libs/libcodec2/raw/hts2a.raw new file mode 100644 index 0000000000..6d9cf17bb9 Binary files /dev/null and b/libs/libcodec2/raw/hts2a.raw differ diff --git a/libs/libcodec2/raw/hts2a_g729a.raw b/libs/libcodec2/raw/hts2a_g729a.raw new file mode 100644 index 0000000000..9199b0ad70 Binary files /dev/null and b/libs/libcodec2/raw/hts2a_g729a.raw differ diff --git a/libs/libcodec2/raw/hts2a_gsm13k.raw b/libs/libcodec2/raw/hts2a_gsm13k.raw new file mode 100644 index 0000000000..f0a58505d1 Binary files /dev/null and b/libs/libcodec2/raw/hts2a_gsm13k.raw differ diff --git a/libs/libcodec2/raw/hts2a_speex_8k.raw b/libs/libcodec2/raw/hts2a_speex_8k.raw new file mode 100644 index 0000000000..c421bb4e7d Binary files /dev/null and b/libs/libcodec2/raw/hts2a_speex_8k.raw differ diff --git a/libs/libcodec2/raw/m2400.raw b/libs/libcodec2/raw/m2400.raw new file mode 100644 index 0000000000..1c0956daba Binary files /dev/null and b/libs/libcodec2/raw/m2400.raw differ diff --git a/libs/libcodec2/raw/mmt1.raw b/libs/libcodec2/raw/mmt1.raw new file mode 100644 index 0000000000..40638a5a8e Binary files /dev/null and b/libs/libcodec2/raw/mmt1.raw differ diff --git a/libs/libcodec2/raw/mmt1_g729a.raw b/libs/libcodec2/raw/mmt1_g729a.raw new file mode 100644 index 0000000000..196716e04f Binary files /dev/null and b/libs/libcodec2/raw/mmt1_g729a.raw differ diff --git a/libs/libcodec2/raw/mmt1_gsm13k.raw b/libs/libcodec2/raw/mmt1_gsm13k.raw new file mode 100644 index 0000000000..a9965af376 Binary files /dev/null and b/libs/libcodec2/raw/mmt1_gsm13k.raw differ diff --git a/libs/libcodec2/raw/mmt1_speex_8k.raw b/libs/libcodec2/raw/mmt1_speex_8k.raw new file mode 100644 index 0000000000..769a49cde4 Binary files /dev/null and b/libs/libcodec2/raw/mmt1_speex_8k.raw differ diff --git a/libs/libcodec2/raw/morig.raw b/libs/libcodec2/raw/morig.raw new file mode 100644 index 0000000000..4af0e8f90f Binary files /dev/null and b/libs/libcodec2/raw/morig.raw differ diff --git a/libs/libcodec2/raw/morig_g729a.raw b/libs/libcodec2/raw/morig_g729a.raw new file mode 100644 index 0000000000..636ecfdc7f Binary files /dev/null and b/libs/libcodec2/raw/morig_g729a.raw differ diff --git a/libs/libcodec2/raw/morig_gsm13k.raw b/libs/libcodec2/raw/morig_gsm13k.raw new file mode 100644 index 0000000000..660368fece Binary files /dev/null and b/libs/libcodec2/raw/morig_gsm13k.raw differ diff --git a/libs/libcodec2/raw/morig_speex_8k.raw b/libs/libcodec2/raw/morig_speex_8k.raw new file mode 100644 index 0000000000..ab667a1ba2 Binary files /dev/null and b/libs/libcodec2/raw/morig_speex_8k.raw differ diff --git a/libs/libcodec2/script/menu.sh b/libs/libcodec2/script/menu.sh new file mode 100755 index 0000000000..11297df9b9 --- /dev/null +++ b/libs/libcodec2/script/menu.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# ./menu.sh +# +# David Rowe +# Created August 2009 +# +# Presents a menu of sound files, press 1 to play file1, 2 to play file2 etc +# +# The aim is to make comparing files with different processing easier than +# using up-arrow on the command line. Based on cdialog. +# +# usage: +# menu.sh file1.raw file2.raw ........ [-d playbackdevice] +# +# for example: +# +# ../script/menu.sh hts1a.raw hts1a_uq.raw +# +# or: +# +# ../script/menu.sh hts1a.raw hts1a_uq.raw -d /dev/dsp1 +# + +# Copyright (C) 2007 David Rowe +# +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +files=0 +items="Q-Quit\n" +while [ ! -z "$1" ] +do + case "$1" in + -d) dsp="${1} ${2}"; shift;; + *) files=`expr 1 + $files`; + new_file=$1; + file[$files]=$new_file; + items="${items} ${files}-${new_file}\n";; + esac + shift +done + +readchar=1 +echo -n -e "\r" $items"- " +while [ $readchar -ne 0 ] +do + echo -n -e "\r -" + stty cbreak # or stty raw + readchar=`dd if=/dev/tty bs=1 count=1 2>/dev/null` + stty -cbreak + if [ $readchar == 'q' ] ; then + readchar=0 + fi + if [ $readchar -ne 0 ] ; then + play -r 8000 -s -2 ${file[$readchar]} $dsp 2> /dev/null + fi +done +echo diff --git a/libs/libcodec2/script/playraw.sh b/libs/libcodec2/script/playraw.sh new file mode 100755 index 0000000000..683cbaa16d --- /dev/null +++ b/libs/libcodec2/script/playraw.sh @@ -0,0 +1,6 @@ +#!/bin/sh +# Plays a raw file +# usage: +# playraw file.raw +# playraw file.raw -d /dev/dsp1 (e.g. for USB headphones) +play -r 8000 -s -2 $1 $2 $3 diff --git a/libs/libcodec2/script/raw2wav.sh b/libs/libcodec2/script/raw2wav.sh new file mode 100755 index 0000000000..a05efb72f6 --- /dev/null +++ b/libs/libcodec2/script/raw2wav.sh @@ -0,0 +1,3 @@ +#!/bin/sh +# Converts 16 bit signed short 8 kHz raw (headerless) files to wave +sox -r 8000 -s -2 $1 $2 diff --git a/libs/libcodec2/script/wav2raw.sh b/libs/libcodec2/script/wav2raw.sh new file mode 100755 index 0000000000..39c0f1aefd --- /dev/null +++ b/libs/libcodec2/script/wav2raw.sh @@ -0,0 +1,3 @@ +#!/bin/sh +# Converts wave files to raw (headerless) files +sox $1 -t raw $2 diff --git a/libs/libcodec2/src/Makefile.am b/libs/libcodec2/src/Makefile.am new file mode 100644 index 0000000000..ce240785d9 --- /dev/null +++ b/libs/libcodec2/src/Makefile.am @@ -0,0 +1,53 @@ +AM_CFLAGS = -I../src -Wall -DFLOATING_POINT -DVAR_ARRAYS +AUTOMAKE_OPTS = gnu +NAME = libcodec2 +AM_CPPFLAGS = $(AM_CFLAGS) + +lib_LTLIBRARIES = libcodec2.la +libcodec2_la_SOURCES = dump.c \ +lpc.c \ +nlp.c \ +postfilter.c \ +sine.c \ +codec2.c \ +four1.c \ +interp.c \ +lsp.c \ +phase.c \ +quantise.c \ +pack.c \ +codebook.c + +libcodec2_la_CFLAGS = $(AM_CFLAGS) +libcodec2_la_LDFLAGS = $(LIBS) + +library_includedir = $(prefix) +library_include_HEADERS = codec2.h \ +defines.h \ +four1.h \ +interp.h \ +lsp.h \ +phase.h \ +quantise.h \ +comp.h \ +dump.h \ +globals.h \ +lpc.h \ +nlp.h \ +postfilter.h \ +sine.h \ +codebook.h + +bin_PROGRAMS = c2dec c2enc c2sim + +c2dec_SOURCES = c2dec.c +c2dec_LDADD = $(lib_LTLIBRARIES) +c2dec_LDFLAGS = $(LIBS) + +c2enc_SOURCES = c2enc.c +c2enc_LDADD = $(lib_LTLIBRARIES) +c2enc_LDFLAGS = $(LIBS) + +c2sim_SOURCES = c2sim.c +c2sim_LDADD = $(lib_LTLIBRARIES) +c2sim_LDFLAGS = $(LIBS) diff --git a/libs/libcodec2/src/c2dec.c b/libs/libcodec2/src/c2dec.c new file mode 100644 index 0000000000..3b876bcac0 --- /dev/null +++ b/libs/libcodec2/src/c2dec.c @@ -0,0 +1,80 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: c2dec.c + AUTHOR......: David Rowe + DATE CREATED: 23/8/2010 + + Decodes a file of bits to a file of raw speech samples using codec2. Demo + program for codec2. + + NOTE: the bit file is not packed, 51 bits/frame actually consumes 51 + bytes/frame on disk. If you are using this for a real world + application you may want to pack the 51 bytes into 7 bytes. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2010 David Rowe + + 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 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. +*/ + +#include "codec2.h" + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + static const int bitsSize = ((CODEC2_BITS_PER_FRAME + 7) / 8); + void *codec2; + FILE *fin; + FILE *fout; + short buf[CODEC2_SAMPLES_PER_FRAME]; + unsigned char bits[bitsSize]; + + if (argc != 3) { + printf("usage: %s InputBitFile OutputRawSpeechFile\n", argv[0]); + exit(1); + } + + if ( (fin = fopen(argv[1],"rb")) == NULL ) { + fprintf(stderr, "Error opening input bit file: %s: %s.\n", + argv[1], strerror(errno)); + exit(1); + } + + if ( (fout = fopen(argv[2],"wb")) == NULL ) { + fprintf(stderr, "Error opening output speech file: %s: %s.\n", + argv[2], strerror(errno)); + exit(1); + } + + codec2 = codec2_create(); + + while(fread(bits, sizeof(char), bitsSize, fin) == bitsSize) { + codec2_decode(codec2, buf, bits); + fwrite(buf, sizeof(short), CODEC2_SAMPLES_PER_FRAME, fout); + } + + codec2_destroy(codec2); + + fclose(fin); + fclose(fout); + + return 0; +} diff --git a/libs/libcodec2/src/c2enc.c b/libs/libcodec2/src/c2enc.c new file mode 100644 index 0000000000..8fd7c7778d --- /dev/null +++ b/libs/libcodec2/src/c2enc.c @@ -0,0 +1,82 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: c2enc.c + AUTHOR......: David Rowe + DATE CREATED: 23/8/2010 + + Encodes a file of raw speech samples using codec2 and ouputs a file + of bits (each bit is stored in the LSB or each output byte). Demo + program for codec2. + + NOTE: the bit file is not packed, 51 bits/frame actually consumes 51 + bytes/frame on disk. If you are using this for a real world + application you may want to pack the 51 bytes into 7 bytes. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2010 David Rowe + + 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 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. +*/ + +#include "codec2.h" + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + static const int bitsSize = ((CODEC2_BITS_PER_FRAME + 7) / 8); + void *codec2; + FILE *fin; + FILE *fout; + short buf[CODEC2_SAMPLES_PER_FRAME]; + unsigned char bits[bitsSize]; + + if (argc != 3) { + printf("usage: %s InputRawspeechFile OutputBitFile\n", argv[0]); + exit(1); + } + + if ( (fin = fopen(argv[1],"rb")) == NULL ) { + fprintf(stderr, "Error opening input bit file: %s: %s.\n", + argv[1], strerror(errno)); + exit(1); + } + + if ( (fout = fopen(argv[2],"wb")) == NULL ) { + fprintf(stderr, "Error opening output speech file: %s: %s.\n", + argv[2], strerror(errno)); + exit(1); + } + + codec2 = codec2_create(); + + while(fread(buf, sizeof(short), CODEC2_SAMPLES_PER_FRAME, fin) == + CODEC2_SAMPLES_PER_FRAME) { + codec2_encode(codec2, bits, buf); + fwrite(bits, sizeof(char), bitsSize, fout); + } + + codec2_destroy(codec2); + + fclose(fin); + fclose(fout); + + return 0; +} diff --git a/libs/libcodec2/src/c2sim.c b/libs/libcodec2/src/c2sim.c new file mode 100644 index 0000000000..b9e5f0f78a --- /dev/null +++ b/libs/libcodec2/src/c2sim.c @@ -0,0 +1,408 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: c2sim.c + AUTHOR......: David Rowe + DATE CREATED: 20/8/2010 + + Codec2 simulation. Combines encoder and decoder and allows switching in + out various algorithms and quantisation steps. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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 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. +*/ + +#include +#include +#include +#include +#include +#include + +#include "defines.h" +#include "sine.h" +#include "nlp.h" +#include "dump.h" +#include "lpc.h" +#include "lsp.h" +#include "quantise.h" +#include "phase.h" +#include "postfilter.h" +#include "interp.h" + +/*---------------------------------------------------------------------------*\ + + switch_present() + + Searches the command line arguments for a "switch". If the switch is + found, returns the command line argument where it ws found, else returns + NULL. + +\*---------------------------------------------------------------------------*/ + +int switch_present(sw,argc,argv) +register char sw[]; /* switch in string form */ +register int argc; /* number of command line arguments */ +register char *argv[]; /* array of command line arguments in string form */ +{ + register int i; /* loop variable */ + + for(i=1; i 20)) { + fprintf(stderr, "Error in lpc order: %d\n", order); + exit(1); + } + } + + dump = switch_present("--dump",argc,argv); + if (dump) + dump_on(argv[dump+1]); + + lsp = switch_present("--lsp",argc,argv); + lsp_quantiser = 0; + + phase0 = switch_present("--phase0",argc,argv); + if (phase0) { + ex_phase[0] = 0; + } + + hand_voicing = switch_present("--hand_voicing",argc,argv); + if (hand_voicing) { + fvoicing = fopen(argv[hand_voicing+1],"rt"); + assert(fvoicing != NULL); + } + + bg_est = 0.0; + postfilt = switch_present("--postfilter",argc,argv); + + decimate = switch_present("--dec",argc,argv); + + /* Initialise ------------------------------------------------------------*/ + + make_analysis_window(w,W); + make_synthesis_window(Pn); + quantise_init(); + + /* Main loop ------------------------------------------------------------*/ + + frames = 0; + sum_snr = 0; + while(fread(buf,sizeof(short),N,fin)) { + frames++; + + /* Read input speech */ + + for(i=0; i 32767.0) + buf[i] = 32767; + else if (Sn_[i] < -32767.0) + buf[i] = -32767; + else + buf[i] = Sn_[i]; + } + +} diff --git a/libs/libcodec2/src/codeall.sh b/libs/libcodec2/src/codeall.sh new file mode 100755 index 0000000000..6bdf825f49 --- /dev/null +++ b/libs/libcodec2/src/codeall.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# codeall.sh +# David Rowe 24 sep 2009 +# Code all samples using various processing steps +./code.sh hts1a +./code.sh hts2a +./code.sh mmt1 +./code.sh morig +./code.sh forig diff --git a/libs/libcodec2/src/codebook.c b/libs/libcodec2/src/codebook.c new file mode 100644 index 0000000000..74ed9ad5fe --- /dev/null +++ b/libs/libcodec2/src/codebook.c @@ -0,0 +1,162 @@ +float codebook_lsp1[] = { + 225, + 250, + 275, + 300, + 325, + 350, + 375, + 400, + 425, + 450, + 475, + 500, + 525, + 550, + 575, + 600,0,0,0,0,0,0,0,0,0,0 +}; + +float codebook_lsp2[] = { + 325, + 350, + 375, + 400, + 425, + 450, + 475, + 500, + 525, + 550, + 575, + 600, + 625, + 650, + 675, + 700,0,0,0,0,0,0,0,0,0,0 +}; + +float codebook_lsp3[] = { + 500, + 550, + 600, + 650, + 700, + 750, + 800, + 850, + 900, + 950, + 1000, + 1050, + 1100, + 1150, + 1200, + 1250,0,0,0,0,0,0,0,0,0,0 +}; + +float codebook_lsp4[] = { + 700, + 800, + 900, + 1000, + 1100, + 1200, + 1300, + 1400, + 1500, + 1600, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200,0,0,0,0,0,0,0,0,0,0 +}; + +float codebook_lsp5[] = { + 950, + 1050, + 1150, + 1250, + 1350, + 1450, + 1550, + 1650, + 1750, + 1850, + 1950, + 2050, + 2150, + 2250, + 2350, + 2450,0,0,0,0,0,0,0,0,0,0 +}; + +float codebook_lsp6[] = { + 1100, + 1200, + 1300, + 1400, + 1500, + 1600, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200, + 2300, + 2400, + 2500, + 2600,0,0,0,0,0,0,0,0,0,0 +}; + +float codebook_lsp7[] = { + 1500, + 1600, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200, + 2300, + 2400, + 2500, + 2600, + 2700, + 2800, + 2900, + 3000,0,0,0,0,0,0,0,0,0,0 +}; + +float codebook_lsp8[] = { + 2300, + 2400, + 2500, + 2600, + 2700, + 2800, + 2900, + 3000,0,0,0,0,0,0,0,0,0,0 +}; + +float codebook_lsp9[] = { + 2500, + 2600, + 2700, + 2800, + 2900, + 3000, + 3100, + 3200,0,0,0,0,0,0,0,0,0,0 +}; + +float codebook_lsp10[] = { + 2900, + 3100, + 3300, + 3500,0,0,0,0,0,0,0,0,0,0 +}; + diff --git a/libs/libcodec2/src/codebook.h b/libs/libcodec2/src/codebook.h new file mode 100644 index 0000000000..d2e77a53f2 --- /dev/null +++ b/libs/libcodec2/src/codebook.h @@ -0,0 +1,15 @@ +#ifndef CODEBOOK_H +#define CODEBOOK_H + +extern float codebook_lsp1[]; +extern float codebook_lsp2[]; +extern float codebook_lsp3[]; +extern float codebook_lsp4[]; +extern float codebook_lsp5[]; +extern float codebook_lsp6[]; +extern float codebook_lsp7[]; +extern float codebook_lsp8[]; +extern float codebook_lsp9[]; +extern float codebook_lsp10[]; + +#endif diff --git a/libs/libcodec2/src/codec2.c b/libs/libcodec2/src/codec2.c new file mode 100644 index 0000000000..30142fec1d --- /dev/null +++ b/libs/libcodec2/src/codec2.c @@ -0,0 +1,337 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: codec2.c + AUTHOR......: David Rowe + DATE CREATED: 21/8/2010 + + Codec2 fully quantised encoder and decoder functions. If you want use + codec2, the codec2_xxx functions are for you. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2010 David Rowe + + 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 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. +*/ + +#include +#include +#include +#include +#include + +#include "defines.h" +#include "sine.h" +#include "nlp.h" +#include "dump.h" +#include "lpc.h" +#include "quantise.h" +#include "phase.h" +#include "interp.h" +#include "postfilter.h" +#include "codec2.h" + +typedef struct { + float Sn[M]; /* input speech */ + float w[M]; /* time domain hamming window */ + COMP W[FFT_ENC]; /* DFT of w[] */ + float Pn[2*N]; /* trapezoidal synthesis window */ + float Sn_[2*N]; /* synthesised speech */ + float prev_Wo; /* previous frame's pitch estimate */ + float ex_phase; /* excitation model phase track */ + float bg_est; /* background noise estimate for post filter */ + MODEL prev_model; /* model parameters from 20ms ago */ + void *nlp; /* pitch predictor states */ +} CODEC2; + +/*---------------------------------------------------------------------------*\ + + FUNCTION HEADERS + +\*---------------------------------------------------------------------------*/ + +void analyse_one_frame(CODEC2 *c2, MODEL *model, short speech[]); +void synthesise_one_frame(CODEC2 *c2, short speech[], MODEL *model,float ak[]); + +/*---------------------------------------------------------------------------*\ + + FUNCTIONS + +\*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: codec2_create + AUTHOR......: David Rowe + DATE CREATED: 21/8/2010 + + Create and initialise an instance of the codec. Returns a pointer + to the codec states or NULL on failure. One set of states is + sufficient for a full duuplex codec (i.e. an encoder and decoder). + You don't need separate states for encoders and decoders. See + c2enc.c and c2dec.c for examples. + +\*---------------------------------------------------------------------------*/ + +void *codec2_create() +{ + CODEC2 *c2; + int i,l; + + c2 = (CODEC2*)malloc(sizeof(CODEC2)); + if (c2 == NULL) + return NULL; + + for(i=0; iSn[i] = 1.0; + for(i=0; i<2*N; i++) + c2->Sn_[i] = 0; + make_analysis_window(c2->w,c2->W); + make_synthesis_window(c2->Pn); + quantise_init(); + c2->prev_Wo = 0.0; + c2->bg_est = 0.0; + c2->ex_phase = 0.0; + + for(l=1; l<=MAX_AMP; l++) + c2->prev_model.A[l] = 0.0; + c2->prev_model.Wo = TWO_PI/P_MAX; + + c2->nlp = nlp_create(); + if (c2->nlp == NULL) { + free (c2); + return NULL; + } + + return (void*)c2; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: codec2_create + AUTHOR......: David Rowe + DATE CREATED: 21/8/2010 + + Destroy an instance of the codec. + +\*---------------------------------------------------------------------------*/ + +void codec2_destroy(void *codec2_state) +{ + CODEC2 *c2; + + assert(codec2_state != NULL); + c2 = (CODEC2*)codec2_state; + nlp_destroy(c2->nlp); + free(codec2_state); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: codec2_encode + AUTHOR......: David Rowe + DATE CREATED: 21/8/2010 + + Encodes 160 speech samples (20ms of speech) into 51 bits. + + The codec2 algorithm actually operates internally on 10ms (80 + sample) frames, so we run the encoding algorithm twice. On the + first frame we just send the voicing bit. One the second frame we + send all model parameters. + + The bit allocation is: + + Parameter bits/frame + -------------------------------------- + Harmonic magnitudes (LSPs) 36 + Low frequency LPC correction 1 + Energy 5 + Wo (fundamental frequnecy) 7 + Voicing (10ms update) 2 + TOTAL 51 + +\*---------------------------------------------------------------------------*/ + +void codec2_encode(void *codec2_state, unsigned char * bits, short speech[]) +{ + CODEC2 *c2; + MODEL model; + int voiced1, voiced2; + int lsp_indexes[LPC_ORD]; + int lpc_correction; + int energy_index; + int Wo_index; + int i; + unsigned int nbit = 0; + + assert(codec2_state != NULL); + c2 = (CODEC2*)codec2_state; + + /* first 10ms analysis frame - we just want voicing */ + + analyse_one_frame(c2, &model, speech); + voiced1 = model.voiced; + + /* second 10ms analysis frame */ + + analyse_one_frame(c2, &model, &speech[N]); + voiced2 = model.voiced; + + Wo_index = encode_Wo(model.Wo); + encode_amplitudes(lsp_indexes, + &lpc_correction, + &energy_index, + &model, + c2->Sn, + c2->w); + memset(bits, '\0', ((CODEC2_BITS_PER_FRAME + 7) / 8)); + pack(bits, &nbit, Wo_index, WO_BITS); + for(i=0; iprev_model, &model); + + synthesise_one_frame(c2, speech, &model_interp, ak); + synthesise_one_frame(c2, &speech[N], &model, ak); + + memcpy(&c2->prev_model, &model, sizeof(MODEL)); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: synthesise_one_frame() + AUTHOR......: David Rowe + DATE CREATED: 23/8/2010 + + Synthesise 80 speech samples (10ms) from model parameters. + +\*---------------------------------------------------------------------------*/ + +void synthesise_one_frame(CODEC2 *c2, short speech[], MODEL *model, float ak[]) +{ + int i; + + phase_synth_zero_order(model, ak, &c2->ex_phase); + postfilter(model, &c2->bg_est); + synthesise(c2->Sn_, model, c2->Pn, 1); + + for(i=0; iSn_[i] > 32767.0) + speech[i] = 32767; + else if (c2->Sn_[i] < -32767.0) + speech[i] = -32767; + else + speech[i] = c2->Sn_[i]; + } + +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: analyse_one_frame() + AUTHOR......: David Rowe + DATE CREATED: 23/8/2010 + + Extract sinusoidal model parameters from 80 speech samples (10ms of + speech). + +\*---------------------------------------------------------------------------*/ + +void analyse_one_frame(CODEC2 *c2, MODEL *model, short speech[]) +{ + COMP Sw[FFT_ENC]; + COMP Sw_[FFT_ENC]; + float pitch; + int i; + + /* Read input speech */ + + for(i=0; iSn[i] = c2->Sn[i+N]; + for(i=0; iSn[i+M-N] = speech[i]; + dft_speech(Sw, c2->Sn, c2->w); + + /* Estimate pitch */ + + nlp(c2->nlp,c2->Sn,N,M,P_MIN,P_MAX,&pitch,Sw,&c2->prev_Wo); + c2->prev_Wo = TWO_PI/pitch; + model->Wo = TWO_PI/pitch; + model->L = PI/model->Wo; + + /* estimate model parameters */ + + dft_speech(Sw, c2->Sn, c2->w); + two_stage_pitch_refinement(model, Sw); + estimate_amplitudes(model, Sw, c2->W); + est_voicing_mbe(model, Sw, c2->W, (FS/TWO_PI)*model->Wo, Sw_); +} diff --git a/libs/libcodec2/src/codec2.h b/libs/libcodec2/src/codec2.h new file mode 100644 index 0000000000..7a1d1450a5 --- /dev/null +++ b/libs/libcodec2/src/codec2.h @@ -0,0 +1,43 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: codec2.h + AUTHOR......: David Rowe + DATE CREATED: 21/8/2010 + + Codec2 fully quantised encoder and decoder functions. If you want use + codec2, these are the functions you need to call. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2010 David Rowe + + 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 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. +*/ + +#ifndef __CODEC2__ +#define __CODEC2__ +#include "codebook.h" + +#define CODEC2_SAMPLES_PER_FRAME 160 +#define CODEC2_BITS_PER_FRAME 51 + +void *codec2_create(); +void codec2_destroy(void *codec2_state); +void codec2_encode(void *codec2_state, unsigned char * bits, short speech_in[]); +void codec2_decode(void *codec2_state, short speech_out[], + const unsigned char * bits); + +#endif diff --git a/libs/libcodec2/src/comp.h b/libs/libcodec2/src/comp.h new file mode 100644 index 0000000000..bca01b5d2f --- /dev/null +++ b/libs/libcodec2/src/comp.h @@ -0,0 +1,39 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: comp.h + AUTHOR......: David Rowe + DATE CREATED: 24/08/09 + + Complex number definition. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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 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. +*/ + +#ifndef __COMP__ +#define __COMP__ + +/* Complex number */ + +typedef struct { + float real; + float imag; +} COMP; + +#endif diff --git a/libs/libcodec2/src/defines.h b/libs/libcodec2/src/defines.h new file mode 100644 index 0000000000..ef4899f70a --- /dev/null +++ b/libs/libcodec2/src/defines.h @@ -0,0 +1,84 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: defines.h + AUTHOR......: David Rowe + DATE CREATED: 23/4/93 + + Defines and structures used throughout the codec. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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 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. +*/ + +#ifndef __DEFINES__ +#define __DEFINES__ + +/*---------------------------------------------------------------------------*\ + + DEFINES + +\*---------------------------------------------------------------------------*/ + +/* General defines */ + +#define N 80 /* number of samples per frame */ +#define MAX_AMP 80 /* maximum number of harmonics */ +#define PI 3.141592654 /* mathematical constant */ +#define TWO_PI 6.283185307 /* mathematical constant */ +#define FS 8000 /* sample rate in Hz */ +#define MAX_STR 256 /* maximum string size */ + +#define NW 279 /* analysis window size */ +#define FFT_ENC 512 /* size of FFT used for encoder */ +#define FFT_DEC 512 /* size of FFT used in decoder */ +#define TW 40 /* Trapezoidal synthesis window overlap */ +#define V_THRESH 4.0 /* voicing threshold in dB */ +#define LPC_MAX 20 /* maximum LPC order */ +#define LPC_ORD 10 /* phase modelling LPC order */ + +/* Pitch estimation defines */ + +#define M 320 /* pitch analysis frame size */ +#define P_MIN 20 /* minimum pitch */ +#define P_MAX 160 /* maximum pitch */ + +/*---------------------------------------------------------------------------*\ + + TYPEDEFS + +\*---------------------------------------------------------------------------*/ + +/* Complex number */ + +typedef struct { + float real; + float imag; +} COMP; + +/* Structure to hold model parameters for one frame */ + +typedef struct { + float Wo; /* fundamental frequency estimate in radians */ + int L; /* number of harmonics */ + float A[MAX_AMP]; /* amplitiude of each harmonic */ + float phi[MAX_AMP]; /* phase of each harmonic */ + int voiced; /* non-zero if this frame is voiced */ +} MODEL; + +#endif diff --git a/libs/libcodec2/src/dump.c b/libs/libcodec2/src/dump.c new file mode 100644 index 0000000000..2d18744483 --- /dev/null +++ b/libs/libcodec2/src/dump.c @@ -0,0 +1,402 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: dump.c + AUTHOR......: David Rowe + DATE CREATED: 25/8/09 + + Routines to dump data to text files for Octave analysis. + +\*---------------------------------------------------------------------------*/ + +/* + 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 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. +*/ + +#include "defines.h" +#include "dump.h" +#include +#include +#include +#include +#include + +static int dumpon = 0; + +static FILE *fsn = NULL; +static FILE *fsw = NULL; +static FILE *fsw_ = NULL; +static FILE *fmodel = NULL; +static FILE *fqmodel = NULL; +static FILE *fpw = NULL; +static FILE *flsp = NULL; +static FILE *fphase = NULL; +static FILE *fphase_ = NULL; +static FILE *ffw = NULL; +static FILE *fe = NULL; +static FILE *fsq = NULL; +static FILE *fdec = NULL; +static FILE *fsnr = NULL; +static FILE *fak = NULL; +static FILE *fbg = NULL; +static FILE *fE = NULL; + +static char prefix[MAX_STR]; + +void dump_on(char p[]) { + dumpon = 1; + strcpy(prefix, p); +} + +void dump_off(){ + if (fsn != NULL) + fclose(fsn); + if (fsw != NULL) + fclose(fsw); + if (fsw_ != NULL) + fclose(fsw_); + if (fmodel != NULL) + fclose(fmodel); + if (fqmodel != NULL) + fclose(fqmodel); + if (fpw != NULL) + fclose(fpw); + if (flsp != NULL) + fclose(flsp); + if (fphase != NULL) + fclose(fphase); + if (fphase_ != NULL) + fclose(fphase_); + if (ffw != NULL) + fclose(ffw); + if (fe != NULL) + fclose(fe); + if (fsq != NULL) + fclose(fsq); + if (fdec != NULL) + fclose(fdec); + if (fsnr != NULL) + fclose(fsnr); + if (fak != NULL) + fclose(fak); + if (fbg != NULL) + fclose(fbg); + if (fE != NULL) + fclose(fE); +} + +void dump_Sn(float Sn[]) { + int i; + char s[MAX_STR]; + + if (!dumpon) return; + + if (fsn == NULL) { + sprintf(s,"%s_sn.txt", prefix); + fsn = fopen(s, "wt"); + assert(fsn != NULL); + } + + /* split across two lines to avoid max line length problems */ + /* reconstruct in Octave */ + + for(i=0; iWo, model->L); + for(l=1; l<=model->L; l++) + fprintf(fmodel,"%f\t",model->A[l]); + for(l=model->L+1; lvoiced); + fprintf(fmodel,"\n"); +} + +void dump_quantised_model(MODEL *model) { + int l; + char s[MAX_STR]; + + if (!dumpon) return; + + if (fqmodel == NULL) { + sprintf(s,"%s_qmodel.txt", prefix); + fqmodel = fopen(s, "wt"); + assert(fqmodel != NULL); + } + + fprintf(fqmodel,"%f\t%d\t", model->Wo, model->L); + for(l=1; l<=model->L; l++) + fprintf(fqmodel,"%f\t",model->A[l]); + for(l=model->L+1; l + +#define SWAP(a,b) tempr=(a);(a)=(b);(b)=tempr + +void four1(data,nn,isign) +float data[]; +int nn,isign; +{ + int n,mmax,m,j,istep,i; + double wtemp,wr,wpr,wpi,wi,theta; + float tempr,tempi; + + n=nn << 1; + j=1; + for (i=1;i i) { + SWAP(data[j],data[i]); + SWAP(data[j+1],data[i+1]); + } + m=n >> 1; + while (m >= 2 && j > m) { + j -= m; + m >>= 1; + } + j += m; + } + mmax=2; + while (n > mmax) { + istep=2*mmax; + theta=6.28318530717959/(isign*mmax); + wtemp=sin(0.5*theta); + wpr = -2.0*wtemp*wtemp; + wpi=sin(theta); + wr=1.0; + wi=0.0; + for (m=1;m +#include +#include + +#include "defines.h" +#include "interp.h" + +float sample_log_amp(MODEL *model, float w); + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: interp() + AUTHOR......: David Rowe + DATE CREATED: 22/8/10 + + Given two frames decribed by model parameters 20ms apart, determines + the model parameters of the 10ms frame between them. Assumes + voicing is available for middle (interpolated) frame. Outputs are + amplitudes and Wo for the interpolated frame. + + This version can interpolate the amplitudes between two frames of + different Wo and L. + +\*---------------------------------------------------------------------------*/ + +void interpolate( + MODEL *interp, /* interpolated model params */ + MODEL *prev, /* previous frames model params */ + MODEL *next /* next frames model params */ +) +{ + int l; + float w,log_amp; + + /* Wo depends on voicing of this and adjacent frames */ + + if (interp->voiced) { + if (prev->voiced && next->voiced) + interp->Wo = (prev->Wo + next->Wo)/2.0; + if (!prev->voiced && next->voiced) + interp->Wo = next->Wo; + if (prev->voiced && !next->voiced) + interp->Wo = prev->Wo; + } + else { + interp->Wo = TWO_PI/P_MAX; + } + interp->L = PI/interp->Wo; + + /* Interpolate amplitudes using linear interpolation in log domain */ + + for(l=1; l<=interp->L; l++) { + w = l*interp->Wo; + log_amp = (sample_log_amp(prev, w) + sample_log_amp(next, w))/2.0; + interp->A[l] = pow(10.0, log_amp); + } +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: sample_log_amp() + AUTHOR......: David Rowe + DATE CREATED: 22/8/10 + + Samples the amplitude envelope at an arbitrary frequency w. Uses + linear interpolation in the log domain to sample between harmonic + amplitudes. + +\*---------------------------------------------------------------------------*/ + +float sample_log_amp(MODEL *model, float w) +{ + int m; + float f, log_amp; + + assert(w > 0.0); assert (w <= PI); + + m = floor(w/model->Wo + 0.5); + f = (w - m*model->Wo)/w; + assert(f <= 1.0); + + if (m < 1) { + log_amp = f*log10(model->A[1]); + } + else if ((m+1) > model->L) { + log_amp = (1.0-f)*log10(model->A[model->L]); + } + else { + log_amp = (1.0-f)*log10(model->A[m]) + f*log10(model->A[m+1]); + } + + return log_amp; +} + diff --git a/libs/libcodec2/src/interp.h b/libs/libcodec2/src/interp.h new file mode 100644 index 0000000000..0684b5bbff --- /dev/null +++ b/libs/libcodec2/src/interp.h @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: interp.h + AUTHOR......: David Rowe + DATE CREATED: 9/10/09 + + Interpolation of 20ms frames to 10ms frames. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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 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. +*/ + +#ifndef __INTERP__ +#define __INTERP__ + +void interpolate(MODEL *interp, MODEL *prev, MODEL *next); + +#endif diff --git a/libs/libcodec2/src/listen.sh b/libs/libcodec2/src/listen.sh new file mode 100644 index 0000000000..bebd106f7a --- /dev/null +++ b/libs/libcodec2/src/listen.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# listensim.sh +# David Rowe 10 Sep 2009 +# +# Listen to files processed with sim.sh + +../script/menu.sh ../raw/$1.raw $1_uq.raw $1_phase0.raw $1_lpc10.raw $1_lsp.raw $1_phase0_lpc10.raw $1_phase0_lsp.raw $1_phase0_lsp.raw $2 $3 + + diff --git a/libs/libcodec2/src/listen1.sh b/libs/libcodec2/src/listen1.sh new file mode 100755 index 0000000000..a3b72671bc --- /dev/null +++ b/libs/libcodec2/src/listen1.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# listen1.sh +# David Rowe 10 Sep 2009 +# +# Run menu with common sample file options, headphone version + +#../script/menu.sh ../raw/$1.raw $1_uq.raw $1_phase0.raw $1_lpc10.raw $1_lsp.raw $1_phase0_lpc10.raw $1_phase0_lsp.raw ../raw/$1_g729a.raw $2 $3 -d /dev/dsp1 + +# compare to other codecs + +#../script/menu.sh ../raw/$1.raw $1_phase0_lsp.raw $1_phase0_lsp_20.raw ../raw/$1_g729a.raw ../raw/$1_gsm13k.raw ../raw/$1_speex_8k.raw $2 $3 -d /dev/dsp1 + +../script/menu.sh ../raw/$1.raw $1_uq.raw $1_phase0.raw $1_test.raw ../raw/$1_g729a.raw $2 $3 -d /dev/dsp1 + + diff --git a/libs/libcodec2/src/listensim.sh b/libs/libcodec2/src/listensim.sh new file mode 100755 index 0000000000..64f7455ab3 --- /dev/null +++ b/libs/libcodec2/src/listensim.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# listensim.sh +# David Rowe 10 Sep 2009 +# +# Listen to files processed with sim.sh + +../script/menu.sh ../raw/$1.raw $1_uq.raw $1_phase0.raw $1_lpc10.raw $1_lsp.raw $1_phase0_lpc10.raw $1_phase0_lsp.raw $1_phase0_lsp_dec.raw $2 $3 + + diff --git a/libs/libcodec2/src/lpc.c b/libs/libcodec2/src/lpc.c new file mode 100644 index 0000000000..1f9ff2bf10 --- /dev/null +++ b/libs/libcodec2/src/lpc.c @@ -0,0 +1,253 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: lpc.c + AUTHOR......: David Rowe + DATE CREATED: 30/9/90 + + Linear Prediction functions written in C. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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 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. +*/ + +#define LPC_MAX_N 512 /* maximum no. of samples in frame */ +#define PI 3.141592654 /* mathematical constant */ + +#include +#include +#include "defines.h" +#include "lpc.h" + +/*---------------------------------------------------------------------------*\ + + hanning_window() + + Hanning windows a frame of speech samples. + +\*---------------------------------------------------------------------------*/ + +void hanning_window( + float Sn[], /* input frame of speech samples */ + float Wn[], /* output frame of windowed samples */ + int Nsam /* number of samples */ +) +{ + int i; /* loop variable */ + + for(i=0; i 1.0) + k[i] = 0.0; + + a[i][i] = k[i]; + + for(j=1; j<=i-1; j++) + a[i][j] = a[i-1][j] + k[i]*a[i-1][i-j]; /* Equation 38c, Makhoul */ + + E[i] = (1-k[i]*k[i])*E[i-1]; /* Equation 38d, Makhoul */ + } + + for(i=1; i<=order; i++) + lpcs[i] = a[order][i]; + lpcs[0] = 1.0; +} + +/*---------------------------------------------------------------------------*\ + + inverse_filter() + + Inverse Filter, A(z). Produces an array of residual samples from an array + of input samples and linear prediction coefficients. + + The filter memory is stored in the first order samples of the input array. + +\*---------------------------------------------------------------------------*/ + +void inverse_filter( + float Sn[], /* Nsam input samples */ + float a[], /* LPCs for this frame of samples */ + int Nsam, /* number of samples */ + float res[], /* Nsam residual samples */ + int order /* order of LPC */ +) +{ + int i,j; /* loop variables */ + + for(i=0; i +#include +#include + +/*---------------------------------------------------------------------------*\ + + Introduction to Line Spectrum Pairs (LSPs) + ------------------------------------------ + + LSPs are used to encode the LPC filter coefficients {ak} for + transmission over the channel. LSPs have several properties (like + less sensitivity to quantisation noise) that make them superior to + direct quantisation of {ak}. + + A(z) is a polynomial of order lpcrdr with {ak} as the coefficients. + + A(z) is transformed to P(z) and Q(z) (using a substitution and some + algebra), to obtain something like: + + A(z) = 0.5[P(z)(z+z^-1) + Q(z)(z-z^-1)] (1) + + As you can imagine A(z) has complex zeros all over the z-plane. P(z) + and Q(z) have the very neat property of only having zeros _on_ the + unit circle. So to find them we take a test point z=exp(jw) and + evaluate P (exp(jw)) and Q(exp(jw)) using a grid of points between 0 + and pi. + + The zeros (roots) of P(z) also happen to alternate, which is why we + swap coefficients as we find roots. So the process of finding the + LSP frequencies is basically finding the roots of 5th order + polynomials. + + The root so P(z) and Q(z) occur in symmetrical pairs at +/-w, hence + the name Line Spectrum Pairs (LSPs). + + To convert back to ak we just evaluate (1), "clocking" an impulse + thru it lpcrdr times gives us the impulse response of A(z) which is + {ak}. + +\*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: cheb_poly_eva() + AUTHOR......: David Rowe + DATE CREATED: 24/2/93 + + This function evalutes a series of chebyshev polynomials + + FIXME: performing memory allocation at run time is very inefficient, + replace with stack variables of MAX_P size. + +\*---------------------------------------------------------------------------*/ + + +float cheb_poly_eva(float *coef,float x,int m) +/* float coef[] coefficients of the polynomial to be evaluated */ +/* float x the point where polynomial is to be evaluated */ +/* int m order of the polynomial */ +{ + int i; + float *T,*t,*u,*v,sum; + + /* Allocate memory for chebyshev series formulation */ + + if((T = (float *)malloc((m/2+1)*sizeof(float))) == NULL){ + fprintf(stderr, "not enough memory to allocate buffer\n"); + exit(1); + } + + /* Initialise pointers */ + + t = T; /* T[i-2] */ + *t++ = 1.0; + u = t--; /* T[i-1] */ + *u++ = x; + v = u--; /* T[i] */ + + /* Evaluate chebyshev series formulation using iterative approach */ + + for(i=2;i<=m/2;i++) + *v++ = (2*x)*(*u++) - *t++; /* T[i] = 2*x*T[i-1] - T[i-2] */ + + sum=0.0; /* initialise sum to zero */ + t = T; /* reset pointer */ + + /* Evaluate polynomial and return value also free memory space */ + + for(i=0;i<=m/2;i++) + sum+=coef[(m/2)-i]**t++; + + free(T); + return sum; +} + + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: lpc_to_lsp() + AUTHOR......: David Rowe + DATE CREATED: 24/2/93 + + This function converts LPC coefficients to LSP coefficients. + +\*---------------------------------------------------------------------------*/ + +int lpc_to_lsp (float *a, int lpcrdr, float *freq, int nb, float delta) +/* float *a lpc coefficients */ +/* int lpcrdr order of LPC coefficients (10) */ +/* float *freq LSP frequencies in radians */ +/* int nb number of sub-intervals (4) */ +/* float delta grid spacing interval (0.02) */ +{ + float psuml,psumr,psumm,temp_xr,xl,xr,xm; + float temp_psumr; + int i,j,m,flag,k; + float *Q; /* ptrs for memory allocation */ + float *P; + float *px; /* ptrs of respective P'(z) & Q'(z) */ + float *qx; + float *p; + float *q; + float *pt; /* ptr used for cheb_poly_eval() + whether P' or Q' */ + int roots=0; /* number of roots found */ + flag = 1; + m = lpcrdr/2; /* order of P'(z) & Q'(z) polynimials */ + + /* Allocate memory space for polynomials */ + + Q = (float *) malloc((m+1)*sizeof(float)); + P = (float *) malloc((m+1)*sizeof(float)); + if( (P == NULL) || (Q == NULL) ) { + fprintf(stderr,"not enough memory to allocate buffer\n"); + exit(1); + } + + /* determine P'(z)'s and Q'(z)'s coefficients where + P'(z) = P(z)/(1 + z^(-1)) and Q'(z) = Q(z)/(1-z^(-1)) */ + + px = P; /* initilaise ptrs */ + qx = Q; + p = px; + q = qx; + *px++ = 1.0; + *qx++ = 1.0; + for(i=1;i<=m;i++){ + *px++ = a[i]+a[lpcrdr+1-i]-*p++; + *qx++ = a[i]-a[lpcrdr+1-i]+*q++; + } + px = P; + qx = Q; + for(i=0;i= -1.0)){ + xr = xl - delta ; /* interval spacing */ + psumr = cheb_poly_eva(pt,xr,lpcrdr);/* poly(xl-delta_x) */ + temp_psumr = psumr; + temp_xr = xr; + + /* if no sign change increment xr and re-evaluate + poly(xr). Repeat til sign change. if a sign change has + occurred the interval is bisected and then checked again + for a sign change which determines in which interval the + zero lies in. If there is no sign change between poly(xm) + and poly(xl) set interval between xm and xr else set + interval between xl and xr and repeat till root is located + within the specified limits */ + + if((psumr*psuml)<0.0){ + roots++; + + psumm=psuml; + for(k=0;k<=nb;k++){ + xm = (xl+xr)/2; /* bisect the interval */ + psumm=cheb_poly_eva(pt,xm,lpcrdr); + if(psumm*psuml>0.){ + psuml=psumm; + xl=xm; + } + else{ + psumr=psumm; + xr=xm; + } + } + + /* once zero is found, reset initial interval to xr */ + freq[j] = (xm); + xl = xm; + flag = 0; /* reset flag for next search */ + } + else{ + psuml=temp_psumr; + xl=temp_xr; + } + } + } + free(P); /* free memory space */ + free(Q); + + /* convert from x domain to radians */ + + for(i=0; i +#include +#include + +/*---------------------------------------------------------------------------*\ + + DEFINES + +\*---------------------------------------------------------------------------*/ + +#define PMAX_M 600 /* maximum NLP analysis window size */ +#define COEFF 0.95 /* notch filter parameter */ +#define PE_FFT_SIZE 512 /* DFT size for pitch estimation */ +#define DEC 5 /* decimation factor */ +#define SAMPLE_RATE 8000 +#define PI 3.141592654 /* mathematical constant */ +#define T 0.1 /* threshold for local minima candidate */ +#define F0_MAX 500 +#define CNLP 0.3 /* post processor constant */ +#define NLP_NTAP 48 /* Decimation LPF order */ + +/*---------------------------------------------------------------------------*\ + + GLOBALS + +\*---------------------------------------------------------------------------*/ + +/* 48 tap 600Hz low pass FIR filter coefficients */ + +float nlp_fir[] = { + -1.0818124e-03, + -1.1008344e-03, + -9.2768838e-04, + -4.2289438e-04, + 5.5034190e-04, + 2.0029849e-03, + 3.7058509e-03, + 5.1449415e-03, + 5.5924666e-03, + 4.3036754e-03, + 8.0284511e-04, + -4.8204610e-03, + -1.1705810e-02, + -1.8199275e-02, + -2.2065282e-02, + -2.0920610e-02, + -1.2808831e-02, + 3.2204775e-03, + 2.6683811e-02, + 5.5520624e-02, + 8.6305944e-02, + 1.1480192e-01, + 1.3674206e-01, + 1.4867556e-01, + 1.4867556e-01, + 1.3674206e-01, + 1.1480192e-01, + 8.6305944e-02, + 5.5520624e-02, + 2.6683811e-02, + 3.2204775e-03, + -1.2808831e-02, + -2.0920610e-02, + -2.2065282e-02, + -1.8199275e-02, + -1.1705810e-02, + -4.8204610e-03, + 8.0284511e-04, + 4.3036754e-03, + 5.5924666e-03, + 5.1449415e-03, + 3.7058509e-03, + 2.0029849e-03, + 5.5034190e-04, + -4.2289438e-04, + -9.2768838e-04, + -1.1008344e-03, + -1.0818124e-03 +}; + +typedef struct { + float sq[PMAX_M]; /* squared speech samples */ + float mem_x,mem_y; /* memory for notch filter */ + float mem_fir[NLP_NTAP]; /* decimation FIR filter memory */ +} NLP; + +float post_process_mbe(COMP Fw[], int pmin, int pmax, float gmax); +float post_process_sub_multiples(COMP Fw[], + int pmin, int pmax, float gmax, int gmax_bin, + float *prev_Wo); + +/*---------------------------------------------------------------------------*\ + + nlp_create() + + Initialisation function for NLP pitch estimator. + +\*---------------------------------------------------------------------------*/ + +void *nlp_create() +{ + NLP *nlp; + int i; + + nlp = (NLP*)malloc(sizeof(NLP)); + if (nlp == NULL) + return NULL; + + for(i=0; isq[i] = 0.0; + nlp->mem_x = 0.0; + nlp->mem_y = 0.0; + for(i=0; imem_fir[i] = 0.0; + + return (void*)nlp; +} + +/*---------------------------------------------------------------------------*\ + + nlp_destory() + + Initialisation function for NLP pitch estimator. + +\*---------------------------------------------------------------------------*/ + +void nlp_destroy(void *nlp_state) +{ + assert(nlp_state != NULL); + free(nlp_state); +} + +/*---------------------------------------------------------------------------*\ + + nlp() + + Determines the pitch in samples using the Non Linear Pitch (NLP) + algorithm [1]. Returns the fundamental in Hz. Note that the actual + pitch estimate is for the centre of the M sample Sn[] vector, not + the current N sample input vector. This is (I think) a delay of 2.5 + frames with N=80 samples. You should align further analysis using + this pitch estimate to be centred on the middle of Sn[]. + + Two post processors have been tried, the MBE version (as discussed + in [1]), and a post processor that checks sub-multiples. Both + suffer occasional gross pitch errors (i.e. neither are perfect). In + the presence of background noise the sub-multiple algorithm tends + towards low F0 which leads to better sounding background noise than + the MBE post processor. + + A good way to test and develop the NLP pitch estimator is using the + tnlp (codec2/unittest) and the codec2/octave/plnlp.m Octave script. + + A pitch tracker searching a few frames forward and backward in time + would be a useful addition. + + References: + + [1] http://www.itr.unisa.edu.au/~steven/thesis/dgr.pdf Chapter 4 + +\*---------------------------------------------------------------------------*/ + +float nlp( + void *nlp_state, + float Sn[], /* input speech vector */ + int n, /* frames shift (no. new samples in Sn[]) */ + int m, /* analysis window size */ + int pmin, /* minimum pitch value */ + int pmax, /* maximum pitch value */ + float *pitch, /* estimated pitch period in samples */ + COMP Sw[], /* Freq domain version of Sn[] */ + float *prev_Wo +) +{ + NLP *nlp; + float notch; /* current notch filter output */ + COMP Fw[PE_FFT_SIZE]; /* DFT of squared signal */ + float gmax; + int gmax_bin; + int i,j; + float best_f0; + + assert(nlp_state != NULL); + nlp = (NLP*)nlp_state; + + /* Square, notch filter at DC, and LP filter vector */ + + for(i=m-n; isq[i] = Sn[i]*Sn[i]; + + for(i=m-n; isq[i] - nlp->mem_x; + notch += COEFF*nlp->mem_y; + nlp->mem_x = nlp->sq[i]; + nlp->mem_y = notch; + nlp->sq[i] = notch; + } + + for(i=m-n; imem_fir[j] = nlp->mem_fir[j+1]; + nlp->mem_fir[NLP_NTAP-1] = nlp->sq[i]; + + nlp->sq[i] = 0.0; + for(j=0; jsq[i] += nlp->mem_fir[j]*nlp_fir[j]; + } + + /* Decimate and DFT */ + + for(i=0; isq[i*DEC]*(0.5 - 0.5*cos(2*PI*i/(m/DEC-1))); + } + dump_dec(Fw); + four1(&Fw[-1].imag,PE_FFT_SIZE,1); + for(i=0; isq); + dump_Fw(Fw); + + /* find global peak */ + + gmax = 0.0; + gmax_bin = PE_FFT_SIZE*DEC/pmax; + for(i=PE_FFT_SIZE*DEC/pmax; i<=PE_FFT_SIZE*DEC/pmin; i++) { + if (Fw[i].real > gmax) { + gmax = Fw[i].real; + gmax_bin = i; + } + } + + best_f0 = post_process_sub_multiples(Fw, pmin, pmax, gmax, gmax_bin, + prev_Wo); + + /* Shift samples in buffer to make room for new samples */ + + for(i=0; isq[i] = nlp->sq[i+n]; + + /* return pitch and F0 estimate */ + + *pitch = (float)SAMPLE_RATE/best_f0; + return(best_f0); +} + +/*---------------------------------------------------------------------------*\ + + post_process_sub_multiples() + + Given the global maximma of Fw[] we search interger submultiples for + local maxima. If local maxima exist and they are above an + experimentally derived threshold (OK a magic number I pulled out of + the air) we choose the submultiple as the F0 estimate. + + The rational for this is that the lowest frequency peak of Fw[] + should be F0, as Fw[] can be considered the autocorrelation function + of Sw[] (the speech spectrum). However sometimes due to phase + effects the lowest frequency maxima may not be the global maxima. + + This works OK in practice and favours low F0 values in the presence + of background noise which means the sinusoidal codec does an OK job + of synthesising the background noise. High F0 in background noise + tends to sound more periodic introducing annoying artifacts. + +\*---------------------------------------------------------------------------*/ + +float post_process_sub_multiples(COMP Fw[], + int pmin, int pmax, float gmax, int gmax_bin, + float *prev_Wo) +{ + int min_bin, cmax_bin; + int mult; + float thresh, best_f0; + int b, bmin, bmax, lmax_bin; + float lmax, cmax; + int prev_f0_bin; + + /* post process estimate by searching submultiples */ + + mult = 2; + min_bin = PE_FFT_SIZE*DEC/pmax; + cmax_bin = gmax_bin; + prev_f0_bin = *prev_Wo*(4000.0/PI)*(PE_FFT_SIZE*DEC)/SAMPLE_RATE; + + while(gmax_bin/mult >= min_bin) { + + b = gmax_bin/mult; /* determine search interval */ + bmin = 0.8*b; + bmax = 1.2*b; + if (bmin < min_bin) + bmin = min_bin; + + /* lower threshold to favour previous frames pitch estimate, + this is a form of pitch tracking */ + + if ((prev_f0_bin > bmin) && (prev_f0_bin < bmax)) + thresh = CNLP*0.5*gmax; + else + thresh = CNLP*gmax; + + lmax = 0; + lmax_bin = bmin; + for (b=bmin; b<=bmax; b++) /* look for maximum in interval */ + if (Fw[b].real > lmax) { + lmax = Fw[b].real; + lmax_bin = b; + } + + if (lmax > thresh) + if ((lmax > Fw[lmax_bin-1].real) && (lmax > Fw[lmax_bin+1].real)) { + cmax = lmax; + cmax_bin = lmax_bin; + } + + mult++; + } + + best_f0 = (float)cmax_bin*SAMPLE_RATE/(PE_FFT_SIZE*DEC); + + return best_f0; +} + diff --git a/libs/libcodec2/src/nlp.h b/libs/libcodec2/src/nlp.h new file mode 100644 index 0000000000..eaaae97052 --- /dev/null +++ b/libs/libcodec2/src/nlp.h @@ -0,0 +1,38 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: nlp.c + AUTHOR......: David Rowe + DATE CREATED: 23/3/93 + + Non Linear Pitch (NLP) estimation functions. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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 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. +*/ + +#ifndef __NLP__ +#define __NLP__ + +void *nlp_create(); +void nlp_destroy(void *nlp_state); +float nlp(void *nlp_state, float Sn[], int n, int m, int pmin, int pmax, + float *pitch, COMP Sw[], float *prev_Wo); +float test_candidate_mbe(COMP Sw[], float f0, COMP Sw_[]); + +#endif diff --git a/libs/libcodec2/src/pack.c b/libs/libcodec2/src/pack.c new file mode 100644 index 0000000000..2cbff4438a --- /dev/null +++ b/libs/libcodec2/src/pack.c @@ -0,0 +1,104 @@ +/* + Copyright (C) 2010 Perens LLC + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + */ +#include "defines.h" +#include "quantise.h" +#include + +/* Compile-time constants */ +/* Size of unsigned char in bits. Assumes 8 bits-per-char. */ +static const unsigned int WordSize = 8; + +/* Mask to pick the bit component out of bitIndex. */ +static const unsigned int IndexMask = 0x7; + +/* Used to pick the word component out of bitIndex. */ +static const unsigned int ShiftRight = 3; + +/** Pack a bit field into a bit string, encoding the field in Gray code. + * + * The output is an array of unsigned char data. The fields are efficiently + * packed into the bit string. The Gray coding is a naive attempt to reduce + * the effect of single-bit errors, we expect to do a better job as the + * codec develops. + * + * This code would be simpler if it just set one bit at a time in the string, + * but would hit the same cache line more often. I'm not sure the complexity + * gains us anything here. + * + * Although field is currently of int type rather than unsigned for + * compatibility with the rest of the code, indices are always expected to + * be >= 0. + */ +void +pack( + unsigned char * bitArray, /* The output bit string. */ + unsigned int * bitIndex, /* Index into the string in BITS, not bytes.*/ + int field, /* The bit field to be packed. */ + unsigned int fieldWidth/* Width of the field in BITS, not bytes. */ + ) +{ + /* Convert the field to Gray code */ + field = (field >> 1) ^ field; + + do { + unsigned int bI = *bitIndex; + unsigned int bitsLeft = WordSize - (bI & IndexMask); + unsigned int sliceWidth = + bitsLeft < fieldWidth ? bitsLeft : fieldWidth; + unsigned int wordIndex = bI >> ShiftRight; + + bitArray[wordIndex] |= + ((unsigned char)((field >> (fieldWidth - sliceWidth)) + << (bitsLeft - sliceWidth))); + + *bitIndex = bI + sliceWidth; + fieldWidth -= sliceWidth; + } while ( fieldWidth != 0 ); +} + +/** Unpack a field from a bit string, converting from Gray code to binary. + * + */ +int +unpack( + const unsigned char * bitArray, /* The input bit string. */ + unsigned int * bitIndex, /* Index into the string in BITS, not bytes.*/ + unsigned int fieldWidth/* Width of the field in BITS, not bytes. */ + ) +{ + unsigned int field = 0; + + do { + unsigned int bI = *bitIndex; + unsigned int bitsLeft = WordSize - (bI & IndexMask); + unsigned int sliceWidth = + bitsLeft < fieldWidth ? bitsLeft : fieldWidth; + + field |= (((bitArray[bI >> ShiftRight] >> (bitsLeft - sliceWidth)) & ((1 << sliceWidth) - 1)) << (fieldWidth - sliceWidth)); + + *bitIndex = bI + sliceWidth; + fieldWidth -= sliceWidth; + } while ( fieldWidth != 0 ); + + /* Convert from Gray code to binary. Works for maximum 8-bit fields. */ + unsigned int t = field ^ (field >> 8); + t ^= (t >> 4); + t ^= (t >> 2); + t ^= (t >> 1); + return t; +} diff --git a/libs/libcodec2/src/phase.c b/libs/libcodec2/src/phase.c new file mode 100644 index 0000000000..83fd680e79 --- /dev/null +++ b/libs/libcodec2/src/phase.c @@ -0,0 +1,254 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: phase.c + AUTHOR......: David Rowe + DATE CREATED: 1/2/09 + + Functions for modelling and synthesising phase. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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 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. +*/ + +#include "defines.h" +#include "phase.h" +#include "four1.h" + +#include +#include +#include +#include + +#define VTHRESH 4.0 + +/*---------------------------------------------------------------------------*\ + + aks_to_H() + + Samples the complex LPC synthesis filter spectrum at the harmonic + frequencies. + +\*---------------------------------------------------------------------------*/ + +void aks_to_H( + MODEL *model, /* model parameters */ + float aks[], /* LPC's */ + float G, /* energy term */ + COMP H[], /* complex LPC spectral samples */ + int order +) +{ + COMP Pw[FFT_DEC]; /* power spectrum */ + int i,m; /* loop variables */ + int am,bm; /* limits of current band */ + float r; /* no. rads/bin */ + float Em; /* energy in band */ + float Am; /* spectral amplitude sample */ + int b; /* centre bin of harmonic */ + float phi_; /* phase of LPC spectra */ + + r = TWO_PI/(FFT_DEC); + + /* Determine DFT of A(exp(jw)) ------------------------------------------*/ + + for(i=0; iL; m++) { + am = floor((m - 0.5)*model->Wo/r + 0.5); + bm = floor((m + 0.5)*model->Wo/r + 0.5); + b = floor(m*model->Wo/r + 0.5); + + Em = 0.0; + for(i=am; iWo)*N/2; + */ + + ex_phase[0] += (model->Wo)*N; + ex_phase[0] -= TWO_PI*floor(ex_phase[0]/TWO_PI + 0.5); + + for(m=1; m<=model->L; m++) { + + /* generate excitation */ + + if (model->voiced) { + /* This method of adding jitter really helped remove the clicky + sound in low pitched makes like hts1a. This moves the onset + of each harmonic over at +/- 0.25 of a sample. + */ + jitter = 0.25*(1.0 - 2.0*rand()/RAND_MAX); + Ex[m].real = cos(ex_phase[0]*m - jitter*model->Wo*m); + Ex[m].imag = sin(ex_phase[0]*m - jitter*model->Wo*m); + } + else { + + /* When a few samples were tested I found that LPC filter + phase is not needed in the unvoiced case, but no harm in + keeping it. + */ + float phi = TWO_PI*(float)rand()/RAND_MAX; + Ex[m].real = cos(phi); + Ex[m].imag = sin(phi); + } + + /* filter using LPC filter */ + + A_[m].real = H[m].real*Ex[m].real - H[m].imag*Ex[m].imag; + A_[m].imag = H[m].imag*Ex[m].real + H[m].real*Ex[m].imag; + + /* modify sinusoidal phase */ + + new_phi = atan2(A_[m].imag, A_[m].real+1E-12); + model->phi[m] = new_phi; + } + +} diff --git a/libs/libcodec2/src/phase.h b/libs/libcodec2/src/phase.h new file mode 100644 index 0000000000..6dbf3fa2d6 --- /dev/null +++ b/libs/libcodec2/src/phase.h @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: phase.h + AUTHOR......: David Rowe + DATE CREATED: 1/2/09 + + Functions for modelling phase. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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 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. +*/ + +#ifndef __PHASE__ +#define __PHASE__ + +void phase_synth_zero_order(MODEL *model, float aks[], float *ex_phase); + +#endif diff --git a/libs/libcodec2/src/postfilter.c b/libs/libcodec2/src/postfilter.c new file mode 100644 index 0000000000..6dad76b1e1 --- /dev/null +++ b/libs/libcodec2/src/postfilter.c @@ -0,0 +1,131 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: postfilter.c + AUTHOR......: David Rowe + DATE CREATED: 13/09/09 + + Postfilter to improve sound quality for speech with high levels of + background noise. Unlike mixed-excitation models requires no bits + to be transmitted to handle background noise. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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 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. +*/ + +#include +#include +#include + +#include "defines.h" +#include "dump.h" +#include "postfilter.h" + +/*---------------------------------------------------------------------------*\ + + DEFINES + +\*---------------------------------------------------------------------------*/ + +#define BG_THRESH 40.0 /* only consider low levels signals for bg_est */ +#define BG_BETA 0.1 /* averaging filter constant */ + +/*---------------------------------------------------------------------------*\ + + postfilter() + + The post filter is designed to help with speech corrupted by + background noise. The zero phase model tends to make speech with + background noise sound "clicky". With high levels of background + noise the low level inter-formant parts of the spectrum will contain + noise rather than speech harmonics, so modelling them as voiced + (i.e. a continuous, non-random phase track) is inaccurate. + + Some codecs (like MBE) have a mixed voicing model that breaks the + spectrum into voiced and unvoiced regions. Several bits/frame + (5-12) are required to transmit the frequency selective voicing + information. Mixed excitation also requires accurate voicing + estimation (parameter estimators always break occasionally under + exceptional condition). + + In our case we use a post filter approach which requires no + additional bits to be transmitted. The decoder measures the average + level of the background noise during unvoiced frames. If a harmonic + is less than this level it is made unvoiced by randomising it's + phases. + + This idea is rather experimental. Some potential problems that may + happen: + + 1/ If someone says "aaaaaaaahhhhhhhhh" will background estimator track + up to speech level? This would be a bad thing. + + 2/ If background noise suddenly dissapears from the source speech does + estimate drop quickly? What is noise suddenly re-appears? + + 3/ Background noise with a non-flat sepctrum. Current algorithm just + comsiders scpetrum as a whole, but this could be broken up into + bands, each with their own estimator. + + 4/ Males and females with the same level of background noise. Check + performance the same. Changing Wo affects width of each band, may + affect bg energy estimates. + + 5/ Not sure what happens during long periods of voiced speech + e.g. "sshhhhhhh" + +\*---------------------------------------------------------------------------*/ + +void postfilter( + MODEL *model, + float *bg_est +) +{ + int m, uv; + float e; + + /* determine average energy across spectrum */ + + e = 0.0; + for(m=1; m<=model->L; m++) + e += model->A[m]*model->A[m]; + + e = 10.0*log10(e/model->L); + + /* If beneath threhold, update bg estimate. The idea + of the threshold is to prevent updating during high level + speech. */ + + if ((e < BG_THRESH) && !model->voiced) + *bg_est = *bg_est*(1.0 - BG_BETA) + e*BG_BETA; + + /* now mess with phases during voiced frames to make any harmonics + less then our background estimate unvoiced. + */ + + uv = 0; + if (model->voiced) + for(m=1; m<=model->L; m++) + if (20.0*log10(model->A[m]) < *bg_est) { + model->phi[m] = TWO_PI*(float)rand()/RAND_MAX; + uv++; + } + + dump_bg(e, *bg_est, 100.0*uv/model->L); + +} diff --git a/libs/libcodec2/src/postfilter.h b/libs/libcodec2/src/postfilter.h new file mode 100644 index 0000000000..d4dd4ae053 --- /dev/null +++ b/libs/libcodec2/src/postfilter.h @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: postfilter.h + AUTHOR......: David Rowe + DATE CREATED: 13/09/09 + + Postfilter header file. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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 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. +*/ + +#ifndef __POSTFILTER__ +#define __POSTFILTER__ + +void postfilter(MODEL *model, float *bg_est); + +#endif diff --git a/libs/libcodec2/src/quantise.c b/libs/libcodec2/src/quantise.c new file mode 100644 index 0000000000..a1cd728112 --- /dev/null +++ b/libs/libcodec2/src/quantise.c @@ -0,0 +1,868 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: quantise.c + AUTHOR......: David Rowe + DATE CREATED: 31/5/92 + + Quantisation functions for the sinusoidal coder. + +\*---------------------------------------------------------------------------*/ + +/* + 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 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. +*/ + +#include +#include +#include +#include +#include +#include + +#include "defines.h" +#include "dump.h" +#include "quantise.h" +#include "lpc.h" +#include "lsp.h" +#include "four1.h" +#include "codebook.h" + +#define LSP_DELTA1 0.01 /* grid spacing for LSP root searches */ +#define MAX_CB 20 /* max number of codebooks */ + +/* describes each codebook */ + +typedef struct { + int k; /* dimension of vector */ + int log2m; /* number of bits in m */ + int m; /* elements in codebook */ + float *fn; /* file name of text file storing the VQ */ +} LSP_CB; + +/* lsp_q describes entire quantiser made up of several codebooks */ + +#ifdef OLDER +/* 10+10+6+6 = 32 bit LSP difference split VQ */ + +LSP_CB lsp_q[] = { + {3, 1024, "/usr/src/freeswitch/libs/libcodec2-1.0/unittest/lspd123.txt"}, + {3, 1024, "/usr/src/freeswitch/libs/libcodec2-1.0/unittest/lspd456.txt"}, + {2, 64, "/usr/src/freeswitch/libs/libcodec2-1.0/unittest/lspd78.txt"}, + {2, 64, "/usr/src/freeswitch/libs/libcodec2-1.0/unittest/lspd910.txt"}, + {0, 0, ""} +}; +#endif + +LSP_CB lsp_q[] = { + {1,4,16, codebook_lsp1 }, + {1,4,16, codebook_lsp2 }, + {1,4,16, codebook_lsp3 }, + {1,4,16, codebook_lsp4 }, + {1,4,16, codebook_lsp5 }, + {1,4,16, codebook_lsp6 }, + {1,4,16, codebook_lsp7 }, + {1,3,8, codebook_lsp8 }, + {1,3,8, codebook_lsp9 }, + {1,2,4, codebook_lsp10 }, + {0,0,0, NULL }, +}; + +/* ptr to each codebook */ + +static float *plsp_cb[MAX_CB]; + +/*---------------------------------------------------------------------------*\ + + FUNCTION HEADERS + +\*---------------------------------------------------------------------------*/ + +float speech_to_uq_lsps(float lsp[], float ak[], float Sn[], float w[], + int order); + +/*---------------------------------------------------------------------------*\ + + FUNCTIONS + +\*---------------------------------------------------------------------------*/ + +int lsp_bits(int i) { + return lsp_q[i].log2m; +} + +/*---------------------------------------------------------------------------*\ + + quantise_uniform + + Simulates uniform quantising of a float. + +\*---------------------------------------------------------------------------*/ + +void quantise_uniform(float *val, float min, float max, int bits) +{ + int levels = 1 << (bits-1); + float norm; + int index; + + /* hard limit to quantiser range */ + + printf("min: %f max: %f val: %f ", min, max, val[0]); + if (val[0] < min) val[0] = min; + if (val[0] > max) val[0] = max; + + norm = (*val - min)/(max-min); + printf("%f norm: %f ", val[0], norm); + index = fabs(levels*norm + 0.5); + + *val = min + index*(max-min)/levels; + + printf("index %d val_: %f\n", index, val[0]); +} + +/*---------------------------------------------------------------------------*\ + + lspd_quantise + + Simulates differential lsp quantiser + +\*---------------------------------------------------------------------------*/ + +void lsp_quantise( + float lsp[], + float lsp_[], + int order +) +{ + int i; + float dlsp[LPC_MAX]; + float dlsp_[LPC_MAX]; + + dlsp[0] = lsp[0]; + for(i=1; i {Am} LPC decode */ + + return snr; +} + +/*---------------------------------------------------------------------------*\ + + aks_to_M2() + + Transforms the linear prediction coefficients to spectral amplitude + samples. This function determines A(m) from the average energy per + band using an FFT. + +\*---------------------------------------------------------------------------*/ + +void aks_to_M2( + float ak[], /* LPC's */ + int order, + MODEL *model, /* sinusoidal model parameters for this frame */ + float E, /* energy term */ + float *snr, /* signal to noise ratio for this frame in dB */ + int dump /* true to dump sample to dump file */ +) +{ + COMP Pw[FFT_DEC]; /* power spectrum */ + int i,m; /* loop variables */ + int am,bm; /* limits of current band */ + float r; /* no. rads/bin */ + float Em; /* energy in band */ + float Am; /* spectral amplitude sample */ + float signal, noise; + + r = TWO_PI/(FFT_DEC); + + /* Determine DFT of A(exp(jw)) --------------------------------------------*/ + + for(i=0; iL; m++) { + am = floor((m - 0.5)*model->Wo/r + 0.5); + bm = floor((m + 0.5)*model->Wo/r + 0.5); + Em = 0.0; + + for(i=am; iA[m],2.0); + noise += pow(model->A[m] - Am,2.0); + model->A[m] = Am; + } + *snr = 10.0*log10(signal/noise); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: encode_Wo() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Encodes Wo using a WO_LEVELS quantiser. + +\*---------------------------------------------------------------------------*/ + +int encode_Wo(float Wo) +{ + int index; + float Wo_min = TWO_PI/P_MAX; + float Wo_max = TWO_PI/P_MIN; + float norm; + + norm = (Wo - Wo_min)/(Wo_max - Wo_min); + index = floor(WO_LEVELS * norm + 0.5); + if (index < 0 ) index = 0; + if (index > (WO_LEVELS-1)) index = WO_LEVELS-1; + + return index; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: decode_Wo() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Decodes Wo using a WO_LEVELS quantiser. + +\*---------------------------------------------------------------------------*/ + +float decode_Wo(int index) +{ + float Wo_min = TWO_PI/P_MAX; + float Wo_max = TWO_PI/P_MIN; + float step; + float Wo; + + step = (Wo_max - Wo_min)/WO_LEVELS; + Wo = Wo_min + step*(index); + + return Wo; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: speech_to_uq_lsps() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Analyse a windowed frame of time domain speech to determine LPCs + which are the converted to LSPs for quantisation and transmission + over the channel. + +\*---------------------------------------------------------------------------*/ + +float speech_to_uq_lsps(float lsp[], + float ak[], + float Sn[], + float w[], + int order +) +{ + int i, roots; + float Wn[M]; + float R[LPC_MAX+1]; + float E; + + for(i=0; iA[1]) - 20.0*log10(tmp.A[1])); + if (E1 > 6.0) + return 1; + else + return 0; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: apply_lpc_correction() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Apply first harmonic LPC correction at decoder. + +\*---------------------------------------------------------------------------*/ + +void apply_lpc_correction(MODEL *model, int lpc_correction) +{ + if (lpc_correction) { + if (model->Wo < (PI*150.0/4000)) { + model->A[1] *= 0.032; + } + } +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: encode_energy() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Encodes LPC energy using an E_LEVELS quantiser. + +\*---------------------------------------------------------------------------*/ + +int encode_energy(float e) +{ + int index; + float e_min = E_MIN_DB; + float e_max = E_MAX_DB; + float norm; + + e = 10.0*log10(e); + norm = (e - e_min)/(e_max - e_min); + index = floor(E_LEVELS * norm + 0.5); + if (index < 0 ) index = 0; + if (index > (E_LEVELS-1)) index = E_LEVELS-1; + + return index; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: decode_energy() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Decodes energy using a WO_BITS quantiser. + +\*---------------------------------------------------------------------------*/ + +float decode_energy(int index) +{ + float e_min = E_MIN_DB; + float e_max = E_MAX_DB; + float step; + float e; + + step = (e_max - e_min)/E_LEVELS; + e = e_min + step*(index); + e = pow(10.0,e/10.0); + + return e; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: encode_amplitudes() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Time domain LPC is used model the amplitudes which are then + converted to LSPs and quantised. So we don't actually encode the + amplitudes directly, rather we derive an equivalent representation + from the time domain speech. + +\*---------------------------------------------------------------------------*/ + +void encode_amplitudes(int lsp_indexes[], + int *lpc_correction, + int *energy_index, + MODEL *model, + float Sn[], + float w[]) +{ + float lsps[LPC_ORD]; + float ak[LPC_ORD+1]; + float e; + + e = speech_to_uq_lsps(lsps, ak, Sn, w, LPC_ORD); + encode_lsps(lsp_indexes, lsps, LPC_ORD); + *lpc_correction = need_lpc_correction(model, ak, e); + *energy_index = encode_energy(e); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: decode_amplitudes() + AUTHOR......: David Rowe + DATE CREATED: 22/8/2010 + + Given the amplitude quantiser indexes recovers the harmonic + amplitudes. + +\*---------------------------------------------------------------------------*/ + +float decode_amplitudes(MODEL *model, + float ak[], + int lsp_indexes[], + int lpc_correction, + int energy_index +) +{ + float lsps[LPC_ORD]; + float e; + float snr; + + decode_lsps(lsps, lsp_indexes, LPC_ORD); + bw_expand_lsps(lsps, LPC_ORD); + lsp_to_lpc(lsps, ak, LPC_ORD); + e = decode_energy(energy_index); + aks_to_M2(ak, LPC_ORD, model, e, &snr, 1); + apply_lpc_correction(model, lpc_correction); + + return snr; +} diff --git a/libs/libcodec2/src/quantise.h b/libs/libcodec2/src/quantise.h new file mode 100644 index 0000000000..ded7645381 --- /dev/null +++ b/libs/libcodec2/src/quantise.h @@ -0,0 +1,84 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: quantise.h + AUTHOR......: David Rowe + DATE CREATED: 31/5/92 + + Quantisation functions for the sinusoidal coder. + +\*---------------------------------------------------------------------------*/ + +/* + 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 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. +*/ + +#ifndef __QUANTISE__ +#define __QUANTISE__ + +#define WO_BITS 7 +#define WO_LEVELS (1< +#include +#include + +#include "defines.h" +#include "sine.h" +#include "four1.h" + +/*---------------------------------------------------------------------------*\ + + HEADERS + +\*---------------------------------------------------------------------------*/ + +void hs_pitch_refinement(MODEL *model, COMP Sw[], float pmin, float pmax, + float pstep); + +/*---------------------------------------------------------------------------*\ + + FUNCTIONS + +\*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: make_analysis_window + AUTHOR......: David Rowe + DATE CREATED: 11/5/94 + + Init function that generates the time domain analysis window and it's DFT. + +\*---------------------------------------------------------------------------*/ + +void make_analysis_window(float w[],COMP W[]) +{ + float m; + COMP temp; + int i,j; + + /* + Generate Hamming window centered on M-sample pitch analysis window + + 0 M/2 M-1 + |-------------|-------------| + |-------|-------| + NW samples + + All our analysis/synthsis is centred on the M/2 sample. + */ + + m = 0.0; + for(i=0; iWo + 5; + pmin = TWO_PI/model->Wo - 5; + pstep = 1.0; + hs_pitch_refinement(model,Sw,pmin,pmax,pstep); + + /* Fine refinement */ + + pmax = TWO_PI/model->Wo + 1; + pmin = TWO_PI/model->Wo - 1; + pstep = 0.25; + hs_pitch_refinement(model,Sw,pmin,pmax,pstep); + + /* Limit range */ + + if (model->Wo < TWO_PI/P_MAX) + model->Wo = TWO_PI/P_MAX; + if (model->Wo > TWO_PI/P_MIN) + model->Wo = TWO_PI/P_MIN; + + model->L = floor(PI/model->Wo); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: hs_pitch_refinement + AUTHOR......: David Rowe + DATE CREATED: 27/5/94 + + Harmonic sum pitch refinement function. + + pmin pitch search range minimum + pmax pitch search range maximum + step pitch search step size + model current pitch estimate in model.Wo + + model refined pitch estimate in model.Wo + +\*---------------------------------------------------------------------------*/ + +void hs_pitch_refinement(MODEL *model, COMP Sw[], float pmin, float pmax, float pstep) +{ + int m; /* loop variable */ + int b; /* bin for current harmonic centre */ + float E; /* energy for current pitch*/ + float Wo; /* current "test" fundamental freq. */ + float Wom; /* Wo that maximises E */ + float Em; /* mamimum energy */ + float r; /* number of rads/bin */ + float p; /* current pitch */ + + /* Initialisation */ + + model->L = PI/model->Wo; /* use initial pitch est. for L */ + Wom = model->Wo; + Em = 0.0; + r = TWO_PI/FFT_ENC; + + /* Determine harmonic sum for a range of Wo values */ + + for(p=pmin; p<=pmax; p+=pstep) { + E = 0.0; + Wo = TWO_PI/p; + + /* Sum harmonic magnitudes */ + + for(m=1; m<=model->L; m++) { + b = floor(m*Wo/r + 0.5); + E += Sw[b].real*Sw[b].real + Sw[b].imag*Sw[b].imag; + } + + /* Compare to see if this is a maximum */ + + if (E > Em) { + Em = E; + Wom = Wo; + } + } + + model->Wo = Wom; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: estimate_amplitudes + AUTHOR......: David Rowe + DATE CREATED: 27/5/94 + + Estimates the complex amplitudes of the harmonics. + +\*---------------------------------------------------------------------------*/ + +void estimate_amplitudes(MODEL *model, COMP Sw[], COMP W[]) +{ + int i,m; /* loop variables */ + int am,bm; /* bounds of current harmonic */ + int b; /* DFT bin of centre of current harmonic */ + float den; /* denominator of amplitude expression */ + float r; /* number of rads/bin */ + int offset; + COMP Am; + + r = TWO_PI/FFT_ENC; + + for(m=1; m<=model->L; m++) { + den = 0.0; + am = floor((m - 0.5)*model->Wo/r + 0.5); + bm = floor((m + 0.5)*model->Wo/r + 0.5); + b = floor(m*model->Wo/r + 0.5); + + /* Estimate ampltude of harmonic */ + + den = 0.0; + Am.real = Am.imag = 0.0; + for(i=am; iWo/r + 0.5); + Am.real += Sw[i].real*W[offset].real; + Am.imag += Sw[i].imag*W[offset].real; + } + + model->A[m] = sqrt(den); + + /* Estimate phase of harmonic */ + + model->phi[m] = atan2(Sw[b].imag,Sw[b].real); + } +} + +/*---------------------------------------------------------------------------*\ + + est_voicing_mbe() + + Returns the error of the MBE cost function for a fiven F0. + + Note: I think a lot of the operations below can be simplified as + W[].imag = 0 and has been normalised such that den always equals 1. + +\*---------------------------------------------------------------------------*/ + +float est_voicing_mbe( + MODEL *model, + COMP Sw[], + COMP W[], + float f0, + COMP Sw_[] /* DFT of all voiced synthesised signal for f0 */ + /* useful for debugging/dump file */ +) +{ + int i,l,al,bl,m; /* loop variables */ + COMP Am; /* amplitude sample for this band */ + int offset; /* centers Hw[] about current harmonic */ + float den; /* denominator of Am expression */ + float error; /* accumulated error between originl and synthesised */ + float Wo; /* current "test" fundamental freq. */ + int L; + float sig, snr; + + sig = 0.0; + for(l=1; l<=model->L/4; l++) { + sig += model->A[l]*model->A[l]; + } + + for(i=0; i V_THRESH) + model->voiced = 1; + else + model->voiced = 0; + + return snr; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: make_synthesis_window + AUTHOR......: David Rowe + DATE CREATED: 11/5/94 + + Init function that generates the trapezoidal (Parzen) sythesis window. + +\*---------------------------------------------------------------------------*/ + +void make_synthesis_window(float Pn[]) +{ + int i; + float win; + + /* Generate Parzen window in time domain */ + + win = 0.0; + for(i=0; iL; l++) { + b = floor(l*model->Wo*FFT_DEC/TWO_PI + 0.5); + Sw_[b].real = model->A[l]*cos(model->phi[l]); + Sw_[b].imag = model->A[l]*sin(model->phi[l]); + Sw_[FFT_DEC-b].real = Sw_[b].real; + Sw_[FFT_DEC-b].imag = -Sw_[b].imag; + } + + /* Perform inverse DFT */ + + four1(&Sw_[-1].imag,FFT_DEC,1); + + /* Overlap add to previous samples */ + + for(i=0; i +#include +#include + +void scan_line(FILE *fp, float f[], int n); + +int main(int argc, char *argv[]) { + FILE *ftext; /* text file of vectors */ + FILE *ffloat; /* float file of vectors */ + int st,en; /* start and end values of vector to copy */ + float *buf; /* ptr to vector read from ftext */ + long lines; /* lines read so far */ + + if (argc != 5) { + printf("usage: extract TextFile FloatFile start end\n"); + exit(0); + } + + /* read command line arguments and open files */ + + ftext = fopen(argv[1],"rt"); + if (ftext == NULL) { + printf("Error opening text file: %s\n",argv[1]); + exit(1); + } + + ffloat = fopen(argv[2],"wb"); + if (ffloat == NULL) { + printf("Error opening float file: %s\n",argv[2]); + exit(1); + } + + st = atoi(argv[3]); + en = atoi(argv[4]); + + buf = (float*)malloc(en*sizeof(float)); + if (buf == NULL) { + printf("Error in malloc()\n"); + exit(1); + } + + lines = 0; + while(!feof(ftext)) { + scan_line(ftext, buf, en); + fwrite(&buf[st-1], sizeof(float), en-st+1, ffloat); + printf("\r%ld lines",lines++); + } + printf("\n"); + + /* clean up and exit */ + + free(buf); + fclose(ftext); + fclose(ffloat); + + return 0; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: scan_line() + + AUTHOR......: David Rowe + DATE CREATED: 20/2/95 + + This function reads a vector of floats from a line in a text file. + +\*---------------------------------------------------------------------------*/ + +void scan_line(FILE *fp, float f[], int n) +/* FILE *fp; file ptr to text file */ +/* float f[]; array of floats to return */ +/* int n; number of floats in line */ +{ + char s[MAX_STR]; + char *ps,*pe; + int i; + + fgets(s,MAX_STR,fp); + ps = pe = s; + for(i=0; i +#include +#include +#include +#include "lpc.h" /* LPC analysis functions */ +#include "lsp.h" /* LSP encode/decode functions */ + +int switch_present(sw,argc,argv) + char sw[]; /* switch in string form */ + int argc; /* number of command line arguments */ + char *argv[]; /* array of command line arguments in string form */ +{ + int i; /* loop variable */ + + for(i=1; i THRESH) { + af++; + printf("Active Frame: %ld unstables: %d\n",af, unstables); + + find_aks(Sn, ak, NW, P, &Eres); + roots = lpc_to_lsp(&ak[1], P , lsp, 5, LSP_DELTA1); + if (roots == P) { + if (lspd) { + fprintf(flsp,"%f ",lsp[0]); + for(i=1; i +#include +#include + +#define N 160 +#define P 10 + +int main(int argc, char *argv[]) +{ + FILE *fin,*fres; /* input and output files */ + short buf[N]; /* buffer of 16 bit speech samples */ + float Sn[P+N]; /* input speech samples */ + float res[N]; /* residual after LPC filtering */ + float E; + float ak[P+1]; /* LP coeffs */ + + int frames; /* frames processed so far */ + int i; /* loop variables */ + + if (argc < 3) { + printf("usage: %s InputFile ResidualFile\n", argv[0]); + exit(0); + } + + /* Open files */ + + if ((fin = fopen(argv[1],"rb")) == NULL) { + printf("Error opening input file: %s\n",argv[1]); + exit(0); + } + + if ((fres = fopen(argv[2],"wb")) == NULL) { + printf("Error opening output residual file: %s\n",argv[2]); + exit(0); + } + + /* Initialise */ + + frames = 0; + for(i=0; i +#include +#include +#include +#include +#include + +#define N 160 +#define P 10 + +#define LPC_FLOOR 0.0002 /* autocorrelation floor */ +#define LSP_DELTA1 0.2 /* grid spacing for LSP root searches */ +#define NDFT 256 /* DFT size for SD calculation */ + +/* Speex lag window */ + +const float lag_window[11] = { + 1.00000, 0.99716, 0.98869, 0.97474, 0.95554, 0.93140, 0.90273, 0.86998, + 0.83367, 0.79434, 0.75258 +}; + +/*---------------------------------------------------------------------------*\ + + find_aks_for_lsp() + + This function takes a frame of samples, and determines the linear + prediction coefficients for that frame of samples. Modified version of + find_aks from lpc.c to include autocorrelation noise floor and lag window + to match Speex processing steps prior to LSP conversion. + +\*---------------------------------------------------------------------------*/ + +void find_aks_for_lsp( + float Sn[], /* Nsam samples with order sample memory */ + float a[], /* order+1 LPCs with first coeff 1.0 */ + int Nsam, /* number of input speech samples */ + int order, /* order of the LPC analysis */ + float *E /* residual energy */ +) +{ + float Wn[N]; /* windowed frame of Nsam speech samples */ + float R[P+1]; /* order+1 autocorrelation values of Sn[] */ + int i; + + hanning_window(Sn,Wn,Nsam); + + autocorrelate(Wn,R,Nsam,order); + R[0] += LPC_FLOOR; + assert(order == 10); /* lag window only defined for order == 10 */ + for(i=0; i<=order; i++) + R[i] *= lag_window[i]; + levinson_durbin(R,a,order); + + *E = 0.0; + for(i=0; i<=order; i++) + *E += a[i]*R[i]; + if (*E < 0.0) + *E = 1E-12; +} + +/*---------------------------------------------------------------------------*\ + + MAIN + +\*---------------------------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + FILE *fin; /* input speech files */ + short buf[N]; /* buffer of 16 bit speech samples */ + float Sn[P+N]; /* input speech samples */ + float E; + float ak[P+1]; /* LP coeffs */ + float ak_[P+1]; /* quantised LP coeffs */ + float lsp[P]; + float lsp_[P]; /* quantised LSPs */ + int roots; /* number of LSP roots found */ + int frames; /* frames processed so far */ + int i; /* loop variables */ + + SpeexBits bits; + + float sd; /* SD for this frame */ + float totsd; /* accumulated SD so far */ + int gt2,gt4; /* number of frames > 2 and 4 dB SD */ + int unstables; /* number of unstable LSP frames */ + + if (argc < 2) { + printf("usage: %s InputFile\n", argv[0]); + exit(0); + } + + /* Open files */ + + if ((fin = fopen(argv[1],"rb")) == NULL) { + printf("Error opening input file: %s\n",argv[1]); + exit(0); + } + + /* Initialise */ + + frames = 0; + for(i=0; i 2.0) gt2++; + if (sd > 4.0) gt4++; + totsd += sd; + } + else + unstables++; + } + + fclose(fin); + + printf("frames = %d Av sd = %3.2f dB", frames, totsd/frames); + printf(" >2 dB %3.2f%% >4 dB %3.2f%% unstables: %d\n",gt2*100.0/frames, + gt4*100.0/frames, unstables); + + return 0; +} + diff --git a/libs/libcodec2/unittest/sd.c b/libs/libcodec2/unittest/sd.c new file mode 100644 index 0000000000..f77b5099d5 --- /dev/null +++ b/libs/libcodec2/unittest/sd.c @@ -0,0 +1,84 @@ +/*--------------------------------------------------------------------------*\ + + FILE........: sd.c + AUTHOR......: David Rowe + DATE CREATED: 20/7/93 + + Function to determine spectral distortion between two sets of LPCs. + +\*--------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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, 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 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. +*/ + +#define MAX_N 2048 /* maximum DFT size */ + +#include +#include "four1.h" +#include "comp.h" +#include "sd.h" + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: spectral_dist() + + AUTHOR......: David Rowe + DATE CREATED: 20/7/93 + + This function returns the soectral distoertion between two + sets of LPCs. + +\*---------------------------------------------------------------------------*/ + +float spectral_dist(float ak1[], float ak2[], int p, int n) +/* float ak1[]; unquantised set of p+1 LPCs */ +/* float ak2[]; quantised set of p+1 LPCs */ +/* int p; LP order */ +/* int n; DFT size to use for SD calculations (power of 2) */ +{ + COMP A1[MAX_N]; /* DFT of ak1[] */ + COMP A2[MAX_N]; /* DFT of ak2[] */ + float P1,P2; /* power of current bin */ + float sd; + int i; + + for(i=0; i +#include +#include +#include +#include +#include "defines.h" +#include "codec2.h" +#include "quantise.h" +#include "interp.h" + +/* CODEC2 struct copies from codec2.c to help with testing */ + +typedef struct { + float Sn[M]; /* input speech */ + float w[M]; /* time domain hamming window */ + COMP W[FFT_ENC]; /* DFT of w[] */ + float Pn[2*N]; /* trapezoidal synthesis window */ + float Sn_[2*N]; /* synthesised speech */ + float prev_Wo; /* previous frame's pitch estimate */ + float ex_phase; /* excitation model phase track */ + float bg_est; /* background noise estimate for post filter */ + MODEL prev_model; /* model parameters from 20ms ago */ +} CODEC2; + +void analyse_one_frame(CODEC2 *c2, MODEL *model, short speech[]); +void synthesise_one_frame(CODEC2 *c2, short speech[], MODEL *model, float ak[]); + +int test1() +{ + FILE *fin, *fout; + short buf[N]; + void *c2; + CODEC2 *c3; + MODEL model; + float ak[LPC_ORD+1]; + float lsps[LPC_ORD]; + + c2 = codec2_create(); + c3 = (CODEC2*)c2; + + fin = fopen("../raw/hts1a.raw", "rb"); + assert(fin != NULL); + fout = fopen("hts1a_test.raw", "wb"); + assert(fout != NULL); + + while(fread(buf, sizeof(short), N, fin) == N) { + analyse_one_frame(c3, &model, buf); + speech_to_uq_lsps(lsps, ak, c3->Sn, c3->w, LPC_ORD); + synthesise_one_frame(c3, buf, &model, ak); + fwrite(buf, sizeof(short), N, fout); + } + + codec2_destroy(c2); + + fclose(fin); + fclose(fout); + + return 0; +} + +int test2() +{ + FILE *fin, *fout; + short buf[2*N]; + void *c2; + CODEC2 *c3; + MODEL model, model_interp; + float ak[LPC_ORD+1]; + int voiced1, voiced2; + int lsp_indexes[LPC_ORD]; + int lpc_correction; + int energy_index; + int Wo_index; + char bits[CODEC2_BITS_PER_FRAME]; + int nbit; + int i; + + c2 = codec2_create(); + c3 = (CODEC2*)c2; + + fin = fopen("../raw/hts1a.raw", "rb"); + assert(fin != NULL); + fout = fopen("hts1a_test.raw", "wb"); + assert(fout != NULL); + + while(fread(buf, sizeof(short), 2*N, fin) == 2*N) { + /* first 10ms analysis frame - we just want voicing */ + + analyse_one_frame(c3, &model, buf); + voiced1 = model.voiced; + + /* second 10ms analysis frame */ + + analyse_one_frame(c3, &model, &buf[N]); + voiced2 = model.voiced; + + Wo_index = encode_Wo(model.Wo); + encode_amplitudes(lsp_indexes, + &lpc_correction, + &energy_index, + &model, + c3->Sn, + c3->w); + nbit = 0; + pack(bits, &nbit, Wo_index, WO_BITS); + for(i=0; iprev_model, &model); + + synthesise_one_frame(c3, buf, &model_interp, ak); + synthesise_one_frame(c3, &buf[N], &model, ak); + + memcpy(&c3->prev_model, &model, sizeof(MODEL)); + fwrite(buf, sizeof(short), 2*N, fout); + } + + codec2_destroy(c2); + + fclose(fin); + fclose(fout); + + return 0; +} + +int test3() +{ + FILE *fin, *fout, *fbits; + short buf1[2*N]; + short buf2[2*N]; + char bits[CODEC2_BITS_PER_FRAME]; + void *c2; + + c2 = codec2_create(); + + fin = fopen("../raw/hts1a.raw", "rb"); + assert(fin != NULL); + fout = fopen("hts1a_test.raw", "wb"); + assert(fout != NULL); + fbits = fopen("hts1a_test3.bit", "wb"); + assert(fout != NULL); + + while(fread(buf1, sizeof(short), 2*N, fin) == 2*N) { + codec2_encode(c2, bits, buf1); + fwrite(bits, sizeof(char), CODEC2_BITS_PER_FRAME, fbits); + codec2_decode(c2, buf2, bits); + fwrite(buf2, sizeof(short), CODEC2_SAMPLES_PER_FRAME, fout); + } + + codec2_destroy(c2); + + fclose(fin); + fclose(fout); + fclose(fbits); + + return 0; +} + +int main() { + test3(); + return 0; +} diff --git a/libs/libcodec2/unittest/tcontphase.c b/libs/libcodec2/unittest/tcontphase.c new file mode 100644 index 0000000000..ee2f662a48 --- /dev/null +++ b/libs/libcodec2/unittest/tcontphase.c @@ -0,0 +1,187 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: tcontphase.c + AUTHOR......: David Rowe + DATE CREATED: 11/9/09 + + Test program for developing continuous phase track synthesis algorithm. + However while developing this it was discovered that synthesis_mixed() + worked just as well. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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, 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 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. +*/ + +#define N 80 /* frame size */ +#define F 160 /* frames to synthesis */ +#define P 10 /* LPC order */ + +#include +#include +#include +#include +#include "sine.h" +#include "dump.h" +#include "synth.h" +#include "phase.h" + +int frames; + +float ak[] = { + 1.000000, +-1.455836, + 1.361841, +-0.879267, + 0.915985, +-1.002202, + 0.944103, +-0.743094, + 1.053356, +-0.817491, + 0.431222 +}; + + +/*---------------------------------------------------------------------------*\ + + switch_present() + + Searches the command line arguments for a "switch". If the switch is + found, returns the command line argument where it ws found, else returns + NULL. + +\*---------------------------------------------------------------------------*/ + +int switch_present(sw,argc,argv) + char sw[]; /* switch in string form */ + int argc; /* number of command line arguments */ + char *argv[]; /* array of command line arguments in string form */ +{ + int i; /* loop variable */ + + for(i=1; i +#include +#include +#include +#include +#include + +#include "defines.h" +#include "sine.h" +#include "interp.h" + +void make_amp(MODEL *model, float f0, float cdB, float mdBHz) +{ + int i; + float mdBrad = mdBHz*FS/TWO_PI; + + model->Wo = f0*TWO_PI/FS; + model->L = PI/model->Wo; + for(i=0; i<=model->L; i++) + model->A[i] = pow(10.0,(cdB + (float)i*model->Wo*mdBrad)/20.0); + model->voiced = 1; +} + +void write_amp(char file[], MODEL *model) +{ + FILE *f; + int i; + + f = fopen(file,"wt"); + for(i=1; i<=model->L; i++) + fprintf(f, "%f\t%f\n", model->Wo*i, model->A[i]); + fclose(f); +} + +char *get_next_float(char *s, float *num) +{ + char *p = s; + char tmp[MAX_STR]; + + while(*p && !isspace(*p)) + p++; + memcpy(tmp, s, p-s); + tmp[p-s] = 0; + *num = atof(tmp); + + return p+1; +} + +char *get_next_int(char *s, int *num) +{ + char *p = s; + char tmp[MAX_STR]; + + while(*p && !isspace(*p)) + p++; + memcpy(tmp, s, p-s); + tmp[p-s] = 0; + *num = atoi(tmp); + + return p+1; +} + +void load_amp(MODEL *model, char file[], int frame) +{ + FILE *f; + int i; + char s[1024]; + char *ps; + + f = fopen(file,"rt"); + + for(i=0; iWo); + ps = get_next_int(ps, &model->L); + for(i=1; i<=model->L; i++) + ps = get_next_float(ps, &model->A[i]); + + fclose(f); +} + +int main() { + MODEL prev, next, interp; + + //make_amp(&prev, 50.0, 60.0, 6E-3); + //make_amp(&next, 50.0, 40.0, 6E-3); + load_amp(&prev, "../src/hts1a_model.txt", 32); + load_amp(&next, "../src/hts1a_model.txt", 34); + + interp.voiced = 1; + interpolate(&interp, &prev, &next); + + write_amp("tinterp_prev.txt", &prev); + write_amp("tinterp_interp.txt", &interp); + write_amp("tinterp_next.txt", &next); + + return 0; +} diff --git a/libs/libcodec2/unittest/tnlp.c b/libs/libcodec2/unittest/tnlp.c new file mode 100644 index 0000000000..4abf69c4ef --- /dev/null +++ b/libs/libcodec2/unittest/tnlp.c @@ -0,0 +1,148 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: tnlp.c + AUTHOR......: David Rowe + DATE CREATED: 23/3/93 + + Test program for non linear pitch estimation functions. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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, 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 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. +*/ + +#define N 80 /* frame size */ +#define M 320 /* pitch analysis window size */ +#define PITCH_MIN 20 +#define PITCH_MAX 160 +#define TNLP + +#include +#include +#include +#include + +#include "defines.h" +#include "dump.h" +#include "sine.h" +#include "nlp.h" + +int frames; + +/*---------------------------------------------------------------------------*\ + + switch_present() + + Searches the command line arguments for a "switch". If the switch is + found, returns the command line argument where it ws found, else returns + NULL. + +\*---------------------------------------------------------------------------*/ + +int switch_present(sw,argc,argv) + char sw[]; /* switch in string form */ + int argc; /* number of command line arguments */ + char *argv[]; /* array of command line arguments in string form */ +{ + int i; /* loop variable */ + + for(i=1; i +#include +#include +#include +#include + +#include "defines.h" +#include "dump.h" +#include "quantise.h" + +int test_Wo_quant(); +int test_lsp_quant(); +int test_lsp(int lsp_number, int levels, float max_error_hz); +int test_energy_quant(int levels, float max_error_dB); + +int main() { + quantise_init(); + test_Wo_quant(); + test_lsp_quant(); + test_energy_quant(E_LEVELS, 0.5*(E_MAX_DB - E_MIN_DB)/E_LEVELS); + + return 0; +} + +int test_lsp_quant() { + test_lsp( 1, 16, 12.5); + test_lsp( 2, 16, 12.5); + test_lsp( 3, 16, 25); + test_lsp( 4, 16, 50); + test_lsp( 5, 16, 50); + test_lsp( 6, 16, 50); + test_lsp( 7, 16, 50); + test_lsp( 8, 8, 50); + test_lsp( 9, 8, 50); + test_lsp(10, 4, 100); + + return 0; +} + +int test_energy_quant(int levels, float max_error_dB) { + FILE *fe; + float e,e_dec, error, low_e, high_e; + int index, index_in, index_out, i; + + /* check 1:1 match between input and output levels */ + + for(i=0; i max_error_dB) { + printf("error: %f %f\n", error, max_error_dB); + exit(0); + } + } + + fclose(fe); + return 0; +} + +int test_lsp(int lsp_number, int levels, float max_error_hz) { + float lsp[LPC_ORD]; + int indexes_in[LPC_ORD]; + int indexes_out[LPC_ORD]; + int indexes[LPC_ORD]; + int i; + float lowf, highf, f, error; + char s[MAX_STR]; + FILE *flsp; + float max_error_rads; + + lsp_number--; + max_error_rads = max_error_hz*TWO_PI/FS; + + for(i=0; i max_error_rads) { + printf("%d error: %f %f\n", lsp_number+1, error, max_error_rads); + exit(0); + } + } + + fclose(flsp); + + printf("OK\n"); + + return 0; +} + +int test_Wo_quant() { + int c; + FILE *f; + float Wo,Wo_dec, error, step_size; + int index, index_in, index_out; + + /* output Wo quant curve for plotting */ + + f = fopen("quant_pitch.txt","wt"); + + for(Wo=0.9*(TWO_PI/P_MAX); Wo<=1.1*(TWO_PI/P_MIN); Wo += 0.001) { + index = encode_Wo(Wo); + fprintf(f, "%f %d\n", Wo, index); + } + + fclose(f); + + /* check for all Wo codes we get 1:1 match between encoder + and decoder Wo levels */ + + for(c=0; c (step_size/2.0)) { + printf("error: %f step_size/2: %f\n", error, step_size/2.0); + exit(0); + } + fprintf(f,"%f\n",error); + } + printf("OK\n"); + + fclose(f); + return 0; +} diff --git a/libs/libcodec2/unittest/vqtrain.c b/libs/libcodec2/unittest/vqtrain.c new file mode 100644 index 0000000000..b46d4fcf30 --- /dev/null +++ b/libs/libcodec2/unittest/vqtrain.c @@ -0,0 +1,297 @@ +/*--------------------------------------------------------------------------*\ + + FILE........: VQTRAIN.C + AUTHOR......: David Rowe + DATE CREATED: 23/2/95 + + This program trains vector quantisers using K dimensional Lloyd-Max + method. + +\*--------------------------------------------------------------------------*/ + +/* + Copyright (C) 2009 David Rowe + + 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, 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 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. +*/ + +/*-----------------------------------------------------------------------*\ + + INCLUDES + +\*-----------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include + +/*-----------------------------------------------------------------------*\ + + DEFINES + +\*-----------------------------------------------------------------------*/ + +#define DELTAQ 0.01 /* quiting distortion */ +#define MAX_STR 80 /* maximum string length */ + +/*-----------------------------------------------------------------------*\ + + FUNCTION PROTOTYPES + +\*-----------------------------------------------------------------------*/ + +void zero(float v[], int k); +void acc(float v1[], float v2[], int k); +void norm(float v[], int k, long n); +long quantise(float cb[], float vec[], int k, int m, float *se); + +/*-----------------------------------------------------------------------*\ + + MAIN + +\*-----------------------------------------------------------------------*/ + +int main(int argc, char *argv[]) { + long k,m; /* dimension and codebook size */ + float *vec; /* current vector */ + float *cb; /* vector codebook */ + float *cent; /* centroids for each codebook entry */ + long *n; /* number of vectors in this interval */ + long J; /* number of vectors in training set */ + long i,j; + long ind; /* index of current vector */ + float se; /* squared error for this iteration */ + float Dn,Dn_1; /* current and previous iterations distortion */ + float delta; /* improvement in distortion */ + FILE *ftrain; /* file containing training set */ + FILE *fvq; /* file containing vector quantiser */ + + /* Interpret command line arguments */ + + if (argc != 5) { + printf("usage: vqtrain TrainFile K M VQFile\n"); + exit(0); + } + + /* Open training file */ + + ftrain = fopen(argv[1],"rb"); + if (ftrain == NULL) { + printf("Error opening training database file: %s\n",argv[1]); + exit(1); + } + + /* determine k and m, and allocate arrays */ + + k = atol(argv[2]); + m = atol(argv[3]); + printf("dimension K=%ld number of entries M=%ld\n", k,m); + vec = (float*)malloc(sizeof(float)*k); + cb = (float*)malloc(sizeof(float)*k*m); + cent = (float*)malloc(sizeof(float)*k*m); + n = (long*)malloc(sizeof(long)*m); + if (cb == NULL || cb == NULL || cent == NULL || vec == NULL) { + printf("Error in malloc.\n"); + exit(1); + } + + /* determine size of training set */ + + J = 0; + while(fread(vec, sizeof(float), k, ftrain) == k) + J++; + printf("J=%ld entries in training set\n", J); + + /* set up initial codebook state from samples of training set */ + + rewind(ftrain); + fread(cb, sizeof(float), k*m, ftrain); + + /* main loop */ + + Dn = 1E32; + j = 1; + do { + Dn_1 = Dn; + + /* zero centroids */ + + for(i=0; i DELTAQ) + for(i=0; i DELTAQ); + + /* save codebook to disk */ + + fvq = fopen(argv[4],"wt"); + if (fvq == NULL) { + printf("Error opening VQ file: %s\n",argv[4]); + exit(1); + } + + for(j=0; jsamples * 2); } } - return ts->samples; + return ts->samples / ts->channels; } /* don't ask */ @@ -413,6 +413,9 @@ TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cm *e++ = '\0'; } do { + if (!p) { + break; + } if ((next = strchr(p, ',')) != 0) { *next++ = '\0'; } diff --git a/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c b/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c index 0eaf955196..ca42c2c578 100644 --- a/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c +++ b/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c @@ -977,7 +977,7 @@ ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event) */ ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event) { - uint32_t i, event_id = 0; + uint32_t i, event_id = ZAP_OOB_INVALID; zt_event_t zt_event_id = 0; for(i = 1; i <= span->chan_count; i++) { @@ -1025,6 +1025,8 @@ ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event) event_id = ZAP_OOB_OFFHOOK; } else if (span->channels[i]->type == ZAP_CHAN_TYPE_FXO) { event_id = ZAP_OOB_RING_START; + } else { + event_id = ZAP_OOB_NOOP; } } break; diff --git a/libs/openzap/src/zap_io.c b/libs/openzap/src/zap_io.c index 7d37a493c4..283a9fe332 100644 --- a/libs/openzap/src/zap_io.c +++ b/libs/openzap/src/zap_io.c @@ -1017,6 +1017,7 @@ OZ_DECLARE(zap_status_t) zap_channel_set_state(zap_channel_t *zchan, zap_channel case ZAP_CHANNEL_STATE_RING: case ZAP_CHANNEL_STATE_PROGRESS_MEDIA: case ZAP_CHANNEL_STATE_PROGRESS: + case ZAP_CHANNEL_STATE_IDLE: case ZAP_CHANNEL_STATE_GET_CALLERID: case ZAP_CHANNEL_STATE_GENRING: ok = 1; diff --git a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h b/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h index d5bb617914..bd42743c9f 100644 --- a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h +++ b/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h @@ -58,7 +58,11 @@ SOFIA_BEGIN_DECLS #define HTTP_DEFAULT_SERV "80" /** HTTP protocol identifier */ +#ifndef _MSC_VER #define HTTP_PROTOCOL_TAG ((void *)0x48545450) /* 'HTTP' */ +#else +#define HTTP_PROTOCOL_TAG ((void *)(UINT_PTR)0x48545450) /* 'HTTP' */ +#endif /** HTTP parser flags */ enum { diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c index 2be30b04b9..061cd5ef2a 100644 --- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c +++ b/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c @@ -50,7 +50,11 @@ #include #include "sofia-sip/msg_tag_class.h" +#ifndef _MSC_VER #define NONE ((void*)-1) +#else +#define NONE ((void*)(INT_PTR)-1) +#endif int msghdrtag_snprintf(tagi_t const *t, char b[], size_t size) { diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h index 91fd72316b..c633aa3632 100644 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h +++ b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h @@ -299,7 +299,12 @@ enum { (h)) /** No header. */ + +#ifndef _MSC_VER #define MSG_HEADER_NONE ((msg_header_t *)-1) +#else +#define MSG_HEADER_NONE ((msg_header_t *)(INT_PTR)-1) +#endif SOFIA_END_DECLS diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h index 4a9f234dec..033c551fdb 100644 --- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h +++ b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h @@ -235,7 +235,11 @@ msg_content_length_t *msg_content_length_create(su_home_t *home, uint32_t n); SOFIAPUBVAR char const msg_mime_version_1_0[]; /** MIME multipart parser table identifier. @HIDE */ +#ifndef _MSC_VER #define MSG_MULTIPART_PROTOCOL_TAG ((void *)0x4d494d45) /* 'MIME' */ +#else +#define MSG_MULTIPART_PROTOCOL_TAG ((void *)(UINT_PTR)0x4d494d45) /* 'MIME' */ +#endif SOFIA_END_DECLS diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c b/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c index 4287ae4359..a6c7d49ac6 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c +++ b/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c @@ -41,7 +41,11 @@ #include "nea_debug.h" +#ifndef _MSC_VER #define NONE ((void *)- 1) +#else +#define NONE ((void *)(INT_PTR)- 1) +#endif #define SU_ROOT_MAGIC_T struct nea_server_s #define SU_MSG_ARG_T tagi_t diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c index 656aecc195..40ee1f8f85 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c +++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c @@ -104,8 +104,11 @@ char const nta_version[] = PACKAGE_VERSION; static char const __func__[] = "nta"; #endif +#ifndef _MSC_VER #define NONE ((void *)-1) - +#else +#define NONE ((void *)(INT_PTR)-1) +#endif /* ------------------------------------------------------------------------- */ /** Resolving order */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c index bf35263d92..b96b1f31c0 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c @@ -53,7 +53,12 @@ #include #ifndef NONE + +#ifndef _MSC_VER #define NONE ((void *)-1) +#else +#define NONE ((void *)(INT_PTR)-1) +#endif #endif /* ======================================================================== */ diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h b/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h index 318ccdd61d..97c88582a3 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h @@ -83,7 +83,11 @@ typedef struct nua_ee_data { nua_event_data_t ee_data[1]; } nua_ee_data_t; +#ifndef _MSC_VER #define NONE ((void *)-1) +#else +#define NONE ((void *)(INT_PTR)-1) +#endif typedef struct register_usage nua_registration_t; diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h index 1a235ca4c8..37ae836598 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h @@ -81,10 +81,18 @@ typedef enum { #define SIP_METHOD_PUBLISH sip_method_publish, "PUBLISH" /** Magic pointer value - never valid for SIP headers. @HI */ +#ifndef _MSC_VER #define SIP_NONE ((void const *)-1L) +#else +#define SIP_NONE ((void const *)(INT_PTR)-1L) +#endif /** SIP protocol identifier @HIDE */ +#ifndef _MSC_VER #define SIP_PROTOCOL_TAG ((void *)0x53495020) /* 'SIP'20 */ +#else +#define SIP_PROTOCOL_TAG ((void *)(UINT_PTR)0x53495020) /* 'SIP'20 */ +#endif enum { /** Default port for SIP as integer */ diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/soa.c b/libs/sofia-sip/libsofia-sip-ua/soa/soa.c index de79e0f3a5..7f272a8e6f 100644 --- a/libs/sofia-sip/libsofia-sip-ua/soa/soa.c +++ b/libs/sofia-sip/libsofia-sip-ua/soa/soa.c @@ -56,7 +56,11 @@ #include #include +#ifndef _MSC_VER #define NONE ((void *)-1) +#else +#define NONE ((void *)(INT_PTR)-1) +#endif #define XXX assert(!"implemented") typedef unsigned longlong ull; diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c b/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c index f94f9b2962..f104274ef4 100644 --- a/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c +++ b/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c @@ -396,7 +396,11 @@ sdp_rtpmap_t *soa_sdp_media_matching_rtpmap(sdp_rtpmap_t const *from, return NULL; } +#ifndef _MSC_VER #define SDP_MEDIA_NONE ((sdp_media_t *)-1) +#else +#define SDP_MEDIA_NONE ((sdp_media_t *)(INT_PTR)-1) +#endif /** Find first matching media in table @a mm. * diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c b/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c index f660b2ce22..e494571f54 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c +++ b/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c @@ -125,7 +125,7 @@ su_inline ssize_t sres_recvfrom(sres_socket_t s, void *buffer, size_t length, int flags, struct sockaddr *from, socklen_t *fromlen) { - int retval, ilen; + int retval, ilen = 0; if (fromlen) ilen = *fromlen; diff --git a/libs/sofia-sip/libsofia-sip-ua/su/su.c b/libs/sofia-sip/libsofia-sip-ua/su/su.c index 250b5d62d1..8067fdec60 100644 --- a/libs/sofia-sip/libsofia-sip-ua/su/su.c +++ b/libs/sofia-sip/libsofia-sip-ua/su/su.c @@ -434,7 +434,7 @@ ssize_t su_recv(su_socket_t s, void *buffer, size_t length, int flags) ssize_t su_recvfrom(su_socket_t s, void *buffer, size_t length, int flags, su_sockaddr_t *from, socklen_t *fromlen) { - int retval, ilen; + int retval, ilen = 0; if (fromlen) ilen = *fromlen; diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h b/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h index b56dd2d9bc..683b79a360 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h @@ -79,7 +79,11 @@ #endif #ifndef NONE +#ifndef _MSC_VER #define NONE ((void *)-1) +#else +#define NONE ((void *)(INT_PTR)-1) +#endif #endif SOFIA_BEGIN_DECLS diff --git a/libs/spandsp/src/spandsp/private/t30.h b/libs/spandsp/src/spandsp/private/t30.h index e56753e07d..b8a2e8be1c 100644 --- a/libs/spandsp/src/spandsp/private/t30.h +++ b/libs/spandsp/src/spandsp/private/t30.h @@ -60,10 +60,8 @@ struct t30_state_s int supported_t30_features; /*! \brief TRUE is ECM mode handling is enabled. */ int ecm_allowed; -#if 0 /*! \brief TRUE if we are capable of retransmitting pages */ int retransmit_capable; -#endif /*! \brief The received DCS, formatted as an ASCII string, for inclusion in the TIFF file. */ @@ -71,12 +69,12 @@ struct t30_state_s /*! \brief The text which will be used in FAX page header. No text results in no header line. */ char header_info[T30_MAX_PAGE_HEADER_INFO + 1]; -#if 0 /*! \brief TRUE for FAX page headers to overlay (i.e. replace) the beginning of the page image. FALSE for FAX page headers to add to the overall length of the page. */ int header_overlays_image; -#endif + /*! \brief TRUE if remote T.30 procedural interrupts are allowed. */ + int remote_interrupts_allowed; /*! \brief The information fields received. */ t30_exchanged_info_t rx_info; @@ -207,13 +205,6 @@ struct t30_state_s /*! \brief This is only used in full duplex (e.g. ISDN) modes. */ int timer_t8; - /* These fields are guessed based on compiler error forensics, I added them to fix the build -anthm */ - int remote_interrupts_allowed; - int rtp_events; - int rtn_events; - int retransmit_capable; - /* end guessed fields */ - /*! \brief TRUE once the far end FAX entity has been detected. */ int far_end_detected; @@ -283,12 +274,10 @@ struct t30_state_s /*! \brief The current completion status. */ int current_status; -#if 0 /*! \brief The number of RTP events */ int rtp_events; /*! \brief The number of RTN events */ int rtn_events; -#endif /*! \brief the FCF2 field of the last PPS message we received. */ uint8_t last_pps_fcf2; diff --git a/libs/spandsp/src/spandsp/t30.h b/libs/spandsp/src/spandsp/t30.h index 9df7321abd..a2fff2d28c 100644 --- a/libs/spandsp/src/spandsp/t30.h +++ b/libs/spandsp/src/spandsp/t30.h @@ -682,6 +682,10 @@ SPAN_DECLARE(void) t30_get_transfer_statistics(t30_state_t *s, t30_stats_t *t); \param state TRUE to enable interrupt request, else FALSE. */ SPAN_DECLARE(void) t30_local_interrupt_request(t30_state_t *s, int state); +/*! Allow remote interrupts of FAX exchange. + \brief Allow remote interrupts of FAX exchange. + \param s The T.30 context. + \param state TRUE to allow interruptd, else FALSE. */ SPAN_DECLARE(void) t30_remote_interrupts_allowed(t30_state_t *s, int state); #if defined(__cplusplus) diff --git a/libs/win32/openssl/libeay32.2010.vcxproj b/libs/win32/openssl/libeay32.2010.vcxproj index 1157e5ca87..4d0d9a44ee 100644 --- a/libs/win32/openssl/libeay32.2010.vcxproj +++ b/libs/win32/openssl/libeay32.2010.vcxproj @@ -74,6 +74,10 @@ true true true + $(PlatformName)\libeay32\$(Configuration)\ + $(PlatformName)\libeay32\$(Configuration)\ + $(PlatformName)\libeay32\$(Configuration)\ + $(PlatformName)\libeay32\$(Configuration)\ diff --git a/libs/win32/openssl/ssleay32.2010.vcxproj b/libs/win32/openssl/ssleay32.2010.vcxproj index 8d6c22df18..1a444bb41f 100644 --- a/libs/win32/openssl/ssleay32.2010.vcxproj +++ b/libs/win32/openssl/ssleay32.2010.vcxproj @@ -73,6 +73,10 @@ true true true + $(PlatformName)\ssleay32\$(Configuration)\ + $(PlatformName)\ssleay32\$(Configuration)\ + $(PlatformName)\ssleay32\$(Configuration)\ + $(PlatformName)\ssleay32\$(Configuration)\ diff --git a/scripts/perl/blacklist.pl b/scripts/perl/blacklist.pl new file mode 100755 index 0000000000..f434669f36 --- /dev/null +++ b/scripts/perl/blacklist.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl +# +# Add this to acl.conf.xml +# +# +# + +use Data::Dumper; +use LWP::Simple; + +# http://www.infiltrated.net/voipabuse/addresses.txt +# http://www.infiltrated.net/voipabuse/netblocks.txt + + +my @addresses = split(/\n/, get("http://www.infiltrated.net/voipabuse/addresses.txt")); +my @netblocks = split(/\n/, get("http://www.infiltrated.net/voipabuse/netblocks.txt")); + +print "\n"; +foreach $addr (@addresses) { + print " \n"; +} +print "\n"; + + +print "\n"; +foreach $netb (@netblocks) { + print " \n"; +} +print "\n"; diff --git a/scripts/perl/honeypot.pl b/scripts/perl/honeypot.pl new file mode 100755 index 0000000000..ef52142cb1 --- /dev/null +++ b/scripts/perl/honeypot.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl +# +# Add this to conf/dialplan/public but only if you wish to setup a honeypot. +# +# +# + +use Data::Dumper; +use LWP::Simple; + +# http://www.infiltrated.net/voipabuse/numberscalled.txt + +my @numberscalled = split(/\n/, get("http://www.infiltrated.net/voipabuse/numberscalled.txt")); + +foreach $number (@numberscalled) { + my ($num,$ts) = split(/\t/, $number); + + print "\n"; + print " \n"; + print " \n"; + print " \n"; + print " \n"; + print "\n"; +} + + diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index 50dde95dc7..e77d5f74ef 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -233,6 +233,8 @@ struct switch_runtime { switch_profile_timer_t *profile_timer; double profile_time; double min_idle_time; + int sql_buffer_len; + int max_sql_buffer_len; }; extern struct switch_runtime runtime; diff --git a/src/include/switch.h b/src/include/switch.h index 7143c61d91..81684c59b0 100644 --- a/src/include/switch.h +++ b/src/include/switch.h @@ -91,7 +91,10 @@ #include #pragma warning(pop) #else +/* work around for warnings in vs 2010 */ +#pragma warning (disable:6386) #include +#pragma warning (default:6386) #endif #else #include diff --git a/src/include/switch_config.h b/src/include/switch_config.h index 2281a9bbc1..4115564f56 100644 --- a/src/include/switch_config.h +++ b/src/include/switch_config.h @@ -38,7 +38,7 @@ /** * @defgroup config Config File Parser * @ingroup core1 - * This module implements a basic interface and file format parser it may be depricated in favor of database entries + * This module implements a basic interface and file format parser it may be deprecated in favor of database entries * or expanded to tie to external handlers in the future as necessary. *
  *
diff --git a/src/include/switch_core.h b/src/include/switch_core.h
index 7275f26319..8b08db7d9d 100644
--- a/src/include/switch_core.h
+++ b/src/include/switch_core.h
@@ -1339,12 +1339,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_timer_destroy(switch_timer_t *timer)
   \param pool the memory pool to use
   \return SWITCH_STATUS_SUCCESS if the handle is allocated
 */
-SWITCH_DECLARE(switch_status_t) switch_core_codec_init(switch_codec_t *codec,
+#define switch_core_codec_init(_codec, _codec_name, _fmtp, _rate, _ms, _channels, _flags, _codec_settings, _pool) \
+	switch_core_codec_init_with_bitrate(_codec, _codec_name, _fmtp, _rate, _ms, _channels, 0, _flags, _codec_settings, _pool)
+SWITCH_DECLARE(switch_status_t) switch_core_codec_init_with_bitrate(switch_codec_t *codec,
 													   const char *codec_name,
 													   const char *fmtp,
 													   uint32_t rate,
 													   int ms,
 													   int channels,
+													   uint32_t bitrate,
 													   uint32_t flags, const switch_codec_settings_t *codec_settings, switch_memory_pool_t *pool);
 
 SWITCH_DECLARE(switch_status_t) switch_core_codec_copy(switch_codec_t *codec, switch_codec_t *new_codec, switch_memory_pool_t *pool);
diff --git a/src/include/switch_cpp.h b/src/include/switch_cpp.h
index ed14f108c7..0ede8e638f 100644
--- a/src/include/switch_cpp.h
+++ b/src/include/switch_cpp.h
@@ -292,7 +292,8 @@ SWITCH_DECLARE(void) consoleCleanLog(char *msg);
 		 SWITCH_DECLARE(int) transfer(char *extension, char *dialplan = NULL, char *context = NULL);
 
 
-		 SWITCH_DECLARE(char *) read(int min_digits, int max_digits, const char *prompt_audio_file, int timeout, const char *valid_terminators);
+		 SWITCH_DECLARE(char *) read(int min_digits, int max_digits, 
+									 const char *prompt_audio_file, int timeout, const char *valid_terminators, int digit_timeout = 0);
 
 	/** \brief Play a file into channel and collect dtmfs
 	 * 
@@ -306,7 +307,7 @@ SWITCH_DECLARE(void) consoleCleanLog(char *msg);
 												 int max_digits,
 												 int max_tries,
 												 int timeout, char *terminators, char *audio_files, char *bad_input_audio_files,
-												 char *digits_regex, const char *var_name = NULL);
+												 char *digits_regex, const char *var_name = NULL, int digit_timeout = 0);
 
 	/** \brief Play a file that resides on disk into the channel
 	 *
diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h
index 40ba1dc16f..4c562a51d7 100644
--- a/src/include/switch_ivr.h
+++ b/src/include/switch_ivr.h
@@ -369,7 +369,8 @@ SWITCH_DECLARE(switch_status_t) switch_play_and_get_digits(switch_core_session_t
 														   const char *audio_file,
 														   const char *bad_input_audio_file,
 														   const char *var_name, char *digit_buffer, uint32_t digit_buffer_length,
-														   const char *digits_regex);
+														   const char *digits_regex,
+														   uint32_t digit_timeout);
 
 SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session_t *session,
 															 switch_speech_handle_t *sh,
@@ -804,7 +805,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_read(switch_core_session_t *session,
 												uint32_t max_digits,
 												const char *prompt_audio_file,
 												const char *var_name,
-												char *digit_buffer, switch_size_t digit_buffer_length, uint32_t timeout, const char *valid_terminators);
+												char *digit_buffer, 
+												switch_size_t digit_buffer_length, 
+												uint32_t timeout, 
+												const char *valid_terminators,
+												uint32_t digit_timeout);
+
 
 SWITCH_DECLARE(switch_status_t) switch_ivr_block_dtmf_session(switch_core_session_t *session);
 SWITCH_DECLARE(switch_status_t) switch_ivr_unblock_dtmf_session(switch_core_session_t *session);
diff --git a/src/include/switch_loadable_module.h b/src/include/switch_loadable_module.h
index 68719062b7..37c752bd3e 100644
--- a/src/include/switch_loadable_module.h
+++ b/src/include/switch_loadable_module.h
@@ -92,7 +92,7 @@ SWITCH_BEGIN_EXTERN_C
   \brief Initilize the module backend and load all the modules
   \return SWITCH_STATUS_SUCCESS when complete
  */
-SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(void);
+SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autoload);
 
 /*!
   \brief Shutdown the module backend and call the shutdown routine in all loaded modules
diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h
index 078b83d2fd..a6013a9386 100644
--- a/src/include/switch_module_interfaces.h
+++ b/src/include/switch_module_interfaces.h
@@ -570,42 +570,23 @@ struct switch_directory_handle {
 	void *private_info;
 };
 
-
 /* nobody has more setting than speex so we will let them set the standard */
 /*! \brief Various codec settings (currently only relevant to speex) */
 struct switch_codec_settings {
-	/*! desired quality */
-	int quality;
-	/*! desired complexity */
-	int complexity;
-	/*! desired enhancement */
-	int enhancement;
-	/*! desired vad level */
-	int vad;
-	/*! desired vbr level */
-	int vbr;
-	/*! desired vbr quality */
-	float vbr_quality;
-	/*! desired abr level */
-	int abr;
-	/*! desired dtx setting */
-	int dtx;
-	/*! desired preprocessor settings */
-	int preproc;
-	/*! preprocessor vad settings */
-	int pp_vad;
-	/*! preprocessor gain control settings */
-	int pp_agc;
-	/*! preprocessor gain level */
-	float pp_agc_level;
-	/*! preprocessor denoise level */
-	int pp_denoise;
-	/*! preprocessor dereverb settings */
-	int pp_dereverb;
-	/*! preprocessor dereverb decay level */
-	float pp_dereverb_decay;
-	/*! preprocessor dereverb level */
-	float pp_dereverb_level;
+	int unused;
+};
+
+/*! an abstract handle of a fmtp parsed by codec */
+struct switch_codec_fmtp {
+	/*! actual samples transferred per second for those who are not moron g722 RFC writers */
+	uint32_t actual_samples_per_second;
+	/*! bits transferred per second */
+	int bits_per_second;
+	/*! number of microseconds of media in one packet (ptime * 1000) */
+	int microseconds_per_packet;
+	/*! private data for the codec module to store handle specific info */
+	void *private_info;
+
 };
 
 /*! an abstract handle to a codec module */
@@ -618,8 +599,6 @@ struct switch_codec {
 	char *fmtp_in;
 	/*! fmtp line for local sdp */
 	char *fmtp_out;
-	/*! codec settings for this handle */
-	switch_codec_settings_t codec_settings;
 	/*! flags to modify behaviour */
 	uint32_t flags;
 	/*! the handle's memory pool */
@@ -678,6 +657,8 @@ struct switch_codec_interface {
 	const char *interface_name;
 	/*! a list of codec implementations related to the codec */
 	switch_codec_implementation_t *implementations;
+	/*! function to decode a codec fmtp parameters */
+	switch_core_codec_fmtp_parse_func_t parse_fmtp;
 	uint32_t codec_id;
 	switch_thread_rwlock_t *rwlock;
 	int refs;
diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h
index 7e6028a68b..7269a2b8d9 100644
--- a/src/include/switch_rtp.h
+++ b/src/include/switch_rtp.h
@@ -449,6 +449,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_stun_ping(switch_rtp_t *rtp_
 SWITCH_DECLARE(void) switch_rtp_intentional_bugs(switch_rtp_t *rtp_session, switch_rtp_bug_flag_t bugs);
 
 SWITCH_DECLARE(switch_rtp_stats_t *) switch_rtp_get_stats(switch_rtp_t *rtp_session, switch_memory_pool_t *pool);
+SWITCH_DECLARE(switch_byte_t) switch_rtp_check_auto_adj(switch_rtp_t *rtp_session);
 
 /*!
   \}
diff --git a/src/include/switch_types.h b/src/include/switch_types.h
index 5a88cd5751..57c5661c7c 100644
--- a/src/include/switch_types.h
+++ b/src/include/switch_types.h
@@ -255,7 +255,8 @@ typedef enum {
 	SCF_USE_CLOCK_RT = (1 << 10),
 	SCF_VERBOSE_EVENTS = (1 << 11),
 	SCF_USE_WIN32_MONOTONIC = (1 << 12),
-	SCF_AUTO_SCHEMAS = (1 << 13)
+	SCF_AUTO_SCHEMAS = (1 << 13),
+	SCF_MINIMAL = (1 << 14)
 } switch_core_flag_enum_t;
 typedef uint32_t switch_core_flag_t;
 
@@ -479,9 +480,16 @@ typedef struct {
 	switch_size_t flush_packet_count;
 } switch_rtp_numbers_t;
 
+
+typedef struct {
+	uint32_t packet_count;
+	uint32_t octet_count;
+} switch_rtcp_numbers_t;
+
 typedef struct {
 	switch_rtp_numbers_t inbound;
 	switch_rtp_numbers_t outbound;
+	switch_rtcp_numbers_t rtcp;
 } switch_rtp_stats_t;
 
 typedef enum {
@@ -762,9 +770,9 @@ typedef struct {
 	const char *T38FaxUdpEC;
 	const char *T38VendorInfo;
 	const char *remote_ip;
-	uint32_t remote_port;
+	uint16_t remote_port;
 	const char *local_ip;
-	uint32_t local_port;
+	uint16_t local_port;
 } switch_t38_options_t;
 
 /*!
@@ -1580,6 +1588,7 @@ typedef struct switch_core_thread_session switch_core_thread_session_t;
 typedef struct switch_codec_implementation switch_codec_implementation_t;
 typedef struct switch_buffer switch_buffer_t;
 typedef struct switch_codec_settings switch_codec_settings_t;
+typedef struct switch_codec_fmtp switch_codec_fmtp_t;
 typedef struct switch_odbc_handle switch_odbc_handle_t;
 
 typedef struct switch_io_routines switch_io_routines_t;
@@ -1638,6 +1647,7 @@ typedef switch_status_t (*switch_core_codec_decode_func_t) (switch_codec_t *code
 															void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate, unsigned int *flag);
 
 typedef switch_status_t (*switch_core_codec_init_func_t) (switch_codec_t *, switch_codec_flag_t, const switch_codec_settings_t *codec_settings);
+typedef switch_status_t (*switch_core_codec_fmtp_parse_func_t) (const char *fmtp, switch_codec_fmtp_t *codec_fmtp);
 typedef switch_status_t (*switch_core_codec_destroy_func_t) (switch_codec_t *);
 
 
diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h
index f24cee5e9f..e5d70c43cc 100644
--- a/src/include/switch_utils.h
+++ b/src/include/switch_utils.h
@@ -139,6 +139,9 @@ static inline char *switch_strchr_strict(const char *in, char find, const char *
 #define switch_is_valid_rate(_tmp) (_tmp == 8000 || _tmp == 12000 || _tmp == 16000 || _tmp == 24000 || _tmp == 32000 || _tmp == 11025 || _tmp == 22050 || _tmp == 44100 || _tmp == 48000)
 
 
+#ifdef _MSC_VER
+#pragma warning(disable:6011)
+#endif
 static inline int switch_string_has_escaped_data(const char *in)
 {
 	const char *i = strchr(in, '\\');
@@ -153,6 +156,9 @@ static inline int switch_string_has_escaped_data(const char *in)
 
 	return 0;
 }
+#ifdef _MSC_VER
+#pragma warning(default:6011)
+#endif
 
 SWITCH_DECLARE(switch_status_t) switch_b64_encode(unsigned char *in, switch_size_t ilen, unsigned char *out, switch_size_t olen);
 SWITCH_DECLARE(switch_size_t) switch_b64_decode(char *in, char *out, switch_size_t olen);
@@ -171,6 +177,23 @@ static inline switch_bool_t switch_is_digit_string(const char *s)
 	return SWITCH_TRUE;
 }
 
+
+static inline uint32_t switch_known_bitrate(switch_payload_t payload)
+{
+	switch(payload) {
+	case 0: /* PCMU */ return 64000;
+	case 3: /* GSM */ return 13200;
+	case 4: /* G723 */ return 6300;
+	case 7: /* LPC */ return 2400;
+	case 8: /* PCMA */ return 64000;
+	case 9: /* G722 */ return 64000;
+	case 18: /* G729 */ return 8000;
+	default: break;
+	}
+
+	return 0;
+}
+
 SWITCH_DECLARE(switch_size_t) switch_fd_read_line(int fd, char *buf, switch_size_t len);
 
 
@@ -353,7 +376,16 @@ switch_mutex_unlock(obj->flag_mutex);
 #define switch_set_string(_dst, _src) switch_copy_string(_dst, _src, sizeof(_dst))
 
 
-	 static inline char *switch_sanitize_number(char *number)
+static inline uint32_t switch_default_ptime(const char *name, uint32_t number)
+{
+	if (!strcasecmp(name, "G723")) {
+		return 30;
+	}
+
+	return 20;
+}
+
+static inline char *switch_sanitize_number(char *number)
 {
 	char *p = number, *q;
 	char warp[] = "/:";
@@ -455,6 +487,9 @@ static inline char *switch_safe_strdup(const char *it)
 }
 
 
+#ifdef _MSC_VER
+#pragma warning(disable:6011)
+#endif
 static inline char *switch_lc_strdup(const char *it)
 {
 	char *dup;
@@ -487,6 +522,9 @@ static inline char *switch_uc_strdup(const char *it)
 
 	return NULL;
 }
+#ifdef _MSC_VER
+#pragma warning(default:6011)
+#endif
 
 
 /*!
@@ -680,7 +718,15 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_netwo
 
 SWITCH_DECLARE(int) switch_inet_pton(int af, const char *src, void *dst);
 
+SWITCH_DECLARE(const char *) switch_dow_int2str(int val);
+SWITCH_DECLARE(int) switch_dow_str2int(const char *exp);
+SWITCH_DECLARE(int) switch_dow_cmp(const char *exp, int val);
 SWITCH_DECLARE(int) switch_number_cmp(const char *exp, int val);
+SWITCH_DECLARE(int) switch_tod_cmp(const char *exp, int val);
+
+SWITCH_DECLARE(int) switch_fulldate_cmp(const char *exp, switch_time_t *ts);
+SWITCH_DECLARE(void) switch_split_date(const char *exp, int *year, int *month, int *day);
+SWITCH_DECLARE(void) switch_split_time(const char *exp, int *hour, int *min, int *sec);
 
 /*!
   \brief Split a user@domain string as user and domain
diff --git a/src/include/switch_xml.h b/src/include/switch_xml.h
index 220e65df02..9b0fbb44f3 100644
--- a/src/include/switch_xml.h
+++ b/src/include/switch_xml.h
@@ -331,6 +331,7 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_open_root(_In_ uint8_t reload, _Out_ con
 ///\return SWITCH_STATUS_SUCCESS if successful
 SWITCH_DECLARE(switch_status_t) switch_xml_init(_In_ switch_memory_pool_t *pool, _Out_ const char **err);
 
+SWITCH_DECLARE(switch_status_t) switch_xml_reload(const char **err);
 
 SWITCH_DECLARE(switch_status_t) switch_xml_destroy(void);
 
diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c
index e08757ba38..b58e647e3b 100644
--- a/src/mod/applications/mod_callcenter/mod_callcenter.c
+++ b/src/mod/applications/mod_callcenter/mod_callcenter.c
@@ -1259,7 +1259,7 @@ static switch_status_t load_config(void)
 			if (!strcasecmp(var, "debug")) {
 				globals.debug = atoi(val);
 			} else if (!strcasecmp(var, "odbc-dsn")) {
-				globals.odbc_dsn = strdup(switch_xml_attr(param, "odbc-dsn"));
+				globals.odbc_dsn = strdup(val);
 
 				if (!zstr(globals.odbc_dsn)) {
 					if ((globals.odbc_user = strchr(globals.odbc_dsn, ':'))) {
@@ -1498,7 +1498,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
 
 		/* Update Agents Items */
 		/* Do not remove uuid of the agent if we are a standby agent */
-		sql = switch_mprintf("UPDATE agents SET %q last_bridge_end = %ld, talk_time = talk_time + (%ld-last_bridge_start) WHERE name = '%q' AND system = '%q';"
+		sql = switch_mprintf("UPDATE agents SET %s last_bridge_end = %ld, talk_time = talk_time + (%ld-last_bridge_start) WHERE name = '%q' AND system = '%q';"
 				, (strcasecmp(h->agent_type, CC_AGENT_TYPE_UUID_STANDBY)?"uuid = '',":""),  (long) switch_epoch_time_now(NULL), (long) switch_epoch_time_now(NULL), h->agent_name, h->agent_system);
 		cc_execute_sql(NULL, sql, NULL);
 		switch_safe_free(sql);
@@ -2675,9 +2675,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_callcenter_load)
 {
 	switch_application_interface_t *app_interface;
 	switch_api_interface_t *api_interface;
-
-	/* connect my internal structure to the blank pointer passed to me */
-	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
+	switch_status_t status;
 
 	memset(&globals, 0, sizeof(globals));
 	globals.pool = pool;
@@ -2685,11 +2683,16 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_callcenter_load)
 	switch_core_hash_init(&globals.queue_hash, globals.pool);
 	switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
 
+	if ((status = load_config()) != SWITCH_STATUS_SUCCESS) {
+		return status;
+	}
+
 	switch_mutex_lock(globals.mutex);
 	globals.running = 1;
 	switch_mutex_unlock(globals.mutex);
 
-	load_config();
+	/* connect my internal structure to the blank pointer passed to me */
+	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
 
 	if (!AGENT_DISPATCH_THREAD_STARTED) {
 		cc_agent_dispatch_thread_start();
diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c
index e1eb2a6b6a..1fb1c95c47 100644
--- a/src/mod/applications/mod_commands/mod_commands.c
+++ b/src/mod/applications/mod_commands/mod_commands.c
@@ -135,7 +135,7 @@ SWITCH_STANDARD_API(nat_map_function)
 	switch_bool_t sticky = SWITCH_FALSE;
 
 	if (!cmd) {
-		goto error;
+		goto usage;
 	}
 
 	if (!switch_nat_is_initialized()) {
@@ -147,9 +147,8 @@ SWITCH_STANDARD_API(nat_map_function)
 	switch_assert(mydata);
 
 	argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
-
 	if (argc < 1) {
-		goto error;
+		goto usage;
 	}
 	if (argv[0] && switch_stristr("status", argv[0])) {
 		tmp = switch_nat_status();
@@ -197,6 +196,10 @@ SWITCH_STANDARD_API(nat_map_function)
   error:
 
 	stream->write_function(stream, "false");
+	goto ok;
+
+ usage:
+	stream->write_function(stream, "USAGE: nat_map [status|reinit|republish] | [add|del]  [tcp|udp] [sticky]");
 
   ok:
 
@@ -605,11 +608,12 @@ SWITCH_STANDARD_API(in_group_function)
 
 SWITCH_STANDARD_API(user_data_function)
 {
-	switch_xml_t x_domain, xml = NULL, x_user = NULL, x_param, x_params;
+	switch_xml_t x_domain, xml = NULL, x_user = NULL, x_group = NULL, x_param, x_params;
 	int argc;
 	char *mydata = NULL, *argv[3], *key = NULL, *type = NULL, *user, *domain;
 	char delim = ' ';
 	const char *container = "params", *elem = "param";
+	const char *result = NULL;
 	switch_event_t *params = NULL;
 
 	if (zstr(cmd) || !(mydata = strdup(cmd))) {
@@ -637,10 +641,10 @@ SWITCH_STANDARD_API(user_data_function)
 	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "domain", domain);
 	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "type", type);
 
-	if (key && type && switch_xml_locate_user("id", user, domain, NULL, &xml, &x_domain, &x_user, NULL, params) == SWITCH_STATUS_SUCCESS) {
+	if (key && type && switch_xml_locate_user("id", user, domain, NULL, &xml, &x_domain, &x_user, &x_group, params) == SWITCH_STATUS_SUCCESS) {
 		if (!strcmp(type, "attr")) {
 			const char *attr = switch_xml_attr_soft(x_user, key);
-			stream->write_function(stream, "%s", attr);
+			result = attr;
 			goto end;
 		}
 
@@ -649,33 +653,45 @@ SWITCH_STANDARD_API(user_data_function)
 			elem = "variable";
 		}
 
-		if ((x_params = switch_xml_child(x_user, container))) {
-			for (x_param = switch_xml_child(x_params, elem); x_param; x_param = x_param->next) {
-				const char *var = switch_xml_attr(x_param, "name");
-				const char *val = switch_xml_attr(x_param, "value");
-
-				if (var && val && !strcasecmp(var, key)) {
-					stream->write_function(stream, "%s", val);
-					goto end;
-				}
-
-			}
-		}
-
 		if ((x_params = switch_xml_child(x_domain, container))) {
 			for (x_param = switch_xml_child(x_params, elem); x_param; x_param = x_param->next) {
 				const char *var = switch_xml_attr(x_param, "name");
 				const char *val = switch_xml_attr(x_param, "value");
 
 				if (var && val && !strcasecmp(var, key)) {
-					stream->write_function(stream, "%s", val);
-					goto end;
+					result = val;
+				}
+
+			}
+		}
+
+		if (x_group && (x_params = switch_xml_child(x_group, container))) {
+			for (x_param = switch_xml_child(x_params, elem); x_param; x_param = x_param->next) {
+				const char *var = switch_xml_attr(x_param, "name");
+				const char *val = switch_xml_attr(x_param, "value");
+
+				if (var && val && !strcasecmp(var, key)) {
+					result = val;
+				}
+			}
+		}
+
+		if ((x_params = switch_xml_child(x_user, container))) {
+			for (x_param = switch_xml_child(x_params, elem); x_param; x_param = x_param->next) {
+				const char *var = switch_xml_attr(x_param, "name");
+				const char *val = switch_xml_attr(x_param, "value");
+
+				if (var && val && !strcasecmp(var, key)) {
+					result = val;
 				}
 			}
 		}
 	}
 
   end:
+	if (result) {
+		stream->write_function(stream, "%s", result);
+	}
 	switch_xml_free(xml);
 	switch_safe_free(mydata);
 	switch_event_destroy(¶ms);
@@ -1049,7 +1065,7 @@ SWITCH_STANDARD_API(url_encode_function)
 	int len = 0;
 
 	if (!zstr(cmd)) {
-		len = (strlen(cmd) * 3) + 1;
+		len = (int)(strlen(cmd) * 3) + 1;
 		switch_zmalloc(data, len);
 		switch_url_encode(cmd, data, len);
 		reply = data;
@@ -1166,17 +1182,18 @@ SWITCH_STANDARD_API(xml_locate_function)
 SWITCH_STANDARD_API(reload_acl_function)
 {
 	const char *err;
-	switch_xml_t xml_root;
 
-	if (cmd && !strcmp(cmd, "reloadxml")) {
-		if ((xml_root = switch_xml_open_root(1, &err))) {
-			switch_xml_free(xml_root);
-		}
+	if (cmd && !strcasecmp(cmd, "reloadxml")) {
+		stream->write_function(stream, "This option is deprecated, we now always reloadxml.\n");
+	}
+	
+	if (switch_xml_reload(&err) == SWITCH_STATUS_SUCCESS) {
+		switch_load_network_lists(SWITCH_TRUE);
+		stream->write_function(stream, "+OK acl reloaded\n");
+	} else {
+		stream->write_function(stream, "-Error [%s]\n", err);
 	}
 
-	switch_load_network_lists(SWITCH_TRUE);
-
-	stream->write_function(stream, "+OK acl reloaded\n");
 	return SWITCH_STATUS_SUCCESS;
 }
 
@@ -1374,7 +1391,7 @@ SWITCH_STANDARD_API(cond_function)
 
 	argc = switch_separate_string(mydata, ':', argv, (sizeof(argv) / sizeof(argv[0])));
 
-	if (argc != 3) {
+	if (! (argc >= 2 && argc <= 3)) {
 		goto error;
 	}
 
@@ -1451,7 +1468,12 @@ SWITCH_STANDARD_API(cond_function)
 		}
 		switch_safe_free(s_a);
 		switch_safe_free(s_b);
-		stream->write_function(stream, "%s", is_true ? argv[1] : argv[2]);
+
+		if ((argc == 2 && !is_true)) {
+			stream->write_function(stream, "");
+		} else {
+			stream->write_function(stream, "%s", is_true ? argv[1] : argv[2]);
+		}
 		goto ok;
 	}
 
@@ -1720,6 +1742,10 @@ SWITCH_STANDARD_API(load_function)
 		return SWITCH_STATUS_SUCCESS;
 	}
 
+	if (switch_xml_reload(&err) == SWITCH_STATUS_SUCCESS) {
+		stream->write_function(stream, "+OK Reloading XML\n");
+	}
+
 	if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, SWITCH_TRUE, &err) == SWITCH_STATUS_SUCCESS) {
 		stream->write_function(stream, "+OK\n");
 	} else {
@@ -1814,6 +1840,10 @@ SWITCH_STANDARD_API(reload_function)
 		stream->write_function(stream, "-ERR unloading module [%s]\n", err);
 	}
 
+	if (switch_xml_reload(&err) == SWITCH_STATUS_SUCCESS) {
+		stream->write_function(stream, "+OK Reloading XML\n");
+	}
+
 	if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, SWITCH_TRUE, &err) == SWITCH_STATUS_SUCCESS) {
 		stream->write_function(stream, "+OK module loaded\n");
 	} else {
@@ -1825,13 +1855,9 @@ SWITCH_STANDARD_API(reload_function)
 
 SWITCH_STANDARD_API(reload_xml_function)
 {
-	const char *err;
-	switch_xml_t xml_root;
-
-	if ((xml_root = switch_xml_open_root(1, &err))) {
-		switch_xml_free(xml_root);
-	}
+	const char *err = "";
 
+	switch_xml_reload(&err);
 	stream->write_function(stream, "+OK [%s]\n", err);
 
 	return SWITCH_STATUS_SUCCESS;
@@ -3022,7 +3048,7 @@ SWITCH_STANDARD_API(xml_wrap_api_function)
 
 		if (mystream.data) {
 			if (encoded) {
-				elen = (int) strlen(mystream.data) * 3;
+				elen = (int) strlen(mystream.data) * 3 + 1;
 				edata = malloc(elen);
 				switch_assert(edata != NULL);
 				memset(edata, 0, elen);
@@ -4040,7 +4066,7 @@ SWITCH_STANDARD_API(uuid_dump_function)
 	return SWITCH_STATUS_SUCCESS;
 }
 
-#define GLOBAL_SETVAR_SYNTAX "  []"
+#define GLOBAL_SETVAR_SYNTAX "= [=]"
 SWITCH_STANDARD_API(global_setvar_function)
 {
 	char *mycmd = NULL, *argv[3] = { 0 };
@@ -4192,7 +4218,7 @@ SWITCH_STANDARD_API(escape_function)
 		return SWITCH_STATUS_SUCCESS;
 	}
 
-	len = strlen(cmd) * 2;
+	len = (int)strlen(cmd) * 2;
 	mycmd = malloc(len);
 
 	stream->write_function(stream, "%s", switch_escape_string(cmd, mycmd, len));
@@ -4551,7 +4577,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
 	SWITCH_ADD_API(commands_api_interface, "originate", "Originate a Call", originate_function, ORIGINATE_SYNTAX);
 	SWITCH_ADD_API(commands_api_interface, "pause", "Pause", pause_function, PAUSE_SYNTAX);
 	SWITCH_ADD_API(commands_api_interface, "regex", "Eval a regex", regex_function, "|[|]");
-	SWITCH_ADD_API(commands_api_interface, "reloadacl", "Reload ACL", reload_acl_function, "[reloadxml]");
+	SWITCH_ADD_API(commands_api_interface, "reloadacl", "Reload ACL", reload_acl_function, "");
 	SWITCH_ADD_API(commands_api_interface, "reload", "Reload Module", reload_function, UNLOAD_SYNTAX);
 	SWITCH_ADD_API(commands_api_interface, "reloadxml", "Reload XML", reload_xml_function, "");
 	SWITCH_ADD_API(commands_api_interface, "replace", "replace a string", replace_function, "||");
diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c
index 5128e3baed..7018294546 100644
--- a/src/mod/applications/mod_conference/mod_conference.c
+++ b/src/mod/applications/mod_conference/mod_conference.c
@@ -99,7 +99,7 @@ typedef enum {
 	CALLER_CONTROL_DEAF_MUTE,
 	CALLER_CONTROL_ENERGY_UP,
 	CALLER_CONTROL_ENERGY_EQU_CONF,
-	CALLER_CONTROL_ENERGEY_DN,
+	CALLER_CONTROL_ENERGY_DN,
 	CALLER_CONTROL_VOL_TALK_UP,
 	CALLER_CONTROL_VOL_TALK_ZERO,
 	CALLER_CONTROL_VOL_TALK_DN,
@@ -121,7 +121,7 @@ typedef struct conference_member conference_member_t;
 
 struct call_list {
 	char *string;
-	int itteration;
+	int iteration;
 	struct call_list *next;
 };
 typedef struct call_list call_list_t;
@@ -717,7 +717,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
 
 		if (call_list) {
 			char saymsg[1024];
-			switch_snprintf(saymsg, sizeof(saymsg), "Auto Calling %d parties", call_list->itteration);
+			switch_snprintf(saymsg, sizeof(saymsg), "Auto Calling %d parties", call_list->iteration);
 			conference_member_say(member, saymsg, 0);
 		} else {
 			if (zstr(conference->special_announce)) {
@@ -1012,7 +1012,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
 	uint8_t *file_frame;
 	uint8_t *async_file_frame;
 	int16_t *bptr;
-	int x = 0;
+	uint32_t x = 0;
 	int32_t z = 0;
 	int member_score_sum = 0;
 	int divisor = 0;
@@ -2298,7 +2298,7 @@ static caller_control_fn_table_t ccfntbl[] = {
 	{"deaf mute", "*", CALLER_CONTROL_DEAF_MUTE, conference_loop_fn_deafmute_toggle},
 	{"energy up", "9", CALLER_CONTROL_ENERGY_UP, conference_loop_fn_energy_up},
 	{"energy equ", "8", CALLER_CONTROL_ENERGY_EQU_CONF, conference_loop_fn_energy_equ_conf},
-	{"energy dn", "7", CALLER_CONTROL_ENERGEY_DN, conference_loop_fn_energy_dn},
+	{"energy dn", "7", CALLER_CONTROL_ENERGY_DN, conference_loop_fn_energy_dn},
 	{"vol talk up", "3", CALLER_CONTROL_VOL_TALK_UP, conference_loop_fn_volume_talk_up},
 	{"vol talk zero", "2", CALLER_CONTROL_VOL_TALK_ZERO, conference_loop_fn_volume_talk_zero},
 	{"vol talk dn", "1", CALLER_CONTROL_VOL_TALK_DN, conference_loop_fn_volume_talk_dn},
@@ -3733,7 +3733,7 @@ static switch_status_t conf_api_sub_list(conference_obj_t *conference, switch_st
 
 static switch_xml_t add_x_tag(switch_xml_t x_member, const char *name, const char *value, int off)
 {
-	switch_size_t dlen = strlen(value) * 3;
+	switch_size_t dlen = strlen(value) * 3 + 1;
 	char *data;
 	switch_xml_t x_tag;
 
@@ -5199,9 +5199,9 @@ SWITCH_STANDARD_APP(conference_auto_function)
 		np->string = switch_core_session_strdup(session, data);
 		if (call_list) {
 			np->next = call_list;
-			np->itteration = call_list->itteration + 1;
+			np->iteration = call_list->iteration + 1;
 		} else {
-			np->itteration = 1;
+			np->iteration = 1;
 		}
 		call_list = np;
 	}
diff --git a/src/mod/applications/mod_directory/mod_directory.c b/src/mod/applications/mod_directory/mod_directory.c
index d3389ab3b1..d92974766d 100644
--- a/src/mod/applications/mod_directory/mod_directory.c
+++ b/src/mod/applications/mod_directory/mod_directory.c
@@ -393,7 +393,7 @@ static dir_profile_t *load_profile(const char *profile_name)
 		profile_set_config(profile);
 
 		/* Add the params to the event structure */
-		count = switch_event_import_xml(switch_xml_child(x_profile, "param"), "name", "value", &event);
+		count = (int)switch_event_import_xml(switch_xml_child(x_profile, "param"), "name", "value", &event);
 
 		if (switch_xml_config_parse_event(event, count, SWITCH_FALSE, profile->config) != SWITCH_STATUS_SUCCESS) {
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to process configuration\n");
@@ -611,7 +611,7 @@ static switch_status_t on_dtmf(switch_core_session_t *session, void *input, swit
 			}
 
 			if (strlen(cbr->digits) < sizeof(cbr->digits) - 2) {
-				int at = strlen(cbr->digits);
+				int at = (int)strlen(cbr->digits);
 				cbr->digits[at++] = dtmf->digit;
 				cbr->digits[at] = '\0';
 			} else {
@@ -649,25 +649,25 @@ static switch_status_t listen_entry(switch_core_session_t *session, dir_profile_
 
 	if (zstr_buf(buf)) {
 		switch_snprintf(macro, sizeof(macro), "phrase:%s:%d", DIR_RESULT_ITEM, cbt->want + 1);
-		switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), 1, profile->terminator_key);
+		switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), 1, profile->terminator_key, 0);
 	}
 
 	if (!zstr_buf(recorded_name) && zstr_buf(buf)) {
-		switch_ivr_read(session, 0, 1, recorded_name, NULL, buf, sizeof(buf), 1, profile->terminator_key);
+		switch_ivr_read(session, 0, 1, recorded_name, NULL, buf, sizeof(buf), 1, profile->terminator_key, 0);
 
 	}
 	if (zstr_buf(recorded_name) && zstr_buf(buf)) {
 		switch_snprintf(macro, sizeof(macro), "phrase:%s:%s", DIR_RESULT_SAY_NAME, cbt->fullname);
-		switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), 1, profile->terminator_key);
+		switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), 1, profile->terminator_key, 0);
 	}
 	if (cbt->exten_visible && zstr_buf(buf)) {
 		switch_snprintf(macro, sizeof(macro), "phrase:%s:%s", DIR_RESULT_AT, cbt->extension);
-		switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), 1, profile->terminator_key);
+		switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), 1, profile->terminator_key, 0);
 	}
 	if (zstr_buf(buf)) {
 		switch_snprintf(macro, sizeof(macro), "phrase:%s:%c,%c,%c,%c", DIR_RESULT_MENU, *profile->select_name_key, *profile->next_key, *profile->prev_key,
 						*profile->new_search_key);
-		switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), profile->digit_timeout, profile->terminator_key);
+		switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), profile->digit_timeout, profile->terminator_key, 0);
 	}
 
 	if (!zstr_buf(buf)) {
@@ -884,6 +884,18 @@ SWITCH_STANDARD_APP(directory_function)
 	if (strcasecmp(profile->search_order, "last_name")) {
 		s_param.search_by_last_name = 0;
 	}
+ 	 
+	{
+		const char *var_search_order = switch_channel_get_variable(channel, "directory_search_order");
+		if (var_search_order) {
+			if (!strcasecmp(var_search_order, "first_name")) {
+				s_param.search_by_last_name = 0;
+			} else {
+				s_param.search_by_last_name = 1;
+			}
+		}
+	}
+
 	attempts = profile->max_menu_attempt;
 	s_param.try_again = 1;
 	while (switch_channel_ready(channel) && (s_param.try_again && attempts-- > 0)) {
diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c
index 55429275dd..dd63f8aae9 100755
--- a/src/mod/applications/mod_dptools/mod_dptools.c
+++ b/src/mod/applications/mod_dptools/mod_dptools.c
@@ -1712,10 +1712,11 @@ SWITCH_STANDARD_APP(att_xfer_function)
 SWITCH_STANDARD_APP(read_function)
 {
 	char *mydata;
-	char *argv[6] = { 0 };
+	char *argv[7] = { 0 };
 	int argc;
 	int32_t min_digits = 0;
 	int32_t max_digits = 0;
+	uint32_t digit_timeout = 0;
 	int timeout = 1000;
 	char digit_buffer[128] = "";
 	const char *prompt_audio_file = NULL;
@@ -1751,6 +1752,13 @@ SWITCH_STANDARD_APP(read_function)
 		valid_terminators = argv[5];
 	}
 
+	if (argc > 6) {
+		digit_timeout = atoi(argv[6]);
+		if (digit_timeout < 0) {
+			digit_timeout = 0;
+		}
+	}
+
 	if (min_digits <= 1) {
 		min_digits = 1;
 	}
@@ -1767,17 +1775,19 @@ SWITCH_STANDARD_APP(read_function)
 		valid_terminators = "#";
 	}
 
-	switch_ivr_read(session, min_digits, max_digits, prompt_audio_file, var_name, digit_buffer, sizeof(digit_buffer), timeout, valid_terminators);
+	switch_ivr_read(session, min_digits, max_digits, prompt_audio_file, var_name, digit_buffer, sizeof(digit_buffer), timeout, valid_terminators, 
+					digit_timeout);
 }
 
 SWITCH_STANDARD_APP(play_and_get_digits_function)
 {
 	char *mydata;
-	char *argv[9] = { 0 };
+	char *argv[10] = { 0 };
 	int argc;
 	int32_t min_digits = 0;
 	int32_t max_digits = 0;
 	int32_t max_tries = 0;
+	uint32_t digit_timeout = 0;
 	int timeout = 1000;
 	char digit_buffer[128] = "";
 	const char *prompt_audio_file = NULL;
@@ -1827,6 +1837,14 @@ SWITCH_STANDARD_APP(play_and_get_digits_function)
 		digits_regex = argv[8];
 	}
 
+	if (argc > 9) {
+		digit_timeout = atoi(argv[9]);
+		if (digit_timeout < 0) {
+			digit_timeout = 0;
+		}
+	}
+
+
 	if (min_digits <= 1) {
 		min_digits = 1;
 	}
@@ -1844,7 +1862,7 @@ SWITCH_STANDARD_APP(play_and_get_digits_function)
 	}
 
 	switch_play_and_get_digits(session, min_digits, max_digits, max_tries, timeout, valid_terminators,
-							   prompt_audio_file, bad_input_audio_file, var_name, digit_buffer, sizeof(digit_buffer), digits_regex);
+							   prompt_audio_file, bad_input_audio_file, var_name, digit_buffer, sizeof(digit_buffer), digits_regex, digit_timeout);
 }
 
 #define SAY_SYNTAX "   [] "
@@ -3367,9 +3385,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
 	SWITCH_ADD_APP(app_interface, "endless_playback", "Playback File Endlessly", "Endlessly Playback a file to the channel",
 				   endless_playback_function, "", SAF_NONE);
 	SWITCH_ADD_APP(app_interface, "att_xfer", "Attended Transfer", "Attended Transfer", att_xfer_function, "", SAF_NONE);
-	SWITCH_ADD_APP(app_interface, "read", "Read Digits", "Read Digits", read_function, "     ", SAF_NONE);
+	SWITCH_ADD_APP(app_interface, "read", "Read Digits", "Read Digits", read_function, 
+				   "      ", SAF_NONE);
 	SWITCH_ADD_APP(app_interface, "play_and_get_digits", "Play and get Digits", "Play and get Digits",
-				   play_and_get_digits_function, "        ", SAF_NONE);
+				   play_and_get_digits_function, 
+				   "         []", SAF_NONE);
 	SWITCH_ADD_APP(app_interface, "stop_record_session", "Stop Record Session", STOP_SESS_REC_DESC, stop_record_session_function, "", SAF_NONE);
 	SWITCH_ADD_APP(app_interface, "record_session", "Record Session", SESS_REC_DESC, record_session_function, " [+]", SAF_MEDIA_TAP);
 	SWITCH_ADD_APP(app_interface, "record", "Record File", "Record a file from the channels input", record_function,
diff --git a/src/mod/applications/mod_fifo/mod_fifo.c b/src/mod/applications/mod_fifo/mod_fifo.c
index aa49689062..563706c9f2 100644
--- a/src/mod/applications/mod_fifo/mod_fifo.c
+++ b/src/mod/applications/mod_fifo/mod_fifo.c
@@ -439,7 +439,7 @@ static switch_status_t moh_on_dtmf(switch_core_session_t *session, void *input,
 
 #define check_string(s) if (!zstr(s) && !strcasecmp(s, "undef")) { s = NULL; }
 
-static int node_consumer_wait_count(fifo_node_t *node)
+static int node_caller_count(fifo_node_t *node)
 {
 	int i, len = 0;
 
@@ -458,7 +458,7 @@ static void node_remove_uuid(fifo_node_t *node, const char *uuid)
 		fifo_queue_popfly(node->fifo_list[i], uuid);
 	}
 
-	if (!node_consumer_wait_count(node)) {
+	if (!node_caller_count(node)) {
 		node->start_waiting = 0;
 	}
 
@@ -513,7 +513,6 @@ static switch_status_t caller_read_frame_callback(switch_core_session_t *session
 			if (match_key(caller_exit_key, *buf)) {
 				cd->abort = 1;
 				return SWITCH_STATUS_FALSE;
-				switch_channel_set_variable(channel, "fifo_caller_exit_key", (char *)buf);
 			}
 			cd->next = switch_epoch_time_now(NULL) + cd->freq;
 			cd->index++;
@@ -875,7 +874,7 @@ static void do_unbridge(switch_core_session_t *consumer_session, switch_core_ses
 		char *sql;
 		switch_event_t *event;
 		
-		switch_channel_clear_app_flag(consumer_channel, FIFO_APP_BRIDGE_TAG);
+		switch_channel_clear_app_flag_key(__FILE__, consumer_channel, FIFO_APP_BRIDGE_TAG);
 		switch_channel_set_variable(consumer_channel, "fifo_bridged", NULL);
 				
 		ts = switch_micro_time_now();
@@ -989,7 +988,7 @@ static switch_status_t messagehook (switch_core_session_t *session, switch_core_
 				goto end;
 			}
 
-			switch_channel_set_app_flag(consumer_channel, FIFO_APP_BRIDGE_TAG);
+			switch_channel_set_app_flag_key(__FILE__, consumer_channel, FIFO_APP_BRIDGE_TAG);
 			
 			switch_channel_set_variable(consumer_channel, "fifo_bridged", "true");
 			switch_channel_set_variable(consumer_channel, "fifo_manual_bridge", "true");
@@ -1683,7 +1682,7 @@ static void find_consumers(fifo_node_t *node)
 	switch(node->outbound_strategy) {
 	case NODE_STRATEGY_ENTERPRISE:
 		{
-			int need = node_consumer_wait_count(node);
+			int need = node_caller_count(node);
 
 			if (node->outbound_per_cycle && node->outbound_per_cycle < need) {
 				need = node->outbound_per_cycle;
@@ -1753,7 +1752,7 @@ static void *SWITCH_THREAD_FUNC node_thread_run(switch_thread_t *thread, void *o
 			if ((node = (fifo_node_t *) val)) {
 				if (node->outbound_priority == 0) node->outbound_priority = 5;
 				if (node->has_outbound && node->ready && !node->busy && node->outbound_priority == cur_priority) {
-					ppl_waiting = node_consumer_wait_count(node);
+					ppl_waiting = node_caller_count(node);
 					consumer_total = node->consumer_count;
 					idle_consumers = node_idle_consumers(node);
 
@@ -1831,7 +1830,7 @@ static void check_cancel(fifo_node_t *node)
 		return;
 	}
 
-	ppl_waiting = node_consumer_wait_count(node);
+	ppl_waiting = node_caller_count(node);
 
     if (node->ring_consumer_count > 0 && ppl_waiting < 1) {
         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Outbound call count (%d) exceeds required value for queue %s (%d), "
@@ -1855,7 +1854,7 @@ static void send_presence(fifo_node_t *node)
 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", "park");
 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", node->name);
 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", node->name);
-		if ((wait_count = node_consumer_wait_count(node)) > 0) {
+		if ((wait_count = node_caller_count(node)) > 0) {
 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "Active (%d waiting)", wait_count);
 		} else {
 			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", "Idle");
@@ -1990,6 +1989,11 @@ static void dec_use_count(switch_core_session_t *session, switch_bool_t send_eve
 	if ((outbound_id = switch_channel_get_variable(channel, "fifo_outbound_uuid"))) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s untracking call on uuid %s!\n", switch_channel_get_name(channel), outbound_id);
 
+
+		sql = switch_mprintf("delete from fifo_bridge where consumer_uuid='%q'", switch_core_session_get_uuid(session));
+		fifo_execute_sql(sql, globals.sql_mutex);
+		switch_safe_free(sql);
+
 		del_bridge_call(outbound_id);
 		sql = switch_mprintf("update fifo_outbound set use_count=use_count-1, stop_time=%ld, next_avail=%ld + lag + 1 where use_count > 0 and uuid='%q'", 
 							 now, now, outbound_id);
@@ -2043,7 +2047,7 @@ SWITCH_STANDARD_APP(fifo_track_call_function)
 
 	add_bridge_call(data);
 
-	switch_channel_set_app_flag(channel, FIFO_APP_TRACKING);
+	switch_channel_set_app_flag_key(__FILE__, channel, FIFO_APP_TRACKING);
 
 	switch_channel_set_variable(channel, "fifo_outbound_uuid", data);
 	switch_channel_set_variable(channel, "fifo_track_call", "true");
@@ -2296,7 +2300,6 @@ SWITCH_STANDARD_APP(fifo_function)
 		switch_channel_answer(channel);
 
 		switch_thread_rwlock_wrlock(node->rwlock);
-		node->caller_count++;
 
 		if ((pri = switch_channel_get_variable(channel, "fifo_priority"))) {
 			p = atoi(pri);
@@ -2306,7 +2309,7 @@ SWITCH_STANDARD_APP(fifo_function)
 			p = MAX_PRI - 1;
 		}
 
-		if (!node_consumer_wait_count(node)) {
+		if (!node_caller_count(node)) {
 			node->start_waiting = switch_micro_time_now();
 		}
 
@@ -2343,7 +2346,7 @@ SWITCH_STANDARD_APP(fifo_function)
 		switch_channel_set_variable(channel, "fifo_timestamp", date);
 		switch_channel_set_variable(channel, "fifo_serviced_uuid", NULL);
 
-		switch_channel_set_app_flag(channel, FIFO_APP_BRIDGE_TAG);
+		switch_channel_set_app_flag_key(__FILE__, channel, FIFO_APP_BRIDGE_TAG);
 
 		if (chime_list) {
 			char *list_dup = switch_core_session_strdup(session, chime_list);
@@ -2416,10 +2419,10 @@ SWITCH_STANDARD_APP(fifo_function)
 			}
 		}
 
-		switch_channel_clear_app_flag(channel, FIFO_APP_BRIDGE_TAG);
+	abort:
+
+		switch_channel_clear_app_flag_key(__FILE__, channel, FIFO_APP_BRIDGE_TAG);
 
-	  abort:
-		
 		fifo_caller_del(switch_core_session_get_uuid(session));
 
 		if (!aborted && switch_channel_ready(channel)) {
@@ -2442,7 +2445,6 @@ SWITCH_STANDARD_APP(fifo_function)
 			switch_mutex_lock(globals.mutex);
 			switch_thread_rwlock_wrlock(node->rwlock);
 			node_remove_uuid(node, uuid);
-			node->caller_count--;
 			switch_thread_rwlock_unlock(node->rwlock);
 			send_presence(node);
 			check_cancel(node);
@@ -2583,7 +2585,7 @@ SWITCH_STANDARD_APP(fifo_function)
 					continue;
 				}
 
-				if ((waiting = node_consumer_wait_count(node))) {
+				if ((waiting = node_caller_count(node))) {
 
 					if (!importance || node->importance > importance) {
 						if (strat == STRAT_WAITING_LONGER) {
@@ -2671,7 +2673,7 @@ SWITCH_STANDARD_APP(fifo_function)
 					}
 				}
 
-				if (pop && !node_consumer_wait_count(node)) {
+				if (pop && !node_caller_count(node)) {
 					switch_thread_rwlock_wrlock(node->rwlock);
 					node->start_waiting = 0;
 					switch_thread_rwlock_unlock(node->rwlock);
@@ -2775,7 +2777,8 @@ SWITCH_STANDARD_APP(fifo_function)
 
 				switch_channel_set_flag(other_channel, CF_BREAK);
 
-				while (switch_channel_ready(channel) && switch_channel_ready(other_channel) && switch_channel_test_app_flag(other_channel, FIFO_APP_BRIDGE_TAG)) {
+				while (switch_channel_ready(channel) && switch_channel_ready(other_channel) && 
+					   switch_channel_test_app_flag(other_channel, FIFO_APP_BRIDGE_TAG)) {
 					status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
 					if (!SWITCH_READ_ACCEPTABLE(status)) {
 						break;
@@ -2787,9 +2790,6 @@ SWITCH_STANDARD_APP(fifo_function)
 					const char *arg = switch_channel_get_variable(other_channel, "current_application_data");
 					switch_caller_extension_t *extension = NULL;
 
-					switch_thread_rwlock_wrlock(node->rwlock);
-					node->caller_count--;
-					switch_thread_rwlock_unlock(node->rwlock);
 					send_presence(node);
 					check_cancel(node);
 
@@ -2955,9 +2955,6 @@ SWITCH_STANDARD_APP(fifo_function)
 				switch_channel_set_variable(other_channel, "fifo_status", "DONE");
 				switch_channel_set_variable(other_channel, "fifo_timestamp", date);
 
-				switch_thread_rwlock_wrlock(node->rwlock);
-				node->caller_count--;
-				switch_thread_rwlock_unlock(node->rwlock);
 				send_presence(node);
 				check_cancel(node);
 				switch_core_session_rwunlock(other_session);
@@ -3070,7 +3067,7 @@ SWITCH_STANDARD_APP(fifo_function)
   done:
 
 	switch_mutex_lock(globals.mutex);
-	if (node && node->ready == FIFO_DELAY_DESTROY && node->consumer_count == 0 && node->caller_count == 0) {
+	if (node && node->ready == FIFO_DELAY_DESTROY && node->consumer_count == 0 && node_caller_count(node) == 0) {
 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "%s removed.\n", node->name);
 		switch_core_hash_delete(globals.fifo_hash, node->name);
 		switch_thread_rwlock_wrlock(node->rwlock);
@@ -3085,7 +3082,7 @@ SWITCH_STANDARD_APP(fifo_function)
 	switch_mutex_unlock(globals.mutex);
 
 
-	switch_channel_clear_app_flag(channel, FIFO_APP_BRIDGE_TAG);
+	switch_channel_clear_app_flag_key(__FILE__, channel, FIFO_APP_BRIDGE_TAG);
 
 	switch_core_media_bug_resume(session);
 
@@ -3505,9 +3502,9 @@ static void list_node(fifo_node_t *node, switch_xml_t x_report, int *off, int ve
 	switch_xml_set_attr_d(x_fifo, "name", node->name);
 	switch_snprintf(tmp, sizeof(buffer), "%d", node->consumer_count);
 	switch_xml_set_attr_d(x_fifo, "consumer_count", tmp);
-	switch_snprintf(tmp, sizeof(buffer), "%d", node->caller_count);
+	switch_snprintf(tmp, sizeof(buffer), "%d", node_caller_count(node));
 	switch_xml_set_attr_d(x_fifo, "caller_count", tmp);
-	switch_snprintf(tmp, sizeof(buffer), "%d", node_consumer_wait_count(node));
+	switch_snprintf(tmp, sizeof(buffer), "%d", node_caller_count(node));
 	switch_xml_set_attr_d(x_fifo, "waiting_count", tmp);
 	switch_snprintf(tmp, sizeof(buffer), "%u", node->importance);
 	switch_xml_set_attr_d(x_fifo, "importance", tmp);
@@ -3569,7 +3566,7 @@ void node_dump(switch_stream_handle_t *stream)
 								   node->outbound_priority,
 								   node->busy,
 								   node->ready,
-								   node_consumer_wait_count(node)
+								   node_caller_count(node)
 								   
 								   );
 		}
@@ -3687,9 +3684,9 @@ SWITCH_STANDARD_API(fifo_api_function)
 			for (hi = switch_hash_first(NULL, globals.fifo_hash); hi; hi = switch_hash_next(hi)) {
 				switch_hash_this(hi, &var, NULL, &val);
 				node = (fifo_node_t *) val;
-				len = node_consumer_wait_count(node);
+				len = node_caller_count(node);
 				switch_thread_rwlock_wrlock(node->rwlock);
-				stream->write_function(stream, "%s:%d:%d:%d\n", (char *) var, node->consumer_count, node->caller_count, len);
+				stream->write_function(stream, "%s:%d:%d:%d\n", (char *) var, node->consumer_count, node_caller_count(node), len);
 				switch_thread_rwlock_unlock(node->rwlock);
 				x++;
 			}
@@ -3698,9 +3695,9 @@ SWITCH_STANDARD_API(fifo_api_function)
 				stream->write_function(stream, "none\n");
 			}
 		} else if ((node = switch_core_hash_find(globals.fifo_hash, argv[1]))) {
-			len = node_consumer_wait_count(node);
+			len = node_caller_count(node);
 			switch_thread_rwlock_wrlock(node->rwlock);
-			stream->write_function(stream, "%s:%d:%d:%d\n", argv[1], node->consumer_count, node->caller_count, len);
+			stream->write_function(stream, "%s:%d:%d:%d\n", argv[1], node->consumer_count, node_caller_count(node), len);
 			switch_thread_rwlock_unlock(node->rwlock);
 		} else {
 			stream->write_function(stream, "none\n");
@@ -3710,7 +3707,7 @@ SWITCH_STANDARD_API(fifo_api_function)
 			for (hi = switch_hash_first(NULL, globals.fifo_hash); hi; hi = switch_hash_next(hi)) {
 				switch_hash_this(hi, &var, NULL, &val);
 				node = (fifo_node_t *) val;
-				len = node_consumer_wait_count(node);
+				len = node_caller_count(node);
 				switch_thread_rwlock_wrlock(node->rwlock);
 				stream->write_function(stream, "%s:%d\n", (char *) var, node->has_outbound);
 				switch_thread_rwlock_unlock(node->rwlock);
@@ -3721,7 +3718,7 @@ SWITCH_STANDARD_API(fifo_api_function)
 				stream->write_function(stream, "none\n");
 			}
 		} else if ((node = switch_core_hash_find(globals.fifo_hash, argv[1]))) {
-			len = node_consumer_wait_count(node);
+			len = node_caller_count(node);
 			switch_thread_rwlock_wrlock(node->rwlock);
 			stream->write_function(stream, "%s:%d\n", argv[1], node->has_outbound);
 			switch_thread_rwlock_unlock(node->rwlock);
@@ -4072,7 +4069,7 @@ static switch_status_t load_config(int reload, int del_all)
 				continue;
 			}
 
-			if (node_consumer_wait_count(node) || node->consumer_count || node_idle_consumers(node)) {
+			if (node_caller_count(node) || node->consumer_count || node_idle_consumers(node)) {
 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s removal delayed, still in use.\n", node->name);
 				node->ready = FIFO_DELAY_DESTROY;
 			} else {
diff --git a/src/mod/applications/mod_hash/mod_hash.c b/src/mod/applications/mod_hash/mod_hash.c
index 3a65528ea3..29a056104f 100644
--- a/src/mod/applications/mod_hash/mod_hash.c
+++ b/src/mod/applications/mod_hash/mod_hash.c
@@ -852,7 +852,8 @@ static void do_config(switch_bool_t reload)
 				const char *username = switch_xml_attr(x_list, "username");
 				const char *password = switch_xml_attr(x_list, "password");
 				const char *szinterval = switch_xml_attr(x_list, "interval");
-				int port = 0,  interval = 0;
+				uint16_t port = 0;
+				int	interval = 0;
 				limit_remote_t *remote;
 				switch_threadattr_t *thd_attr = NULL;
 				
@@ -866,7 +867,7 @@ static void do_config(switch_bool_t reload)
 				}
 
 				if (!zstr(szport)) {
-					port = atoi(szport);
+					port = (uint16_t)atoi(szport);
 				}
 				
 				if (!zstr(szinterval)) {
@@ -949,7 +950,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_hash_shutdown)
 	/* Kill remote connections, destroy needs a wrlock so we unlock after finding a pointer */
 	while(remote_clean) {
 		void *val;	
-		const void *key;
+		const void *key = NULL;
 		switch_ssize_t keylen;
 		limit_remote_t *item = NULL;
 		
diff --git a/src/mod/applications/mod_lcr/mod_lcr.c b/src/mod/applications/mod_lcr/mod_lcr.c
index bbf7bb568d..cc93707367 100644
--- a/src/mod/applications/mod_lcr/mod_lcr.c
+++ b/src/mod/applications/mod_lcr/mod_lcr.c
@@ -167,7 +167,7 @@ static const char *do_cid(switch_memory_pool_t *pool, const char *cid, const cha
 	switch_channel_t *channel = NULL;
 	
 	if (!zstr(cid)) {
-		len = strlen(cid);
+		len = (uint32_t)strlen(cid);
 	} else {
 		goto done;
 	}
@@ -506,7 +506,7 @@ static char *expand_digits(switch_memory_pool_t *pool, char *digits, switch_bool
 	int digit_len;
 	SWITCH_STANDARD_STREAM(dig_stream);
 
-	digit_len = strlen(digits);
+	digit_len = (int)strlen(digits);
 	digits_copy = switch_core_strdup(pool, digits);
 	
 	for (n = digit_len; n > 0; n--) {
@@ -1571,7 +1571,6 @@ SWITCH_STANDARD_APP(lcr_app_function)
 				switch_channel_set_variable(channel, vbuf, cur_route->carrier_name);
 				switch_snprintf(vbuf, sizeof(vbuf), "lcr_codec_%d", cnt);
 				switch_channel_set_variable(channel, vbuf, cur_route->codec);
-				cnt++;
 				if (cur_route->next) {
 					if (routes.profile->enable_sip_redir) {
 						dig_stream.write_function(&dig_stream, "%s,", cur_route->dialstring);
diff --git a/src/mod/applications/mod_nibblebill/mod_nibblebill.c b/src/mod/applications/mod_nibblebill/mod_nibblebill.c
index 06bc7d0abd..42369f5d0b 100755
--- a/src/mod/applications/mod_nibblebill/mod_nibblebill.c
+++ b/src/mod/applications/mod_nibblebill/mod_nibblebill.c
@@ -419,10 +419,10 @@ static switch_status_t do_billing(switch_core_session_t *session)
 	billaccount = switch_channel_get_variable(channel, "nibble_account");
 	
 	if (!zstr(switch_channel_get_variable(channel, "nobal_amt"))) {
-		nobal_amt = atof(switch_channel_get_variable(channel, "nobal_amt"));
+		nobal_amt = (float)atof(switch_channel_get_variable(channel, "nobal_amt"));
 	}
 	if (!zstr(switch_channel_get_variable(channel, "lowbal_amt"))) {
-		lowbal_amt = atof(switch_channel_get_variable(channel, "lowbal_amt"));
+		lowbal_amt = (float)atof(switch_channel_get_variable(channel, "lowbal_amt"));
 	}
 
 	/* Return if there's no billing information on this session */
diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_dsp.c b/src/mod/applications/mod_spandsp/mod_spandsp_dsp.c
index 096d967ff0..aa7d05cf9e 100644
--- a/src/mod/applications/mod_spandsp/mod_spandsp_dsp.c
+++ b/src/mod/applications/mod_spandsp/mod_spandsp_dsp.c
@@ -549,8 +549,8 @@ static switch_status_t do_config(void)
 				if (id == -1) {
 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unable to add tone_descriptor: %s, tone: %s.  (too many tones)\n", name, tone_name);
 					return SWITCH_STATUS_FALSE;
-				
-				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s, tone: %s(%d)\n", name, tone_name, id);}
+				}
+				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s, tone: %s(%d)\n", name, tone_name, id);
 				/* add elements to tone */
 				for (element = switch_xml_child(tone, "element"); element; element = switch_xml_next(element)) {
 					const char *freq1_attr = switch_xml_attr(element, "freq1");
diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c
index 7ff106aceb..27878246f0 100644
--- a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c
+++ b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c
@@ -74,6 +74,8 @@ static struct {
 	char header[50];
 	char *prepend_string;
 	char *spool;
+	switch_thread_cond_t *cond;
+	switch_mutex_t *cond_mutex;    
 } globals;
 
 struct pvt_s {
@@ -118,27 +120,34 @@ static struct {
     int thread_running;
 } t38_state_list;
 
+
+
+static void wake_thread(int force)
+{
+	if (force) {
+        switch_thread_cond_signal(globals.cond);
+		return;
+	}
+
+	if (switch_mutex_trylock(globals.cond_mutex) == SWITCH_STATUS_SUCCESS) {
+		switch_thread_cond_signal(globals.cond);
+		switch_mutex_unlock(globals.cond_mutex);
+	}
+}
+
 static int add_pvt(pvt_t *pvt)
 {
     int r = 0;
-    uint32_t sanity = 50;
-
-    switch_mutex_lock(t38_state_list.mutex);
-    if (!t38_state_list.thread_running) {
-
-        launch_timer_thread();
-
-        while(--sanity && !t38_state_list.thread_running) {
-            switch_yield(10000);
-        }
-    }
-    switch_mutex_unlock(t38_state_list.mutex);
     
     if (t38_state_list.thread_running) {
         switch_mutex_lock(t38_state_list.mutex);
         pvt->next = t38_state_list.head;
         t38_state_list.head = pvt;
         switch_mutex_unlock(t38_state_list.mutex);
+        r = 1;
+        wake_thread(0);
+    } else {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error launching thread\n");
     }
 
     return r;
@@ -151,9 +160,9 @@ static int del_pvt(pvt_t *del_pvt)
     pvt_t *p, *l = NULL;
     int r = 0;
 
-    if (!t38_state_list.thread_running) goto end;
-    
+
     switch_mutex_lock(t38_state_list.mutex);
+
     for (p = t38_state_list.head; p; p = p->next) {
         if (p == del_pvt) {
             if (l) {
@@ -163,34 +172,38 @@ static int del_pvt(pvt_t *del_pvt)
             }
             p->next = NULL;
             r = 1;
-            goto end;
+            break;
         }
 
         l = p;
     }
 
- end:
-
     switch_mutex_unlock(t38_state_list.mutex);
 
-    return r;
+    wake_thread(0);
 
+    return r;
 }
 
 static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *obj)
 {
     switch_timer_t timer = { 0 };
     pvt_t *pvt;
-    int samples = 240;
-    int ms = 30;
+    int samples = 160;
+    int ms = 20;
 
-    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "timer thread started.\n");
+    switch_mutex_lock(t38_state_list.mutex);
+    t38_state_list.thread_running = 1;
+    switch_mutex_unlock(t38_state_list.mutex);
+
+    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FAX timer thread started.\n");
 
 	if (switch_core_timer_init(&timer, "soft", ms, samples, NULL) != SWITCH_STATUS_SUCCESS) {
-        return NULL;
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "timer init failed.\n");
+        goto end;
     }
 
-    t38_state_list.thread_running = 1;
+    switch_mutex_lock(globals.cond_mutex);
 
     while(t38_state_list.thread_running) {
 
@@ -198,7 +211,9 @@ static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *
 
         if (!t38_state_list.head) {
             switch_mutex_unlock(t38_state_list.mutex);
-            goto end;
+			switch_thread_cond_wait(globals.cond, globals.cond_mutex);
+            switch_core_timer_sync(&timer);
+            continue;
         }
 
         for (pvt = t38_state_list.head; pvt; pvt = pvt->next) {
@@ -211,13 +226,20 @@ static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *
 
         switch_core_timer_next(&timer);
     }
+
+    switch_mutex_unlock(globals.cond_mutex);
     
  end:
 
-    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "timer thread ended.\n");
-
+    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FAX timer thread ended.\n");
+    
+    switch_mutex_lock(t38_state_list.mutex);
     t38_state_list.thread_running = 0;
-    switch_core_timer_destroy(&timer);
+    switch_mutex_unlock(t38_state_list.mutex);
+
+    if (timer.timer_interface) {
+        switch_core_timer_destroy(&timer);
+    }
     
     return NULL;
 }
@@ -468,49 +490,61 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
 		}
 		break;
 	case T38_MODE:
-		if (pvt->t38_state == NULL) {
-			pvt->t38_state = (t38_terminal_state_t *) switch_core_session_alloc(pvt->session, sizeof(t38_terminal_state_t));
-		}
-		if (pvt->t38_state == NULL) {
-			return SWITCH_STATUS_FALSE;
-		}
-		if (pvt->udptl_state == NULL) {
-            pvt->udptl_state = (udptl_state_t *) switch_core_session_alloc(pvt->session, sizeof(udptl_state_t));
-        }
-		if (pvt->udptl_state == NULL) {
-    		t38_terminal_free(pvt->t38_state);
-            pvt->t38_state = NULL;
-			return SWITCH_STATUS_FALSE;
-		}
+        {
+            switch_core_session_message_t msg = { 0 };
 
-        /* add to timer thread processing */
-        add_pvt(pvt);
+            if (pvt->t38_state == NULL) {
+                pvt->t38_state = (t38_terminal_state_t *) switch_core_session_alloc(pvt->session, sizeof(t38_terminal_state_t));
+            }
+            if (pvt->t38_state == NULL) {
+                return SWITCH_STATUS_FALSE;
+            }
+            if (pvt->udptl_state == NULL) {
+                pvt->udptl_state = (udptl_state_t *) switch_core_session_alloc(pvt->session, sizeof(udptl_state_t));
+            }
+            if (pvt->udptl_state == NULL) {
+                t38_terminal_free(pvt->t38_state);
+                pvt->t38_state = NULL;
+                return SWITCH_STATUS_FALSE;
+            }
+
+            t38 = pvt->t38_state;
+            t30 = t38_terminal_get_t30_state(t38);
+
+            memset(t38, 0, sizeof(t38_terminal_state_t));
+
+            if (t38_terminal_init(t38, pvt->caller, t38_tx_packet_handler, pvt) == NULL) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my T.38 structs\n");
+                return SWITCH_STATUS_FALSE;
+            }
+
+            pvt->t38_core = t38_terminal_get_t38_core_state(pvt->t38_state);
+
+            if (udptl_init(pvt->udptl_state, UDPTL_ERROR_CORRECTION_REDUNDANCY, 3, 3, 
+                           (udptl_rx_packet_handler_t *) t38_core_rx_ifp_packet, (void *) pvt->t38_core) == NULL) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my UDPTL structs\n");
+                return SWITCH_STATUS_FALSE;
+            }
+
+            msg.from = __FILE__;
+            msg.message_id = SWITCH_MESSAGE_INDICATE_UDPTL_MODE;
+            switch_core_session_receive_message(pvt->session, &msg);
         
-		t38 = pvt->t38_state;
-		t30 = t38_terminal_get_t30_state(t38);
+            /* add to timer thread processing */
+            if (!add_pvt(pvt)) {
+                if (channel) {
+                    switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                }
+            }
+        
+            span_log_set_message_handler(&t38->logging, spanfax_log_message);
+            span_log_set_message_handler(&t30->logging, spanfax_log_message);
 
-		memset(t38, 0, sizeof(t38_terminal_state_t));
-
-		if (t38_terminal_init(t38, pvt->caller, t38_tx_packet_handler, pvt) == NULL) {
-			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my T.38 structs\n");
-			return SWITCH_STATUS_FALSE;
-		}
-
-        pvt->t38_core = t38_terminal_get_t38_core_state(pvt->t38_state);
-
-        if (udptl_init(pvt->udptl_state, UDPTL_ERROR_CORRECTION_REDUNDANCY, 3, 3, 
-                       (udptl_rx_packet_handler_t *) t38_core_rx_ifp_packet, (void *) pvt->t38_core) == NULL) {
-			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my UDPTL structs\n");
-			return SWITCH_STATUS_FALSE;
-		}
-
-		span_log_set_message_handler(&t38->logging, spanfax_log_message);
-		span_log_set_message_handler(&t30->logging, spanfax_log_message);
-
-		if (pvt->verbose) {
-			span_log_set_level(&t38->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
-			span_log_set_level(&t30->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
-		}
+            if (pvt->verbose) {
+                span_log_set_level(&t38->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
+                span_log_set_level(&t30->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
+            }
+        }
 		break;
  case T38_GATEWAY_MODE:
 	 if (pvt->t38_gateway_state == NULL) {
@@ -757,9 +791,9 @@ static t38_mode_t negotiate_t38(pvt_t *pvt)
         t38_options->T38FaxRateManagement = "transferredTCF";
         t38_options->T38FaxMaxBuffer = 2000;
         t38_options->T38FaxMaxDatagram = LOCAL_FAX_MAX_DATAGRAM;
-        if (strcasecmp(t38_options->T38FaxUdpEC, "t38UDPRedundancy") == 0
-            ||
-            strcasecmp(t38_options->T38FaxUdpEC, "t38UDPFEC") == 0) {
+        if (!zstr(t38_options->T38FaxUdpEC) &&
+            (strcasecmp(t38_options->T38FaxUdpEC, "t38UDPRedundancy") == 0 ||
+             strcasecmp(t38_options->T38FaxUdpEC, "t38UDPFEC") == 0)) {
             t38_options->T38FaxUdpEC = "t38UDPRedundancy";
         } else {
             t38_options->T38FaxUdpEC = NULL;
@@ -818,6 +852,12 @@ static t38_mode_t request_t38(pvt_t *pvt)
         insist = globals.enable_t38_insist;
     }
 
+    if ((t38_options = switch_channel_get_private(channel, "t38_options"))) {
+        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, 
+                          "%s already has T.38 data\n", switch_channel_get_name(channel));
+        enabled = 0;
+    }
+
     if (enabled) {
         t38_options = switch_core_session_alloc(session, sizeof(*t38_options));
         
@@ -960,6 +1000,7 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
 	switch_frame_t write_frame = { 0 };
 	switch_codec_implementation_t read_impl = { 0 };
 	int16_t *buf = NULL;
+    uint32_t req_counter = 0;
 
 	switch_core_session_get_read_impl(session, &read_impl);
 
@@ -1075,10 +1116,11 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
 
 	switch_ivr_sleep(session, 250, SWITCH_TRUE, NULL);
 
-
-    /* If you have the means, I highly recommend picking one up. ...*/
-    request_t38(pvt);
-
+    if (pvt->app_mode == FUNCTION_TX) {
+        req_counter = 100;
+    } else {
+        req_counter = 50;
+    }
 
 	while (switch_channel_ready(channel)) {
 		int tx = 0;
@@ -1122,6 +1164,13 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
             break;
         case T38_MODE_UNKNOWN:
             {
+                if (req_counter) {
+                    if (!--req_counter) {
+                        /* If you have the means, I highly recommend picking one up. ...*/
+                        request_t38(pvt);
+                    }
+                }
+                
                 if (switch_channel_test_app_flag_key("T38", channel, CF_APP_T38)) {
                     if (negotiate_t38(pvt) == T38_MODE_NEGOTIATED) {
                         /* is is safe to call this again, it was already called above in AUDIO_MODE */
@@ -1145,8 +1194,6 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
                     //switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "READ %d udptl bytes\n", read_frame->packetlen);
                     
                     udptl_rx_packet(pvt->udptl_state, read_frame->packet, read_frame->packetlen);
-
-
                 }
             }
             continue;
@@ -1282,6 +1329,8 @@ void mod_spandsp_fax_event_handler(switch_event_t *event)
 
 void mod_spandsp_fax_load(switch_memory_pool_t *pool)
 {
+    uint32_t sanity = 200;
+
 	memset(&globals, 0, sizeof(globals));
     memset(&t38_state_list, 0, sizeof(t38_state_list));
 
@@ -1289,6 +1338,9 @@ void mod_spandsp_fax_load(switch_memory_pool_t *pool)
 
 	switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
 	switch_mutex_init(&t38_state_list.mutex, SWITCH_MUTEX_NESTED, globals.pool);
+
+	switch_mutex_init(&globals.cond_mutex, SWITCH_MUTEX_NESTED, globals.pool);
+	switch_thread_cond_create(&globals.cond, globals.pool);
     
     globals.enable_t38 = 1;
 	globals.total_sessions = 0;
@@ -1301,10 +1353,22 @@ void mod_spandsp_fax_load(switch_memory_pool_t *pool)
 	strncpy(globals.header, "SpanDSP Fax Header", sizeof(globals.header) - 1);
 
 	load_configuration(0);
+
+
+    launch_timer_thread();
+
+    while(--sanity && !t38_state_list.thread_running) {
+        switch_yield(20000);
+    }
 }
 
 void mod_spandsp_fax_shutdown(void)
 {
+    switch_status_t tstatus = SWITCH_STATUS_SUCCESS;
+
+    t38_state_list.thread_running = 0;
+    wake_thread(1);
+    switch_thread_join(&tstatus, t38_state_list.thread);
 	memset(&globals, 0, sizeof(globals));
 }
 
@@ -1659,8 +1723,8 @@ static switch_status_t t38_gateway_on_reset(switch_core_session_t *session)
     
     switch_channel_clear_flag(channel, CF_REDIRECT);
 
-    if (switch_channel_test_app_flag(channel, CF_APP_TAGGED)) {
-        switch_channel_clear_app_flag(channel, CF_APP_TAGGED);
+    if (switch_channel_test_app_flag_key("T38", channel, CF_APP_TAGGED)) {
+        switch_channel_clear_app_flag_key("T38", channel, CF_APP_TAGGED);
         switch_channel_set_state(channel, CS_CONSUME_MEDIA);
     } else {
         switch_channel_set_state(channel, CS_SOFT_EXECUTE);
@@ -1697,6 +1761,9 @@ switch_bool_t t38_gateway_start(switch_core_session_t *session, const char *app,
         switch_channel_set_variable(channel, "t38_peer", switch_core_session_get_uuid(other_session));
         switch_channel_set_variable(other_channel, "t38_peer", switch_core_session_get_uuid(session));
 
+        switch_channel_set_variable(peer ? other_channel : channel, "t38_gateway_format", "audio");
+        switch_channel_set_variable(peer ? channel : other_channel, "t38_gateway_format", "udptl");
+
 
         switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s starting gateway mode to %s\n", 
                           switch_channel_get_name(peer ? channel : other_channel),
@@ -1709,8 +1776,8 @@ switch_bool_t t38_gateway_start(switch_core_session_t *session, const char *app,
         switch_channel_add_state_handler(channel, &t38_gateway_state_handlers);
         switch_channel_add_state_handler(other_channel, &t38_gateway_state_handlers);
 
-        switch_channel_set_app_flag(peer ? channel : other_channel, CF_APP_TAGGED);
-        switch_channel_clear_app_flag(peer ? other_channel : channel, CF_APP_TAGGED);   
+        switch_channel_set_app_flag_key("T38", peer ? channel : other_channel, CF_APP_TAGGED);
+        switch_channel_clear_app_flag_key("T38", peer ? other_channel : channel, CF_APP_TAGGED);   
         
         switch_channel_set_flag(channel, CF_REDIRECT);
         switch_channel_set_state(channel, CS_RESET);
diff --git a/src/mod/applications/mod_spandsp/udptl.c b/src/mod/applications/mod_spandsp/udptl.c
index a2651513f0..f5b3be2445 100644
--- a/src/mod/applications/mod_spandsp/udptl.c
+++ b/src/mod/applications/mod_spandsp/udptl.c
@@ -93,7 +93,7 @@ static int encode_length(uint8_t *buf, int *len, int value)
 
 	if (value < 0x80) {
 		/* 1 octet */
-		buf[(*len)++] = value;
+		buf[(*len)++] = (uint8_t)value;
 		return value;
 	}
 	if (value < 0x4000) {
@@ -106,7 +106,7 @@ static int encode_length(uint8_t *buf, int *len, int value)
 	/* Fragmentation */
 	multiplier = (value < 0x10000) ? (value >> 14) : 4;
 	/* Set the first 2 bits of the octet */
-	buf[(*len)++] = 0xC0 | multiplier;
+	buf[(*len)++] = (uint8_t) (0xC0 | multiplier);
 	return multiplier << 14;
 }
 
@@ -419,10 +419,10 @@ int udptl_build_packet(udptl_state_t *s, uint8_t buf[], const uint8_t msg[], int
 		/* Span is defined as an inconstrained integer, which it dumb. It will only
 		   ever be a small value. Treat it as such. */
 		buf[len++] = 1;
-		buf[len++] = span;
+		buf[len++] = (uint8_t)span;
 		/* The number of entries is defined as a length, but will only ever be a small
 		   value. Treat it as such. */
-		buf[len++] = entries;
+		buf[len++] = (uint8_t)entries;
 		for (m = 0; m < entries; m++) {
 			/* Make an XOR'ed entry the maximum length */
 			limit = (entry + m) & UDPTL_BUF_MASK;
diff --git a/src/mod/applications/mod_valet_parking/mod_valet_parking.c b/src/mod/applications/mod_valet_parking/mod_valet_parking.c
index aee49c76e9..b75202189c 100644
--- a/src/mod/applications/mod_valet_parking/mod_valet_parking.c
+++ b/src/mod/applications/mod_valet_parking/mod_valet_parking.c
@@ -203,7 +203,7 @@ SWITCH_STANDARD_APP(valet_parking_function)
 			}
 
 			do {
-				status = switch_ivr_read(session, min, max, prompt, NULL, dtmf_buf, sizeof(dtmf_buf), to, "#");
+				status = switch_ivr_read(session, min, max, prompt, NULL, dtmf_buf, sizeof(dtmf_buf), to, "#", 0);
 			} while (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_FALSE);
 
 			if (status == SWITCH_STATUS_SUCCESS) {
diff --git a/src/mod/applications/mod_voicemail/mod_voicemail.c b/src/mod/applications/mod_voicemail/mod_voicemail.c
index c683712922..860f89788b 100644
--- a/src/mod/applications/mod_voicemail/mod_voicemail.c
+++ b/src/mod/applications/mod_voicemail/mod_voicemail.c
@@ -824,7 +824,8 @@ static switch_status_t control_playback(switch_core_session_t *session, void *in
 			if (!cc->noexit
 				&& (dtmf->digit == *cc->profile->delete_file_key || dtmf->digit == *cc->profile->save_file_key
 					|| dtmf->digit == *cc->profile->prev_msg_key || dtmf->digit == *cc->profile->next_msg_key
-					|| dtmf->digit == *cc->profile->terminator_key || dtmf->digit == *cc->profile->skip_info_key)) {
+					|| dtmf->digit == *cc->profile->terminator_key || dtmf->digit == *cc->profile->skip_info_key
+					|| dtmf->digit == *cc->profile->email_key || dtmf->digit == *cc->profile->forward_key)) {
 				*cc->buf = dtmf->digit;
 				return SWITCH_STATUS_BREAK;
 			}
@@ -1421,6 +1422,7 @@ static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t
 	char cid_buf[1024] = "";
 
 	if (switch_channel_ready(channel)) {
+		const char *vm_announce_cid = NULL;
 
 		switch_snprintf(cid_buf, sizeof(cid_buf), "%s|%s", cbt->cid_number, cbt->cid_name);
 
@@ -1428,7 +1430,13 @@ static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t
 		msg.string_arg = cid_buf;
 		msg.message_id = SWITCH_MESSAGE_INDICATE_DISPLAY;
 		switch_core_session_receive_message(session, &msg);
-
+		
+		if (!zstr(cbt->cid_number) && (vm_announce_cid = switch_channel_get_variable(channel, "vm_announce_cid"))) {
+			switch_ivr_play_file(session, NULL, vm_announce_cid, NULL);
+			switch_ivr_sleep(session, 500, SWITCH_TRUE, NULL);
+			switch_ivr_say(session, cbt->cid_number, NULL, "name_spelled", "pronounced", NULL, NULL);
+		}
+		
 		args.input_callback = cancel_on_dtmf;
 		
 		switch_snprintf(key_buf, sizeof(key_buf), "%s:%s:%s:%s:%s:%s%s%s", profile->listen_file_key, profile->save_file_key,
@@ -1523,7 +1531,7 @@ static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t
 				vm_cc[0] = '\0';
 
 				TRY_CODE(switch_ivr_read
-						 (session, 0, sizeof(vm_cc), macro_buf, NULL, vm_cc, sizeof(vm_cc), profile->digit_timeout, profile->terminator_key));
+						 (session, 0, sizeof(vm_cc), macro_buf, NULL, vm_cc, sizeof(vm_cc), profile->digit_timeout, profile->terminator_key, 0));
 
 				cmd = switch_core_session_sprintf(session, "%s@%s %s %s '%s'", vm_cc, cbt->domain, new_file_path, cbt->cid_number, cbt->cid_name);
 
@@ -1987,7 +1995,7 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
 					switch_xml_t xx_user, xx_domain, xx_domain_root;
 
 					switch_snprintf(macro, sizeof(macro), "phrase:%s:%s", VM_ENTER_PASS_MACRO, profile->terminator_key);
-					TRY_CODE(switch_ivr_read(session, 0, 255, macro, NULL, buf, sizeof(buf), 10000, profile->terminator_key));
+					TRY_CODE(switch_ivr_read(session, 0, 255, macro, NULL, buf, sizeof(buf), 10000, profile->terminator_key, 0));
 					sql = switch_mprintf("update voicemail_prefs set password='%s' where username='%s' and domain='%s'", buf, myid, domain_name);
 					vm_execute_sql(profile, sql, profile->mutex);
 					switch_safe_free(file_path);
@@ -2686,23 +2694,29 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t
 
 	if ((domain = strchr(user, '@'))) {
 		*domain++ = '\0';
-	} else {
-		domain = user;
-	}
 
-	if ((profile_name = strchr(domain, '@'))) {
-		*profile_name++ = '\0';
-	} else {
-		profile_name = domain;
+		if ((profile_name = strchr(domain, '@'))) {
+			*profile_name++ = '\0';
+		} else {
+			profile_name = domain;
+		}
 	}
 
 	if (switch_stristr("group=", user)) {
 		user += 6;
 		isgroup++;
-	} else if (user == domain) {
+	} else if (switch_stristr("domain=", user)) {
+		user += 7;
+		domain = user;
+		profile_name = domain;
 		isall++;
 	}
 
+	if (zstr(domain)) {
+		domain = switch_core_get_variable("domain");
+		profile_name = domain;
+	}
+
 	if (!(user && domain)) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid syntax [%s][%s]\n", switch_str_nil(user), switch_str_nil(domain));
 		status = SWITCH_STATUS_FALSE;
@@ -2746,6 +2760,7 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate domain %s\n", domain);
 			status = SWITCH_STATUS_FALSE;
 			switch_event_destroy(&my_params);
+			profile_rwunlock(profile);
 			goto end;
 		}
 
@@ -3164,7 +3179,7 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
 		switch_event_destroy(&vars);
 		if (status == SWITCH_STATUS_SUCCESS) {
 			if ((vm_cc = switch_channel_get_variable(channel, "vm_cc"))) {
-				char *cmd = switch_core_session_sprintf(session, "%s %s %s %s %s@%s %s",
+				char *cmd = switch_core_session_sprintf(session, "%s %s %s '%s' %s@%s %s",
 														vm_cc, file_path, caller_id_number, caller_id_name, id, domain_name, read_flags);
 
 				if (voicemail_inject(cmd, session) == SWITCH_STATUS_SUCCESS) {
@@ -3670,7 +3685,7 @@ static int web_callback(void *pArg, int argc, char **argv, char **columnNames)
 	const char *fmt = "%a, %e %b %Y %T %z";
 	char heard[80];
 	char title_b4[128] = "";
-	char title_aft[128 * 3] = "";
+	char title_aft[128 * 3 + 1] = "";
 
 	if (argc > 0) {
 		l_created = switch_time_make(atol(argv[0]), 0);
@@ -3961,7 +3976,7 @@ static void do_web(vm_profile_t *profile, const char *user_in, const char *domai
 	}
 }
 
-#define VM_INJECT_USAGE "[group=]  [] []"
+#define VM_INJECT_USAGE "[group=[@domain]|domain=|[@]]  [] []"
 SWITCH_STANDARD_API(voicemail_inject_api_function)
 {
 	if (voicemail_inject(cmd, session) == SWITCH_STATUS_SUCCESS) {
diff --git a/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c b/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c
index 139fe217a3..4b36e1435e 100644
--- a/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c
+++ b/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c
@@ -2724,7 +2724,7 @@ static switch_status_t recog_asr_open(switch_asr_handle_t *ah, const char *codec
 		name++;
 		name = switch_core_sprintf(ah->memory_pool, "%s ASR-%d", name, speech_channel_number);
 	} else {
-		name = switch_core_sprintf(ah->memory_pool, "ASR-%d", name, speech_channel_number);
+		name = switch_core_sprintf(ah->memory_pool, "ASR-%d", speech_channel_number);
 	}
 
 	/* Allocate the channel */
diff --git a/src/mod/codecs/mod_amr/mod_amr.c b/src/mod/codecs/mod_amr/mod_amr.c
index a864254e28..e8925c4581 100644
--- a/src/mod/codecs/mod_amr/mod_amr.c
+++ b/src/mod/codecs/mod_amr/mod_amr.c
@@ -98,11 +98,8 @@ typedef enum {
 	AMR_DTX_ENABLED
 } amr_dtx_t;
 
-struct amr_context {
-	void *encoder_state;
-	void *decoder_state;
-	switch_byte_t enc_modes;
-	switch_byte_t enc_mode;
+/*! \brief Various codec settings */
+struct amr_codec_settings {
 	int dtx_mode;
 	uint32_t change_period;
 	switch_byte_t max_ptime;
@@ -110,6 +107,24 @@ struct amr_context {
 	switch_byte_t channels;
 	switch_byte_t flags;
 };
+typedef struct amr_codec_settings amr_codec_settings_t;
+
+static amr_codec_settings_t default_codec_settings = {
+	/*.dtx_mode */ AMR_DTX_ENABLED,
+	/*.change_period */ 0,
+	/*.max_ptime */ 0,
+	/*.ptime */ 0,
+	/*.channels */ 0,
+	/*.flags */ 0,
+};
+
+
+struct amr_context {
+	void *encoder_state;
+	void *decoder_state;
+	switch_byte_t enc_modes;
+	switch_byte_t enc_mode;
+};
 
 #define AMR_DEFAULT_BITRATE AMR_BITRATE_1220
 
@@ -117,6 +132,88 @@ static struct {
 	switch_byte_t default_bitrate;
 } globals;
 
+static switch_status_t switch_amr_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
+{
+	if (codec_fmtp) {
+		amr_codec_settings_t *codec_settings = NULL;
+		if (codec_fmtp->private_info) {
+			codec_settings = codec_fmtp->private_info;
+			memcpy(codec_settings, &default_codec_settings, sizeof(*codec_settings));
+		}
+
+		if (fmtp) {
+			int x, argc;
+			char *argv[10];
+			char *fmtp_dup = strdup(fmtp);
+
+			switch_assert(fmtp_dup);
+
+			argc = switch_separate_string((char *) fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0])));
+			for (x = 0; x < argc; x++) {
+				char *data = argv[x];
+				char *arg;
+				switch_assert(data);
+				while (*data == ' ') {
+					data++;
+				}
+				if ((arg = strchr(data, '='))) {
+					*arg++ = '\0';
+					/*
+					   if (!strcasecmp(data, "bitrate")) {
+					   bit_rate = atoi(arg);
+					   }
+					 */
+					if (codec_settings) {
+						if (!strcasecmp(data, "octet-align")) {
+							if (atoi(arg)) {
+								switch_set_flag(codec_settings, AMR_OPT_OCTET_ALIGN);
+							}
+						} else if (!strcasecmp(data, "mode-change-neighbor")) {
+							if (atoi(arg)) {
+								switch_set_flag(codec_settings, AMR_OPT_MODE_CHANGE_NEIGHBOR);
+							}
+						} else if (!strcasecmp(data, "crc")) {
+							if (atoi(arg)) {
+								switch_set_flag(codec_settings, AMR_OPT_CRC);
+							}
+						} else if (!strcasecmp(data, "robust-sorting")) {
+							if (atoi(arg)) {
+								switch_set_flag(codec_settings, AMR_OPT_ROBUST_SORTING);
+							}
+						} else if (!strcasecmp(data, "interveaving")) {
+							if (atoi(arg)) {
+								switch_set_flag(codec_settings, AMR_OPT_INTERLEAVING);
+							}
+						} else if (!strcasecmp(data, "mode-change-period")) {
+							codec_settings->change_period = atoi(arg);
+						} else if (!strcasecmp(data, "ptime")) {
+							codec_settings->ptime = (switch_byte_t) atoi(arg);
+						} else if (!strcasecmp(data, "channels")) {
+							codec_settings->channels = (switch_byte_t) atoi(arg);
+						} else if (!strcasecmp(data, "maxptime")) {
+							codec_settings->max_ptime = (switch_byte_t) atoi(arg);
+						} else if (!strcasecmp(data, "mode-set")) {
+							int y, m_argc;
+							char *m_argv[7];
+							m_argc = switch_separate_string(arg, ',', m_argv, (sizeof(m_argv) / sizeof(m_argv[0])));
+							for (y = 0; y < m_argc; y++) {
+								codec_settings->enc_modes |= (1 << atoi(m_argv[y]));
+							}
+						} else if (!strcasecmp(data, "dtx")) {
+							codec_settings->dtx_mode = (atoi(arg)) ? AMR_DTX_ENABLED : AMR_DTX_DISABLED;
+						}
+					}
+
+				}
+			}
+			free(fmtp_dup);
+		}
+		//codec_fmtp->bits_per_second = bit_rate;
+		return SWITCH_STATUS_SUCCESS;
+	}
+	return SWITCH_STATUS_FALSE;
+}
+
 #endif
 
 static switch_status_t switch_amr_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
@@ -128,7 +225,10 @@ static switch_status_t switch_amr_init(switch_codec_t *codec, switch_codec_flag_
 	}
 	return SWITCH_STATUS_SUCCESS;
 #else
+
 	struct amr_context *context = NULL;
+	switch_codec_fmtp_t codec_fmtp;
+	amr_codec_settings_t amr_codec_settings;
 	int encoding, decoding;
 	int x, i, argc;
 	char *argv[10];
@@ -141,58 +241,9 @@ static switch_status_t switch_amr_init(switch_codec_t *codec, switch_codec_flag_
 		return SWITCH_STATUS_FALSE;
 	} else {
 
-		context->dtx_mode = AMR_DTX_ENABLED;
-		if (codec->fmtp_in) {
-			argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0])));
-			for (x = 0; x < argc; x++) {
-				char *data = argv[x];
-				char *arg;
-				while (*data && *data == ' ') {
-					data++;
-				}
-				if ((arg = strchr(data, '='))) {
-					*arg++ = '\0';
-					if (!strcasecmp(data, "octet-align")) {
-						if (atoi(arg)) {
-							switch_set_flag(context, AMR_OPT_OCTET_ALIGN);
-						}
-					} else if (!strcasecmp(data, "mode-change-neighbor")) {
-						if (atoi(arg)) {
-							switch_set_flag(context, AMR_OPT_MODE_CHANGE_NEIGHBOR);
-						}
-					} else if (!strcasecmp(data, "crc")) {
-						if (atoi(arg)) {
-							switch_set_flag(context, AMR_OPT_CRC);
-						}
-					} else if (!strcasecmp(data, "robust-sorting")) {
-						if (atoi(arg)) {
-							switch_set_flag(context, AMR_OPT_ROBUST_SORTING);
-						}
-					} else if (!strcasecmp(data, "interveaving")) {
-						if (atoi(arg)) {
-							switch_set_flag(context, AMR_OPT_INTERLEAVING);
-						}
-					} else if (!strcasecmp(data, "mode-change-period")) {
-						context->change_period = atoi(arg);
-					} else if (!strcasecmp(data, "ptime")) {
-						context->ptime = (switch_byte_t) atoi(arg);
-					} else if (!strcasecmp(data, "channels")) {
-						context->channels = (switch_byte_t) atoi(arg);
-					} else if (!strcasecmp(data, "maxptime")) {
-						context->max_ptime = (switch_byte_t) atoi(arg);
-					} else if (!strcasecmp(data, "mode-set")) {
-						int y, m_argc;
-						char *m_argv[7];
-						m_argc = switch_separate_string(arg, ',', m_argv, (sizeof(m_argv) / sizeof(m_argv[0])));
-						for (y = 0; y < m_argc; y++) {
-							context->enc_modes |= (1 << atoi(m_argv[y]));
-						}
-					} else if (!strcasecmp(data, "dtx")) {
-						context->dtx_mode = (atoi(arg)) ? AMR_DTX_ENABLED : AMR_DTX_DISABLED;
-					}
-				}
-			}
-		}
+		memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
+		codec_fmtp.private_info = &amr_codec_settings;
+		switch_amr_fmtp_parse(codec->fmtp_in, &codec_fmtp);
 
 		if (context->enc_modes) {
 			for (i = 7; i > -1; i++) {
@@ -321,6 +372,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_amr_load)
 	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
 
 	SWITCH_ADD_CODEC(codec_interface, "AMR");
+#ifndef AMR_PASSTHROUGH
+	codec_interface->parse_fmtp = switch_amr_fmtp_parse;
+#endif 
 	switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO,	/* enumeration defining the type of the codec */
 										 96,	/* the IANA code number */
 										 "AMR",	/* the IANA code name */
diff --git a/src/mod/codecs/mod_codec2/Makefile b/src/mod/codecs/mod_codec2/Makefile
new file mode 100644
index 0000000000..568df9c64d
--- /dev/null
+++ b/src/mod/codecs/mod_codec2/Makefile
@@ -0,0 +1,14 @@
+BASE=../../../..
+
+CODEC2_DIR=$(switch_srcdir)/libs/libcodec2
+CODEC2_BUILDDIR=$(switch_builddir)/libs/libcodec2
+CODEC2LA=$(CODEC2_BUILDDIR)/src/libcodec2.la
+
+LOCAL_CFLAGS=-I$(CODEC2_DIR)/include -I$(CODEC2_BUILDDIR)/src
+LOCAL_LIBADD=$(CODEC2LA)
+include $(BASE)/build/modmake.rules
+
+$(CODEC2LA): $(CODEC2_DIR) $(CODEC2_DIR)/.update
+	cd $(CODEC2_BUILDDIR) && $(MAKE)
+	$(TOUCH_TARGET)
+
diff --git a/src/mod/codecs/mod_codec2/mod_codec2.c b/src/mod/codecs/mod_codec2/mod_codec2.c
new file mode 100644
index 0000000000..e7aa645090
--- /dev/null
+++ b/src/mod/codecs/mod_codec2/mod_codec2.c
@@ -0,0 +1,264 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2010, Anthony Minessale II 
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library
+ *
+ * The Initial Developer of the Original Code is
+ * Brian West 
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mathieu Rene 
+ *
+ * mod_codec2 -- FreeSWITCH CODEC2 Module
+ *
+ */
+
+#include 
+#include 
+
+/* Uncomment to log input/output data for debugging 
+#define LOG_DATA 
+#define CODEC2_DEBUG
+*/
+
+#ifdef CODEC2_DEBUG
+#define codec2_assert(_x) switch_assert(_x)
+#else
+#define codec2_assert(_x) 
+#endif
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_codec2_load);
+
+SWITCH_MODULE_DEFINITION(mod_codec2, mod_codec2_load, NULL, NULL);
+
+struct codec2_context {
+	void *encoder;
+	void *decoder;
+#ifdef LOG_DATA	
+	FILE *encoder_in;
+	FILE *encoder_out;
+	FILE *encoder_out_unpacked;
+	FILE *decoder_in;
+	FILE *decoder_in_unpacked;
+	FILE *decoder_out;
+#endif
+};
+
+#ifdef LOG_DATA
+static int c2_count = 0;
+#endif
+
+static switch_status_t switch_codec2_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
+{
+	uint32_t encoding, decoding;
+	struct codec2_context *context = NULL;
+
+	encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
+	decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
+
+	if (!(encoding || decoding)) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	if (!(context = switch_core_alloc(codec->memory_pool, sizeof(*context)))) {
+		return SWITCH_STATUS_FALSE;
+	}
+	
+	if (encoding) {
+		context->encoder = codec2_create();		
+	}
+	
+	if (decoding) {
+		context->decoder = codec2_create();
+	}
+
+	codec->private_info = context;
+	
+#ifdef LOG_DATA		
+	{
+		
+		int c = c2_count++;
+		char buf[1024];
+		
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Logging as /tmp/c2-%d-*\n", c);
+		
+		if (encoding) {
+			snprintf(buf, sizeof(buf), "/tmp/c2-%d-enc-in", c);
+			context->encoder_in = fopen(buf, "w");
+		
+			snprintf(buf, sizeof(buf), "/tmp/c2-%d-enc-out", c);
+			context->encoder_out = fopen(buf, "w");
+		
+			snprintf(buf, sizeof(buf), "/tmp/c2-%d-enc-out-unpacked", c);
+			context->encoder_out_unpacked = fopen(buf, "w");
+		}
+		if (decoding) {
+			snprintf(buf, sizeof(buf), "/tmp/c2-%d-dec-in", c);
+			context->decoder_in = fopen(buf, "w");
+		
+			snprintf(buf, sizeof(buf), "/tmp/c2-%d-dec-out", c);
+			context->decoder_out = fopen(buf, "w");
+		
+			snprintf(buf, sizeof(buf), "/tmp/c2-%d-dec-out-unpacked", c);
+			context->decoder_in_unpacked = fopen(buf, "w");
+		}
+	}
+#endif
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t switch_codec2_encode(switch_codec_t *codec, switch_codec_t *other_codec,
+										  void *decoded_data,
+										  uint32_t decoded_data_len,
+										  uint32_t decoded_rate,
+										  void *encoded_data,
+										  uint32_t *encoded_data_len,
+										  uint32_t *encoded_rate,
+										  unsigned int *flag)
+{
+	struct codec2_context *context = codec->private_info;
+	
+	codec2_assert(decoded_data_len == CODEC2_SAMPLES_PER_FRAME * 2);
+	
+#ifdef LOG_DATA	
+	fwrite(decoded_data, decoded_data_len, 1, context->encoder_in);
+	fflush(context->encoder_in);
+#endif
+
+	codec2_encode(context->encoder, encoded_data, decoded_data);
+	
+#ifdef LOG_DATA	
+	fwrite(encode_buf, sizeof(encode_buf), 1, context->encoder_out_unpacked);
+	fflush(context->encoder_out_unpacked);
+	fwrite(encoded_data, 8, 1, context->encoder_out);
+	fflush(context->encoder_out);
+#endif
+	
+	*encoded_data_len = 8;
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t switch_codec2_decode(switch_codec_t *codec,
+										  switch_codec_t *other_codec,
+										  void *encoded_data,
+										  uint32_t encoded_data_len,
+										  uint32_t encoded_rate,
+										  void *decoded_data,
+										  uint32_t *decoded_data_len,
+										  uint32_t *decoded_rate,
+										  unsigned int *flag)
+{
+	struct codec2_context *context = codec->private_info;
+	
+	codec2_assert(encoded_data_len == 8 /* aligned to 8 */);
+	
+#ifdef LOG_DATA	
+	fwrite(encoded_data, encoded_data_len, 1, context->decoder_in);
+	fflush(context->decoder_in);
+	fwrite(bits, sizeof(bits), 1, context->decoder_in_unpacked);
+	fflush(context->decoder_in_unpacked);
+#endif
+	
+	codec2_decode(context->decoder, decoded_data, encoded_data);
+
+#ifdef LOG_DATA	
+	fwrite(decoded_data, CODEC2_SAMPLES_PER_FRAME, 2, context->decoder_out);
+	fflush(context->decoder_out);
+#endif
+
+	*decoded_data_len = CODEC2_SAMPLES_PER_FRAME * 2; /* 160 samples */
+	
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t switch_codec2_destroy(switch_codec_t *codec)
+{
+	struct codec2_context *context = codec->private_info;
+	
+	codec2_destroy(context->encoder);
+	codec2_destroy(context->decoder);
+
+	context->encoder = NULL;
+	context->decoder = NULL;
+
+#ifdef LOG_DATA
+	if (context->encoder_in) {
+		fclose(context->encoder_in);
+	}
+	if (context->encoder_out) {
+		fclose(context->encoder_out);
+	}
+	if (context->encoder_out_unpacked) {
+		fclose(context->encoder_out_unpacked);
+	}
+	if (context->decoder_in) {
+		fclose(context->decoder_in);
+	}
+	if (context->decoder_in_unpacked) {
+		fclose(context->decoder_in_unpacked);
+	}
+	if (context->decoder_out) {
+		fclose(context->decoder_out);
+	}
+#endif
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_codec2_load)
+{
+	switch_codec_interface_t *codec_interface;
+
+	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+	SWITCH_ADD_CODEC(codec_interface, "CODEC2 2550bps");
+
+	switch_core_codec_add_implementation(pool, codec_interface,
+							 SWITCH_CODEC_TYPE_AUDIO,
+							 111,
+							 "CODEC2",
+							 NULL,
+							 8000, /* samples/sec */
+							 8000, /* samples/sec */
+							 2550, /* bps */
+							 20000, /* ptime */
+							 CODEC2_SAMPLES_PER_FRAME,	/* samples decoded */
+							 CODEC2_SAMPLES_PER_FRAME*2,	/* bytes decoded */
+							 0,	/* bytes encoded */
+							 1,	/* channels */
+							 1,	/* frames/packet */
+							 switch_codec2_init,
+							 switch_codec2_encode,
+							 switch_codec2_decode,
+							 switch_codec2_destroy);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* 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/src/mod/codecs/mod_ilbc/mod_ilbc.c b/src/mod/codecs/mod_ilbc/mod_ilbc.c
index b37056c393..85298375db 100644
--- a/src/mod/codecs/mod_ilbc/mod_ilbc.c
+++ b/src/mod/codecs/mod_ilbc/mod_ilbc.c
@@ -40,6 +40,27 @@ struct ilbc_context {
 	ilbc_decode_state_t decoder_object;
 };
 
+static switch_status_t switch_ilbc_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
+{
+	if (codec_fmtp) {
+		char *mode = NULL;
+		int codec_ms = 0;
+
+		memset(codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
+
+		if (fmtp && (mode = strstr(fmtp, "mode=")) && (mode + 5)) {
+			codec_ms = atoi(mode + 5);
+		}
+		if (!codec_ms) {
+			/* default to 30 when no mode is defined for ilbc ONLY */
+			codec_ms = 30;
+		}
+		codec_fmtp->microseconds_per_packet = (codec_ms * 1000);
+		return SWITCH_STATUS_SUCCESS;
+	}
+	return SWITCH_STATUS_FALSE;
+}
+
 static switch_status_t switch_ilbc_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
 {
 	struct ilbc_context *context;
@@ -51,26 +72,6 @@ static switch_status_t switch_ilbc_init(switch_codec_t *codec, switch_codec_flag
 		return SWITCH_STATUS_FALSE;
 	}
 
-	if (codec->fmtp_in) {
-		int x, argc;
-		char *argv[10];
-		argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0])));
-		for (x = 0; x < argc; x++) {
-			char *data = argv[x];
-			char *arg;
-			switch_assert(data);
-			while (*data == ' ') {
-				data++;
-			}
-			if ((arg = strchr(data, '='))) {
-				*arg++ = '\0';
-				if (!strcasecmp(data, "mode")) {
-					mode = atoi(arg);
-				}
-			}
-		}
-	}
-
 	codec->fmtp_out = switch_core_sprintf(codec->memory_pool, "mode=%d", mode);
 
 	if (encoding) {
@@ -136,6 +137,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_ilbc_load)
 	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
 
 	SWITCH_ADD_CODEC(codec_interface, "iLBC");
+	codec_interface->parse_fmtp = switch_ilbc_fmtp_parse;
 
 	switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO,	/* enumeration defining the type of the codec */
 										 98,	/* the IANA code number */
diff --git a/src/mod/codecs/mod_silk/mod_silk.c b/src/mod/codecs/mod_silk/mod_silk.c
index 9d0abcdf8b..934c9ebe32 100644
--- a/src/mod/codecs/mod_silk/mod_silk.c
+++ b/src/mod/codecs/mod_silk/mod_silk.c
@@ -41,6 +41,22 @@ SWITCH_MODULE_DEFINITION(mod_silk, mod_silk_load, NULL, NULL);
 #define MAX_LBRR_DELAY			2
 #define MAX_FRAME_LENGTH		480
 
+/*! \brief Various codec settings */
+struct silk_codec_settings {
+	SKP_int useinbandfec;
+	SKP_int usedtx;
+	SKP_int maxaveragebitrate;
+	SKP_int plpct;
+};
+typedef struct silk_codec_settings silk_codec_settings_t;
+
+static silk_codec_settings_t default_codec_settings = {
+	/*.useinbandfec */ 0,
+	/*.usedtx */ 0,
+	/*.maxaveragebitrate */ 0,
+	/*.plpct */ 10, // 10% for now
+};
+
 struct silk_context {
 	SKP_SILK_SDK_EncControlStruct encoder_object;
 	SKP_SILK_SDK_DecControlStruct decoder_object;
@@ -48,12 +64,105 @@ struct silk_context {
 	void *dec_state;
 };
 
+static switch_status_t switch_silk_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
+{
+	if (codec_fmtp) {
+		silk_codec_settings_t *codec_settings = NULL;
+
+		if (codec_fmtp->private_info) {
+			codec_settings = codec_fmtp->private_info;
+			memcpy(codec_settings, &default_codec_settings, sizeof(*codec_settings));
+		}
+
+		if (fmtp) {
+			int x, argc;
+			char *argv[10];
+			char *fmtp_dup = strdup(fmtp);
+
+			switch_assert(fmtp_dup);
+
+			argc = switch_separate_string(fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0])));
+			for (x = 0; x < argc; x++) {
+				char *data = argv[x];
+				char *arg;
+				switch_assert(data);
+				while (*data == ' ') {
+					data++;
+				}
+				if ((arg = strchr(data, '='))) {
+					*arg++ = '\0';
+					if (codec_settings) {
+						if (!strcasecmp(data, "useinbandfec")) {
+							if (switch_true(arg)) {
+								codec_settings->useinbandfec = 1;
+							}
+						}
+						if (!strcasecmp(data, "usedtx")) {
+							if (switch_true(arg)) {
+								codec_settings->usedtx = 1;
+							}
+						}
+						if (!strcasecmp(data, "maxaveragebitrate")) {
+							codec_settings->maxaveragebitrate = atoi(arg);
+							switch(codec_fmtp->actual_samples_per_second) {
+								case 8000:
+									{
+										if(codec_settings->maxaveragebitrate < 6000 || codec_settings->maxaveragebitrate > 20000) {
+											codec_settings->maxaveragebitrate = 20000;
+										}
+										break;
+									}
+								case 12000:
+									{
+										if(codec_settings->maxaveragebitrate < 7000 || codec_settings->maxaveragebitrate > 25000) {
+											codec_settings->maxaveragebitrate = 25000;
+										}
+										break;
+									}
+								case 16000:
+									{
+										if(codec_settings->maxaveragebitrate < 8000 || codec_settings->maxaveragebitrate > 30000) {
+											codec_settings->maxaveragebitrate = 30000;
+										}
+										break;
+									}
+								case 24000:
+									{
+										if(codec_settings->maxaveragebitrate < 12000 || codec_settings->maxaveragebitrate > 40000) {
+											codec_settings->maxaveragebitrate = 40000;
+										}
+										break;
+									}
+
+								default:
+									/* this should never happen but 20000 is common among all rates */
+									codec_settings->maxaveragebitrate = 20000;
+									break;
+							}
+
+						}
+
+					}
+				}
+			}
+			free(fmtp_dup);
+		}
+		//codec_fmtp->bits_per_second = bit_rate;
+		return SWITCH_STATUS_SUCCESS;
+	}
+	return SWITCH_STATUS_FALSE;
+}
+
+
+
+
 static switch_status_t switch_silk_init(switch_codec_t *codec, 
 										switch_codec_flag_t freeswitch_flags, 
 										const switch_codec_settings_t *codec_settings)
 {
 	struct silk_context *context = NULL;
-	SKP_int useinbandfec = 0, usedtx = 0, maxaveragebitrate = 0, plpct =0;
+	switch_codec_fmtp_t codec_fmtp;
+	silk_codec_settings_t silk_codec_settings;
 	SKP_int32 encSizeBytes;
 	SKP_int32 decSizeBytes;
 	int encoding = (freeswitch_flags & SWITCH_CODEC_FLAG_ENCODE);
@@ -62,78 +171,15 @@ static switch_status_t switch_silk_init(switch_codec_t *codec,
 	if (!(encoding || decoding) || (!(context = switch_core_alloc(codec->memory_pool, sizeof(*context))))) {
 		return SWITCH_STATUS_FALSE;
 	}
-	
-	if (codec->fmtp_in) {
-		int x, argc;
-		char *argv[10];
-		argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0])));
-		for (x = 0; x < argc; x++) {
-			char *data = argv[x];
-			char *arg;
-			switch_assert(data);
-			while (*data == ' ') {
-				data++;
-			}
-			if ((arg = strchr(data, '='))) {
-				*arg++ = '\0';
-				if (!strcasecmp(data, "useinbandfec")) {
-					if (switch_true(arg)) {
-						useinbandfec = 1;
-						plpct = 10;// 10% for now
-					}
-				}
-				if (!strcasecmp(data, "usedtx")) {
-					if (switch_true(arg)) {
-						usedtx = 1;
-					}
-				}
-				if (!strcasecmp(data, "maxaveragebitrate")) {
-					maxaveragebitrate = atoi(arg);
-					switch(codec->implementation->actual_samples_per_second) {
-					case 8000:
-						{
-							if(maxaveragebitrate < 6000 || maxaveragebitrate > 20000) {
-								maxaveragebitrate = 20000;
-							}
-							break;
-						}
-					case 12000:
-						{
-							if(maxaveragebitrate < 7000 || maxaveragebitrate > 25000) {
-								maxaveragebitrate = 25000;
-							}
-							break;
-						}
-					case 16000:
-						{
-							if(maxaveragebitrate < 8000 || maxaveragebitrate > 30000) {
-								maxaveragebitrate = 30000;
-							}
-							break;
-						}
-					case 24000:
-						{
-							if(maxaveragebitrate < 12000 || maxaveragebitrate > 40000) {
-								maxaveragebitrate = 40000;
-							}
-							break;
-						}
-						
-					default:
-						/* this should never happen but 20000 is common among all rates */
-						maxaveragebitrate = 20000;
-						break;
-					}
-					
-				}
-			}
-		}
-	}
+
+	memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
+	codec_fmtp.private_info = &silk_codec_settings;
+	switch_silk_fmtp_parse(codec->fmtp_in, &codec_fmtp);
 	
 	codec->fmtp_out = switch_core_sprintf(codec->memory_pool, "useinbandfec=%s; usedtx=%s; maxaveragebitrate=%d",
-										  useinbandfec ? "1" : "0",
-										  usedtx ? "1" : "0",
-										  maxaveragebitrate ? maxaveragebitrate : codec->implementation->bits_per_second);
+										  silk_codec_settings.useinbandfec ? "1" : "0",
+										  silk_codec_settings.usedtx ? "1" : "0",
+										  silk_codec_settings.maxaveragebitrate ? silk_codec_settings.maxaveragebitrate : codec->implementation->bits_per_second);
 
 	if (encoding) {
 		if (SKP_Silk_SDK_Get_Encoder_Size(&encSizeBytes)) {
@@ -148,11 +194,11 @@ static switch_status_t switch_silk_init(switch_codec_t *codec,
 		
 		context->encoder_object.sampleRate = codec->implementation->actual_samples_per_second;
 		context->encoder_object.packetSize = codec->implementation->samples_per_packet;
-		context->encoder_object.useInBandFEC = useinbandfec;
+		context->encoder_object.useInBandFEC = silk_codec_settings.useinbandfec;
 		context->encoder_object.complexity = 0;
-		context->encoder_object.bitRate = maxaveragebitrate ? maxaveragebitrate : codec->implementation->bits_per_second;
-		context->encoder_object.useDTX = usedtx;
-		context->encoder_object.packetLossPercentage = plpct;;
+		context->encoder_object.bitRate = silk_codec_settings.maxaveragebitrate ? silk_codec_settings.maxaveragebitrate : codec->implementation->bits_per_second;
+		context->encoder_object.useDTX = silk_codec_settings.usedtx;
+		context->encoder_object.packetLossPercentage = silk_codec_settings.plpct;
 	}
 
 	if (decoding) {
@@ -174,7 +220,7 @@ static switch_status_t switch_silk_init(switch_codec_t *codec,
 
 static switch_status_t switch_silk_destroy(switch_codec_t *codec)
 {
-    codec->private_info = NULL;
+	codec->private_info = NULL;
 	return SWITCH_STATUS_SUCCESS;
 }
 
@@ -299,6 +345,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_silk_load)
 	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
 
 	SWITCH_ADD_CODEC(codec_interface, "SILK");
+	codec_interface->parse_fmtp = switch_silk_fmtp_parse;
 	switch_core_codec_add_implementation(pool, codec_interface,
 										 SWITCH_CODEC_TYPE_AUDIO,	/* enumeration defining the type of the codec */
 										 117,						/* the IANA code number */
diff --git a/src/mod/codecs/mod_siren/mod_siren.c b/src/mod/codecs/mod_siren/mod_siren.c
index 1ccd36eafb..4646ffc5ae 100644
--- a/src/mod/codecs/mod_siren/mod_siren.c
+++ b/src/mod/codecs/mod_siren/mod_siren.c
@@ -47,6 +47,40 @@ struct siren_context {
 	g722_1_encode_state_t encoder_object;
 };
 
+static switch_status_t switch_siren_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
+{
+	if (codec_fmtp) {
+		int bit_rate = 0;
+		memset(codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
+		if (fmtp) {
+			int x, argc;
+			char *argv[10];
+			char *fmtp_dup = strdup(fmtp);
+
+			switch_assert(fmtp_dup);
+			argc = switch_separate_string(fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0])));
+			for (x = 0; x < argc; x++) {
+				char *data = argv[x];
+				char *arg;
+				switch_assert(data);
+				while (*data == ' ') {
+					data++;
+				}
+				if ((arg = strchr(data, '='))) {
+					*arg++ = '\0';
+					if (!strcasecmp(data, "bitrate")) {
+						bit_rate = atoi(arg);
+					}
+				}
+			}
+			free(fmtp_dup);
+		}
+		codec_fmtp->bits_per_second = bit_rate;
+		return SWITCH_STATUS_SUCCESS;
+	}
+	return SWITCH_STATUS_FALSE;
+}
+
 static switch_status_t switch_siren_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
 {
 	struct siren_context *context = NULL;
@@ -58,26 +92,6 @@ static switch_status_t switch_siren_init(switch_codec_t *codec, switch_codec_fla
 		return SWITCH_STATUS_FALSE;
 	}
 
-	if (codec->fmtp_in) {
-		int x, argc;
-		char *argv[10];
-		argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0])));
-		for (x = 0; x < argc; x++) {
-			char *data = argv[x];
-			char *arg;
-			switch_assert(data);
-			while (*data == ' ') {
-				data++;
-			}
-			if ((arg = strchr(data, '='))) {
-				*arg++ = '\0';
-				if (!strcasecmp(data, "bitrate")) {
-					bit_rate = atoi(arg);
-				}
-			}
-		}
-	}
-
 	codec->fmtp_out = switch_core_sprintf(codec->memory_pool, "bitrate=%d", bit_rate);
 
 	if (encoding) {
@@ -145,6 +159,28 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_siren_load)
 	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
 
 	SWITCH_ADD_CODEC(codec_interface, "Polycom(R) G722.1/G722.1C");
+	codec_interface->parse_fmtp = switch_siren_fmtp_parse;
+
+	spf = 320, bpf = 640;
+	for (count = 3; count > 0; count--) {
+		switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO,    /* enumeration defining the type of the codec */
+				107,   /* the IANA code number */
+				"G7221",       /* the IANA code name */
+				"bitrate=24000",       /* default fmtp to send (can be overridden by the init function) */
+				16000, /* samples transferred per second */
+				16000, /* actual samples transferred per second */
+				24000, /* bits transferred per second */
+				mpf * count,   /* number of microseconds per frame */
+				spf * count,   /* number of samples per frame */
+				bpf * count,   /* number of bytes per frame decompressed */
+				0,     /* number of bytes per frame compressed */
+				1,     /* number of channels represented */
+				1,     /* number of frames per network packet */
+				switch_siren_init,     /* function to initialize a codec handle using this implementation */
+				switch_siren_encode,   /* function to encode raw data into encoded data */
+				switch_siren_decode,   /* function to decode encoded data into raw data */
+				switch_siren_destroy); /* deinitalize a codec handle using this implementation */
+	}
 
 	spf = 320, bpf = 640;
 	for (count = 3; count > 0; count--) {
diff --git a/src/mod/codecs/mod_speex/mod_speex.c b/src/mod/codecs/mod_speex/mod_speex.c
index 1d4a0409b8..a951b12d84 100644
--- a/src/mod/codecs/mod_speex/mod_speex.c
+++ b/src/mod/codecs/mod_speex/mod_speex.c
@@ -37,7 +37,46 @@
 SWITCH_MODULE_LOAD_FUNCTION(mod_speex_load);
 SWITCH_MODULE_DEFINITION(mod_speex, mod_speex_load, NULL, NULL);
 
-static switch_codec_settings_t default_codec_settings = {
+/* nobody has more setting than speex so we will let them set the standard */
+/*! \brief Various codec settings (currently only relevant to speex) */
+struct speex_codec_settings {
+	/*! desired quality */
+	int quality;
+	/*! desired complexity */
+	int complexity;
+	/*! desired enhancement */
+	int enhancement;
+	/*! desired vad level */
+	int vad;
+	/*! desired vbr level */
+	int vbr;
+	/*! desired vbr quality */
+	float vbr_quality;
+	/*! desired abr level */
+	int abr;
+	/*! desired dtx setting */
+	int dtx;
+	/*! desired preprocessor settings */
+	int preproc;
+	/*! preprocessor vad settings */
+	int pp_vad;
+	/*! preprocessor gain control settings */
+	int pp_agc;
+	/*! preprocessor gain level */
+	float pp_agc_level;
+	/*! preprocessor denoise level */
+	int pp_denoise;
+	/*! preprocessor dereverb settings */
+	int pp_dereverb;
+	/*! preprocessor dereverb decay level */
+	float pp_dereverb_decay;
+	/*! preprocessor dereverb level */
+	float pp_dereverb_level;
+};
+
+typedef struct speex_codec_settings speex_codec_settings_t;
+
+static speex_codec_settings_t default_codec_settings = {
 	/*.quality */ 5,
 	/*.complexity */ 5,
 	/*.enhancement */ 1,
@@ -58,6 +97,7 @@ static switch_codec_settings_t default_codec_settings = {
 
 struct speex_context {
 	switch_codec_t *codec;
+	speex_codec_settings_t codec_settings; 
 	unsigned int flags;
 
 	/* Encoder */
@@ -74,6 +114,56 @@ struct speex_context {
 	int decoder_mode;
 };
 
+static switch_status_t switch_speex_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
+{
+	if (codec_fmtp) {
+		speex_codec_settings_t *codec_settings = NULL;
+		if (codec_fmtp->private_info) {
+			codec_settings = codec_fmtp->private_info;
+			memcpy(codec_settings, &default_codec_settings, sizeof(*codec_settings));
+		}
+
+		if (fmtp) {
+			int x, argc;
+			char *argv[10];
+			char *fmtp_dup = strdup(fmtp);
+
+			switch_assert(fmtp_dup);
+
+			argc = switch_separate_string(fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0])));
+
+			for (x = 0; x < argc; x++) {
+				char *data = argv[x];
+				char *arg;
+				switch_assert(data);
+				while (*data == ' ') {
+					data++;
+				}
+				if ((arg = strchr(data, '='))) {
+					*arg++ = '\0';
+					/*
+					   if (!strcasecmp(data, "bitrate")) {
+					   bit_rate = atoi(arg);
+					   }
+					 */
+					/*
+					   if (codec_settings) {
+					   if (!strcasecmp(data, "vad")) {
+					   bit_rate = atoi(arg);
+					   }
+					   }
+					 */			
+				}
+			}
+			free(fmtp_dup);
+		}
+		/*codec_fmtp->bits_per_second = bit_rate;*/
+		return SWITCH_STATUS_SUCCESS;
+	}
+	return SWITCH_STATUS_FALSE;
+}
+
+
 static switch_status_t switch_speex_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
 {
 	struct speex_context *context = NULL;
@@ -82,16 +172,18 @@ static switch_status_t switch_speex_init(switch_codec_t *codec, switch_codec_fla
 	encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
 	decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
 
-	if (!codec_settings) {
-		codec_settings = &default_codec_settings;
-	}
-
-	memcpy(&codec->codec_settings, codec_settings, sizeof(codec->codec_settings));
-
 	if (!(encoding || decoding) || ((context = switch_core_alloc(codec->memory_pool, sizeof(*context))) == 0)) {
 		return SWITCH_STATUS_FALSE;
 	} else {
 		const SpeexMode *mode = NULL;
+		switch_codec_fmtp_t codec_fmtp;
+		speex_codec_settings_t codec_settings;
+
+		memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
+		codec_fmtp.private_info = &codec_settings;
+		switch_speex_fmtp_parse(codec->fmtp_in, &codec_fmtp);
+
+		memcpy(&context->codec_settings, &codec_settings, sizeof(context->codec_settings));
 
 		context->codec = codec;
 		if (codec->implementation->actual_samples_per_second == 8000) {
@@ -110,41 +202,41 @@ static switch_status_t switch_speex_init(switch_codec_t *codec, switch_codec_fla
 			speex_bits_init(&context->encoder_bits);
 			context->encoder_state = speex_encoder_init(mode);
 			speex_encoder_ctl(context->encoder_state, SPEEX_GET_FRAME_SIZE, &context->encoder_frame_size);
-			speex_encoder_ctl(context->encoder_state, SPEEX_SET_COMPLEXITY, &codec->codec_settings.complexity);
-			if (codec->codec_settings.preproc) {
+			speex_encoder_ctl(context->encoder_state, SPEEX_SET_COMPLEXITY, &context->codec_settings.complexity);
+			if (context->codec_settings.preproc) {
 				context->pp = speex_preprocess_state_init(context->encoder_frame_size, codec->implementation->actual_samples_per_second);
-				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_VAD, &codec->codec_settings.pp_vad);
-				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC, &codec->codec_settings.pp_agc);
-				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &codec->codec_settings.pp_agc_level);
-				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DENOISE, &codec->codec_settings.pp_denoise);
-				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB, &codec->codec_settings.pp_dereverb);
-				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &codec->codec_settings.pp_dereverb_decay);
-				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &codec->codec_settings.pp_dereverb_level);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_VAD, &context->codec_settings.pp_vad);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC, &context->codec_settings.pp_agc);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &context->codec_settings.pp_agc_level);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DENOISE, &context->codec_settings.pp_denoise);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB, &context->codec_settings.pp_dereverb);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &context->codec_settings.pp_dereverb_decay);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &context->codec_settings.pp_dereverb_level);
 			}
 
-			if (!codec->codec_settings.abr && !codec->codec_settings.vbr) {
-				speex_encoder_ctl(context->encoder_state, SPEEX_SET_QUALITY, &codec->codec_settings.quality);
-				if (codec->codec_settings.vad) {
-					speex_encoder_ctl(context->encoder_state, SPEEX_SET_VAD, &codec->codec_settings.vad);
+			if (!context->codec_settings.abr && !context->codec_settings.vbr) {
+				speex_encoder_ctl(context->encoder_state, SPEEX_SET_QUALITY, &context->codec_settings.quality);
+				if (context->codec_settings.vad) {
+					speex_encoder_ctl(context->encoder_state, SPEEX_SET_VAD, &context->codec_settings.vad);
 				}
 			}
-			if (codec->codec_settings.vbr) {
-				speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR, &codec->codec_settings.vbr);
-				speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR_QUALITY, &codec->codec_settings.vbr_quality);
+			if (context->codec_settings.vbr) {
+				speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR, &context->codec_settings.vbr);
+				speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR_QUALITY, &context->codec_settings.vbr_quality);
 			}
-			if (codec->codec_settings.abr) {
-				speex_encoder_ctl(context->encoder_state, SPEEX_SET_ABR, &codec->codec_settings.abr);
+			if (context->codec_settings.abr) {
+				speex_encoder_ctl(context->encoder_state, SPEEX_SET_ABR, &context->codec_settings.abr);
 			}
-			if (codec->codec_settings.dtx) {
-				speex_encoder_ctl(context->encoder_state, SPEEX_SET_DTX, &codec->codec_settings.dtx);
+			if (context->codec_settings.dtx) {
+				speex_encoder_ctl(context->encoder_state, SPEEX_SET_DTX, &context->codec_settings.dtx);
 			}
 		}
 
 		if (decoding) {
 			speex_bits_init(&context->decoder_bits);
 			context->decoder_state = speex_decoder_init(mode);
-			if (codec->codec_settings.enhancement) {
-				speex_decoder_ctl(context->decoder_state, SPEEX_SET_ENH, &codec->codec_settings.enhancement);
+			if (context->codec_settings.enhancement) {
+				speex_decoder_ctl(context->decoder_state, SPEEX_SET_ENH, &context->codec_settings.enhancement);
 			}
 		}
 
@@ -178,7 +270,7 @@ static switch_status_t switch_speex_encode(switch_codec_t *codec,
 
 	if (is_speech) {
 		is_speech = speex_encode_int(context->encoder_state, buf, &context->encoder_bits)
-			|| !context->codec->codec_settings.dtx;
+			|| !context->codec_settings.dtx;
 	} else {
 		speex_bits_pack(&context->encoder_bits, 0, 5);
 	}
@@ -270,6 +362,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_speex_load)
 	/* connect my internal structure to the blank pointer passed to me */
 	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
 	SWITCH_ADD_CODEC(codec_interface, "Speex");
+	codec_interface->parse_fmtp = switch_speex_fmtp_parse;
 	for (counta = 1; counta <= 3; counta++) {
 		for (countb = 1; countb > 0; countb--) {
 			switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO,	/* enumeration defining the type of the codec */
diff --git a/src/mod/endpoints/mod_h323/changes.txt b/src/mod/endpoints/mod_h323/changes.txt
index ff47780118..19aca46dc8 100644
--- a/src/mod/endpoints/mod_h323/changes.txt
+++ b/src/mod/endpoints/mod_h323/changes.txt
@@ -1,3 +1,4 @@
+fix crashes on FSH323Connection calls in on_hangup routine in different threads.
 move PTrace level set to FSH323EndPoint::Initialise
 partially apply patch from from Peter Olsson, Remove UnLock() when TryLock() failed and DEBUG_RTP_PACKETS directive.
 apply changes from mod_h323-patch.diff by Peter Olsson.
diff --git a/src/mod/endpoints/mod_h323/mod_h323.cpp b/src/mod/endpoints/mod_h323/mod_h323.cpp
index aeee422ca5..142506dd92 100644
--- a/src/mod/endpoints/mod_h323/mod_h323.cpp
+++ b/src/mod/endpoints/mod_h323/mod_h323.cpp
@@ -24,7 +24,7 @@
  *
  * mod_h323.cpp -- H323 endpoint
  *
- *	Version 0.0.55
+ *	Version 0.0.56
 */
 
 //#define DEBUG_RTP_PACKETS
@@ -747,6 +747,17 @@ FSH323Connection::~FSH323Connection()
 //	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"------------->h323_mutex_unlock\n");
 }	
 
+void FSH323Connection::AttachSignalChannel(const PString & token,
+                                         H323Transport * channel,
+                                         PBoolean answeringCall)
+{
+	h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
+	tech_pvt->token = strdup((const char *)token);
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"---------->token = %s [%p]\n",(const char *)token,this);
+	H323Connection::AttachSignalChannel(token,channel,answeringCall);
+}
+
+
 void FSH323Connection::OnSetLocalCapabilities()
 {
 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"======>FSH323Connection::OnSetLocalCapabilities() [%p]\n",this);
@@ -2321,8 +2332,9 @@ static switch_status_t on_hangup(switch_core_session_t *session)
 	switch_channel_t *channel = switch_core_session_get_channel(session);
 	h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(session);
 	FSH323Connection *me = tech_pvt->me;
+	FSH323EndPoint & ep = h323_process->GetH323EndPoint();
 	tech_pvt->me = NULL;
-
+    
 	if (me) {
 		if (me->m_rtp_resetting == 1) {
 			switch_core_session_unlock_codec_read(session);
@@ -2340,12 +2352,12 @@ static switch_status_t on_hangup(switch_core_session_t *session)
 			me->CloseAllLogicalChannels(false);
 			me->Unlock();
 		}
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"----->%s\n",(const char *)(me->GetCallToken()));
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"----->%s\n",(const char *)(tech_pvt->token));
 		Q931::CauseValues cause = (Q931::CauseValues)switch_channel_get_cause_q850(channel);
 		int trylock = me->TryLock();
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"-----> () = %d\n",trylock);
 		if (trylock == 1) {
-			const PString currentToken(me->GetCallToken());
+			const PString currentToken(tech_pvt->token);
 			FSH323Connection *connection = (FSH323Connection *)me->GetEndPoint()->FindConnectionWithLock(currentToken); 
 			if (connection) {
 				connection->Unlock();
@@ -2356,8 +2368,10 @@ static switch_status_t on_hangup(switch_core_session_t *session)
 		} else if (trylock == -1) {
 			/* Failed to lock - just go on */
 		}
+		const PString currentToken(tech_pvt->token);
 		me->SetQ931Cause(cause);
-		me->ClearCallSynchronous(NULL, H323TranslateToCallEndReason(cause, UINT_MAX));
+//		me->ClearCallSynchronous(NULL, H323TranslateToCallEndReason(cause, UINT_MAX));
+		ep.ClearCall(currentToken, H323TranslateToCallEndReason(cause, UINT_MAX));
 //		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"------------->h323_mutex_lock\n");
 //		switch_mutex_lock(tech_pvt->h323_mutex);
 	}
diff --git a/src/mod/endpoints/mod_h323/mod_h323.h b/src/mod/endpoints/mod_h323/mod_h323.h
index 087540c509..8127206126 100644
--- a/src/mod/endpoints/mod_h323/mod_h323.h
+++ b/src/mod/endpoints/mod_h323/mod_h323.h
@@ -184,6 +184,7 @@ typedef struct {
 	switch_mutex_t *h323_io_mutex;
 
 	FSH323Connection *me;
+	char			*token;
 } h323_private_t;
 
 #define DECLARE_CALLBACK0(name)                           \
@@ -306,7 +307,11 @@ class FSH323Connection:public H323Connection {
 					 unsigned callReference, switch_caller_profile_t *outbound_profile,
 					 switch_core_session_t *fsSession, switch_channel_t *fsChannel);
 	~FSH323Connection();
-
+	virtual void AttachSignalChannel(
+      const PString & token,
+      H323Transport * channel,
+      PBoolean answeringCall
+    );
 	virtual H323Channel *CreateRealTimeLogicalChannel(const H323Capability & capability,
 							H323Channel::Directions dir,
 							unsigned sessionID, const H245_H2250LogicalChannelParameters * param, RTP_QOS * rtpqos = NULL);
diff --git a/src/mod/endpoints/mod_loopback/mod_loopback.c b/src/mod/endpoints/mod_loopback/mod_loopback.c
index 8275893be8..ab4db6a1b0 100644
--- a/src/mod/endpoints/mod_loopback/mod_loopback.c
+++ b/src/mod/endpoints/mod_loopback/mod_loopback.c
@@ -52,7 +52,8 @@ typedef enum {
 	TFLAG_BRIDGE = (1 << 4),
 	TFLAG_BOWOUT = (1 << 5),
 	TFLAG_BLEG = (1 << 6),
-	TFLAG_APP = (1 << 7)
+	TFLAG_APP = (1 << 7),
+	TFLAG_BOWOUT_USED = (1 << 8)
 } TFLAGS;
 
 struct private_object {
@@ -635,7 +636,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
 	tech_pvt = switch_core_session_get_private(session);
 	switch_assert(tech_pvt != NULL);
 
-	if (switch_test_flag(frame, SFF_CNG) || switch_test_flag(tech_pvt, TFLAG_CNG) || switch_test_flag(tech_pvt, TFLAG_BOWOUT)) {
+	if (switch_test_flag(frame, SFF_CNG) || switch_test_flag(tech_pvt, TFLAG_CNG) || (switch_test_flag(tech_pvt, TFLAG_BOWOUT) && switch_test_flag(tech_pvt, TFLAG_BOWOUT_USED))) {
 		return SWITCH_STATUS_SUCCESS;
 	}
 
@@ -662,6 +663,9 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
 			switch_clear_flag_locked(tech_pvt, TFLAG_WRITE);
 			switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE);
 
+			switch_set_flag_locked(tech_pvt, TFLAG_BOWOUT_USED);
+			switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_BOWOUT_USED);
+
 			if (a_uuid && b_uuid) {
 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
 								  "%s detected bridge on both ends, attempting direct connection.\n", switch_channel_get_name(channel));
diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c
index 165815078b..2df8937647 100644
--- a/src/mod/endpoints/mod_skinny/mod_skinny.c
+++ b/src/mod/endpoints/mod_skinny/mod_skinny.c
@@ -1343,19 +1343,6 @@ static switch_status_t kill_listener(listener_t *listener, void *pvt)
 	return SWITCH_STATUS_SUCCESS;
 }
 
-static switch_status_t kill_expired_listener(listener_t *listener, void *pvt)
-{
-	switch_event_t *event = NULL;
-
-	if(listener->expire_time < switch_epoch_time_now(NULL)) {
-		/* skinny::expire event */
-		skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_EXPIRE);
-		switch_event_fire(&event);
-		return kill_listener(listener, pvt);
-	}
-	return SWITCH_STATUS_SUCCESS;
-}
-
 switch_status_t keepalive_listener(listener_t *listener, void *pvt)
 {
 	skinny_profile_t *profile;
@@ -1414,6 +1401,13 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
 				case SWITCH_STATUS_TIMEOUT:
 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Communication Time Out with %s:%d.\n",
 						listener->remote_ip, listener->remote_port);
+
+					if(listener->expire_time < switch_epoch_time_now(NULL)) {
+						switch_event_t *event = NULL;
+						/* skinny::expire event */
+						skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_EXPIRE);
+						switch_event_fire(&event);
+					}
 					break;
 				default: 
 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Communication Error with %s:%d.\n",
@@ -1917,9 +1911,57 @@ static switch_status_t load_skinny_config(void)
 	return SWITCH_STATUS_SUCCESS;
 }
 
-static void skinny_heartbeat_event_handler(switch_event_t *event)
+static void skinny_user_to_device_event_handler(switch_event_t *event)
 {
-	walk_listeners(kill_expired_listener, NULL);
+	char *profile_name = switch_event_get_header_nil(event, "Skinny-Profile-Name");
+	skinny_profile_t *profile;
+
+	if ((profile = skinny_find_profile(profile_name))) {
+		char *device_name = switch_event_get_header_nil(event, "Skinny-Device-Name");
+		uint32_t device_instance = atoi(switch_event_get_header_nil(event, "Skinny-Station-Instance"));
+		listener_t *listener = NULL;
+		skinny_profile_find_listener_by_device_name_and_instance(profile, device_name, device_instance, &listener);
+		if(listener) {
+			uint32_t message_type = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Message-Id"));
+			uint32_t application_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Application-Id"));
+			uint32_t line_instance = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Line-Instance"));
+			uint32_t call_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Call-Id"));
+			uint32_t transaction_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Transaction-Id"));
+			uint32_t data_length = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Data-Length"));
+			uint32_t sequence_flag = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Sequence-Flag"));
+			uint32_t display_priority = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Display-Priority"));
+			uint32_t conference_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Conference-Id"));
+			uint32_t app_instance_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-App-Instance-Id"));
+			uint32_t routing_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Routing-Id"));
+			char *data = switch_event_get_body(event);
+			if (message_type == 0) {
+				message_type = skinny_str2message_type(switch_event_get_header_nil(event, "Skinny-UserToDevice-Message-Id-String"));
+			}
+			switch(message_type) {
+				case USER_TO_DEVICE_DATA_MESSAGE:
+					data_length = strlen(data); /* we ignore data_length sent */
+					send_data(listener, message_type,
+						application_id, line_instance, call_id, transaction_id, data_length,
+						data);
+				case USER_TO_DEVICE_DATA_VERSION1_MESSAGE:
+					data_length = strlen(data); /* we ignore data_length sent */
+					send_extended_data(listener, message_type,
+						application_id, line_instance, call_id, transaction_id, data_length,
+						sequence_flag, display_priority, conference_id, app_instance_id, routing_id,
+						data);
+					break;
+				default:
+					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+						"Incorrect message type %s (%d).\n", skinny_message_type2str(message_type), message_type);
+			}
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+				"Device %s:%d in profile '%s' not found.\n", device_name, device_instance, profile_name);
+		}
+	} else {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+			"Profile '%s' not found.\n", profile_name);
+	}
 }
 
 static void skinny_call_state_event_handler(switch_event_t *event)
@@ -2129,10 +2171,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load)
 		return SWITCH_STATUS_TERM;
 	}
 	/* bind to events */
-	if ((switch_event_bind_removable(modname, SWITCH_EVENT_HEARTBEAT, NULL, skinny_heartbeat_event_handler, NULL, &globals.heartbeat_node) != SWITCH_STATUS_SUCCESS)) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't bind our heartbeat handler!\n");
-		/* Not such severe to prevent loading */
-	}
 	if ((switch_event_bind_removable(modname, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_CALL_STATE, skinny_call_state_event_handler, NULL, &globals.call_state_node) != SWITCH_STATUS_SUCCESS)) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our call_state handler!\n");
 		return SWITCH_STATUS_TERM;
@@ -2145,6 +2183,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load)
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't bind our trap handler!\n");
 		/* Not such severe to prevent loading */
 	}
+	if ((switch_event_bind_removable(modname, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_USER_TO_DEVICE, skinny_user_to_device_event_handler, NULL, &globals.user_to_device_node) != SWITCH_STATUS_SUCCESS)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our user_to_device handler!\n");
+		/* Not such severe to prevent loading */
+	}
 
 	/* reserve events */
 	if (switch_event_reserve_subclass(SKINNY_EVENT_REGISTER) != SWITCH_STATUS_SUCCESS) {
@@ -2167,6 +2209,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load)
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_CALL_STATE);
 		return SWITCH_STATUS_TERM;
 	}
+	if (switch_event_reserve_subclass(SKINNY_EVENT_USER_TO_DEVICE) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_USER_TO_DEVICE);
+		return SWITCH_STATUS_TERM;
+	}
+	if (switch_event_reserve_subclass(SKINNY_EVENT_DEVICE_TO_USER) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_DEVICE_TO_USER);
+		return SWITCH_STATUS_TERM;
+	}
 
 	/* connect my internal structure to the blank pointer passed to me */
 	*module_interface = switch_loadable_module_create_module_interface(globals.pool, modname);
@@ -2205,7 +2255,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skinny_shutdown)
 	skinny_api_unregister();
 	
 	/* release events */
-	switch_event_unbind(&globals.heartbeat_node);
+	switch_event_unbind(&globals.user_to_device_node);
 	switch_event_unbind(&globals.call_state_node);
 	switch_event_unbind(&globals.message_waiting_node);
 	switch_event_unbind(&globals.trap_node);
@@ -2214,6 +2264,8 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skinny_shutdown)
 	switch_event_free_subclass(SKINNY_EVENT_EXPIRE);
 	switch_event_free_subclass(SKINNY_EVENT_ALARM);
 	switch_event_free_subclass(SKINNY_EVENT_CALL_STATE);
+	switch_event_free_subclass(SKINNY_EVENT_USER_TO_DEVICE);
+	switch_event_free_subclass(SKINNY_EVENT_DEVICE_TO_USER);
 
 	switch_mutex_lock(mutex);
 
diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h
index bbd318b746..b5cc96b7ae 100644
--- a/src/mod/endpoints/mod_skinny/mod_skinny.h
+++ b/src/mod/endpoints/mod_skinny/mod_skinny.h
@@ -43,13 +43,15 @@
 #define SKINNY_EVENT_EXPIRE "skinny::expire"
 #define SKINNY_EVENT_ALARM "skinny::alarm"
 #define SKINNY_EVENT_CALL_STATE "skinny::call_state"
+#define SKINNY_EVENT_USER_TO_DEVICE "skinny::user_to_device"
+#define SKINNY_EVENT_DEVICE_TO_USER "skinny::device_to_user"
 
 struct skinny_globals {
     int running;
     switch_memory_pool_t *pool;
     switch_mutex_t *mutex;
     switch_hash_t *profile_hash;
-    switch_event_node_t *heartbeat_node;
+    switch_event_node_t *user_to_device_node;
     switch_event_node_t *call_state_node;
     switch_event_node_t *message_waiting_node;
     switch_event_node_t *trap_node;
diff --git a/src/mod/endpoints/mod_skinny/skinny_api.c b/src/mod/endpoints/mod_skinny/skinny_api.c
index 90699d1ad2..7bbb27afd3 100644
--- a/src/mod/endpoints/mod_skinny/skinny_api.c
+++ b/src/mod/endpoints/mod_skinny/skinny_api.c
@@ -366,6 +366,62 @@ static switch_status_t skinny_api_cmd_profile_device_send_reset_message(const ch
     return SWITCH_STATUS_SUCCESS;
 }
 
+static switch_status_t skinny_api_cmd_profile_device_send_data(const char *profile_name, const char *device_name, const char *message_type, char *params, const char *body, switch_stream_handle_t *stream)
+{
+    skinny_profile_t *profile;
+
+    if ((profile = skinny_find_profile(profile_name))) {
+	    listener_t *listener = NULL;
+	    skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
+	    if(listener) {
+			switch_event_t *event = NULL;
+			char *argv[64] = { 0 };
+			int argc = 0;
+			int x = 0;
+			/* skinny::user_to_device event */
+			skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_USER_TO_DEVICE);
+			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Message-Id-String", "%s", message_type);
+			argc = switch_separate_string(params, ';', argv, (sizeof(argv) / sizeof(argv[0])));
+			for (x = 0; x < argc; x++) {
+				char *var_name, *var_value = NULL;
+				var_name = argv[x];
+				if (var_name && (var_value = strchr(var_name, '='))) {
+					*var_value++ = '\0';
+				}
+				if (zstr(var_name)) {
+					stream->write_function(stream, "-ERR No variable specified\n");
+				} else {
+					char *tmp = switch_mprintf("Skinny-UserToDevice-%s", var_name);
+					switch_event_add_header(event, SWITCH_STACK_BOTTOM, tmp, "%s", var_value);
+					switch_safe_free(tmp);
+					/*
+					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Application-Id", "%d", request->data.extended_data.application_id);
+					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Line-Instance", "%d", request->data.extended_data.line_instance);
+					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Call-Id", "%d", request->data.extended_data.call_id);
+					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Transaction-Id", "%d", request->data.extended_data.transaction_id);
+					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Data-Length", "%d", request->data.extended_data.data_length);
+					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Sequence-Flag", "%d", request->data.extended_data.sequence_flag);
+					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Display-Priority", "%d", request->data.extended_data.display_priority);
+					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Conference-Id", "%d", request->data.extended_data.conference_id);
+					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-App-Instance-Id", "%d", request->data.extended_data.app_instance_id);
+					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Routing-Id", "%d", request->data.extended_data.routing_id);
+					*/
+				}
+			}
+			switch_event_add_body(event, "%s", body);
+			switch_event_fire(&event);
+			stream->write_function(stream, "+OK\n");
+	    } else {
+		    stream->write_function(stream, "Listener not found!\n");
+	    }
+    } else {
+	    stream->write_function(stream, "Profile not found!\n");
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
 static switch_status_t skinny_api_cmd_profile_set(const char *profile_name, const char *name, const char *value, switch_stream_handle_t *stream)
 {
     skinny_profile_t *profile;
@@ -403,6 +459,7 @@ SWITCH_STANDARD_API(skinny_function)
 	    "skinny profile  device  send SetLampMessage   \n"
 	    "skinny profile  device  send SetSpeakerModeMessage \n"
 	    "skinny profile  device  send CallStateMessage   \n"
+	    "skinny profile  device  send  [ =;... ] \n"
 	    "skinny profile  set  \n"
 	    "--------------------------------------------------------------------------------\n";
     if (session) {
@@ -465,6 +522,16 @@ SWITCH_STANDARD_API(skinny_function)
 				    status = skinny_api_cmd_profile_device_send_reset_message(argv[1], argv[3], argv[6], stream);
 			    }
 			    break;
+			case USER_TO_DEVICE_DATA_MESSAGE:
+			case USER_TO_DEVICE_DATA_VERSION1_MESSAGE:
+			    if(argc == 8) {
+					/*  [ =;... ]  */
+					status = skinny_api_cmd_profile_device_send_data(argv[1], argv[3], argv[5], argv[6], argv[7], stream);
+			    } else if(argc == 7) {
+					/*   */
+					status = skinny_api_cmd_profile_device_send_data(argv[1], argv[3], argv[5], "", argv[6], stream);
+				}
+			    break;
 		    default:
 			    stream->write_function(stream, "Unhandled message %s\n", argv[5]);
 	    }
@@ -495,6 +562,8 @@ switch_status_t skinny_api_register(switch_loadable_module_interface_t **module_
     switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetLampMessage ::skinny::list_stimuli ::skinny::list_stimulus_instances ::skinny::list_stimulus_modes");
     switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetSpeakerModeMessage ::skinny::list_speaker_modes");
     switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send CallStateMessage ::skinny::list_call_states ::skinny::list_line_instances ::skinny::list_call_ids");
+    switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send UserToDeviceDataMessage");
+    switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send UserToDeviceDataVersion1Message");
     switch_console_set_complete("add skinny profile ::skinny::list_profiles set ::skinny::list_settings");
 
     switch_console_add_complete_func("::skinny::list_profiles", skinny_api_list_profiles);
diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c
index 1aea812574..743514d98c 100644
--- a/src/mod/endpoints/mod_skinny/skinny_protocol.c
+++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c
@@ -135,6 +135,10 @@ switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req)
 
 		status = switch_socket_recv(listener->sock, ptr, &mlen);
 
+		if (listener->expire_time && listener->expire_time < switch_epoch_time_now(NULL)) {
+			return SWITCH_STATUS_TIMEOUT;
+		}
+
 		if (!listener_is_ready(listener)) {
 			break;
 		}
@@ -898,6 +902,68 @@ switch_status_t send_reset(listener_t *listener, uint32_t reset_type)
 	return skinny_send_reply(listener, message);
 }
 
+switch_status_t send_data(listener_t *listener, uint32_t message_type,
+	uint32_t application_id,
+	uint32_t line_instance,
+	uint32_t call_id,
+	uint32_t transaction_id,
+	uint32_t data_length,
+	const char *data)
+{
+	skinny_message_t *message;
+	switch_assert(data_length == strlen(data));
+	/* data_length should be a multiple of 4 */
+	if ((data_length % 4) != 0) {
+		data_length = (data_length / 4 + 1) * 4;
+	}
+	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.data)+data_length-1);
+	message->type = message_type;
+	message->length = 4 + sizeof(message->data.data)+data_length-1;
+	message->data.data.application_id = application_id;
+	message->data.data.line_instance = line_instance;
+	message->data.data.call_id = call_id;
+	message->data.data.transaction_id = transaction_id;
+	message->data.data.data_length = data_length;
+	strncpy(message->data.data.data, data, data_length);
+	return skinny_send_reply(listener, message);
+}
+
+switch_status_t send_extended_data(listener_t *listener, uint32_t message_type,
+	uint32_t application_id,
+	uint32_t line_instance,
+	uint32_t call_id,
+	uint32_t transaction_id,
+	uint32_t data_length,
+	uint32_t sequence_flag,
+	uint32_t display_priority,
+	uint32_t conference_id,
+	uint32_t app_instance_id,
+	uint32_t routing_id,
+	const char *data)
+{
+	skinny_message_t *message;
+	switch_assert(data_length == strlen(data));
+	/* data_length should be a multiple of 4 */
+	if ((data_length % 4) != 0) {
+		data_length = (data_length / 4 + 1) * 4;
+	}
+	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.extended_data)+data_length-1);
+	message->type = message_type;
+	message->length = 4 + sizeof(message->data.extended_data)+data_length-1;
+	message->data.extended_data.application_id = application_id;
+	message->data.extended_data.line_instance = line_instance;
+	message->data.extended_data.call_id = call_id;
+	message->data.extended_data.transaction_id = transaction_id;
+	message->data.extended_data.data_length = data_length;
+	message->data.extended_data.sequence_flag = sequence_flag;
+	message->data.extended_data.display_priority = display_priority;
+	message->data.extended_data.conference_id = conference_id;
+	message->data.extended_data.app_instance_id = app_instance_id;
+	message->data.extended_data.routing_id = routing_id;
+	strncpy(message->data.extended_data.data, data, data_length);
+	return skinny_send_reply(listener, message);
+}
+
 switch_status_t skinny_perform_send_reply(listener_t *listener, const char *file, const char *func, int line, skinny_message_t *reply)
 {
 	char *ptr;
diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.h b/src/mod/endpoints/mod_skinny/skinny_protocol.h
index 236c667509..d85a190ba8 100644
--- a/src/mod/endpoints/mod_skinny/skinny_protocol.h
+++ b/src/mod/endpoints/mod_skinny/skinny_protocol.h
@@ -174,6 +174,21 @@ struct PACKED register_available_lines_message {
     uint32_t count;
 };
 
+/* DeviceToUserDataMessage */
+#define DEVICE_TO_USER_DATA_MESSAGE 0x002E
+struct PACKED data_message {
+	uint32_t application_id;
+	uint32_t line_instance;
+	uint32_t call_id;
+	uint32_t transaction_id;
+	uint32_t data_length;
+	char data[1];
+};
+
+/* DeviceToUserDataResponseMessage */
+#define DEVICE_TO_USER_DATA_RESPONSE_MESSAGE 0x002F
+/* See struct PACKED data_message */
+
 /* ServiceUrlStatReqMessage */
 #define SERVICE_URL_STAT_REQ_MESSAGE 0x0033
 struct PACKED service_url_stat_req_message {
@@ -186,6 +201,26 @@ struct PACKED feature_stat_req_message {
     uint32_t feature_index;
 };
 
+/* DeviceToUserDataVersion1Message */
+#define DEVICE_TO_USER_DATA_VERSION1_MESSAGE 0x0041
+struct PACKED extended_data_message {
+	uint32_t application_id;
+	uint32_t line_instance;
+	uint32_t call_id;
+	uint32_t transaction_id;
+	uint32_t data_length;
+	uint32_t sequence_flag;
+	uint32_t display_priority;
+	uint32_t conference_id;
+	uint32_t app_instance_id;
+	uint32_t routing_id;
+	char data[1];
+};
+
+/* DeviceToUserDataResponseVersion1Message */
+#define DEVICE_TO_USER_DATA_RESPONSE_VERSION1_MESSAGE 0x0042
+/* See struct PACKED extended_data_message */
+
 /* RegisterAckMessage */
 #define REGISTER_ACK_MESSAGE 0x0081
 struct PACKED register_ack_message {
@@ -479,6 +514,10 @@ struct PACKED dialed_number_message {
     uint32_t call_id;
 };
 
+/* UserToDeviceDataMessage */
+#define USER_TO_DEVICE_DATA_MESSAGE 0x011E
+/* See struct PACKED data_message */
+
 /* FeatureStatMessage */
 #define FEATURE_STAT_RES_MESSAGE 0x011F
 struct PACKED feature_stat_res_message {
@@ -504,6 +543,10 @@ struct PACKED service_url_stat_res_message {
     char display_name[40];
 };
 
+/* UserToDeviceDataVersion1Message */
+#define USER_TO_DEVICE_DATA_VERSION1_MESSAGE 0x013F
+/* See struct PACKED extended_data_message */
+
 /*****************************************************************************/
 /* SKINNY MESSAGE */
 /*****************************************************************************/
@@ -512,6 +555,7 @@ struct PACKED service_url_stat_res_message {
 #define SKINNY_MESSAGE_MAXSIZE 1000
 
 union skinny_data {
+	/* no data for KEEP_ALIVE_MESSAGE */
     struct register_message reg;
     struct port_message port;
     struct keypad_button_message keypad_button;
@@ -520,14 +564,25 @@ union skinny_data {
     struct on_hook_message on_hook;
     struct speed_dial_stat_req_message speed_dial_req;
     struct line_stat_req_message line_req;
+    /* no data for CONFIG_STAT_REQ_MESSAGE */
+    /* no data for TIME_DATE_REQ_MESSAGE */
+    /* no data for BUTTON_TEMPLATE_REQ_MESSAGE */
+    /* no data for VERSION_REQ_MESSAGE */
     struct capabilities_res_message cap_res;
     struct alarm_message alarm;
     struct open_receive_channel_ack_message open_receive_channel_ack;
+    /* no data for SOFT_KEY_SET_REQ_MESSAGE */
     struct soft_key_event_message soft_key_event;
-    struct service_url_stat_req_message service_url_req;
-    struct feature_stat_req_message feature_req;
+    /* no data for UNREGISTER_MESSAGE */
+    /* no data for SOFT_KEY_TEMPLATE_REQ_MESSAGE */
     struct headset_status_message headset_status;
     struct register_available_lines_message reg_lines;
+    /* see field "data" for DEVICE_TO_USER_DATA_MESSAGE */
+    /* see field "data" for DEVICE_TO_USER_DATA_RESPONSE_MESSAGE */
+    struct service_url_stat_req_message service_url_req;
+    struct feature_stat_req_message feature_req;
+    /* see field "extended_data" for DEVICE_TO_USER_DATA_VERSION1_MESSAGE */
+    /* see field "extended_data" for DEVICE_TO_USER_DATA_RESPONSE_VERSION1_MESSAGE */
     struct register_ack_message reg_ack;
     struct start_tone_message start_tone;
     struct stop_tone_message stop_tone;
@@ -543,8 +598,10 @@ union skinny_data {
     struct define_time_date_message define_time_date;
     struct button_template_message button_template;
     struct version_message version;
+    /* no data for CAPABILITIES_REQ_MESSAGE */
     struct register_reject_message reg_rej;
     struct reset_message reset;
+    /* no data for KEEP_ALIVE_ACK_MESSAGE */
     struct open_receive_channel_message open_receive_channel;
     struct close_receive_channel_message close_receive_channel;
     struct soft_key_template_res_message soft_key_template;
@@ -557,9 +614,14 @@ union skinny_data {
     struct unregister_ack_message unregister_ack;
     struct back_space_req_message back_space_req;
     struct dialed_number_message dialed_number;
+    /* see field "data" for USER_TO_DEVICE_DATA_MESSAGE */
     struct feature_stat_res_message feature_res;
     struct display_pri_notify_message display_pri_notify;
     struct service_url_stat_res_message service_url_res;
+    /* see field "extended_data" for USER_TO_DEVICE_DATA_VERSION1_MESSAGE */
+
+	struct data_message data;
+	struct extended_data_message extended_data;
 
     uint16_t as_uint16;
     char as_char;
@@ -777,6 +839,27 @@ switch_status_t send_display_pri_notify(listener_t *listener,
 switch_status_t send_reset(listener_t *listener,
     uint32_t reset_type);
 
+switch_status_t send_data(listener_t *listener, uint32_t message_type,
+	uint32_t application_id,
+	uint32_t line_instance,
+	uint32_t call_id,
+	uint32_t transaction_id,
+	uint32_t data_length,
+	const char *data);
+
+switch_status_t send_extended_data(listener_t *listener, uint32_t message_type,
+	uint32_t application_id,
+	uint32_t line_instance,
+	uint32_t call_id,
+	uint32_t transaction_id,
+	uint32_t data_length,
+	uint32_t sequence_flag,
+	uint32_t display_priority,
+	uint32_t conference_id,
+	uint32_t app_instance_id,
+	uint32_t routing_id,
+	const char *data);
+
 #endif /* _SKINNY_PROTOCOL_H */
 
 /* For Emacs:
diff --git a/src/mod/endpoints/mod_skinny/skinny_server.c b/src/mod/endpoints/mod_skinny/skinny_server.c
index 3fa4aab6c4..cfafea6f01 100644
--- a/src/mod/endpoints/mod_skinny/skinny_server.c
+++ b/src/mod/endpoints/mod_skinny/skinny_server.c
@@ -1864,6 +1864,33 @@ switch_status_t skinny_handle_register_available_lines_message(listener_t *liste
 	return SWITCH_STATUS_SUCCESS;
 }
 
+switch_status_t skinny_handle_data_message(listener_t *listener, skinny_message_t *request)
+{
+	switch_event_t *event = NULL;
+	char *tmp = NULL;
+	skinny_check_data_length(request, sizeof(request->data.data));
+	skinny_check_data_length(request, sizeof(request->data.data) + request->data.data.data_length - 1);
+
+	/* skinny::device_to_user event */
+	skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_DEVICE_TO_USER);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Message-Id", "%d", request->type);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Message-Id-String", "%s", skinny_message_type2str(request->type));
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Application-Id", "%d", request->data.data.application_id);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Line-Instance", "%d", request->data.data.line_instance);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Call-Id", "%d", request->data.data.call_id);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Transaction-Id", "%d", request->data.data.transaction_id);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Data-Length", "%d", request->data.data.data_length);
+	/* Ensure that the body is null-terminated */
+	tmp = malloc(request->data.data.data_length + 1);
+	memcpy(tmp, request->data.data.data, request->data.data.data_length);
+	tmp[request->data.data.data_length] = '\0';
+	switch_event_add_body(event, "%s", tmp);
+	switch_safe_free(tmp);
+	switch_event_fire(&event);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
 switch_status_t skinny_handle_service_url_stat_request(listener_t *listener, skinny_message_t *request)
 {
 	skinny_message_t *message;
@@ -1904,6 +1931,38 @@ switch_status_t skinny_handle_feature_stat_request(listener_t *listener, skinny_
 	return SWITCH_STATUS_SUCCESS;
 }
 
+switch_status_t skinny_handle_extended_data_message(listener_t *listener, skinny_message_t *request)
+{
+	switch_event_t *event = NULL;
+	char *tmp = NULL;
+	skinny_check_data_length(request, sizeof(request->data.extended_data));
+	skinny_check_data_length(request, sizeof(request->data.extended_data)+request->data.extended_data.data_length-1);
+
+	/* skinny::device_to_user event */
+	skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_DEVICE_TO_USER);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Message-Id", "%d", request->type);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Message-Id-String", "%s", skinny_message_type2str(request->type));
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Application-Id", "%d", request->data.extended_data.application_id);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Line-Instance", "%d", request->data.extended_data.line_instance);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Call-Id", "%d", request->data.extended_data.call_id);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Transaction-Id", "%d", request->data.extended_data.transaction_id);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Data-Length", "%d", request->data.extended_data.data_length);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Sequence-Flag", "%d", request->data.extended_data.sequence_flag);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Display-Priority", "%d", request->data.extended_data.display_priority);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Conference-Id", "%d", request->data.extended_data.conference_id);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-App-Instance-Id", "%d", request->data.extended_data.app_instance_id);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-DeviceToUser-Routing-Id", "%d", request->data.extended_data.routing_id);
+	/* Ensure that the body is null-terminated */
+	tmp = malloc(request->data.data.data_length + 1);
+	memcpy(tmp, request->data.data.data, request->data.data.data_length);
+	tmp[request->data.data.data_length] = '\0';
+	switch_event_add_body(event, "%s", tmp);
+	switch_safe_free(tmp);
+	switch_event_fire(&event);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
 switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *request)
 {
 	if (listener->profile->debug >= 10 || request->type != KEEP_ALIVE_MESSAGE) {
@@ -1961,10 +2020,18 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re
 			return skinny_headset_status_message(listener, request);
 		case REGISTER_AVAILABLE_LINES_MESSAGE:
 			return skinny_handle_register_available_lines_message(listener, request);
+		case DEVICE_TO_USER_DATA_MESSAGE:
+			return skinny_handle_data_message(listener, request);
+		case DEVICE_TO_USER_DATA_RESPONSE_MESSAGE:
+			return skinny_handle_data_message(listener, request);
 		case SERVICE_URL_STAT_REQ_MESSAGE:
 			return skinny_handle_service_url_stat_request(listener, request);
 		case FEATURE_STAT_REQ_MESSAGE:
 			return skinny_handle_feature_stat_request(listener, request);
+		case DEVICE_TO_USER_DATA_VERSION1_MESSAGE:
+			return skinny_handle_extended_data_message(listener, request);
+		case DEVICE_TO_USER_DATA_RESPONSE_VERSION1_MESSAGE:
+			return skinny_handle_extended_data_message(listener, request);
 		default:
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
 				"Unhandled request %s (type=%x,length=%d).\n", skinny_message_type2str(request->type), request->type, request->length);
diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.c b/src/mod/endpoints/mod_skinny/skinny_tables.c
index 43b2290560..0a27ad76c4 100644
--- a/src/mod/endpoints/mod_skinny/skinny_tables.c
+++ b/src/mod/endpoints/mod_skinny/skinny_tables.c
@@ -55,10 +55,14 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = {
     {"SoftKeyEventMessage", SOFT_KEY_EVENT_MESSAGE},
     {"UnregisterMessage", UNREGISTER_MESSAGE},
     {"SoftKeyTemplateReqMessage", SOFT_KEY_TEMPLATE_REQ_MESSAGE},
-    {"ServiceUrlStatReqMessage", SERVICE_URL_STAT_REQ_MESSAGE},
-    {"FeatureStatReqMessage", FEATURE_STAT_REQ_MESSAGE},
     {"HeadsetStatusMessage", HEADSET_STATUS_MESSAGE},
     {"RegisterAvailableLinesMessage", REGISTER_AVAILABLE_LINES_MESSAGE},
+    {"DeviceToUserDataMessage", DEVICE_TO_USER_DATA_MESSAGE},
+    {"DeviceToUserDataResponseMessage", DEVICE_TO_USER_DATA_RESPONSE_MESSAGE},
+    {"ServiceUrlStatReqMessage", SERVICE_URL_STAT_REQ_MESSAGE},
+    {"FeatureStatReqMessage", FEATURE_STAT_REQ_MESSAGE},
+    {"DeviceToUserDataVersion1Message", DEVICE_TO_USER_DATA_VERSION1_MESSAGE},
+    {"DeviceToUserDataResponseVersion1Message", DEVICE_TO_USER_DATA_RESPONSE_VERSION1_MESSAGE},
     {"RegisterAckMessage", REGISTER_ACK_MESSAGE},
     {"StartToneMessage", START_TONE_MESSAGE},
     {"StopToneMessage", STOP_TONE_MESSAGE},
@@ -90,9 +94,11 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = {
     {"UnregisterAckMessage", UNREGISTER_ACK_MESSAGE},
     {"BackSpaceReqMessage", BACK_SPACE_REQ_MESSAGE},
     {"DialedNumberMessage", DIALED_NUMBER_MESSAGE},
+    {"UserToDeviceDataMessage", USER_TO_DEVICE_DATA_MESSAGE},
     {"FeatureResMessage", FEATURE_STAT_RES_MESSAGE},
     {"DisplayPriNotifyMessage", DISPLAY_PRI_NOTIFY_MESSAGE},
     {"ServiceUrlStatMessage", SERVICE_URL_STAT_RES_MESSAGE},
+    {"UserToDeviceDataVersion1Message", USER_TO_DEVICE_DATA_VERSION1_MESSAGE},
     {NULL, 0}
 };
 SKINNY_DECLARE_ID2STR(skinny_message_type2str, SKINNY_MESSAGE_TYPES, "UnknownMessage")
diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.h b/src/mod/endpoints/mod_skinny/skinny_tables.h
index 1747360264..14962b8b78 100644
--- a/src/mod/endpoints/mod_skinny/skinny_tables.h
+++ b/src/mod/endpoints/mod_skinny/skinny_tables.h
@@ -87,7 +87,7 @@ uint32_t func(const char *str)\
     }
 
 
-extern struct skinny_table SKINNY_MESSAGE_TYPES[59];
+extern struct skinny_table SKINNY_MESSAGE_TYPES[65];
 const char *skinny_message_type2str(uint32_t id);
 uint32_t skinny_str2message_type(const char *str);
 #define SKINNY_PUSH_MESSAGE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_MESSAGE_TYPES)
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c
index 19a44f43e1..7e92decfb1 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.c
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.c
@@ -85,6 +85,10 @@ static switch_status_t sofia_on_init(switch_core_session_t *session)
 		sofia_glue_tech_absorb_sdp(tech_pvt);
 	}
 
+	if (sofia_test_flag(tech_pvt, TFLAG_RECOVERING) || sofia_test_flag(tech_pvt, TFLAG_RECOVERING_BRIDGE)) {
+		sofia_set_flag(tech_pvt, TFLAG_RECOVERED);
+	}
+
 	if (sofia_test_flag(tech_pvt, TFLAG_OUTBOUND) || sofia_test_flag(tech_pvt, TFLAG_RECOVERING)) {
 		const char *var;
 
@@ -717,6 +721,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
 						TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)),
 						TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
 						NUTAG_SESSION_TIMER(session_timeout),
+						TAG_IF(session_timeout, NUTAG_SESSION_REFRESHER(nua_remote_refresher)),
 						SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
 						SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")),
 						SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
@@ -732,6 +737,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
 						TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)),
 						TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
 						NUTAG_SESSION_TIMER(session_timeout),
+						TAG_IF(session_timeout, NUTAG_SESSION_REFRESHER(nua_remote_refresher)),
 						SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
 						SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")),
 						SIPTAG_CONTENT_TYPE_STR("application/sdp"),
@@ -1232,7 +1238,12 @@ static void start_udptl(private_object_t *tech_pvt, switch_t38_options_t *t38_op
 
 		switch_rtp_udptl_mode(tech_pvt->rtp_session);
 
-		if (remote_host && remote_port && !strcmp(remote_host, t38_options->remote_ip) && remote_port == t38_options->remote_port) {
+		if (!t38_options || !t38_options->remote_ip) {
+			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "No remote address\n");
+			return;
+		}
+
+		if (remote_host && remote_port && remote_port == t38_options->remote_port && !strcmp(remote_host, t38_options->remote_ip)) {
 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Remote address:port [%s:%d] has not changed.\n",
 							  t38_options->remote_ip, t38_options->remote_port);
 			return;
@@ -1471,12 +1482,11 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
 	switch (msg->message_id) {
 	case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ:
 		{
-			const char *pl =
-				"\r\n"
-				" \r\n"
-				"  \r\n"
-				"   \r\n"
-				"    \r\n" "    \r\n" "   \r\n" "  \r\n" " \r\n";
+			const char *pl = "";
+
+			if (!zstr(msg->string_arg)) {
+				pl = msg->string_arg;
+			}
 
 			nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("application/media_control+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END());
 
@@ -1765,7 +1775,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
 							nua_update(tech_pvt->nh,
 									   TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)),
 									   TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END());
-						} else if ((ua && (switch_stristr("cisco", ua)))) {
+						} else if (0 && (ua && (switch_stristr("cisco", ua)))) {
                                                         snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" ", name, number, tech_pvt->profile->sipip);
 
                                                         sofia_set_flag_locked(tech_pvt, TFLAG_UPDATING_DISPLAY);
@@ -2005,6 +2015,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
 							switch_t38_options_t *t38_options = switch_channel_get_private(tech_pvt->channel, "t38_options");
 							if (t38_options) {
 								sofia_glue_set_image_sdp(tech_pvt, t38_options, 0);
+								if (switch_rtp_ready(tech_pvt->rtp_session)) {
+									switch_rtp_udptl_mode(tech_pvt->rtp_session);
+								}
 							}
 						} else {
 							sofia_glue_tech_set_local_sdp(tech_pvt, sdp, SWITCH_TRUE);
@@ -2090,6 +2103,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
 		break;
 	case SWITCH_MESSAGE_INDICATE_ANSWER:
 		status = sofia_answer_channel(session);
+		if (switch_channel_test_flag(tech_pvt->channel, CF_VIDEO)) {
+			sofia_glue_build_vid_refresh_message(session, NULL);
+		}
 		break;
 	case SWITCH_MESSAGE_INDICATE_PROGRESS:
 		{
@@ -2315,7 +2331,7 @@ static int show_reg_callback(void *pArg, int argc, char **argv, char **columnNam
 		switch_time_t etime = atoi(argv[6]);
 		switch_size_t retsize;
 
-		exp_secs = etime - now;
+		exp_secs = (int)(etime - now);
 		switch_time_exp_lt(&tm, switch_time_from_sec(etime));
 		switch_strftime_nocheck(exp_buf, &retsize, sizeof(exp_buf), "%Y-%m-%d %T", &tm);
 	}
@@ -2355,7 +2371,7 @@ static int show_reg_callback_xml(void *pArg, int argc, char **argv, char **colum
 		switch_time_t etime = atoi(argv[6]);
 		switch_size_t retsize;
 
-		exp_secs = etime - now;
+		exp_secs = (int)(etime - now);
 		switch_time_exp_lt(&tm, switch_time_from_sec(etime));
 		switch_strftime_nocheck(exp_buf, &retsize, sizeof(exp_buf), "%Y-%m-%d %T", &tm);
 	}
@@ -2422,7 +2438,7 @@ static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t
 							ob_failed += gp->ob_failed_calls;
 							ob += gp->ob_calls;
 
-							stream->write_function(stream, "%25s\t%32s\t%s\t%ld/%ld\t%ld/%ld",
+							stream->write_function(stream, "%25s\t%32s\t%s\t%u/%u\t%u/%u",
 												   pkey, gp->register_to, sofia_state_names[gp->state],
 												   gp->ib_failed_calls, gp->ib_calls, gp->ob_failed_calls, gp->ob_calls);
 
@@ -2441,8 +2457,8 @@ static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t
 			}
 			switch_mutex_unlock(mod_sofia_globals.hash_mutex);
 			stream->write_function(stream, "%s\n", line);
-			stream->write_function(stream, "%d gateway%s: Inound(Failed/Total): %ld/%ld,"
-								   "Outbound(Failed/Total):%ld/%ld\n", c, c == 1 ? "" : "s", ib_failed, ib, ob_failed, ob);
+			stream->write_function(stream, "%d gateway%s: Inbound(Failed/Total): %u/%u,"
+								   "Outbound(Failed/Total):%u/%u\n", c, c == 1 ? "" : "s", ib_failed, ib, ob_failed, ob);
 
 			return SWITCH_STATUS_SUCCESS;
 		}
@@ -2471,10 +2487,10 @@ static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t
 				stream->write_function(stream, "PingState\t%d/%d/%d\n", gp->ping_min, gp->ping_count, gp->ping_max);
 				stream->write_function(stream, "State   \t%s\n", sofia_state_names[gp->state]);
 				stream->write_function(stream, "Status  \t%s%s\n", status_names[gp->status], gp->pinging ? " (ping)" : "");
-				stream->write_function(stream, "CallsIN \t%d\n", gp->ib_calls);
-				stream->write_function(stream, "CallsOUT\t%d\n", gp->ob_calls);
-				stream->write_function(stream, "FailedCallsIN\t%d\n", gp->ib_failed_calls);
-				stream->write_function(stream, "FailedCallsOUT\t%d\n", gp->ob_failed_calls);
+				stream->write_function(stream, "CallsIN \t%u\n", gp->ib_calls);
+				stream->write_function(stream, "CallsOUT\t%u\n", gp->ob_calls);
+				stream->write_function(stream, "FailedCallsIN\t%u\n", gp->ib_failed_calls);
+				stream->write_function(stream, "FailedCallsOUT\t%u\n", gp->ob_failed_calls);
 				stream->write_function(stream, "%s\n", line);
 				sofia_reg_release_gateway(gp);
 			} else {
@@ -2483,7 +2499,7 @@ static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t
 		} else if (!strcasecmp(argv[0], "profile")) {
 			struct cb_helper cb;
 			char *sql = NULL;
-			int x = 0;
+			uint32_t x = 0;
 
 			cb.row_process = 0;
 
@@ -2548,10 +2564,10 @@ static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t
 					if (profile->max_registrations_perext > 0) {
 						stream->write_function(stream, "MAX-REG-PEREXT   \t%d\n", profile->max_registrations_perext);
 					}
-					stream->write_function(stream, "CALLS-IN         \t%d\n", profile->ib_calls);
-					stream->write_function(stream, "FAILED-CALLS-IN  \t%d\n", profile->ib_failed_calls);
-					stream->write_function(stream, "CALLS-OUT        \t%d\n", profile->ob_calls);
-					stream->write_function(stream, "FAILED-CALLS-OUT \t%d\n", profile->ob_failed_calls);
+					stream->write_function(stream, "CALLS-IN         \t%u\n", profile->ib_calls);
+					stream->write_function(stream, "FAILED-CALLS-IN  \t%u\n", profile->ib_failed_calls);
+					stream->write_function(stream, "CALLS-OUT        \t%u\n", profile->ob_calls);
+					stream->write_function(stream, "FAILED-CALLS-OUT \t%u\n", profile->ob_failed_calls);
 				}
 				stream->write_function(stream, "\nRegistrations:\n%s\n", line);
 
@@ -2697,10 +2713,10 @@ static void xml_gateway_status(sofia_gateway_t *gp, switch_stream_handle_t *stre
 	stream->write_function(stream, "    %d\n", gp->ping_freq);
 	stream->write_function(stream, "    %s\n", sofia_state_names[gp->state]);
 	stream->write_function(stream, "    %s%s\n", status_names[gp->status], gp->pinging ? " (ping)" : "");
-	stream->write_function(stream, "    %d\n", gp->ib_calls);
-	stream->write_function(stream, "    %d\n", gp->ob_calls);
-	stream->write_function(stream, "    %d\n", gp->ib_failed_calls);
-	stream->write_function(stream, "    %d\n", gp->ob_failed_calls);
+	stream->write_function(stream, "    %u\n", gp->ib_calls);
+	stream->write_function(stream, "    %u\n", gp->ob_calls);
+	stream->write_function(stream, "    %u\n", gp->ib_failed_calls);
+	stream->write_function(stream, "    %u\n", gp->ob_failed_calls);
 
 	if (gp->state == REG_STATE_FAILED || gp->state == REG_STATE_TRYING) {
 		time_t now = switch_epoch_time_now(NULL);
@@ -2763,7 +2779,7 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl
 		} else if (!strcasecmp(argv[0], "profile")) {
 			struct cb_helper cb;
 			char *sql = NULL;
-			int x = 0;
+			uint32_t x = 0;
 
 			cb.row_process = 0;
 
@@ -2819,10 +2835,10 @@ static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handl
 					stream->write_function(stream, "    %s\n", switch_str_nil(profile->user_agent_filter));
 					stream->write_function(stream, "    %d\n",
 										   profile->max_registrations_perext);
-					stream->write_function(stream, "    %d\n", profile->ib_calls);
-					stream->write_function(stream, "    %d\n", profile->ob_calls);
-					stream->write_function(stream, "    %d\n", profile->ib_failed_calls);
-					stream->write_function(stream, "    %d\n", profile->ob_failed_calls);
+					stream->write_function(stream, "    %u\n", profile->ib_calls);
+					stream->write_function(stream, "    %u\n", profile->ob_calls);
+					stream->write_function(stream, "    %u\n", profile->ib_failed_calls);
+					stream->write_function(stream, "    %u\n", profile->ob_failed_calls);
 					stream->write_function(stream, "  \n");
 				}
 				stream->write_function(stream, "  \n");
@@ -2951,7 +2967,6 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t
 	sofia_profile_t *profile = NULL;
 	char *profile_name = argv[0];
 	const char *err;
-	switch_xml_t xml_root;
 
 	if (argc < 2) {
 		stream->write_function(stream, "Invalid Args!\n");
@@ -2959,12 +2974,10 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t
 	}
 
 	if (!strcasecmp(argv[1], "start")) {
-		if (argc > 2 && !strcasecmp(argv[2], "reloadxml")) {
-			if ((xml_root = switch_xml_open_root(1, &err))) {
-				switch_xml_free(xml_root);
-			}
-			stream->write_function(stream, "Reload XML [%s]\n", err);
-		}
+
+		switch_xml_reload(&err);
+		stream->write_function(stream, "Reload XML [%s]\n", err);
+
 		if (config_sofia(1, argv[0]) == SWITCH_STATUS_SUCCESS) {
 			stream->write_function(stream, "%s started successfully\n", argv[0]);
 		} else {
@@ -3039,12 +3052,8 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t
 
 	if (!strcasecmp(argv[1], "rescan")) {
 
-		if (argc > 2 && !strcasecmp(argv[2], "reloadxml")) {
-			if ((xml_root = switch_xml_open_root(1, &err))) {
-				switch_xml_free(xml_root);
-			}
-			stream->write_function(stream, "Reload XML [%s]\n", err);
-		}
+		switch_xml_reload(&err);
+		stream->write_function(stream, "Reload XML [%s]\n", err);
 
 		if (reconfig_sofia(profile) == SWITCH_STATUS_SUCCESS) {
 			stream->write_function(stream, "+OK scan complete\n");
@@ -3141,12 +3150,8 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t
 								   profile->name, rsec, remain, remain == 1 ? "" : "s");
 		} else {
 
-			if (argc > 2 && !strcasecmp(argv[2], "reloadxml")) {
-				if ((xml_root = switch_xml_open_root(1, &err))) {
-					switch_xml_free(xml_root);
-				}
-				stream->write_function(stream, "Reload XML [%s]\n", err);
-			}
+			switch_xml_reload(&err);
+			stream->write_function(stream, "Reload XML [%s]\n", err);
 
 			if (!strcasecmp(argv[1], "stop")) {
 				sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
@@ -3171,6 +3176,21 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t
 		goto done;
 	}
 
+
+	if (!strcasecmp(argv[1], "gwlist")) {
+		int up = 1;
+		
+		if (argc > 2) {
+			if (!strcasecmp(argv[2], "down")) {
+				up = 0;
+			}
+		}
+
+		sofia_glue_gateway_list(profile, stream, up);
+		goto done;
+	}
+
+
 	stream->write_function(stream, "-ERR Unknown command!\n");
 
   done:
@@ -3487,7 +3507,7 @@ SWITCH_STANDARD_API(sofia_function)
 	const char *usage_string = "USAGE:\n"
 		"--------------------------------------------------------------------------------\n"
 		"sofia help\n"
-		"sofia profile  [[start|stop|restart|rescan] [reloadxml]|"
+		"sofia profile  [[start|stop|restart|rescan]|"
 		"flush_inbound_reg [] [reboot]|"
 		"[register|unregister] [|all]|"
 		"killgw |"
@@ -3497,6 +3517,7 @@ SWITCH_STANDARD_API(sofia_function)
 		"sofia status|xmlstatus gateway \n"
 		"sofia loglevel  [0-9]\n"
 		"sofia tracelevel \n"
+		"sofa global siptrace [on|off]\n"
 		"--------------------------------------------------------------------------------\n";
 
 	if (session) {
@@ -3552,6 +3573,26 @@ SWITCH_STANDARD_API(sofia_function)
 	} else if (!strcasecmp(argv[0], "help")) {
 		stream->write_function(stream, "%s", usage_string);
 		goto done;
+	} else if (!strcasecmp(argv[0], "global")) {
+		int on = -1;
+
+		if (argc > 1) {
+			if (!strcasecmp(argv[1], "siptrace")) {
+				if (argc > 2) {
+					on = switch_true(argv[2]);
+				}
+			}
+		}
+
+		if (on != -1) {
+			sofia_glue_global_siptrace(on);
+			stream->write_function(stream, "+OK Global siptrace %s", on ? "on" : "off");
+		} else {
+			stream->write_function(stream, "-ERR Usage: siptrace on|off");
+		}
+		
+		goto done;
+
 	} else if (!strcasecmp(argv[0], "recover")) {
 		if (argv[1] && !strcasecmp(argv[1], "flush")) {
 			sofia_glue_recover(SWITCH_TRUE);
@@ -4353,7 +4394,8 @@ static void general_event_handler(switch_event_t *event)
 				switch_mutex_lock(mod_sofia_globals.hash_mutex);
 				if (mod_sofia_globals.profile_hash) {
 					for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
-						int rb = 0, x = 0;
+						int rb = 0;
+						uint32_t x = 0;
 						switch_hash_this(hi, &var, NULL, &val);
 						if ((profile = (sofia_profile_t *) val) && profile->auto_restart) {
 							if (!strcmp(profile->sipip, old_ip4)) {
@@ -4623,15 +4665,19 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
 	switch_console_set_complete("add sofia help");
 	switch_console_set_complete("add sofia status");
 	switch_console_set_complete("add sofia xmlstatus");
-	switch_console_set_complete("add sofia loglevel");
-	switch_console_set_complete("add sofia tracelevel");
+
+	switch_console_set_complete("add sofia loglevel ::[all:default:tport:iptsec:nea:nta:nth_client:nth_server:nua:soa:sresolv:stun ::[0:1:2:3:4:5:6:7:8:9");
+	switch_console_set_complete("add sofia tracelevel ::[console:alert:crit:err:warning:notice:info:debug");
+
+	switch_console_set_complete("add sofia global siptrace ::[on:off");
+
 	switch_console_set_complete("add sofia profile");
 	switch_console_set_complete("add sofia profile restart all");
 
-	switch_console_set_complete("add sofia profile ::sofia::list_profiles start reloadxml");
-	switch_console_set_complete("add sofia profile ::sofia::list_profiles stop reloadxml");
-	switch_console_set_complete("add sofia profile ::sofia::list_profiles rescan reloadxml");
-	switch_console_set_complete("add sofia profile ::sofia::list_profiles restart reloadxml");
+	switch_console_set_complete("add sofia profile ::sofia::list_profiles start");
+	switch_console_set_complete("add sofia profile ::sofia::list_profiles stop");
+	switch_console_set_complete("add sofia profile ::sofia::list_profiles rescan");
+	switch_console_set_complete("add sofia profile ::sofia::list_profiles restart");
 
 	switch_console_set_complete("add sofia profile ::sofia::list_profiles flush_inbound_reg");
 	switch_console_set_complete("add sofia profile ::sofia::list_profiles register ::sofia::list_profile_gateway");
@@ -4640,6 +4686,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
 	switch_console_set_complete("add sofia profile ::sofia::list_profiles siptrace on");
 	switch_console_set_complete("add sofia profile ::sofia::list_profiles siptrace off");
 
+	switch_console_set_complete("add sofia profile ::sofia::list_profiles gwlist up");
+	switch_console_set_complete("add sofia profile ::sofia::list_profiles gwlist down");
+
 	switch_console_set_complete("add sofia status profile ::sofia::list_profiles");
 	switch_console_set_complete("add sofia status profile ::sofia::list_profiles reg");
 	switch_console_set_complete("add sofia status gateway ::sofia::list_gateways");
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h
index aa2149503a..5674046074 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.h
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.h
@@ -106,6 +106,7 @@ typedef struct private_object private_object_t;
 #define SOFIA_CRYPTO_MANDATORY_VARIABLE "sip_crypto_mandatory"
 #define FREESWITCH_SUPPORT "update_display"
 
+#include 
 #include 
 #include 
 #include 
@@ -199,6 +200,7 @@ typedef enum {
 	PFLAG_DISABLE_NAPTR,
 	PFLAG_AUTOFLUSH,
 	PFLAG_NAT_OPTIONS_PING,
+	PFLAG_ALL_REG_OPTIONS_PING,
 	PFLAG_AUTOFIX_TIMING,
 	PFLAG_MESSAGE_QUERY_ON_REGISTER,
 	PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER,
@@ -218,6 +220,7 @@ typedef enum {
 	PFLAG_T38_PASSTHRU,
 	PFLAG_CID_IN_1XX,
 	PFLAG_IN_DIALOG_CHAT,
+	PFLAG_DEL_SUBS_ON_REG,
 	/* No new flags below this line */
 	PFLAG_MAX
 } PFLAGS;
@@ -275,6 +278,7 @@ typedef enum {
 	TFLAG_RECOVERING,
 	TFLAG_RECOVERING_BRIDGE,
 	TFLAG_T38_PASSTHRU,
+	TFLAG_RECOVERED,
 	/* No new flags below this line */
 	TFLAG_MAX
 } TFLAGS;
@@ -574,6 +578,7 @@ struct private_object {
 	switch_codec_t read_codec;
 	switch_codec_t write_codec;
 	uint32_t codec_ms;
+	uint32_t bitrate;
 	switch_caller_profile_t *caller_profile;
 	uint32_t timestamp_send;
 	switch_rtp_t *rtp_session;
@@ -939,6 +944,7 @@ switch_status_t sofia_glue_tech_set_video_codec(private_object_t *tech_pvt, int
 const char *sofia_glue_strip_proto(const char *uri);
 switch_status_t reconfig_sofia(sofia_profile_t *profile);
 void sofia_glue_del_gateway(sofia_gateway_t *gp);
+void sofia_glue_gateway_list(sofia_profile_t *profile, switch_stream_handle_t *stream, int up);
 void sofia_glue_del_every_gateway(sofia_profile_t *profile);
 void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const char *host, const char *contact, const char *user_agent,
 						   const char *network_ip);
@@ -1008,3 +1014,7 @@ char *sofia_glue_get_multipart(switch_core_session_t *session, const char *prefi
 void sofia_glue_tech_simplify(private_object_t *tech_pvt);
 switch_console_callback_match_t *sofia_reg_find_reg_url_multi(sofia_profile_t *profile, const char *user, const char *host);
 switch_bool_t sofia_glue_profile_exists(const char *key);
+void sofia_glue_global_siptrace(switch_bool_t on);
+void sofia_glue_proxy_codec(switch_core_session_t *session, const char *r_sdp);
+switch_status_t sofia_glue_sdp_map(const char *r_sdp, switch_event_t **fmtp, switch_event_t **pt);
+void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl);
diff --git a/src/mod/endpoints/mod_sofia/sip-dig.c b/src/mod/endpoints/mod_sofia/sip-dig.c
index f4714bccda..d0c9aa6aff 100644
--- a/src/mod/endpoints/mod_sofia/sip-dig.c
+++ b/src/mod/endpoints/mod_sofia/sip-dig.c
@@ -785,7 +785,7 @@ int dig_addr(struct dig *dig,
 	char const *tport2 = NULL;
 	sres_record_t **answers1 = NULL, **answers2 = NULL;
 	unsigned count1 = 0, count2 = 0, tcount = 0;
-	int type1 = 0, type2 = 0, family1 = 0, family2 = 0;
+	uint16_t type1 = 0, type2 = 0, family1 = 0, family2 = 0;
 
 	if (dig->ip6 > dig->ip4) {
 		type1 = sres_type_aaaa, family1 = AF_INET6;
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index 14d05fd977..aa208c2aee 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -1225,7 +1225,7 @@ static void sofia_perform_profile_start_failure(sofia_profile_t *profile, char *
 #define sofia_profile_start_failure(p, xp) sofia_perform_profile_start_failure(p, xp, __FILE__, __LINE__)
 
 
-#define SQLLEN 1024 * 64
+#define SQLLEN 1024 * 1024
 void *SWITCH_THREAD_FUNC sofia_profile_worker_thread_run(switch_thread_t *thread, void *obj)
 {
 	sofia_profile_t *profile = (sofia_profile_t *) obj;
@@ -1233,11 +1233,12 @@ void *SWITCH_THREAD_FUNC sofia_profile_worker_thread_run(switch_thread_t *thread
 	uint32_t gateway_loops = 0;
 	int loops = 0;
 	uint32_t qsize;
-	void *pop;
+	void *pop = NULL;
 	int loop_count = 0;
-	switch_size_t sql_len = SQLLEN;
+	switch_size_t sql_len = 1024 * 32;
 	char *tmp, *sqlbuf = NULL;
-
+	char *sql = NULL;
+	
 	if (sofia_test_pflag(profile, PFLAG_SQL_IN_TRANS)) {
 		sqlbuf = (char *) malloc(sql_len);
 	}
@@ -1253,37 +1254,43 @@ void *SWITCH_THREAD_FUNC sofia_profile_worker_thread_run(switch_thread_t *thread
 
 	while ((mod_sofia_globals.running == 1 && sofia_test_pflag(profile, PFLAG_RUNNING)) || qsize) {
 		if (sofia_test_pflag(profile, PFLAG_SQL_IN_TRANS)) {
-			if (qsize > 0 && (qsize >= 1024 || ++loop_count >= profile->trans_timeout)) {
+			if (qsize > 0 && (qsize >= 1024 || ++loop_count >= (int)profile->trans_timeout)) {
 				switch_size_t newlen;
-				uint32_t itterations = 0;
+				uint32_t iterations = 0;
 				switch_size_t len = 0;
 
 				switch_mutex_lock(profile->ireg_mutex);
 				
-				//sofia_glue_actually_execute_sql(profile, "begin;\n", NULL);
-
-				while (switch_queue_trypop(profile->sql_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
-					char *sql = (char *) pop;
+				while (sql || (switch_queue_trypop(profile->sql_queue, &pop) == SWITCH_STATUS_SUCCESS && pop)) {
+					if (!sql) sql = (char *) pop;
 
 					newlen = strlen(sql) + 2;
+					iterations++;
 
-					if (newlen + 10 < SQLLEN) {
-						itterations++;
-						if (len + newlen + 10 > sql_len) {
-							sql_len = len + 10 + SQLLEN;
+					if (len + newlen + 10 > sql_len) {
+						switch_size_t new_mlen = len + newlen + 10 + 10240;
+						
+						if (new_mlen < SQLLEN) {
+							sql_len = new_mlen;
+							
 							if (!(tmp = realloc(sqlbuf, sql_len))) {
 								abort();
 								break;
 							}
 							sqlbuf = tmp;
+						} else {
+							goto skip;
 						}
-						sprintf(sqlbuf + len, "%s;\n", sql);
-						len += newlen;
 					}
 
-					free(pop);
+					sprintf(sqlbuf + len, "%s;\n", sql);
+					len += newlen;
+					free(sql);
+					sql = NULL;
 				}
 
+			skip:
+
 				//printf("TRANS:\n%s\n", sqlbuf);
 				sofia_glue_actually_execute_sql_trans(profile, sqlbuf, NULL);
 				//sofia_glue_actually_execute_sql(profile, "commit;\n", NULL);
@@ -2258,6 +2265,12 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
 						} else {
 							sofia_clear_pflag(profile, PFLAG_PASS_CALLEE_ID);
 						}
+					} else if (!strcasecmp(var, "delete-subs-on-register")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_DEL_SUBS_ON_REG);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_DEL_SUBS_ON_REG);
+						}
 					} else if (!strcasecmp(var, "in-dialog-chat")) {
 						if (switch_true(val)) {
 							sofia_set_pflag(profile, PFLAG_IN_DIALOG_CHAT);
@@ -2305,12 +2318,6 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
 						} else {
 							sofia_clear_pflag(profile, PFLAG_FORWARD_MWI_NOTIFY);
 						}
-					} else if (!strcasecmp(var, "forward-unsolicited-mwi-notify")) {
-						if (switch_true(val)) {
-							sofia_set_pflag(profile, PFLAG_FORWARD_MWI_NOTIFY);
-						} else {
-							sofia_clear_pflag(profile, PFLAG_FORWARD_MWI_NOTIFY);
-						}
 					} else if (!strcasecmp(var, "t38-passthru")) {
 						if (switch_true(val)) {
 							sofia_set_pflag(profile, PFLAG_T38_PASSTHRU);
@@ -2549,6 +2556,12 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
 						} else {
 							sofia_clear_pflag(profile, PFLAG_NAT_OPTIONS_PING);
 						}
+					} else if (!strcasecmp(var, "all-reg-options-ping")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_ALL_REG_OPTIONS_PING);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_ALL_REG_OPTIONS_PING);
+						}
 					} else if (!strcasecmp(var, "inbound-codec-negotiation")) {
 						if (!strcasecmp(val, "greedy")) {
 							sofia_set_pflag(profile, PFLAG_GREEDY);
@@ -2860,7 +2873,7 @@ switch_status_t config_sofia(int reload, char *profile_name)
 					goto done;
 				}
 
-				profile->trans_timeout = 500;
+				profile->trans_timeout = 100;
 
 				profile->auto_rtp_bugs = RTP_BUG_CISCO_SKIP_MARK_BIT_2833;// | RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
 
@@ -2920,6 +2933,12 @@ switch_status_t config_sofia(int reload, char *profile_name)
 						} else {
 							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
 						}
+                                        } else if (!strcasecmp(var, "forward-unsolicited-mwi-notify")) {
+                                                if (switch_true(val)) {
+                                                        sofia_set_pflag(profile, PFLAG_FORWARD_MWI_NOTIFY);
+                                                } else {
+                                                        sofia_clear_pflag(profile, PFLAG_FORWARD_MWI_NOTIFY);
+                                                }
 					} else if (!strcasecmp(var, "user-agent-string")) {
 						profile->user_agent = switch_core_strdup(profile->pool, val);
 					} else if (!strcasecmp(var, "auto-restart")) {
@@ -2936,6 +2955,12 @@ switch_status_t config_sofia(int reload, char *profile_name)
 						} else {
 							sofia_clear_pflag(profile, PFLAG_IN_DIALOG_CHAT);
 						}
+					} else if (!strcasecmp(var, "delete-subs-on-register")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_DEL_SUBS_ON_REG);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_DEL_SUBS_ON_REG);
+						}
 					} else if (!strcasecmp(var, "t38-passthru")) {
 						if (switch_true(val)) {
 							sofia_set_pflag(profile, PFLAG_T38_PASSTHRU);
@@ -3303,6 +3328,12 @@ switch_status_t config_sofia(int reload, char *profile_name)
 						} else {
 							sofia_clear_pflag(profile, PFLAG_NAT_OPTIONS_PING);
 						}
+					} else if (!strcasecmp(var, "all-options-ping")) {
+						if (switch_true(val)) {
+							sofia_set_pflag(profile, PFLAG_ALL_REG_OPTIONS_PING);
+						} else {
+							sofia_clear_pflag(profile, PFLAG_ALL_REG_OPTIONS_PING);
+						}
 					} else if (!strcasecmp(var, "inbound-codec-negotiation")) {
 						if (!strcasecmp(val, "greedy")) {
 							sofia_set_pflag(profile, PFLAG_GREEDY);
@@ -3914,6 +3945,23 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status
 			}
 		}
 
+#if 0
+		if (status == 200 && switch_channel_test_flag(channel, CF_PROXY_MEDIA) && 
+			sip->sip_payload && sip->sip_payload->pl_data && !strcasecmp(tech_pvt->iananame, "PROXY")) {
+			switch_core_session_t *other_session;
+			
+			sofia_glue_proxy_codec(session, sip->sip_payload->pl_data);
+			
+			if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
+				if (switch_core_session_compare(session, other_session)) {
+					sofia_glue_proxy_codec(other_session, sip->sip_payload->pl_data);
+				}
+				switch_core_session_rwunlock(other_session);
+			}
+		}
+#endif
+
+
 		if ((status == 180 || status == 183 || status == 200)) {
 			const char *x_freeswitch_support;
 
@@ -3940,7 +3988,7 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status
 
 		}
 
-		if (channel && sip && (status == 300 || status == 302 || status == 305) && switch_channel_test_flag(channel, CF_OUTBOUND)) {
+		if (channel && sip && (status == 300 || status == 301 || status == 302 || status == 305) && switch_channel_test_flag(channel, CF_OUTBOUND)) {
 			sip_contact_t *p_contact = sip->sip_contact;
 			int i = 0;
 			char var_name[80];
@@ -4090,7 +4138,8 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status
 			}
 		}
 
-		if (tech_pvt && tech_pvt->remote_sdp_str && switch_stristr("m=image", tech_pvt->remote_sdp_str)) {
+
+		if (sip->sip_payload && sip->sip_payload->pl_data && switch_stristr("m=image", sip->sip_payload->pl_data)) {
 			has_t38 = 1;
 		}
 		
@@ -4118,6 +4167,36 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status
 					if (status == 200 && sofia_test_flag(tech_pvt, TFLAG_T38_PASSTHRU) && has_t38) {
 						if (sip->sip_payload && sip->sip_payload->pl_data) {
 							switch_t38_options_t *t38_options = sofia_glue_extract_t38_options(session, sip->sip_payload->pl_data);
+							char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
+							switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
+							char tmp[32] = "";
+					
+							tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, t38_options->remote_ip);
+							tech_pvt->remote_sdp_audio_port = t38_options->remote_port;
+							
+							if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_audio_ip) && 
+								remote_port == tech_pvt->remote_sdp_audio_port) {
+								switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
+												  "Audio params are unchanged for %s.\n",
+												  switch_channel_get_name(tech_pvt->channel));
+							} else {
+								const char *err = NULL;
+
+								switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, 
+												  "Audio params changed for %s from %s:%d to %s:%d\n",
+												  switch_channel_get_name(tech_pvt->channel),
+												  remote_host, remote_port, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+								
+								switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
+								switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
+								switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
+								if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip,
+																  tech_pvt->remote_sdp_audio_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
+									switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
+									switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
+								}
+							}
+
 
 							if (t38_options) {
 								sofia_glue_copy_t38_options(t38_options, other_session);
@@ -4145,16 +4224,13 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status
 					}
 					
 					if (status == 200 && sofia_test_flag(tech_pvt, TFLAG_T38_PASSTHRU) && has_t38) {
-						switch_core_session_receive_message(other_session, msg);
 						if (switch_rtp_ready(tech_pvt->rtp_session) && switch_rtp_ready(other_tech_pvt->rtp_session)) {
 							switch_rtp_udptl_mode(tech_pvt->rtp_session);
-							switch_rtp_udptl_mode(other_tech_pvt->rtp_session);
 							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Activating T38 Passthru\n");
 						}
-					} else {
-						switch_core_session_queue_message(other_session, msg);
 					}
 
+					switch_core_session_queue_message(other_session, msg);
 
 					switch_core_session_rwunlock(other_session);
 				}
@@ -4374,7 +4450,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
 
 	if (ss_state == nua_callstate_terminated) {
 
-		if ((status == 300 || status == 302 || status == 305) && session) {
+		if ((status == 300 || status == 301 || status == 302 || status == 305) && session) {
 			channel = switch_core_session_get_channel(session);
 			tech_pvt = switch_core_session_get_private(session);
 
@@ -4447,6 +4523,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
 		}
 	}
 
+
+
   state_process:
 
 	switch ((enum nua_callstate) ss_state) {
@@ -4521,7 +4599,20 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
 		}
 		break;
 	case nua_callstate_completing:
-		nua_ack(nh, TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END());
+		{
+			if (sofia_test_pflag(profile, PFLAG_TRACK_CALLS)) {
+				const char *invite_full_via = switch_channel_get_variable(tech_pvt->channel, "sip_invite_full_via");
+				const char *invite_route_uri = switch_channel_get_variable(tech_pvt->channel, "sip_invite_route_uri");			
+
+				nua_ack(nh, 
+						TAG_IF(!zstr(invite_full_via), SIPTAG_VIA_STR(invite_full_via)),
+						TAG_IF(!zstr(invite_route_uri), SIPTAG_ROUTE_STR(invite_route_uri)),
+						TAG_END());
+						
+			} else {
+				nua_ack(nh, TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END());
+			}
+		}
 		goto done;
 	case nua_callstate_received:
 		if (!sofia_test_flag(tech_pvt, TFLAG_SDP)) {
@@ -4912,6 +5003,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
 				sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
 				sofia_set_flag(tech_pvt, TFLAG_SDP);
 				switch_channel_mark_answered(channel);
+
 				if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
 					if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
 						&& (other_session = switch_core_session_locate(uuid))) {
@@ -4932,6 +5024,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
 					sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
 					sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
 					switch_channel_mark_answered(channel);
+
 					if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
 						if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
 							goto done;
@@ -5037,6 +5130,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
 	}
 
   done:
+	
 
 	if ((enum nua_callstate) ss_state == nua_callstate_ready && channel && session && tech_pvt) {
 		sofia_glue_tech_simplify(tech_pvt);
@@ -5188,7 +5282,6 @@ nua_handle_t *sofia_global_nua_handle_by_replaces(sip_replaces_t *replaces)
 
 }
 
-
 void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[])
 {
 	/* Incoming refer */
@@ -5761,7 +5854,17 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t
 
 		if (sip && sip->sip_content_type && sip->sip_content_type->c_type && sip->sip_content_type->c_subtype &&
 			sip->sip_payload && sip->sip_payload->pl_data) {
-			if (!strncasecmp(sip->sip_content_type->c_type, "application", 11) && !strcasecmp(sip->sip_content_type->c_subtype, "dtmf-relay")) {
+			if (!strncasecmp(sip->sip_content_type->c_type, "application", 11) && !strcasecmp(sip->sip_content_type->c_subtype, "media_control+xml")) {
+				switch_core_session_t *other_session;
+				
+				if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
+					sofia_glue_build_vid_refresh_message(other_session, sip->sip_payload->pl_data);
+					switch_core_session_rwunlock(other_session);
+				} else {
+					sofia_glue_build_vid_refresh_message(session, sip->sip_payload->pl_data);
+				}
+
+			} else if (!strncasecmp(sip->sip_content_type->c_type, "application", 11) && !strcasecmp(sip->sip_content_type->c_subtype, "dtmf-relay")) {
 				/* Try and find signal information in the payload */
 				if ((signal_ptr = switch_stristr("Signal=", sip->sip_payload->pl_data))) {
 					int tmp;
@@ -5901,6 +6004,26 @@ void sofia_handle_sip_i_reinvite(switch_core_session_t *session,
 {
 	char *call_info = NULL;
 
+	if (session && profile && sip && sofia_test_pflag(profile, PFLAG_TRACK_CALLS)) {
+		switch_channel_t *channel = switch_core_session_get_channel(session);
+		private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+		char network_ip[80];
+		int network_port = 0;
+		char via_space[2048];
+		char branch[16] = "";
+
+		sofia_glue_get_addr(nua_current_request(nua), network_ip, sizeof(network_ip), &network_port);
+		switch_stun_random_string(branch, sizeof(branch) - 1, "0123456789abcdef");
+
+		switch_snprintf(via_space, sizeof(via_space), "SIP/2.0/UDP %s;rport=%d;branch=%s", network_ip, network_port, branch);
+		switch_channel_set_variable(channel, "sip_full_via", via_space);
+		switch_channel_set_variable_printf(channel, "sip_network_port", "%d", network_port);
+		switch_channel_set_variable_printf(channel, "sip_recieved_port", "%d", network_port);
+		switch_channel_set_variable_printf(channel, "sip_via_rport", "%d", network_port);
+		
+		sofia_glue_tech_track(tech_pvt->profile, session);
+	}
+
 	if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
 		switch_channel_t *channel = switch_core_session_get_channel(session);
 		if (channel && sip->sip_call_info) {
diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c
index 82b933c981..e4933c63c1 100644
--- a/src/mod/endpoints/mod_sofia/sofia_glue.c
+++ b/src/mod/endpoints/mod_sofia/sofia_glue.c
@@ -41,11 +41,16 @@ switch_cache_db_handle_t *sofia_glue_get_db_handle(sofia_profile_t *profile);
 
 void sofia_glue_set_image_sdp(private_object_t *tech_pvt, switch_t38_options_t *t38_options, int insist)
 {
-	char buf[2048];
+	char buf[2048] = "";
+	char max_buf[128] = "";
+	char max_data[128] = "";
 	const char *ip = t38_options->local_ip;
 	uint32_t port = t38_options->local_port;
 	const char *family = "IP4";
 	const char *username = tech_pvt->profile->username;
+	char MMR[32] = "";
+	char JBIG[32] = "";
+	char FILLBIT[32] = "";
 
 	//sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
 
@@ -89,6 +94,56 @@ void sofia_glue_set_image_sdp(private_object_t *tech_pvt, switch_t38_options_t *
 					"o=%s %010u %010u IN %s %s\n"
 					"s=%s\n" "c=IN %s %s\n" "t=0 0\n", username, tech_pvt->owner_id, tech_pvt->session_id, family, ip, username, family, ip);
 
+	if(t38_options->T38FaxFillBitRemoval) {
+		if (switch_true(switch_channel_get_variable(tech_pvt->channel, "broken_T38FaxFillBitRemoval"))) {
+			switch_snprintf(FILLBIT, sizeof(FILLBIT), "a=T38FaxFillBitRemoval:1\n");
+		} else {
+			switch_set_string(FILLBIT, "a=T38FaxFillBitRemoval\n");
+		}
+	} else {
+		if (switch_true(switch_channel_get_variable(tech_pvt->channel, "broken_T38FaxFillBitRemoval"))) {
+			switch_snprintf(FILLBIT, sizeof(FILLBIT), "a=T38FaxFillBitRemoval:0\n");
+		} else {
+			switch_set_string(FILLBIT, "");
+		}
+	}
+
+	if( t38_options->T38FaxTranscodingMMR) {
+		if (switch_true(switch_channel_get_variable(tech_pvt->channel, "broken_T38FaxTranscodingMMR"))) {
+			switch_snprintf(MMR, sizeof(MMR), "a=T38FaxTranscodingMMR:1\n");
+		} else {
+			switch_set_string(MMR, "a=T38FaxTranscodingMMR\n");
+		}
+	} else {
+		if (switch_true(switch_channel_get_variable(tech_pvt->channel, "broken_T38FaxTranscodingMMR"))) {
+			switch_snprintf(MMR, sizeof(MMR), "a=T38FaxTranscodingMMR:0\n");
+		} else {
+			switch_set_string(MMR, "");
+		}
+	}
+
+	if( t38_options->T38FaxTranscodingJBIG) {
+		if (switch_true(switch_channel_get_variable(tech_pvt->channel, "broken_T38FaxTranscodingJBIG"))) {
+			switch_snprintf(JBIG, sizeof(JBIG), "a=T38FaxTranscodingJBIG:1\n");
+		} else {
+			switch_set_string(JBIG, "a=T38FaxTranscodingJBIG\n");
+		}
+	} else {
+		if (switch_true(switch_channel_get_variable(tech_pvt->channel, "broken_T38FaxTranscodingJBIG"))) {
+			switch_snprintf(JBIG, sizeof(JBIG), "a=T38FaxTranscodingJBIG:0\n");
+		} else {
+			switch_set_string(JBIG, "");
+		}
+	}
+
+	if (t38_options->T38FaxMaxBuffer) {
+		switch_snprintf(max_buf, sizeof(max_buf), "a=T38FaxMaxBuffer:%d\n", t38_options->T38FaxMaxBuffer);
+	};
+
+	if (t38_options->T38FaxMaxDatagram) {
+		switch_snprintf(max_data, sizeof(max_data), "a=T38FaxMaxDatagram:%d\n", t38_options->T38FaxMaxDatagram);
+	};
+
 
 	switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
 					"m=image %d udptl t38\n"
@@ -98,19 +153,20 @@ void sofia_glue_set_image_sdp(private_object_t *tech_pvt, switch_t38_options_t *
 					"%s"
 					"%s"
 					"a=T38FaxRateManagement:%s\n"
-					"a=T38FaxMaxBuffer:%d\n"
-					"a=T38FaxMaxDatagram:%d\n"
+					"%s"
+					"%s"
 					"a=T38FaxUdpEC:%s\n",
 					//"a=T38VendorInfo:%s\n",
 					port,
 					t38_options->T38FaxVersion,
 					t38_options->T38MaxBitRate,
-					t38_options->T38FaxFillBitRemoval ? "a=T38FaxFillBitRemoval\n" : "",
-					t38_options->T38FaxTranscodingMMR ? "a=T38FaxTranscodingMMR\n" : "",
-					t38_options->T38FaxTranscodingJBIG ? "a=T38FaxTranscodingJBIG\n" : "",
+					FILLBIT,
+					MMR,
+					JBIG,
 					t38_options->T38FaxRateManagement,
-					t38_options->T38FaxMaxBuffer,
-					t38_options->T38FaxMaxDatagram, t38_options->T38FaxUdpEC
+					max_buf,
+					max_data,
+					t38_options->T38FaxUdpEC
 					//t38_options->T38VendorInfo ? t38_options->T38VendorInfo : "0 0 0"
 					);
 
@@ -146,6 +202,13 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32
 	const char *username = tech_pvt->profile->username;
 	const char *fmtp_out = tech_pvt->fmtp_out;
 	const char *fmtp_out_var = switch_channel_get_variable(tech_pvt->channel, "sip_force_audio_fmtp");
+	switch_event_t *map = NULL, *ptmap = NULL;
+	const char *b_sdp = NULL;
+
+	if (!tech_pvt->rm_encoding && (b_sdp = switch_channel_get_variable(tech_pvt->channel, SWITCH_B_SDP_VARIABLE))) {
+		sofia_glue_sdp_map(b_sdp, &map, &ptmap);
+	}
+
 
 	if (fmtp_out_var) {
 		fmtp_out = fmtp_out_var;
@@ -274,7 +337,8 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32
 		int already_did[128] = { 0 };
 		for (i = 0; i < tech_pvt->num_codecs; i++) {
 			const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
-
+			char *fmtp = imp->fmtp;
+			
 			if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
 				continue;
 			}
@@ -289,9 +353,20 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32
 
 			rate = imp->samples_per_second;
 
+			if (map) {
+				char key[128] = "";
+				char *check = NULL;
+				switch_snprintf(key, sizeof(key), "%s:%u", imp->iananame, imp->bits_per_second);
+
+				if ((check = switch_event_get_header(map, key)) || (check = switch_event_get_header(map, imp->iananame))) {
+					fmtp = check;
+				}
+			}
+			
 			switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", imp->ianacode, imp->iananame, rate);
-			if (imp->fmtp) {
-				switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, imp->fmtp);
+
+			if (fmtp) {
+				switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, fmtp);
 			}
 		}
 	}
@@ -423,38 +498,87 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32
 				int i;
 				int already_did[128] = { 0 };
 
+#if 0				
+				switch_event_t *event;
+				char *buf;
+				int level = SWITCH_LOG_INFO;
+				
+				if (switch_event_create_plain(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) {
+					switch_channel_event_set_data(switch_core_session_get_channel(tech_pvt->session), event);
+					switch_event_serialize(event, &buf, SWITCH_FALSE);
+					switch_assert(buf);
+					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), level, "CHANNEL_DATA:\n%s\n", buf);
+					switch_event_destroy(&event);
+					free(buf);
+				}
+#endif
+		
 				for (i = 0; i < tech_pvt->num_codecs; i++) {
 					const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+					char *fmtp = NULL;
+					uint32_t ianacode = imp->ianacode;
+#if 0
+					const char *str;
 
+
+
+					if ((str = switch_event_get_header(ptmap, imp->iananame))) {
+						int tmp = atoi(str);
+						if (tmp > 0) {
+							ianacode = tmp;
+						}
+					}
+#endif			
 					if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
 						continue;
 					}
 
-					if (imp->ianacode < 128) {
-						if (already_did[imp->ianacode]) {
+					if (ianacode < 128) {
+						if (already_did[ianacode]) {
 							continue;
 						}
-						already_did[imp->ianacode] = 1;
+						already_did[ianacode] = 1;
 					}
 
 					if (!rate) {
 						rate = imp->samples_per_second;
 					}
-
-					switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", imp->ianacode, imp->iananame,
+					
+					
+					switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", ianacode, imp->iananame,
 									imp->samples_per_second);
-					if (imp->fmtp) {
-						switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, imp->fmtp);
+					
+					if (!zstr(ov_fmtp)) {
+						fmtp = (char *) ov_fmtp;
 					} else {
-						if (pass_fmtp) {
-							switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, pass_fmtp);
+					
+						if (map) {
+							fmtp = switch_event_get_header(map, imp->iananame);
 						}
+						
+						if (zstr(fmtp)) fmtp = imp->fmtp;
+
+						if (zstr(fmtp)) fmtp = (char *) pass_fmtp;
+					}
+					
+					if (!zstr(fmtp) && strcasecmp(fmtp, "_blank_")) {
+						switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, fmtp);
 					}
 				}
+				
 			}
 		}
 	}
 
+
+	if (map) {
+		switch_event_destroy(&map);
+	}
+	
+	if (ptmap) {
+		switch_event_destroy(&ptmap);
+	}
+	
 	sofia_glue_tech_set_local_sdp(tech_pvt, buf, SWITCH_TRUE);
 }
 
@@ -748,32 +872,30 @@ switch_status_t sofia_glue_tech_choose_port(private_object_t *tech_pvt, int forc
 
 	sdp_port = tech_pvt->local_sdp_audio_port;
 
-	if (!(use_ip = switch_channel_get_variable(tech_pvt->channel, "rtp_adv_audio_ip"))
-		&& !zstr(tech_pvt->profile->extrtpip)) {
-		use_ip = tech_pvt->profile->extrtpip;
-	}
+	/* Check if NAT is detected  */
+	if (!zstr(tech_pvt->remote_ip) && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) {
+		/* Yes, map the port through switch_nat */
+		switch_nat_add_mapping(tech_pvt->local_sdp_audio_port, SWITCH_NAT_UDP, &sdp_port, SWITCH_FALSE);
+		switch_nat_add_mapping(tech_pvt->local_sdp_audio_port + 1, SWITCH_NAT_UDP, &rtcp_port, SWITCH_FALSE);
 
-	if (use_ip) {
-		if (sofia_glue_ext_address_lookup(tech_pvt->profile, tech_pvt, &lookup_rtpip, &sdp_port,
-										  use_ip, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
-			/* Address lookup was required and fail (external ip was "host:..." or "stun:...") */
-			return SWITCH_STATUS_FALSE;
-		} else {
-			if (lookup_rtpip == use_ip) {
-				/* sofia_glue_ext_address_lookup didn't return any error, but the return IP is the same as the original one, 
-				   which means no lookup was necessary. Check if NAT is detected  */
-				if (!zstr(tech_pvt->remote_ip) && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) {
-					/* Yes, map the port through switch_nat */
-					switch_nat_add_mapping(tech_pvt->local_sdp_audio_port, SWITCH_NAT_UDP, &sdp_port, SWITCH_FALSE);
-					switch_nat_add_mapping(tech_pvt->local_sdp_audio_port + 1, SWITCH_NAT_UDP, &rtcp_port, SWITCH_FALSE);
-				} else {
-					/* No NAT detected */
-					use_ip = tech_pvt->rtpip;
-				}
+		/* Find an IP address to use */
+		if (!(use_ip = switch_channel_get_variable(tech_pvt->channel, "rtp_adv_audio_ip"))
+			&& !zstr(tech_pvt->profile->extrtpip)) {
+			use_ip = tech_pvt->profile->extrtpip;
+		}
+
+		if (use_ip) {
+			if (sofia_glue_ext_address_lookup(tech_pvt->profile, tech_pvt, &lookup_rtpip, &sdp_port,
+											  use_ip, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+				/* Address lookup was required and fail (external ip was "host:..." or "stun:...") */
+				return SWITCH_STATUS_FALSE;
 			} else {
 				/* Address properly resolved, use it as external ip */
 				use_ip = lookup_rtpip;
 			}
+		} else {
+			/* No external ip found, use the profile's rtp ip */
+			use_ip = tech_pvt->rtpip;
 		}
 	} else {
 		/* No NAT traversal required, use the profile's rtp ip */
@@ -817,31 +939,29 @@ switch_status_t sofia_glue_tech_choose_video_port(private_object_t *tech_pvt, in
 
 	sdp_port = tech_pvt->local_sdp_video_port;
 
-	if (!(use_ip = switch_channel_get_variable(tech_pvt->channel, "rtp_adv_video_ip"))
-		&& !zstr(tech_pvt->profile->extrtpip)) {
-		use_ip = tech_pvt->profile->extrtpip;
-	}
+	/* Check if NAT is detected  */
+	if (!zstr(tech_pvt->remote_ip) && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) {
+		/* Yes, map the port through switch_nat */
+		switch_nat_add_mapping(tech_pvt->local_sdp_video_port, SWITCH_NAT_UDP, &sdp_port, SWITCH_FALSE);
 
-	if (use_ip) {
-		if (sofia_glue_ext_address_lookup(tech_pvt->profile, tech_pvt, &lookup_rtpip, &sdp_port,
-										  use_ip, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
-			/* Address lookup was required and fail (external ip was "host:..." or "stun:...") */
-			return SWITCH_STATUS_FALSE;
-		} else {
-			if (lookup_rtpip == use_ip) {
-				/* sofia_glue_ext_address_lookup didn't return any error, but the return IP is the same as the original one, 
-				   which means no lookup was necessary. Check if NAT is detected  */
-				if (!zstr(tech_pvt->remote_ip) && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) {
-					/* Yes, map the port through switch_nat */
-					switch_nat_add_mapping(tech_pvt->local_sdp_video_port, SWITCH_NAT_UDP, &sdp_port, SWITCH_FALSE);
-				} else {
-					/* No NAT detected */
-					use_ip = tech_pvt->rtpip;
-				}
+		/* Find an IP address to use */
+		if (!(use_ip = switch_channel_get_variable(tech_pvt->channel, "rtp_adv_video_ip"))
+			&& !zstr(tech_pvt->profile->extrtpip)) {
+			use_ip = tech_pvt->profile->extrtpip;
+		}
+
+		if (use_ip) {
+			if (sofia_glue_ext_address_lookup(tech_pvt->profile, tech_pvt, &lookup_rtpip, &sdp_port,
+											  use_ip, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+				/* Address lookup was required and fail (external ip was "host:..." or "stun:...") */
+				return SWITCH_STATUS_FALSE;
 			} else {
 				/* Address properly resolved, use it as external ip */
 				use_ip = lookup_rtpip;
 			}
+		} else {
+			/* No external ip found, use the profile's rtp ip */
+			use_ip = tech_pvt->rtpip;
 		}
 	} else {
 		/* No NAT traversal required, use the profile's rtp ip */
@@ -1162,7 +1282,7 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt)
 				switch_port_t remote_rtcp_port = 0;
 
 				if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_video_rtcp_port"))) {
-					remote_rtcp_port = atoi(rport);
+					remote_rtcp_port = (switch_port_t)atoi(rport);
 				}
 
 
@@ -1198,7 +1318,7 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt)
 		}
 
 		if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port"))) {
-			remote_rtcp_port = atoi(rport);
+			remote_rtcp_port = (switch_port_t)atoi(rport);
 		}
 
 
@@ -1516,7 +1636,11 @@ char *sofia_glue_get_multipart(switch_core_session_t *session, const char *prefi
 
 			if (!strncasecmp(name, prefix, strlen(prefix))) {
 				const char *hname = name + strlen(prefix);
-				stream.write_function(&stream, "--%s\nContent-Type: %s\nContent-Length: %d\n\n%s\n", boundary, hname, strlen(value) + 1, value);
+				if (*value == '~') {
+					stream.write_function(&stream, "--%s\nContent-Type: %s\nContent-Length: %d\n%s\n", boundary, hname, strlen(value), value + 1);
+				} else {
+					stream.write_function(&stream, "--%s\nContent-Type: %s\nContent-Length: %d\n\n%s\n", boundary, hname, strlen(value) + 1, value);
+				}
 				x++;
 			}
 		}
@@ -1658,7 +1782,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
 		sofia_private_t *sofia_private;
 		char *invite_contact = NULL, *to_str, *use_from_str, *from_str;
 		const char *t_var;
-		char *rpid_domain = "cluecon.com", *p;
+		char *rpid_domain = NULL, *p;
 		const char *priv = "off";
 		const char *screen = "no";
 		const char *invite_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_params");
@@ -1670,6 +1794,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
 		const char *from_var = switch_channel_get_variable(tech_pvt->channel, "sip_from_uri");
 		const char *from_display = switch_channel_get_variable(tech_pvt->channel, "sip_from_display");
 		const char *invite_req_uri = switch_channel_get_variable(tech_pvt->channel, "sip_invite_req_uri");
+		const char *invite_domain = switch_channel_get_variable(tech_pvt->channel, "sip_invite_domain");
 		const char *use_name, *use_number;
 
 		if (zstr(tech_pvt->dest)) {
@@ -1688,7 +1813,6 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
 		if (!tech_pvt->from_str) {
 			const char *sipip;
 			const char *format;
-			const char *alt = NULL;
 
 			sipip = tech_pvt->profile->sipip;
 
@@ -1698,8 +1822,8 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
 
 			format = strchr(sipip, ':') ? "\"%s\" " : "\"%s\" ";
 
-			if ((alt = switch_channel_get_variable(channel, "sip_invite_domain"))) {
-				sipip = alt;
+			if (!zstr(invite_domain)) {
+				sipip = invite_domain;
 			}
 
 			tech_pvt->from_str = switch_core_session_sprintf(tech_pvt->session, format, cid_name, cid_num, !zstr(cid_num) ? "@" : "", sipip);
@@ -1739,6 +1863,10 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
 			}
 		}
 
+		if (!zstr(invite_domain)) {
+			rpid_domain = (char *)invite_domain;
+		}
+
 		if (zstr(rpid_domain)) {
 			rpid_domain = "cluecon.com";
 		}
@@ -1864,10 +1992,22 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
 			switch_channel_set_variable(channel, "sip_req_uri", s);
 		}
 
-		tech_pvt->nh = nua_handle(tech_pvt->profile->nua, NULL,
-								  NUTAG_URL(url_str),
-								  TAG_IF(call_id, SIPTAG_CALL_ID_STR(call_id)),
-								  SIPTAG_TO_STR(to_str), SIPTAG_FROM_STR(from_str), SIPTAG_CONTACT_STR(invite_contact), TAG_END());
+		if (!(tech_pvt->nh = nua_handle(tech_pvt->profile->nua, NULL,
+										NUTAG_URL(url_str),
+										TAG_IF(call_id, SIPTAG_CALL_ID_STR(call_id)),
+										SIPTAG_TO_STR(to_str), SIPTAG_FROM_STR(from_str), SIPTAG_CONTACT_STR(invite_contact), TAG_END()))) {
+
+			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, 
+							  "Error creating HANDLE!\nurl_str=[%s]\ncall_id=[%s]\nto_str=[%s]\nfrom_str=[%s]\ninvite_contact=[%s]\n",
+							  url_str,
+							  call_id ? call_id : "N/A",
+							  to_str,
+							  from_str,
+							  invite_contact);
+			
+			switch_safe_free(d_url);
+			return SWITCH_STATUS_FALSE;
+		}
 
 		if (tech_pvt->dest && (strstr(tech_pvt->dest, ";fs_nat") || strstr(tech_pvt->dest, ";received")
 							   || ((val = switch_channel_get_variable(channel, "sip_sticky_contact")) && switch_true(val)))) {
@@ -2055,10 +2195,16 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
 		sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
 	}
 
+	if (sofia_test_flag(tech_pvt, TFLAG_RECOVERED)) {
+		session_timeout = 0;
+	}
+
 	if (sofia_use_soa(tech_pvt)) {
 		nua_invite(tech_pvt->nh,
 				   NUTAG_AUTOANSWER(0),
 				   NUTAG_SESSION_TIMER(session_timeout),
+				   TAG_IF(session_timeout, NUTAG_SESSION_REFRESHER(nua_remote_refresher)),
+				   TAG_IF(sofia_test_flag(tech_pvt, TFLAG_RECOVERED), NUTAG_INVITE_TIMER(UINT_MAX)),
 				   TAG_IF(invite_full_from, SIPTAG_FROM_STR(invite_full_from)),
 				   TAG_IF(invite_full_to, SIPTAG_TO_STR(invite_full_to)),
 				   TAG_IF(tech_pvt->redirected, NUTAG_URL(tech_pvt->redirected)),
@@ -2087,6 +2233,8 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
 		nua_invite(tech_pvt->nh,
 				   NUTAG_AUTOANSWER(0),
 				   NUTAG_SESSION_TIMER(session_timeout),
+				   TAG_IF(session_timeout, NUTAG_SESSION_REFRESHER(nua_remote_refresher)),
+				   TAG_IF(sofia_test_flag(tech_pvt, TFLAG_RECOVERED), NUTAG_INVITE_TIMER(UINT_MAX)),
 				   TAG_IF(invite_full_from, SIPTAG_FROM_STR(invite_full_from)),
 				   TAG_IF(invite_full_to, SIPTAG_TO_STR(invite_full_to)),
 				   TAG_IF(tech_pvt->redirected, NUTAG_URL(tech_pvt->redirected)),
@@ -2230,6 +2378,9 @@ static void set_stats(switch_rtp_t *rtp_session, private_object_t *tech_pvt, con
 		add_stat(stats->outbound.dtmf_packet_count, "out_dtmf_packet_count");
 		add_stat(stats->outbound.cng_packet_count, "out_cng_packet_count");
 
+		add_stat(stats->rtcp.packet_count, "rtcp_packet_count");
+		add_stat(stats->rtcp.octet_count, "rtcp_octet_count");
+
 	}
 }
 
@@ -2386,24 +2537,26 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force)
 		}
 	}
 
-	if (switch_core_codec_init(&tech_pvt->read_codec,
+	if (switch_core_codec_init_with_bitrate(&tech_pvt->read_codec,
 							   tech_pvt->iananame,
 							   tech_pvt->rm_fmtp,
 							   tech_pvt->rm_rate,
 							   tech_pvt->codec_ms,
 							   1,
+							   tech_pvt->bitrate,
 							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags,
 							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n");
 		switch_goto_status(SWITCH_STATUS_FALSE, end);
 	}
 
-	if (switch_core_codec_init(&tech_pvt->write_codec,
+	if (switch_core_codec_init_with_bitrate(&tech_pvt->write_codec,
 							   tech_pvt->iananame,
 							   tech_pvt->rm_fmtp,
 							   tech_pvt->rm_rate,
 							   tech_pvt->codec_ms,
 							   1,
+							   tech_pvt->bitrate,
 							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags,
 							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n");
@@ -2427,9 +2580,10 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force)
 
 	if (switch_rtp_ready(tech_pvt->rtp_session)) {
 		switch_assert(tech_pvt->read_codec.implementation);
-
+		
 		if (switch_rtp_change_interval(tech_pvt->rtp_session,
-									   tech_pvt->read_impl.microseconds_per_packet, tech_pvt->read_impl.samples_per_packet) != SWITCH_STATUS_SUCCESS) {
+									   tech_pvt->read_impl.microseconds_per_packet, 
+									   tech_pvt->read_impl.samples_per_packet) != SWITCH_STATUS_SUCCESS) {
 			switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
 			switch_goto_status(SWITCH_STATUS_FALSE, end);
 		}
@@ -2443,9 +2597,9 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force)
 		switch_goto_status(SWITCH_STATUS_FALSE, end);
 	}
 
-	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Codec %s %s/%ld %d ms %d samples\n",
+	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Codec %s %s/%ld %d ms %d samples %d bits\n",
 					  switch_channel_get_name(tech_pvt->channel), tech_pvt->iananame, tech_pvt->rm_rate, tech_pvt->codec_ms,
-					  tech_pvt->read_impl.samples_per_packet);
+					  tech_pvt->read_impl.samples_per_packet, tech_pvt->read_impl.bits_per_second);
 	tech_pvt->read_frame.codec = &tech_pvt->read_codec;
 
 	tech_pvt->write_codec.agreed_pt = tech_pvt->agreed_pt;
@@ -2689,6 +2843,10 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
 						  tech_pvt->local_sdp_audio_port,
 						  tech_pvt->remote_sdp_audio_ip,
 						  tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
+
+		if (switch_rtp_ready(tech_pvt->rtp_session)) {
+			switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->agreed_pt);
+		}
 	}
 
 	switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->local_sdp_audio_port);
@@ -2702,7 +2860,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
 		sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
 
 		if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port"))) {
-			remote_rtcp_port = atoi(rport);
+			remote_rtcp_port = (switch_port_t)atoi(rport);
 		}
 
 		if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port,
@@ -2741,6 +2899,10 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
 						  tech_pvt->remote_sdp_audio_ip,
 						  tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
 
+		if (switch_rtp_ready(tech_pvt->rtp_session)) {
+			switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->agreed_pt);
+		}
+
 	} else {
 		timer_name = tech_pvt->profile->timer_name;
 
@@ -2833,7 +2995,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
 			const char *rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port");
 			switch_port_t remote_port = 0;
 			if (rport) {
-				remote_port = atoi(rport);
+				remote_port = (switch_port_t)atoi(rport);
 			}
 			if (!strcasecmp(val, "passthru")) {
 				switch_rtp_activate_rtcp(tech_pvt->rtp_session, -1, remote_port);
@@ -2931,13 +3093,14 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
 
 		sofia_glue_check_video_codecs(tech_pvt);
 		if (sofia_test_flag(tech_pvt, TFLAG_VIDEO) && tech_pvt->video_rm_encoding && tech_pvt->remote_sdp_video_port) {
-
+			
 			/******************************************************************************************/
 			if (tech_pvt->video_rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
 				//const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
 				//const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
 				char *remote_host = switch_rtp_get_remote_host(tech_pvt->video_rtp_session);
 				switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->video_rtp_session);
+				
 
 				if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_video_ip) && remote_port == tech_pvt->remote_sdp_video_port) {
 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Video params are unchanged for %s.\n",
@@ -2955,8 +3118,12 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
 								  "VIDEO RTP [%s] %s port %d -> %s port %d codec: %u ms: %d\n", switch_channel_get_name(tech_pvt->channel),
 								  tech_pvt->local_sdp_audio_ip, tech_pvt->local_sdp_video_port, tech_pvt->remote_sdp_video_ip,
 								  tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
-			}
 
+				if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
+					switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt);
+				}
+			}
+			
 			switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->local_sdp_video_port);
 			switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
 			switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE, tmp);
@@ -2968,7 +3135,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
 				sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
 
 				if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_video_rtcp_port"))) {
-					remote_rtcp_port = atoi(rport);
+					remote_rtcp_port = (switch_port_t)atoi(rport);
 				}
 
 				if (switch_rtp_set_remote_address
@@ -2983,6 +3150,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
 						/* Reactivate the NAT buster flag. */
 						switch_rtp_set_flag(tech_pvt->video_rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
 					}
+
 				}
 				goto video_up;
 			}
@@ -3008,6 +3176,9 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
 								  tech_pvt->remote_sdp_video_ip,
 								  tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt, tech_pvt->read_impl.microseconds_per_packet / 1000);
 
+				if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
+					switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt);
+				}
 			} else {
 				timer_name = tech_pvt->profile->timer_name;
 
@@ -3058,6 +3229,11 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
 							  tech_pvt->remote_sdp_video_port, tech_pvt->video_agreed_pt,
 							  0, switch_rtp_ready(tech_pvt->video_rtp_session) ? "SUCCESS" : err);
 
+
+			if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
+				switch_rtp_set_default_payload(tech_pvt->video_rtp_session, tech_pvt->video_agreed_pt);
+			}
+
 			if (switch_rtp_ready(tech_pvt->video_rtp_session)) {
 				const char *ssrc;
 				switch_channel_set_flag(tech_pvt->channel, CF_VIDEO);
@@ -3076,7 +3252,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
 					const char *rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_video_rtcp_port");
 					switch_port_t remote_port = 0;
 					if (rport) {
-						remote_port = atoi(rport);
+						remote_port = (switch_port_t)atoi(rport);
 					}
 					if (!strcasecmp(val, "passthru")) {
 						switch_rtp_activate_rtcp(tech_pvt->rtp_session, -1, remote_port);
@@ -3418,11 +3594,11 @@ static switch_t38_options_t *tech_process_udptl(private_object_t *tech_pvt, sdp_
 		t38_options = switch_core_session_alloc(tech_pvt->session, sizeof(switch_t38_options_t));
 	}
 
-	t38_options->remote_port = m->m_port;
+	t38_options->remote_port = (switch_port_t)m->m_port;
 
-	if (m->m_connections) {
+	if (m->m_connections && m->m_connections->c_address) {
 		t38_options->remote_ip = switch_core_session_strdup(tech_pvt->session, m->m_connections->c_address);
-	} else if (sdp && sdp->sdp_connection) {
+	} else if (sdp && sdp->sdp_connection && sdp->sdp_connection->c_address) {
 		t38_options->remote_ip = switch_core_session_strdup(tech_pvt->session, sdp->sdp_connection->c_address);
 	}
 
@@ -3432,11 +3608,41 @@ static switch_t38_options_t *tech_process_udptl(private_object_t *tech_pvt, sdp_
 		} else if (!strcasecmp(attr->a_name, "T38MaxBitRate") && attr->a_value) {
 			t38_options->T38MaxBitRate = (uint32_t) atoi(attr->a_value);
 		} else if (!strcasecmp(attr->a_name, "T38FaxFillBitRemoval")) {
-			t38_options->T38FaxFillBitRemoval = SWITCH_TRUE;
+			if (switch_stristr("T38FaxFillBitRemoval:", tech_pvt->remote_sdp_str)) {
+				switch_channel_set_variable(tech_pvt->channel, "broken_T38FaxFillBitRemoval", "true");
+				if (atoi(attr->a_value) == 0) {
+					t38_options->T38FaxFillBitRemoval = SWITCH_FALSE;
+				} else {
+					t38_options->T38FaxFillBitRemoval = SWITCH_TRUE;
+				}
+			} else {
+				switch_channel_set_variable(tech_pvt->channel, "broken_T38FaxFillBitRemoval", "false");
+				t38_options->T38FaxFillBitRemoval = SWITCH_TRUE;
+			}
 		} else if (!strcasecmp(attr->a_name, "T38FaxTranscodingMMR")) {
-			t38_options->T38FaxTranscodingMMR = SWITCH_TRUE;
+			if (switch_stristr("T38FaxTranscodingMMR:", tech_pvt->remote_sdp_str)) {
+				switch_channel_set_variable(tech_pvt->channel, "broken_T38FaxTranscodingMMR", "true");
+				if (atoi(attr->a_value) == 0) {
+					t38_options->T38FaxTranscodingMMR = SWITCH_FALSE;
+				} else {
+					t38_options->T38FaxTranscodingMMR = SWITCH_TRUE;
+				}
+			} else {
+				switch_channel_set_variable(tech_pvt->channel, "broken_T38FaxTranscodingMMR", "false");
+				t38_options->T38FaxTranscodingMMR = SWITCH_TRUE;
+			}
 		} else if (!strcasecmp(attr->a_name, "T38FaxTranscodingJBIG")) {
-			t38_options->T38FaxTranscodingJBIG = SWITCH_TRUE;
+			if (switch_stristr("T38FaxTranscodingJBIG:", tech_pvt->remote_sdp_str)) {
+				switch_channel_set_variable(tech_pvt->channel, "broken_T38FaxTranscodingJBIG", "true");
+				if (atoi(attr->a_value) == 0) {
+					t38_options->T38FaxTranscodingJBIG = SWITCH_FALSE;
+				} else {
+					t38_options->T38FaxTranscodingJBIG = SWITCH_TRUE;
+				}
+			} else {
+				switch_channel_set_variable(tech_pvt->channel, "broken_T38FaxTranscodingJBIG", "false");
+				t38_options->T38FaxTranscodingJBIG = SWITCH_TRUE;
+			}
 		} else if (!strcasecmp(attr->a_name, "T38FaxRateManagement") && attr->a_value) {
 			t38_options->T38FaxRateManagement = switch_core_session_strdup(tech_pvt->session, attr->a_value);
 		} else if (!strcasecmp(attr->a_name, "T38FaxMaxBuffer") && attr->a_value) {
@@ -3457,6 +3663,131 @@ static switch_t38_options_t *tech_process_udptl(private_object_t *tech_pvt, sdp_
 	return t38_options;
 }
 
+
+switch_status_t sofia_glue_sdp_map(const char *r_sdp, switch_event_t **fmtp, switch_event_t **pt)
+{
+	sdp_media_t *m;
+	sdp_parser_t *parser = NULL;
+	sdp_session_t *sdp;
+
+	if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	if (!(sdp = sdp_session(parser))) {
+		sdp_parser_free(parser);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	switch_event_create(&(*fmtp), SWITCH_EVENT_REQUEST_PARAMS);
+	switch_event_create(&(*pt), SWITCH_EVENT_REQUEST_PARAMS);
+
+	for (m = sdp->sdp_media; m; m = m->m_next) {
+		if (m->m_proto == sdp_proto_rtp) {
+			sdp_rtpmap_t *map;
+			
+			for (map = m->m_rtpmaps; map; map = map->rm_next) {
+				if (map->rm_encoding) {
+					char buf[25] = "";
+					char key[128] = "";
+					char *br = NULL;
+
+					if (map->rm_fmtp) {
+						if ((br = strstr(map->rm_fmtp, "bitrate="))) {
+							br += 8;
+						}
+					}
+
+					switch_snprintf(buf, sizeof(buf), "%d", map->rm_pt);
+
+					if (br) {
+						switch_snprintf(key, sizeof(key), "%s:%s", map->rm_encoding, br);
+					} else {
+						switch_snprintf(key, sizeof(key), "%s", map->rm_encoding);
+					}
+					
+					switch_event_add_header_string(*pt, SWITCH_STACK_BOTTOM, key, buf);
+
+					if (map->rm_fmtp) {
+						switch_event_add_header_string(*fmtp, SWITCH_STACK_BOTTOM, key, map->rm_fmtp);
+					}
+				}
+			}
+		}
+	}
+	
+	sdp_parser_free(parser);
+
+	return SWITCH_STATUS_SUCCESS;
+	
+}
+
+
+void sofia_glue_proxy_codec(switch_core_session_t *session, const char *r_sdp)
+{
+	sdp_media_t *m;
+	sdp_parser_t *parser = NULL;
+	sdp_session_t *sdp;
+	private_object_t *tech_pvt = switch_core_session_get_private(session);
+	sdp_attribute_t *attr;
+	int ptime = 0, dptime = 0, dmaxptime = 0, maxptime = 0;
+
+	if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
+		return;
+	}
+
+	if (!(sdp = sdp_session(parser))) {
+		sdp_parser_free(parser);
+		return;
+	}
+
+	switch_assert(tech_pvt != NULL);
+
+
+	for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) {
+		if (zstr(attr->a_name)) {
+			continue;
+		}
+
+		if (!strcasecmp(attr->a_name, "ptime")) {
+			dptime = atoi(attr->a_value);
+		} else if (!strcasecmp(attr->a_name, "maxptime")) {
+			dmaxptime = atoi(attr->a_value);
+		}
+	}
+
+
+	for (m = sdp->sdp_media; m; m = m->m_next) {
+
+		ptime = dptime;
+		maxptime = dmaxptime;
+
+		if (m->m_proto == sdp_proto_rtp) {
+			sdp_rtpmap_t *map;
+			for (attr = m->m_attributes; attr; attr = attr->a_next) {
+				if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
+					ptime = atoi(attr->a_value);
+				} else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) {
+					maxptime = atoi(attr->a_value);		
+				}
+			}
+
+			for (map = m->m_rtpmaps; map; map = map->rm_next) {
+				tech_pvt->iananame = switch_core_session_strdup(tech_pvt->session, map->rm_encoding);
+				tech_pvt->rm_rate = map->rm_rate;
+				tech_pvt->codec_ms = ptime;
+				sofia_glue_tech_set_codec(tech_pvt, 0);
+				break;
+			}
+
+			break;
+		}
+	}
+
+	sdp_parser_free(parser);
+
+}
+
 switch_t38_options_t *sofia_glue_extract_t38_options(switch_core_session_t *session, const char *r_sdp)
 {
 	sdp_media_t *m;
@@ -3498,7 +3829,6 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
 	sdp_attribute_t *attr;
 	int first = 0, last = 0;
 	int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0;
-	int codec_ms = 0;
 	int sendonly = 0;
 	int greedy = 0, x = 0, skip = 0, mine = 0;
 	switch_channel_t *channel = switch_core_session_get_channel(session);
@@ -3579,11 +3909,12 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
 	if (sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_HOLD) ||
 		((val = switch_channel_get_variable(tech_pvt->channel, "sip_disable_hold")) && switch_true(val))) {
 		sendonly = 0;
-	}
+	} else {
 
-	if (!tech_pvt->hold_laps) {
-		tech_pvt->hold_laps++;
-		sofia_glue_toggle_hold(tech_pvt, sendonly);
+		if (!tech_pvt->hold_laps) {
+			tech_pvt->hold_laps++;
+			sofia_glue_toggle_hold(tech_pvt, sendonly);
+		}
 	}
 
 	for (m = sdp->sdp_media; m; m = m->m_next) {
@@ -3603,7 +3934,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
 
 		if (got_udptl && m->m_type == sdp_media_image && m->m_port) {
 			switch_t38_options_t *t38_options = tech_process_udptl(tech_pvt, sdp, m);
-
+			
 			if (switch_true(switch_channel_get_variable(channel, "refuse_t38"))) {
 				match = 0;
 				goto done;
@@ -3618,10 +3949,46 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
 				if (sofia_test_flag(tech_pvt, TFLAG_T38_PASSTHRU)) {
 					pass = 0;
 				}
-
+				
+				if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) || 
+					switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) || !switch_rtp_ready(tech_pvt->rtp_session)) {
+					pass = 0;
+				}
+				
 				if (pass && switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
 					private_object_t *other_tech_pvt = switch_core_session_get_private(other_session);
 					switch_core_session_message_t *msg;
+					char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
+					switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
+					char tmp[32] = "";
+					
+					tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, t38_options->remote_ip);
+					tech_pvt->remote_sdp_audio_port = t38_options->remote_port;
+
+					if (remote_host && remote_port && !strcmp(remote_host, tech_pvt->remote_sdp_audio_ip) && remote_port == tech_pvt->remote_sdp_audio_port) {
+						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n",
+										  switch_channel_get_name(tech_pvt->channel));
+					} else {
+						const char *err = NULL;
+
+						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n",
+										  switch_channel_get_name(tech_pvt->channel),
+										  remote_host, remote_port, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+						
+						switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
+						switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
+						switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
+
+						if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip,
+														  tech_pvt->remote_sdp_audio_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) {
+							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err);
+							switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
+						}
+						
+					}
+
+
+
 					sofia_glue_copy_t38_options(t38_options, other_session);
 
 					sofia_set_flag(tech_pvt, TFLAG_T38_PASSTHRU);
@@ -3783,6 +4150,8 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
 				uint32_t near_rate = 0;
 				const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
 				const char *rm_encoding;
+				uint32_t map_bit_rate = 0;
+				int codec_ms = 0;
 
 				if (x++ < skip) {
 					continue;
@@ -3823,40 +4192,37 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
 				}
 
 				if (!ptime) {
-					ptime = 20;
+					ptime = switch_default_ptime(rm_encoding, map->rm_pt);
 				}
 
-				if (!strcasecmp((char *) rm_encoding, "ilbc")) {
-					char *mode = NULL;
-					if (map->rm_fmtp && (mode = strstr(map->rm_fmtp, "mode=")) && (mode + 5)) {
-						codec_ms = atoi(mode + 5);
-					}
-					if (!codec_ms) {
-						/* default to 30 when no mode is defined for ilbc ONLY */
-						codec_ms = 30;
-					}
-				} else {
+				map_bit_rate = switch_known_bitrate(map->rm_pt);
+
+				if (!codec_ms) {
 					codec_ms = ptime;
 				}
 
-
-
 				for (i = first; i < last && i < tech_pvt->num_codecs; i++) {
 					const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+					uint32_t bit_rate = imp->bits_per_second;
 					uint32_t codec_rate = imp->samples_per_second;
 					if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
 						continue;
 					}
 
-					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d]/[%s:%d:%u:%d]\n",
-									  rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms,
-									  imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000);
+					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d:%u]/[%s:%d:%u:%d:%u]\n",
+									  rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms, map_bit_rate,
+									  imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate);
 					if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
 						match = (map->rm_pt == imp->ianacode) ? 1 : 0;
 					} else {
 						match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
 					}
 
+					if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate) {
+						/* nevermind */
+						match = 0;
+					}
+					
 					if (match) {
 						if (scrooge) {
 							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
@@ -3918,6 +4284,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
 					tech_pvt->pt = (switch_payload_t) map->rm_pt;
 					tech_pvt->rm_rate = map->rm_rate;
 					tech_pvt->codec_ms = mimp->microseconds_per_packet / 1000;
+					tech_pvt->bitrate = mimp->bits_per_second;
 					tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, (char *) connection->c_address);
 					tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
 					tech_pvt->remote_sdp_audio_port = (switch_port_t) m->m_port;
@@ -4251,6 +4618,28 @@ void sofia_glue_del_every_gateway(sofia_profile_t *profile)
 }
 
 
+void sofia_glue_gateway_list(sofia_profile_t *profile, switch_stream_handle_t *stream, int up)
+{
+	sofia_gateway_t *gp = NULL;
+	char *r = (char *) stream->data;
+
+	switch_mutex_lock(mod_sofia_globals.hash_mutex);
+	for (gp = profile->gateways; gp; gp = gp->next) {
+		int reged = (gp->status == SOFIA_GATEWAY_UP);
+		
+		if (up ? reged : !reged) {
+			stream->write_function(stream, "%s ", gp->name);
+		}
+	}
+
+	if (r) {
+		end_of(r) = '\0';
+	}
+
+	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+}
+
+
 void sofia_glue_del_gateway(sofia_gateway_t *gp)
 {
 	if (!gp->deleted) {
@@ -4304,6 +4693,27 @@ void sofia_glue_restart_all_profiles(void)
 
 }
 
+
+void sofia_glue_global_siptrace(switch_bool_t on)
+{
+	switch_hash_index_t *hi;
+	const void *var;
+	void *val;
+	sofia_profile_t *pptr;
+
+	switch_mutex_lock(mod_sofia_globals.hash_mutex);
+	if (mod_sofia_globals.profile_hash) {
+		for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+			switch_hash_this(hi, &var, NULL, &val);
+			if ((pptr = (sofia_profile_t *) val)) {
+				nua_set_params(pptr->nua, TPTAG_LOG(on), TAG_END());				
+			}
+		}
+	}
+	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+
+}
+
 void sofia_glue_del_profile(sofia_profile_t *profile)
 {
 	sofia_gateway_t *gp;
@@ -4457,13 +4867,13 @@ static int recover_callback(void *pArg, int argc, char **argv, char **columnName
 			}
 
 			if ((tmp = switch_channel_get_variable(channel, "sip_use_pt"))) {
-				tech_pvt->pt = tech_pvt->agreed_pt = atoi(tmp);
+				tech_pvt->pt = tech_pvt->agreed_pt = (switch_payload_t)atoi(tmp);
 			}
 
 			sofia_glue_tech_set_codec(tech_pvt, 1);
 
 			tech_pvt->adv_sdp_audio_ip = tech_pvt->extrtpip = (char *) ip;
-			tech_pvt->adv_sdp_audio_port = tech_pvt->local_sdp_audio_port = atoi(port);
+			tech_pvt->adv_sdp_audio_port = tech_pvt->local_sdp_audio_port = (switch_port_t)atoi(port);
 
 			if ((tmp = switch_channel_get_variable(channel, "local_media_ip"))) {
 				tech_pvt->local_sdp_audio_ip = switch_core_session_strdup(session, tmp);
@@ -4472,12 +4882,12 @@ static int recover_callback(void *pArg, int argc, char **argv, char **columnName
 
 			if (r_ip && r_port) {
 				tech_pvt->remote_sdp_audio_ip = (char *) r_ip;
-				tech_pvt->remote_sdp_audio_port = atoi(r_port);
+				tech_pvt->remote_sdp_audio_port = (switch_port_t)atoi(r_port);
 			}
 
 			if (switch_channel_test_flag(channel, CF_VIDEO)) {
 				if ((tmp = switch_channel_get_variable(channel, "sip_use_video_pt"))) {
-					tech_pvt->video_pt = tech_pvt->video_agreed_pt = atoi(tmp);
+					tech_pvt->video_pt = tech_pvt->video_agreed_pt = (switch_payload_t)atoi(tmp);
 				}
 
 
@@ -4499,11 +4909,11 @@ static int recover_callback(void *pArg, int argc, char **argv, char **columnName
 					tech_pvt->video_codec_ms = atoi(tmp);
 				}
 
-				tech_pvt->adv_sdp_video_port = tech_pvt->local_sdp_video_port = atoi(port);
+				tech_pvt->adv_sdp_video_port = tech_pvt->local_sdp_video_port = (switch_port_t)atoi(port);
 
 				if (r_ip && r_port) {
 					tech_pvt->remote_sdp_video_ip = (char *) r_ip;
-					tech_pvt->remote_sdp_video_port = atoi(r_port);
+					tech_pvt->remote_sdp_video_port = (switch_port_t)atoi(r_port);
 				}
 				//sofia_glue_tech_set_video_codec(tech_pvt, 1);
 			}
@@ -4644,7 +5054,7 @@ void sofia_glue_tech_untrack(sofia_profile_t *profile, switch_core_session_t *se
 			}
 		}
 		
-		sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
+		sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
 		sofia_clear_flag(tech_pvt, TFLAG_TRACKED);
 		
 		switch_safe_free(sql);
@@ -5388,6 +5798,23 @@ void sofia_glue_tech_simplify(private_object_t *tech_pvt)
 }
 
 
+void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl)
+{
+	switch_core_session_message_t *msg;
+	msg = switch_core_session_alloc(session, sizeof(*msg));
+	MESSAGE_STAMP_FFL(msg);
+	msg->message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ;
+	if (pl) {
+		msg->string_arg = switch_core_session_strdup(session, pl);
+	}
+	msg->from = __FILE__;
+
+	switch_core_session_queue_message(session, msg);
+}
+
+
+
+
 
 /* For Emacs:
  * Local Variables:
diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c
index 73d930314b..333f31b91d 100644
--- a/src/mod/endpoints/mod_sofia/sofia_presence.c
+++ b/src/mod/endpoints/mod_sofia/sofia_presence.c
@@ -1442,7 +1442,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
 					op = switch_event_get_header(helper->event, "Caller-Callee-ID-Number");
 				}
 
-				if (!op) {
+				if (zstr(op)) {
 					op = switch_event_get_header(helper->event, "Caller-Destination-Number");
 				}
 
@@ -1452,7 +1452,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
 
 				if (!strcmp(astate, "early")) {
 					if (zstr(op)) {
-						switch_snprintf(status_line, sizeof(status_line), "%s %s", what, status);
+						switch_snprintf(status_line, sizeof(status_line), "%sing", what);
 					} else {
 						switch_snprintf(status_line, sizeof(status_line), "%s %s", what, op);
 					}
@@ -1983,12 +1983,20 @@ void sofia_presence_handle_sip_i_subscribe(int status,
 			is_nat = NULL;
 		}
 
+		if (zstr(contact_host)) {
+			is_nat = "No contact host";
+		}
+
 		if (is_nat) {
 			contact_host = network_ip;
 			switch_snprintf(new_port, sizeof(new_port), ":%d", network_port);
 			port = NULL;
 		}
 
+		if (zstr(contact_host)) {
+			nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END());
+			return;
+		}
 
 		if (port) {
 			switch_snprintf(new_port, sizeof(new_port), ":%s", port);
@@ -2043,7 +2051,11 @@ void sofia_presence_handle_sip_i_subscribe(int status,
 			from_host = "n/a";
 		}
 
-		exp_delta = profile->force_subscription_expires ? profile->force_subscription_expires : (sip->sip_expires ? sip->sip_expires->ex_delta : 3600);
+		if ((exp_delta = sip->sip_expires ? sip->sip_expires->ex_delta : 3600)) {
+			if (profile->force_subscription_expires) {
+				exp_delta = profile->force_subscription_expires;
+			}
+		}
 
 		if (exp_delta) {
 			exp_abs = (long) switch_epoch_time_now(NULL) + exp_delta;
diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c
index eb9b03d958..285dc8ae3a 100644
--- a/src/mod/endpoints/mod_sofia/sofia_reg.c
+++ b/src/mod/endpoints/mod_sofia/sofia_reg.c
@@ -438,11 +438,14 @@ int sofia_reg_nat_callback(void *pArg, int argc, char **argv, char **columnNames
 	switch_snprintf(to, sizeof(to), "sip:%s@%s", argv[1], argv[2]);
 	dst = sofia_glue_get_destination(argv[3]);
 	switch_assert(dst);
-
+	
 	nh = nua_handle(profile->nua, NULL, SIPTAG_FROM_STR(profile->url), SIPTAG_TO_STR(to), NUTAG_URL(dst->contact), SIPTAG_CONTACT_STR(profile->url),
 					TAG_END());
 	nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
-	nua_options(nh, TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), TAG_END());
+	nua_options(nh, 
+				NTATAG_SIP_T2(5000),
+				NTATAG_SIP_T4(10000),
+				TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), TAG_END());
 
 	sofia_glue_free_destination(dst);
 
@@ -514,7 +517,7 @@ int sofia_reg_del_callback(void *pArg, int argc, char **argv, char **columnNames
 			switch_event_fire(&s_event);
 		}
 
-		if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
+		if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
 			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
 			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", "away");
 			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->url);
@@ -637,15 +640,14 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot)
 	}
 
 	sofia_glue_actually_execute_sql(profile, sql, NULL);
-
-
-
+	
 	if (now) {
 		switch_snprintf(sql, sizeof(sql),
 						"select call_id from sip_subscriptions where (expires = -1 or (expires > 0 and expires <= %ld)) and hostname='%s'", (long) now,
 						mod_sofia_globals.hostname);
 	} else {
-		switch_snprintf(sql, sizeof(sql), "select call_id from sip_subscriptions where expires >= -1 and hostname='%s'", mod_sofia_globals.hostname);
+		switch_snprintf(sql, sizeof(sql), "select sub_to_user,sub_to_host,call_id from sip_subscriptions where expires >= -1 and hostname='%s'", 
+						mod_sofia_globals.hostname);
 	}
 
 	sofia_glue_execute_sql_callback(profile, NULL, sql, sofia_sub_del_callback, profile);
@@ -670,13 +672,21 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot)
 	sofia_glue_actually_execute_sql(profile, sql, NULL);
 
 
-	if (now && sofia_test_pflag(profile, PFLAG_NAT_OPTIONS_PING)) {
-		switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,"
-						"expires,user_agent,server_user,server_host,profile_name"
-						" from sip_registrations where (status like '%%AUTO-NAT%%' "
-						"or status like '%%UDP-NAT%%') and hostname='%s'", mod_sofia_globals.hostname);
-
-		sofia_glue_execute_sql_callback(profile, NULL, sql, sofia_reg_nat_callback, profile);
+	if (now) {
+		if (sofia_test_pflag(profile, PFLAG_ALL_REG_OPTIONS_PING)) {
+			switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,"
+							"expires,user_agent,server_user,server_host,profile_name"
+							" from sip_registrations where hostname='%s'", mod_sofia_globals.hostname);
+			
+			sofia_glue_execute_sql_callback(profile, NULL, sql, sofia_reg_nat_callback, profile);
+		} else if (sofia_test_pflag(profile, PFLAG_NAT_OPTIONS_PING)) {
+			switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,"
+							"expires,user_agent,server_user,server_host,profile_name"
+							" from sip_registrations where (status like '%%NAT%%' "
+							"or contact like '%%fs_nat=yes%%') and hostname='%s'", mod_sofia_globals.hostname);
+			
+			sofia_glue_execute_sql_callback(profile, NULL, sql, sofia_reg_nat_callback, profile);
+		}
 	}
 
 	switch_mutex_unlock(profile->ireg_mutex);
@@ -810,6 +820,10 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
 	switch_event_t *auth_params = NULL;
 	int r = 0;
 	long reg_count = 0;
+	int delete_subs;
+	const char *agent = "unknown";
+		
+	delete_subs = sofia_test_pflag(profile, PFLAG_DEL_SUBS_ON_REG);
 
 	/* all callers must confirm that sip, sip->sip_request and sip->sip_contact are not NULL */
 	switch_assert(sip != NULL && sip->sip_contact != NULL && sip->sip_request != NULL);
@@ -826,6 +840,10 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
 	to = sip->sip_to;
 	from = sip->sip_from;
 
+	if (sip->sip_user_agent) {
+		agent = sip->sip_user_agent->g_string;
+	}
+
 	if (from) {
 		from_user = from->a_url->url_user;
 		from_host = from->a_url->url_host;
@@ -913,7 +931,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
 
 		if (sip->sip_path) {
 			path_val = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_path);
-			path_encoded_len = (strlen(path_val) * 3) + 1;
+			path_encoded_len = (int)(strlen(path_val) * 3) + 1;
 			switch_zmalloc(path_encoded, path_encoded_len);
 			switch_copy_string(path_encoded, ";fs_path=", 10);
 			switch_url_encode(path_val, path_encoded + 9, path_encoded_len - 9);
@@ -926,7 +944,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
 				switch_snprintf(my_contact_str, sizeof(my_contact_str), "sip:%s@%s:%d", contact->m_url->url_user, url_ip, network_port);
 			}
 
-			path_encoded_len = (strlen(my_contact_str) * 3) + 1;
+			path_encoded_len = (int)(strlen(my_contact_str) * 3) + 1;
 
 			switch_zmalloc(path_encoded, path_encoded_len);
 			switch_copy_string(path_encoded, ";fs_path=", 10);
@@ -1135,7 +1153,6 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
 	}
 
 	if (exptime) {
-		const char *agent = "dunno";
 		char guess_ip4[256];
 		const char *username = "unknown";
 		const char *realm = reg_host;
@@ -1145,19 +1162,15 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
 			realm = switch_event_get_header(auth_params, "sip_auth_realm");
 		}
 
-		if (sip->sip_user_agent) {
-			agent = sip->sip_user_agent->g_string;
-		}
-
 		if (multi_reg) {
 
-#ifdef DEL_SUBS
-			if (reg_count == 1) {
-				sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q' and contact='%q'", 
-									 to_user, sub_host, contact_str);
-				sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
+			if (delete_subs) {
+				if (reg_count == 1) {
+					sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q' and contact='%q'", 
+										 to_user, sub_host, contact_str);
+					sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
+				}
 			}
-#endif
 				
 
 			if (multi_reg_contact) {
@@ -1167,10 +1180,10 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
 				sql = switch_mprintf("delete from sip_registrations where call_id='%q'", call_id);
 			}
 		} else {
-#ifdef DEL_SUBS
-			sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q'", to_user, sub_host);
-			sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
-#endif
+			if (delete_subs) {
+				sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q'", to_user, sub_host);
+				sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
+			}
 			sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", to_user, reg_host);
 		}
 		switch_mutex_lock(profile->ireg_mutex);
@@ -1185,7 +1198,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
 							 "mwi_user,mwi_host, orig_server_host, orig_hostname) "
 							 "values ('%q','%q', '%q','%q','%q','%q', '%q', %ld, '%q', '%q', '%q', '%q', '%q', '%q', '%q','%q','%q','%q','%q','%q','%q')", 
 							 call_id, to_user, reg_host, profile->presence_hosts ? profile->presence_hosts : reg_host, 
-							 contact_str, reg_desc, rpid, (long) switch_epoch_time_now(NULL) + (long) exptime * 2, 
+							 contact_str, reg_desc, rpid, (long) switch_epoch_time_now(NULL) + (long) exptime + 60, 
 							 agent, from_user, guess_ip4, profile->name, mod_sofia_globals.hostname, network_ip, network_port_c, username, realm, 
 							 mwi_user, mwi_host, guess_ip4, mod_sofia_globals.hostname);
 							 
@@ -1290,16 +1303,16 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
 			if ((p = strchr(icontact + 4, ':'))) {
 				*p = '\0';
 			}
-#ifdef DEL_SUBS
-			if (multi_reg_contact) {
-				sql =
-					switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q' and contact='%q'", to_user, sub_host, contact_str);
-			} else {
-				sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", call_id);
-			}
+			if (delete_subs) {
+				if (multi_reg_contact) {
+					sql =
+						switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q' and contact='%q'", to_user, sub_host, contact_str);
+				} else {
+					sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", call_id);
+				}
 
-			sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
-#endif
+				sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
+			}
 
 			if (multi_reg_contact) {
 				sql =
@@ -1312,11 +1325,11 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
 
 			switch_safe_free(icontact);
 		} else {
-#ifdef DEL_SUBS
-			if ((sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q'", to_user, sub_host))) {
-				sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
+			if (delete_subs) {
+				if ((sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q'", to_user, sub_host))) {
+					sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
+				}
 			}
-#endif
 			if ((sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", to_user, reg_host))) {
 				sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
 			}
@@ -2110,7 +2123,8 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
 
 	if (auth_acl) {
 		if (!switch_check_network_list_ip(ip, auth_acl)) {
-			int network_ip_is_proxy = 0, x = 0;
+			int network_ip_is_proxy = 0;
+			uint32_t x = 0;
 			char *last_acl = NULL;
 			if (profile->proxy_acl_count == 0) {
 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by user acl [%s] and no proxy acl present\n", ip, auth_acl);
@@ -2207,7 +2221,7 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
 	if (max_registrations_perext > 0 && (sip && sip->sip_contact && (sip->sip_contact->m_expires == NULL || atol(sip->sip_contact->m_expires) > 0))) {
 		/* if expires is null still process */
 		/* expires == 0 means the phone is going to unregiser, so don't count against max */
-		int count = 0;
+		uint32_t count = 0;
 
 		call_id = sip->sip_call_id->i_id;
 		switch_assert(call_id);
@@ -2292,9 +2306,9 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
 				switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, "mwi-account", mwi_account);
 			}
 
-			if ((uparams = switch_xml_child(user, "params"))) {
+			if ((dparams = switch_xml_child(domain, "params"))) {
 				xparams_type[i] = 0;
-				xparams[i++] = uparams;
+				xparams[i++] = dparams;
 			}
 
 			if (group && (gparams = switch_xml_child(group, "params"))) {
@@ -2302,102 +2316,98 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
 				xparams[i++] = gparams;
 			}
 
-			if ((dparams = switch_xml_child(domain, "params"))) {
+			if ((uparams = switch_xml_child(user, "params"))) {
 				xparams_type[i] = 0;
-				xparams[i++] = dparams;
-			}
-
-			if ((uparams = switch_xml_child(user, "variables"))) {
-				xparams_type[i] = 1;
 				xparams[i++] = uparams;
 			}
 
-			if (group && (gparams = switch_xml_child(group, "variables"))) {
-				xparams_type[i] = 1;
-				xparams[i++] = gparams;
-			}
-
 			if ((dparams = switch_xml_child(domain, "variables"))) {
 				xparams_type[i] = 1;
 				xparams[i++] = dparams;
 			}
 
+			if (group && (gparams = switch_xml_child(group, "variables"))) {
+				xparams_type[i] = 1;
+				xparams[i++] = gparams;
+			}
+
+			if ((uparams = switch_xml_child(user, "variables"))) {
+				xparams_type[i] = 1;
+				xparams[i++] = uparams;
+			}
+
 			if (i <= 6) {
 				int j = 0;
+				const char *gw_val = NULL;
 
 				for (j = 0; j < i; j++) {
 					for (param = switch_xml_child(xparams[j], (xparams_type[j] ? "variable" : "param")); param; param = param->next) {
 						const char *var = switch_xml_attr_soft(param, "name");
 						const char *val = switch_xml_attr_soft(param, "value");
-						sofia_gateway_t *gateway_ptr = NULL;
 
 						if (!zstr(var) && !zstr(val) && (xparams_type[j] == 1 || !strncasecmp(var, "sip-", 4) || !strcasecmp(var, "register-gateway"))) {
-							if (!switch_event_get_header(*v_event, var)) {
-								if (profile->debug) {
-									switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event_add_header -> '%s' = '%s'\n", var, val);
-								}
-								switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, var, val);
-							} else {
-								continue;
+							if (profile->debug) {
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event_add_header -> '%s' = '%s'\n", var, val);
 							}
-
-							if (!strcasecmp(var, "register-gateway")) {
-								if (!strcasecmp(val, "all")) {
-									switch_xml_t gateways_tag, gateway_tag;
-									if ((gateways_tag = switch_xml_child(user, "gateways"))) {
-										for (gateway_tag = switch_xml_child(gateways_tag, "gateway"); gateway_tag; gateway_tag = gateway_tag->next) {
-											char *name = (char *) switch_xml_attr_soft(gateway_tag, "name");
-											if (zstr(name)) {
-												name = "anonymous";
-											}
-
-											if ((gateway_ptr = sofia_reg_find_gateway(name))) {
-												reg_state_t ostate = gateway_ptr->state;
-												gateway_ptr->retry = 0;
-												if (exptime) {
-													gateway_ptr->state = REG_STATE_UNREGED;
-												} else {
-													gateway_ptr->state = REG_STATE_UNREGISTER;
-												}
-												if (ostate != gateway_ptr->state) {
-													sofia_reg_fire_custom_gateway_state_event(gateway_ptr, 0, NULL);
-												}
-												sofia_reg_release_gateway(gateway_ptr);
-											}
-
-										}
-									}
-								} else {
-									int x, argc;
-									char *mydata, *argv[50];
-
-									mydata = strdup(val);
-									switch_assert(mydata != NULL);
-
-									argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0])));
-
-									for (x = 0; x < argc; x++) {
-										if ((gateway_ptr = sofia_reg_find_gateway((char *) argv[x]))) {
-											reg_state_t ostate = gateway_ptr->state;
-											gateway_ptr->retry = 0;
-											if (exptime) {
-												gateway_ptr->state = REG_STATE_UNREGED;
-											} else {
-												gateway_ptr->state = REG_STATE_UNREGISTER;
-											}
-											if (ostate != gateway_ptr->state) {
-												sofia_reg_fire_custom_gateway_state_event(gateway_ptr, 0, NULL);
-											}
-											sofia_reg_release_gateway(gateway_ptr);
-										} else {
-											switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Gateway '%s' not found.\n", argv[x]);
-										}
-									}
-
-									free(mydata);
+							switch_event_add_header_string(*v_event, SWITCH_STACK_BOTTOM, var, val);
+						}
+					}
+				}
+				if ((gw_val = switch_event_get_header(*v_event, "register-gateway"))) {
+					sofia_gateway_t *gateway_ptr = NULL;
+					if (!strcasecmp(gw_val, "all")) {
+						switch_xml_t gateways_tag, gateway_tag;
+						if ((gateways_tag = switch_xml_child(user, "gateways"))) {
+							for (gateway_tag = switch_xml_child(gateways_tag, "gateway"); gateway_tag; gateway_tag = gateway_tag->next) {
+								char *name = (char *) switch_xml_attr_soft(gateway_tag, "name");
+								if (zstr(name)) {
+									name = "anonymous";
 								}
+
+								if ((gateway_ptr = sofia_reg_find_gateway(name))) {
+									reg_state_t ostate = gateway_ptr->state;
+									gateway_ptr->retry = 0;
+									if (exptime) {
+										gateway_ptr->state = REG_STATE_UNREGED;
+									} else {
+										gateway_ptr->state = REG_STATE_UNREGISTER;
+									}
+									if (ostate != gateway_ptr->state) {
+										sofia_reg_fire_custom_gateway_state_event(gateway_ptr, 0, NULL);
+									}
+									sofia_reg_release_gateway(gateway_ptr);
+								}
+
 							}
 						}
+					} else {
+						int x, argc;
+						char *mydata, *argv[50];
+
+						mydata = strdup(gw_val);
+						switch_assert(mydata != NULL);
+
+						argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0])));
+
+						for (x = 0; x < argc; x++) {
+							if ((gateway_ptr = sofia_reg_find_gateway((char *) argv[x]))) {
+								reg_state_t ostate = gateway_ptr->state;
+								gateway_ptr->retry = 0;
+								if (exptime) {
+									gateway_ptr->state = REG_STATE_UNREGED;
+								} else {
+									gateway_ptr->state = REG_STATE_UNREGISTER;
+								}
+								if (ostate != gateway_ptr->state) {
+									sofia_reg_fire_custom_gateway_state_event(gateway_ptr, 0, NULL);
+								}
+								sofia_reg_release_gateway(gateway_ptr);
+							} else {
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Gateway '%s' not found.\n", argv[x]);
+							}
+						}
+
+						free(mydata);
 					}
 				}
 			}
@@ -2486,7 +2496,7 @@ sofia_gateway_t *sofia_reg_find_gateway_by_realm__(const char *file, const char
 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
 	for (hi = switch_hash_first(NULL, mod_sofia_globals.gateway_hash); hi; hi = switch_hash_next(hi)) {
 		switch_hash_this(hi, &var, NULL, &val);
-		if ((gateway = (sofia_gateway_t *) val) && gateway->register_realm && !strcasecmp(gateway->register_realm, key)) {
+		if (key && (gateway = (sofia_gateway_t *) val) && gateway->register_realm && !strcasecmp(gateway->register_realm, key)) {
 			break;
 		} else {
 			gateway = NULL;
diff --git a/src/mod/formats/mod_shout/mod_shout.c b/src/mod/formats/mod_shout/mod_shout.c
index d3fa2e8a45..97f20b867a 100644
--- a/src/mod/formats/mod_shout/mod_shout.c
+++ b/src/mod/formats/mod_shout/mod_shout.c
@@ -1100,7 +1100,7 @@ static int web_callback(void *pArg, int argc, char **argv, char **columnNames)
 {
 	struct holder *holder = (struct holder *) pArg;
 	char title_b4[128] = "";
-	char title_aft[128 * 3] = "";
+	char title_aft[128 * 3 + 1] = "";
 	char *mp3, *m3u;
 
 	/*
diff --git a/src/mod/languages/mod_java/src/org/freeswitch/swig/CoreSession.java b/src/mod/languages/mod_java/src/org/freeswitch/swig/CoreSession.java
index 2b9353c063..e7bcb56834 100644
--- a/src/mod/languages/mod_java/src/org/freeswitch/swig/CoreSession.java
+++ b/src/mod/languages/mod_java/src/org/freeswitch/swig/CoreSession.java
@@ -213,12 +213,12 @@ public class CoreSession {
     return freeswitchJNI.CoreSession_transfer(swigCPtr, this, extension, dialplan, context);
   }
 
-  public String read(int min_digits, int max_digits, String prompt_audio_file, int timeout, String valid_terminators) {
-    return freeswitchJNI.CoreSession_read(swigCPtr, this, min_digits, max_digits, prompt_audio_file, timeout, valid_terminators);
+  public String read(int min_digits, int max_digits, String prompt_audio_file, int timeout, String valid_terminators, int digit_timeout) {
+    return freeswitchJNI.CoreSession_read(swigCPtr, this, min_digits, max_digits, prompt_audio_file, timeout, valid_terminators, digit_timeout);
   }
 
-  public String playAndGetDigits(int min_digits, int max_digits, int max_tries, int timeout, String terminators, String audio_files, String bad_input_audio_files, String digits_regex, String var_name) {
-    return freeswitchJNI.CoreSession_playAndGetDigits(swigCPtr, this, min_digits, max_digits, max_tries, timeout, terminators, audio_files, bad_input_audio_files, digits_regex, var_name);
+  public String playAndGetDigits(int min_digits, int max_digits, int max_tries, int timeout, String terminators, String audio_files, String bad_input_audio_files, String digits_regex, String var_name, int digit_timeout) {
+    return freeswitchJNI.CoreSession_playAndGetDigits(swigCPtr, this, min_digits, max_digits, max_tries, timeout, terminators, audio_files, bad_input_audio_files, digits_regex, var_name, digit_timeout);
   }
 
   public int streamFile(String file, int starting_sample_count) {
diff --git a/src/mod/languages/mod_java/src/org/freeswitch/swig/freeswitchJNI.java b/src/mod/languages/mod_java/src/org/freeswitch/swig/freeswitchJNI.java
index 541777840b..206103c4be 100644
--- a/src/mod/languages/mod_java/src/org/freeswitch/swig/freeswitchJNI.java
+++ b/src/mod/languages/mod_java/src/org/freeswitch/swig/freeswitchJNI.java
@@ -125,8 +125,8 @@ class freeswitchJNI {
   public final static native String CoreSession_getDigits__SWIG_0(long jarg1, CoreSession jarg1_, int jarg2, String jarg3, int jarg4);
   public final static native String CoreSession_getDigits__SWIG_1(long jarg1, CoreSession jarg1_, int jarg2, String jarg3, int jarg4, int jarg5);
   public final static native int CoreSession_transfer(long jarg1, CoreSession jarg1_, String jarg2, String jarg3, String jarg4);
-  public final static native String CoreSession_read(long jarg1, CoreSession jarg1_, int jarg2, int jarg3, String jarg4, int jarg5, String jarg6);
-  public final static native String CoreSession_playAndGetDigits(long jarg1, CoreSession jarg1_, int jarg2, int jarg3, int jarg4, int jarg5, String jarg6, String jarg7, String jarg8, String jarg9, String jarg10);
+  public final static native String CoreSession_read(long jarg1, CoreSession jarg1_, int jarg2, int jarg3, String jarg4, int jarg5, String jarg6, int jarg7);
+  public final static native String CoreSession_playAndGetDigits(long jarg1, CoreSession jarg1_, int jarg2, int jarg3, int jarg4, int jarg5, String jarg6, String jarg7, String jarg8, String jarg9, String jarg10, int jarg11);
   public final static native int CoreSession_streamFile(long jarg1, CoreSession jarg1_, String jarg2, int jarg3);
   public final static native int CoreSession_sleep(long jarg1, CoreSession jarg1_, int jarg2, int jarg3);
   public final static native int CoreSession_flushEvents(long jarg1, CoreSession jarg1_);
diff --git a/src/mod/languages/mod_java/switch_swig_wrap.cpp b/src/mod/languages/mod_java/switch_swig_wrap.cpp
index fc9d6c4681..b275b170d6 100644
--- a/src/mod/languages/mod_java/switch_swig_wrap.cpp
+++ b/src/mod/languages/mod_java/switch_swig_wrap.cpp
@@ -2405,7 +2405,7 @@ SWIGEXPORT jint JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1tran
 }
 
 
-SWIGEXPORT jstring JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1read(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jint jarg2, jint jarg3, jstring jarg4, jint jarg5, jstring jarg6) {
+SWIGEXPORT jstring JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1read(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jint jarg2, jint jarg3, jstring jarg4, jint jarg5, jstring jarg6, jint jarg7) {
   jstring jresult = 0 ;
   CoreSession *arg1 = (CoreSession *) 0 ;
   int arg2 ;
@@ -2413,6 +2413,7 @@ SWIGEXPORT jstring JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1r
   char *arg4 = (char *) 0 ;
   int arg5 ;
   char *arg6 = (char *) 0 ;
+  int arg7 = (int) 0 ;
   char *result = 0 ;
   
   (void)jenv;
@@ -2432,7 +2433,8 @@ SWIGEXPORT jstring JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1r
     arg6 = (char *)jenv->GetStringUTFChars(jarg6, 0);
     if (!arg6) return 0;
   }
-  result = (char *)(arg1)->read(arg2,arg3,(char const *)arg4,arg5,(char const *)arg6);
+  arg7 = (int)jarg7; 
+  result = (char *)(arg1)->read(arg2,arg3,(char const *)arg4,arg5,(char const *)arg6,arg7);
   if(result) jresult = jenv->NewStringUTF((const char *)result);
   if (arg4) jenv->ReleaseStringUTFChars(jarg4, (const char *)arg4);
   if (arg6) jenv->ReleaseStringUTFChars(jarg6, (const char *)arg6);
@@ -2440,7 +2442,7 @@ SWIGEXPORT jstring JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1r
 }
 
 
-SWIGEXPORT jstring JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1playAndGetDigits(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jint jarg2, jint jarg3, jint jarg4, jint jarg5, jstring jarg6, jstring jarg7, jstring jarg8, jstring jarg9, jstring jarg10) {
+SWIGEXPORT jstring JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1playAndGetDigits(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jint jarg2, jint jarg3, jint jarg4, jint jarg5, jstring jarg6, jstring jarg7, jstring jarg8, jstring jarg9, jstring jarg10, jint jarg11) {
   jstring jresult = 0 ;
   CoreSession *arg1 = (CoreSession *) 0 ;
   int arg2 ;
@@ -2452,6 +2454,7 @@ SWIGEXPORT jstring JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1p
   char *arg8 = (char *) 0 ;
   char *arg9 = (char *) 0 ;
   char *arg10 = (char *) NULL ;
+  int arg11 = (int) 0 ;
   char *result = 0 ;
   
   (void)jenv;
@@ -2487,7 +2490,8 @@ SWIGEXPORT jstring JNICALL Java_org_freeswitch_swig_freeswitchJNI_CoreSession_1p
     arg10 = (char *)jenv->GetStringUTFChars(jarg10, 0);
     if (!arg10) return 0;
   }
-  result = (char *)(arg1)->playAndGetDigits(arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,(char const *)arg10);
+  arg11 = (int)jarg11; 
+  result = (char *)(arg1)->playAndGetDigits(arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,(char const *)arg10,arg11);
   if(result) jresult = jenv->NewStringUTF((const char *)result);
   if (arg6) jenv->ReleaseStringUTFChars(jarg6, (const char *)arg6);
   if (arg7) jenv->ReleaseStringUTFChars(jarg7, (const char *)arg7);
diff --git a/src/mod/languages/mod_lua/freeswitch.i b/src/mod/languages/mod_lua/freeswitch.i
index 383580103f..54bdb7bdc9 100644
--- a/src/mod/languages/mod_lua/freeswitch.i
+++ b/src/mod/languages/mod_lua/freeswitch.i
@@ -19,8 +19,15 @@
 
 
 /* Lua function typemap */
-%typemap(in,checkfn="lua_isfunction") SWIGLUA_FN
-%{  $1.L=L; $1.idx=$input; %}
+%typemap(in, checkfn = "lua_isfunction") SWIGLUA_FN {
+  $1.L = L;
+  $1.idx = $input;
+}
+
+%typemap(default) SWIGLUA_FN {
+  SWIGLUA_FN default_swiglua_fn = { 0 };
+  $1 = default_swiglua_fn;
+}
 
 
 %ignore SwitchToMempool;   
diff --git a/src/mod/languages/mod_lua/freeswitch_lua.cpp b/src/mod/languages/mod_lua/freeswitch_lua.cpp
index 17d12bc1cb..d60ae737a8 100644
--- a/src/mod/languages/mod_lua/freeswitch_lua.cpp
+++ b/src/mod/languages/mod_lua/freeswitch_lua.cpp
@@ -367,10 +367,15 @@ int Dbh::query_callback(void *pArg, int argc, char **argv, char **cargv)
 bool Dbh::query(char *sql, SWIGLUA_FN lua_fun)
 {
   if (connected) {
-    if (switch_cache_db_execute_sql_callback(dbh, sql, query_callback, &lua_fun, NULL) == SWITCH_STATUS_SUCCESS) {
-      return true;
+    if (lua_fun.L) {
+      if (switch_cache_db_execute_sql_callback(dbh, sql, query_callback, &lua_fun, NULL) == SWITCH_STATUS_SUCCESS) {
+        return true;
+      }
+    } else { /* if no lua_fun arg is passed from Lua, an empty initialized struct will be sent - see freeswitch.i */
+      if (switch_cache_db_execute_sql(dbh, sql, NULL) == SWITCH_STATUS_SUCCESS) {
+        return true;
+      }
     }
   }
-  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no workie workie :(\n");
   return false;
 }
diff --git a/src/mod/languages/mod_lua/mod_lua.cpp b/src/mod/languages/mod_lua/mod_lua.cpp
index 3ccbef5aaa..cf9b373ce0 100644
--- a/src/mod/languages/mod_lua/mod_lua.cpp
+++ b/src/mod/languages/mod_lua/mod_lua.cpp
@@ -588,7 +588,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_lua_load)
 
 	SWITCH_ADD_API(api_interface, "luarun", "run a script", luarun_api_function, "