diff --git a/.gitignore b/.gitignore index 41b0907f48..3b82069a68 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.lo *.a *.la +*.loT .libs .deps .\#* @@ -70,3 +71,19 @@ configure.lineno /scripts/gentls_cert /a.out.dSYM /freeswitch-sounds-* +src/mod/applications/mod_easyroute/Makefile +src/mod/applications/mod_lcr/Makefile +src/mod/applications/mod_nibblebill/Makefile +src/mod/applications/mod_rss/Makefile +src/mod/applications/mod_snipe_hunt/Makefile +src/mod/codecs/mod_dahdi_codec/Makefile +src/mod/dialplans/mod_dialplan_directory/Makefile +src/mod/formats/mod_shell_stream/Makefile +src/mod/say/mod_say_de/Makefile +src/mod/say/mod_say_es/Makefile +src/mod/say/mod_say_fr/Makefile +src/mod/say/mod_say_it/Makefile +src/mod/say/mod_say_nl/Makefile +src/mod/say/mod_say_th/Makefile +src/mod/say/mod_say_zh/Makefile +libs/curl/lib/ca-bundle.h diff --git a/Freeswitch.2008.express.sln b/Freeswitch.2008.express.sln index 5d298734c8..e621622630 100644 --- a/Freeswitch.2008.express.sln +++ b/Freeswitch.2008.express.sln @@ -613,6 +613,24 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_valet_parking", "src\mo {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download JSON", "libs\win32\Download JSON.2008.vcproj", "{B808178B-82F0-4CF4-A2B1-921939FA24D0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjson", "libs\win32\json\libjson.2008.vcproj", "{9778F1C0-09BC-4698-8EBC-BD982247209A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_curl", "src\mod\applications\mod_curl\mod_curl.2008.vcproj", "{EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}" + ProjectSection(ProjectDependencies) = postProject + {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} + {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588} + {9778F1C0-09BC-4698-8EBC-BD982247209A} = {9778F1C0-09BC-4698-8EBC-BD982247209A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_json_cdr", "src\mod\event_handlers\mod_json_cdr\mod_json_cdr.2008.vcproj", "{EBE7452D-B3F7-4798-8EED-A0DDE2D738F5}" + ProjectSection(ProjectDependencies) = postProject + {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} + {87EE9DA4-DE1E-4448-8324-183C98DCA588} = {87EE9DA4-DE1E-4448-8324-183C98DCA588} + {9778F1C0-09BC-4698-8EBC-BD982247209A} = {9778F1C0-09BC-4698-8EBC-BD982247209A} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Win32 = All|Win32 @@ -1602,7 +1620,6 @@ Global {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|Win32.Build.0 = Release|Win32 {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.All|x64.ActiveCfg = Release|Win32 {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|Win32.ActiveCfg = Debug|Win32 - {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|Win32.Build.0 = Debug|Win32 {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64.ActiveCfg = Debug|Win32 {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Debug|x64.Build.0 = Debug|Win32 {D5D2BF72-29FE-4982-A9FA-82AB2086DB1B}.Release|Win32.ActiveCfg = Release|Win32 @@ -2002,6 +2019,31 @@ Global {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|Win32.Build.0 = Release|Win32 {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|x64.ActiveCfg = Release|x64 {432DB165-1EB2-4781-A9C0-71E62610B20A}.Release|x64.Build.0 = Release|x64 + {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|Win32.ActiveCfg = Release|Win32 + {B808178B-82F0-4CF4-A2B1-921939FA24D0}.All|x64.ActiveCfg = Release|Win32 + {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|Win32.ActiveCfg = Debug|Win32 + {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|Win32.Build.0 = Debug|Win32 + {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Debug|x64.ActiveCfg = Debug|Win32 + {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|Win32.ActiveCfg = Release|Win32 + {B808178B-82F0-4CF4-A2B1-921939FA24D0}.Release|x64.ActiveCfg = Release|Win32 + {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|Win32.ActiveCfg = Release|Win32 + {9778F1C0-09BC-4698-8EBC-BD982247209A}.All|x64.ActiveCfg = Release|Win32 + {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|Win32.ActiveCfg = Debug|Win32 + {9778F1C0-09BC-4698-8EBC-BD982247209A}.Debug|x64.ActiveCfg = Debug|Win32 + {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|Win32.ActiveCfg = Release|Win32 + {9778F1C0-09BC-4698-8EBC-BD982247209A}.Release|x64.ActiveCfg = Release|Win32 + {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|Win32.ActiveCfg = Release|Win32 + {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.All|x64.ActiveCfg = Release|Win32 + {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|Win32.ActiveCfg = Debug|Win32 + {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Debug|x64.ActiveCfg = Debug|Win32 + {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|Win32.ActiveCfg = Release|Win32 + {EF300386-A8DF-4372-B6D8-FB9BFFCA9AED}.Release|x64.ActiveCfg = Release|Win32 + {EBE7452D-B3F7-4798-8EED-A0DDE2D738F5}.All|Win32.ActiveCfg = Release|Win32 + {EBE7452D-B3F7-4798-8EED-A0DDE2D738F5}.All|x64.ActiveCfg = Release|Win32 + {EBE7452D-B3F7-4798-8EED-A0DDE2D738F5}.Debug|Win32.ActiveCfg = Debug|Win32 + {EBE7452D-B3F7-4798-8EED-A0DDE2D738F5}.Debug|x64.ActiveCfg = Debug|Win32 + {EBE7452D-B3F7-4798-8EED-A0DDE2D738F5}.Release|Win32.ActiveCfg = Release|Win32 + {EBE7452D-B3F7-4798-8EED-A0DDE2D738F5}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/bootstrap.sh b/bootstrap.sh index 861ce6c918..f4da83706f 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -4,7 +4,7 @@ echo "bootstrap: checking installation..." BASEDIR=`pwd`; LIBDIR=${BASEDIR}/libs; SUBDIRS="ilbc curl iksemel js js/nsprpub libdingaling libedit libsndfile pcre sofia-sip \ - speex sqlite srtp openzap 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"; if [ ! -f modules.conf ]; then cp build/modules.conf.in modules.conf @@ -22,7 +22,7 @@ ac_version=`${AUTOCONF:-autoconf} --version 2>/dev/null|sed -e 's/^[^0-9]*//;s/[ if test -z "$ac_version"; then echo "bootstrap: autoconf not found." echo " You need autoconf version 2.59 or newer installed" -echo " to build FreeSWITCH from SVN." +echo " to build FreeSWITCH from source." exit 1 fi @@ -37,7 +37,7 @@ IFS=.; set $ac_version; IFS=' ' if test "$1" = "2" -a "$2" -lt "59" || test "$1" -lt "2"; then echo "bootstrap: autoconf version $ac_version found." echo " You need autoconf version 2.59 or newer installed" -echo " to build FreeSWITCH from SVN." +echo " to build FreeSWITCH from source." exit 1 else echo "bootstrap: autoconf version $ac_version (ok)" @@ -50,7 +50,7 @@ am_version=`${AUTOMAKE:-automake} --version 2>/dev/null|sed -e 's/^[^0-9]*//;s/[ if test -z "$am_version"; then echo "bootstrap: automake not found." echo " You need automake version 1.7 or newer installed" -echo " to build FreeSWITCH from SVN." +echo " to build FreeSWITCH from source." exit 1 fi IFS=_; set $am_version; IFS=' ' @@ -59,7 +59,7 @@ IFS=.; set $am_version; IFS=' ' if test "$1" = "1" -a "$2" -lt "7"; then echo "bootstrap: automake version $am_version found." echo " You need automake version 1.7 or newer installed" -echo " to build FreeSWITCH from SVN." +echo " to build FreeSWITCH from source." exit 1 else echo "bootstrap: automake version $am_version (ok)" @@ -71,7 +71,7 @@ acl_version=`${ACLOCAL:-aclocal} --version 2>/dev/null|sed -e 's/^[^0-9]*//;s/[a if test -z "$acl_version"; then echo "bootstrap: aclocal not found." echo " You need aclocal version 1.7 or newer installed" -echo " to build FreeSWITCH from SVN." +echo " to build FreeSWITCH from source." exit 1 fi IFS=_; set $acl_version; IFS=' ' @@ -80,7 +80,7 @@ IFS=.; set $acl_version; IFS=' ' if test "$1" = "1" -a "$2" -lt "7"; then echo "bootstrap: aclocal version $acl_version found." echo " You need aclocal version 1.7 or newer installed" -echo " to build FreeSWITCH from SVN." +echo " to build FreeSWITCH from source." exit 1 else echo "bootstrap: aclocal version $acl_version (ok)" @@ -96,7 +96,7 @@ libtool=${LIBTOOL:-`${LIBDIR}/apr/build/PrintPath glibtool libtool libtool22 lib lt_pversion=`$libtool --version 2>/dev/null|sed -e 's/([^)]*)//g;s/^[^0-9]*//;s/[- ].*//g;q'` if test -z "$lt_pversion"; then echo "bootstrap: libtool not found." - echo " You need libtool version 1.5.14 or newer to build FreeSWITCH from SVN." + echo " You need libtool version 1.5.14 or newer to build FreeSWITCH from source." exit 1 fi lt_version=`echo $lt_pversion|sed -e 's/\([a-z]*\)$/.\1/'` @@ -121,7 +121,7 @@ if test $lt_status = "good"; then echo "bootstrap: libtool version $lt_pversion (ok)" else echo "bootstrap: libtool version $lt_pversion found." - echo " You need libtool version 1.5.14 or newer to build FreeSWITCH from SVN." + echo " You need libtool version 1.5.14 or newer to build FreeSWITCH from source." exit 1 fi diff --git a/conf/dialplan/skinny-patterns.xml b/conf/dialplan/skinny-patterns.xml new file mode 100644 index 0000000000..a78b83bdc7 --- /dev/null +++ b/conf/dialplan/skinny-patterns.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + diff --git a/conf/dialplan/skinny-patterns/20-Demo.xml b/conf/dialplan/skinny-patterns/20-Demo.xml new file mode 100644 index 0000000000..0246fe29a4 --- /dev/null +++ b/conf/dialplan/skinny-patterns/20-Demo.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/conf/dialplan/skinny-patterns/20-Local_extension.xml b/conf/dialplan/skinny-patterns/20-Local_extension.xml new file mode 100644 index 0000000000..488d740790 --- /dev/null +++ b/conf/dialplan/skinny-patterns/20-Local_extension.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/conf/dialplan/skinny-patterns/90-External.xml b/conf/dialplan/skinny-patterns/90-External.xml new file mode 100644 index 0000000000..706bf74027 --- /dev/null +++ b/conf/dialplan/skinny-patterns/90-External.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/conf/dialplan/skinny-patterns/99-Default_Drop.xml b/conf/dialplan/skinny-patterns/99-Default_Drop.xml new file mode 100644 index 0000000000..897fd8fb94 --- /dev/null +++ b/conf/dialplan/skinny-patterns/99-Default_Drop.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/conf/sip_profiles/internal.xml b/conf/sip_profiles/internal.xml index eda248626e..2196eff20d 100644 --- a/conf/sip_profiles/internal.xml +++ b/conf/sip_profiles/internal.xml @@ -207,6 +207,11 @@ + + + + + diff --git a/conf/skinny_profiles/internal.xml b/conf/skinny_profiles/internal.xml index 00ce803493..eaa493c047 100644 --- a/conf/skinny_profiles/internal.xml +++ b/conf/skinny_profiles/internal.xml @@ -3,6 +3,8 @@ + + @@ -10,5 +12,10 @@ + + + + + diff --git a/configure.in b/configure.in index 16ba3e6999..23ff3d5680 100644 --- a/configure.in +++ b/configure.in @@ -954,6 +954,7 @@ AC_CONFIG_SUBDIRS([libs/sofia-sip]) AC_CONFIG_SUBDIRS([libs/speex]) AC_CONFIG_SUBDIRS([libs/portaudio]) AC_CONFIG_SUBDIRS([libs/openzap]) +AC_CONFIG_SUBDIRS([libs/freetdm]) AC_CONFIG_SUBDIRS([libs/unimrcp]) AC_CONFIG_SUBDIRS([libs/tiff-3.8.2]) AC_CONFIG_SUBDIRS([libs/spandsp]) diff --git a/debian/freeswitch.conffiles b/debian/freeswitch.conffiles index 7f06d05c00..a9cd17804b 100644 --- a/debian/freeswitch.conffiles +++ b/debian/freeswitch.conffiles @@ -48,6 +48,11 @@ /opt/freeswitch/conf/dialplan/features.xml /opt/freeswitch/conf/dialplan/public/00_inbound_did.xml /opt/freeswitch/conf/dialplan/public.xml +/opt/freeswitch/conf/dialplan/skinny-patterns/20-Demo.xml +/opt/freeswitch/conf/dialplan/skinny-patterns/99-Default_Drop.xml +/opt/freeswitch/conf/dialplan/skinny-patterns/20-Local_extension.xml +/opt/freeswitch/conf/dialplan/skinny-patterns/90-External.xml +/opt/freeswitch/conf/dialplan/skinny-patterns.xml /opt/freeswitch/conf/directory/default/1000.xml /opt/freeswitch/conf/directory/default/1001.xml /opt/freeswitch/conf/directory/default/1002.xml @@ -87,6 +92,7 @@ /opt/freeswitch/conf/sip_profiles/internal/example.xml /opt/freeswitch/conf/sip_profiles/internal-ipv6.xml /opt/freeswitch/conf/sip_profiles/internal.xml +/opt/freeswitch/conf/skinny_profiles/internal.xml /opt/freeswitch/conf/tetris.ttml /opt/freeswitch/conf/tones.conf /opt/freeswitch/conf/vars.xml diff --git a/debian/freeswitch.install b/debian/freeswitch.install index 421e2a2286..820039c806 100644 --- a/debian/freeswitch.install +++ b/debian/freeswitch.install @@ -55,6 +55,11 @@ opt/freeswitch/conf/dialplan/default.xml opt/freeswitch/conf/dialplan/features.xml opt/freeswitch/conf/dialplan/public/00_inbound_did.xml opt/freeswitch/conf/dialplan/public.xml +opt/freeswitch/conf/dialplan/skinny-patterns/20-Demo.xml +opt/freeswitch/conf/dialplan/skinny-patterns/99-Default_Drop.xml +opt/freeswitch/conf/dialplan/skinny-patterns/20-Local_extension.xml +opt/freeswitch/conf/dialplan/skinny-patterns/90-External.xml +opt/freeswitch/conf/dialplan/skinny-patterns.xml opt/freeswitch/conf/directory/default/1000.xml opt/freeswitch/conf/directory/default/1001.xml opt/freeswitch/conf/directory/default/1002.xml @@ -95,6 +100,7 @@ opt/freeswitch/conf/sip_profiles/external.xml opt/freeswitch/conf/sip_profiles/internal/example.xml opt/freeswitch/conf/sip_profiles/internal-ipv6.xml opt/freeswitch/conf/sip_profiles/internal.xml +opt/freeswitch/conf/skinny_profiles/internal.xml opt/freeswitch/conf/tetris.ttml opt/freeswitch/conf/tones.conf opt/freeswitch/conf/vars.xml @@ -139,6 +145,7 @@ opt/freeswitch/mod/mod_portaudio.so* opt/freeswitch/mod/mod_rss.so* opt/freeswitch/mod/mod_shout.so* opt/freeswitch/mod/mod_siren.so* +opt/freeswitch/mod/mod_skinny.so* opt/freeswitch/mod/mod_skypopen.so* opt/freeswitch/mod/mod_sndfile.so* opt/freeswitch/mod/mod_snom.so* diff --git a/debian/rules b/debian/rules index 409f6473ec..f2c57ea95a 100755 --- a/debian/rules +++ b/debian/rules @@ -20,7 +20,8 @@ export DIALPLANS_MODULES=dialplans/mod_dialplan_asterisk dialplans/mod_dialplan_ export DIRECTORIES_MODULES= export DOTNET_MODULES= export ENDPOINTS_MODULES=endpoints/mod_dingaling endpoints/mod_portaudio endpoints/mod_sofia \ - endpoints/mod_loopback ../../libs/openzap/mod_openzap endpoints/mod_skypopen + endpoints/mod_loopback ../../libs/openzap/mod_openzap endpoints/mod_skypopen \ + 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 diff --git a/docs/ChangeLog b/docs/ChangeLog index eb93bd70ff..28ab06c2ec 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -1,3 +1,20 @@ +freeswitch (1.0.7) + + config: move limit.conf to db.conf + libesl: Fix potential race condition (ESL-36) + mod_db: fix stack corruption (MODAPP-407) + mod_tts_commandline: fix core dump, temp file problem. flush can be called several times (FSMOD-35) + mod_lcr: Expand variables (MODAPP-418) + mod_sofia: Send SIP MESSAGE to unregistered users by prefixing sip: to user@domain + mod_sofia: fix callee being updated with callee information + + +freeswitch (1.0.6) + + all: migrate to git + core: add ... and shutdown as a fail-safe when no modules are loaded + core: fix high mem usage during shutdown + freeswitch (1.0.5) all: run indent on the whole tree and update copyright dates in prep for 1.0.5 (r:16579) @@ -50,6 +67,7 @@ freeswitch (1.0.5) build: Remove libuuid from tree (r:16072) build: Avoid building static version of modules (e.g. mod_enum.a) by adding the "-shared" libtool option. (r:16225) build: Fix pidfile path in debian init script (FSBUILD-264/r:17040) + build: Numerous debian improvements (r:17119) config: improvements to French language handling (MODASRTTS-20/r:14911) config: Add valet_parking to default config (r:15124) config: Add valet macros (r:15156) @@ -66,6 +84,7 @@ freeswitch (1.0.5) config: Allow specifying auth-scheme in config (r:16350/MDXMLINT-56) config: Improvements to french lang (FSCONFIG-18/r:16585) config: Add new English sounds, sound prompts (r:16911) + config: Improvements to French sound prompts (FSCONFIG-23/r:17118) core: Add per-call logging (r:14509) core: Fix IVR menu timeout when caller presses no digits (DP-4/r:14548) core: re-factor node allocation and make a copy of userdata in case the session gets killed before the logger module gets the node (r:14555) @@ -253,6 +272,9 @@ freeswitch (1.0.5) core: Break the loop in switch_ivr_parse_all_events() if CF_BREAK flag has been set (FSCORE-577/r:17074) core: Fix memory leak caused by the function switch_core_codec_copy (FSCORE-579/r:17105) core: add sanity check to project size of decoded codec data (r:17108) + core: handle some errors on missing db handle conditions (r:17136) + core: Fix warning message (FSCORE-578) + core: add switch_channel_export_variable docs: Add large Doxygen update (thanks Muhammed Shahzad) (r:14973) docs: update es phrase file (MODAPP-317/r:15575) embedded_languages: Prevent unloading of embedded languages modules (also fixes MODLANG-121/r:14491) @@ -387,6 +409,7 @@ freeswitch (1.0.5) mod_dptools: Fix bypass_media ignored in dial string (DP-14/r:16588) mod_dptools: add param setting function to asr (r:16600) mod_dptools: add action='user_call' to xml_curl lookups for the user endpoint (r:17115) + mod_enum: fix mod_enum build when udns is already on the base system mod_erlang_event: Add support for simply sending an arbitrary message to an arbitrary registered process at a node (r:14875) mod_erlang_event: Deprecate new_pid message in favor of get_pid which has an extra element, the call's UUID (r:14877) mod_erlang_event: optionally allow compatibility with nodes running older OTP releases (R7 through current) (r:15189) @@ -455,6 +478,7 @@ freeswitch (1.0.5) mod_memcache: update to libmemcached 0.32 (r:14935) mod_memcache: add --with-memcached=no to libmemcached configure (r:14938) mod_nibblebill: Support custom sql with var expansion (MODAPP-409/r:17081) + mod_nibblebill: Fix url (FSCORE-580/r:17129) mod_opal: Added setting of outgoing number and display name from extension number so H.323/Q.931 fields are set correctly in ALERTING and CONNECT messages sent for incoming calls.(r:14900) mod_opal: Fixed compile issues with latest Opal (r:15545) mod_portaudio: fix compilation failure in mod_portaudio_stream (MODFORM-35/r:14531) @@ -624,6 +648,7 @@ freeswitch (1.0.5) mod_sofia: prevent race in killgw followed by an immediate rescan with the same gateway name (r:17096) mod_sofia: fix telephone-event negotiation with devices that don't do what the rfc says they SHOULD do (r:17097) mod_sofia: Double @ in To header (MODENDP-300/r:17098) + mod_sofia: add killgw _all_ to delete all gws mod_spidermonkey: allow inline javascript, use a ~ as first script character (r:15598) mod_spidermonkey: fix mod_spidermonkey on OSX 10.6 (lets see if this breaks any other platforms) (r:15650) mod_spidermonkey: fix teletone issues in javascript (MODLANG-159/MODLANG-162/r:16909) diff --git a/freeswitch.spec b/freeswitch.spec index 7f4212b50b..3522c8c0d0 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -9,8 +9,8 @@ Name: freeswitch Summary: FreeSWITCH open source telephony platform License: MPL Group: Productivity/Telephony/Servers -Version: 1.0.4 -Release: 1 +Version: 1.0.7 +Release: trunk URL: http://www.freeswitch.org/ Packager: Michal Bielicki Vendor: http://www.freeswitch.org/ @@ -355,6 +355,7 @@ fi %dir %attr(0750, freeswitch, daemon) %{prefix}/conf %dir %attr(0750, freeswitch, daemon) %{prefix}/conf/autoload_configs %dir %attr(0750, freeswitch, daemon) %{prefix}/conf/dialplan +%dir %attr(0750, freeswitch, daemon) %{prefix}/conf/dialplan/skinny-patterns %dir %attr(0750, freeswitch, daemon) %{prefix}/conf/directory %dir %attr(0750, freeswitch, daemon) %{prefix}/conf/directory/default %dir %attr(0750, freeswitch, daemon) %{prefix}/conf/lang @@ -430,6 +431,7 @@ fi %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 %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/directory/*.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/directory/default/* %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/ivr_menus/*.xml @@ -614,6 +616,9 @@ fi %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/lang/ru/dir/*.xml %changelog +* Fr Apr 23 2010 - michal.bielicki@seventhsignal.de +- bumped spec file vrersion up to 1.0.7-trunk for trunk +- added skinny dialplan stuff to specfile * Sun Mar 28 2010 - michal.bielicki@seventhsignal.de - added sangoma codec config file * Wed Dec 02 2009 - michal.bielicki@seventhsignal.de diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 356eba5cb8..f00e7988e3 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -2050,6 +2050,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co case FTDM_COMMAND_SET_RX_GAIN: { + if (!FTDM_IS_VOICE_CHANNEL(ftdmchan)) { + ftdm_log(FTDM_LOG_ERROR, "Cannot set rx gain in non-voice channel of type: %s\n", ftdm_chan_type2str(ftdmchan->type)); + GOTO_STATUS(done, FTDM_FAIL); + } ftdmchan->rxgain = FTDM_COMMAND_OBJ_FLOAT; reset_gain_table(ftdmchan->rxgain_table, ftdmchan->rxgain, ftdmchan->native_codec); if (ftdmchan->rxgain == 0.0) { @@ -2068,6 +2072,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co break; case FTDM_COMMAND_SET_TX_GAIN: { + if (!FTDM_IS_VOICE_CHANNEL(ftdmchan)) { + ftdm_log(FTDM_LOG_ERROR, "Cannot set tx gain in non-voice channel of type: %s\n", ftdm_chan_type2str(ftdmchan->type)); + GOTO_STATUS(done, FTDM_FAIL); + } ftdmchan->txgain = FTDM_COMMAND_OBJ_FLOAT; reset_gain_table(ftdmchan->txgain_table, ftdmchan->txgain, ftdmchan->native_codec); if (ftdmchan->txgain == 0.0) { @@ -2468,17 +2476,17 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "ftdmchan is null\n"); ftdm_assert_return(ftdmchan->fio != NULL, FTDM_FAIL, "No I/O module attached to ftdmchan\n"); - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) { + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "channel not open"); - return FTDM_FAIL; - } + return FTDM_FAIL; + } if (!ftdmchan->fio->read) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented"); return FTDM_FAIL; } - status = ftdmchan->fio->read(ftdmchan, data, datalen); + status = ftdmchan->fio->read(ftdmchan, data, datalen); if (ftdmchan->fds[0] > -1) { int dlen = (int) *datalen; if (write(ftdmchan->fds[0], data, dlen) != dlen) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c index f788de3f71..f2270a0daa 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c @@ -688,13 +688,13 @@ static void handle_call_start_ack(sangomabc_connection_t *mcon, sangomabc_short_ if (ftdmchan->state == FTDM_CHANNEL_STATE_UP || ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA || ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS) { - ftdm_log(FTDM_LOG_CRIT, "ZCHAN CALL ACK STATE UP -> Changed to TERMINATING %d:%d\n", event->span+1,event->chan+1); + ftdm_log(FTDM_LOG_CRIT, "FTDMCHAN CALL ACK STATE UP -> Changed to TERMINATING %d:%d\n", event->span+1,event->chan+1); ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r); } else if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP || ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) { - ftdm_log(FTDM_LOG_CRIT, "ZCHAN CALL ACK STATE HANGUP -> Changed to HANGUP COMPLETE %d:%d\n", event->span+1,event->chan+1); + ftdm_log(FTDM_LOG_CRIT, "FTDMCHAN CALL ACK STATE HANGUP -> Changed to HANGUP COMPLETE %d:%d\n", event->span+1,event->chan+1); ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, 0, r); } else { - ftdm_log(FTDM_LOG_CRIT, "ZCHAN STATE INVALID State %s on IN CALL ACK %d:%d\n", + ftdm_log(FTDM_LOG_CRIT, "FTDMCHAN STATE INVALID State %s on IN CALL ACK %d:%d\n", ftdm_channel_state2str(ftdmchan->state),event->span+1,event->chan+1); } ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG); @@ -814,7 +814,9 @@ static void handle_call_start_nack(ftdm_span_t *span, sangomabc_connection_t *mc if (sangoma_boost_data->sigmod) { ftdmchan = OUTBOUND_REQUESTS[event->call_setup_id].ftdmchan; CALL_DATA(ftdmchan)->last_event_id = event->event_id; + CALL_DATA(ftdmchan)->call_setup_id = event->call_setup_id; ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + ftdm_clear_sflag_locked(ftdmchan, SFLAG_SENT_FINAL_MSG); } else { sangomabc_exec_command(mcon, 0, @@ -856,7 +858,7 @@ static void handle_call_start_nack(ftdm_span_t *span, sangomabc_connection_t *mc sangomabc_exec_command(mcon, event->span, event->chan, - 0, + event->call_setup_id, SIGBOOST_EVENT_CALL_START_NACK_ACK, 0, 0); } @@ -1001,23 +1003,26 @@ static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, s if (ftdmchan->state == FTDM_CHANNEL_STATE_UP || ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA || ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS) { - ftdm_log(FTDM_LOG_CRIT, "ZCHAN STATE UP -> Changed to TERMINATING %d:%d\n", event->span+1,event->chan+1); + ftdm_log(FTDM_LOG_CRIT, "s%dc%d:FTDMCHAN STATE UP -> Changed to TERMINATING\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event)); ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r); } else if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP || ftdm_test_sflag(ftdmchan, SFLAG_HANGUP)) { - ftdm_log(FTDM_LOG_CRIT, "ZCHAN STATE HANGUP -> Changed to HANGUP COMPLETE %d:%d\n", event->span+1,event->chan+1); + ftdm_log(FTDM_LOG_CRIT, "s%dc%d:FTDMCHAN STATE HANGUP -> Changed to HANGUP COMPLETE\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event)); ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, 0, r); + } else if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) { + ftdm_log(FTDM_LOG_WARNING, "s%dc%d:Collision, hanging up incoming call\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event)); + ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING, 0, r); } else { - ftdm_log(FTDM_LOG_CRIT, "ZCHAN STATE INVALID %s on IN CALL %d:%d\n", ftdm_channel_state2str(ftdmchan->state),event->span+1,event->chan+1); + ftdm_log(FTDM_LOG_CRIT, "s%dc%d:FTDMCHAN STATE INVALID %s on IN CALL\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event), ftdm_channel_state2str(ftdmchan->state)); } ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG); ftdmchan = NULL; } - ftdm_log(FTDM_LOG_CRIT, "START CANT FIND CHAN %d:%d\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event)); + ftdm_log(FTDM_LOG_CRIT, "s%dc%d:START CANT FIND CHAN\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event)); goto error; } if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_CRIT, "START CANT OPEN CHAN %d:%d\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event)); + ftdm_log(FTDM_LOG_CRIT, "s%dc%d:START CANT OPEN CHAN\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event)); goto error; } @@ -1071,7 +1076,7 @@ static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, s sangomabc_exec_command(mcon, event->span, event->chan, - 0, + event->call_setup_id, SIGBOOST_EVENT_CALL_START_NACK, hangup_cause, 0); @@ -1304,6 +1309,8 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon, if (event->call_setup_id) { nack_map[event->call_setup_id] = 0; release_request_id(event->call_setup_id); + } else { + handle_call_done(span, mcon, event); } break; case SIGBOOST_EVENT_INSERT_CHECK_LOOP: @@ -1372,7 +1379,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) sangomabc_exec_command(mcon, BOOST_SPAN(ftdmchan), BOOST_CHAN(ftdmchan), - 0, + CALL_DATA(ftdmchan)->call_setup_id, SIGBOOST_EVENT_CALL_START_NACK_ACK, 0, 0); @@ -1823,7 +1830,7 @@ static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj) } if (ftdm_boost_connection_open(span) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "ftdm_boost_connection_open failed\n"); + ftdm_log(FTDM_LOG_CRIT, "ftdm_boost_connection_open failed\n"); goto end; } @@ -1867,10 +1874,6 @@ static void *ftdm_sangoma_boost_run(ftdm_thread_t *me, void *obj) check_state(span); } - goto end; - - ftdm_log(FTDM_LOG_CRIT, "Boost event processing Error!\n"); - end: if (!sangoma_boost_data->sigmod) { sangomabc_connection_close(&sangoma_boost_data->mcon); @@ -1917,13 +1920,17 @@ static int sigmod_ss7box_isup_exec_cmd(ftdm_stream_handle_t *stream, char *cmd) static void ftdm_cli_span_state_cmd(ftdm_span_t *span, char *state) { - int j; + unsigned int j; int cnt=0; + ftdm_channel_state_t state_e = ftdm_str2ftdm_channel_state(state); + if (state_e == FTDM_CHANNEL_STATE_INVALID) { + ftdm_log(FTDM_LOG_CRIT, "Checking for channels not in the INVALID state is probably not waht you want\n"); + } for(j = 1; j <= span->chan_count; j++) { - if (span->channels[j]->state != FTDM_CHANNEL_STATE_DOWN) { + if (span->channels[j]->state != state_e) { ftdm_channel_t *ftdmchan = span->channels[j]; ftdm_log(FTDM_LOG_CRIT, "Channel %i s%dc%d State=%s\n", - j,ftdmchan->physical_span_id-1,ftdmchan->physical_chan_id-1,ftdm_channel_state2str(ftdmchan->state)); + j, ftdmchan->physical_span_id-1, ftdmchan->physical_chan_id-1, ftdm_channel_state2str(ftdmchan->state)); cnt++; } } @@ -1986,6 +1993,7 @@ static FIO_API_FUNCTION(ftdm_sangoma_boost_api) #endif } else if (!strcasecmp(argv[0], "span")) { + int err; sangomabc_connection_t *pcon; ftdm_sangoma_boost_data_t *sangoma_boost_data; ftdm_span_t *span; @@ -1995,7 +2003,7 @@ static FIO_API_FUNCTION(ftdm_sangoma_boost_api) goto done; } - int err = ftdm_span_find_by_name(argv[1], &span); + err = ftdm_span_find_by_name(argv[1], &span); if (FTDM_SUCCESS != err) { stream->write_function(stream, "-ERR failed to find span by name %s\n",argv[1]); goto done; @@ -2132,23 +2140,23 @@ static ftdm_status_t ftdm_sangoma_boost_start(ftdm_span_t *span) static ftdm_status_t ftdm_sangoma_boost_stop(ftdm_span_t *span) { - int cnt = 10; ftdm_status_t status = FTDM_SUCCESS; ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data; if (sangoma_boost_data->sigmod) { - - /* FIXME: we should make sure the span thread is stopped (use pthread_kill or freetdm thread kill function) */ /* I think stopping the span before destroying the queue makes sense otherwise may be boost events would still arrive when the queue is already destroyed! */ status = sangoma_boost_data->sigmod->stop_span(span); ftdm_queue_enqueue(sangoma_boost_data->boost_queue, NULL); - while(ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING) && cnt-- > 0) { - ftdm_log(FTDM_LOG_DEBUG, "Waiting for boost thread\n"); - ftdm_sleep(500); - } + } + + while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING)) { + ftdm_log(FTDM_LOG_DEBUG, "Waiting for boost thread\n"); + ftdm_sleep(100); + } + + if (sangoma_boost_data->sigmod) { ftdm_queue_destroy(&sangoma_boost_data->boost_queue); - return status; } return status; } @@ -2443,7 +2451,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span) ftdm_dso_lib_t lib = NULL; char path[255] = ""; char *err = NULL; - int j = 0; + unsigned int j = 0; unsigned paramindex = 0; ftdm_status_t rc = FTDM_SUCCESS; diff --git a/libs/freetdm/src/include/ftdm_types.h b/libs/freetdm/src/include/ftdm_types.h index bf7720efd1..a4f4eda047 100644 --- a/libs/freetdm/src/include/ftdm_types.h +++ b/libs/freetdm/src/include/ftdm_types.h @@ -383,7 +383,8 @@ typedef enum { } ftdm_channel_state_t; #define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \ "RING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \ - "RESTART", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", "HANGUP", "HANGUP_COMPLETE", "INVALID" + "RESTART", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \ + "HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "INVALID" FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t) typedef enum { diff --git a/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c b/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c index 15803017b5..e1552a9b77 100644 --- a/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c +++ b/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c @@ -978,7 +978,7 @@ ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event) ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event) { uint32_t i, event_id = 0; - zap_oob_event_t zt_event_id = 0; + zt_event_t zt_event_id = 0; for(i = 1; i <= span->chan_count; i++) { if (zap_test_flag(span->channels[i], ZAP_CHANNEL_EVENT)) { diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c index 9ea45131a5..867ca7a79d 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c +++ b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp.c @@ -1469,7 +1469,7 @@ int sdp_media_cmp(sdp_media_t const *a, sdp_media_t const *b) if (a->m_proto != b->m_proto) return a->m_proto < b->m_proto ? -1 : 1; - if (a->m_proto == sdp_media_x) + if (a->m_proto == sdp_proto_x) if ((rv = su_strcmp(a->m_proto_name, b->m_proto_name))) return rv; diff --git a/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2008.vcproj b/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2008.vcproj index 29dcd35d94..d77441afa5 100644 --- a/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2008.vcproj +++ b/libs/unimrcp/libs/apr-toolkit/aprtoolkit.2008.vcproj @@ -133,6 +133,8 @@ "" Then VERSION = strVerRev diff --git a/src/include/switch.h b/src/include/switch.h index 7e93646e29..2b007d2425 100644 --- a/src/include/switch.h +++ b/src/include/switch.h @@ -116,6 +116,7 @@ #include "switch_utils.h" #include "switch_caller.h" #include "switch_frame.h" +#include "switch_rtcp_frame.h" #include "switch_module_interfaces.h" #include "switch_channel.h" #include "switch_buffer.h" diff --git a/src/include/switch_rtcp_frame.h b/src/include/switch_rtcp_frame.h new file mode 100644 index 0000000000..1c718a089f --- /dev/null +++ b/src/include/switch_rtcp_frame.h @@ -0,0 +1,74 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2009, 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 / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Sherwin Sim + * + * + * switch_rtcp_frame.h -- RTCP Frame Structure + * + */ +/*! \file switch_rtcp_frame.h + \brief RTCP Frame Structure +*/ + +#ifndef SWITCH_RTCP_FRAME_H +#define SWITCH_RTCP_FRAME_H + +#include + +SWITCH_BEGIN_EXTERN_C +/*! \brief An abstraction of a rtcp frame */ + struct switch_rtcp_frame { + + uint16_t report_count; + + uint16_t packet_type; + + uint32_t ssrc; + + uint32_t ntp_msw; + + uint32_t ntp_lsw; + + uint32_t timestamp; + + uint32_t packet_count; + + uint32_t octect_count; + +}; + +SWITCH_END_EXTERN_C +#endif +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index e3098d0035..8e0693cdc1 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -41,6 +41,7 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_RTP_MAX_BUF_LEN 16384 +#define SWITCH_RTCP_MAX_BUF_LEN 16384 #define SWITCH_RTP_MAX_CRYPTO_LEN 64 #define SWITCH_RTP_KEY_LEN 30 #define SWITCH_RTP_CRYPTO_KEY_32 "AES_CM_128_HMAC_SHA1_32" @@ -167,7 +168,7 @@ SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host, \param port the remote port \param err pointer for error messages */ -SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, +SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, switch_port_t remote_rtcp_port, switch_bool_t change_adv_addr, const char **err); SWITCH_DECLARE(char *) switch_rtp_get_remote_host(switch_rtp_t *rtp_session); @@ -213,6 +214,13 @@ SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session); */ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_session, char *login, char *rlogin); +/*! + \brief Activate sending RTCP Sender Reports (SR's) + \param send_rate interval in milliseconds to send at + \return SWITCH_STATUS_SUCCESS +*/ +SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_session, int send_rate, switch_port_t remote_port); + /*! \brief Acvite a jitter buffer on an RTP session \param rtp_session the rtp session @@ -347,6 +355,15 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_sessi */ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp_session, switch_frame_t *frame, switch_io_flag_t io_flags); + +/*! + \brief Read RTCP data from a given RTP session without copying + \param rtp_session the RTP session to read from + \param frame an RTCP frame to populate with information + \return the number of bytes read +*/ +SWITCH_DECLARE(switch_status_t) switch_rtcp_zerocopy_read_frame(switch_rtp_t *rtp_session, switch_rtcp_frame_t *frame); + SWITCH_DECLARE(void) rtp_flush_read_buffer(switch_rtp_t *rtp_session, switch_rtp_flush_t flush); /*! diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 0d47984a5f..2589e2b8c3 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -534,7 +534,10 @@ typedef enum { SWITCH_ZRTP_FLAG_SECURE_MITM_RECV = (1 << 26), SWITCH_RTP_FLAG_DEBUG_RTP_READ = (1 << 27), SWITCH_RTP_FLAG_DEBUG_RTP_WRITE = (1 << 28), - SWITCH_RTP_FLAG_VIDEO = (1 << 29) + SWITCH_RTP_FLAG_VIDEO = (1 << 29), + SWITCH_RTP_FLAG_ENABLE_RTCP = (1 << 30), + SWITCH_RTP_FLAG_RTCP_PASSTHRU = (1 << 31) + /* don't add any more 31 is the limit! gotta chnge to an array to add more */ } switch_rtp_flag_enum_t; typedef uint32_t switch_rtp_flag_t; @@ -607,6 +610,35 @@ typedef struct { #pragma pack(pop, r1) #endif +#ifdef _MSC_VER +#pragma pack(push, r1, 1) +#endif + +#if SWITCH_BYTE_ORDER == __BIG_ENDIAN +typedef struct { + unsigned version:2; /* protocol version */ + unsigned p:1; /* padding flag */ + unsigned count:5; /* number of reception report blocks */ + unsigned type:8; /* packet type */ + unsigned length:16; /* length in 32-bit words - 1 */ +} switch_rtcp_hdr_t; + +#else /* BIG_ENDIAN */ + +typedef struct { + unsigned count:5; /* number of reception report blocks */ + unsigned p:1; /* padding flag */ + unsigned version:2; /* protocol version */ + unsigned type:8; /* packet type */ + unsigned length:16; /* length in 32-bit words - 1 */ +} switch_rtcp_hdr_t; + +#endif + +#ifdef _MSC_VER +#pragma pack(pop, r1) +#endif + /*! \enum switch_priority_t \brief Priority Indication @@ -690,6 +722,7 @@ typedef enum { SWITCH_MESSAGE_INDICATE_PROXY_MEDIA, SWITCH_MESSAGE_INDICATE_APPLICATION_EXEC, SWITCH_MESSAGE_INDICATE_APPLICATION_EXEC_COMPLETE, + SWITCH_MESSAGE_INDICATE_PHONE_EVENT, SWITCH_MESSAGE_INVALID } switch_core_session_message_types_t; @@ -1351,6 +1384,7 @@ typedef enum { SWITCH_EVENT_SERVER_DISCONNECTED, SWITCH_EVENT_SEND_INFO, SWITCH_EVENT_RECV_INFO, + SWITCH_EVENT_RECV_RTCP_MESSAGE, SWITCH_EVENT_CALL_SECURE, SWITCH_EVENT_NAT, SWITCH_EVENT_RECORD_START, @@ -1471,6 +1505,7 @@ typedef uint16_t switch_port_t; typedef uint8_t switch_payload_t; typedef struct switch_app_log switch_app_log_t; typedef struct switch_rtp switch_rtp_t; +typedef struct switch_rtcp switch_rtcp_t; typedef struct switch_core_session_message switch_core_session_message_t; typedef struct switch_event_header switch_event_header_t; typedef struct switch_event switch_event_t; @@ -1478,6 +1513,7 @@ typedef struct switch_event_subclass switch_event_subclass_t; typedef struct switch_event_node switch_event_node_t; typedef struct switch_loadable_module switch_loadable_module_t; typedef struct switch_frame switch_frame_t; +typedef struct switch_rtcp_frame switch_rtcp_frame_t; typedef struct switch_channel switch_channel_t; typedef struct switch_file_handle switch_file_handle_t; typedef struct switch_core_session switch_core_session_t; diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 23fbaf23a4..6dc2d8c913 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -2319,7 +2319,7 @@ SWITCH_STANDARD_API(uuid_display_function) #define SIMPLIFY_SYNTAX "" SWITCH_STANDARD_API(uuid_simplify_function) { - switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_status_t status = SWITCH_STATUS_FALSE; if (zstr(cmd)) { stream->write_function(stream, "-USAGE: %s\n", SIMPLIFY_SYNTAX); @@ -2347,6 +2347,45 @@ SWITCH_STANDARD_API(uuid_simplify_function) } +#define PHONE_EVENT_SYNTAX "" +SWITCH_STANDARD_API(uuid_phone_event_function) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + char *mycmd = NULL, *argv[2] = { 0 }; + int argc = 0; + + if (!zstr(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } + + if (argc < 1) { + stream->write_function(stream, "-USAGE: %s\n", PHONE_EVENT_SYNTAX); + } else { + switch_core_session_message_t msg = { 0 }; + switch_core_session_t *lsession = NULL; + + msg.message_id = SWITCH_MESSAGE_INDICATE_PHONE_EVENT; + msg.string_arg = argv[1]; + msg.from = __FILE__; + + if ((lsession = switch_core_session_locate(argv[0]))) { + status = switch_core_session_receive_message(lsession, &msg); + switch_core_session_rwunlock(lsession); + } + } + + if (status == SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "+OK Success\n"); + } else { + stream->write_function(stream, "-ERR Operation Failed\n"); + } + + switch_safe_free(mycmd); + + return SWITCH_STATUS_SUCCESS; +} + + #define DEBUG_AUDIO_SYNTAX " " SWITCH_STANDARD_API(uuid_debug_audio_function) { @@ -4219,6 +4258,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "uuid_loglevel", "set loglevel on session", uuid_loglevel, UUID_LOGLEVEL_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_media", "media", uuid_media_function, MEDIA_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_park", "Park Channel", park_function, PARK_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "uuid_phone_event", "Send and event to the phone", uuid_phone_event_function, PHONE_EVENT_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_preprocess", "Pre-process Channel", preprocess_function, PREPROCESS_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_record", "session record", session_record_function, SESS_REC_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_recv_dtmf", "receive dtmf digits", uuid_recv_dtmf_function, UUID_RECV_DTMF_SYNTAX); @@ -4325,6 +4365,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add uuid_loglevel ::console::list_uuid debug"); switch_console_set_complete("add uuid_media ::console::list_uuid"); switch_console_set_complete("add uuid_park ::console::list_uuid"); + switch_console_set_complete("add uuid_phone_event ::console::list_uuid talk"); + switch_console_set_complete("add uuid_phone_event ::console::list_uuid hold"); switch_console_set_complete("add uuid_preprocess ::console::list_uuid"); switch_console_set_complete("add uuid_record ::console::list_uuid"); switch_console_set_complete("add uuid_recv_dtmf ::console::list_uuid"); diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c old mode 100644 new mode 100755 index 9990871df3..fadb23eabc --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -358,16 +358,18 @@ SWITCH_STANDARD_APP(eavesdrop_function) char terminator; switch_status_t status; - if (switch_core_db_handle(&db) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Database Error!\n"); - } - while (switch_channel_ready(channel)) { for (x = 0; x < MAX_SPY; x++) { switch_safe_free(e_data.uuid_list[x]); } e_data.total = 0; + + if (switch_core_db_handle(&db) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Database Error!\n"); + break; + } switch_cache_db_execute_sql_callback(db, sql, e_callback, &e_data, &errmsg); + switch_cache_db_release_db_handle(&db); if (errmsg) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Error: %s\n", errmsg); switch_core_db_free(errmsg); @@ -408,7 +410,6 @@ SWITCH_STANDARD_APP(eavesdrop_function) } free(sql); - switch_cache_db_release_db_handle(&db); } else { switch_ivr_eavesdrop_session(session, data, require_group, ED_DTMF); diff --git a/src/mod/applications/mod_nibblebill/mod_nibblebill.c b/src/mod/applications/mod_nibblebill/mod_nibblebill.c old mode 100644 new mode 100755 index 78b7addf37..b1b124bc67 --- a/src/mod/applications/mod_nibblebill/mod_nibblebill.c +++ b/src/mod/applications/mod_nibblebill/mod_nibblebill.c @@ -337,9 +337,10 @@ static switch_status_t bill_event(float billamount, const char *billaccount, swi switch_odbc_statement_handle_free(&stmt); end: - if (sql != globals.custom_sql_save) { + if (sql != globals.custom_sql_lookup && sql != sql_stream.data) { switch_safe_free(sql); } + switch_safe_free(sql_stream.data); return SWITCH_STATUS_SUCCESS; } @@ -385,9 +386,10 @@ static float get_balance(const char *billaccount, switch_channel_t *channel) } end: - if (sql != globals.custom_sql_lookup) { + if (sql != globals.custom_sql_lookup && sql != sql_stream.data) { switch_safe_free(sql); } + switch_safe_free(sql_stream.data); return balance; } @@ -942,7 +944,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_nibblebill_load) /* Add dialplan applications */ SWITCH_ADD_APP(app_interface, "nibblebill", "Handle billing for the current channel/call", "Pause, resume, reset, adjust, flush, heartbeat commands to handle billing.", nibblebill_app_function, APP_SYNTAX, - SAF_NONE | SAF_ROUTING_EXEC); + SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC); /* register state handlers for billing */ switch_core_add_state_handler(&nibble_state_handler); @@ -964,6 +966,18 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_nibblebill_shutdown) switch_core_remove_state_handler(&nibble_state_handler); switch_odbc_handle_disconnect(globals.master_odbc); + switch_safe_free(globals.db_username); + switch_safe_free(globals.db_password); + switch_safe_free(globals.db_dsn); + switch_safe_free(globals.db_table); + switch_safe_free(globals.db_column_cash); + switch_safe_free(globals.db_column_account); + switch_safe_free(globals.custom_sql_save); + switch_safe_free(globals.custom_sql_lookup); + switch_safe_free(globals.percall_action); + switch_safe_free(globals.lowbal_action); + switch_safe_free(globals.nobal_action); + return SWITCH_STATUS_UNLOAD; } diff --git a/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c b/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c index dfce2cecaf..1ecc1404ce 100644 --- a/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c +++ b/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c @@ -2059,6 +2059,7 @@ static switch_status_t recog_channel_start(speech_channel_t *schannel, const cha r->start_of_input = 0; /* input timers are started by default unless the start-input-timers=false param is set */ + /* TODO this is true for Nuance, but might not be true on other MRCP servers */ start_input_timers = (char *) switch_core_hash_find(schannel->params, "start-input-timers"); r->timers_started = zstr(start_input_timers) || strcasecmp(start_input_timers, "false"); diff --git a/src/mod/codecs/mod_mp4v/Makefile b/src/mod/codecs/mod_mp4v/Makefile new file mode 100644 index 0000000000..2c35e6e98f --- /dev/null +++ b/src/mod/codecs/mod_mp4v/Makefile @@ -0,0 +1,2 @@ +BASE=../../../.. +include $(BASE)/build/modmake.rules diff --git a/src/mod/codecs/mod_mp4v/mod_mp4v.c b/src/mod/codecs/mod_mp4v/mod_mp4v.c new file mode 100644 index 0000000000..9500075de3 --- /dev/null +++ b/src/mod/codecs/mod_mp4v/mod_mp4v.c @@ -0,0 +1,102 @@ +/* + * 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 / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * + * mod_mp4v.c -- MP4V Signed Linear Codec + * + */ + +#include + +SWITCH_MODULE_LOAD_FUNCTION(mod_mp4v_load); +SWITCH_MODULE_DEFINITION(mod_mp4v, mod_mp4v_load, NULL, NULL); + +static switch_status_t switch_mp4v_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings) +{ + int encoding, decoding; + + encoding = (flags & SWITCH_CODEC_FLAG_ENCODE); + decoding = (flags & SWITCH_CODEC_FLAG_DECODE); + + if (!(encoding || decoding)) { + return SWITCH_STATUS_FALSE; + } else { + if (codec->fmtp_in) { + codec->fmtp_out = switch_core_strdup(codec->memory_pool, codec->fmtp_in); + } + return SWITCH_STATUS_SUCCESS; + } +} + +static switch_status_t switch_mp4v_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) +{ + return SWITCH_STATUS_FALSE; +} + +static switch_status_t switch_mp4v_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) +{ + return SWITCH_STATUS_FALSE; +} + +static switch_status_t switch_mp4v_destroy(switch_codec_t *codec) +{ + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_MODULE_LOAD_FUNCTION(mod_mp4v_load) +{ + switch_codec_interface_t *codec_interface; + /* 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, "H.264 Video (passthru)"); + switch_core_codec_add_implementation(pool, codec_interface, + SWITCH_CODEC_TYPE_VIDEO, 99, "MP4V-ES", NULL, 90000, 90000, 0, + 0, 0, 0, 0, 1, 1, switch_mp4v_init, switch_mp4v_encode, switch_mp4v_decode, switch_mp4v_destroy); + /* indicate that the module should continue to be loaded */ + 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/endpoints/mod_gsmopen/mod_gsmopen.2008.vcproj b/src/mod/endpoints/mod_gsmopen/mod_gsmopen.2008.vcproj index edfccb09e5..98c5d842ab 100644 --- a/src/mod/endpoints/mod_gsmopen/mod_gsmopen.2008.vcproj +++ b/src/mod/endpoints/mod_gsmopen/mod_gsmopen.2008.vcproj @@ -39,7 +39,7 @@ /> hold_file = switch_core_session_strdup(session, hold_file); } - + if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL INIT %d %d\n", - switch_channel_get_name(channel), switch_channel_get_state(channel), switch_test_flag(tech_pvt, TFLAG_ANSWER)); - if (engage_device(0) != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); return SWITCH_STATUS_FALSE; @@ -309,14 +316,7 @@ static switch_status_t channel_on_init(switch_core_session_t *session) switch_set_flag_locked(tech_pvt, TFLAG_IO); - /* Move channel's state machine to ROUTING */ - switch_channel_set_state(channel, CS_ROUTING); - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t channel_on_routing(switch_core_session_t *session) -{ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(switch_core_session_get_channel(session))); return SWITCH_STATUS_SUCCESS; diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 2a6e65d695..5b780d3700 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -107,21 +107,23 @@ switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stre switch_assert(profile); stream->write_function(stream, "%s\n", line); /* prefs */ - stream->write_function(stream, "Name \t%s\n", profile->name); - stream->write_function(stream, "Domain Name \t%s\n", profile->domain); - stream->write_function(stream, "IP \t%s\n", profile->ip); - stream->write_function(stream, "Port \t%d\n", profile->port); - stream->write_function(stream, "Dialplan \t%s\n", profile->dialplan); - stream->write_function(stream, "Context \t%s\n", profile->context); - stream->write_function(stream, "Keep-Alive \t%d\n", profile->keep_alive); - stream->write_function(stream, "Date-Format \t%s\n", profile->date_format); - stream->write_function(stream, "DBName \t%s\n", profile->dbname ? profile->dbname : switch_str_nil(profile->odbc_dsn)); - stream->write_function(stream, "Debug \t%d\n", profile->debug); + stream->write_function(stream, "Name \t%s\n", profile->name); + stream->write_function(stream, "Domain Name \t%s\n", profile->domain); + stream->write_function(stream, "IP \t%s\n", profile->ip); + stream->write_function(stream, "Port \t%d\n", profile->port); + stream->write_function(stream, "Dialplan \t%s\n", profile->dialplan); + stream->write_function(stream, "Context \t%s\n", profile->context); + stream->write_function(stream, "Patterns-Dialplan \t%s\n", profile->patterns_dialplan); + stream->write_function(stream, "Patterns-Context \t%s\n", profile->patterns_context); + stream->write_function(stream, "Keep-Alive \t%d\n", profile->keep_alive); + stream->write_function(stream, "Date-Format \t%s\n", profile->date_format); + stream->write_function(stream, "DBName \t%s\n", profile->dbname ? profile->dbname : switch_str_nil(profile->odbc_dsn)); + stream->write_function(stream, "Debug \t%d\n", profile->debug); /* stats */ - 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%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); /* listener */ stream->write_function(stream, "Listener-Threads \t%d\n", profile->listener_threads); stream->write_function(stream, "%s\n", line); @@ -542,9 +544,9 @@ void tech_init(private_t *tech_pvt, skinny_profile_t *profile, switch_core_sessi tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf); switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); + tech_pvt->profile = profile; tech_pvt->call_id = ++profile->next_call_id; tech_pvt->party_id = tech_pvt->call_id; - tech_pvt->profile = profile; switch_core_session_set_private(session, tech_pvt); tech_pvt->session = session; } @@ -1429,6 +1431,10 @@ static void skinny_profile_set(skinny_profile_t *profile, char *var, char *val) profile->dialplan = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "context")) { profile->context = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "patterns-dialplan")) { + profile->patterns_dialplan = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "patterns-context")) { + profile->patterns_context = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "date-format")) { strncpy(profile->date_format, val, 6); } else if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) { @@ -1460,13 +1466,14 @@ static switch_status_t load_skinny_config(void) if ((xprofiles = switch_xml_child(xcfg, "profiles"))) { for (xprofile = switch_xml_child(xprofiles, "profile"); xprofile; xprofile = xprofile->next) { char *profile_name = (char *) switch_xml_attr_soft(xprofile, "name"); - switch_xml_t xsettings = switch_xml_child(xprofile, "settings"); + switch_xml_t xsettings; + switch_xml_t xdevice_types; if (zstr(profile_name)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " is missing name attribute\n"); continue; } - if (xsettings) { + if ((xsettings = switch_xml_child(xprofile, "settings"))) { switch_memory_pool_t *profile_pool = NULL; char dbname[256]; switch_core_db_t *db; @@ -1498,6 +1505,10 @@ static switch_status_t load_skinny_config(void) skinny_profile_set(profile, "dialplan", val); } else if (!strcmp(var, "context")) { skinny_profile_set(profile, "context", val); + } else if (!strcmp(var, "patterns-dialplan")) { + skinny_profile_set(profile, "patterns-dialplan", val); + } else if (!strcmp(var, "patterns-context")) { + skinny_profile_set(profile, "patterns-context", val); } else if (!strcmp(var, "keep-alive")) { profile->keep_alive = atoi(val); } else if (!strcmp(var, "date-format")) { @@ -1510,17 +1521,26 @@ static switch_status_t load_skinny_config(void) } /* param */ if (!profile->dialplan) { - skinny_profile_set(profile, "dialplan","default"); + skinny_profile_set(profile, "dialplan","XML"); } if (!profile->context) { - skinny_profile_set(profile, "context","public"); + skinny_profile_set(profile, "context","default"); + } + + if (!profile->patterns_dialplan) { + skinny_profile_set(profile, "patterns-dialplan","XML"); + } + + if (!profile->patterns_context) { + skinny_profile_set(profile, "patterns-context","skinny-patterns"); } if (profile->port == 0) { profile->port = 2000; } + /* Database */ switch_snprintf(dbname, sizeof(dbname), "skinny_%s", profile->name); profile->dbname = switch_core_strdup(profile->pool, dbname); @@ -1558,6 +1578,32 @@ static switch_status_t load_skinny_config(void) skinny_execute_sql_callback(profile, profile->sql_mutex, "DELETE FROM skinny_buttons", NULL, NULL); skinny_execute_sql_callback(profile, profile->sql_mutex, "DELETE FROM skinny_active_lines", NULL, NULL); + /* Device types */ + switch_core_hash_init(&profile->device_type_params_hash, profile->pool); + if ((xdevice_types = switch_xml_child(xprofile, "device-types"))) { + switch_xml_t xdevice_type; + for (xdevice_type = switch_xml_child(xdevice_types, "device-type"); xdevice_type; xdevice_type = xdevice_type->next) { + uint32_t id = skinny_str2device_type(switch_xml_attr_soft(xdevice_type, "id")); + if (id != 0) { + char *id_str = switch_mprintf("%d", id); + skinny_device_type_params_t *params = switch_core_alloc(profile->pool, sizeof(skinny_device_type_params_t)); + for (param = switch_xml_child(xdevice_type, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + + if (!strcasecmp(var, "firmware-version")) { + strncpy(params->firmware_version, val, 16); + } + } /* param */ + switch_core_hash_insert(profile->device_type_params_hash, id_str, params); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Unknow device type %s in profile %s.\n", switch_xml_attr_soft(xdevice_type, "id"), profile->name); + } + } + } + + /* Register profile */ switch_mutex_lock(globals.mutex); switch_core_hash_insert(globals.profile_hash, profile->name, profile); switch_mutex_unlock(globals.mutex); diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h index 3443d2f7dd..314e29ba73 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.h +++ b/src/mod/endpoints/mod_skinny/mod_skinny.h @@ -64,9 +64,12 @@ struct skinny_profile { unsigned int port; char *dialplan; char *context; + char *patterns_dialplan; + char *patterns_context; uint32_t keep_alive; char date_format[6]; int debug; + switch_hash_t *device_type_params_hash; /* db */ char *dbname; char *odbc_dsn; @@ -93,6 +96,16 @@ struct skinny_profile { }; typedef struct skinny_profile skinny_profile_t; +struct skinny_device_type_params { + char firmware_version[16]; +}; +typedef struct skinny_device_type_params skinny_device_type_params_t; + +typedef enum { + SKINNY_ACTION_ROUTE, + SKINNY_ACTION_DROP, + SKINNY_ACTION_WAIT +} skinny_action_t; /*****************************************************************************/ /* LISTENERS TYPES */ @@ -107,6 +120,9 @@ struct listener { skinny_profile_t *profile; char device_name[16]; uint32_t device_instance; + uint32_t device_type; + + char firmware_version[16]; switch_socket_t *sock; switch_memory_pool_t *pool; @@ -147,36 +163,40 @@ typedef enum { } GFLAGS; struct private_object { - unsigned int flags; - switch_frame_t read_frame; - unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; - switch_core_session_t *session; - switch_caller_profile_t *caller_profile; - switch_mutex_t *mutex; - switch_mutex_t *flag_mutex; - /* identification */ - uint32_t call_id; - uint32_t party_id; + unsigned int flags; + switch_frame_t read_frame; + unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; + switch_core_session_t *session; + switch_caller_profile_t *caller_profile; + switch_mutex_t *mutex; + switch_mutex_t *flag_mutex; - skinny_profile_t *profile; + /* identification */ + skinny_profile_t *profile; + uint32_t call_id; + uint32_t party_id; - /* codec */ - char *iananame; - switch_codec_t read_codec; - switch_codec_t write_codec; - switch_codec_implementation_t read_impl; - switch_codec_implementation_t write_impl; - unsigned long rm_rate; - uint32_t codec_ms; - char *rm_encoding; - char *rm_fmtp; - switch_payload_t agreed_pt; - /* RTP */ - switch_rtp_t *rtp_session; - char *local_sdp_audio_ip; - switch_port_t local_sdp_audio_port; - char *remote_sdp_audio_ip; - switch_port_t remote_sdp_audio_port; + /* related calls */ + uint32_t transfer_to_call_id; + uint32_t transfer_from_call_id; + + /* codec */ + char *iananame; + switch_codec_t read_codec; + switch_codec_t write_codec; + switch_codec_implementation_t read_impl; + switch_codec_implementation_t write_impl; + unsigned long rm_rate; + uint32_t codec_ms; + char *rm_encoding; + char *rm_fmtp; + switch_payload_t agreed_pt; + /* RTP */ + switch_rtp_t *rtp_session; + char *local_sdp_audio_ip; + switch_port_t local_sdp_audio_port; + char *remote_sdp_audio_ip; + switch_port_t remote_sdp_audio_port; }; typedef struct private_object private_t; diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index 7fd7998545..7acede0da5 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -500,12 +500,13 @@ switch_status_t skinny_create_ingoing_session(listener_t *listener, uint32_t *li "Error Locking Session\n"); goto error; } + /* First create the caller profile in the patterns Dialplan */ if (!(tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(nsession), - NULL, listener->profile->dialplan, + NULL, listener->profile->patterns_dialplan, button->shortname, button->name, listener->remote_ip, NULL, NULL, NULL, "skinny" /* modname */, - listener->profile->context, + listener->profile->patterns_context, "")) != 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(nsession), SWITCH_LOG_CRIT, "Error Creating Session caller profile\n"); @@ -548,6 +549,75 @@ done: return SWITCH_STATUS_SUCCESS; } +skinny_action_t skinny_session_dest_match_pattern(switch_core_session_t *session, char **data) +{ + skinny_action_t action = SKINNY_ACTION_DROP; + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + + switch_assert(session); + + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); + + /* this part of the code is similar to switch_core_standard_on_routing() */ + if (!zstr(tech_pvt->profile->patterns_dialplan)) { + switch_dialplan_interface_t *dialplan_interface = NULL; + switch_caller_extension_t *extension = NULL; + char *expanded = NULL; + char *dpstr = NULL; + char *dp[25]; + int argc, x; + + if ((dpstr = switch_core_session_strdup(session, tech_pvt->profile->patterns_dialplan))) { + expanded = switch_channel_expand_variables(channel, dpstr); + argc = switch_separate_string(expanded, ',', dp, (sizeof(dp) / sizeof(dp[0]))); + for (x = 0; x < argc; x++) { + char *dpname = dp[x]; + char *dparg = NULL; + + if (dpname) { + if ((dparg = strchr(dpname, ':'))) { + *dparg++ = '\0'; + } + } else { + continue; + } + if (!(dialplan_interface = switch_loadable_module_get_dialplan_interface(dpname))) { + continue; + } + + extension = dialplan_interface->hunt_function(session, dparg, NULL); + UNPROTECT_INTERFACE(dialplan_interface); + + if (extension) { + goto found; + } + } + } +found: + while (extension && extension->current_application) { + switch_caller_application_t *current_application = extension->current_application; + + extension->current_application = extension->current_application->next; + + if (!strcmp(current_application->application_name, "skinny-route")) { + action = SKINNY_ACTION_ROUTE; + } else if (!strcmp(current_application->application_name, "skinny-drop")) { + action = SKINNY_ACTION_DROP; + } else if (!strcmp(current_application->application_name, "skinny-wait")) { + action = SKINNY_ACTION_WAIT; + *data = switch_core_session_strdup(session, current_application->application_data); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "Unknown skinny dialplan application %s\n", current_application->application_name); + } + } + } + return action; +} + + struct skinny_session_process_dest_helper { private_t *tech_pvt; listener_t *listener; @@ -597,8 +667,11 @@ int skinny_session_process_dest_callback(void *pArg, int argc, char **argv, char switch_status_t skinny_session_process_dest(switch_core_session_t *session, listener_t *listener, uint32_t line_instance, char *dest, char append_dest, uint32_t backspace) { + skinny_action_t action; switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; + char *data = NULL; + struct skinny_session_process_dest_helper helper = {0}; switch_assert(session); switch_assert(listener); @@ -633,19 +706,32 @@ switch_status_t skinny_session_process_dest(switch_core_session_t *session, list tech_pvt->caller_profile->destination_number = switch_core_strdup(tech_pvt->caller_profile->pool, dest); } - /* TODO Number is complete -> check against dialplan */ - if ((strlen(tech_pvt->caller_profile->destination_number) >= 4) || dest) { - struct skinny_session_process_dest_helper helper = {0}; - send_dialed_number(listener, tech_pvt->caller_profile->destination_number, line_instance, tech_pvt->call_id); - skinny_line_set_state(listener, line_instance, tech_pvt->call_id, SKINNY_PROCEED); - skinny_send_call_info(session, listener, line_instance); + if(dest) { + action = SKINNY_ACTION_ROUTE; + } else { + action = skinny_session_dest_match_pattern(session, &data); + } + switch(action) { + case SKINNY_ACTION_ROUTE: + tech_pvt->caller_profile->dialplan = switch_core_strdup(tech_pvt->caller_profile->pool, listener->profile->dialplan); + tech_pvt->caller_profile->context = switch_core_strdup(tech_pvt->caller_profile->pool, listener->profile->context); + send_dialed_number(listener, tech_pvt->caller_profile->destination_number, line_instance, tech_pvt->call_id); + skinny_line_set_state(listener, line_instance, tech_pvt->call_id, SKINNY_PROCEED); + skinny_send_call_info(session, listener, line_instance); - skinny_session_start_media(session, listener, line_instance); - - helper.tech_pvt = tech_pvt; - helper.listener = listener; - helper.line_instance = line_instance; - skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), skinny_session_process_dest_callback, &helper); + skinny_session_start_media(session, listener, line_instance); + + helper.tech_pvt = tech_pvt; + helper.listener = listener; + helper.line_instance = line_instance; + skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), skinny_session_process_dest_callback, &helper); + break; + case SKINNY_ACTION_WAIT: + /* for now, wait forever */ + break; + case SKINNY_ACTION_DROP: + default: + switch_channel_hangup(channel, SWITCH_CAUSE_UNALLOCATED_NUMBER); } return SWITCH_STATUS_SUCCESS; @@ -837,6 +923,51 @@ switch_status_t skinny_session_unhold_line(switch_core_session_t *session, liste return SWITCH_STATUS_SUCCESS; } +switch_status_t skinny_session_transfer(switch_core_session_t *session, listener_t *listener, uint32_t line_instance) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + private_t *tech_pvt = NULL; + switch_channel_t *channel = NULL; + const char *remote_uuid = NULL; + switch_core_session_t *session2 = NULL; + private_t *tech_pvt2 = NULL; + + switch_assert(session); + switch_assert(listener); + switch_assert(listener->profile); + + tech_pvt = switch_core_session_get_private(session); + channel = switch_core_session_get_channel(session); + remote_uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE); + + if (tech_pvt->transfer_from_call_id) { + if((session2 = skinny_profile_find_session(listener->profile, listener, &line_instance, tech_pvt->transfer_from_call_id))) { + switch_channel_t *channel2 = switch_core_session_get_channel(session2); + const char *remote_uuid2 = switch_channel_get_variable(channel2, SWITCH_SIGNAL_BOND_VARIABLE); + if (switch_ivr_uuid_bridge(remote_uuid, remote_uuid2) == SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + switch_channel_hangup(channel2, SWITCH_CAUSE_NORMAL_CLEARING); + } else { + /* TODO: How to inform the user that the bridge is not possible? */ + } + switch_core_session_rwunlock(session2); + } + } else { + if(remote_uuid) { + /* TODO CallSelectStat */ + status = skinny_create_ingoing_session(listener, &line_instance, &session2); + tech_pvt2 = switch_core_session_get_private(session2); + tech_pvt2->transfer_from_call_id = tech_pvt->call_id; + tech_pvt->transfer_to_call_id = tech_pvt2->call_id; + skinny_session_process_dest(session2, listener, line_instance, NULL, '\0', 0); + switch_core_session_rwunlock(session2); + } else { + /* TODO: How to inform the user that the bridge is not possible? */ + } + } + return status; +} + switch_status_t skinny_session_stop_media(switch_core_session_t *session, listener_t *listener, uint32_t line_instance) { switch_channel_t *channel = NULL; @@ -1348,6 +1479,17 @@ switch_status_t send_capabilities_req(listener_t *listener) return skinny_send_reply(listener, message); } +switch_status_t send_version(listener_t *listener, + char *version) +{ + skinny_message_t *message; + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.version)); + message->type = VERSION_MESSAGE; + message->length = 4+ sizeof(message->data.version); + strncpy(message->data.version.version, version, 16); + return skinny_send_reply(listener, message); +} + switch_status_t send_register_reject(listener_t *listener, char *error) { @@ -1538,25 +1680,18 @@ switch_status_t send_reset(listener_t *listener, uint32_t reset_type) return skinny_send_reply(listener, message); } -/* Message handling */ -switch_status_t skinny_handle_alarm(listener_t *listener, skinny_message_t *request) +/*****************************************************************************/ +/* SKINNY MESSAGE HANDLERS */ +/*****************************************************************************/ +switch_status_t skinny_handle_keep_alive_message(listener_t *listener, skinny_message_t *request) { - switch_event_t *event = NULL; - - skinny_check_data_length(request, sizeof(request->data.alarm)); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, - "Received alarm: Severity=%d, DisplayMessage=%s, Param1=%d, Param2=%d.\n", - request->data.alarm.alarm_severity, request->data.alarm.display_message, - request->data.alarm.alarm_param1, request->data.alarm.alarm_param2); - /* skinny::alarm event */ - skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_ALARM); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Severity", "%d", request->data.alarm.alarm_severity); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-DisplayMessage", "%s", request->data.alarm.display_message); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param1", "%d", request->data.alarm.alarm_param1); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param2", "%d", request->data.alarm.alarm_param2); - switch_event_fire(&event); + skinny_message_t *message; + message = switch_core_alloc(listener->pool, 12); + message->type = KEEP_ALIVE_ACK_MESSAGE; + message->length = 4; + keepalive_listener(listener, NULL); + skinny_send_reply(listener, message); return SWITCH_STATUS_SUCCESS; } @@ -1566,7 +1701,7 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r skinny_profile_t *profile; switch_event_t *event = NULL; switch_event_t *params = NULL; - switch_xml_t xroot, xdomain, xgroup, xuser, xskinny, xbuttons, xbutton; + switch_xml_t xroot, xdomain, xgroup, xuser, xskinny, xparams, xparam, xbuttons, xbutton; char *sql; assert(listener->profile); profile = listener->profile; @@ -1612,11 +1747,20 @@ switch_status_t skinny_handle_register(listener_t *listener, skinny_message_t *r strncpy(listener->device_name, request->data.reg.device_name, 16); listener->device_instance = request->data.reg.instance; + listener->device_type = request->data.reg.device_type; xskinny = switch_xml_child(xuser, "skinny"); if (xskinny) { - xbuttons = switch_xml_child(xskinny, "buttons"); - if (xbuttons) { + if ((xparams = switch_xml_child(xskinny, "params"))) { + for (xparam = switch_xml_child(xparams, "param"); xparam; xparam = xparam->next) { + const char *name = switch_xml_attr_soft(xparam, "name"); + const char *value = switch_xml_attr_soft(xparam, "value"); + if (!strcasecmp(name, "skinny-firmware-version")) { + strncpy(listener->firmware_version, value, 16); + } + } + } + if ((xbuttons = switch_xml_child(xskinny, "buttons"))) { uint32_t line_instance = 1; for (xbutton = switch_xml_child(xbuttons, "button"); xbutton; xbutton = xbutton->next) { uint32_t position = atoi(switch_xml_attr_soft(xbutton, "position")); @@ -1692,11 +1836,231 @@ end: return status; } -switch_status_t skinny_headset_status_message(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_port_message(listener_t *listener, skinny_message_t *request) { - skinny_check_data_length(request, sizeof(request->data.headset_status)); + char *sql; + skinny_profile_t *profile; + + switch_assert(listener->profile); + switch_assert(listener->device_name); + + profile = listener->profile; + + skinny_check_data_length(request, sizeof(request->data.as_uint16)); + + if ((sql = switch_mprintf( + "UPDATE skinny_devices SET port=%d WHERE name='%s' and instance=%d", + request->data.port.port, + listener->device_name, + listener->device_instance + ))) { + skinny_execute_sql(profile, sql, profile->sql_mutex); + switch_safe_free(sql); + } + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny_message_t *request) +{ + uint32_t line_instance = 0; + switch_core_session_t *session; + + skinny_check_data_length(request, sizeof(request->data.keypad_button)); + + if(request->data.keypad_button.line_instance) { + line_instance = request->data.keypad_button.line_instance; + } else { + line_instance = 1; + } + + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.keypad_button.call_id); + + if(session) { + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + char digit = '\0'; + + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "SEND DTMF ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); + + if (request->data.keypad_button.button == 14) { + digit = '*'; + } else if (request->data.keypad_button.button == 15) { + digit = '#'; + } else if (request->data.keypad_button.button >= 0 && request->data.keypad_button.button <= 9) { + digit = '0' + request->data.keypad_button.button; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "UNKNOW DTMF RECEIVED ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); + } + + /* TODO check call_id and line */ + + if((skinny_line_get_state(listener, line_instance, tech_pvt->call_id) == SKINNY_OFF_HOOK)) { + + skinny_session_process_dest(session, listener, line_instance, NULL, digit, 0); + } else { + if(digit != '\0') { + switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0)}; + dtmf.digit = digit; + switch_channel_queue_dtmf(channel, &dtmf); + } + } + } + + if(session) { + switch_core_session_rwunlock(session); + } + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_message_t *request) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + struct speed_dial_stat_res_message *button = NULL; + uint32_t line_instance = 0; + uint32_t call_id = 0; + switch_core_session_t *session = NULL; + + skinny_check_data_length(request, sizeof(request->data.stimulus)-sizeof(request->data.stimulus.call_id)); + + if(skinny_check_data_length_soft(request, sizeof(request->data.stimulus))) { + call_id = request->data.stimulus.call_id; + } + + switch(request->data.stimulus.instance_type) { + case SKINNY_BUTTON_LAST_NUMBER_REDIAL: + skinny_create_ingoing_session(listener, &line_instance, &session); + skinny_session_process_dest(session, listener, line_instance, "redial", '\0', 0); + break; + case SKINNY_BUTTON_SPEED_DIAL: + skinny_speed_dial_get(listener, request->data.stimulus.instance, &button); + if(strlen(button->line) > 0) { + skinny_create_ingoing_session(listener, &line_instance, &session); + skinny_session_process_dest(session, listener, line_instance, button->line, '\0', 0); + } + break; + case SKINNY_BUTTON_HOLD: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, call_id); + + if(session) { + status = skinny_session_hold_line(session, listener, line_instance); + } + break; + case SKINNY_BUTTON_VOICEMAIL: + skinny_create_ingoing_session(listener, &line_instance, &session); + skinny_session_process_dest(session, listener, line_instance, "vmain", '\0', 0); + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown Stimulus Type Received [%d]\n", request->data.stimulus.instance_type); + } + + if(session) { + switch_core_session_rwunlock(session); + } + + return status; +} + +switch_status_t skinny_handle_off_hook_message(listener_t *listener, skinny_message_t *request) +{ + uint32_t line_instance; + switch_core_session_t *session = NULL; + private_t *tech_pvt = NULL; + + skinny_check_data_length(request, sizeof(request->data.off_hook)); + + if(request->data.off_hook.line_instance > 0) { + line_instance = request->data.off_hook.line_instance; + } else { + line_instance = 1; + } + + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.off_hook.call_id); + + if(session) { /*answering a call */ + skinny_session_answer(session, listener, line_instance); + } else { /* start a new call */ + skinny_create_ingoing_session(listener, &line_instance, &session); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0); + } + + if(session) { + switch_core_session_rwunlock(session); + } + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_handle_on_hook_message(listener_t *listener, skinny_message_t *request) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + switch_core_session_t *session = NULL; + uint32_t line_instance = 0; + + skinny_check_data_length(request, sizeof(request->data.on_hook)); + + line_instance = request->data.on_hook.line_instance; + + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.on_hook.call_id); + + if(session) { + switch_channel_t *channel = NULL; + + channel = switch_core_session_get_channel(session); + + switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + } + + if(session) { + switch_core_session_rwunlock(session); + } + + return status; +} + +switch_status_t skinny_handle_speed_dial_stat_request(listener_t *listener, skinny_message_t *request) +{ + skinny_message_t *message; + struct speed_dial_stat_res_message *button = NULL; + + skinny_check_data_length(request, sizeof(request->data.speed_dial_req)); + + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.speed_dial_res)); + message->type = SPEED_DIAL_STAT_RES_MESSAGE; + message->length = 4 + sizeof(message->data.speed_dial_res); + + skinny_speed_dial_get(listener, request->data.speed_dial_req.number, &button); + + memcpy(&message->data.speed_dial_res, button, sizeof(struct speed_dial_stat_res_message)); + + skinny_send_reply(listener, message); + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_handle_line_stat_request(listener_t *listener, skinny_message_t *request) +{ + skinny_message_t *message; + struct line_stat_res_message *button = NULL; + + skinny_check_data_length(request, sizeof(request->data.line_req)); + + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.line_res)); + message->type = LINE_STAT_RES_MESSAGE; + message->length = 4 + sizeof(message->data.line_res); + + skinny_line_get(listener, request->data.line_req.number, &button); + + memcpy(&message->data.line_res, button, sizeof(struct line_stat_res_message)); + + skinny_send_reply(listener, message); - /* Nothing to do */ return SWITCH_STATUS_SUCCESS; } @@ -1757,88 +2121,9 @@ switch_status_t skinny_handle_config_stat_request(listener_t *listener, skinny_m return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_handle_capabilities_response(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_time_date_request(listener_t *listener, skinny_message_t *request) { - char *sql; - skinny_profile_t *profile; - - uint32_t i = 0; - uint32_t n = 0; - char *codec_order[SWITCH_MAX_CODECS]; - char *codec_string; - - size_t string_len, string_pos, pos; - - switch_assert(listener->profile); - switch_assert(listener->device_name); - - profile = listener->profile; - - skinny_check_data_length(request, sizeof(request->data.cap_res.count)); - - n = request->data.cap_res.count; - if (n > SWITCH_MAX_CODECS) { - n = SWITCH_MAX_CODECS; - } - string_len = -1; - - skinny_check_data_length(request, sizeof(request->data.cap_res.count) + n * sizeof(request->data.cap_res.caps[0])); - - for (i = 0; i < n; i++) { - char *codec = skinny_codec2string(request->data.cap_res.caps[i].codec); - codec_order[i] = codec; - string_len += strlen(codec)+1; - } - i = 0; - pos = 0; - codec_string = switch_core_alloc(listener->pool, string_len+1); - for (string_pos = 0; string_pos < string_len; string_pos++) { - char *codec = codec_order[i]; - switch_assert(i < n); - if(pos == strlen(codec)) { - codec_string[string_pos] = ','; - i++; - pos = 0; - } else { - codec_string[string_pos] = codec[pos++]; - } - } - codec_string[string_len] = '\0'; - if ((sql = switch_mprintf( - "UPDATE skinny_devices SET codec_string='%s' WHERE name='%s'", - codec_string, - listener->device_name - ))) { - skinny_execute_sql(profile, sql, profile->sql_mutex); - switch_safe_free(sql); - } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, - "Codecs %s supported.\n", codec_string); - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_port_message(listener_t *listener, skinny_message_t *request) -{ - char *sql; - skinny_profile_t *profile; - - switch_assert(listener->profile); - switch_assert(listener->device_name); - - profile = listener->profile; - - skinny_check_data_length(request, sizeof(request->data.as_uint16)); - - if ((sql = switch_mprintf( - "UPDATE skinny_devices SET port=%d WHERE name='%s' and instance=%d", - request->data.port.port, - listener->device_name, - listener->device_instance - ))) { - skinny_execute_sql(profile, sql, profile->sql_mutex); - switch_safe_free(sql); - } - return SWITCH_STATUS_SUCCESS; + return send_define_current_time_date(listener); } struct button_template_helper { @@ -1927,346 +2212,114 @@ switch_status_t skinny_handle_button_template_request(listener_t *listener, skin } } - skinny_send_reply(listener, message); - - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_soft_key_template_request(listener_t *listener, skinny_message_t *request) -{ - skinny_message_t *message; - skinny_profile_t *profile; - - switch_assert(listener->profile); - switch_assert(listener->device_name); - - profile = listener->profile; - - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.soft_key_template)); - message->type = SOFT_KEY_TEMPLATE_RES_MESSAGE; - message->length = 4 + sizeof(message->data.soft_key_template); - - message->data.soft_key_template.soft_key_offset = 0; - message->data.soft_key_template.soft_key_count = 21; - message->data.soft_key_template.total_soft_key_count = 21; - - memcpy(message->data.soft_key_template.soft_key, - soft_key_template_default, - sizeof(soft_key_template_default)); - - skinny_send_reply(listener, message); - - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_message_t *request) -{ - skinny_message_t *message; - skinny_profile_t *profile; - - switch_assert(listener->profile); - switch_assert(listener->device_name); - - profile = listener->profile; - - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.soft_key_set)); - message->type = SOFT_KEY_SET_RES_MESSAGE; - message->length = 4 + sizeof(message->data.soft_key_set); - - message->data.soft_key_set.soft_key_set_offset = 0; - message->data.soft_key_set.soft_key_set_count = 11; - message->data.soft_key_set.total_soft_key_set_count = 11; - - /* TODO fill the set */ - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[0] = SOFTKEY_NEWCALL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[1] = SOFTKEY_REDIAL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK].soft_key_template_index[1] = SOFTKEY_REDIAL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK].soft_key_template_index[2] = SOFTKEY_ENDCALL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT].soft_key_template_index[0] = SOFTKEY_BACKSPACE; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT].soft_key_template_index[2] = SOFTKEY_ENDCALL; - - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[0] = SOFTKEY_ENDCALL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[1] = SOFTKEY_HOLD; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[2] = SOFTKEY_NEWCALL; - - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[0] = SOFTKEY_ANSWER; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[1] = SOFTKEY_ENDCALL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[2] = SOFTKEY_NEWCALL; - - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[0] = SOFTKEY_NEWCALL; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[1] = SOFTKEY_RESUME; - message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[2] = SOFTKEY_ENDCALL; - - skinny_send_reply(listener, message); - - /* Init the states */ - send_select_soft_keys(listener, 0, 0, SKINNY_KEY_SET_ON_HOOK, 0xffff); - - return SWITCH_STATUS_SUCCESS; + return skinny_send_reply(listener, message);; } -switch_status_t skinny_handle_line_stat_request(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_version_request(listener_t *listener, skinny_message_t *request) { - skinny_message_t *message; - struct line_stat_res_message *button = NULL; - - skinny_check_data_length(request, sizeof(request->data.line_req)); - - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.line_res)); - message->type = LINE_STAT_RES_MESSAGE; - message->length = 4 + sizeof(message->data.line_res); - - skinny_line_get(listener, request->data.line_req.number, &button); - - memcpy(&message->data.line_res, button, sizeof(struct line_stat_res_message)); - - skinny_send_reply(listener, message); - - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_speed_dial_stat_request(listener_t *listener, skinny_message_t *request) -{ - skinny_message_t *message; - struct speed_dial_stat_res_message *button = NULL; - - skinny_check_data_length(request, sizeof(request->data.speed_dial_req)); - - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.speed_dial_res)); - message->type = SPEED_DIAL_STAT_RES_MESSAGE; - message->length = 4 + sizeof(message->data.speed_dial_res); - - skinny_speed_dial_get(listener, request->data.speed_dial_req.number, &button); - - memcpy(&message->data.speed_dial_res, button, sizeof(struct speed_dial_stat_res_message)); - - skinny_send_reply(listener, message); - - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_service_url_stat_request(listener_t *listener, skinny_message_t *request) -{ - skinny_message_t *message; - struct service_url_stat_res_message *button = NULL; - - skinny_check_data_length(request, sizeof(request->data.service_url_req)); - - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.service_url_res)); - message->type = SERVICE_URL_STAT_RES_MESSAGE; - message->length = 4 + sizeof(message->data.service_url_res); - - skinny_service_url_get(listener, request->data.service_url_req.service_url_index, &button); - - memcpy(&message->data.service_url_res, button, sizeof(struct service_url_stat_res_message)); - - skinny_send_reply(listener, message); - - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_feature_stat_request(listener_t *listener, skinny_message_t *request) -{ - skinny_message_t *message; - struct feature_stat_res_message *button = NULL; - - skinny_check_data_length(request, sizeof(request->data.feature_req)); - - message = switch_core_alloc(listener->pool, 12+sizeof(message->data.feature_res)); - message->type = FEATURE_STAT_RES_MESSAGE; - message->length = 4 + sizeof(message->data.feature_res); - - skinny_feature_get(listener, request->data.feature_req.feature_index, &button); - - memcpy(&message->data.feature_res, button, sizeof(struct feature_stat_res_message)); - - skinny_send_reply(listener, message); - - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_register_available_lines_message(listener_t *listener, skinny_message_t *request) -{ - skinny_check_data_length(request, sizeof(request->data.reg_lines)); - - /* Do nothing */ - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_time_date_request(listener_t *listener, skinny_message_t *request) -{ - return send_define_current_time_date(listener); -} - -switch_status_t skinny_handle_keep_alive_message(listener_t *listener, skinny_message_t *request) -{ - skinny_message_t *message; - - message = switch_core_alloc(listener->pool, 12); - message->type = KEEP_ALIVE_ACK_MESSAGE; - message->length = 4; - keepalive_listener(listener, NULL); - skinny_send_reply(listener, message); - return SWITCH_STATUS_SUCCESS; -} - -switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinny_message_t *request) -{ - switch_status_t status = SWITCH_STATUS_SUCCESS; - uint32_t line_instance = 0; - switch_core_session_t *session = NULL; - switch_channel_t *channel = NULL; - private_t *tech_pvt = NULL; - - switch_assert(listener); - switch_assert(listener->profile); - - skinny_check_data_length(request, sizeof(request->data.soft_key_event)); - - line_instance = request->data.soft_key_event.line_instance; - - switch(request->data.soft_key_event.event) { - case SOFTKEY_REDIAL: - status = skinny_create_ingoing_session(listener, &line_instance, &session); - - skinny_session_process_dest(session, listener, line_instance, "redial", '\0', 0); - break; - case SOFTKEY_NEWCALL: - status = skinny_create_ingoing_session(listener, &line_instance, &session); - tech_pvt = switch_core_session_get_private(session); - - skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0); - break; - case SOFTKEY_HOLD: - session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); - - if(session) { - status = skinny_session_hold_line(session, listener, line_instance); - } - break; - case SOFTKEY_BACKSPACE: - session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); - - if(session) { - skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 1); - } - break; - case SOFTKEY_ENDCALL: - session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); - - if(session) { - channel = switch_core_session_get_channel(session); - - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - } - break; - case SOFTKEY_RESUME: - session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); - - if(session) { - status = skinny_session_unhold_line(session, listener, line_instance); - } - break; - case SOFTKEY_ANSWER: - session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); - - if(session) { - status = skinny_session_answer(session, listener, line_instance); - } - break; - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, - "Unknown SoftKeyEvent type: %d.\n", request->data.soft_key_event.event); + if (zstr(listener->firmware_version)) { + char *id_str; + skinny_device_type_params_t *params; + id_str = switch_mprintf("%d", listener->device_type); + params = (skinny_device_type_params_t *) switch_core_hash_find(listener->profile->device_type_params_hash, id_str); + if (params) { + if (!zstr(params->firmware_version)) { + strncpy(listener->firmware_version, params->firmware_version, 16); + } + } } - - if(session) { - switch_core_session_rwunlock(session); - } - - return status; -} - -switch_status_t skinny_handle_off_hook_message(listener_t *listener, skinny_message_t *request) -{ - uint32_t line_instance; - switch_core_session_t *session = NULL; - private_t *tech_pvt = NULL; - - skinny_check_data_length(request, sizeof(request->data.off_hook)); - - if(request->data.off_hook.line_instance > 0) { - line_instance = request->data.off_hook.line_instance; + + if (!zstr(listener->firmware_version)) { + return send_version(listener, listener->firmware_version); } else { - line_instance = 1; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Device %s:%d is requesting for firmware version, but none is set.\n", + listener->device_name, listener->device_instance); + return SWITCH_STATUS_SUCCESS; } +} - session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.off_hook.call_id); +switch_status_t skinny_handle_capabilities_response(listener_t *listener, skinny_message_t *request) +{ + char *sql; + skinny_profile_t *profile; - if(session) { /*answering a call */ - skinny_session_answer(session, listener, line_instance); - } else { /* start a new call */ - skinny_create_ingoing_session(listener, &line_instance, &session); - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); + uint32_t i = 0; + uint32_t n = 0; + char *codec_order[SWITCH_MAX_CODECS]; + char *codec_string; - skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0); + size_t string_len, string_pos, pos; + + switch_assert(listener->profile); + switch_assert(listener->device_name); + + profile = listener->profile; + + skinny_check_data_length(request, sizeof(request->data.cap_res.count)); + + n = request->data.cap_res.count; + if (n > SWITCH_MAX_CODECS) { + n = SWITCH_MAX_CODECS; } + string_len = -1; - if(session) { - switch_core_session_rwunlock(session); + skinny_check_data_length(request, sizeof(request->data.cap_res.count) + n * sizeof(request->data.cap_res.caps[0])); + + for (i = 0; i < n; i++) { + char *codec = skinny_codec2string(request->data.cap_res.caps[i].codec); + codec_order[i] = codec; + string_len += strlen(codec)+1; } - + i = 0; + pos = 0; + codec_string = switch_core_alloc(listener->pool, string_len+1); + for (string_pos = 0; string_pos < string_len; string_pos++) { + char *codec = codec_order[i]; + switch_assert(i < n); + if(pos == strlen(codec)) { + codec_string[string_pos] = ','; + i++; + pos = 0; + } else { + codec_string[string_pos] = codec[pos++]; + } + } + codec_string[string_len] = '\0'; + if ((sql = switch_mprintf( + "UPDATE skinny_devices SET codec_string='%s' WHERE name='%s'", + codec_string, + listener->device_name + ))) { + skinny_execute_sql(profile, sql, profile->sql_mutex); + switch_safe_free(sql); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "Codecs %s supported.\n", codec_string); return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_alarm(listener_t *listener, skinny_message_t *request) { - switch_status_t status = SWITCH_STATUS_SUCCESS; - struct speed_dial_stat_res_message *button = NULL; - uint32_t line_instance = 0; - uint32_t call_id = 0; - switch_core_session_t *session = NULL; + switch_event_t *event = NULL; - skinny_check_data_length(request, sizeof(request->data.stimulus)-sizeof(request->data.stimulus.call_id)); + skinny_check_data_length(request, sizeof(request->data.alarm)); - if(skinny_check_data_length_soft(request, sizeof(request->data.stimulus))) { - call_id = request->data.stimulus.call_id; - } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Received alarm: Severity=%d, DisplayMessage=%s, Param1=%d, Param2=%d.\n", + request->data.alarm.alarm_severity, request->data.alarm.display_message, + request->data.alarm.alarm_param1, request->data.alarm.alarm_param2); + /* skinny::alarm event */ + skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_ALARM); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Severity", "%d", request->data.alarm.alarm_severity); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-DisplayMessage", "%s", request->data.alarm.display_message); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param1", "%d", request->data.alarm.alarm_param1); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param2", "%d", request->data.alarm.alarm_param2); + switch_event_fire(&event); - switch(request->data.stimulus.instance_type) { - case SKINNY_BUTTON_LAST_NUMBER_REDIAL: - skinny_create_ingoing_session(listener, &line_instance, &session); - skinny_session_process_dest(session, listener, line_instance, "redial", '\0', 0); - break; - case SKINNY_BUTTON_SPEED_DIAL: - skinny_speed_dial_get(listener, request->data.stimulus.instance, &button); - if(strlen(button->line) > 0) { - skinny_create_ingoing_session(listener, &line_instance, &session); - skinny_session_process_dest(session, listener, line_instance, button->line, '\0', 0); - } - break; - case SKINNY_BUTTON_HOLD: - session = skinny_profile_find_session(listener->profile, listener, &line_instance, call_id); - - if(session) { - status = skinny_session_hold_line(session, listener, line_instance); - } - break; - case SKINNY_BUTTON_VOICEMAIL: - skinny_create_ingoing_session(listener, &line_instance, &session); - skinny_session_process_dest(session, listener, line_instance, "vmain", '\0', 0); - break; - default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown Stimulus Type Received [%d]\n", request->data.stimulus.instance_type); - } - - if(session) { - switch_core_session_rwunlock(session); - } - - return status; + return SWITCH_STATUS_SUCCESS; } switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *listener, skinny_message_t *request) @@ -2341,96 +2394,146 @@ switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *liste 0, /* uint32_t silence_suppression, */ 0, /* uint16_t max_frames_per_packet, */ 0 /* uint32_t g723_bitrate */ - ); - if (switch_channel_get_state(channel) == CS_NEW) { - switch_channel_set_state(channel, CS_INIT); - } - switch_channel_mark_answered(channel); + ); + if (switch_channel_get_state(channel) == CS_NEW) { + switch_channel_set_state(channel, CS_INIT); + } + switch_channel_mark_answered(channel); } end: - if(session) { switch_core_session_rwunlock(session); } - return status; } -switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_message_t *request) { - uint32_t line_instance = 0; - switch_core_session_t *session; + skinny_message_t *message; + skinny_profile_t *profile; - skinny_check_data_length(request, sizeof(request->data.keypad_button)); + switch_assert(listener->profile); + switch_assert(listener->device_name); + + profile = listener->profile; + + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.soft_key_set)); + message->type = SOFT_KEY_SET_RES_MESSAGE; + message->length = 4 + sizeof(message->data.soft_key_set); + + message->data.soft_key_set.soft_key_set_offset = 0; + message->data.soft_key_set.soft_key_set_count = 11; + message->data.soft_key_set.total_soft_key_set_count = 11; + + /* TODO fill the set */ + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[0] = SOFTKEY_NEWCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOOK].soft_key_template_index[1] = SOFTKEY_REDIAL; - if(request->data.keypad_button.line_instance) { - line_instance = request->data.keypad_button.line_instance; - } else { - line_instance = 1; - } + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK].soft_key_template_index[1] = SOFTKEY_REDIAL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK].soft_key_template_index[2] = SOFTKEY_ENDCALL; - session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.keypad_button.call_id); + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT].soft_key_template_index[0] = SOFTKEY_BACKSPACE; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT].soft_key_template_index[2] = SOFTKEY_ENDCALL; - if(session) { - switch_channel_t *channel = NULL; - private_t *tech_pvt = NULL; - char digit = '\0'; - - channel = switch_core_session_get_channel(session); - tech_pvt = switch_core_session_get_private(session); - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "SEND DTMF ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); - - if (request->data.keypad_button.button == 14) { - digit = '*'; - } else if (request->data.keypad_button.button == 15) { - digit = '#'; - } else if (request->data.keypad_button.button >= 0 && request->data.keypad_button.button <= 9) { - digit = '0' + request->data.keypad_button.button; - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "UNKNOW DTMF RECEIVED ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button); - } - - /* TODO check call_id and line */ - - if((skinny_line_get_state(listener, line_instance, tech_pvt->call_id) == SKINNY_OFF_HOOK)) { + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[0] = SOFTKEY_ENDCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[1] = SOFTKEY_HOLD; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[2] = SOFTKEY_NEWCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_CONNECTED].soft_key_template_index[3] = SOFTKEY_TRANSFER; - skinny_session_process_dest(session, listener, line_instance, NULL, digit, 0); - } else { - if(digit != '\0') { - switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0)}; - dtmf.digit = digit; - switch_channel_queue_dtmf(channel, &dtmf); - } - } - } + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[0] = SOFTKEY_ANSWER; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[1] = SOFTKEY_ENDCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_RING_IN].soft_key_template_index[2] = SOFTKEY_NEWCALL; - if(session) { - switch_core_session_rwunlock(session); - } + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[0] = SOFTKEY_NEWCALL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[1] = SOFTKEY_RESUME; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_ON_HOLD].soft_key_template_index[2] = SOFTKEY_ENDCALL; + + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES].soft_key_template_index[1] = SOFTKEY_REDIAL; + message->data.soft_key_set.soft_key_set[SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES].soft_key_template_index[2] = SOFTKEY_ENDCALL; + + skinny_send_reply(listener, message); + + /* Init the states */ + send_select_soft_keys(listener, 0, 0, SKINNY_KEY_SET_ON_HOOK, 0xffff); return SWITCH_STATUS_SUCCESS; } -switch_status_t skinny_handle_on_hook_message(listener_t *listener, skinny_message_t *request) +switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinny_message_t *request) { switch_status_t status = SWITCH_STATUS_SUCCESS; - switch_core_session_t *session = NULL; uint32_t line_instance = 0; + switch_core_session_t *session = NULL; + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; - skinny_check_data_length(request, sizeof(request->data.on_hook)); - - line_instance = request->data.on_hook.line_instance; + switch_assert(listener); + switch_assert(listener->profile); - session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.on_hook.call_id); + skinny_check_data_length(request, sizeof(request->data.soft_key_event)); - if(session) { - switch_channel_t *channel = NULL; + line_instance = request->data.soft_key_event.line_instance; - channel = switch_core_session_get_channel(session); + switch(request->data.soft_key_event.event) { + case SOFTKEY_REDIAL: + status = skinny_create_ingoing_session(listener, &line_instance, &session); - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + skinny_session_process_dest(session, listener, line_instance, "redial", '\0', 0); + break; + case SOFTKEY_NEWCALL: + status = skinny_create_ingoing_session(listener, &line_instance, &session); + tech_pvt = switch_core_session_get_private(session); + + skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0); + break; + case SOFTKEY_HOLD: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); + + if(session) { + status = skinny_session_hold_line(session, listener, line_instance); + } + break; + case SOFTKEY_TRANSFER: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); + + if(session) { + status = skinny_session_transfer(session, listener, line_instance); + } + break; + case SOFTKEY_BACKSPACE: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); + + if(session) { + skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 1); + } + break; + case SOFTKEY_ENDCALL: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); + + if(session) { + channel = switch_core_session_get_channel(session); + + switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + } + break; + case SOFTKEY_RESUME: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); + + if(session) { + status = skinny_session_unhold_line(session, listener, line_instance); + } + break; + case SOFTKEY_ANSWER: + session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.soft_key_event.call_id); + + if(session) { + status = skinny_session_answer(session, listener, line_instance); + } + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Unknown SoftKeyEvent type: %d.\n", request->data.soft_key_event.event); } if(session) { @@ -2461,6 +2564,89 @@ switch_status_t skinny_handle_unregister(listener_t *listener, skinny_message_t return SWITCH_STATUS_SUCCESS; } +switch_status_t skinny_handle_soft_key_template_request(listener_t *listener, skinny_message_t *request) +{ + skinny_message_t *message; + skinny_profile_t *profile; + + switch_assert(listener->profile); + switch_assert(listener->device_name); + + profile = listener->profile; + + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.soft_key_template)); + message->type = SOFT_KEY_TEMPLATE_RES_MESSAGE; + message->length = 4 + sizeof(message->data.soft_key_template); + + message->data.soft_key_template.soft_key_offset = 0; + message->data.soft_key_template.soft_key_count = 21; + message->data.soft_key_template.total_soft_key_count = 21; + + memcpy(message->data.soft_key_template.soft_key, + soft_key_template_default, + sizeof(soft_key_template_default)); + + skinny_send_reply(listener, message); + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_headset_status_message(listener_t *listener, skinny_message_t *request) +{ + skinny_check_data_length(request, sizeof(request->data.headset_status)); + + /* Nothing to do */ + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_handle_register_available_lines_message(listener_t *listener, skinny_message_t *request) +{ + skinny_check_data_length(request, sizeof(request->data.reg_lines)); + + /* Do nothing */ + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_handle_service_url_stat_request(listener_t *listener, skinny_message_t *request) +{ + skinny_message_t *message; + struct service_url_stat_res_message *button = NULL; + + skinny_check_data_length(request, sizeof(request->data.service_url_req)); + + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.service_url_res)); + message->type = SERVICE_URL_STAT_RES_MESSAGE; + message->length = 4 + sizeof(message->data.service_url_res); + + skinny_service_url_get(listener, request->data.service_url_req.service_url_index, &button); + + memcpy(&message->data.service_url_res, button, sizeof(struct service_url_stat_res_message)); + + skinny_send_reply(listener, message); + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t skinny_handle_feature_stat_request(listener_t *listener, skinny_message_t *request) +{ + skinny_message_t *message; + struct feature_stat_res_message *button = NULL; + + skinny_check_data_length(request, sizeof(request->data.feature_req)); + + message = switch_core_alloc(listener->pool, 12+sizeof(message->data.feature_res)); + message->type = FEATURE_STAT_RES_MESSAGE; + message->length = 4 + sizeof(message->data.feature_res); + + skinny_feature_get(listener, request->data.feature_req.feature_index, &button); + + memcpy(&message->data.feature_res, button, sizeof(struct feature_stat_res_message)); + + skinny_send_reply(listener, message); + + return SWITCH_STATUS_SUCCESS; +} + switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *request) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, @@ -2495,6 +2681,8 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re return skinny_handle_time_date_request(listener, request); case BUTTON_TEMPLATE_REQ_MESSAGE: return skinny_handle_button_template_request(listener, request); + case VERSION_REQ_MESSAGE: + return skinny_handle_version_request(listener, request); case CAPABILITIES_RES_MESSAGE: return skinny_handle_capabilities_response(listener, request); case ALARM_MESSAGE: @@ -2509,14 +2697,14 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re return skinny_handle_unregister(listener, request); case SOFT_KEY_TEMPLATE_REQ_MESSAGE: return skinny_handle_soft_key_template_request(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 HEADSET_STATUS_MESSAGE: return skinny_headset_status_message(listener, request); case REGISTER_AVAILABLE_LINES_MESSAGE: return skinny_handle_register_available_lines_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); 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_protocol.h b/src/mod/endpoints/mod_skinny/skinny_protocol.h index c038be5cc9..aeaa42f09e 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.h +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.h @@ -114,6 +114,9 @@ struct line_stat_req_message { /* ButtonTemplateReqMessage */ #define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E +/* VersionReqMessage */ +#define VERSION_REQ_MESSAGE 0x000F + /* CapabilitiesResMessage */ #define CAPABILITIES_RES_MESSAGE 0x0010 struct station_capabilities { @@ -162,18 +165,6 @@ struct soft_key_event_message { /* SoftKeyTemplateReqMessage */ #define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028 -/* ServiceUrlStatReqMessage */ -#define SERVICE_URL_STAT_REQ_MESSAGE 0x0033 -struct service_url_stat_req_message { - uint32_t service_url_index; -}; - -/* FeatureStatReqMessage */ -#define FEATURE_STAT_REQ_MESSAGE 0x0034 -struct feature_stat_req_message { - uint32_t feature_index; -}; - /* HeadsetStatusMessage */ #define HEADSET_STATUS_MESSAGE 0x002B struct headset_status_message { @@ -186,6 +177,18 @@ struct register_available_lines_message { uint32_t count; }; +/* ServiceUrlStatReqMessage */ +#define SERVICE_URL_STAT_REQ_MESSAGE 0x0033 +struct service_url_stat_req_message { + uint32_t service_url_index; +}; + +/* FeatureStatReqMessage */ +#define FEATURE_STAT_REQ_MESSAGE 0x0034 +struct feature_stat_req_message { + uint32_t feature_index; +}; + /* RegisterAckMessage */ #define REGISTER_ACK_MESSAGE 0x0081 struct register_ack_message { @@ -343,6 +346,12 @@ struct button_template_message { struct button_definition btn[SKINNY_MAX_BUTTON_COUNT]; }; +/* VersionMessage */ +#define VERSION_MESSAGE 0x0098 +struct version_message { + char version[16]; +}; + /* CapabilitiesReqMessage */ #define CAPABILITIES_REQ_MESSAGE 0x009B @@ -535,6 +544,7 @@ union skinny_data { struct config_stat_res_message config_res; struct define_time_date_message define_time_date; struct button_template_message button_template; + struct version_message version; struct register_reject_message reg_rej; struct reset_message reset; struct open_receive_channel_message open_receive_channel; @@ -724,6 +734,10 @@ switch_status_t send_define_time_date(listener_t *listener, uint32_t milliseconds, uint32_t timestamp); switch_status_t send_define_current_time_date(listener_t *listener); +switch_status_t send_version(listener_t *listener, + char *version); +switch_status_t send_register_reject(listener_t *listener, + char *error); switch_status_t send_open_receive_channel(listener_t *listener, uint32_t conference_id, uint32_t pass_thru_party_id, diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.c b/src/mod/endpoints/mod_skinny/skinny_tables.c index a9bf84431f..ac16b6509f 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.c +++ b/src/mod/endpoints/mod_skinny/skinny_tables.c @@ -47,6 +47,7 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = { {"ConfigStatReqMessage", CONFIG_STAT_REQ_MESSAGE}, {"TimeDateReqMessage", TIME_DATE_REQ_MESSAGE}, {"ButtonTemplateReqMessage", BUTTON_TEMPLATE_REQ_MESSAGE}, + {"VersionReqMessage", VERSION_REQ_MESSAGE}, {"CapabilitiesReqMessage", CAPABILITIES_RES_MESSAGE}, {"AlarmMessage", ALARM_MESSAGE}, {"OpenReceiveChannelAckMessage", OPEN_RECEIVE_CHANNEL_ACK_MESSAGE}, @@ -72,6 +73,7 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = { {"ConfigStatResMessage", CONFIG_STAT_RES_MESSAGE}, {"DefineTimeDateMessage", DEFINE_TIME_DATE_MESSAGE}, {"ButtonTemplateResMessage", BUTTON_TEMPLATE_RES_MESSAGE}, + {"VersionMessage", VERSION_MESSAGE}, {"CapabilitiesReqMessage", CAPABILITIES_REQ_MESSAGE}, {"RegisterRejectMessage", REGISTER_REJECT_MESSAGE}, {"ResetMessage", RESET_MESSAGE}, @@ -96,6 +98,24 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = { SKINNY_DECLARE_ID2STR(skinny_message_type2str, SKINNY_MESSAGE_TYPES, "UnknownMessage") SKINNY_DECLARE_STR2ID(skinny_str2message_type, SKINNY_MESSAGE_TYPES, -1) +struct skinny_table SKINNY_DEVICE_TYPES[] = { + {"Cisco 30 SP+", 0x0001}, + {"Cisco 12 SP+", 0x0002}, + {"Cisco 12 SP", 0x0003}, + {"Cisco 12", 0x0004}, + {"Cisco 30 VIP", 0x0005}, + {"Cisco IP Phone 7910", 0x0006}, + {"Cisco IP Phone 7960", 0x0007}, + {"Cisco IP Phone 7940", 0x0008}, + {"Cisco IP Phone 7935", 0x0009}, + {"Cisco ATA 186", 0x000c}, + {"Cisco IP Phone 7961", 0x4275}, + {"Cisco IP Phone 7936", 0x4276}, + {NULL, 0} +}; +SKINNY_DECLARE_ID2STR(skinny_device_type2str, SKINNY_DEVICE_TYPES, "UnknownDeviceType") +SKINNY_DECLARE_STR2ID(skinny_str2device_type, SKINNY_DEVICE_TYPES, -1) + struct skinny_table SKINNY_RING_TYPES[] = { {"RingOff", SKINNY_RING_OFF}, {"RingInside", SKINNY_RING_INSIDE}, diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.h b/src/mod/endpoints/mod_skinny/skinny_tables.h index f3755b5c2f..5efd774648 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.h +++ b/src/mod/endpoints/mod_skinny/skinny_tables.h @@ -84,11 +84,16 @@ uint32_t func(const char *str)\ } -struct skinny_table SKINNY_MESSAGE_TYPES[57]; +struct skinny_table SKINNY_MESSAGE_TYPES[59]; 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) +struct skinny_table SKINNY_DEVICE_TYPES[13]; +const char *skinny_device_type2str(uint32_t id); +uint32_t skinny_str2device_type(const char *str); +#define SKINNY_PUSH_DEVICE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_DEVICE_TYPES) + enum skinny_tone { SKINNY_TONE_SILENCE = 0x00, SKINNY_TONE_DIALTONE = 0x21, diff --git a/src/mod/endpoints/mod_skinny/test-skinny.pl b/src/mod/endpoints/mod_skinny/test-skinny.pl index a8c7bb5d68..a44afa33dc 100644 --- a/src/mod/endpoints/mod_skinny/test-skinny.pl +++ b/src/mod/endpoints/mod_skinny/test-skinny.pl @@ -64,6 +64,11 @@ $socket->send_message( ) ); +if(0) { + $socket->send_message(VERSION_REQ_MESSAGE); + $socket->receive_message(); # VersionMessage +} + $socket->send_message(BUTTON_TEMPLATE_REQ_MESSAGE); $socket->receive_message(); # ButtonTemplateMessage diff --git a/src/mod/endpoints/mod_skypopen/mod_skypopen.2008.vcproj b/src/mod/endpoints/mod_skypopen/mod_skypopen.2008.vcproj index 585123b4a2..1e3acada07 100644 --- a/src/mod/endpoints/mod_skypopen/mod_skypopen.2008.vcproj +++ b/src/mod/endpoints/mod_skypopen/mod_skypopen.2008.vcproj @@ -118,7 +118,7 @@ /> diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 0f0abfa09a..1930454ebc 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -657,7 +657,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) } if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { - char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); + char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_RESPONSE_HEADER_PREFIX); if (sofia_use_soa(tech_pvt)) { nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_AUTOANSWER(0), @@ -802,6 +802,7 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f switch_channel_t *channel = switch_core_session_get_channel(session); int payload = 0; uint32_t sanity = 1000; + switch_rtcp_frame_t rtcp_frame; switch_assert(tech_pvt != NULL); @@ -859,6 +860,50 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f } return status; } + + /* Try to read an RTCP frame, if successful raise an event */ + if (switch_rtcp_zerocopy_read_frame(tech_pvt->rtp_session, &rtcp_frame) == SWITCH_STATUS_SUCCESS) { + switch_event_t *event; + + if (switch_event_create(&event, SWITCH_EVENT_RECV_RTCP_MESSAGE) == SWITCH_STATUS_SUCCESS) { + char buf[30]; + + char* uuid = switch_core_session_get_uuid(session); + if (uuid) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(session)); + } + + snprintf(buf, sizeof(buf), "%.8x", rtcp_frame.ssrc); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SSRC", buf); + + snprintf(buf, sizeof(buf), "%u", rtcp_frame.ntp_msw); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "NTP-Most-Significant-Word", buf); + + snprintf(buf, sizeof(buf), "%u", rtcp_frame.ntp_lsw); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "NTP-Least-Significant-Word", buf); + + snprintf(buf, sizeof(buf), "%u", rtcp_frame.timestamp); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "RTP-Timestamp", buf); + + snprintf(buf, sizeof(buf), "%u", rtcp_frame.packet_count); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Sender-Packet-Count", buf); + + snprintf(buf, sizeof(buf), "%u", rtcp_frame.octect_count); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Octect-Packet-Count", buf); + + snprintf(buf, sizeof(buf), "%" SWITCH_SIZE_T_FMT, tech_pvt->read_frame.timestamp); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Last-RTP-Timestamp", buf); + + snprintf(buf, sizeof(buf), "%u", tech_pvt->read_frame.rate); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "RTP-Rate", buf); + + snprintf(buf, sizeof(buf), "%" SWITCH_TIME_T_FMT, switch_time_now()); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Capture-Time", buf); + + switch_event_fire(&event); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG10, "Dispatched RTCP event\n"); + } + } /* Fast PASS! */ if (switch_test_flag((&tech_pvt->read_frame), SFF_PROXY_PACKET)) { @@ -1496,6 +1541,19 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } break; + case SWITCH_MESSAGE_INDICATE_PHONE_EVENT: + { + const char *event = "talk"; + if (!zstr(msg->string_arg) && strcasecmp(msg->string_arg, event)) { + if (!strcasecmp(msg->string_arg, "hold")) { + event = "hold"; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid event.\n"); + } + } + nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active), SIPTAG_EVENT_STR(event), TAG_END()); + } + break; case SWITCH_MESSAGE_INDICATE_SIMPLIFY: { char *ref_to, *ref_by; diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index c03da5f648..e1b1e61d53 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -466,6 +466,8 @@ struct sofia_profile { char *record_path; char *presence_hosts; char *challenge_realm; + char *rtcp_audio_interval_msec; + char *rtcp_video_interval_msec; sofia_cid_type_t cid_type; sofia_dtmf_t dtmf_type; int auto_restart; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index df3da21156..8338663e30 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1371,6 +1371,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void NUTAG_ALLOW("INFO"), NUTAG_ALLOW("NOTIFY"), NUTAG_ALLOW_EVENTS("talk"), + NUTAG_ALLOW_EVENTS("hold"), NUTAG_SESSION_TIMER(profile->session_timeout), NTATAG_MAX_PROCEEDING(profile->max_proceeding), TAG_IF(profile->pres_type, NUTAG_ALLOW("PUBLISH")), @@ -2458,6 +2459,10 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile) profile->hold_music = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "outbound-proxy")) { profile->outbound_proxy = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "rtcp-audio-interval-msec")) { + profile->rtcp_audio_interval_msec = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "rtcp-video-interval-msec")) { + profile->rtcp_video_interval_msec = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "session-timeout")) { int v_session_timeout = atoi(val); if (v_session_timeout >= 0) { @@ -2995,6 +3000,10 @@ switch_status_t config_sofia(int reload, char *profile_name) profile->hold_music = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "outbound-proxy")) { profile->outbound_proxy = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "rtcp-audio-interval-msec")) { + profile->rtcp_audio_interval_msec = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "rtcp-video-interval-msec")) { + profile->rtcp_video_interval_msec = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "session-timeout")) { int v_session_timeout = atoi(val); if (v_session_timeout >= 0) { @@ -3743,6 +3752,12 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status char *full_contact = NULL; char *invite_contact; const char *br; + const char *v; + + if ((v = switch_channel_get_variable(channel, "outbound_redirect_fatal")) && switch_true(v)) { + switch_channel_hangup(channel, SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL); + goto end; + } if (!p_contact) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing contact header in redirect request\n"); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 782e62dd90..77b82b0665 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -691,7 +691,7 @@ const char *sofia_glue_get_unknown_header(sip_t const *sip, const char *name) switch_status_t sofia_glue_tech_choose_port(private_object_t *tech_pvt, int force) { char *lookup_rtpip = tech_pvt->profile->rtpip; /* Pointer to externally looked up address */ - switch_port_t sdp_port; /* The external port to be sent in the SDP */ + switch_port_t sdp_port, rtcp_port; /* The external port to be sent in the SDP */ const char *use_ip = NULL; /* The external IP to be sent in the SDP */ /* Don't do anything if we're in proxy mode or if a (remote) port already has been found */ @@ -734,6 +734,7 @@ switch_status_t sofia_glue_tech_choose_port(private_object_t *tech_pvt, int forc 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->profile->rtpip; @@ -1126,8 +1127,16 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt) sofia_set_flag_locked(tech_pvt, TFLAG_VIDEO); switch_channel_set_flag(tech_pvt->channel, CF_VIDEO); if (switch_rtp_ready(tech_pvt->video_rtp_session)) { + const char *rport = NULL; + 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); + } + + if (switch_rtp_set_remote_address(tech_pvt->video_rtp_session, tech_pvt->remote_sdp_video_ip, - tech_pvt->remote_sdp_video_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { + tech_pvt->remote_sdp_video_port, remote_rtcp_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", err); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "VIDEO RTP CHANGING DEST TO: [%s:%d]\n", @@ -1148,6 +1157,8 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt) if (switch_rtp_ready(tech_pvt->rtp_session)) { 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); + const char *rport = NULL; + switch_port_t remote_rtcp_port = 0; 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, "Remote address:port [%s:%d] has not changed.\n", @@ -1155,8 +1166,13 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt) return SWITCH_STATUS_SUCCESS; } + if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port"))) { + remote_rtcp_port = atoi(rport); + } + + if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, - tech_pvt->remote_sdp_audio_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { + tech_pvt->remote_sdp_audio_port, remote_rtcp_port, 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); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "AUDIO RTP CHANGING DEST TO: [%s:%d]\n", @@ -2604,9 +2620,17 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp); if (tech_pvt->rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) { + const char *rport = NULL; + switch_port_t remote_rtcp_port = 0; + sofia_clear_flag_locked(tech_pvt, TFLAG_REINVITE); - if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port, SWITCH_TRUE, &err) != + if ((rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port"))) { + remote_rtcp_port = atoi(rport); + } + + if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port, + remote_rtcp_port, 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); } else { @@ -2725,6 +2749,24 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f switch_rtp_activate_stun_ping(tech_pvt->rtp_session, tech_pvt->stun_ip, tech_pvt->stun_port, stun_ping, (tech_pvt->stun_flags & STUN_FLAG_FUNNY) ? 1 : 0); } + + if ((val = switch_channel_get_variable(tech_pvt->channel, "rtcp_audio_interval_msec")) || (val = tech_pvt->profile->rtcp_audio_interval_msec)) { + 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); + } + if (!strcasecmp(val, "passthru")) { + switch_rtp_activate_rtcp(tech_pvt->rtp_session, -1, remote_port); + } else { + int interval = atoi(val); + if (interval < 100 || interval > 5000) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Invalid rtcp interval spec [%d] must be between 100 and 5000\n", interval); + } else { + switch_rtp_activate_rtcp(tech_pvt->rtp_session, interval, remote_port); + } + } + } if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec"))) { int len = atoi(val); @@ -2840,10 +2882,17 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f switch_channel_set_variable(tech_pvt->channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE, tmp); if (tech_pvt->video_rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) { + const char *rport = NULL; + switch_port_t remote_rtcp_port = 0; + 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); + } + if (switch_rtp_set_remote_address - (tech_pvt->video_rtp_session, tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port, SWITCH_TRUE, + (tech_pvt->video_rtp_session, tech_pvt->remote_sdp_video_ip, tech_pvt->remote_sdp_video_port, remote_rtcp_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", err); } else { @@ -2940,6 +2989,27 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_video_pt", "%d", tech_pvt->video_agreed_pt); tech_pvt->video_ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session); switch_channel_set_variable_printf(tech_pvt->channel, "rtp_use_video_ssrc", "%u", tech_pvt->ssrc); + + + if ((val = switch_channel_get_variable(tech_pvt->channel, "rtcp_audio_interval_msec")) || (val = tech_pvt->profile->rtcp_audio_interval_msec)) { + 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); + } + if (!strcasecmp(val, "passthru")) { + switch_rtp_activate_rtcp(tech_pvt->rtp_session, -1, remote_port); + } else { + int interval = atoi(val); + if (interval < 100 || interval > 5000) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Invalid rtcp interval spec [%d] must be between 100 and 5000\n", interval); + } else { + switch_rtp_activate_rtcp(tech_pvt->rtp_session, interval, remote_port); + } + } + } + + } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err)); switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); @@ -3369,6 +3439,11 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t * } else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) { sdp_rtpmap_t *map; for (attr = m->m_attributes; attr; attr = attr->a_next) { + + if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) { + switch_channel_set_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port", attr->a_value); + } + if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) { ptime = atoi(attr->a_value); } else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) { @@ -3699,6 +3774,9 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t * if (!strcasecmp(attr->a_name, "framerate") && attr->a_value) { framerate = atoi(attr->a_value); } + if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) { + switch_channel_set_variable(tech_pvt->channel, "sip_remote_video_rtcp_port", attr->a_value); + } } if (!(rm_encoding = map->rm_encoding)) { rm_encoding = ""; diff --git a/src/mod/event_handlers/mod_json_cdr/mod_json_cdr.2008.vcproj b/src/mod/event_handlers/mod_json_cdr/mod_json_cdr.2008.vcproj index 1af8141191..d330aba5d8 100644 --- a/src/mod/event_handlers/mod_json_cdr/mod_json_cdr.2008.vcproj +++ b/src/mod/event_handlers/mod_json_cdr/mod_json_cdr.2008.vcproj @@ -104,7 +104,7 @@ /> version = arg2; + +} + + +SWIGEXPORT unsigned int SWIGSTDCALL CSharp_switch_rtcp_hdr_t_version_get(void * jarg1) { + unsigned int jresult ; + switch_rtcp_hdr_t *arg1 = (switch_rtcp_hdr_t *) 0 ; + unsigned int result; + + arg1 = (switch_rtcp_hdr_t *)jarg1; + result = (unsigned int) ((arg1)->version); + jresult = result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_rtcp_hdr_t_p_set(void * jarg1, unsigned int jarg2) { + switch_rtcp_hdr_t *arg1 = (switch_rtcp_hdr_t *) 0 ; + unsigned int arg2 ; + + arg1 = (switch_rtcp_hdr_t *)jarg1; + arg2 = (unsigned int)jarg2; + if (arg1) (arg1)->p = arg2; + +} + + +SWIGEXPORT unsigned int SWIGSTDCALL CSharp_switch_rtcp_hdr_t_p_get(void * jarg1) { + unsigned int jresult ; + switch_rtcp_hdr_t *arg1 = (switch_rtcp_hdr_t *) 0 ; + unsigned int result; + + arg1 = (switch_rtcp_hdr_t *)jarg1; + result = (unsigned int) ((arg1)->p); + jresult = result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_rtcp_hdr_t_count_set(void * jarg1, unsigned int jarg2) { + switch_rtcp_hdr_t *arg1 = (switch_rtcp_hdr_t *) 0 ; + unsigned int arg2 ; + + arg1 = (switch_rtcp_hdr_t *)jarg1; + arg2 = (unsigned int)jarg2; + if (arg1) (arg1)->count = arg2; + +} + + +SWIGEXPORT unsigned int SWIGSTDCALL CSharp_switch_rtcp_hdr_t_count_get(void * jarg1) { + unsigned int jresult ; + switch_rtcp_hdr_t *arg1 = (switch_rtcp_hdr_t *) 0 ; + unsigned int result; + + arg1 = (switch_rtcp_hdr_t *)jarg1; + result = (unsigned int) ((arg1)->count); + jresult = result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_rtcp_hdr_t_type_set(void * jarg1, unsigned int jarg2) { + switch_rtcp_hdr_t *arg1 = (switch_rtcp_hdr_t *) 0 ; + unsigned int arg2 ; + + arg1 = (switch_rtcp_hdr_t *)jarg1; + arg2 = (unsigned int)jarg2; + if (arg1) (arg1)->type = arg2; + +} + + +SWIGEXPORT unsigned int SWIGSTDCALL CSharp_switch_rtcp_hdr_t_type_get(void * jarg1) { + unsigned int jresult ; + switch_rtcp_hdr_t *arg1 = (switch_rtcp_hdr_t *) 0 ; + unsigned int result; + + arg1 = (switch_rtcp_hdr_t *)jarg1; + result = (unsigned int) ((arg1)->type); + jresult = result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_rtcp_hdr_t_length_set(void * jarg1, unsigned int jarg2) { + switch_rtcp_hdr_t *arg1 = (switch_rtcp_hdr_t *) 0 ; + unsigned int arg2 ; + + arg1 = (switch_rtcp_hdr_t *)jarg1; + arg2 = (unsigned int)jarg2; + if (arg1) (arg1)->length = arg2; + +} + + +SWIGEXPORT unsigned int SWIGSTDCALL CSharp_switch_rtcp_hdr_t_length_get(void * jarg1) { + unsigned int jresult ; + switch_rtcp_hdr_t *arg1 = (switch_rtcp_hdr_t *) 0 ; + unsigned int result; + + arg1 = (switch_rtcp_hdr_t *)jarg1; + result = (unsigned int) ((arg1)->length); + jresult = result; + return jresult; +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_new_switch_rtcp_hdr_t() { + void * jresult ; + switch_rtcp_hdr_t *result = 0 ; + + result = (switch_rtcp_hdr_t *)new switch_rtcp_hdr_t(); + jresult = (void *)result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_delete_switch_rtcp_hdr_t(void * jarg1) { + switch_rtcp_hdr_t *arg1 = (switch_rtcp_hdr_t *) 0 ; + + arg1 = (switch_rtcp_hdr_t *)jarg1; + delete arg1; + +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_t38_options_t_T38MaxBitRate_set(void * jarg1, unsigned long jarg2) { switch_t38_options_t *arg1 = (switch_t38_options_t *) 0 ; uint32_t arg2 ; @@ -25900,6 +26034,17 @@ SWIGEXPORT int SWIGSTDCALL CSharp_SWITCH_RTP_MAX_BUF_LEN_get() { } +SWIGEXPORT int SWIGSTDCALL CSharp_SWITCH_RTCP_MAX_BUF_LEN_get() { + int jresult ; + int result; + + result = (int) 16384; + + jresult = result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_SWITCH_RTP_MAX_CRYPTO_LEN_get() { int jresult ; int result; @@ -26288,21 +26433,23 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_switch_rtp_new(char * jarg1, unsigned short } -SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_set_remote_address(void * jarg1, char * jarg2, unsigned short jarg3, int jarg4, void * jarg5) { +SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_set_remote_address(void * jarg1, char * jarg2, unsigned short jarg3, unsigned short jarg4, int jarg5, void * jarg6) { int jresult ; switch_rtp_t *arg1 = (switch_rtp_t *) 0 ; char *arg2 = (char *) 0 ; switch_port_t arg3 ; - switch_bool_t arg4 ; - char **arg5 = (char **) 0 ; + switch_port_t arg4 ; + switch_bool_t arg5 ; + char **arg6 = (char **) 0 ; switch_status_t result; arg1 = (switch_rtp_t *)jarg1; arg2 = (char *)jarg2; arg3 = (switch_port_t)jarg3; - arg4 = (switch_bool_t)jarg4; - arg5 = (char **)jarg5; - result = (switch_status_t)switch_rtp_set_remote_address(arg1,(char const *)arg2,arg3,arg4,(char const **)arg5); + arg4 = (switch_port_t)jarg4; + arg5 = (switch_bool_t)jarg5; + arg6 = (char **)jarg6; + result = (switch_status_t)switch_rtp_set_remote_address(arg1,(char const *)arg2,arg3,arg4,arg5,(char const **)arg6); jresult = result; return jresult; } @@ -26420,6 +26567,22 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_ice(void * jarg1, char * j } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_rtcp(void * jarg1, int jarg2, unsigned short jarg3) { + int jresult ; + switch_rtp_t *arg1 = (switch_rtp_t *) 0 ; + int arg2 ; + switch_port_t arg3 ; + switch_status_t result; + + arg1 = (switch_rtp_t *)jarg1; + arg2 = (int)jarg2; + arg3 = (switch_port_t)jarg3; + result = (switch_status_t)switch_rtp_activate_rtcp(arg1,arg2,arg3); + jresult = result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_jitter_buffer(void * jarg1, unsigned long jarg2) { int jresult ; switch_rtp_t *arg1 = (switch_rtp_t *) 0 ; @@ -26638,6 +26801,20 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_zerocopy_read_frame(void * jarg1, v } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtcp_zerocopy_read_frame(void * jarg1, void * jarg2) { + int jresult ; + switch_rtp_t *arg1 = (switch_rtp_t *) 0 ; + switch_rtcp_frame_t *arg2 = (switch_rtcp_frame_t *) 0 ; + switch_status_t result; + + arg1 = (switch_rtp_t *)jarg1; + arg2 = (switch_rtcp_frame_t *)jarg2; + result = (switch_status_t)switch_rtcp_zerocopy_read_frame(arg1,arg2); + jresult = result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_rtp_flush_read_buffer(void * jarg1, int jarg2) { switch_rtp_t *arg1 = (switch_rtp_t *) 0 ; switch_rtp_flush_t arg2 ; diff --git a/src/mod/languages/mod_managed/managed/swig.cs b/src/mod/languages/mod_managed/managed/swig.cs index 1821bbb088..66be726ebd 100644 --- a/src/mod/languages/mod_managed/managed/swig.cs +++ b/src/mod/languages/mod_managed/managed/swig.cs @@ -4056,8 +4056,8 @@ public class freeswitch { return ret; } - public static switch_status_t switch_rtp_set_remote_address(SWIGTYPE_p_switch_rtp rtp_session, string host, ushort port, switch_bool_t change_adv_addr, ref string err) { - switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_set_remote_address(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), host, port, (int)change_adv_addr, ref err); + public static switch_status_t switch_rtp_set_remote_address(SWIGTYPE_p_switch_rtp rtp_session, string host, ushort port, ushort remote_rtcp_port, switch_bool_t change_adv_addr, ref string err) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_set_remote_address(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), host, port, remote_rtcp_port, (int)change_adv_addr, ref err); return ret; } @@ -4106,6 +4106,11 @@ public class freeswitch { return ret; } + public static switch_status_t switch_rtp_activate_rtcp(SWIGTYPE_p_switch_rtp rtp_session, int send_rate, ushort remote_port) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_activate_rtcp(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), send_rate, remote_port); + return ret; + } + public static switch_status_t switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session, uint queue_frames) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), queue_frames); return ret; @@ -4183,6 +4188,11 @@ public class freeswitch { return ret; } + public static switch_status_t switch_rtcp_zerocopy_read_frame(SWIGTYPE_p_switch_rtp rtp_session, SWIGTYPE_p_switch_rtcp_frame frame) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtcp_zerocopy_read_frame(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), SWIGTYPE_p_switch_rtcp_frame.getCPtr(frame)); + return ret; + } + public static void rtp_flush_read_buffer(SWIGTYPE_p_switch_rtp rtp_session, switch_rtp_flush_t flush) { freeswitchPINVOKE.rtp_flush_read_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), (int)flush); } @@ -4914,6 +4924,7 @@ public class freeswitch { public static readonly int SWITCH_SMIN = freeswitchPINVOKE.SWITCH_SMIN_get(); public static readonly int SWITCH_RESAMPLE_QUALITY = freeswitchPINVOKE.SWITCH_RESAMPLE_QUALITY_get(); public static readonly int SWITCH_RTP_MAX_BUF_LEN = freeswitchPINVOKE.SWITCH_RTP_MAX_BUF_LEN_get(); + public static readonly int SWITCH_RTCP_MAX_BUF_LEN = freeswitchPINVOKE.SWITCH_RTCP_MAX_BUF_LEN_get(); public static readonly int SWITCH_RTP_MAX_CRYPTO_LEN = freeswitchPINVOKE.SWITCH_RTP_MAX_CRYPTO_LEN_get(); public static readonly int SWITCH_RTP_KEY_LEN = freeswitchPINVOKE.SWITCH_RTP_KEY_LEN_get(); public static readonly string SWITCH_RTP_CRYPTO_KEY_32 = freeswitchPINVOKE.SWITCH_RTP_CRYPTO_KEY_32_get(); @@ -5866,6 +5877,42 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_delete_switch_rtp_hdr_t")] public static extern void delete_switch_rtp_hdr_t(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtcp_hdr_t_version_set")] + public static extern void switch_rtcp_hdr_t_version_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtcp_hdr_t_version_get")] + public static extern uint switch_rtcp_hdr_t_version_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtcp_hdr_t_p_set")] + public static extern void switch_rtcp_hdr_t_p_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtcp_hdr_t_p_get")] + public static extern uint switch_rtcp_hdr_t_p_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtcp_hdr_t_count_set")] + public static extern void switch_rtcp_hdr_t_count_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtcp_hdr_t_count_get")] + public static extern uint switch_rtcp_hdr_t_count_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtcp_hdr_t_type_set")] + public static extern void switch_rtcp_hdr_t_type_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtcp_hdr_t_type_get")] + public static extern uint switch_rtcp_hdr_t_type_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtcp_hdr_t_length_set")] + public static extern void switch_rtcp_hdr_t_length_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtcp_hdr_t_length_get")] + public static extern uint switch_rtcp_hdr_t_length_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_new_switch_rtcp_hdr_t")] + public static extern IntPtr new_switch_rtcp_hdr_t(); + + [DllImport("mod_managed", EntryPoint="CSharp_delete_switch_rtcp_hdr_t")] + public static extern void delete_switch_rtcp_hdr_t(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_t38_options_t_T38MaxBitRate_set")] public static extern void switch_t38_options_t_T38MaxBitRate_set(HandleRef jarg1, uint jarg2); @@ -11152,6 +11199,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_SWITCH_RTP_MAX_BUF_LEN_get")] public static extern int SWITCH_RTP_MAX_BUF_LEN_get(); + [DllImport("mod_managed", EntryPoint="CSharp_SWITCH_RTCP_MAX_BUF_LEN_get")] + public static extern int SWITCH_RTCP_MAX_BUF_LEN_get(); + [DllImport("mod_managed", EntryPoint="CSharp_SWITCH_RTP_MAX_CRYPTO_LEN_get")] public static extern int SWITCH_RTP_MAX_CRYPTO_LEN_get(); @@ -11240,7 +11290,7 @@ class freeswitchPINVOKE { public static extern IntPtr switch_rtp_new(string jarg1, ushort jarg2, string jarg3, ushort jarg4, byte jarg5, uint jarg6, uint jarg7, uint jarg8, string jarg9, ref string jarg10, HandleRef jarg11); [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_set_remote_address")] - public static extern int switch_rtp_set_remote_address(HandleRef jarg1, string jarg2, ushort jarg3, int jarg4, ref string jarg5); + public static extern int switch_rtp_set_remote_address(HandleRef jarg1, string jarg2, ushort jarg3, ushort jarg4, int jarg5, ref string jarg6); [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_get_remote_host")] public static extern string switch_rtp_get_remote_host(HandleRef jarg1); @@ -11272,6 +11322,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_activate_ice")] public static extern int switch_rtp_activate_ice(HandleRef jarg1, string jarg2, string jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_activate_rtcp")] + public static extern int switch_rtp_activate_rtcp(HandleRef jarg1, int jarg2, ushort jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_activate_jitter_buffer")] public static extern int switch_rtp_activate_jitter_buffer(HandleRef jarg1, uint jarg2); @@ -11320,6 +11373,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_zerocopy_read_frame")] public static extern int switch_rtp_zerocopy_read_frame(HandleRef jarg1, HandleRef jarg2, uint jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtcp_zerocopy_read_frame")] + public static extern int switch_rtcp_zerocopy_read_frame(HandleRef jarg1, HandleRef jarg2); + [DllImport("mod_managed", EntryPoint="CSharp_rtp_flush_read_buffer")] public static extern void rtp_flush_read_buffer(HandleRef jarg1, int jarg2); @@ -16855,6 +16911,36 @@ namespace FreeSWITCH.Native { using System; using System.Runtime.InteropServices; +public class SWIGTYPE_p_switch_rtcp_frame { + private HandleRef swigCPtr; + + internal SWIGTYPE_p_switch_rtcp_frame(IntPtr cPtr, bool futureUse) { + swigCPtr = new HandleRef(this, cPtr); + } + + protected SWIGTYPE_p_switch_rtcp_frame() { + swigCPtr = new HandleRef(null, IntPtr.Zero); + } + + internal static HandleRef getCPtr(SWIGTYPE_p_switch_rtcp_frame obj) { + return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr; + } +} + +} +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 1.3.35 + * + * Do not make changes to this file unless you know what you are doing--modify + * the SWIG interface file instead. + * ----------------------------------------------------------------------------- */ + +namespace FreeSWITCH.Native { + +using System; +using System.Runtime.InteropServices; + public class SWIGTYPE_p_switch_rtp { private HandleRef swigCPtr; @@ -21473,6 +21559,7 @@ public enum switch_core_session_message_types_t { SWITCH_MESSAGE_INDICATE_PROXY_MEDIA, SWITCH_MESSAGE_INDICATE_APPLICATION_EXEC, SWITCH_MESSAGE_INDICATE_APPLICATION_EXEC_COMPLETE, + SWITCH_MESSAGE_INDICATE_PHONE_EVENT, SWITCH_MESSAGE_INVALID } @@ -22861,6 +22948,7 @@ public enum switch_event_types_t { SWITCH_EVENT_SERVER_DISCONNECTED, SWITCH_EVENT_SEND_INFO, SWITCH_EVENT_RECV_INFO, + SWITCH_EVENT_RECV_RTCP_MESSAGE, SWITCH_EVENT_CALL_SECURE, SWITCH_EVENT_NAT, SWITCH_EVENT_RECORD_START, @@ -25770,6 +25858,103 @@ public enum switch_priority_t { namespace FreeSWITCH.Native { +using System; +using System.Runtime.InteropServices; + +public class switch_rtcp_hdr_t : IDisposable { + private HandleRef swigCPtr; + protected bool swigCMemOwn; + + internal switch_rtcp_hdr_t(IntPtr cPtr, bool cMemoryOwn) { + swigCMemOwn = cMemoryOwn; + swigCPtr = new HandleRef(this, cPtr); + } + + internal static HandleRef getCPtr(switch_rtcp_hdr_t obj) { + return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr; + } + + ~switch_rtcp_hdr_t() { + Dispose(); + } + + public virtual void Dispose() { + lock(this) { + if(swigCPtr.Handle != IntPtr.Zero && swigCMemOwn) { + swigCMemOwn = false; + freeswitchPINVOKE.delete_switch_rtcp_hdr_t(swigCPtr); + } + swigCPtr = new HandleRef(null, IntPtr.Zero); + GC.SuppressFinalize(this); + } + } + + public uint version { + set { + freeswitchPINVOKE.switch_rtcp_hdr_t_version_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_rtcp_hdr_t_version_get(swigCPtr); + return ret; + } + } + + public uint p { + set { + freeswitchPINVOKE.switch_rtcp_hdr_t_p_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_rtcp_hdr_t_p_get(swigCPtr); + return ret; + } + } + + public uint count { + set { + freeswitchPINVOKE.switch_rtcp_hdr_t_count_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_rtcp_hdr_t_count_get(swigCPtr); + return ret; + } + } + + public uint type { + set { + freeswitchPINVOKE.switch_rtcp_hdr_t_type_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_rtcp_hdr_t_type_get(swigCPtr); + return ret; + } + } + + public uint length { + set { + freeswitchPINVOKE.switch_rtcp_hdr_t_length_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_rtcp_hdr_t_length_get(swigCPtr); + return ret; + } + } + + public switch_rtcp_hdr_t() : this(freeswitchPINVOKE.new_switch_rtcp_hdr_t(), true) { + } + +} + +} +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 1.3.35 + * + * Do not make changes to this file unless you know what you are doing--modify + * the SWIG interface file instead. + * ----------------------------------------------------------------------------- */ + +namespace FreeSWITCH.Native { + public enum switch_rtp_bug_flag_t { RTP_BUG_NONE = 0, RTP_BUG_CISCO_SKIP_MARK_BIT_2833 = (1 << 0), @@ -25953,7 +26138,9 @@ namespace FreeSWITCH.Native { SWITCH_ZRTP_FLAG_SECURE_MITM_RECV = (1 << 26), SWITCH_RTP_FLAG_DEBUG_RTP_READ = (1 << 27), SWITCH_RTP_FLAG_DEBUG_RTP_WRITE = (1 << 28), - SWITCH_RTP_FLAG_VIDEO = (1 << 29) + SWITCH_RTP_FLAG_VIDEO = (1 << 29), + SWITCH_RTP_FLAG_ENABLE_RTCP = (1 << 30), + SWITCH_RTP_FLAG_RTCP_PASSTHRU = (1 << 31) } } diff --git a/src/mod/loggers/mod_logfile/mod_logfile.c b/src/mod/loggers/mod_logfile/mod_logfile.c index 3645cb1ea1..8cdaf9615a 100644 --- a/src/mod/loggers/mod_logfile/mod_logfile.c +++ b/src/mod/loggers/mod_logfile/mod_logfile.c @@ -398,9 +398,11 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_logfile_shutdown) if ((profile = (logfile_profile_t *) val)) { switch_file_close(profile->log_afd); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Closing %s\n", profile->logfile); + switch_safe_free(profile->logfile); } } + switch_core_hash_destroy(&profile_hash); return SWITCH_STATUS_SUCCESS; diff --git a/src/switch.c b/src/switch.c index 5c761e372c..77aea8dc00 100644 --- a/src/switch.c +++ b/src/switch.c @@ -791,6 +791,7 @@ int main(int argc, char *argv[]) destroy_status = switch_core_destroy(); switch_file_close(fd); + apr_pool_destroy(pool); if (unlink(pid_path) != 0) { fprintf(stderr, "Failed to delete pid file [%s]\n", pid_path); diff --git a/src/switch_channel.c b/src/switch_channel.c index 345d4e791a..acefec30dc 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -2108,6 +2108,11 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_hangup(switch_chan switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_channel_get_uuid(channel), SWITCH_LOG_NOTICE, "Hangup %s [%s] [%s]\n", channel->name, state_names[last_state], switch_channel_cause2str(channel->hangup_cause)); + + if (!switch_core_session_running(channel->session)) { + switch_core_session_thread_launch(channel->session); + } + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_HANGUP) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Hangup-Cause", switch_channel_cause2str(hangup_cause)); switch_channel_event_set_data(channel, event); diff --git a/src/switch_core.c b/src/switch_core.c index fe0ffcbaba..78296ebe7b 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1867,13 +1867,23 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void) switch_safe_free(SWITCH_GLOBAL_dirs.script_dir); switch_safe_free(SWITCH_GLOBAL_dirs.htdocs_dir); switch_safe_free(SWITCH_GLOBAL_dirs.grammar_dir); + switch_safe_free(SWITCH_GLOBAL_dirs.storage_dir); switch_safe_free(SWITCH_GLOBAL_dirs.recordings_dir); switch_safe_free(SWITCH_GLOBAL_dirs.sounds_dir); + switch_safe_free(SWITCH_GLOBAL_dirs.run_dir); switch_safe_free(SWITCH_GLOBAL_dirs.temp_dir); switch_core_hash_destroy(&runtime.global_vars); switch_core_hash_destroy(&runtime.mime_types); + if (IP_LIST.hash) { + switch_core_hash_destroy(&IP_LIST.hash); + } + + if (IP_LIST.pool) { + switch_core_destroy_memory_pool(&IP_LIST.pool); + } + if (runtime.memory_pool) { apr_pool_destroy(runtime.memory_pool); apr_terminate(); diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 863b928092..69f2492a93 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -555,6 +555,7 @@ static const char *message_names[] = { "PROXY_MEDIA", "APPLICATION_EXEC", "APPLICATION_EXEC_COMPLETE", + "PHONE_EVENT", "INVALID" }; diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 0d6ac3d15e..9e02a91c8e 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -311,7 +311,7 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h if ((odbc_dbh = switch_odbc_handle_new(connection_options->odbc_options.dsn, connection_options->odbc_options.user, connection_options->odbc_options.pass))) { - if (switch_odbc_handle_connect(odbc_dbh) != SWITCH_STATUS_SUCCESS) { + if (switch_odbc_handle_connect(odbc_dbh) != SWITCH_ODBC_SUCCESS) { switch_odbc_handle_destroy(&odbc_dbh); } } @@ -386,7 +386,7 @@ static switch_status_t switch_cache_db_execute_sql_real(switch_cache_db_handle_t case SCDB_TYPE_ODBC: { switch_odbc_statement_handle_t stmt = NULL; - if ((status = switch_odbc_handle_exec(dbh->native_handle.odbc_dbh, sql, &stmt, NULL)) != SWITCH_ODBC_SUCCESS) { + if ((status = switch_odbc_handle_exec(dbh->native_handle.odbc_dbh, sql, &stmt, NULL)) != SWITCH_STATUS_SUCCESS) { errmsg = switch_odbc_handle_get_error(dbh->native_handle.odbc_dbh, stmt); } switch_odbc_statement_handle_free(&stmt); @@ -809,6 +809,7 @@ static void *SWITCH_THREAD_FUNC switch_core_sql_thread(switch_thread_t *thread, int lc = 0; uint32_t loops = 0, sec = 0; uint32_t l1 = 1000; + uint32_t sanity = 120; switch_assert(sqlbuf); @@ -816,10 +817,19 @@ static void *SWITCH_THREAD_FUNC switch_core_sql_thread(switch_thread_t *thread, l1 = 10; } - if (!sql_manager.event_db) { - switch_core_db_handle(&sql_manager.event_db); + while (!sql_manager.event_db) { + if (switch_core_db_handle(&sql_manager.event_db) == SWITCH_STATUS_SUCCESS && sql_manager.event_db) break; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Error getting core db, Retrying\n"); + switch_yield(500000); + sanity--; } + if (!sql_manager.event_db) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error getting core db Disabling core sql functionality\n"); + return NULL; + } + + sql_manager.thread_running = 1; while (sql_manager.thread_running == 1) { diff --git a/src/switch_dso.c b/src/switch_dso.c index 6fc5c7b86c..152c280d5d 100644 --- a/src/switch_dso.c +++ b/src/switch_dso.c @@ -127,7 +127,16 @@ void *switch_dso_data_sym(switch_dso_lib_t lib, const char *sym, char **err) { void *addr = dlsym(lib, sym); if (!addr) { - *err = strdup(dlerror()); + char *err_str = NULL; + dlerror(); + + if (!(addr = dlsym(lib, sym))) { + err_str = dlerror(); + } + + if (err_str) { + *err = strdup(err_str); + } } return addr; } diff --git a/src/switch_event.c b/src/switch_event.c index b65c7b1371..00a08fba1b 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -180,6 +180,7 @@ static char *EVENT_NAMES[] = { "SERVER_DISCONNECTED", "SEND_INFO", "RECV_INFO", + "RECV_RTCP_MESSAGE", "CALL_SECURE", "NAT", "RECORD_START", diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 2df902bcc4..27dd189600 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1366,6 +1366,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess int argc; char *argv[256]; + switch_event_del_header(var_event, SWITCH_EXPORT_VARS_VARIABLE); + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, SWITCH_EXPORT_VARS_VARIABLE, export_vars); + if ((argc = switch_separate_string(cptmp, ',', argv, (sizeof(argv) / sizeof(argv[0]))))) { int x; diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index 62ca411609..2e37585e52 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -788,7 +788,7 @@ static switch_status_t switch_loadable_module_load_file(char *path, char *filena switch_loadable_module_interface_t *module_interface = NULL; char *derr = NULL; const char *err = NULL; - switch_memory_pool_t *pool; + switch_memory_pool_t *pool = NULL; switch_bool_t load_global = global; switch_assert(path != NULL); @@ -1349,6 +1349,7 @@ SWITCH_DECLARE(void) switch_loadable_module_shutdown(void) switch_core_hash_destroy(&loadable_modules.management_hash); switch_core_hash_destroy(&loadable_modules.dialplan_hash); + switch_core_destroy_memory_pool(&loadable_modules.pool); } SWITCH_DECLARE(switch_endpoint_interface_t *) switch_loadable_module_get_endpoint_interface(const char *name) diff --git a/src/switch_rtp.c b/src/switch_rtp.c index fc929e8f74..d1126703e6 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -89,6 +89,11 @@ typedef struct { char body[SWITCH_RTP_MAX_BUF_LEN]; } rtp_msg_t; +typedef struct { + switch_rtcp_hdr_t header; + char body[SWITCH_RTCP_MAX_BUF_LEN]; +} rtcp_msg_t; + struct switch_rtp_vad_data { switch_core_session_t *session; switch_codec_t vad_codec; @@ -137,16 +142,17 @@ struct switch_rtp { * families are equal, sock_input == sock_output and only one socket is * used. */ - switch_socket_t *sock_input, *sock_output; - switch_pollfd_t *read_pollfd; + switch_socket_t *sock_input, *sock_output, *rtcp_sock_input, *rtcp_sock_output; + switch_pollfd_t *read_pollfd, *rtcp_read_pollfd; switch_pollfd_t *jb_pollfd; - switch_sockaddr_t *local_addr; + switch_sockaddr_t *local_addr, *rtcp_local_addr; rtp_msg_t send_msg; + rtcp_msg_t rtcp_send_msg; - switch_sockaddr_t *remote_addr; + switch_sockaddr_t *remote_addr, *rtcp_remote_addr; rtp_msg_t recv_msg; - + rtcp_msg_t rtcp_recv_msg; switch_sockaddr_t *remote_stun_addr; @@ -173,12 +179,13 @@ struct switch_rtp { switch_time_t last_write_timestamp; uint32_t flags; switch_memory_pool_t *pool; - switch_sockaddr_t *from_addr; + switch_sockaddr_t *from_addr, *rtcp_from_addr; char *rx_host; switch_port_t rx_port; char *ice_user; char *user_ice; char *timer_name; + char *local_host_str; char *remote_host_str; switch_time_t last_stun; uint32_t samples_per_interval; @@ -186,7 +193,9 @@ struct switch_rtp { uint32_t conf_samples_per_interval; uint32_t rsamples_per_interval; uint32_t ms_per_packet; + switch_port_t local_port; switch_port_t remote_port; + switch_port_t remote_rtcp_port; uint32_t stuncount; uint32_t funny_stun; uint32_t default_stuncount; @@ -216,6 +225,8 @@ struct switch_rtp { switch_rtp_stats_t stats; uint32_t hot_hits; uint32_t sync_packets; + int rtcp_interval; + switch_bool_t rtcp_fresh_frame; #ifdef ENABLE_ZRTP zrtp_session_t *zrtp_session; @@ -225,10 +236,16 @@ struct switch_rtp { int zinit; #endif -#ifdef RTP_DEBUG_WRITE_DELTA switch_time_t send_time; -#endif +}; +struct switch_rtcp_senderinfo { + unsigned ssrc:32; + unsigned ntp_msw:32; + unsigned ntp_lsw:32; + unsigned ts:32; + unsigned pc:32; + unsigned oc:32; }; static int global_init = 0; @@ -284,7 +301,7 @@ static switch_status_t do_stun_ping(switch_rtp_t *rtp_session) switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_stun_addr, 0, (void *) packet, &bytes); rtp_session->stuncount = rtp_session->default_stuncount; - end: + end: WRITE_DEC(rtp_session); return status; @@ -324,7 +341,7 @@ static switch_status_t ice_out(switch_rtp_t *rtp_session) switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_addr, 0, (void *) packet, &bytes); rtp_session->stuncount = rtp_session->default_stuncount; - end: + end: WRITE_DEC(rtp_session); return status; @@ -410,7 +427,7 @@ static void handle_ice(switch_rtp_t *rtp_session, void *data, switch_size_t len) switch_socket_sendto(rtp_session->sock_output, rtp_session->from_addr, 0, (void *) rpacket, &bytes); } - end: + end: READ_DEC(rtp_session); WRITE_DEC(rtp_session); @@ -750,6 +767,110 @@ SWITCH_DECLARE(void) switch_rtp_intentional_bugs(switch_rtp_t *rtp_session, swit rtp_session->rtp_bugs = bugs; } + +static switch_status_t enable_remote_rtcp_socket(switch_rtp_t *rtp_session, const char **err) { + + switch_status_t status = SWITCH_STATUS_SUCCESS; + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) { + + if (switch_sockaddr_info_get(&rtp_session->rtcp_remote_addr, rtp_session->remote_host_str, SWITCH_UNSPEC, + rtp_session->remote_rtcp_port, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS || !rtp_session->rtcp_remote_addr) { + *err = "RTCP Remote Address Error!"; + return SWITCH_STATUS_FALSE; + } else { + const char *host; + char bufa[30]; + host = switch_get_addr(bufa, sizeof(bufa), rtp_session->rtcp_remote_addr); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting RTCP remote addr to %s:%d\n", host, rtp_session->remote_rtcp_port); + } + + if (!(rtp_session->rtcp_sock_input && rtp_session->rtcp_sock_output)) { + if (rtp_session->rtcp_sock_input && switch_sockaddr_get_family(rtp_session->rtcp_remote_addr) == + switch_sockaddr_get_family(rtp_session->rtcp_local_addr)) { + rtp_session->rtcp_sock_output = rtp_session->rtcp_sock_input; + } else { + if (rtp_session->rtcp_sock_output && rtp_session->rtcp_sock_output != rtp_session->rtcp_sock_input) { + switch_socket_close(rtp_session->rtcp_sock_output); + } + if ((status = switch_socket_create(&rtp_session->rtcp_sock_output, + switch_sockaddr_get_family(rtp_session->rtcp_remote_addr), + SOCK_DGRAM, 0, rtp_session->pool)) != SWITCH_STATUS_SUCCESS) { + *err = "RTCP Socket Error!"; + } + } + } + } else { + *err = "RTCP NOT ACTIVE!"; + } + + return status; + +} + +static switch_status_t enable_local_rtcp_socket(switch_rtp_t *rtp_session, const char **err) { + + const char *host = rtp_session->local_host_str; + switch_port_t port = rtp_session->local_port; + switch_socket_t *rtcp_new_sock = NULL, *rtcp_old_sock = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + char bufa[30]; + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) { + if (switch_sockaddr_info_get(&rtp_session->rtcp_local_addr, host, SWITCH_UNSPEC, port+1, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS) { + *err = "RTCP Local Address Error!"; + goto done; + } + + if (switch_socket_create(&rtcp_new_sock, switch_sockaddr_get_family(rtp_session->rtcp_local_addr), SOCK_DGRAM, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS) { + *err = "RTCP Socket Error!"; + goto done; + } + + if (switch_socket_opt_set(rtcp_new_sock, SWITCH_SO_REUSEADDR, 1) != SWITCH_STATUS_SUCCESS) { + *err = "RTCP Socket Error!"; + goto done; + } + + if (switch_socket_bind(rtcp_new_sock, rtp_session->rtcp_local_addr) != SWITCH_STATUS_SUCCESS) { + *err = "RTCP Bind Error!"; + goto done; + } + + if (switch_sockaddr_info_get(&rtp_session->rtcp_from_addr, switch_get_addr(bufa, sizeof(bufa), rtp_session->from_addr), + SWITCH_UNSPEC, switch_sockaddr_get_port(rtp_session->from_addr) + 1, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS) { + *err = "RTCP From Address Error!"; + goto done; + } + + rtcp_old_sock = rtp_session->rtcp_sock_input; + rtp_session->rtcp_sock_input = rtcp_new_sock; + rtcp_new_sock = NULL; + + switch_socket_create_pollset(&rtp_session->rtcp_read_pollfd, rtp_session->rtcp_sock_input, SWITCH_POLLIN | SWITCH_POLLERR, rtp_session->pool); + + done: + + if (*err) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocating rtcp [%s]\n", *err); + status = SWITCH_STATUS_FALSE; + } + + if (rtcp_new_sock) { + switch_socket_close(rtcp_new_sock); + } + + if (rtcp_old_sock) { + switch_socket_close(rtcp_old_sock); + } + } else { + status = SWITCH_STATUS_FALSE; + } + + return status; +} + SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, const char **err) { switch_socket_t *new_sock = NULL, *old_sock = NULL; @@ -781,11 +902,17 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s goto done; } + + rtp_session->local_host_str = switch_core_strdup(rtp_session->pool, host); + rtp_session->local_port = port; + + if (switch_sockaddr_info_get(&rtp_session->local_addr, host, SWITCH_UNSPEC, port, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS) { *err = "Local Address Error!"; goto done; } + if (rtp_session->sock_input) { switch_rtp_kill_socket(rtp_session); } @@ -799,11 +926,12 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s *err = "Socket Error!"; goto done; } - + if (switch_socket_bind(new_sock, rtp_session->local_addr) != SWITCH_STATUS_SUCCESS) { *err = "Bind Error!"; goto done; } + #ifndef WIN32 len = sizeof(i); switch_socket_opt_set(new_sock, SWITCH_SO_NONBLOCK, TRUE); @@ -827,12 +955,15 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s } switch_socket_opt_set(new_sock, SWITCH_SO_NONBLOCK, FALSE); -#endif old_sock = rtp_session->sock_input; rtp_session->sock_input = new_sock; new_sock = NULL; + +#endif + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER) || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_NOBLOCK)) { switch_socket_opt_set(rtp_session->sock_input, SWITCH_SO_NONBLOCK, TRUE); switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_NOBLOCK); @@ -840,11 +971,18 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s switch_socket_create_pollset(&rtp_session->read_pollfd, rtp_session->sock_input, SWITCH_POLLIN | SWITCH_POLLERR, rtp_session->pool); - status = SWITCH_STATUS_SUCCESS; - *err = "Success"; + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) { + if ((status = enable_local_rtcp_socket(rtp_session, err)) == SWITCH_STATUS_SUCCESS) { + *err = "Success"; + } + } else { + status = SWITCH_STATUS_SUCCESS; + *err = "Success"; + } + switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_IO); - done: + done: if (new_sock) { switch_socket_close(new_sock); @@ -854,6 +992,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s switch_socket_close(old_sock); } + if (rtp_session->ready != 1) { WRITE_DEC(rtp_session); READ_DEC(rtp_session); @@ -889,7 +1028,7 @@ SWITCH_DECLARE(switch_port_t) switch_rtp_get_remote_port(switch_rtp_t *rtp_sessi } -SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, +SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, switch_port_t remote_rtcp_port, switch_bool_t change_adv_addr, const char **err) { switch_sockaddr_t *remote_addr; @@ -901,6 +1040,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_ return SWITCH_STATUS_FALSE; } + switch_mutex_lock(rtp_session->write_mutex); rtp_session->remote_addr = remote_addr; @@ -923,6 +1063,15 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_ } } + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) { + if (remote_rtcp_port) { + rtp_session->remote_rtcp_port = remote_rtcp_port; + } else { + rtp_session->remote_rtcp_port = rtp_session->remote_port + 1; + } + status = enable_remote_rtcp_socket(rtp_session, err); + } + switch_mutex_unlock(rtp_session->write_mutex); return status; @@ -985,8 +1134,11 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_sess policy->next = NULL; policy->key = (uint8_t *) crypto_key->key; - crypto_policy_set_rtcp_default(&policy->rtcp); - policy->rtcp.sec_serv = sec_serv_none; + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) { + crypto_policy_set_rtcp_default(&policy->rtcp); + policy->rtcp.sec_serv = sec_serv_none; + } policy->rtp.sec_serv = sec_serv_conf_and_auth; switch (direction) { @@ -1108,6 +1260,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session { switch_rtp_t *rtp_session = NULL; switch_core_session_t *session = switch_core_memory_pool_get_data(pool, "__session"); + switch_channel_t *channel = NULL; + + if (session) channel = switch_core_session_get_channel(session); *new_rtp_session = NULL; @@ -1136,8 +1291,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session /* for from address on recvfrom calls */ switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool); - - + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) { + switch_sockaddr_info_get(&rtp_session->rtcp_from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool); + } rtp_session->seq = (uint16_t) rand(); rtp_session->ssrc = (uint32_t) ((intptr_t) rtp_session + (uint32_t) switch_epoch_time_now(NULL)); @@ -1162,6 +1318,14 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session rtp_session->payload = payload; + + rtp_session->rtcp_send_msg.header.version = 2; + rtp_session->rtcp_send_msg.header.p = 0; + rtp_session->rtcp_send_msg.header.type = 200; + rtp_session->rtcp_send_msg.header.count = 0; + rtp_session->rtcp_send_msg.header.length = htons(6); + + switch_rtp_set_interval(rtp_session, ms_per_packet, samples_per_interval); rtp_session->conf_samples_per_interval = samples_per_interval; @@ -1192,12 +1356,13 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_NOBLOCK); } + switch_channel_set_private(channel, "__rtcp_audio_rtp_session", rtp_session); + #ifdef ENABLE_ZRTP if (zrtp_on) { switch_rtp_t *master_rtp_session = NULL; int initiator = 0; - switch_channel_t *channel = switch_core_session_get_channel(session); const char *zrtp_enabled = switch_channel_get_variable(channel, "zrtp_secure_media"); const char *srtp_enabled = switch_channel_get_variable(channel, "sip_secure_media"); @@ -1257,7 +1422,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session } } - end: + end: #endif @@ -1310,13 +1475,13 @@ SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host, goto end; } - if (switch_rtp_set_remote_address(rtp_session, tx_host, tx_port, SWITCH_TRUE, err) != SWITCH_STATUS_SUCCESS) { + if (switch_rtp_set_remote_address(rtp_session, tx_host, tx_port, 0, SWITCH_TRUE, err) != SWITCH_STATUS_SUCCESS) { switch_mutex_unlock(rtp_session->flag_mutex); rtp_session = NULL; goto end; } - end: + end: if (rtp_session) { switch_mutex_unlock(rtp_session->flag_mutex); @@ -1382,6 +1547,29 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t * return SWITCH_STATUS_SUCCESS; } +SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_session, int send_rate, switch_port_t remote_port) +{ + const char *err = NULL; + + switch_set_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP); + + if (!(rtp_session->remote_rtcp_port = remote_port)) { + rtp_session->remote_rtcp_port = rtp_session->remote_port + 1; + } + + if (send_rate == -1) { + switch_set_flag(rtp_session, SWITCH_RTP_FLAG_RTCP_PASSTHRU); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTCP passthru enabled. Remote Port: %d\n", rtp_session->remote_rtcp_port); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTCP send rate is: %d and packet rate is: %d Remote Port: %d\n", + send_rate, rtp_session->ms_per_packet, rtp_session->remote_rtcp_port); + rtp_session->rtcp_interval = send_rate/(rtp_session->ms_per_packet/1000); + } + + return enable_local_rtcp_socket(rtp_session, &err) || enable_remote_rtcp_socket(rtp_session, &err); + +} + SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_session, char *login, char *rlogin) { char ice_user[80]; @@ -1407,6 +1595,10 @@ static void ping_socket(switch_rtp_t *rtp_session) uint32_t o = UINT_MAX; switch_size_t len = sizeof(o); switch_socket_sendto(rtp_session->sock_input, rtp_session->local_addr, 0, (void *) &o, &len); + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP) && rtp_session->rtcp_sock_input) { + switch_socket_sendto(rtp_session->rtcp_sock_input, rtp_session->rtcp_local_addr, 0, (void *) &o, &len); + } } SWITCH_DECLARE(void) switch_rtp_break(switch_rtp_t *rtp_session) @@ -1443,6 +1635,16 @@ SWITCH_DECLARE(void) switch_rtp_kill_socket(switch_rtp_t *rtp_session) if (rtp_session->sock_output && rtp_session->sock_output != rtp_session->sock_input) { switch_socket_shutdown(rtp_session->sock_output, SWITCH_SHUTDOWN_READWRITE); } + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) { + if (rtp_session->rtcp_sock_input) { + ping_socket(rtp_session); + switch_socket_shutdown(rtp_session->rtcp_sock_input, SWITCH_SHUTDOWN_READWRITE); + } + if (rtp_session->rtcp_sock_output && rtp_session->rtcp_sock_output != rtp_session->rtcp_sock_input) { + switch_socket_shutdown(rtp_session->rtcp_sock_output, SWITCH_SHUTDOWN_READWRITE); + } + } } switch_mutex_unlock(rtp_session->flag_mutex); } @@ -1746,7 +1948,7 @@ static void do_flush(switch_rtp_t *rtp_session) } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CONSOLE, "%s FLUSH\n", switch_channel_get_name(switch_core_session_get_channel(session)) - ); + ); } } @@ -1841,18 +2043,126 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t return status; } +static switch_status_t read_rtcp_packet(switch_rtp_t *rtp_session, switch_size_t *bytes, switch_frame_flag_t *flags) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + + if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) { + return SWITCH_STATUS_FALSE; + } + + switch_assert(bytes); + + *bytes = sizeof(rtcp_msg_t); + if ((status = switch_socket_recvfrom(rtp_session->rtcp_from_addr, rtp_session->rtcp_sock_input, 0, (void *) &rtp_session->rtcp_recv_msg, bytes)) + != SWITCH_STATUS_SUCCESS) { + *bytes = 0; + } + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV)) { + int sbytes = (int) *bytes; + err_status_t stat = 0; + + stat = srtp_unprotect_rtcp(rtp_session->recv_ctx, &rtp_session->rtcp_recv_msg.header, &sbytes); + + if (stat) { + if (++rtp_session->srtp_errs >= MAX_SRTP_ERRS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Error: SRTP RTCP unprotect failed with code %d%s\n", stat, + stat == err_status_replay_fail ? " (replay check failed)" : stat == + err_status_auth_fail ? " (auth check failed)" : ""); + return SWITCH_STATUS_FALSE; + } else { + sbytes = 0; + } + } else { + rtp_session->srtp_errs = 0; + } + + *bytes = sbytes; + + } + + +#ifdef ENABLE_ZRTP + /* ZRTP Recv */ + if (bytes) { + unsigned int sbytes = (int) bytes; + zrtp_status_t stat = 0; + + stat = zrtp_process_srtcp(rtp_session->zrtp_stream, (void *) &rtp_session->rtcp_recv_msg, &sbytes); + + switch (stat) { + case zrtp_status_ok: + bytes = sbytes; + break; + case zrtp_status_drop: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat); + bytes = 0; + goto do_continue; + case zrtp_status_fail: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection fail with code %d\n", stat); + ret = -1; + goto end; + default: + break; + } + } +#endif + + + if (*bytes) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10,"Received an RTCP packet of length %" SWITCH_SIZE_T_FMT " bytes\n", *bytes); + if (rtp_session->rtcp_recv_msg.header.version == 2) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10,"RTCP packet type is %d\n", rtp_session->rtcp_recv_msg.header.type); + if (rtp_session->rtcp_recv_msg.header.type == 200) { + struct switch_rtcp_senderinfo* sr = (struct switch_rtcp_senderinfo*)rtp_session->rtcp_recv_msg.body; + + rtp_session->rtcp_fresh_frame = 1; + + /* sender report */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10,"Received a SR with %d report blocks, " \ + "length in words = %d, " \ + "SSRC = 0x%X, " \ + "NTP MSW = %u, " \ + "NTP LSW = %u, " \ + "RTP timestamp = %u, " \ + "Sender Packet Count = %u, " \ + "Sender Octet Count = %u\n", + rtp_session->rtcp_recv_msg.header.count, + ntohs(rtp_session->rtcp_recv_msg.header.length), + ntohl(sr->ssrc), + ntohl(sr->ntp_msw), + ntohl(sr->ntp_lsw), + ntohl(sr->ts), + ntohl(sr->pc), + ntohl(sr->oc)); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Received an unsupported RTCP packet version %d\nn", rtp_session->rtcp_recv_msg.header.version); + } + + status = SWITCH_STATUS_SUCCESS; + } + + return status; +} + static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_type, switch_frame_flag_t *flags, switch_io_flag_t io_flags) { switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session"); switch_channel_t *channel = NULL; switch_size_t bytes = 0; + switch_size_t rtcp_bytes = 0; switch_status_t status = SWITCH_STATUS_SUCCESS, poll_status = SWITCH_STATUS_SUCCESS; + switch_status_t rtcp_status = SWITCH_STATUS_SUCCESS, rtcp_poll_status = SWITCH_STATUS_SUCCESS; int check = 0; int ret = -1; int sleep_mss = 1000; int poll_sec = 5; int poll_loop = 0; int fdr = 0; + int rtcp_fdr = 0; int hot_socket = 0; if (session) { @@ -1904,7 +2214,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ } } - recvfrom: + recvfrom: bytes = 0; if (!switch_rtp_ready(rtp_session)) { @@ -1946,6 +2256,76 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ return_cng_frame(); } } + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP) && rtp_session->rtcp_read_pollfd) { + rtcp_poll_status = switch_poll(rtp_session->rtcp_read_pollfd, 1, &rtcp_fdr, 0); + + if (rtcp_poll_status == SWITCH_STATUS_SUCCESS) { + rtcp_status = read_rtcp_packet(rtp_session, &rtcp_bytes, flags); + + if (rtcp_status == SWITCH_STATUS_SUCCESS && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_RTCP_PASSTHRU)) { + switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session"); + switch_channel_t *channel = switch_core_session_get_channel(session); + + const char *uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE); + if (uuid) { + switch_core_session_t *other_session; + switch_rtp_t *other_rtp_session = NULL; + + if ((other_session = switch_core_session_locate(uuid))) { + switch_channel_t *other_channel = switch_core_session_get_channel(other_session); + if ((other_rtp_session = switch_channel_get_private(other_channel, "__rtcp_audio_rtp_session")) && + switch_test_flag(other_rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) { + *other_rtp_session->rtcp_send_msg.body = *rtp_session->rtcp_recv_msg.body; + + if (switch_test_flag(other_rtp_session, SWITCH_RTP_FLAG_SECURE_SEND)) { + int sbytes = (int) rtcp_bytes; + int stat = srtp_protect_rtcp(other_rtp_session->send_ctx, &other_rtp_session->rtcp_send_msg.header, &sbytes); + if (stat) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: SRTP RTCP protection failed with code %d\n", stat); + } + rtcp_bytes = sbytes; + } + +#ifdef ENABLE_ZRTP + /* ZRTP Send */ + if (1) { + unsigned int sbytes = (int) bytes; + zrtp_status_t stat = zrtp_status_fail; + + stat = zrtp_process_rtcp(other_rtp_session->zrtp_stream, (void *) &other_rtp_session->rtcp_send_msg, &sbytes); + + switch (stat) { + case zrtp_status_ok: + break; + case zrtp_status_drop: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat); + ret = (int) bytes; + goto end; + break; + case zrtp_status_fail: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection fail with code %d\n", stat); + break; + default: + break; + } + + bytes = sbytes; + } +#endif + if (switch_socket_sendto(other_rtp_session->rtcp_sock_output, other_rtp_session->rtcp_remote_addr, 0, + (const char*)&other_rtp_session->rtcp_send_msg, &rtcp_bytes ) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"RTCP packet not written\n"); + } + + + } + } + } + + } + } + } if (bytes < 0) { ret = (int) bytes; @@ -2059,7 +2439,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ switch_channel_set_variable(channel, "rtp_auto_adjust", "true"); } - switch_rtp_set_remote_address(rtp_session, tx_host, switch_sockaddr_get_port(rtp_session->from_addr), SWITCH_FALSE, &err); + switch_rtp_set_remote_address(rtp_session, tx_host, switch_sockaddr_get_port(rtp_session->from_addr), 0, SWITCH_FALSE, &err); switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_AUTOADJ); } } else { @@ -2210,7 +2590,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ We know the real rules here, but if we enforce them, it's an interop nightmare so, we put up with as much as we can so we don't have to deal with being punished for doing it right. Nice guys finish last! - */ + */ if (bytes && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833) && rtp_session->recv_msg.header.pt == rtp_session->recv_te) { switch_size_t len = bytes - rtp_header_len; @@ -2324,7 +2704,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ return_cng_frame(); } - timer_check: + timer_check: if (do_cng) { uint8_t *data = (uint8_t *) rtp_session->recv_msg.body; @@ -2371,7 +2751,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ break; - do_continue: + do_continue: if (!bytes && !rtp_session->timer.interval) { switch_yield(sleep_mss); @@ -2391,7 +2771,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ ret = -1; } - end: + end: READ_DEC(rtp_session); @@ -2513,6 +2893,33 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_read(switch_rtp_t *rtp_session, void return SWITCH_STATUS_SUCCESS; } +SWITCH_DECLARE(switch_status_t) switch_rtcp_zerocopy_read_frame(switch_rtp_t *rtp_session, switch_rtcp_frame_t *frame) +{ + + if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) { + return SWITCH_STATUS_FALSE; + } + + /* A fresh frame has been found! */ + if (rtp_session->rtcp_fresh_frame) { + struct switch_rtcp_senderinfo* sr = (struct switch_rtcp_senderinfo*)rtp_session->rtcp_recv_msg.body; + /* turn the flag off! */ + rtp_session->rtcp_fresh_frame = 0; + + frame->ssrc = ntohl(sr->ssrc); + frame->packet_type = rtp_session->rtcp_recv_msg.header.type; + frame->ntp_msw = ntohl(sr->ntp_msw); + frame->ntp_lsw = ntohl(sr->ntp_lsw); + frame->timestamp = ntohl(sr->ts); + frame->packet_count = ntohl(sr->pc); + frame->octect_count = ntohl(sr->oc); + + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_TIMEOUT; +} + SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp_session, switch_frame_t *frame, switch_io_flag_t io_flags) { int bytes = 0; @@ -2625,10 +3032,11 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_sessi static int rtp_common_write(switch_rtp_t *rtp_session, rtp_msg_t *send_msg, void *data, uint32_t datalen, switch_payload_t payload, uint32_t timestamp, switch_frame_flag_t *flags) { - switch_size_t bytes; + switch_size_t bytes, rtcp_bytes; uint8_t send = 1; uint32_t this_ts = 0; int ret; + switch_time_t now; if (!switch_rtp_ready(rtp_session)) { return SWITCH_STATUS_FALSE; @@ -2860,15 +3268,14 @@ static int rtp_common_write(switch_rtp_t *rtp_session, } #endif + now = switch_time_now(); #ifdef RTP_DEBUG_WRITE_DELTA { - switch_time_t now = switch_time_now(); int delta = (int) (now - rtp_session->send_time) / 1000; printf("WRITE %d delta %d\n", (int) bytes, delta); - rtp_session->send_time = now; } #endif - + rtp_session->send_time = now; if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_DEBUG_RTP_WRITE)) { switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session"); @@ -2924,6 +3331,61 @@ static int rtp_common_write(switch_rtp_t *rtp_session, } rtp_session->last_write_ts = this_ts; + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP) && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_RTCP_PASSTHRU) && + rtp_session->rtcp_interval && (rtp_session->stats.outbound.packet_count % rtp_session->rtcp_interval) == 0) { + struct switch_rtcp_senderinfo* sr = (struct switch_rtcp_senderinfo*)rtp_session->rtcp_send_msg.body; + + sr->ssrc = send_msg->header.ssrc; + sr->ntp_msw = htonl(rtp_session->send_time / 1000000 + 2208988800UL); + sr->ntp_lsw = htonl(rtp_session->send_time % 1000000 * ((UINT_MAX * 1.0)/ 1000000.0)); + sr->ts = send_msg->header.ts; + sr->pc = htonl(rtp_session->stats.outbound.packet_count); + sr->oc = htonl((rtp_session->stats.outbound.raw_bytes - rtp_session->stats.outbound.packet_count * sizeof(srtp_hdr_t))); + + rtcp_bytes = sizeof(switch_rtcp_hdr_t) + sizeof(struct switch_rtcp_senderinfo); + + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND)) { + int sbytes = (int) rtcp_bytes; + int stat = srtp_protect_rtcp(rtp_session->send_ctx, &rtp_session->rtcp_send_msg.header, &sbytes); + if (stat) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: SRTP RTCP protection failed with code %d\n", stat); + } + rtcp_bytes = sbytes; + } + +#ifdef ENABLE_ZRTP + /* ZRTP Send */ + if (1) { + unsigned int sbytes = (int) bytes; + zrtp_status_t stat = zrtp_status_fail; + + stat = zrtp_process_rtcp(rtp_session->zrtp_stream, (void *) &rtp_session->rtcp_send_msg, &sbytes); + + switch (stat) { + case zrtp_status_ok: + break; + case zrtp_status_drop: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat); + ret = (int) bytes; + goto end; + break; + case zrtp_status_fail: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection fail with code %d\n", stat); + break; + default: + break; + } + + bytes = sbytes; + } +#endif + + if (switch_socket_sendto(rtp_session->rtcp_sock_output, rtp_session->rtcp_remote_addr, 0, + (const char*)&rtp_session->rtcp_send_msg, &rtcp_bytes ) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"RTCP packet not written\n"); + } + } } if (rtp_session->remote_stun_addr) { @@ -2939,7 +3401,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session, ret = (int) bytes; - end: + end: WRITE_DEC(rtp_session); @@ -3031,9 +3493,9 @@ SWITCH_DECLARE(int) switch_rtp_write_frame(switch_rtp_t *rtp_session, switch_fra send_msg = frame->packet; /* - if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO)) { - send_msg->header.pt = rtp_session->payload; - } + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO)) { + send_msg->header.pt = rtp_session->payload; + } */ if (switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_addr, 0, frame->packet, &bytes) != SWITCH_STATUS_SUCCESS) { @@ -3131,9 +3593,9 @@ SWITCH_DECLARE(int) switch_rtp_write_frame(switch_rtp_t *rtp_session, switch_fra } /* - if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO)) { - send_msg->header.pt = rtp_session->payload; - } + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO)) { + send_msg->header.pt = rtp_session->payload; + } */ return rtp_common_write(rtp_session, send_msg, data, len, payload, ts, &frame->flags); @@ -3234,7 +3696,7 @@ SWITCH_DECLARE(int) switch_rtp_write_manual(switch_rtp_t *rtp_session, ret = (int) bytes; - end: + end: WRITE_DEC(rtp_session); diff --git a/src/switch_time.c b/src/switch_time.c index cbdc2f8eb1..2d74e60594 100644 --- a/src/switch_time.c +++ b/src/switch_time.c @@ -1064,6 +1064,10 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(softtimer_shutdown) switch_core_destroy_memory_pool(&TIMEZONES_LIST.pool); } + if (NODE) { + switch_event_unbind(&NODE); + } + return SWITCH_STATUS_SUCCESS; }