diff --git a/bootstrap.sh b/bootstrap.sh index 97237d7a95..f3bed2d4e1 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -159,7 +159,7 @@ check_lt_ver() { check_libtoolize() { # check libtoolize availability if [ -n "${LIBTOOL}" ]; then - libtoolize=${LIBTOOLIZE:-`dirname "${libtool}"`/libtoolize} + libtoolize=${LIBTOOLIZE:-`dirname "${LIBTOOL}"`/libtoolize} else libtoolize=${LIBTOOLIZE:-`${LIBDIR}/apr/build/PrintPath glibtoolize libtoolize libtoolize22 libtoolize15 libtoolize14`} fi @@ -190,7 +190,7 @@ check_make() { make=`which make` if [ -x "$make" ]; then - make_version=`$make --version | grep GNU` + make_version=`$make --version || true | grep GNU` if [ $? -ne 0 ]; then make=`which gmake` if [ -x "$make" ]; then diff --git a/build/modules.conf.in b/build/modules.conf.in index 9c1a6d4ac0..a3ee343f05 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -40,6 +40,7 @@ applications/mod_httapi #applications/mod_redis #applications/mod_rss applications/mod_sms +#applications/mod_sms_flowroute #applications/mod_snapshot #applications/mod_snom #applications/mod_sonar diff --git a/conf/vanilla/autoload_configs/conference.conf.xml b/conf/vanilla/autoload_configs/conference.conf.xml index d289bb5712..2df467b6d7 100644 --- a/conf/vanilla/autoload_configs/conference.conf.xml +++ b/conf/vanilla/autoload_configs/conference.conf.xml @@ -238,7 +238,7 @@ - + diff --git a/conf/vanilla/autoload_configs/modules.conf.xml b/conf/vanilla/autoload_configs/modules.conf.xml index c850d7365f..2c465d1231 100644 --- a/conf/vanilla/autoload_configs/modules.conf.xml +++ b/conf/vanilla/autoload_configs/modules.conf.xml @@ -71,6 +71,7 @@ + @@ -100,6 +101,7 @@ + diff --git a/conf/vanilla/autoload_configs/sms_flowroute.conf.xml b/conf/vanilla/autoload_configs/sms_flowroute.conf.xml new file mode 100644 index 0000000000..43d1c3eb06 --- /dev/null +++ b/conf/vanilla/autoload_configs/sms_flowroute.conf.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/conf/vanilla/autoload_configs/verto.conf.xml b/conf/vanilla/autoload_configs/verto.conf.xml index 8b839dedf8..7714053083 100644 --- a/conf/vanilla/autoload_configs/verto.conf.xml +++ b/conf/vanilla/autoload_configs/verto.conf.xml @@ -2,6 +2,12 @@ + + + + + + diff --git a/conf/vanilla/chatplan/default.xml b/conf/vanilla/chatplan/default.xml index b67bb638fa..22d34da552 100644 --- a/conf/vanilla/chatplan/default.xml +++ b/conf/vanilla/chatplan/default.xml @@ -6,7 +6,7 @@ - + diff --git a/conf/vanilla/dialplan/default.xml b/conf/vanilla/dialplan/default.xml index 3ffe2871ca..d4ae8e711a 100644 --- a/conf/vanilla/dialplan/default.xml +++ b/conf/vanilla/dialplan/default.xml @@ -382,6 +382,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/configure.ac b/configure.ac index 500e68bc66..1f3f14c909 100644 --- a/configure.ac +++ b/configure.ac @@ -597,7 +597,7 @@ AC_SUBST(SYS_XMLRPC_CFLAGS) AC_SUBST(SYS_XMLRPC_LDFLAGS) AM_CONDITIONAL([SYSTEM_XMLRPCC],[test "${enable_xmlrpcc}" = "yes"]) -for luaversion in lua5.2 lua-5.2 lua5.1 lua-5.1 lua; do +for luaversion in lua5.2 lua-5.2 lua52 lua5.1 lua-5.1 lua; do PKG_CHECK_MODULES([LUA],[${luaversion}],[have_lua=yes],[have_lua=no]) if test ${have_lua} = yes; then break @@ -793,7 +793,7 @@ case "$host" in ;; *openbsd*) APR_ADDTO(CPPFLAGS, -I/usr/local/include) - APR_ADDTO(LDFLAGS, -L/usr/local/lib) + APR_ADDTO(LDFLAGS, -L/usr/local/lib -ltermcap) APR_ADDTO(SWITCH_AM_CFLAGS, -I/usr/local/include) ;; *netbsd*) @@ -1413,6 +1413,18 @@ PKG_CHECK_MODULES([AMQP], [librabbitmq >= 0.5.2],[ AM_CONDITIONAL([HAVE_AMQP],[true])],[ AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_AMQP],[false])]) +PKG_CHECK_MODULES([H2O], [libh2o-evloop >= 0.11.0],[ + AM_CONDITIONAL([HAVE_H2O],[true])],[ + AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_H2O],[false])]) + +PKG_CHECK_MODULES([BROTLIENC], [libbrotlienc >= 0.1.0],[ + AM_CONDITIONAL([HAVE_BROTLIENC],[true])],[ + AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_BROTLIENC],[false])]) + +PKG_CHECK_MODULES([BROTLIDEC], [libbrotlidec >= 0.1.0],[ + AM_CONDITIONAL([HAVE_BROTLIDEC],[true])],[ + AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_BROTLIDEC],[false])]) + PKG_CHECK_MODULES([TAP], [tap >= 0.1.0],[ AM_CONDITIONAL([HAVE_TAP],[true])],[ AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_TAP],[false])]) @@ -1693,6 +1705,22 @@ else AC_MSG_WARN([python support disabled, building mod_python will fail!]) fi +# +# SNMP checks for mod_snmp +# +AC_PATH_PROG([NET_SNMP_CONFIG], [net-snmp-config], [no]) +if test "$NET_SNMP_CONFIG" != "no"; then + AC_MSG_CHECKING([for Net-SNMP libraries via net-snmp-config]) + SNMP_LIBS="`$NET_SNMP_CONFIG --base-agent-libs`" +else + # net-snmp-config not in path, fallback to sensible defaults + SNMP_LIBS="-lnetsnmpmibs -lnetsnmpagent -lnetsnmp" +fi + +# fix linking error on Solaris patched Net-SNMP +AS_CASE([$host], [*-solaris2*], [AC_CHECK_LIB([dladm], [dladm_open], [SNMP_LIBS="$SNMP_LIBS -ldladm"])]) +AC_SUBST(SNMP_LIBS) + CHECK_ERLANG # we never use this, and hard setting it will make cross compile work better @@ -1746,6 +1774,7 @@ AC_CONFIG_FILES([Makefile src/mod/applications/mod_rss/Makefile src/mod/applications/mod_skel/Makefile src/mod/applications/mod_sms/Makefile + src/mod/applications/mod_sms_flowroute/Makefile src/mod/applications/mod_snapshot/Makefile src/mod/applications/mod_snom/Makefile src/mod/applications/mod_sonar/Makefile @@ -1962,22 +1991,6 @@ esac AC_OUTPUT -## -## Registering for ClueCon -## -if ! test -f noreg -o -f /noreg; then -echo "" -echo "" -echo $ECHO_N "Registering you for ClueCon http://www.cluecon.com $ECHO_C" 1>&6 -sleep 1 -echo $ECHO_N ".$ECHO_C" 1>&6 -sleep 1 -echo $ECHO_N ".$ECHO_C" 1>&6 -sleep 1 -AC_MSG_RESULT([ See you in August. ;-)]) -echo "" -fi - ## ## Configuration summary ## diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh index a8ccae6570..f9835c4546 100755 --- a/debian/bootstrap.sh +++ b/debian/bootstrap.sh @@ -32,6 +32,7 @@ supported_debian_distros="wheezy jessie stretch sid" supported_ubuntu_distros="trusty utopic" supported_distros="$supported_debian_distros $supported_ubuntu_distros" avoid_mods=( + applications/mod_sms_flowroute applications/mod_limit applications/mod_mongo applications/mod_mp4 @@ -634,10 +635,12 @@ Depends: \${misc:Depends}, freeswitch (= \${binary:Version}), freeswitch-mod-dingaling (= \${binary:Version}), freeswitch-mod-loopback (= \${binary:Version}), freeswitch-mod-portaudio (= \${binary:Version}), + freeswitch-mod-rtc (= \${binary:Version}), freeswitch-mod-rtmp (= \${binary:Version}), freeswitch-mod-skinny (= \${binary:Version}), freeswitch-mod-skypopen (= \${binary:Version}), freeswitch-mod-sofia (= \${binary:Version}), + freeswitch-mod-verto (= \${binary:Version}), freeswitch-mod-cdr-csv (= \${binary:Version}), freeswitch-mod-cdr-mongodb (= \${binary:Version}), freeswitch-mod-cdr-sqlite (= \${binary:Version}), @@ -704,6 +707,33 @@ Description: Cross-Platform Scalable Multi-Protocol Soft Switch This is a metapackage which depends on the packages needed to install most FreeSWITCH codecs. +Package: freeswitch-meta-codecs-dbg +Architecture: any +Depends: \${misc:Depends}, freeswitch (= \${binary:Version}), + freeswitch-mod-amr-dbg (= \${binary:Version}), + freeswitch-mod-amrwb-dbg (= \${binary:Version}), + freeswitch-mod-b64-dbg (= \${binary:Version}), + freeswitch-mod-bv-dbg (= \${binary:Version}), + freeswitch-mod-codec2-dbg (= \${binary:Version}), + freeswitch-mod-dahdi-codec-dbg (= \${binary:Version}), + freeswitch-mod-g723-1-dbg (= \${binary:Version}), + freeswitch-mod-g729-dbg (= \${binary:Version}), + freeswitch-mod-h26x-dbg (= \${binary:Version}), + freeswitch-mod-isac-dbg (= \${binary:Version}), + freeswitch-mod-mp4v-dbg (= \${binary:Version}), + freeswitch-mod-opus-dbg (= \${binary:Version}), + freeswitch-mod-silk-dbg (= \${binary:Version}), + freeswitch-mod-spandsp-dbg (= \${binary:Version}), + freeswitch-mod-theora-dbg (= \${binary:Version}), +Suggests: + freeswitch-mod-ilbc-dbg (= \${binary:Version}), + freeswitch-mod-siren-dbg (= \${binary:Version}) +Description: Cross-Platform Scalable Multi-Protocol Soft Switch + $(debian_wrap "${fs_description}") + . + This is a metapackage which depends on the packages needed to install + most FreeSWITCH codecs. + Package: freeswitch-meta-conf Architecture: all Depends: \${misc:Depends}, @@ -759,11 +789,141 @@ Description: Cross-Platform Scalable Multi-Protocol Soft Switch This is a metapackage which depends on all mod_say languages for FreeSWITCH. +Package: freeswitch-meta-mod-say-dbg +Architecture: any +Depends: \${misc:Depends}, + freeswitch-mod-say-de-dbg (= \${binary:Version}), + freeswitch-mod-say-en-dbg (= \${binary:Version}), + freeswitch-mod-say-es-dbg (= \${binary:Version}), + freeswitch-mod-say-fa-dbg (= \${binary:Version}), + freeswitch-mod-say-fr-dbg (= \${binary:Version}), + freeswitch-mod-say-he-dbg (= \${binary:Version}), + freeswitch-mod-say-hr-dbg (= \${binary:Version}), + freeswitch-mod-say-hu-dbg (= \${binary:Version}), + freeswitch-mod-say-it-dbg (= \${binary:Version}), + freeswitch-mod-say-ja-dbg (= \${binary:Version}), + freeswitch-mod-say-nl-dbg (= \${binary:Version}), + freeswitch-mod-say-pl-dbg (= \${binary:Version}), + freeswitch-mod-say-pt-dbg (= \${binary:Version}), + freeswitch-mod-say-ru-dbg (= \${binary:Version}), + freeswitch-mod-say-th-dbg (= \${binary:Version}), + freeswitch-mod-say-zh-dbg (= \${binary:Version}), +Description: Cross-Platform Scalable Multi-Protocol Soft Switch + $(debian_wrap "${fs_description}") + . + This is a metapackage which depends on all mod_say languages for + FreeSWITCH. + +Package: freeswitch-meta-all-dbg +Architecture: any +Depends: \${misc:Depends}, freeswitch (= \${binary:Version}), + freeswitch-meta-codecs-dbg (= \${binary:Version}), + freeswitch-meta-lang-dbg (= \${binary:Version}), + freeswitch-meta-mod-say (= \${binary:Version}), + freeswitch-mod-abstraction-dbg (= \${binary:Version}), + freeswitch-mod-avmd-dbg (= \${binary:Version}), + freeswitch-mod-av-dbg (= \${binary:Version}), + freeswitch-mod-blacklist-dbg (= \${binary:Version}), + freeswitch-mod-callcenter-dbg (= \${binary:Version}), + freeswitch-mod-cidlookup-dbg (= \${binary:Version}), + freeswitch-mod-commands-dbg (= \${binary:Version}), + freeswitch-mod-conference-dbg (= \${binary:Version}), + freeswitch-mod-curl-dbg (= \${binary:Version}), + freeswitch-mod-db-dbg (= \${binary:Version}), + freeswitch-mod-directory-dbg (= \${binary:Version}), + freeswitch-mod-distributor-dbg (= \${binary:Version}), + freeswitch-mod-dptools-dbg (= \${binary:Version}), + freeswitch-mod-easyroute-dbg (= \${binary:Version}), + freeswitch-mod-enum-dbg (= \${binary:Version}), + freeswitch-mod-esf-dbg (= \${binary:Version}), + freeswitch-mod-esl-dbg (= \${binary:Version}), + freeswitch-mod-expr-dbg (= \${binary:Version}), + freeswitch-mod-fifo-dbg (= \${binary:Version}), + freeswitch-mod-fsk-dbg (= \${binary:Version}), + freeswitch-mod-fsv-dbg (= \${binary:Version}), + freeswitch-mod-hash-dbg (= \${binary:Version}), + freeswitch-mod-httapi-dbg (= \${binary:Version}), + freeswitch-mod-http-cache-dbg (= \${binary:Version}), + freeswitch-mod-lcr-dbg (= \${binary:Version}), + freeswitch-mod-memcache-dbg (= \${binary:Version}), + freeswitch-mod-nibblebill-dbg (= \${binary:Version}), + freeswitch-mod-oreka-dbg (= \${binary:Version}), + freeswitch-mod-png-dbg (= \${binary:Version}), + freeswitch-mod-redis-dbg (= \${binary:Version}), + freeswitch-mod-rss-dbg (= \${binary:Version}), + freeswitch-mod-sms-dbg (= \${binary:Version}), + freeswitch-mod-snapshot-dbg (= \${binary:Version}), + freeswitch-mod-snom-dbg (= \${binary:Version}), + freeswitch-mod-sonar-dbg (= \${binary:Version}), + freeswitch-mod-soundtouch-dbg (= \${binary:Version}), + freeswitch-mod-spandsp-dbg (= \${binary:Version}), + freeswitch-mod-spy-dbg (= \${binary:Version}), + freeswitch-mod-stress-dbg (= \${binary:Version}), + freeswitch-mod-translate-dbg (= \${binary:Version}), + freeswitch-mod-valet-parking-dbg (= \${binary:Version}), + freeswitch-mod-voicemail-dbg (= \${binary:Version}), + freeswitch-mod-voicemail-ivr-dbg (= \${binary:Version}), + freeswitch-mod-flite-dbg (= \${binary:Version}), + freeswitch-mod-pocketsphinx-dbg (= \${binary:Version}), + freeswitch-mod-tts-commandline-dbg (= \${binary:Version}), + freeswitch-mod-unimrcp-dbg (= \${binary:Version}), + freeswitch-mod-dialplan-asterisk-dbg (= \${binary:Version}), + freeswitch-mod-dialplan-directory-dbg (= \${binary:Version}), + freeswitch-mod-dialplan-xml-dbg (= \${binary:Version}), + freeswitch-mod-ldap-dbg (= \${binary:Version}), + freeswitch-mod-dingaling-dbg (= \${binary:Version}), + freeswitch-mod-loopback-dbg (= \${binary:Version}), + freeswitch-mod-portaudio-dbg (= \${binary:Version}), + freeswitch-mod-rtc-dbg (= \${binary:Version}), + freeswitch-mod-rtmp-dbg (= \${binary:Version}), + freeswitch-mod-skinny-dbg (= \${binary:Version}), + freeswitch-mod-skypopen-dbg (= \${binary:Version}), + freeswitch-mod-sofia-dbg (= \${binary:Version}), + freeswitch-mod-verto-dbg (= \${binary:Version}), + freeswitch-mod-cdr-csv-dbg (= \${binary:Version}), + freeswitch-mod-cdr-mongodb-dbg (= \${binary:Version}), + freeswitch-mod-cdr-sqlite-dbg (= \${binary:Version}), + freeswitch-mod-erlang-event-dbg (= \${binary:Version}), + freeswitch-mod-event-multicast-dbg (= \${binary:Version}), + freeswitch-mod-event-socket-dbg (= \${binary:Version}), + freeswitch-mod-json-cdr-dbg (= \${binary:Version}), + freeswitch-mod-kazoo-dbg (= \${binary:Version}), + freeswitch-mod-snmp-dbg (= \${binary:Version}), + freeswitch-mod-local-stream-dbg (= \${binary:Version}), + freeswitch-mod-native-file-dbg (= \${binary:Version}), + freeswitch-mod-portaudio-stream-dbg (= \${binary:Version}), + freeswitch-mod-shell-stream-dbg (= \${binary:Version}), + freeswitch-mod-sndfile-dbg (= \${binary:Version}), + freeswitch-mod-tone-stream-dbg (= \${binary:Version}), + freeswitch-mod-java-dbg (= \${binary:Version}), + freeswitch-mod-lua-dbg (= \${binary:Version}), + freeswitch-mod-perl-dbg (= \${binary:Version}), + freeswitch-mod-python-dbg (= \${binary:Version}), + freeswitch-mod-yaml-dbg (= \${binary:Version}), + freeswitch-mod-console-dbg (= \${binary:Version}), + freeswitch-mod-logfile-dbg (= \${binary:Version}), + freeswitch-mod-syslog-dbg (= \${binary:Version}), + freeswitch-mod-posix-timer-dbg (= \${binary:Version}), + freeswitch-mod-timerfd-dbg (= \${binary:Version}), + freeswitch-mod-xml-cdr-dbg (= \${binary:Version}), + freeswitch-mod-xml-curl-dbg (= \${binary:Version}), + freeswitch-mod-xml-rpc-dbg (= \${binary:Version}), + freeswitch-mod-xml-scgi-dbg (= \${binary:Version}), +Recommends: +Suggests: + freeswitch-mod-vmd-dbg (= \${binary:Version}), + freeswitch-mod-vlc-dbg (= \${binary:Version}), +Description: Cross-Platform Scalable Multi-Protocol Soft Switch + $(debian_wrap "${fs_description}") + . + This is a metapackage which recommends or suggests all packaged + FreeSWITCH modules. + Package: freeswitch-all-dbg Section: debug Priority: extra Architecture: any -Depends: \${misc:Depends}, freeswitch-meta-all (= \${binary:Version}) +Depends: \${misc:Depends}, freeswitch-meta-all (= \${binary:Version}), freeswitch-meta-all-dbg (= \${binary:Version}) Description: debugging symbols for FreeSWITCH $(debian_wrap "${fs_description}") . @@ -840,7 +1000,7 @@ if [ ${use_sysvinit} = "true" ]; then cat <= 3.0-6), sysvinit +Depends: \${misc:Depends}, lsb-base (>= 3.0-6), sysvinit | sysvinit-utils Conflicts: freeswitch-init Provides: freeswitch-init Description: FreeSWITCH SysV init script diff --git a/freeswitch.spec b/freeswitch.spec index a6b38719bb..f23e23de52 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -1935,6 +1935,7 @@ fi %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/shout.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/skinny.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/smpp.conf.xml +%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/sms_flowroute.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/sofia.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/spandsp.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/switch.conf.xml diff --git a/html5/verto/js/src/jquery.FSRTC.js b/html5/verto/js/src/jquery.FSRTC.js index c0785576ff..225c1b16ec 100644 --- a/html5/verto/js/src/jquery.FSRTC.js +++ b/html5/verto/js/src/jquery.FSRTC.js @@ -1089,7 +1089,7 @@ return [w, h]; } - var resList = [[320, 180], [320, 240], [640, 360], [640, 480], [1280, 720], [1920, 1080]]; + var resList = [[160, 120], [320, 180], [320, 240], [640, 360], [640, 480], [1280, 720], [1920, 1080]]; var resI = 0; var ttl = 0; diff --git a/html5/verto/verto_communicator/src/index.html b/html5/verto/verto_communicator/src/index.html index e886875756..2f4e2af1f5 100644 --- a/html5/verto/verto_communicator/src/index.html +++ b/html5/verto/verto_communicator/src/index.html @@ -88,7 +88,7 @@ - + diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/MainController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/MainController.js index 6f61816c82..c1a528784a 100644 --- a/html5/verto/verto_communicator/src/vertoControllers/controllers/MainController.js +++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/MainController.js @@ -292,7 +292,10 @@ $scope.closeSettings = function() { var settingsEl = angular.element(document.querySelector('#settings')); - settingsEl.removeClass('toggled'); + if (settingsEl.hasClass('toggled')) { + settingsEl.removeClass('toggled'); + $rootScope.$emit('toggledSettings', settingsEl.hasClass('toggled')); + } }; $scope.goFullscreen = function() { diff --git a/html5/verto/verto_communicator/src/vertoService/services/vertoService.js b/html5/verto/verto_communicator/src/vertoService/services/vertoService.js index 824e5e9e91..12583b4571 100644 --- a/html5/verto/verto_communicator/src/vertoService/services/vertoService.js +++ b/html5/verto/verto_communicator/src/vertoService/services/vertoService.js @@ -3,6 +3,11 @@ /* Controllers */ var videoQuality = []; var videoQualitySource = [{ + id: 'qqvga', + label: 'QQVGA 160x120', + width: 160, + height: 120 +}, { id: 'qvga', label: 'QVGA 320x240', width: 320, @@ -35,6 +40,10 @@ var videoQualitySource = [{ }, ]; var videoResolution = { + qqvga: { + width: 160, + height: 120 + }, qvga: { width: 320, height: 240 @@ -910,7 +919,10 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora storage.data.useDedenc = false; storage.data.vidQual = 'hd'; - if (upBand < 512) { + if (upBand < 256) { + storage.data.vidQual = 'qqvga'; + } + else if (upBand < 512) { storage.data.vidQual = 'qvga'; } else if (upBand < 1024) { diff --git a/html5/verto/video_demo/index.html b/html5/verto/video_demo/index.html index 74992e5807..229275e9cf 100644 --- a/html5/verto/video_demo/index.html +++ b/html5/verto/video_demo/index.html @@ -394,6 +394,10 @@ if ($('#devices').is(':visible')) {
Video Quality: + + + + diff --git a/html5/verto/video_demo/verto.js b/html5/verto/video_demo/verto.js index 997d63a119..e0ee4aec19 100644 --- a/html5/verto/video_demo/verto.js +++ b/html5/verto/video_demo/verto.js @@ -21,7 +21,7 @@ var master = null; var canvas_id = null; var second_screen = null; var save_settings = true; - +var vertoHandle = null; var video_screen = "webcam" $( ".selector" ).pagecontainer({ "theme": "a" }); @@ -140,7 +140,12 @@ function real_size() { function check_vid_res() { - if ($("#vqual_qvga").is(':checked')) { + if ($("#vqual_qqvga").is(':checked')) { + vid_width = 160; + vid_height = 120; + local_vid_width = 80; + local_vid_height = 60; + } else if ($("#vqual_qvga").is(':checked')) { vid_width = 320; vid_height = 240; local_vid_width = 160; @@ -218,6 +223,10 @@ function do_speed_test(fn) $("#vqual_qvga").prop("checked", true); vid = "320x240"; } + if (outgoingBandwidth < 256) { + $("#vqual_qqvga").prop("checked", true); + vid = "160x120"; + } //} if (incomingBandwidth === "default") { @@ -1315,6 +1324,15 @@ function init() { + $("#vqual_qqvga").prop("checked", vqual === "qqvga").change(function(e) { + if ($("#vqual_qqvga").is(':checked')) { + vqual = "qqvga"; + $.cookie("verto_demo_vqual", vqual, { + expires: 365 + }); + } + }); + $("#vqual_qvga").prop("checked", vqual === "qvga").change(function(e) { if ($("#vqual_qvga").is(':checked')) { vqual = "qvga"; diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 2dea680987..8b36cdb8f3 100755 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -1021,7 +1021,6 @@ static void ftdm_r2_on_chan_log(openr2_chan_t *r2chan, const char *file, const c static int ftdm_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit) { ftdm_sigmsg_t sigev; - ftdm_r2_data_t *r2data; ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); ftdm_size_t collected_len = R2CALL(ftdmchan)->dnis_index; @@ -1039,7 +1038,6 @@ static int ftdm_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit) sigev.span_id = ftdmchan->span_id; sigev.channel = ftdmchan; sigev.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT; - r2data = ftdmchan->span->signal_data; if (ftdm_span_send_signal(ftdmchan->span, &sigev) == FTDM_BREAK) { ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Requested to stop getting DNIS. Current DNIS = %s\n", ftdmchan->caller_data.dnis.digits); return OR2_STOP_DNIS_REQUEST; diff --git a/libs/libvpx/.gitignore b/libs/libvpx/.gitignore index 9fed8d5b67..96e97c06af 100644 --- a/libs/libvpx/.gitignore +++ b/libs/libvpx/.gitignore @@ -4,6 +4,7 @@ Makefile config.mk libs-*.mk +libs.doxy vp8_rtcd.h vp9_rtcd.h vpx_config.asm diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index 7d1f2d2217..eb6dc88486 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Wed Apr 27 16:01:46 EDT 2016 +Tue Aug 16 13:39:03 CDT 2016 diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c index 4a79bf3b36..887e4e818a 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c +++ b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c @@ -1397,6 +1397,8 @@ void sdp_media_transport(sdp_media_t *m, char const *s) m->m_proto = sdp_proto_rtp, m->m_proto_name = "RTP/AVP"; else if (su_casematch(s, "RTP/SAVP")) m->m_proto = sdp_proto_srtp, m->m_proto_name = "RTP/SAVP"; + else if (su_casematch(s, "UDP/TLS/RTP/SAVP")) + m->m_proto = sdp_proto_srtp, m->m_proto_name = "RTP/SAVP"; else if (su_casematch(s, "RTP/SAVPF")) m->m_proto = sdp_proto_extended_srtp, m->m_proto_name = "RTP/SAVPF"; else if (su_casematch(s, "UDP/TLS/RTP/SAVPF")) diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c b/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c index 0e192acd0c..c80d45ce36 100644 --- a/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c +++ b/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c @@ -1061,9 +1061,11 @@ int soa_sdp_mode_set(sdp_session_t const *user, continue; } - send_mode = (sdp_mode_t)(um->m_mode & sdp_sendonly); - if (rm) - send_mode = (rm->m_mode & sdp_recvonly) ? sdp_sendonly : 0; + if (um->m_mode) { /* when its inactive, keep it inactive */ + send_mode = (sdp_mode_t)(um->m_mode & sdp_sendonly); + if (rm) + send_mode = (rm->m_mode & sdp_recvonly) ? sdp_sendonly : 0; + } else send_mode = um->m_mode; recv_mode = (sdp_mode_t)(um->m_mode & sdp_recvonly); diff --git a/libs/sofia-sip/libsofia-sip-ua/su/su_time.c b/libs/sofia-sip/libsofia-sip-ua/su/su_time.c index 2326bfaba8..2782dcec77 100644 --- a/libs/sofia-sip/libsofia-sip-ua/su/su_time.c +++ b/libs/sofia-sip/libsofia-sip-ua/su/su_time.c @@ -398,7 +398,7 @@ uint64_t su_nanocounter(void) static int init = 0; static clockid_t cpu = CLOCK_REALTIME; -# define CLOCK_GETTIMEOFDAY 0xdedbeefUL +# define CLOCK_GETTIMEOFDAY ((clockid_t)-1) if (init == 0) { init = 1; diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c index 3e7f933f8c..1c74570ee0 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c @@ -467,7 +467,7 @@ int tport_capt_msg_hepv2 (tport_t const *self, msg_t *msg, size_t n, struct hep_ip6hdr hep_ip6header = {{{{0}}}}; #endif int eth_frame_len = 16000; - size_t i, dst = 0; + size_t i, dst = 1; tport_master_t *mr; assert(self); assert(msg); @@ -501,25 +501,25 @@ int tport_capt_msg_hepv2 (tport_t const *self, msg_t *msg, size_t n, else hep_header.hp_p = IPPROTO_UDP; /* DEFAULT UDP */ /* Check destination */ - if(strncmp("sent", what, 4) == 0) dst = 1; + if(strncmp("sent", what, 4) == 0) dst = 0; /* copy destination and source IPs*/ if(su->su_family == AF_INET) { - memcpy(dst ? &hep_ipheader.hp_dst : &hep_ipheader.hp_src, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr)); - memcpy(dst ? &hep_ipheader.hp_src : &hep_ipheader.hp_dst, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr)); + memcpy(dst ? &hep_ipheader.hp_src : &hep_ipheader.hp_dst, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr)); + memcpy(dst ? &hep_ipheader.hp_dst : &hep_ipheader.hp_src, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr)); hep_header.hp_l += sizeof(struct hep_iphdr); } #if SU_HAVE_IN6 else { - memcpy(dst ? &hep_ip6header.hp6_dst : &hep_ip6header.hp6_src, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr)); - memcpy(dst ? &hep_ip6header.hp6_src : &hep_ip6header.hp6_dst, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr)); + memcpy(dst ? &hep_ip6header.hp6_src : &hep_ip6header.hp6_dst, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr)); + memcpy(dst ? &hep_ip6header.hp6_dst : &hep_ip6header.hp6_src, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr)); hep_header.hp_l += sizeof(struct hep_ip6hdr); } #endif - hep_header.hp_dport = dst ? su->su_port : su_self->su_port; - hep_header.hp_sport = dst ? su_self->su_port : su->su_port; + hep_header.hp_dport = dst ? su_self->su_port : su->su_port; + hep_header.hp_sport = dst ? su->su_port : su_self->su_port; if (hep_header.hp_v == 2){ hep_header.hp_l += sizeof(struct hep_timehdr); @@ -605,7 +605,7 @@ int tport_capt_msg_hepv3 (tport_t const *self, msg_t *msg, size_t n, #endif int eth_frame_len = 16000; - size_t i, dst = 0; + size_t i, dst = 1; tport_master_t *mr; assert(self); assert(msg); @@ -649,7 +649,7 @@ int tport_capt_msg_hepv3 (tport_t const *self, msg_t *msg, size_t n, hg->ip_proto.chunk.length = htons(sizeof(hg->ip_proto)); /* Check destination */ - if(strncmp("sent", what, 4) == 0) dst = 1; + if(strncmp("sent", what, 4) == 0) dst = 0; /* copy destination and source IPs*/ if(su->su_family == AF_INET) { @@ -657,13 +657,13 @@ int tport_capt_msg_hepv3 (tport_t const *self, msg_t *msg, size_t n, /* SRC IP */ src_ip4.chunk.vendor_id = htons(0x0000); src_ip4.chunk.type_id = htons(0x0003); - memcpy(dst ? &dst_ip4.data : &src_ip4.data, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr)); + memcpy(dst ? &src_ip4.data : &dst_ip4.data, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr)); src_ip4.chunk.length = htons(sizeof(src_ip4)); /* DST IP */ dst_ip4.chunk.vendor_id = htons(0x0000); dst_ip4.chunk.type_id = htons(0x0004); - memcpy(dst ? &src_ip4.data : &dst_ip4.data, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr)); + memcpy(dst ? &dst_ip4.data : &src_ip4.data, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr)); dst_ip4.chunk.length = htons(sizeof(dst_ip4)); iplen = sizeof(dst_ip4) + sizeof(src_ip4); @@ -674,13 +674,13 @@ int tport_capt_msg_hepv3 (tport_t const *self, msg_t *msg, size_t n, /* SRC IPv6 */ src_ip6.chunk.vendor_id = htons(0x0000); src_ip6.chunk.type_id = htons(0x0005); - memcpy(dst ? &dst_ip6.data : &src_ip6.data, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr)); + memcpy(dst ? &src_ip6.data : &dst_ip6.data, &su->su_sin.sin_addr.s_addr, sizeof(su->su_sin.sin_addr.s_addr)); src_ip6.chunk.length = htons(sizeof(src_ip6)); /* DST IPv6 */ dst_ip6.chunk.vendor_id = htons(0x0000); dst_ip6.chunk.type_id = htons(0x0006); - memcpy(dst ? &src_ip6.data : &dst_ip6.data, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr)); + memcpy(dst ? &dst_ip6.data : &src_ip6.data, &su_self->su_sin.sin_addr.s_addr, sizeof(su_self->su_sin.sin_addr.s_addr)); dst_ip6.chunk.length = htons(sizeof(dst_ip6)); iplen = sizeof(dst_ip6) + sizeof(src_ip6); diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c index 050b2f8364..6b525581f1 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c @@ -461,6 +461,7 @@ int tport_ws_init_secondary(tport_t *self, int socket, int accepted, tport_ws_t *wstp = (tport_ws_t *)self; self->tp_has_connection = 1; + self->tp_params->tpp_keepalive = 5000; /* override the default 30 minute timeout on tport connections */ self->tp_params->tpp_idle = UINT_MAX; @@ -493,10 +494,12 @@ int tport_ws_init_secondary(tport_t *self, int socket, int accepted, return *return_reason = "WS_INIT", -1; } + wstp->connected = time(NULL); + wstp->ws_initialized = 1; self->tp_pre_framed = 1; - + tport_set_secondary_timer(self); return 0; } @@ -592,6 +595,32 @@ int tport_ws_next_timer(tport_t *self, su_time_t *return_target, char const **return_why) { + tport_ws_t *wstp = (tport_ws_t *)self; + int ll = establish_logical_layer(&wstp->ws); + int punt = 0; + + if (ll == -1) { + punt = 1; + } else if (ll < 0) { + time_t now = time(NULL); + if (now - wstp->connected > 5) { + punt = 2; + } + } else { + self->tp_params->tpp_keepalive = 0; + } + + if (punt) { + tport_close(self); + + SU_DEBUG_7(("%s(%p): %s to " TPN_FORMAT "%s\n", + __func__, (void *)self, + (punt == 2 ? "Timeout establishing SSL" : "Error establishing SSL"), TPN_ARGS(self->tp_name), "")); + + return -1; + } + + return tport_next_recv_timeout(self, return_target, return_why) | tport_next_keepalive(self, return_target, return_why); diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_ws.h b/libs/sofia-sip/libsofia-sip-ua/tport/tport_ws.h index d48101e5cb..d43e02e2ca 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_ws.h +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_ws.h @@ -59,6 +59,7 @@ typedef struct tport_ws_s { char wstp_buffer[65536]; size_t wstp_buflen; SU_S8_T ws_initialized; + time_t connected; unsigned ws_secure:1; unsigned:0; } tport_ws_t; diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/ws.c b/libs/sofia-sip/libsofia-sip-ua/tport/ws.c index 7fe9f182bf..5e5bbd638d 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/ws.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/ws.c @@ -500,7 +500,7 @@ static int restore_socket(ws_socket_t sock) #endif -static int establish_logical_layer(wsh_t *wsh) +int establish_logical_layer(wsh_t *wsh) { if (!wsh->sanity) { diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/ws.h b/libs/sofia-sip/libsofia-sip-ua/tport/ws.h index 045ff32acc..83a6890cca 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/ws.h +++ b/libs/sofia-sip/libsofia-sip-ua/tport/ws.h @@ -119,7 +119,7 @@ typedef struct wsh_s { ssize_t ws_send_buf(wsh_t *wsh, ws_opcode_t oc); ssize_t ws_feed_buf(wsh_t *wsh, void *data, size_t bytes); - +int establish_logical_layer(wsh_t *wsh); ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes, int block); ssize_t ws_raw_write(wsh_t *wsh, void *data, size_t bytes); ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data); diff --git a/libs/srtp/crypto/cipher/aes_icm.c b/libs/srtp/crypto/cipher/aes_icm.c index ef7545f283..cda56a8ddc 100644 --- a/libs/srtp/crypto/cipher/aes_icm.c +++ b/libs/srtp/crypto/cipher/aes_icm.c @@ -284,12 +284,15 @@ aes_icm_set_octet(aes_icm_ctx_t *c, err_status_t aes_icm_set_iv(aes_icm_ctx_t *c, void *iv, int direction) { - v128_t *nonce = (v128_t *) iv; + v128_t nonce; + + /* set nonce (for alignment) */ + v128_copy_octet_string(&nonce, iv); debug_print(mod_aes_icm, - "setting iv: %s", v128_hex_string(nonce)); + "setting iv: %s", v128_hex_string(&nonce)); - v128_xor(&c->counter, &c->offset, nonce); + v128_xor(&c->counter, &c->offset, &nonce); debug_print(mod_aes_icm, "set_counter: %s", v128_hex_string(&c->counter)); diff --git a/libs/srtp/crypto/cipher/aes_icm_ossl.c b/libs/srtp/crypto/cipher/aes_icm_ossl.c index 12054a2cc9..1e1860d093 100644 --- a/libs/srtp/crypto/cipher/aes_icm_ossl.c +++ b/libs/srtp/crypto/cipher/aes_icm_ossl.c @@ -263,11 +263,14 @@ err_status_t aes_icm_openssl_context_init (aes_icm_ctx_t *c, const uint8_t *key) err_status_t aes_icm_openssl_set_iv (aes_icm_ctx_t *c, void *iv, int dir) { const EVP_CIPHER *evp; - v128_t *nonce = (v128_t*)iv; + v128_t nonce; - debug_print(mod_aes_icm, "setting iv: %s", v128_hex_string(nonce)); + /* set nonce (for alignment) */ + v128_copy_octet_string(&nonce, iv); - v128_xor(&c->counter, &c->offset, nonce); + debug_print(mod_aes_icm, "setting iv: %s", v128_hex_string(&nonce)); + + v128_xor(&c->counter, &c->offset, &nonce); debug_print(mod_aes_icm, "set_counter: %s", v128_hex_string(&c->counter)); diff --git a/scripts/perl/fax.cgi b/scripts/perl/fax.cgi new file mode 100644 index 0000000000..fecc26e684 --- /dev/null +++ b/scripts/perl/fax.cgi @@ -0,0 +1,142 @@ +#!/usr/bin/perl +# Simple Fax Test +# +# +# +use CGI qw(:standard); +use ESL; +use Data::Dumper; +use Data::UUID; +use XML::Simple; + +# Replace Your CID Here +my $cid_num = "1NXXNXXXXXX"; + +my $q = new CGI; +my $c = new ESL::ESLconnection("127.0.0.1", "8021", "ClueCon"); + +my $action = $q->param('action'); + +if($action eq 'log') { + my $uuid = $q->param('uuid'); + + if($uuid =~ m/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/) { + if(-e "/tmp/$uuid.log") { + print $q->header('text/plain'); + open(LOG, ") { print $_; } + close(LOG); + } else { + print $q->header(); + if(check_call($uuid)) { + my $pages = pages_sent($uuid); + print $q->start_html(-title=> 'FreeSWITCH Fax Results', + -head =>meta({-http_equiv => 'Refresh', + -content => "10;fax.cgi?uuid=$uuid&action=log"})), + font({-color=>'black', -face=>'Arial', -size=>'4'}), + "$pages pages(s) sent , Waiting on fax to complete. Please Wait! Page will reload again in 10 seconds.",br,br, + end_html; + } else { + print $q->start_html(-title=> 'FreeSWITCH Fax Failed'), + font({-color=>'black', -face=>'Arial', -size=>'4'}), + "Fax call appears to have failed.",br,br, + end_html; + } + } + } +} elsif ($action eq 'fax') { + print $q->header; + + my $file = '/var/www/fax.tif'; + my $fax = $q->param('fax'); + my $ecm = $q->param('ecm') || 'false'; + my $v17 = $q->param('v17') || 'false'; + my $t38 = $q->param('t38') || 'false'; + my $large = $q->param('large') || 'false'; + my $gateway = $q->param('gateway'); + my $refresh = 10; + my $ug = new Data::UUID; + my $buuid = $ug->create(); + my $uuid = $ug->to_string( $buuid ); + + $fax =~ s/\D+//g; + + if($fax =~ m/^(1[2-9]\d{2}[2-9]\d{6})$/) { + + if($large eq 'true') { + $file = '/var/www/fax_large.tif'; + $refresh = 60; + } + + my $e = $c->sendRecv("api bgapi originate {fax_ident='FreeSWITCH Test Fax',fax_header='FreeSWITCH Test Fax',api_hangup_hook='system /bin/grep $uuid /usr/local/freeswitch/log/freeswitch.log > /tmp/$uuid.log',origination_uuid=$uuid,fax_disable_v17=$v17,fax_use_ecm=$ecm,origination_caller_id_number=$cid_num,fax_verbose=true,fax_enable_t38=$t38,ignore_early_media=true,fax_enable_t38_request=$t38,t38_passthru=false,absolute_codec_string=PCMU}sofia/gateway/$gateway/$fax &txfax($file)"); + my $res = $e->getBody(); + print $q->start_html(-title=> 'FreeSWITCH Fax Results', + -head =>meta({ + -http_equiv => 'Refresh', + -content => "$refresh;fax.cgi?uuid=$uuid&action=log"})),br + font({-color=>'black', -face=>'Arial', -size=>'4'}), + "API Results: $res",br,br + "Send 10 Pages: $large",br, + "Enable T.38: $t38",br, + "Enable ECM: $ecm",br, + "Disable V17: $v17",br, + "Via Gateway: $gateway", br,br, + "Fax is queued to $fax immediately and will not retry on failure.",br,br + "Your log UUID is $uuid, wait here the page will reload showing you the results once complete",br,br, + end_html; + } else { + print "Invalid Number 1NXXNXXXXXX Only!"; + } +} else { + my @gateways = load_gateways(); + + print $q->header; + + print $q->start_html(-title=> 'FreeSWITCH Test Fax'), start_form, + img( {-src => "data:image/png;base64," . }),br,br,font({-color=>'black', -face=>'Arial', -size=>'4'}), + "Call will be coming from $cid_num",br,br, + "Customer Fax Number: ", textfield('fax'),br, + br,"Fax options:",br,hidden('action', 'fax'), + br,checkbox(-label => 'Send 10 Pages', -name => "large", -value => 'true', -selected => 0), br, + br,checkbox(-label => 'Enable T.38', -name => "t38", -value => 'true', -selected => 1), br, + br,checkbox(-label => 'Enable ECM', -name => "ecm", -value => 'true', -selected => 1), br, + br,checkbox(-label => 'Disable v.17', -name => "v17", -value => 'true', -selected => 0), br, + br,'Using Gateway:',popup_menu( -name=>'gateway', -values => \@gateways),br, + br,submit('SEND FAX'),end_form,end_html; +} + +sub check_call { + my $uuid = shift; + my $e = $c->api("uuid_getvar $uuid uuid"); + my $res = $e->getBody(); + if($res =~ m/No such channel/) { + return 0; + } + return 1; +} + +sub pages_sent { + my $uuid = shift; + my $e = $c->api("uuid_getvar $uuid fax_document_transferred_pages"); + my $res = $e->getBody(); + if ($res =~ /_undef_/) { return 0 }; + return $res; +} + +# Query FreeSWITCH for gateway list to populate the test rig. +sub load_gateways { + my $e = $c->api('sofia xmlstatus gateways'); + my $gwxml = $e->getBody(); + + my $ref = XMLin($gwxml); + my @gateways; + + foreach my $key (keys %{ $ref->{gateway} }) { + push @gateways, $key; + } + return @gateways; +} + + +__DATA__ +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 diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index 6f3b7244a0..096bc815fc 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -64,8 +64,6 @@ typedef enum { SCMF_CODEC_GREEDY, SCMF_CODEC_SCROOGE, SCMF_DISABLE_HOLD, - SCMF_RENEG_ON_HOLD, - SCMF_RENEG_ON_REINVITE, SCMF_LIBERAL_DTMF, SCMF_SUPPRESS_CNG, SCMF_DISABLE_RTP_AUTOADJ, @@ -75,6 +73,7 @@ typedef enum { SCMF_RTP_AUTOFLUSH_DURING_BRIDGE, SCMF_MULTI_ANSWER_AUDIO, SCMF_MULTI_ANSWER_VIDEO, + SCMF_RECV_SDP, SCMF_MAX } switch_core_media_flag_t; @@ -230,6 +229,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_choose_ports(switch_core_sessi SWITCH_DECLARE(void) switch_core_media_check_dtmf_type(switch_core_session_t *session); SWITCH_DECLARE(void) switch_core_media_absorb_sdp(switch_core_session_t *session); SWITCH_DECLARE(switch_status_t) switch_core_media_proxy_remote_addr(switch_core_session_t *session, const char *sdp_str); +SWITCH_DECLARE(void) switch_core_media_parse_media_flags(switch_core_session_t *session); SWITCH_DECLARE(void) switch_core_media_deactivate_rtp(switch_core_session_t *session); SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_session_t *session); SWITCH_DECLARE(switch_status_t) switch_core_media_ext_address_lookup(switch_core_session_t *session, char **ip, switch_port_t *port, const char *sourceip); diff --git a/src/include/switch_core_video.h b/src/include/switch_core_video.h index 068a138107..babe865f4e 100644 --- a/src/include/switch_core_video.h +++ b/src/include/switch_core_video.h @@ -352,10 +352,10 @@ SWITCH_DECLARE(void) switch_img_find_position(switch_img_position_t pos, int sw, * * \param[in] src The image descriptor * \param[in] dest The target memory address -* \param[in] size The size of target memory address used for bounds check +* \param[in] stride Bytes in a row for the destination. Pass 0 if the buffer has contiguous rows. Can be negative. A multiple of 16 is optimal. * \param[in] fmt The target format */ -SWITCH_DECLARE(switch_status_t) switch_img_to_raw(switch_image_t *src, void *dest, switch_size_t size, switch_img_fmt_t fmt); +SWITCH_DECLARE(switch_status_t) switch_img_to_raw(switch_image_t *src, void *dest, int stride, switch_img_fmt_t fmt); /*!\brief convert raw memory to switch_img_t * * if dest is NULL then a new img is created, user should destroy it later, diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index 7d6d6ac1db..06fa8c137a 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -414,6 +414,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_tone_detect_session(switch_core_sessi SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *session, switch_file_handle_t *fh, const char *file, switch_input_args_t *args); +SWITCH_DECLARE(switch_status_t) switch_ivr_detect_audio(switch_core_session_t *session, uint32_t thresh, uint32_t audio_hits, + uint32_t timeout_ms, const char *file); + +SWITCH_DECLARE(switch_status_t) switch_ivr_detect_silence(switch_core_session_t *session, uint32_t thresh, uint32_t silence_hits, + uint32_t timeout_ms, const char *file); + SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_silence(switch_core_session_t *session, uint32_t thresh, uint32_t silence_hits, uint32_t listen_hits, uint32_t timeout_ms, const char *file); diff --git a/src/include/switch_platform.h b/src/include/switch_platform.h index 962bf972b3..00909770ee 100644 --- a/src/include/switch_platform.h +++ b/src/include/switch_platform.h @@ -139,6 +139,9 @@ typedef int gid_t; #ifndef __BYTE_ORDER #ifdef SWITCH_BYTE_ORDER #define __BYTE_ORDER SWITCH_BYTE_ORDER +/* solaris */ +#elif defined(_BIG_ENDIAN) +#define __BYTE_ORDER __BIG_ENDIAN #else #define __BYTE_ORDER __LITTLE_ENDIAN #endif diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 8279e10a7f..4f5d0d1b74 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -766,6 +766,7 @@ typedef enum { SWITCH_RTP_FLAG_NACK, SWITCH_RTP_FLAG_TMMBR, SWITCH_RTP_FLAG_GEN_TS_DELTA, + SWITCH_RTP_FLAG_DETECT_SSRC, SWITCH_RTP_FLAG_INVALID } switch_rtp_flag_t; @@ -1509,6 +1510,7 @@ typedef enum { CF_3P_MEDIA_REQUESTED, CF_3P_NOMEDIA_REQUESTED, CF_3P_NOMEDIA_REQUESTED_BLEG, + CF_IMAGE_SDP, CF_VIDEO_SDP_RECVD, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ /* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */ @@ -1627,7 +1629,8 @@ typedef enum { SWITCH_CODEC_FLAG_AAL2 = (1 << 6), SWITCH_CODEC_FLAG_PASSTHROUGH = (1 << 7), SWITCH_CODEC_FLAG_READY = (1 << 8), - SWITCH_CODEC_FLAG_HAS_PLC = (1 << 15) + SWITCH_CODEC_FLAG_HAS_PLC = (1 << 15), + SWITCH_CODEC_FLAG_VIDEO_PATCHING = (1 << 16) } switch_codec_flag_enum_t; typedef uint32_t switch_codec_flag_t; @@ -1769,7 +1772,8 @@ typedef enum { SMBF_WRITE_VIDEO_STREAM = (1 << 20), SMBF_VIDEO_PATCH = (1 << 21), SMBF_SPY_VIDEO_STREAM = (1 << 22), - SMBF_SPY_VIDEO_STREAM_BLEG = (1 << 23) + SMBF_SPY_VIDEO_STREAM_BLEG = (1 << 23), + SMBF_READ_VIDEO_PATCH = (1 << 24) } switch_media_bug_flag_enum_t; typedef uint32_t switch_media_bug_flag_t; diff --git a/src/mod/applications/mod_av/avcodec.c b/src/mod/applications/mod_av/avcodec.c index 5373400e8c..e76b4030ba 100644 --- a/src/mod/applications/mod_av/avcodec.c +++ b/src/mod/applications/mod_av/avcodec.c @@ -693,7 +693,10 @@ static switch_status_t consume_h263_bitstream(h264_codec_context_t *context, swi #endif } - if (!context->nalus[context->nalu_current_index].len) frame->m = 1; + if (!context->nalus[context->nalu_current_index].len) { + av_packet_unref(&context->encoder_avpacket); + frame->m = 1; + } #if 0 { diff --git a/src/mod/applications/mod_av/avformat.c b/src/mod/applications/mod_av/avformat.c index 7d0ca45815..7546ad6391 100644 --- a/src/mod/applications/mod_av/avformat.c +++ b/src/mod/applications/mod_av/avformat.c @@ -1239,6 +1239,7 @@ SWITCH_STANDARD_API(av_format_api_function) struct av_file_context { switch_memory_pool_t *pool; switch_mutex_t *mutex; + switch_thread_cond_t *cond; switch_buffer_t *buf; switch_buffer_t *audio_buffer; switch_timer_t video_timer; @@ -1261,6 +1262,7 @@ struct av_file_context { record_helper_t eh; switch_thread_t *file_read_thread; int file_read_thread_running; + int file_read_thread_started; switch_time_t video_start_time; switch_image_t *last_img; int read_fps; @@ -1417,7 +1419,11 @@ static void *SWITCH_THREAD_FUNC file_read_thread_run(switch_thread_t *thread, vo int sync = 0; int eof = 0; + switch_mutex_lock(context->mutex); + context->file_read_thread_started = 1; context->file_read_thread_running = 1; + switch_thread_cond_signal(context->cond); + switch_mutex_unlock(context->mutex); while (context->file_read_thread_running && !context->closed) { int vid_frames = 0; @@ -1684,6 +1690,7 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa } switch_mutex_init(&context->mutex, SWITCH_MUTEX_NESTED, handle->memory_pool); + switch_thread_cond_create(&context->cond, handle->memory_pool); switch_buffer_create_dynamic(&context->audio_buffer, 512, 512, 0); if (!context->audio_buffer) { @@ -2064,6 +2071,12 @@ static switch_status_t av_file_read(switch_file_handle_t *handle, void *data, si return SWITCH_STATUS_SUCCESS; } + switch_mutex_lock(context->mutex); + while (!context->file_read_thread_started) { + switch_thread_cond_wait(context->cond, context->mutex); + } + switch_mutex_unlock(context->mutex); + if (!context->file_read_thread_running && switch_buffer_inuse(context->audio_buffer) == 0) { *len = 0; return SWITCH_STATUS_FALSE; diff --git a/src/mod/applications/mod_avmd/avmd_amplitude.c b/src/mod/applications/mod_avmd/avmd_amplitude.c index a54caef4fa..16f1312d04 100644 --- a/src/mod/applications/mod_avmd/avmd_amplitude.c +++ b/src/mod/applications/mod_avmd/avmd_amplitude.c @@ -5,15 +5,8 @@ #include "avmd_amplitude.h" #include "avmd_psi.h" -/*! \brief - * @author Eric des Courtis - * @param b A circular audio sample buffer - * @param i Position in the buffer - * @param f Frequency estimate - * @return The amplitude at position i - */ -extern double avmd_amplitude(circ_buffer_t *b, size_t i, double f) -{ + +double avmd_amplitude(circ_buffer_t *b, size_t i, double f) { double result; result = sqrt(PSI(b, i) / sin(f * f)); return result; diff --git a/src/mod/applications/mod_avmd/avmd_amplitude.h b/src/mod/applications/mod_avmd/avmd_amplitude.h index b059dfffba..0878390935 100644 --- a/src/mod/applications/mod_avmd/avmd_amplitude.h +++ b/src/mod/applications/mod_avmd/avmd_amplitude.h @@ -1,7 +1,10 @@ /* * @brief Estimation of amplitude using DESA-2 algorithm. - * @author Eric des Courtis - * @par Modifications: Piotr Gregor < piotrek.gregor gmail.com > + * + * Contributor(s): + * + * Eric des Courtis + * Piotr Gregor : */ @@ -12,7 +15,12 @@ #include "avmd_buffer.h" -extern double avmd_amplitude(circ_buffer_t *, size_t i, double f); +#ifdef WIN32 +#define __attribute__(x) +#endif + + +double avmd_amplitude(circ_buffer_t *, size_t i, double f) __attribute__ ((nonnull(1))); #endif /* __AVMD_AMPLITUDE_H__ */ diff --git a/src/mod/applications/mod_avmd/avmd_desa2.c b/src/mod/applications/mod_avmd/avmd_desa2.c index b1d19eb8ae..2f35d3beb5 100644 --- a/src/mod/applications/mod_avmd/avmd_desa2.c +++ b/src/mod/applications/mod_avmd/avmd_desa2.c @@ -19,8 +19,8 @@ int __isnan(double); #include "avmd_fast_acosf.h" #endif -extern double avmd_desa2(circ_buffer_t *b, size_t i) -{ + +double avmd_desa2(circ_buffer_t *b, size_t i, double *amplitude) { double d; double n; double x0; @@ -30,6 +30,7 @@ extern double avmd_desa2(circ_buffer_t *b, size_t i) double x4; double x2sq; double result; + double PSI_Xn, PSI_Yn, NEEDED; x0 = GET_SAMPLE((b), (i)); x1 = GET_SAMPLE((b), ((i) + 1)); @@ -39,8 +40,14 @@ extern double avmd_desa2(circ_buffer_t *b, size_t i) x2sq = x2 * x2; d = 2.0 * ((x2sq) - (x1 * x3)); - if (d == 0.0) return 0.0; - n = ((x2sq) - (x0 * x4)) - ((x1 * x1) - (x0 * x2)) - ((x3 * x3) - (x2 * x4)); + if (d == 0.0) { + *amplitude = 0.0; + return 0.0; + } + PSI_Xn = ((x2sq) - (x0 * x4)); + NEEDED = ((x1 * x1) - (x0 * x2)) + ((x3 * x3) - (x2 * x4)); + n = ((x2sq) - (x0 * x4)) - NEEDED; + PSI_Yn = NEEDED + PSI_Xn; #ifdef AVMD_FAST_MATH result = 0.5 * (double)fast_acosf((float)n/d); @@ -48,7 +55,10 @@ extern double avmd_desa2(circ_buffer_t *b, size_t i) result = 0.5 * acos(n/d); #endif - if (ISNAN(result)) result = 0.0; + if (ISNAN(result)) { + result = 0.0; + } + *amplitude = 2.0 * PSI_Xn / sqrt(PSI_Yn); return result; diff --git a/src/mod/applications/mod_avmd/avmd_desa2.h b/src/mod/applications/mod_avmd/avmd_desa2.h index f6488e2ad8..d555df448e 100644 --- a/src/mod/applications/mod_avmd/avmd_desa2.h +++ b/src/mod/applications/mod_avmd/avmd_desa2.h @@ -1,7 +1,10 @@ /* * @brief DESA-2 algorithm implementation. - * @author Eric des Courtis - * @par Modifications: Piotr Gregor < piotrek.gregor gmail.com > + * + * Contributor(s): + * + * Eric des Courtis + * Piotr Gregor : */ @@ -12,8 +15,14 @@ #include #include "avmd_buffer.h" -/* Returns digital frequency estimation. */ -extern double avmd_desa2(circ_buffer_t *b, size_t i); + +#ifdef WIN32 +#define __attribute__(x) +#endif + + +/* Returns digital frequency estimation and amplitude estimation. */ +extern double avmd_desa2(circ_buffer_t *b, size_t i, double *amplitude) __attribute__ ((nonnull(1,3))); #endif /* __AVMD_DESA2_H__ */ diff --git a/src/mod/applications/mod_avmd/avmd_desa2_tweaked.c b/src/mod/applications/mod_avmd/avmd_desa2_tweaked.c index 8eae1753f3..f1ad5243d6 100644 --- a/src/mod/applications/mod_avmd/avmd_desa2_tweaked.c +++ b/src/mod/applications/mod_avmd/avmd_desa2_tweaked.c @@ -19,11 +19,10 @@ int __isnan(double); #include "avmd_fast_acosf.h" #endif + double -avmd_desa2_tweaked(circ_buffer_t *b, size_t i) -{ - double d; - double n; +avmd_desa2_tweaked(circ_buffer_t *b, size_t i, double *amplitude) { + double n, d; double x0; double x1; double x2; @@ -31,6 +30,7 @@ avmd_desa2_tweaked(circ_buffer_t *b, size_t i) double x4; double x2sq; double result; + double PSI_Xn, PSI_Yn, NEEDED; x0 = GET_SAMPLE((b), (i)); x1 = GET_SAMPLE((b), ((i) + 1)); @@ -39,8 +39,10 @@ avmd_desa2_tweaked(circ_buffer_t *b, size_t i) x4 = GET_SAMPLE((b), ((i) + 4)); x2sq = x2 * x2; d = 2.0 * ((x2sq) - (x1 * x3)); - n = ((x2sq) - (x0 * x4)) - ((x1 * x1) - - (x0 * x2)) - ((x3 * x3) - (x2 * x4)); + PSI_Xn = ((x2sq) - (x0 * x4)); + NEEDED = ((x1 * x1) - (x0 * x2)) + ((x3 * x3) - (x2 * x4)); + n = ((x2sq) - (x0 * x4)) - NEEDED; + PSI_Yn = NEEDED + PSI_Xn; /* instead of #ifdef FASTMATH @@ -52,11 +54,14 @@ avmd_desa2_tweaked(circ_buffer_t *b, size_t i) result = n/d; if (ISINF(result)) { - if (n < 0.0) + *amplitude = 0.0; + if (n < 0.0) { return -10.0; - else + } else { return 10.0; + } } + *amplitude = 2.0 * PSI_Xn / sqrt(PSI_Yn); return result; } diff --git a/src/mod/applications/mod_avmd/avmd_desa2_tweaked.h b/src/mod/applications/mod_avmd/avmd_desa2_tweaked.h index 167e241c9d..2d16ca2972 100644 --- a/src/mod/applications/mod_avmd/avmd_desa2_tweaked.h +++ b/src/mod/applications/mod_avmd/avmd_desa2_tweaked.h @@ -21,6 +21,11 @@ #include +#ifdef WIN32 +#define __attribute__(x) +#endif + + /* Instead of returning digital frequency estimation using * result = 0.5 * acos(n/d), * which involves expensive computation of arc cosine on @@ -33,9 +38,10 @@ * to corresponding frequencies is nonlinear. * The actual frequency estimation can be retrieved later * from this partial result using - * 0.5 * acos(n/d) + * 0.5 * acos(returned_value) + * Amplitude estimation is returned by address. */ -double avmd_desa2_tweaked(circ_buffer_t *b, size_t i); +double avmd_desa2_tweaked(circ_buffer_t *b, size_t i, double *amplitude) __attribute__ ((nonnull(1,3))); #endif /* __AVMD_DESA2_TWEAKED_H__ */ diff --git a/src/mod/applications/mod_avmd/avmd_psi.h b/src/mod/applications/mod_avmd/avmd_psi.h index 1764897d65..db6d83a60e 100644 --- a/src/mod/applications/mod_avmd/avmd_psi.h +++ b/src/mod/applications/mod_avmd/avmd_psi.h @@ -4,6 +4,8 @@ #include "avmd_buffer.h" -#define PSI(b, i) (GET_SAMPLE((b), ((i) + 1))*GET_SAMPLE((b), ((i) + 1))-GET_SAMPLE((b), ((i) + 2))*GET_SAMPLE((b), ((i) + 0))) + +#define PSI(b, i) (GET_SAMPLE((b), ((i) + 1)) * GET_SAMPLE((b), ((i) + 1)) - GET_SAMPLE((b), ((i) + 2)) * GET_SAMPLE((b), ((i) + 0))) + #endif /* __AVMD_PSI_H__ */ diff --git a/src/mod/applications/mod_avmd/conf/autoload_configs/avmd.conf.xml b/src/mod/applications/mod_avmd/conf/autoload_configs/avmd.conf.xml index 039658cf8d..2366195621 100644 --- a/src/mod/applications/mod_avmd/conf/autoload_configs/avmd.conf.xml +++ b/src/mod/applications/mod_avmd/conf/autoload_configs/avmd.conf.xml @@ -8,12 +8,14 @@ - - + + without reset. This parameter helps to avoid false beeps, bigger this value is + smaller the probability of getting false detection --> - + of the frame and/or after reset has happened. This serves the purpose of skipping first few + estimations on each frame, as these estimations may be inaccurate. This parameter also helps + to give more robust detections when it's value is increased (up to scertain limit of about 60). --> + + + + + diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 5dfbfe87c8..36ef8b06b9 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -50,6 +50,7 @@ switch_endpoint_interface_t *sofia_endpoint_interface; #define STRLEN 15 +void mod_sofia_shutdown_cleanup(); static switch_status_t sofia_on_init(switch_core_session_t *session); static switch_status_t sofia_on_exchange_media(switch_core_session_t *session); @@ -1212,7 +1213,6 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi case SWITCH_MESSAGE_INDICATE_MEDIA_RENEG: { if (msg->string_arg) { - sofia_set_media_flag(tech_pvt->profile, SCMF_RENEG_ON_REINVITE); sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA); } @@ -1378,25 +1378,21 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi break; case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ: - if (!switch_channel_test_flag(channel, CF_AVPF)) { - //const char *ua = switch_channel_get_variable(tech_pvt->channel, "sip_user_agent"); - //if (ua && switch_stristr("polycom", ua)) { - - //const char *pl = "\n\n\n\n\n\n\n\n"; - const char *pl = "\n\n"; - switch_time_t now = switch_micro_time_now(); + if (!switch_channel_test_flag(channel, CF_AVPF) && switch_true(switch_core_get_variable("sofia_send_info_vid_refresh"))) { + const char *pl = "\n\n"; + switch_time_t now = switch_micro_time_now(); + + if (!tech_pvt->last_vid_info || (now - tech_pvt->last_vid_info) > 500000) { - if (!tech_pvt->last_vid_info || (now - tech_pvt->last_vid_info) > 500000) { - - tech_pvt->last_vid_info = now; - - if (!zstr(msg->string_arg)) { - pl = msg->string_arg; - } - - nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("application/media_control+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END()); + tech_pvt->last_vid_info = now; + + if (!zstr(msg->string_arg)) { + pl = msg->string_arg; } - //} + + nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("application/media_control+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END()); + } + } break; case SWITCH_MESSAGE_INDICATE_BROADCAST: @@ -5758,109 +5754,112 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) switch_management_interface_t *management_interface; switch_application_interface_t *app_interface; struct in_addr in; + switch_status_t status; - - if (switch_event_reserve_subclass(MY_EVENT_NOTIFY_REFER) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_NOTIFY_REFER); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_NOTIFY_WATCHED_HEADER) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_NOTIFY_WATCHED_HEADER); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_UNREGISTER) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_UNREGISTER); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_PROFILE_START) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_PROFILE_START); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_REINVITE) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REINVITE); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_REPLACED) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REPLACED); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_TRANSFEROR) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_TRANSFEROR); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_TRANSFEREE) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_TRANSFEREE); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_ERROR) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_ERROR); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_INTERCEPTED) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_INTERCEPTED); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_GATEWAY_STATE) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_GATEWAY_STATE); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_SIP_USER_STATE) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_SIP_USER_STATE); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_GATEWAY_DEL) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_GATEWAY_DEL); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_EXPIRE) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_EXPIRE); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_REGISTER_ATTEMPT) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REGISTER_ATTEMPT); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_REGISTER_FAILURE) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REGISTER_FAILURE); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_PRE_REGISTER) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_PRE_REGISTER); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_REGISTER) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REGISTER); - return SWITCH_STATUS_TERM; - } - - if (switch_event_reserve_subclass(MY_EVENT_GATEWAY_ADD) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_GATEWAY_ADD); - return SWITCH_STATUS_TERM; - } - memset(&mod_sofia_globals, 0, sizeof(mod_sofia_globals)); mod_sofia_globals.destroy_private.destroy_nh = 1; mod_sofia_globals.destroy_private.is_static = 1; mod_sofia_globals.keep_private.is_static = 1; mod_sofia_globals.pool = pool; switch_mutex_init(&mod_sofia_globals.mutex, SWITCH_MUTEX_NESTED, mod_sofia_globals.pool); + switch_core_hash_init(&mod_sofia_globals.profile_hash); + switch_core_hash_init(&mod_sofia_globals.gateway_hash); + switch_mutex_init(&mod_sofia_globals.hash_mutex, SWITCH_MUTEX_NESTED, mod_sofia_globals.pool); + + if (switch_event_reserve_subclass(MY_EVENT_NOTIFY_REFER) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_NOTIFY_REFER); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_NOTIFY_WATCHED_HEADER) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_NOTIFY_WATCHED_HEADER); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_UNREGISTER) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_UNREGISTER); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_PROFILE_START) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_PROFILE_START); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_REINVITE) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REINVITE); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_REPLACED) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REPLACED); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_TRANSFEROR) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_TRANSFEROR); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_TRANSFEREE) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_TRANSFEREE); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_ERROR) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_ERROR); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_INTERCEPTED) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_INTERCEPTED); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_GATEWAY_STATE) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_GATEWAY_STATE); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_SIP_USER_STATE) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_SIP_USER_STATE); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_GATEWAY_DEL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_GATEWAY_DEL); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_EXPIRE) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_EXPIRE); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_REGISTER_ATTEMPT) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REGISTER_ATTEMPT); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_REGISTER_FAILURE) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REGISTER_FAILURE); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_PRE_REGISTER) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_PRE_REGISTER); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_REGISTER) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REGISTER); + switch_goto_status(SWITCH_STATUS_TERM, err); + } + + if (switch_event_reserve_subclass(MY_EVENT_GATEWAY_ADD) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_GATEWAY_ADD); + switch_goto_status(SWITCH_STATUS_TERM, err); + } switch_find_local_ip(mod_sofia_globals.guess_ip, sizeof(mod_sofia_globals.guess_ip), &mod_sofia_globals.guess_mask, AF_INET); in.s_addr = mod_sofia_globals.guess_mask; @@ -5868,11 +5867,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) strcpy(mod_sofia_globals.hostname, switch_core_get_switchname()); - - switch_core_hash_init(&mod_sofia_globals.profile_hash); - switch_core_hash_init(&mod_sofia_globals.gateway_hash); - switch_mutex_init(&mod_sofia_globals.hash_mutex, SWITCH_MUTEX_NESTED, mod_sofia_globals.pool); - switch_mutex_lock(mod_sofia_globals.mutex); mod_sofia_globals.running = 1; switch_mutex_unlock(mod_sofia_globals.mutex); @@ -5896,83 +5890,95 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) /* start one message thread */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Starting initial message thread.\n"); - sofia_msg_thread_start(0); if (sofia_init() != SWITCH_STATUS_SUCCESS) { + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } if (config_sofia(SOFIA_CONFIG_LOAD, NULL) != SWITCH_STATUS_SUCCESS) { mod_sofia_globals.running = 0; + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } + sofia_msg_thread_start(0); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for profiles to start\n"); switch_yield(1500000); if (switch_event_bind(modname, SWITCH_EVENT_CUSTOM, MULTICAST_EVENT, event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); - return SWITCH_STATUS_TERM; + switch_goto_status(SWITCH_STATUS_TERM, err); } if (switch_event_bind(modname, SWITCH_EVENT_CONFERENCE_DATA, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } if (switch_event_bind(modname, SWITCH_EVENT_PRESENCE_IN, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } if (switch_event_bind(modname, SWITCH_EVENT_PRESENCE_OUT, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } if (switch_event_bind(modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } if (switch_event_bind(modname, SWITCH_EVENT_ROSTER, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } if (switch_event_bind(modname, SWITCH_EVENT_MESSAGE_WAITING, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } if (switch_event_bind(modname, SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } if (switch_event_bind(modname, SWITCH_EVENT_NOTIFY, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } if (switch_event_bind(modname, SWITCH_EVENT_PHONE_FEATURE, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } if (switch_event_bind(modname, SWITCH_EVENT_SEND_MESSAGE, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } if (switch_event_bind(modname, SWITCH_EVENT_SEND_INFO, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); + switch_goto_status(SWITCH_STATUS_GENERR, err); return SWITCH_STATUS_GENERR; } @@ -6035,10 +6041,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; + + err: + + mod_sofia_shutdown_cleanup(); + return status; } -SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown) -{ +void mod_sofia_shutdown_cleanup() { int sanity = 0; int i; switch_status_t st; @@ -6077,8 +6087,10 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown) switch_event_unbind_callback(general_queue_event_handler); switch_event_unbind_callback(event_handler); - switch_queue_push(mod_sofia_globals.presence_queue, NULL); - switch_queue_interrupt_all(mod_sofia_globals.presence_queue); + if (mod_sofia_globals.presence_queue) { + switch_queue_push(mod_sofia_globals.presence_queue, NULL); + switch_queue_interrupt_all(mod_sofia_globals.presence_queue); + } while (mod_sofia_globals.threads) { switch_cond_next(); @@ -6087,13 +6099,11 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown) } } - for (i = 0; mod_sofia_globals.msg_queue_thread[i]; i++) { switch_queue_push(mod_sofia_globals.msg_queue, NULL); switch_queue_interrupt_all(mod_sofia_globals.msg_queue); } - for (i = 0; mod_sofia_globals.msg_queue_thread[i]; i++) { switch_thread_join(&st, mod_sofia_globals.msg_queue_thread[i]); } @@ -6102,14 +6112,17 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown) switch_thread_join(&st, mod_sofia_globals.presence_thread); } - //switch_yield(1000000); su_deinit(); switch_mutex_lock(mod_sofia_globals.hash_mutex); switch_core_hash_destroy(&mod_sofia_globals.profile_hash); switch_core_hash_destroy(&mod_sofia_globals.gateway_hash); switch_mutex_unlock(mod_sofia_globals.hash_mutex); +} +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown) +{ + mod_sofia_shutdown_cleanup(); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 1ff30451da..6d97c55f81 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -293,6 +293,7 @@ typedef enum { PFLAG_CHANNEL_XML_FETCH_ON_NIGHTMARE_TRANSFER, PFLAG_FIRE_TRANFER_EVENTS, PFLAG_BLIND_AUTH_ENFORCE_RESULT, + PFLAG_PROXY_HOLD, /* No new flags below this line */ PFLAG_MAX @@ -763,6 +764,8 @@ struct sofia_profile { ka_type_t keepalive; int bind_attempts; int bind_attempt_interval; + char *proxy_notify_events; + char *proxy_info_content_types; }; @@ -1027,6 +1030,7 @@ void sofia_presence_set_chat_hash(private_object_t *tech_pvt, sip_t const *sip); switch_status_t sofia_on_hangup(switch_core_session_t *session); char *sofia_glue_get_url_from_contact(char *buf, uint8_t to_dup); char *sofia_glue_get_path_from_contact(char *buf); +char *sofia_glue_get_profile_url(sofia_profile_t *profile, char *remote_ip, const sofia_transport_t transport); void sofia_presence_set_hash_key(char *hash_key, int32_t len, sip_t const *sip); void sofia_glue_sql_close(sofia_profile_t *profile, time_t prune); int sofia_glue_init_sql(sofia_profile_t *profile); @@ -1064,6 +1068,8 @@ void sofia_reg_release_gateway__(const char *file, const char *func, int line, s #define sofia_use_soa(_t) sofia_test_flag(_t, TFLAG_ENABLE_SOA) +#define sofia_test_extra_headers(val) (((!strncasecmp(val, "X-", 2) && strncasecmp(val, "X-FS-", 5)) || !strncasecmp(val, "P-", 2) || !strncasecmp(val, "On", 2)) ? 1 : 0) + #define check_decode(_var, _session) do { \ assert(_session); \ if (!zstr(_var)) { \ @@ -1160,6 +1166,7 @@ switch_status_t sofia_glue_send_notify(sofia_profile_t *profile, const char *use char *sofia_glue_get_extra_headers(switch_channel_t *channel, const char *prefix); void sofia_glue_set_extra_headers(switch_core_session_t *session, sip_t const *sip, const char *prefix); char *sofia_glue_get_extra_headers_from_event(switch_event_t *event, const char *prefix); +char *sofia_glue_get_non_extra_unknown_headers(sip_t const *sip); void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *profile, sip_t const *sip, switch_bool_t send); void sofia_send_callee_id(switch_core_session_t *session, const char *name, const char *number); int sofia_sla_supported(sip_t const *sip); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 35062228dc..7f886a307d 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -679,6 +679,29 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, /* if no session, assume it could be an incoming notify from a gateway subscription */ if (session) { + if (!zstr(profile->proxy_notify_events) && (!strcasecmp(profile->proxy_notify_events, "all") || strstr(profile->proxy_notify_events, sip->sip_event->o_type))) { + switch_core_session_t *other_session; + if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { + private_object_t *other_tech_pvt = switch_core_session_get_private(other_session); + const char *full_to = NULL; + char *pl = NULL; + char *unknown = NULL; + + full_to = switch_str_nil(switch_channel_get_variable(switch_core_session_get_channel(other_session), "sip_full_to")); + if (sip->sip_payload && sip->sip_payload->pl_data) { + pl = switch_core_session_strdup(other_session, (char*)sip->sip_payload->pl_data); + } + unknown = sofia_glue_get_non_extra_unknown_headers(sip); + nua_notify(other_tech_pvt->nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active), + TAG_IF((full_to), SIPTAG_TO_STR(full_to)), SIPTAG_SUBSCRIPTION_STATE_STR("active"), + SIPTAG_EVENT_STR(sip->sip_event->o_type), TAG_IF(!zstr(unknown), SIPTAG_HEADER_STR(unknown)), + TAG_IF(!zstr(pl), SIPTAG_PAYLOAD_STR(pl)), TAG_END()); + switch_safe_free(unknown); + switch_core_session_rwunlock(other_session); + } + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + goto end; + } /* make sure we have a proper "talk" event */ if (strcasecmp(sip->sip_event->o_type, "talk")) { goto error; @@ -1567,20 +1590,25 @@ static void our_sofia_event_callback(nua_event_t event, if (channel && sip) { const char *r_sdp = NULL; - if (sofia_test_flag(tech_pvt, TFLAG_PASS_ACK) && sip->sip_payload && sip->sip_payload->pl_data) { - r_sdp = sip->sip_payload->pl_data; + if (sip->sip_payload && sip->sip_payload->pl_data) { + if (sofia_test_flag(tech_pvt, TFLAG_PASS_ACK)) { + r_sdp = sip->sip_payload->pl_data; - if (tech_pvt->mparams.last_sdp_str) { - tech_pvt->mparams.prev_sdp_str = tech_pvt->mparams.last_sdp_str; - } - tech_pvt->mparams.last_sdp_str = NULL; + if (tech_pvt->mparams.last_sdp_str) { + tech_pvt->mparams.prev_sdp_str = tech_pvt->mparams.last_sdp_str; + } + tech_pvt->mparams.last_sdp_str = NULL; - if (!zstr(tech_pvt->mparams.prev_sdp_str) && strcmp(tech_pvt->mparams.prev_sdp_str, sip->sip_payload->pl_data)) { + if (!zstr(tech_pvt->mparams.prev_sdp_str) && strcmp(tech_pvt->mparams.prev_sdp_str, sip->sip_payload->pl_data)) { + switch_channel_set_variable(channel, "sip_reinvite_sdp", sip->sip_payload->pl_data); + tech_pvt->mparams.last_sdp_str = switch_core_session_strdup(session, sip->sip_payload->pl_data); + } else { + tech_pvt->mparams.last_sdp_str = tech_pvt->mparams.prev_sdp_str; + } + } else { switch_channel_set_variable(channel, "sip_reinvite_sdp", sip->sip_payload->pl_data); tech_pvt->mparams.last_sdp_str = switch_core_session_strdup(session, sip->sip_payload->pl_data); - } else { - tech_pvt->mparams.last_sdp_str = tech_pvt->mparams.prev_sdp_str; } } @@ -4307,7 +4335,6 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) sofia_set_pflag(profile, PFLAG_ENABLE_CHAT); profile->auto_restart = 1; sofia_set_media_flag(profile, SCMF_AUTOFIX_TIMING); - sofia_set_media_flag(profile, SCMF_RENEG_ON_REINVITE); sofia_set_media_flag(profile, SCMF_RTP_AUTOFLUSH_DURING_BRIDGE); profile->contact_user = SOFIA_DEFAULT_CONTACT_USER; sofia_set_pflag(profile, PFLAG_PASS_CALLEE_ID); @@ -4364,17 +4391,15 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s [%s]\n", var, val); - if (!strcasecmp(var, "debug")) { + if (!strcasecmp(var, "debug") && val) { profile->debug = atoi(val); } else if (!strcasecmp(var, "parse-invite-tel-params")) { profile->parse_invite_tel_params = switch_true(val); - } else if (!strcasecmp(var, "keepalive-method")) { - if (!zstr(val)) { - if (!strcasecmp(val, "info")) { - profile->keepalive = KA_INFO; - } else { - profile->keepalive = KA_MESSAGE; - } + } else if (!strcasecmp(var, "keepalive-method") && !zstr(val)) { + if (!strcasecmp(val, "info")) { + profile->keepalive = KA_INFO; + } else { + profile->keepalive = KA_MESSAGE; } } else if (!strcasecmp(var, "bind-attempts") && val) { int ba = atoi(val) - 1; @@ -4455,17 +4480,17 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { profile->mndlb &= ~SM_NDLB_NEVER_PATCH_REINVITE; } - } else if (!strcasecmp(var, "registration-thread-frequency")) { + } else if (!strcasecmp(var, "registration-thread-frequency") && !zstr(val)) { profile->ireg_seconds = atoi(val); if (profile->ireg_seconds < 0) { profile->ireg_seconds = IREG_SECONDS; } - } else if (!strcasecmp(var, "ping-mean-interval")) { + } else if (!strcasecmp(var, "ping-mean-interval") && !zstr(val)) { profile->iping_seconds = atoi(val); if (profile->iping_seconds < 0) { profile->iping_seconds = IPING_SECONDS; } - } else if (!strcasecmp(var, "ping-thread-frequency")) { + } else if (!strcasecmp(var, "ping-thread-frequency") && !zstr(val)) { profile->iping_freq = atoi(val); if (profile->iping_freq < 0) { profile->iping_freq = IPING_FREQUENCY; @@ -4540,7 +4565,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_LIBERAL_DTMF); } - } else if (!strcasecmp(var, "rtp-digit-delay")) { + } else if (!strcasecmp(var, "rtp-digit-delay") && !zstr(val)) { int delay = atoi(val); if (delay < 0) { delay = 0; @@ -4548,11 +4573,10 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) profile->rtp_digit_delay = (uint32_t) delay; } else if (!strcasecmp(var, "watchdog-enabled")) { profile->watchdog_enabled = switch_true(val); - } else if (!strcasecmp(var, "watchdog-step-timeout")) { + } else if (!strcasecmp(var, "watchdog-step-timeout") && !zstr(val)) { profile->step_timeout = atoi(val); - } else if (!strcasecmp(var, "watchdog-event-timeout")) { + } else if (!strcasecmp(var, "watchdog-event-timeout") && !zstr(val)) { profile->event_timeout = atoi(val); - } else if (!strcasecmp(var, "in-dialog-chat")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_IN_DIALOG_CHAT); @@ -4589,18 +4613,6 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_IGNORE_183NOSDP); } - } else if (!strcasecmp(var, "renegotiate-codec-on-hold")) { - if (switch_true(val)) { - sofia_set_media_flag(profile, SCMF_RENEG_ON_HOLD); - } else { - sofia_clear_media_flag(profile, SCMF_RENEG_ON_HOLD); - } - } else if (!strcasecmp(var, "renegotiate-codec-on-reinvite")) { - if (switch_true(val)) { - sofia_set_media_flag(profile, SCMF_RENEG_ON_REINVITE); - } else { - sofia_clear_media_flag(profile, SCMF_RENEG_ON_REINVITE); - } } else if (!strcasecmp(var, "presence-probe-on-register")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER); @@ -4608,9 +4620,9 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) sofia_clear_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER); } } else if (!strcasecmp(var, "send-presence-on-register")) { - if (switch_true(val) || !strcasecmp(val, "all")) { + if (val && (switch_true(val) || !strcasecmp(val, "all"))) { sofia_set_pflag(profile, PFLAG_PRESENCE_ON_REGISTER); - } else if (!strcasecmp(val, "first-only")) { + } else if (val && !strcasecmp(val, "first-only")) { sofia_clear_pflag(profile, PFLAG_PRESENCE_ON_REGISTER); sofia_set_pflag(profile, PFLAG_PRESENCE_ON_FIRST_REGISTER); } else { @@ -4623,22 +4635,21 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_CID_IN_1XX); } - } else if (!strcasecmp(var, "disable-hold")) { if (switch_true(val)) { sofia_set_media_flag(profile, SCMF_DISABLE_HOLD); } else { sofia_clear_media_flag(profile, SCMF_DISABLE_HOLD); } - } else if (!strcasecmp(var, "auto-jitterbuffer-msec")) { + } else if (!strcasecmp(var, "auto-jitterbuffer-msec") && !zstr(val)) { int msec = atoi(val); if (msec > 19) { profile->jb_msec = switch_core_strdup(profile->pool, val); } } else if (!strcasecmp(var, "dtmf-type")) { - if (!strcasecmp(val, "rfc2833")) { + if (val && !strcasecmp(val, "rfc2833")) { profile->dtmf_type = DTMF_2833; - } else if (!strcasecmp(val, "info")) { + } else if (val && !strcasecmp(val, "info")) { profile->dtmf_type = DTMF_INFO; } else { profile->dtmf_type = DTMF_NONE; @@ -4711,12 +4722,12 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_clear_flag(profile, TFLAG_ZRTP_PASSTHRU); } - } else if (!strcasecmp(var, "force-subscription-expires")) { + } else if (!strcasecmp(var, "force-subscription-expires") && !zstr(val)) { int tmp = atoi(val); if (tmp > 0) { profile->force_subscription_expires = tmp; } - } else if (!strcasecmp(var, "force-publish-expires")) { + } else if (!strcasecmp(var, "force-publish-expires") && !zstr(val)) { int tmp = atoi(val); if (tmp > 0) { profile->force_publish_expires = tmp; @@ -4724,7 +4735,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else if (!strcasecmp(var, "send-message-query-on-register")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER); - } else if (!strcasecmp(val, "first-only")) { + } else if (val && !strcasecmp(val, "first-only")) { sofia_clear_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER); sofia_set_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER); } else { @@ -4779,20 +4790,20 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } } else if (!strcasecmp(var, "user-agent-filter")) { profile->user_agent_filter = switch_core_strdup(profile->pool, val); - } else if (!strcasecmp(var, "max-registrations-per-extension")) { + } else if (!strcasecmp(var, "max-registrations-per-extension") && !zstr(val)) { profile->max_registrations_perext = atoi(val); - } else if (!strcasecmp(var, "rfc2833-pt")) { + } else if (!strcasecmp(var, "rfc2833-pt") && !zstr(val)) { profile->te = (switch_payload_t) atoi(val); - } else if (!strcasecmp(var, "cng-pt") && !sofia_test_media_flag(profile, SCMF_SUPPRESS_CNG)) { + } else if (!strcasecmp(var, "cng-pt") && !sofia_test_media_flag(profile, SCMF_SUPPRESS_CNG) && !zstr(val)) { profile->cng_pt = (switch_payload_t) atoi(val); - } else if (!strcasecmp(var, "sip-port")) { + } else if (!strcasecmp(var, "sip-port") && !zstr(val)) { if (!strcasecmp(val, "auto")) { sofia_set_pflag(profile, PFLAG_AUTO_ASSIGN_PORT); } else { profile->sip_port = (switch_port_t) atoi(val); if (!profile->extsipport) profile->extsipport = profile->sip_port; } - } else if (!strcasecmp(var, "vad")) { + } else if (!strcasecmp(var, "vad") && !zstr(val)) { if (!strcasecmp(val, "in")) { profile->vflags |= VAD_IN; } else if (!strcasecmp(val, "out")) { @@ -4829,7 +4840,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid ext-rtp-ip\n"); } - } else if (!strcasecmp(var, "rtp-ip")) { + } else if (!strcasecmp(var, "rtp-ip") && val) { char *ip = mod_sofia_globals.guess_ip; char buf[64]; @@ -4864,7 +4875,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Max IPs configured for profile %s.\n", profile->name); } } - } else if (!strcasecmp(var, "sip-ip")) { + } else if (!strcasecmp(var, "sip-ip") && val) { char *ip = mod_sofia_globals.guess_ip; char buf[64]; @@ -4922,7 +4933,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid ext-sip-ip\n"); } } else if (!strcasecmp(var, "local-network-acl")) { - if (!strcasecmp(var, "none")) { + if (val && !strcasecmp(val, "none")) { profile->local_network = NULL; } else { profile->local_network = switch_core_strdup(profile->pool, val); @@ -4941,7 +4952,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) profile->timer_name = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "hold-music")) { profile->hold_music = switch_core_strdup(profile->pool, val); - } else if (!strcasecmp(var, "outbound-proxy")) { + } else if (!strcasecmp(var, "outbound-proxy") && val) { if (strncasecmp(val, "sip:", 4) && strncasecmp(val, "sips:", 5)) { profile->outbound_proxy = switch_core_sprintf(profile->pool, "sip:%s", val); } else { @@ -4951,22 +4962,22 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) 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")) { + } else if (!strcasecmp(var, "session-timeout") && !zstr(val)) { int v_session_timeout = atoi(val); if (v_session_timeout >= 0) { profile->session_timeout = v_session_timeout; } - } else if (!strcasecmp(var, "max-proceeding")) { + } else if (!strcasecmp(var, "max-proceeding") && !zstr(val)) { int v_max_proceeding = atoi(val); if (v_max_proceeding >= 0) { profile->max_proceeding = v_max_proceeding; } - } else if (!strcasecmp(var, "rtp-timeout-sec")) { + } else if (!strcasecmp(var, "rtp-timeout-sec") && !zstr(val)) { int v = atoi(val); if (v >= 0) { profile->rtp_timeout_sec = v; } - } else if (!strcasecmp(var, "rtp-hold-timeout-sec")) { + } else if (!strcasecmp(var, "rtp-hold-timeout-sec") && !zstr(val)) { int v = atoi(val); if (v >= 0) { profile->rtp_hold_timeout_sec = v; @@ -4983,7 +4994,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { profile->mflags |= MFLAG_REGISTER; } - } else if (!strcasecmp(var, "media-option")) { + } else if (!strcasecmp(var, "media-option") && !zstr(val)) { if (!strcasecmp(val, "resume-media-on-hold")) { profile->media_options |= MEDIA_OPT_MEDIA_ON_HOLD; } else if (!strcasecmp(val, "bypass-media-after-att-xfer")) { @@ -5001,10 +5012,10 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else if (!strcasecmp(var, "pnp-provision-url")) { profile->pnp_prov_url = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "manage-presence")) { - if (!strcasecmp(val, "passive")) { + if (val && !strcasecmp(val, "passive")) { profile->pres_type = PRES_TYPE_PASSIVE; - } else if (!strcasecmp(val, "pnp")) { + } else if (val && !strcasecmp(val, "pnp")) { profile->pres_type = PRES_TYPE_PNP; } else if (switch_true(val)) { profile->pres_type = PRES_TYPE_FULL; @@ -5012,9 +5023,9 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) profile->pres_type = 0; } } else if (!strcasecmp(var, "presence-hold-state")) { - if (!strcasecmp(val, "confirmed")) { + if (val && !strcasecmp(val, "confirmed")) { profile->pres_held_type = PRES_HELD_CONFIRMED; - } else if (!strcasecmp(val, "terminated")) { + } else if (val && !strcasecmp(val, "terminated")) { profile->pres_held_type = PRES_HELD_TERMINATED; } else { profile->pres_held_type = 0; @@ -5031,7 +5042,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) profile->pres_type = PRES_TYPE_FULL; sofia_set_pflag(profile, PFLAG_MULTIREG); - } else if (!strcasecmp(val, "sylantro")) { + } else if (val && !strcasecmp(val, "sylantro")) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Sylantro support has been removed.\n" "It was incomplete anyway, and we fully support the broadsoft SCA shared line spec."); @@ -5063,9 +5074,9 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL); } - } else if (!strcasecmp(var, "sip-user-ping-max")) { + } else if (!strcasecmp(var, "sip-user-ping-max") && !zstr(val)) { profile->sip_user_ping_max = atoi(val); - } else if (!strcasecmp(var, "sip-user-ping-min")) { + } else if (!strcasecmp(var, "sip-user-ping-min") && !zstr(val)) { profile->sip_user_ping_min = atoi(val); } else if (!strcasecmp(var, "require-secure-rtp")) { if (switch_true(val)) { @@ -5079,9 +5090,9 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) if (found) continue; if (!strcasecmp(var, "multiple-registrations")) { - if (!strcasecmp(val, "call-id")) { + if (val && !strcasecmp(val, "call-id")) { sofia_set_pflag(profile, PFLAG_MULTIREG); - } else if (!strcasecmp(val, "contact") || switch_true(val)) { + } else if (val && (!strcasecmp(val, "contact") || switch_true(val))) { sofia_set_pflag(profile, PFLAG_MULTIREG); sofia_set_pflag(profile, PFLAG_MULTIREG_CONTACT); } else if (!switch_true(val)) { @@ -5146,7 +5157,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else if (!strcasecmp(var, "contact-user")) { profile->contact_user = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "nat-options-ping")) { - if (!strcasecmp(val, "udp-only")) { + if (val && !strcasecmp(val, "udp-only")) { sofia_set_pflag(profile, PFLAG_UDP_NAT_OPTIONS_PING); } else if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_NAT_OPTIONS_PING); @@ -5161,9 +5172,9 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) sofia_clear_pflag(profile, PFLAG_ALL_REG_OPTIONS_PING); } } else if (!strcasecmp(var, "inbound-codec-negotiation")) { - if (!strcasecmp(val, "greedy")) { + if (val && !strcasecmp(val, "greedy")) { sofia_set_media_flag(profile, SCMF_CODEC_GREEDY); - } else if (!strcasecmp(val, "scrooge")) { + } else if (val && !strcasecmp(val, "scrooge")) { sofia_set_media_flag(profile, SCMF_CODEC_GREEDY); sofia_set_media_flag(profile, SCMF_CODEC_SCROOGE); } else { @@ -5206,9 +5217,9 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_EXTENDED_INFO_PARSING); } - } else if (!strcasecmp(var, "nonce-ttl")) { + } else if (!strcasecmp(var, "nonce-ttl") && !zstr(val)) { profile->nonce_ttl = atoi(val); - } else if (!strcasecmp(var, "max-auth-validity")) { + } else if (!strcasecmp(var, "max-auth-validity") && !zstr(val)) { profile->max_auth_validity = atoi(val); } else if (!strcasecmp(var, "accept-blind-reg")) { if (switch_true(val)) { @@ -5264,7 +5275,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_ENABLE_RFC5626); } - } else if (!strcasecmp(var, "minimum-session-expires")) { + } else if (!strcasecmp(var, "minimum-session-expires") && !zstr(val)) { profile->minimum_session_expires = atoi(val); /* per RFC 4028: minimum_session_expires must be > 90 */ if (profile->minimum_session_expires < 90) { @@ -5301,7 +5312,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) sofia_clear_pflag(profile, PFLAG_PARSE_ALL_INVITE_HEADERS); } } else if (!strcasecmp(var, "bitpacking")) { - if (!strcasecmp(val, "aal2")) { + if (val && !strcasecmp(val, "aal2")) { profile->codec_flags = SWITCH_CODEC_FLAG_AAL2; } else { profile->codec_flags = 0; @@ -5310,7 +5321,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) profile->sdp_username = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "context")) { profile->context = switch_core_strdup(profile->pool, val); - } else if (!strcasecmp(var, "apply-nat-acl")) { + } else if (!strcasecmp(var, "apply-nat-acl") && !zstr(val)) { if (!strcasecmp(val,"none")) { profile->nat_acl_count = 0; } else if (profile->nat_acl_count < SOFIA_MAX_ACL) { @@ -5322,7 +5333,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL); } - } else if (!strcasecmp(var, "apply-inbound-acl")) { + } else if (!strcasecmp(var, "apply-inbound-acl") && !zstr(val)) { if (!strcasecmp(val,"none")) { profile->acl_count = 0; } else if (profile->acl_count < SOFIA_MAX_ACL) { @@ -5348,7 +5359,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL); } - } else if (!strcasecmp(var, "apply-proxy-acl")) { + } else if (!strcasecmp(var, "apply-proxy-acl") && !zstr(val)) { if (!strcasecmp(val,"none")) { profile->proxy_acl_count = 0; } else if (profile->proxy_acl_count < SOFIA_MAX_ACL) { @@ -5356,7 +5367,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL); } - } else if (!strcasecmp(var, "apply-register-acl")) { + } else if (!strcasecmp(var, "apply-register-acl") && !zstr(val)) { if (!strcasecmp(val,"none")) { profile->reg_acl_count = 0; } else if (profile->reg_acl_count < SOFIA_MAX_ACL) { @@ -5365,7 +5376,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL); } - } else if (!strcasecmp(var, "apply-candidate-acl")) { + } else if (!strcasecmp(var, "apply-candidate-acl") && !zstr(val)) { if (!strcasecmp(val,"none")) { profile->cand_acl_count = 0; } else if (profile->cand_acl_count < SWITCH_MAX_CAND_ACL) { @@ -5387,7 +5398,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } } else if (!strcasecmp(var, "dialplan")) { profile->dialplan = switch_core_strdup(profile->pool, val); - } else if (!strcasecmp(var, "max-calls")) { + } else if (!strcasecmp(var, "max-calls") && !zstr(val)) { profile->max_calls = atoi(val); } else if (!strcasecmp(var, "codec-prefs")) { profile->inbound_codec_string = switch_core_strdup(profile->pool, val); @@ -5398,7 +5409,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) profile->outbound_codec_string = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "challenge-realm")) { profile->challenge_realm = switch_core_strdup(profile->pool, val); - } else if (!strcasecmp(var, "dtmf-duration")) { + } else if (!strcasecmp(var, "dtmf-duration") && !zstr(val)) { uint32_t dur = atoi(val); if (dur >= switch_core_min_dtmf_duration(0) && dur <= switch_core_max_dtmf_duration(0)) { profile->dtmf_duration = dur; @@ -5451,7 +5462,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) sofia_clear_pflag(profile, PFLAG_TLS); } } else if (!strcasecmp(var, "tls-bind-params")) { - if (switch_stristr("transport=tls", val)) { + if (val && switch_stristr("transport=tls", val)) { profile->tls_bind_params = switch_core_strdup(profile->pool, val); } else { profile->tls_bind_params = switch_core_sprintf(profile->pool, "%s;transport=tls", val); @@ -5460,11 +5471,11 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) profile->tls_only = switch_true(val); } else if (!strcasecmp(var, "tls-verify-date")) { profile->tls_verify_date = switch_true(val); - } else if (!strcasecmp(var, "tls-verify-depth")) { + } else if (!strcasecmp(var, "tls-verify-depth") && !zstr(val)) { profile->tls_verify_depth = atoi(val); } else if (!strcasecmp(var, "tls-verify-policy")) { profile->tls_verify_policy = sofia_glue_str2tls_verify_policy(val); - } else if (!strcasecmp(var, "tls-sip-port")) { + } else if (!strcasecmp(var, "tls-sip-port") && !zstr(val)) { if (!strcasecmp(val, "auto")) { sofia_set_pflag(profile, PFLAG_AUTO_ASSIGN_TLS_PORT); } else { @@ -5501,79 +5512,79 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) profile->tls_version |= SOFIA_TLS_VERSION_TLSv1_2; ps=pe+1; } - } else if (!strcasecmp(var, "tls-timeout")) { + } else if (!strcasecmp(var, "tls-timeout") && !zstr(val)) { int v = atoi(val); profile->tls_timeout = v > 0 ? (unsigned int)v : 300; - } else if (!strcasecmp(var, "timer-T1")) { + } else if (!strcasecmp(var, "timer-T1") && !zstr(val)) { int v = atoi(val); if (v > 0) { profile->timer_t1 = v; } else { profile->timer_t1 = 500; } - } else if (!strcasecmp(var, "timer-T1X64")) { + } else if (!strcasecmp(var, "timer-T1X64") && !zstr(val)) { int v = atoi(val); if (v > 0) { profile->timer_t1x64 = v; } else { profile->timer_t1x64 = 32000; } - } else if (!strcasecmp(var, "timer-T2")) { + } else if (!strcasecmp(var, "timer-T2") && !zstr(val)) { int v = atoi(val); if (v > 0) { profile->timer_t2 = v; } else { profile->timer_t2 = 4000; } - } else if (!strcasecmp(var, "timer-T4")) { + } else if (!strcasecmp(var, "timer-T4") && !zstr(val)) { int v = atoi(val); if (v > 0) { profile->timer_t4 = v; } else { profile->timer_t4 = 4000; } - } else if (!strcasecmp(var, "sip-options-respond-503-on-busy")) { - if (switch_true(val)) { - sofia_set_pflag(profile, PFLAG_OPTIONS_RESPOND_503_ON_BUSY); - } else { - sofia_clear_pflag(profile, PFLAG_OPTIONS_RESPOND_503_ON_BUSY); - } - } else if (!strcasecmp(var, "sip-expires-late-margin")) { + } else if (!strcasecmp(var, "sip-options-respond-503-on-busy")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_OPTIONS_RESPOND_503_ON_BUSY); + } else { + sofia_clear_pflag(profile, PFLAG_OPTIONS_RESPOND_503_ON_BUSY); + } + } else if (!strcasecmp(var, "sip-expires-late-margin") && !zstr(val)) { int32_t sip_expires_late_margin = atoi(val); if (sip_expires_late_margin >= 0) { profile->sip_expires_late_margin = sip_expires_late_margin; } else { profile->sip_expires_late_margin = 60; } - } else if (!strcasecmp(var, "sip-force-expires-min")) { + } else if (!strcasecmp(var, "sip-force-expires-min") && !zstr(val)) { int32_t sip_force_expires_min = atoi(val); if (sip_force_expires_min >= 0) { profile->sip_force_expires_min = sip_force_expires_min; } else { profile->sip_force_expires_min = 0; } - } else if (!strcasecmp(var, "sip-force-expires-max")) { + } else if (!strcasecmp(var, "sip-force-expires-max") && !zstr(val)) { int32_t sip_force_expires_max = atoi(val); if (sip_force_expires_max >= 0) { profile->sip_force_expires_max = sip_force_expires_max; } else { profile->sip_force_expires_max = 0; } - } else if (!strcasecmp(var, "sip-force-expires")) { + } else if (!strcasecmp(var, "sip-force-expires") && !zstr(val)) { int32_t sip_force_expires = atoi(val); if (sip_force_expires >= 0) { profile->sip_force_expires = sip_force_expires; } else { profile->sip_force_expires = 0; } - } else if (!strcasecmp(var, "sip-expires-max-deviation")) { + } else if (!strcasecmp(var, "sip-expires-max-deviation") && !zstr(val)) { int32_t sip_expires_max_deviation = atoi(val); if (sip_expires_max_deviation >= 0) { profile->sip_expires_max_deviation = sip_expires_max_deviation; } else { profile->sip_expires_max_deviation = 0; } - } else if (!strcasecmp(var, "sip-subscription-max-deviation")) { + } else if (!strcasecmp(var, "sip-subscription-max-deviation") && !zstr(val)) { int32_t sip_subscription_max_deviation = atoi(val); if (sip_subscription_max_deviation >= 0) { profile->sip_subscription_max_deviation = sip_subscription_max_deviation; @@ -5588,7 +5599,9 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) sofia_clear_pflag(profile, PFLAG_NO_CONNECTION_REUSE); } } else if (!strcasecmp(var, "p-asserted-id-parse")) { - if (!strncasecmp(val, "default", 7)) { + if (!val) { + profile->paid_type = PAID_DEFAULT; + } else if (!strncasecmp(val, "default", 7)) { profile->paid_type = PAID_DEFAULT; } else if (!strncasecmp(val, "user-only", 9)) { profile->paid_type = PAID_USER; @@ -5611,12 +5624,22 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_FIRE_TRANFER_EVENTS); } - } else if (!strcasecmp(var, "enforce-blind-auth-result")) { - if(switch_true(val)) { - sofia_set_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT); - } else { - sofia_clear_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT); - } + } else if (!strcasecmp(var, "enforce-blind-auth-result")) { + if(switch_true(val)) { + sofia_set_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT); + } else { + sofia_clear_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT); + } + } else if (!strcasecmp(var, "proxy-hold")) { + if(switch_true(val)) { + sofia_set_pflag(profile, PFLAG_PROXY_HOLD); + } else { + sofia_clear_pflag(profile, PFLAG_PROXY_HOLD); + } + } else if (!strcasecmp(var, "proxy-notify-events")) { + profile->proxy_notify_events = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "proxy-info-content-types")) { + profile->proxy_info_content_types = switch_core_strdup(profile->pool, val); } } @@ -6495,6 +6518,12 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status switch_core_media_proxy_remote_addr(session, NULL); } + if (status == 415) { + int new_status = 488; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Overriding %d %s with %d\n", status, phrase, new_status); + status = new_status; + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing %d %s to other leg\n%s\n", status, phrase, switch_str_nil(r_sdp)); if (switch_core_session_compare(session, other_session)) { @@ -6854,7 +6883,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (tech_pvt->mparams.last_sdp_response) { r_sdp = tech_pvt->mparams.last_sdp_response; } - } else if (ss_state == nua_callstate_received) { + } else if (ss_state == nua_callstate_received || ss_state == nua_callstate_ready) { if (tech_pvt->mparams.last_sdp_str) { r_sdp = tech_pvt->mparams.last_sdp_str; } @@ -7398,9 +7427,11 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } else { switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP"); switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0); - switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0); - sofia_set_flag_locked(tech_pvt, TFLAG_3PCC); + switch_core_media_prepare_codecs(session, 1); switch_channel_set_state(channel, CS_HIBERNATE); + switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 0); + sofia_set_flag_locked(tech_pvt, TFLAG_3PCC); + if (sofia_use_soa(tech_pvt)) { nua_respond(tech_pvt->nh, SIP_200_OK, SIPTAG_CONTACT_STR(tech_pvt->profile->url), @@ -7457,15 +7488,13 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0); - nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END()); - goto done; - - /* } else if (0 && r_sdp && !sofia_use_soa(tech_pvt)) { nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTACT_STR(tech_pvt->profile->url), SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END()); - */ + + goto done; + } else { ss_state = nua_callstate_completed; goto state_process; @@ -7659,6 +7688,64 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } goto done; } else { + if (sofia_test_pflag(profile, PFLAG_PROXY_HOLD)) { + switch_channel_set_flag(tech_pvt->channel, CF_REINVITE); + if (tech_pvt->mparams.num_codecs){ + match = sofia_media_negotiate_sdp(session, r_sdp, SDP_TYPE_REQUEST); + } + if (!match) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Reinvite Codec Error!\n"); + nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); + goto done; + } + if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { + switch_core_session_message_t *msg; + + msg = switch_core_session_alloc(other_session, sizeof(*msg)); + if (switch_stristr("sendonly", r_sdp) || switch_stristr("0.0.0.0", r_sdp)) { + const char *hold_msg = "hold"; + + msg->message_id = SWITCH_MESSAGE_INDICATE_HOLD; + if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { + const char *info = switch_channel_get_variable(channel, "presence_call_info"); + + if (info) { + if (switch_stristr("private", info)) { + hold_msg = "hold-private"; + } + } + } + sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + switch_channel_set_flag(channel, CF_LEG_HOLDING); + switch_channel_presence(tech_pvt->channel, "unknown", hold_msg, NULL); + } else { + msg->message_id = SWITCH_MESSAGE_INDICATE_UNHOLD; + sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + switch_channel_clear_flag(channel, CF_LEG_HOLDING); + switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL); + } + msg->from = __FILE__; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Indicating Hold to other leg.\n%s\n", r_sdp); + + switch_core_session_queue_message(other_session, msg); + switch_core_session_rwunlock(other_session); + } + switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0); + if (sofia_use_soa(tech_pvt)){ + nua_respond(tech_pvt->nh, SIP_200_OK, + SIPTAG_CONTACT_STR(tech_pvt->reply_contact), + SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str), + SOATAG_REUSE_REJECTED(1), + SOATAG_AUDIO_AUX("cn telephone-event"), + TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END()); + } else { + nua_respond(tech_pvt->nh, SIP_200_OK, + NUTAG_MEDIA_ENABLE(0), + SIPTAG_CONTACT_STR(tech_pvt->reply_contact), + SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END()); + } + goto done; + } if (switch_channel_test_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_NEGOTIATED)) { nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END()); goto done; @@ -8816,6 +8903,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_core_session_t *b_session; switch_channel_set_variable_printf(channel, "transfer_to", "blind:%s", br ? br : exten); + switch_channel_set_variable_printf(channel, "transfer_destination", "blind:%s", exten); if (!zstr(br) && (b_session = switch_core_session_locate(br))) { const char *var; @@ -9052,8 +9140,37 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t assert(switch_core_session_get_private(session)); sofia_glue_set_extra_headers(session, sip, SOFIA_SIP_INFO_HEADER_PREFIX); + if (!zstr(profile->proxy_info_content_types) && sip && sip->sip_content_type && sip->sip_content_type->c_type && sip->sip_content_type->c_subtype && + (!strcasecmp(profile->proxy_info_content_types,"all") || strstr(profile->proxy_info_content_types,sip->sip_content_type->c_type))) { + switch_core_session_t *other_session; + if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { + char *pl = NULL; + char *ct = NULL; + char *extra_headers = NULL; + char *unknown = NULL; + private_object_t *other_tech_pvt = switch_core_session_get_private(other_session); + ct = switch_core_session_strdup(other_session, (char*)sip->sip_content_type->c_type); + if (sip->sip_payload && sip->sip_payload->pl_data) { + pl = switch_core_session_strdup(other_session,(char*)sip->sip_payload->pl_data); + } + unknown = sofia_glue_get_non_extra_unknown_headers(sip); + + extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_INFO_HEADER_PREFIX); + + nua_info(other_tech_pvt->nh, + SIPTAG_CONTENT_TYPE_STR(ct), + TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(!zstr(unknown), SIPTAG_HEADER_STR(unknown)), + TAG_IF(!zstr(other_tech_pvt->user_via), SIPTAG_VIA_STR(other_tech_pvt->user_via)), + TAG_IF(!zstr(pl), SIPTAG_PAYLOAD_STR(pl)), + TAG_END()); + switch_safe_free(extra_headers); + switch_safe_free(unknown); + switch_core_session_rwunlock(other_session); + } + } if (sip && sip->sip_content_type && sip->sip_content_type->c_type && !strcasecmp(sip->sip_content_type->c_type, "freeswitch/data")) { char *data = NULL; @@ -9984,11 +10101,9 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia user, ipv6 ? "[" : "", host, ipv6 ? "]" : "", port, sofia_glue_transport2str(transport)); if (sofia_glue_check_nat(profile, tech_pvt->mparams.remote_ip)) { - url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_public_url : profile->public_url; check_nat = 1; - } else { - url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url; } + url = sofia_glue_get_profile_url(profile, tech_pvt->mparams.remote_ip, transport); if (!url) { if (check_nat) { @@ -10023,11 +10138,7 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia } else { const char *url = NULL; - if (sofia_glue_check_nat(profile, tech_pvt->mparams.remote_ip)) { - url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_public_url : profile->public_url; - } else { - url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url; - } + url = sofia_glue_get_profile_url(profile, tech_pvt->mparams.remote_ip, transport); if (url) { const char *brackets = NULL; diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index eaad00a2a1..acbddcaf73 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -644,7 +644,7 @@ void sofia_glue_set_extra_headers(switch_core_session_t *session, sip_t const *s } for (un = sip->sip_unknown; un; un = un->un_next) { - if ((!strncasecmp(un->un_name, "X-", 2) && strncasecmp(un->un_name, "X-FS-", 5)) || !strncasecmp(un->un_name, "P-", 2) || !strncasecmp(un->un_name, "On", 2)) { + if (sofia_test_extra_headers(un->un_name)) { if (!zstr(un->un_value)) { switch_snprintf(name, sizeof(name), "%s%s", prefix, un->un_name); switch_channel_set_variable(channel, name, un->un_value); @@ -685,6 +685,33 @@ char *sofia_glue_get_extra_headers_from_event(switch_event_t *event, const char return extra_headers; } +char *sofia_glue_get_non_extra_unknown_headers(sip_t const *sip) +{ + char *unknown = NULL; + switch_stream_handle_t stream = { 0 }; + sip_unknown_t *un; + + if (!sip) { + return NULL; + } + + SWITCH_STANDARD_STREAM(stream); + for (un = sip->sip_unknown; un; un = un->un_next) { + if (!sofia_test_extra_headers(un->un_name)) { + if (!zstr(un->un_value)) { + stream.write_function(&stream, "%s: %s\r\n",un->un_name,un->un_value); + } + } + } + if (!zstr((char *) stream.data)) { + unknown = stream.data; + } else { + switch_safe_free(stream.data); + } + + return unknown; +} + switch_status_t sofia_glue_do_invite(switch_core_session_t *session) { char *alert_info = NULL; @@ -931,15 +958,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) ipv6 ? "[" : "", ip_addr, ipv6 ? "]" : "", tech_pvt->profile->extsipport); } } else { - if (sofia_glue_transport_has_tls(tech_pvt->transport)) { - tech_pvt->invite_contact = tech_pvt->profile->tls_url; - } else { - if (!zstr(tech_pvt->mparams.remote_ip) && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->mparams.remote_ip)) { - tech_pvt->invite_contact = tech_pvt->profile->public_url; - } else { - tech_pvt->invite_contact = tech_pvt->profile->url; - } - } + tech_pvt->invite_contact = sofia_glue_get_profile_url(tech_pvt->profile, tech_pvt->mparams.remote_ip, tech_pvt->transport); } } @@ -3105,6 +3124,33 @@ void sofia_glue_clear_soa(switch_core_session_t *session, switch_bool_t partner) } +char *sofia_glue_get_profile_url(sofia_profile_t *profile, char *remote_ip, const sofia_transport_t transport) +{ + char *url = NULL; + int check_nat = 0; + + if (!zstr(remote_ip) && sofia_glue_check_nat(profile, remote_ip)) { + check_nat = 1; + } + + if (sofia_glue_transport_has_tls(transport)) { + if (check_nat && profile->tls_public_url) { + url = profile->tls_public_url; + } else { + url = profile->tls_url; + } + } else { + if (check_nat && profile->public_url) { + url = profile->public_url; + } else { + url = profile->url; + } + } + + if (!url) url = profile->url; + + return url; +} /* For Emacs: * Local Variables: diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 343c231a44..e1973efabe 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -384,6 +384,7 @@ switch_status_t sofia_presence_chat_send(switch_event_t *message_event) sofia_glue_free_destination(dst); switch_safe_free(dup_dest); + switch_safe_free(user_via); switch_safe_free(remote_host); } diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 8316620cc2..ca2153eefe 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -161,7 +161,7 @@ static void close_socket(ws_socket_t *sock) } } - +void verto_broadcast(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id); static int ssl_init = 0; static int verto_init_ssl(verto_profile_t *profile) @@ -2389,8 +2389,6 @@ static void verto_set_media_options(verto_pvt_t *tech_pvt, verto_profile_t *prof tech_pvt->mparams->jb_msec = "-1"; switch_media_handle_set_media_flag(tech_pvt->smh, SCMF_SUPPRESS_CNG); - switch_media_handle_set_media_flag(tech_pvt->smh, SCMF_RENEG_ON_REINVITE); - //tech_pvt->mparams->auto_rtp_bugs = profile->auto_rtp_bugs; tech_pvt->mparams->timer_name = profile->timer_name; //tech_pvt->mparams->vflags = profile->vflags; @@ -3819,8 +3817,10 @@ static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, js } jevent = cJSON_Duplicate(params, 1); + write_event(event_channel, NULL, jevent); switch_event_channel_broadcast(event_channel, &jevent, modname, globals.event_channel_id); + if (jsock->profile->mcast_pub.sock != ws_sock_invalid) { if ((json_text = cJSON_PrintUnformatted(params))) { @@ -4677,7 +4677,7 @@ static switch_status_t parse_config(const char *cf) vhost->alias = switch_core_strdup(vhost->pool, val); } else if (!strcasecmp(var, "root")) { vhost->root = switch_core_strdup(vhost->pool, val); - } else if (!strcasecmp(var, "script_root")) { + } else if (!strcasecmp(var, "script-root")) { vhost->script_root = switch_core_strdup(vhost->pool, val); } else if (!strcasecmp(var, "index")) { vhost->index = switch_core_strdup(vhost->pool, val); diff --git a/src/mod/event_handlers/mod_amqp/mod_amqp_logging.c b/src/mod/event_handlers/mod_amqp/mod_amqp_logging.c index 8d4e4805be..da512cef39 100644 --- a/src/mod/event_handlers/mod_amqp/mod_amqp_logging.c +++ b/src/mod/event_handlers/mod_amqp/mod_amqp_logging.c @@ -94,12 +94,13 @@ switch_status_t mod_amqp_logging_recv(const switch_log_node_t *node, switch_log_ if (switch_queue_trypush(logging->send_queue, msg) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AMQP logging message queue full. Messages will be dropped!\n"); - return SWITCH_STATUS_SUCCESS; + switch_safe_free(hi); + goto done; } } } - + done: switch_safe_free(json); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/event_handlers/mod_smpp/mod_smpp_gateway.c b/src/mod/event_handlers/mod_smpp/mod_smpp_gateway.c index 1bf3771912..7125f04e0f 100644 --- a/src/mod/event_handlers/mod_smpp/mod_smpp_gateway.c +++ b/src/mod/event_handlers/mod_smpp/mod_smpp_gateway.c @@ -201,6 +201,7 @@ switch_status_t mod_smpp_gateway_connection_read(mod_smpp_gateway_t *gateway, sw switch_event_t *evt = NULL; generic_nack_t *gennack = NULL; char data[2048] = {0}; /* local buffer for unpacked PDU */ + int err = 0; /* Read from socket */ /* TODO: Add/Expand support for partial reads */ @@ -227,8 +228,7 @@ switch_status_t mod_smpp_gateway_connection_read(mod_smpp_gateway_t *gateway, sw } if ( smpp34_unpack2((void *)data, local_buffer, read_len + 4) ) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "smpp: error decoding the receive buffer:%d:%s\n", smpp34_errno, smpp34_strerror); - switch_goto_status(SWITCH_STATUS_GENERR, done); + err++; } if ( mod_smpp_globals.debug || gateway->debug ) { @@ -237,6 +237,12 @@ switch_status_t mod_smpp_gateway_connection_read(mod_smpp_gateway_t *gateway, sw gennack = (generic_nack_t *) data; *command_id = gennack->command_id; + + if (err && *command_id != SUBMIT_SM_RESP) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "smpp: error decoding the receive buffer:%d:%s\n", smpp34_errno, smpp34_strerror); + switch_goto_status(SWITCH_STATUS_GENERR, done); + } + switch(*command_id) { case BIND_TRANSCEIVER_RESP: if ( gennack->command_status != ESME_ROK ) { @@ -256,6 +262,21 @@ switch_status_t mod_smpp_gateway_connection_read(mod_smpp_gateway_t *gateway, sw case ENQUIRE_LINK: case ENQUIRE_LINK_RESP: case SUBMIT_SM_RESP: + switch (gennack->command_status) { + case ESME_ROK: + //AOK + break; + case ESME_RINVSRCADR: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Source Addr ID: %u\n", *command_id); + break; + case ESME_RINVDSTADR: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Dest Addr ID: %u\n", *command_id); + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Undocumented Error 0X%.8x ID: %u\n", gennack->command_status, *command_id); + break; + } + break; default: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unrecognized Command ID: %u\n", *command_id); diff --git a/src/mod/event_handlers/mod_snmp/Makefile.am b/src/mod/event_handlers/mod_snmp/Makefile.am index e949e9ad9e..a94ebe0c51 100644 --- a/src/mod/event_handlers/mod_snmp/Makefile.am +++ b/src/mod/event_handlers/mod_snmp/Makefile.am @@ -4,5 +4,5 @@ MODNAME=mod_snmp mod_LTLIBRARIES = mod_snmp.la mod_snmp_la_SOURCES = mod_snmp.c subagent.c mod_snmp_la_CFLAGS = $(AM_CFLAGS) -mod_snmp_la_LIBADD = $(switch_builddir)/libfreeswitch.la -lnetsnmpmibs -lnetsnmpagent -lnetsnmp +mod_snmp_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(SNMP_LIBS) mod_snmp_la_LDFLAGS = -avoid-version -module -no-undefined -shared diff --git a/src/mod/formats/mod_local_stream/mod_local_stream.c b/src/mod/formats/mod_local_stream/mod_local_stream.c index b314132f95..87be23842a 100644 --- a/src/mod/formats/mod_local_stream/mod_local_stream.c +++ b/src/mod/formats/mod_local_stream/mod_local_stream.c @@ -125,6 +125,7 @@ struct local_stream_source { switch_img_position_t logo_pos; uint8_t logo_opacity; uint8_t text_opacity; + switch_mm_t mm; }; typedef struct local_stream_source local_stream_source_t; @@ -479,6 +480,10 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void retry: + if (switch_core_file_has_video(use_fh, SWITCH_TRUE)) { + source->mm = use_fh->mm; + } + source->has_video = switch_core_file_has_video(use_fh, SWITCH_TRUE) || source->cover_art || source->banner_txt; is_open = switch_test_flag(use_fh, SWITCH_FILE_OPEN); @@ -934,8 +939,9 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle switch_status_t status; switch_time_t now; unsigned int fps = (unsigned int)ceil(handle->mm.fps); - unsigned int min_qsize = fps; - + unsigned int min_qsize = fps / 2; + unsigned int buf_qsize = 5; + if (!(context->ready && context->source->ready)) { return SWITCH_STATUS_FALSE; } @@ -973,7 +979,12 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle return SWITCH_STATUS_BREAK; } - while(context->ready && context->source->ready && (flags & SVR_FLUSH) && switch_queue_size(context->video_q) > min_qsize / 2) { + if (handle->mm.fps >= context->source->mm.source_fps) { + min_qsize = 1; + buf_qsize = 1; + } + + while(context->ready && context->source->ready && (flags & SVR_FLUSH) && switch_queue_size(context->video_q) > min_qsize) { if (switch_queue_trypop(context->video_q, &pop) == SWITCH_STATUS_SUCCESS) { switch_image_t *img = (switch_image_t *) pop; switch_img_free(&img); @@ -984,7 +995,7 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle return SWITCH_STATUS_FALSE; } - while (!(flags & SVR_BLOCK) && switch_queue_size(context->video_q) < 5) { + while (!(flags & SVR_BLOCK) && switch_queue_size(context->video_q) < buf_qsize) { return SWITCH_STATUS_BREAK; } diff --git a/src/mod/formats/mod_vlc/mod_vlc.c b/src/mod/formats/mod_vlc/mod_vlc.c index dbacf4e513..3cd8a2cebb 100644 --- a/src/mod/formats/mod_vlc/mod_vlc.c +++ b/src/mod/formats/mod_vlc/mod_vlc.c @@ -1659,7 +1659,7 @@ int vlc_write_video_imem_get_callback(void *data, const char *cookie, int64_t * } *output = context->video_frame_buffer; - switch_img_to_raw(img, *output, *size, SWITCH_IMG_FMT_YUY2); + switch_img_to_raw(img, *output, 0, SWITCH_IMG_FMT_YUY2); switch_img_free(&img); return 0; } diff --git a/src/mod/languages/mod_v8/include/fscoredb.hpp b/src/mod/languages/mod_v8/include/fscoredb.hpp index 5ac0a052b5..e15e308f1d 100644 --- a/src/mod/languages/mod_v8/include/fscoredb.hpp +++ b/src/mod/languages/mod_v8/include/fscoredb.hpp @@ -72,6 +72,7 @@ public: JS_COREDB_FUNCTION_DEF(Prepare); JS_COREDB_FUNCTION_DEF(BindText); JS_COREDB_FUNCTION_DEF(BindInt); + JS_COREDB_FUNCTION_DEF(Finalize); JS_COREDB_GET_PROPERTY_DEF(GetProperty); }; diff --git a/src/mod/languages/mod_v8/src/fscoredb.cpp b/src/mod/languages/mod_v8/src/fscoredb.cpp index a846eb8bbf..9bcb00c38f 100644 --- a/src/mod/languages/mod_v8/src/fscoredb.cpp +++ b/src/mod/languages/mod_v8/src/fscoredb.cpp @@ -232,6 +232,14 @@ JS_COREDB_FUNCTION_IMPL(Step) StepEx(info, SWITCH_CORE_DB_DONE); } +JS_COREDB_FUNCTION_IMPL(Finalize) +{ + if (_stmt) { + switch_core_db_finalize(_stmt); + _stmt = NULL; + } +} + JS_COREDB_FUNCTION_IMPL(Fetch) { HandleScope handle_scope(info.GetIsolate()); @@ -415,6 +423,7 @@ static const js_function_t db_methods[] = { {"prepare", FSCoreDB::Prepare}, {"bindText", FSCoreDB::BindText}, {"bindInt", FSCoreDB::BindInt}, + {"finalize", FSCoreDB::Finalize}, {0} }; diff --git a/src/switch.c b/src/switch.c index 942b5cd763..292baade79 100644 --- a/src/switch.c +++ b/src/switch.c @@ -504,8 +504,8 @@ int main(int argc, char *argv[]) char *arg_argv[128] = { 0 }; int alt_dirs = 0, alt_base = 0, log_set = 0, run_set = 0, do_kill = 0; int priority = 0; -#ifdef __sun - switch_core_flag_t flags = SCF_USE_SQL; +#if (defined(__SVR4) && defined(__sun)) + switch_core_flag_t flags = SCF_USE_SQL | SCF_CALIBRATE_CLOCK | SCF_USE_CLOCK_RT; #else switch_core_flag_t flags = SCF_USE_SQL | SCF_USE_AUTO_NAT | SCF_USE_NAT_MAPPING | SCF_CALIBRATE_CLOCK | SCF_USE_CLOCK_RT; #endif diff --git a/src/switch_core.c b/src/switch_core.c index 039531bb86..e06b6b1f39 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1373,6 +1373,10 @@ SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_ switch_bool_t ok = SWITCH_FALSE; char *ipv4 = NULL; + if (!list_name) { + return SWITCH_FALSE; + } + if ((ipv4 = switch_network_ipv4_mapped_ipv6_addr(ip_str))) { ip_str = ipv4; ipv6 = NULL; diff --git a/src/switch_core_media.c b/src/switch_core_media.c index f1295b0ee5..f5f6f427b1 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -1827,6 +1827,8 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses return; } + ocodec = switch_channel_get_variable(session->channel, SWITCH_ORIGINATOR_CODEC_VARIABLE); + smh->payload_space = 0; switch_assert(smh->session != NULL); @@ -1837,11 +1839,10 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses } val = switch_channel_get_variable_dup(session->channel, "media_mix_inbound_outbound_codecs", SWITCH_FALSE, -1); - if (!val || !switch_true(val)) { - if ((ocodec = switch_channel_get_variable(session->channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) { - codec_string = ocodec; - goto ready; - } + + if ((!val || !switch_true(val) || smh->media_flags[SCMF_DISABLE_TRANSCODING]) && ocodec) { + codec_string = ocodec; + goto ready; } if (!(codec_string = switch_channel_get_variable(session->channel, "codec_string"))) { @@ -1854,13 +1855,7 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses } if (ocodec) { - if (!codec_string || (smh->media_flags[SCMF_DISABLE_TRANSCODING])) { - codec_string = ocodec; - } else { - if (!(codec_string = switch_core_session_sprintf(smh->session, "%s,%s", ocodec, codec_string))) { - codec_string = ocodec; - } - } + codec_string = switch_core_session_sprintf(smh->session, "%s,%s", ocodec, codec_string); } ready: @@ -1873,83 +1868,6 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses switch_channel_set_variable(session->channel, "rtp_use_codec_string", codec_string); smh->codec_order_last = switch_separate_string(tmp_codec_string, ',', smh->codec_order, SWITCH_MAX_CODECS); smh->mparams->num_codecs = switch_loadable_module_get_codecs_sorted(smh->codecs, smh->fmtp, SWITCH_MAX_CODECS, smh->codec_order, smh->codec_order_last); - -} - -static void adjust_jb(switch_core_session_t *session, int new_ptime_ms) -{ - const char *val; - switch_media_handle_t *smh; - switch_rtp_engine_t *a_engine = NULL; - int maxlen = 0; - int32_t jb_msec = 0 ; - int qlen, maxqlen = 50; - - switch_assert(session); - - if (!(smh = session->media_handle)) { - return; - } - - a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO]; - - if ((val = switch_channel_get_variable(session->channel, "jitterbuffer_msec")) || (val = smh->mparams->jb_msec)) { - char *p; - - if (!jb_msec) { - jb_msec = atoi(val); - - if (strchr(val, 'p') && jb_msec > 0) { - jb_msec *= -1; - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG3, "Will not adjust JB size, token 'p' not specified\n"); - return; - } - - if ((p = strchr(val, ':'))) { - p++; - maxlen = atoi(p); - - if (strchr(p, 'p') && maxlen > 0) { - maxlen *= -1; - } - } - } - - if (jb_msec < 0 && jb_msec > -1000) { - jb_msec = new_ptime_ms * abs(jb_msec); - } - - if (maxlen < 0 && maxlen > -1000) { - maxlen = new_ptime_ms * abs(maxlen); - } - - if (jb_msec < 10 || jb_msec > 10000) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, - "Invalid Jitterbuffer spec [%d] must be between 10 and 10000\n", jb_msec); - } else { - qlen = jb_msec / new_ptime_ms; - if (maxlen) { - maxqlen = maxlen / new_ptime_ms; - } - if (maxqlen < qlen) { - maxqlen = qlen * 5; - } - if (switch_rtp_activate_jitter_buffer(a_engine->rtp_session, qlen, maxqlen, - a_engine->read_impl.samples_per_packet, a_engine->read_impl.samples_per_second) == SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), - SWITCH_LOG_DEBUG, "Adjusting Jitterbuffer to %dms (%d frames) (%d max frames)\n", - jb_msec, qlen, maxqlen); - switch_channel_set_flag(session->channel, CF_JITTERBUFFER); - if (!switch_false(switch_channel_get_variable(session->channel, "rtp_jitter_buffer_plc"))) { - switch_channel_set_flag(session->channel, CF_JITTERBUFFER_PLC); - } - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), - SWITCH_LOG_DEBUG, "Error adjusting Jitterbuffer to %dms (%d frames)\n", jb_msec, qlen); - } - } - } } static void check_jb(switch_core_session_t *session, const char *input, int32_t jb_msec, int32_t maxlen, switch_bool_t silent) @@ -2498,6 +2416,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session if (engine->last_codec_ms && engine->last_codec_ms == codec_ms) { engine->mismatch_count++; + } else { + engine->mismatch_count = 0; } engine->last_codec_ms = codec_ms; @@ -2554,9 +2474,17 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session codec_ms = codec_ms / (int) (engine->read_frame.seq - engine->last_seq); } + if (codec_ms && codec_ms != engine->cur_payload_map->codec_ms) { + if (engine->last_codec_ms && engine->last_codec_ms == codec_ms) { + engine->mismatch_count++; + } + } else { + engine->mismatch_count = 0; + } + engine->last_codec_ms = codec_ms; - if (codec_ms != engine->cur_payload_map->codec_ms && codec_ms) { + if (engine->mismatch_count > MAX_MISMATCH_FRAMES) { if (codec_ms > 120) { /*will show too many times with packet loss*/ @@ -2571,14 +2499,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session if (codec_ms != engine->cur_payload_map->codec_ms) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, - "[%s]: Asynchronous PTIME supported, adjusting JB size. Remote PTIME changed from [%d] to [%d]\n", + "[%s]: Packet size change detected. Remote PTIME changed from [%d] to [%d]\n", is_vbr?"VBR":"CBR", (int) engine->cur_payload_map->codec_ms, (int) codec_ms ); engine->cur_payload_map->codec_ms = codec_ms; - /* adjust audio JB size, but do not substitute the codec */ - adjust_jb(session,codec_ms); engine->reset_codec = 2; if (switch_channel_test_flag(session->channel, CF_CONFERENCE)) { @@ -3576,7 +3502,7 @@ static switch_status_t check_ice(switch_media_handle_t *smh, switch_media_type_t done_choosing: - if (!engine->ice_in.is_chosen[0] || !engine->ice_in.is_chosen[1]) { + if (!engine->ice_in.is_chosen[0]) { /* PUNT */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "%s no suitable candidates found.\n", switch_channel_get_name(smh->session->channel)); @@ -3780,7 +3706,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s sdp_media_t *m; sdp_attribute_t *attr; int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0; - int sendonly = 0, recvonly = 0; + int sendonly = 0, recvonly = 0, inactive = 0; int greedy = 0, x = 0, skip = 0; switch_channel_t *channel = switch_core_session_get_channel(session); const char *val; @@ -3789,7 +3715,6 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s int scrooge = 0; sdp_parser_t *parser = NULL; sdp_session_t *sdp; - int reneg = 1; const switch_codec_implementation_t **codec_array; int total_codecs; switch_rtp_engine_t *a_engine, *v_engine; @@ -3839,7 +3764,9 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s a_engine->new_dtls = 1; a_engine->new_ice = 1; a_engine->reject_avp = 0; - + + switch_media_handle_set_media_flag(smh, SCMF_RECV_SDP); + switch_core_session_parse_crypto_prefs(session); clear_pmaps(a_engine); @@ -3951,116 +3878,120 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s got_udptl++; } - if (got_udptl && m->m_type == sdp_media_image && m->m_port) { - switch_t38_options_t *t38_options = switch_core_media_process_udptl(session, sdp, m); + if (got_udptl && m->m_type == sdp_media_image) { + switch_channel_set_flag(session->channel, CF_IMAGE_SDP); - if (switch_channel_test_app_flag_key("T38", session->channel, CF_APP_T38_NEGOTIATED)) { + if (m->m_port) { + switch_t38_options_t *t38_options = switch_core_media_process_udptl(session, sdp, m); + + if (switch_channel_test_app_flag_key("T38", session->channel, CF_APP_T38_NEGOTIATED)) { + match = 1; + goto done; + } + + if (switch_true(switch_channel_get_variable(channel, "refuse_t38"))) { + switch_channel_clear_app_flag_key("T38", session->channel, CF_APP_T38); + match = 0; + goto done; + } else { + const char *var = switch_channel_get_variable(channel, "t38_passthru"); + int pass = switch_channel_test_flag(smh->session->channel, CF_T38_PASSTHRU); + + + if (switch_channel_test_app_flag_key("T38", session->channel, CF_APP_T38)) { + if (proceed) *proceed = 0; + } + + if (var) { + if (!(pass = switch_true(var))) { + if (!strcasecmp(var, "once")) { + pass = 2; + } + } + } + + if ((pass == 2 && switch_channel_test_flag(smh->session->channel, CF_T38_PASSTHRU)) + || !switch_channel_test_flag(session->channel, CF_REINVITE) || + + switch_channel_test_flag(session->channel, CF_PROXY_MODE) || + switch_channel_test_flag(session->channel, CF_PROXY_MEDIA) || + !switch_rtp_ready(a_engine->rtp_session)) { + pass = 0; + } + + if (pass && switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { + switch_channel_t *other_channel = switch_core_session_get_channel(other_session); + switch_core_session_message_t *msg; + char *remote_host = switch_rtp_get_remote_host(a_engine->rtp_session); + switch_port_t remote_port = switch_rtp_get_remote_port(a_engine->rtp_session); + char tmp[32] = ""; + + + if (!switch_channel_test_flag(other_channel, CF_ANSWERED)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), + SWITCH_LOG_WARNING, "%s Error Passing T.38 to unanswered channel %s\n", + switch_channel_get_name(session->channel), switch_channel_get_name(other_channel)); + switch_core_session_rwunlock(other_session); + + pass = 0; + match = 0; + goto done; + } + + + if (switch_true(switch_channel_get_variable(session->channel, "t38_broken_boolean")) && + switch_true(switch_channel_get_variable(session->channel, "t38_pass_broken_boolean"))) { + switch_channel_set_variable(other_channel, "t38_broken_boolean", "true"); + } + + a_engine->cur_payload_map->remote_sdp_ip = switch_core_session_strdup(session, t38_options->remote_ip); + a_engine->cur_payload_map->remote_sdp_port = t38_options->remote_port; + + if (remote_host && remote_port && !strcmp(remote_host, a_engine->cur_payload_map->remote_sdp_ip) && remote_port == a_engine->cur_payload_map->remote_sdp_port) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n", + switch_channel_get_name(session->channel)); + } else { + const char *err = NULL; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n", + switch_channel_get_name(session->channel), + remote_host, remote_port, a_engine->cur_payload_map->remote_sdp_ip, a_engine->cur_payload_map->remote_sdp_port); + + switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->remote_sdp_port); + switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, a_engine->cur_payload_map->remote_sdp_ip); + switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp); + + if (switch_rtp_set_remote_address(a_engine->rtp_session, a_engine->cur_payload_map->remote_sdp_ip, + a_engine->cur_payload_map->remote_sdp_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err); + switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); + } + + switch_core_media_check_autoadj(session); + } + + + + switch_core_media_copy_t38_options(t38_options, other_session); + + switch_channel_set_flag(smh->session->channel, CF_T38_PASSTHRU); + switch_channel_set_flag(other_session->channel, CF_T38_PASSTHRU); + + msg = switch_core_session_alloc(other_session, sizeof(*msg)); + msg->message_id = SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA; + msg->from = __FILE__; + msg->string_arg = switch_core_session_strdup(other_session, r_sdp); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing T38 req to other leg.\n%s\n", r_sdp); + switch_core_session_queue_message(other_session, msg); + switch_core_session_rwunlock(other_session); + } + } + + + /* do nothing here, mod_fax will trigger a response (if it's listening =/) */ match = 1; goto done; } - - if (switch_true(switch_channel_get_variable(channel, "refuse_t38"))) { - switch_channel_clear_app_flag_key("T38", session->channel, CF_APP_T38); - match = 0; - goto done; - } else { - const char *var = switch_channel_get_variable(channel, "t38_passthru"); - int pass = switch_channel_test_flag(smh->session->channel, CF_T38_PASSTHRU); - - - if (switch_channel_test_app_flag_key("T38", session->channel, CF_APP_T38)) { - if (proceed) *proceed = 0; - } - - if (var) { - if (!(pass = switch_true(var))) { - if (!strcasecmp(var, "once")) { - pass = 2; - } - } - } - - if ((pass == 2 && switch_channel_test_flag(smh->session->channel, CF_T38_PASSTHRU)) - || !switch_channel_test_flag(session->channel, CF_REINVITE) || - - switch_channel_test_flag(session->channel, CF_PROXY_MODE) || - switch_channel_test_flag(session->channel, CF_PROXY_MEDIA) || - !switch_rtp_ready(a_engine->rtp_session)) { - pass = 0; - } - - if (pass && switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { - switch_channel_t *other_channel = switch_core_session_get_channel(other_session); - switch_core_session_message_t *msg; - char *remote_host = switch_rtp_get_remote_host(a_engine->rtp_session); - switch_port_t remote_port = switch_rtp_get_remote_port(a_engine->rtp_session); - char tmp[32] = ""; - - - if (!switch_channel_test_flag(other_channel, CF_ANSWERED)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), - SWITCH_LOG_WARNING, "%s Error Passing T.38 to unanswered channel %s\n", - switch_channel_get_name(session->channel), switch_channel_get_name(other_channel)); - switch_core_session_rwunlock(other_session); - - pass = 0; - match = 0; - goto done; - } - - - if (switch_true(switch_channel_get_variable(session->channel, "t38_broken_boolean")) && - switch_true(switch_channel_get_variable(session->channel, "t38_pass_broken_boolean"))) { - switch_channel_set_variable(other_channel, "t38_broken_boolean", "true"); - } - - a_engine->cur_payload_map->remote_sdp_ip = switch_core_session_strdup(session, t38_options->remote_ip); - a_engine->cur_payload_map->remote_sdp_port = t38_options->remote_port; - - if (remote_host && remote_port && !strcmp(remote_host, a_engine->cur_payload_map->remote_sdp_ip) && remote_port == a_engine->cur_payload_map->remote_sdp_port) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio params are unchanged for %s.\n", - switch_channel_get_name(session->channel)); - } else { - const char *err = NULL; - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio params changed for %s from %s:%d to %s:%d\n", - switch_channel_get_name(session->channel), - remote_host, remote_port, a_engine->cur_payload_map->remote_sdp_ip, a_engine->cur_payload_map->remote_sdp_port); - - switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->remote_sdp_port); - switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, a_engine->cur_payload_map->remote_sdp_ip); - switch_channel_set_variable(session->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp); - - if (switch_rtp_set_remote_address(a_engine->rtp_session, a_engine->cur_payload_map->remote_sdp_ip, - a_engine->cur_payload_map->remote_sdp_port, 0, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err); - switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); - } - - switch_core_media_check_autoadj(session); - } - - - - switch_core_media_copy_t38_options(t38_options, other_session); - - switch_channel_set_flag(smh->session->channel, CF_T38_PASSTHRU); - switch_channel_set_flag(other_session->channel, CF_T38_PASSTHRU); - - msg = switch_core_session_alloc(other_session, sizeof(*msg)); - msg->message_id = SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA; - msg->from = __FILE__; - msg->string_arg = switch_core_session_strdup(other_session, r_sdp); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing T38 req to other leg.\n%s\n", r_sdp); - switch_core_session_queue_message(other_session, msg); - switch_core_session_rwunlock(other_session); - } - } - - - /* do nothing here, mod_fax will trigger a response (if it's listening =/) */ - match = 1; - goto done; } else if (m->m_type == sdp_media_audio && m->m_port && got_audio && got_savp) { a_engine->reject_avp = 1; } else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) { @@ -4074,6 +4005,9 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s if (!sendonly && (m->m_mode == sdp_sendonly || m->m_mode == sdp_inactive)) { sendonly = 1; + if (m->m_mode == sdp_inactive) { + inactive = 1; + } } if (!sendonly && m->m_connections && m->m_connections->c_address && !strcmp(m->m_connections->c_address, "0.0.0.0")) { @@ -4093,6 +4027,10 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s switch_channel_set_variable(smh->session->channel, "audio_media_flow", "recvonly"); a_engine->smode = SWITCH_MEDIA_FLOW_RECVONLY; break; + case SWITCH_MEDIA_FLOW_INACTIVE: + switch_channel_set_variable(smh->session->channel, "audio_media_flow", "inactive"); + a_engine->smode = SWITCH_MEDIA_FLOW_INACTIVE; + break; default: switch_channel_set_variable(smh->session->channel, "audio_media_flow", "sendrecv"); a_engine->smode = SWITCH_MEDIA_FLOW_SENDRECV; @@ -4112,7 +4050,6 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s sendonly = 1; switch_channel_set_variable(session->channel, "media_audio_mode", "recvonly"); } else if (sendonly < 2 && !strcasecmp(attr->a_name, "inactive")) { - sendonly = 1; switch_channel_set_variable(session->channel, "media_audio_mode", "inactive"); } else if (!strcasecmp(attr->a_name, "recvonly")) { switch_channel_set_variable(session->channel, "media_audio_mode", "sendonly"); @@ -4140,12 +4077,19 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s } - if (sendonly != 1 && recvonly != 1) { + if (sendonly != 1 && recvonly != 1 && inactive != 1) { switch_channel_set_variable(session->channel, "media_audio_mode", NULL); } if (sdp_type == SDP_TYPE_RESPONSE) { - if (sendonly) { + if (inactive) { + // When freeswitch had previously sent inactive in sip request. it should remain inactive otherwise smode should be sendrecv + if (a_engine->smode==SWITCH_MEDIA_FLOW_INACTIVE) { + a_engine->smode = sdp_media_flow(sdp_inactive); + } else { + a_engine->smode = sdp_media_flow(sdp_sendrecv); + } + } else if (sendonly) { a_engine->smode = sdp_media_flow(sdp_sendonly); } else if (recvonly) { a_engine->smode = sdp_media_flow(sdp_recvonly); @@ -4158,48 +4102,15 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s && switch_true(val))) && !smh->mparams->hold_laps) { smh->mparams->hold_laps++; - if (switch_core_media_toggle_hold(session, sendonly)) { - reneg = switch_media_handle_test_media_flag(smh, SCMF_RENEG_ON_HOLD); - if ((val = switch_channel_get_variable(session->channel, "rtp_renegotiate_codec_on_hold"))) { - reneg = switch_true(val); - } - } - } - - if (reneg) { - reneg = switch_media_handle_test_media_flag(smh, SCMF_RENEG_ON_REINVITE); - - if ((val = switch_channel_get_variable(session->channel, "rtp_renegotiate_codec_on_reinvite"))) { - reneg = switch_true(val); - } - } - - if (session->bugs) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, - "Session is connected to a media bug. " - "Re-Negotiation implicitly disabled.\n"); - reneg = 0; - } - - if (switch_channel_test_flag(session->channel, CF_RECOVERING)) { - reneg = 0; - } - - if (sdp_type == SDP_TYPE_RESPONSE && smh->num_negotiated_codecs) { - /* response to re-invite or update, only negotiated codecs are valid */ - reneg = 0; + switch_core_media_toggle_hold(session, sendonly); } - if (!reneg && smh->num_negotiated_codecs) { - codec_array = smh->negotiated_codecs; - total_codecs = smh->num_negotiated_codecs; - } else if (reneg) { - smh->mparams->num_codecs = 0; - switch_core_media_prepare_codecs(session, SWITCH_FALSE); - codec_array = smh->codecs; - total_codecs = smh->mparams->num_codecs; - } + smh->mparams->num_codecs = 0; + smh->num_negotiated_codecs = 0; + switch_core_media_prepare_codecs(session, SWITCH_TRUE); + codec_array = smh->codecs; + total_codecs = smh->mparams->num_codecs; if (switch_rtp_has_dtls() && dtls_ok(session)) { @@ -4261,7 +4172,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s } x = 0; - + for (map = m->m_rtpmaps; map; map = map->rm_next) { int32_t i; const char *rm_encoding; @@ -4493,7 +4404,6 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s match = 1; a_engine->codec_negotiated = 1; - smh->num_negotiated_codecs = 0; for(j = 0; j < m_idx; j++) { payload_map_t *pmap = switch_core_media_add_payload_map(session, @@ -4552,6 +4462,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s pmap->rm_fmtp = switch_core_session_strdup(session, (char *) mmap->rm_fmtp); pmap->agreed_pt = (switch_payload_t) mmap->rm_pt; + smh->negotiated_codecs[smh->num_negotiated_codecs++] = mimp; pmap->recv_pt = (switch_payload_t)mmap->rm_pt; @@ -4585,14 +4496,6 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s -#if 0 - if (!switch_true(mirror) && - switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && - (!switch_channel_test_flag(session->channel, CF_REINVITE) || switch_media_handle_test_media_flag(smh, SCMF_RENEG_ON_REINVITE))) { - switch_core_media_get_offered_pt(session, matches[0].imp, &a_engine->cur_payload_map->recv_pt); - } -#endif - switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->recv_pt); switch_channel_set_variable(session->channel, "rtp_audio_recv_pt", tmp); @@ -4759,6 +4662,10 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s switch_channel_set_variable(smh->session->channel, "video_media_flow", "recvonly"); v_engine->smode = SWITCH_MEDIA_FLOW_RECVONLY; break; + case SWITCH_MEDIA_FLOW_INACTIVE: + switch_channel_set_variable(smh->session->channel, "video_media_flow", "inactive"); + v_engine->smode = SWITCH_MEDIA_FLOW_INACTIVE; + break; default: switch_channel_set_variable(smh->session->channel, "video_media_flow", "sendrecv"); v_engine->smode = SWITCH_MEDIA_FLOW_SENDRECV; @@ -4836,10 +4743,11 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s if (!(rm_encoding = map->rm_encoding)) { rm_encoding = ""; } + printf("WTF TOT %d\n", total_codecs); for (i = 0; i < total_codecs; i++) { const switch_codec_implementation_t *imp = codec_array[i]; - + if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) { continue; } @@ -4849,7 +4757,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s continue; } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CONSOLE, "Video Codec Compare [%s:%d]/[%s:%d]\n", + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video Codec Compare [%s:%d]/[%s:%d]\n", rm_encoding, map->rm_pt, imp->iananame, imp->ianacode); if ((zstr(map->rm_encoding) || (smh->mparams->ndlb & SM_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) { vmatch = (map->rm_pt == imp->ianacode) ? 1 : 0; @@ -4873,9 +4781,10 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s matches[m_idx].imp = imp; matches[m_idx].map = map; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CONSOLE, "Video Codec Compare [%s:%d] +++ is saved as a match\n", + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video Codec Compare [%s:%d] +++ is saved as a match\n", imp->iananame, map->rm_pt); - m_idx++; + + m_idx++; } vmatch = 0; @@ -5255,7 +5164,7 @@ static void *SWITCH_THREAD_FUNC video_write_thread(switch_thread_t *thread, void switch_core_media_gen_key_frame(session); - if (smh->video_write_fh->mm.source_fps) { + if (smh->video_write_fh && smh->video_write_fh->mm.source_fps) { fps = (int) smh->video_write_fh->mm.source_fps; } else { fps = video_globals.fps; @@ -5758,6 +5667,24 @@ SWITCH_DECLARE(switch_bool_t) switch_core_session_in_video_thread(switch_core_se } +SWITCH_DECLARE(void) switch_core_media_parse_media_flags(switch_core_session_t *session) +{ + const char *var; + switch_media_handle_t *smh; + + if (!(smh = session->media_handle)) { + return; + } + + if ((var = switch_channel_get_variable(session->channel, "rtp_media_autofix_timing"))) { + if (switch_true(var)) { + switch_media_handle_set_media_flag(smh, SCMF_AUTOFIX_TIMING); + } else { + switch_media_handle_clear_media_flag(smh, SCMF_AUTOFIX_TIMING); + } + } +} + //? #define RA_PTR_LEN 512 SWITCH_DECLARE(switch_status_t) switch_core_media_proxy_remote_addr(switch_core_session_t *session, const char *sdp_str) @@ -6134,6 +6061,16 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_choose_port(switch_core_sessio use_ip = smh->mparams->rtpip; } + if (zstr(smh->mparams->remote_ip)) { /* no remote_ip, we're originating */ + if (!zstr(smh->mparams->extrtpip)) { /* and we've got an ext-rtp-ip, eg, from verto config */ + use_ip = smh->mparams->extrtpip; /* let's use it for composing local sdp to send to client */ + /* + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, + "%s will use %s instead of %s in SDP, because we're originating and we have an ext-rtp-ip setting\n", + switch_channel_get_name(smh->session->channel), smh->mparams->extrtpip, smh->mparams->rtpip); + */ + } + } engine->adv_sdp_port = sdp_port; engine->adv_sdp_ip = smh->mparams->adv_sdp_audio_ip = smh->mparams->extrtpip = switch_core_session_strdup(session, use_ip); @@ -6392,6 +6329,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi return SWITCH_STATUS_FALSE; } + switch_core_media_parse_media_flags(session); if (switch_rtp_ready(a_engine->rtp_session)) { switch_rtp_reset_media_timer(a_engine->rtp_session); @@ -6525,9 +6463,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "AUDIO RTP CHANGING DEST TO: [%s:%d]\n", a_engine->cur_payload_map->remote_sdp_ip, a_engine->cur_payload_map->remote_sdp_port); - if (switch_channel_test_flag(session->channel, CF_PROTO_HOLD) && strcmp(a_engine->cur_payload_map->remote_sdp_ip, "0.0.0.0")) { - switch_core_media_toggle_hold(session, 0); - } + //if (switch_channel_test_flag(session->channel, CF_PROTO_HOLD) && strcmp(a_engine->cur_payload_map->remote_sdp_ip, "0.0.0.0")) { + // switch_core_media_toggle_hold(session, 0); + //} if (!switch_media_handle_test_media_flag(smh, SCMF_DISABLE_RTP_AUTOADJ) && @@ -7099,8 +7037,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi if (v_engine->ice_in.cands[v_engine->ice_in.chosen[1]][1].ready) { - if (v_engine->rtcp_mux > 0 && !strcmp(v_engine->ice_in.cands[v_engine->ice_in.chosen[1]][1].con_addr, v_engine->ice_in.cands[v_engine->ice_in.chosen[0]][0].con_addr) - && v_engine->ice_in.cands[v_engine->ice_in.chosen[1]][1].con_port == v_engine->ice_in.cands[v_engine->ice_in.chosen[0]][0].con_port) { + if (v_engine->rtcp_mux > 0 && v_engine->ice_in.cands[v_engine->ice_in.chosen[0]][0].ready && + !strcmp(v_engine->ice_in.cands[v_engine->ice_in.chosen[1]][1].con_addr, + v_engine->ice_in.cands[v_engine->ice_in.chosen[0]][0].con_addr) && + v_engine->ice_in.cands[v_engine->ice_in.chosen[1]][1].con_port == v_engine->ice_in.cands[v_engine->ice_in.chosen[0]][0].con_port) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Skipping VIDEO RTCP ICE (Same as VIDEO RTP)\n"); } else { @@ -7410,7 +7350,7 @@ static void generate_m(switch_core_session_t *session, char *buf, size_t buflen, } if (!zstr(a_engine->local_dtls_fingerprint.type) && secure) { - switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=fingerprint:%s %s\na=setup:%s\r\n", a_engine->local_dtls_fingerprint.type, + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=fingerprint:%s %s\r\na=setup:%s\r\n", a_engine->local_dtls_fingerprint.type, a_engine->local_dtls_fingerprint.str, get_setup(a_engine, session, sdp_type)); } @@ -7704,7 +7644,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess int is_outbound = switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND; const char *vbw; int bw = 256; - uint8_t fir = 0, nack = 0, pli = 0, tmmbr = 0; + uint8_t fir = 0, nack = 0, pli = 0, tmmbr = 0, has_vid = 0; switch_assert(session); @@ -7749,6 +7689,10 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess smh->mparams->rtcp_video_interval_msec = SWITCH_RTCP_VIDEO_INTERVAL_MSEC; } + if (switch_true(switch_channel_get_variable(session->channel, "add_ice_candidates"))) { + switch_channel_set_flag(session->channel, CF_ICE); + } + if ( switch_rtp_has_dtls() && dtls_ok(session)) { if (switch_channel_test_flag(session->channel, CF_AVPF) || switch_true(switch_channel_get_variable(smh->session->channel, "rtp_use_dtls"))) { @@ -7940,12 +7884,14 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess sr = "sendonly"; } else if (a_engine->smode == SWITCH_MEDIA_FLOW_RECVONLY) { sr = "recvonly"; + } else if (a_engine->smode == SWITCH_MEDIA_FLOW_INACTIVE) { + sr = "inactive"; } else { sr = "sendrecv"; } if ((var_val = switch_channel_get_variable(session->channel, "origination_audio_mode"))) { - if (!strcasecmp(sr, "sendonly") || !strcasecmp(sr, "recvonly") || !strcasecmp(sr, "sendrecv")) { + if (!strcasecmp(sr, "sendonly") || !strcasecmp(sr, "recvonly") || !strcasecmp(sr, "sendrecv") || !strcasecmp(sr, "inactive")) { sr = var_val; } switch_channel_set_variable(session->channel, "origination_audio_mode", NULL); @@ -8073,7 +8019,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d telephone-event/%d\r\n", smh->mparams->te, smh->mparams->te_rate); } else { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d telephone-event/%d\na=fmtp:%d 0-16\r\n", + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d telephone-event/%d\r\na=fmtp:%d 0-16\r\n", smh->mparams->te, smh->mparams->te_rate, smh->mparams->te); } } @@ -8290,9 +8236,34 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess } + if (switch_channel_test_flag(session->channel, CF_IMAGE_SDP)) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "m=image 0 UDPTL T38\r\n", SWITCH_VA_NONE); + + } + + video: - if (!switch_channel_test_flag(session->channel, CF_VIDEO_POSSIBLE)) { + + if (!switch_channel_test_flag(session->channel, CF_VIDEO_POSSIBLE) && switch_media_handle_test_media_flag(smh, SCMF_RECV_SDP)) { + has_vid = 0; + } else { + int i; + + for (i = 0; i < smh->mparams->num_codecs; i++) { + const switch_codec_implementation_t *imp = smh->codecs[i]; + + + if (imp->codec_type == SWITCH_CODEC_TYPE_VIDEO) { + has_vid = 1; + break; + } + } + + } + + + if (!has_vid) { if (switch_channel_test_flag(session->channel, CF_VIDEO_SDP_RECVD)) { switch_channel_clear_flag(session->channel, CF_VIDEO_SDP_RECVD); switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "m=video 0 %s 19\r\n", @@ -8385,6 +8356,24 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess } switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "\r\n"); + + + if (!(vbw = switch_channel_get_variable(smh->session->channel, "rtp_video_max_bandwidth"))) { + vbw = switch_channel_get_variable(smh->session->channel, "rtp_video_max_bandwidth_in"); + } + + if (!vbw) { + vbw = "1mb"; + } + + bw = switch_parse_bandwidth_string(vbw); + + if (bw > 0) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "b=AS:%d\r\n", bw); + //switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "b=TIAS:%d\r\n", bw); + } + + if (v_engine->codec_negotiated) { const char *of; @@ -8452,6 +8441,8 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s", "a=sendonly\r\n"); } else if (v_engine->smode == SWITCH_MEDIA_FLOW_RECVONLY) { switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s", "a=recvonly\r\n"); + } else if (v_engine->smode == SWITCH_MEDIA_FLOW_INACTIVE) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s", "a=inactive\r\n"); } } else if (smh->mparams->num_codecs) { @@ -8537,8 +8528,8 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess if (!zstr(v_engine->local_dtls_fingerprint.type)) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fingerprint:%s %s\na=setup:%s\r\n", v_engine->local_dtls_fingerprint.type, - v_engine->local_dtls_fingerprint.str, get_setup(v_engine, session, sdp_type)); + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fingerprint:%s %s\r\na=setup:%s\r\n", + v_engine->local_dtls_fingerprint.type, v_engine->local_dtls_fingerprint.str, get_setup(v_engine, session, sdp_type)); } @@ -8551,22 +8542,6 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess } } - - if (!(vbw = switch_channel_get_variable(smh->session->channel, "rtp_video_max_bandwidth"))) { - vbw = switch_channel_get_variable(smh->session->channel, "rtp_video_max_bandwidth_in"); - } - - if (!vbw) { - vbw = "1mb"; - } - - bw = switch_parse_bandwidth_string(vbw); - - if (bw > 0) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "b=AS:%d\r\n", bw); - //switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "b=TIAS:%d\r\n", bw); - } - if (sdp_type == SDP_TYPE_REQUEST) { fir++; pli++; @@ -8826,6 +8801,7 @@ SWITCH_DECLARE(void) switch_core_media_set_udptl_image_sdp(switch_core_session_t a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO]; + switch_channel_clear_flag(session->channel, CF_IMAGE_SDP); switch_assert(t38_options); @@ -9837,8 +9813,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 1); } - switch_media_handle_set_media_flag(smh, SCMF_RENEG_ON_REINVITE); - if (msg->numeric_arg && switch_core_session_get_partner(session, &nsession) == SWITCH_STATUS_SUCCESS) { msg->numeric_arg = 0; switch_core_session_receive_message(nsession, msg); @@ -11222,8 +11196,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_encoded_video_frame(sw switch_io_event_hook_video_write_frame_t *ptr; switch_status_t status = SWITCH_STATUS_FALSE; - if (switch_core_session_media_flow(session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG3, "Writing video to RECVONLY session\n"); + if (switch_core_session_media_flow(session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY || switch_core_session_media_flow(session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_INACTIVE) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG3, "Writing video to RECVONLY/INACTIVE session\n"); return SWITCH_STATUS_SUCCESS; } @@ -11293,8 +11267,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor return SWITCH_STATUS_FALSE; } - if (switch_core_session_media_flow(session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG3, "Writing video to RECVONLY session\n"); + if (switch_core_session_media_flow(session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY || switch_core_session_media_flow(session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_INACTIVE) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG3, "Writing video to RECVONLY/INACTIVE session\n"); return SWITCH_STATUS_SUCCESS; } @@ -11524,6 +11498,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core switch_io_event_hook_video_read_frame_t *ptr; uint32_t loops = 0; switch_media_handle_t *smh; + int patchers = 0; switch_assert(session != NULL); @@ -11679,7 +11654,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core if (bp->callback && switch_test_flag(bp, SMBF_READ_VIDEO_PING)) { + if (switch_test_flag(bp, SMBF_READ_VIDEO_PATCH)) { + patchers++; + } + bp->video_ping_frame = *frame; + if (bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ_VIDEO_PING) == SWITCH_FALSE || (bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL))) { ok = SWITCH_FALSE; @@ -11705,7 +11685,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core } } - + if ((*frame) && (*frame)->codec) { + if (patchers) { + switch_set_flag((*frame)->codec, SWITCH_CODEC_FLAG_VIDEO_PATCHING); + } else { + switch_clear_flag((*frame)->codec, SWITCH_CODEC_FLAG_VIDEO_PATCHING); + } + } if (status == SWITCH_STATUS_SUCCESS) { switch_core_session_video_read_callback(session, *frame); diff --git a/src/switch_core_video.c b/src/switch_core_video.c index 4a32027fed..e4cb5f1ad3 100644 --- a/src/switch_core_video.c +++ b/src/switch_core_video.c @@ -2031,7 +2031,7 @@ static inline uint32_t switch_img_fmt2fourcc(switch_img_fmt_t fmt) } #endif -SWITCH_DECLARE(switch_status_t) switch_img_to_raw(switch_image_t *src, void *dest, switch_size_t size, switch_img_fmt_t fmt) +SWITCH_DECLARE(switch_status_t) switch_img_to_raw(switch_image_t *src, void *dest, int stride, switch_img_fmt_t fmt) { #ifdef SWITCH_HAVE_YUV uint32_t fourcc; @@ -2050,7 +2050,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_to_raw(switch_image_t *src, void *des ret = ConvertFromI420(src->planes[0], src->stride[0], src->planes[1], src->stride[1], src->planes[2], src->stride[2], - dest, size, + dest, stride, src->d_w, src->d_h, fourcc); diff --git a/src/switch_event.c b/src/switch_event.c index 58d5b81735..4ebe0f37d5 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -2752,6 +2752,7 @@ static void unsub_all_switch_event_channel(void) free(head); } + switch_safe_free(hi); switch_thread_rwlock_unlock(event_channel_manager.rwlock); } diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 47b49725a4..d35cb9662f 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1759,9 +1759,18 @@ static void *SWITCH_THREAD_FUNC early_thread_run(switch_thread_t *thread, void * switch_codec_implementation_t read_impl = { 0 }; for (i = 0; i < MAX_PEERS && i < state->ttl; i++) { - if (switch_core_session_read_lock(state->originate_status[i].peer_session) == SWITCH_STATUS_SUCCESS) { - originate_status[i].peer_session = state->originate_status[i].peer_session; - originate_status[i].peer_channel = switch_core_session_get_channel(state->originate_status[i].peer_session); + switch_core_session_t *session = state->originate_status[i].peer_session; + switch_channel_t *channel = NULL; + + if (session) channel = switch_core_session_get_channel(session); + + if (!session || !channel || !switch_channel_up(channel)) { + continue; + } + + if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) { + originate_status[i].peer_session = session; + originate_status[i].peer_channel = channel; } } diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index 4a1d6da68c..5da20b25ae 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -2111,6 +2111,259 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_silence(switch_core_session_ return status; } +SWITCH_DECLARE(switch_status_t) switch_ivr_detect_audio(switch_core_session_t *session, uint32_t thresh, + uint32_t audio_hits, uint32_t timeout_ms, const char *file) +{ + uint32_t score, count = 0, j = 0; + double energy = 0; + switch_channel_t *channel = switch_core_session_get_channel(session); + int divisor = 0; + uint32_t channels; + switch_frame_t *read_frame; + switch_status_t status = SWITCH_STATUS_FALSE; + int16_t *data; + uint32_t hits = 0; + switch_codec_t raw_codec = { 0 }; + int16_t *abuf = NULL; + switch_frame_t write_frame = { 0 }; + switch_file_handle_t fh = { 0 }; + int32_t sample_count = 0; + switch_codec_implementation_t read_impl = { 0 }; + switch_core_session_get_read_impl(session, &read_impl); + + if (timeout_ms) { + sample_count = (read_impl.actual_samples_per_second / 1000) * timeout_ms; + } + + if (file) { + if (switch_core_file_open(&fh, + file, + read_impl.number_of_channels, + read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { + switch_core_session_reset(session, SWITCH_TRUE, SWITCH_FALSE); + return SWITCH_STATUS_NOTFOUND; + } + switch_zmalloc(abuf, SWITCH_RECOMMENDED_BUFFER_SIZE); + write_frame.data = abuf; + write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE; + } + + + if (switch_core_codec_init(&raw_codec, + "L16", + NULL, + NULL, + read_impl.actual_samples_per_second, + read_impl.microseconds_per_packet / 1000, + 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + + status = SWITCH_STATUS_FALSE; + goto end; + } + + write_frame.codec = &raw_codec; + + divisor = read_impl.actual_samples_per_second / 8000; + channels = read_impl.number_of_channels; + + switch_core_session_set_read_codec(session, &raw_codec); + + while (switch_channel_ready(channel)) { + + status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); + + if (!SWITCH_READ_ACCEPTABLE(status)) { + break; + } + + if (sample_count) { + sample_count -= raw_codec.implementation->samples_per_packet; + if (sample_count <= 0) { + switch_channel_set_variable(channel, "detect_audio_timeout", "true"); + switch_channel_set_variable_printf(channel, "detect_audio_hits", "%d", hits); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "switch_ivr_detect_audio: TIMEOUT %d hits\n", hits); + break; + } + } + + if (abuf) { + switch_size_t olen = raw_codec.implementation->samples_per_packet; + + if (switch_core_file_read(&fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) { + break; + } + + write_frame.samples = (uint32_t) olen; + write_frame.datalen = (uint32_t) (olen * sizeof(int16_t) * fh.channels); + if ((status = switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0)) != SWITCH_STATUS_SUCCESS) { + break; + } + } + + data = (int16_t *) read_frame->data; + + for (energy = 0, j = 0, count = 0; count < read_frame->samples; count++) { + energy += abs(data[j++]); + j += channels; + } + + score = (uint32_t) (energy / (read_frame->samples / divisor)); + + if (score >= thresh) { + hits++; + } else { + hits=0; + } + + if (hits > audio_hits) { + switch_channel_set_variable(channel, "detect_audio_timeout", "false"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "switch_ivr_detect_audio: AUDIO DETECTED\n"); + break; + } + } + + switch_core_session_reset(session, SWITCH_FALSE, SWITCH_TRUE); + switch_core_codec_destroy(&raw_codec); + + end: + + if (abuf) { + + switch_core_file_close(&fh); + free(abuf); + } + + return status; +} + +SWITCH_DECLARE(switch_status_t) switch_ivr_detect_silence(switch_core_session_t *session, uint32_t thresh, + uint32_t silence_hits, uint32_t timeout_ms, const char *file) +{ + uint32_t score, count = 0, j = 0; + double energy = 0; + switch_channel_t *channel = switch_core_session_get_channel(session); + int divisor = 0; + uint32_t channels; + switch_frame_t *read_frame; + switch_status_t status = SWITCH_STATUS_FALSE; + int16_t *data; + uint32_t hits = 0; + switch_codec_t raw_codec = { 0 }; + int16_t *abuf = NULL; + switch_frame_t write_frame = { 0 }; + switch_file_handle_t fh = { 0 }; + int32_t sample_count = 0; + switch_codec_implementation_t read_impl = { 0 }; + switch_core_session_get_read_impl(session, &read_impl); + + + if (timeout_ms) { + sample_count = (read_impl.actual_samples_per_second / 1000) * timeout_ms; + } + + if (file) { + if (switch_core_file_open(&fh, + file, + read_impl.number_of_channels, + read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { + switch_core_session_reset(session, SWITCH_TRUE, SWITCH_FALSE); + return SWITCH_STATUS_NOTFOUND; + } + switch_zmalloc(abuf, SWITCH_RECOMMENDED_BUFFER_SIZE); + write_frame.data = abuf; + write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE; + } + + + if (switch_core_codec_init(&raw_codec, + "L16", + NULL, + NULL, + read_impl.actual_samples_per_second, + read_impl.microseconds_per_packet / 1000, + 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + + status = SWITCH_STATUS_FALSE; + goto end; + } + + write_frame.codec = &raw_codec; + + divisor = read_impl.actual_samples_per_second / 8000; + channels = read_impl.number_of_channels; + + switch_core_session_set_read_codec(session, &raw_codec); + + while (switch_channel_ready(channel)) { + + status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); + + if (!SWITCH_READ_ACCEPTABLE(status)) { + break; + } + + if (sample_count) { + sample_count -= raw_codec.implementation->samples_per_packet; + if (sample_count <= 0) { + switch_channel_set_variable(channel, "detect_silence_timeout", "true"); + switch_channel_set_variable_printf(channel, "detect_silence_hits", "%d", hits); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "switch_ivr_detect_silence: TIMEOUT %d hits\n", hits); + break; + } + } + + if (abuf) { + switch_size_t olen = raw_codec.implementation->samples_per_packet; + + if (switch_core_file_read(&fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) { + break; + } + + write_frame.samples = (uint32_t) olen; + write_frame.datalen = (uint32_t) (olen * sizeof(int16_t) * fh.channels); + if ((status = switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0)) != SWITCH_STATUS_SUCCESS) { + break; + } + } + + data = (int16_t *) read_frame->data; + + for (energy = 0, j = 0, count = 0; count < read_frame->samples; count++) { + energy += abs(data[j++]); + j += channels; + } + + score = (uint32_t) (energy / (read_frame->samples / divisor)); + + if (score <= thresh) { + hits++; + } else { + hits=0; + } + + if (hits > silence_hits) { + switch_channel_set_variable(channel, "detect_silence_timeout", "false"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "switch_ivr_detect_silence: SILENCE DETECTED\n"); + break; + } + } + + switch_core_session_reset(session, SWITCH_FALSE, SWITCH_TRUE); + switch_core_codec_destroy(&raw_codec); + + end: + + if (abuf) { + + switch_core_file_close(&fh); + free(abuf); + } + + return status; +} + SWITCH_DECLARE(switch_status_t) switch_ivr_read(switch_core_session_t *session, uint32_t min_digits, uint32_t max_digits, diff --git a/src/switch_jitterbuffer.c b/src/switch_jitterbuffer.c index 4bfca88821..b396dd4611 100644 --- a/src/switch_jitterbuffer.c +++ b/src/switch_jitterbuffer.c @@ -902,10 +902,10 @@ SWITCH_DECLARE(switch_status_t) switch_jb_peek_frame(switch_jb_t *jb, uint32_t t frame->seq = ntohs(node->packet.header.seq); frame->timestamp = ntohl(node->packet.header.ts); frame->m = node->packet.header.m; - frame->datalen = node->len; + frame->datalen = node->len - 12; - if (frame->data && frame->buflen > node->len) { - memcpy(frame->data, node->packet.body, node->len); + if (frame->data && frame->buflen > node->len - 12) { + memcpy(frame->data, node->packet.body, node->len - 12); } return SWITCH_STATUS_SUCCESS; } @@ -1039,7 +1039,7 @@ SWITCH_DECLARE(uint32_t) switch_jb_pop_nack(switch_jb_t *jb) top: - for (hi = switch_core_hash_first(jb->missing_seq_hash); hi; hi = switch_core_hash_next(&hi)) { + for (hi = switch_core_hash_first_iter(jb->missing_seq_hash, hi); hi; hi = switch_core_hash_next(&hi)) { uint16_t seq; //const char *token; switch_time_t then = 0; @@ -1076,6 +1076,8 @@ SWITCH_DECLARE(uint32_t) switch_jb_pop_nack(switch_jb_t *jb) } } + switch_safe_free(hi); + if (least && switch_core_inthash_delete(jb->missing_seq_hash, (uint32_t)htons(least))) { jb_debug(jb, 3, "Found NACKABLE seq %u\n", least); nack = (uint32_t) htons(least); diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 0649be6c2d..a2c4ebdc3e 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -452,6 +452,7 @@ struct switch_rtp { uint8_t has_ice; uint8_t punts; uint8_t clean; + uint32_t last_max_vb_frames; #ifdef ENABLE_ZRTP zrtp_session_t *zrtp_session; zrtp_profile_t *zrtp_profile; @@ -2069,17 +2070,8 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) rtcp_generate_report_block(rtp_session, rtcp_report_block); rtp_session->rtcp_send_msg.header.length = htons((uint16_t)(rtcp_bytes / 4) - 1); - - if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) { - //if (rtp_session->remote_ssrc == 0) { - // rtp_session->remote_ssrc = rtp_session->stats.rtcp.peer_ssrc; - //} - - //if (rtp_session->remote_ssrc == 0) { - // rtp_session->remote_ssrc = ntohl(rtp_session->last_rtp_hdr.ssrc); - //} - + if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) { if (rtp_session->pli_count) { switch_rtcp_ext_hdr_t *ext_hdr; @@ -2094,7 +2086,8 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) ext_hdr->send_ssrc = htonl(rtp_session->ssrc); ext_hdr->recv_ssrc = htonl(rtp_session->remote_ssrc); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP PLI\n"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP PLI %u %u\n", + rtp_session->ssrc, rtp_session->remote_ssrc); ext_hdr->length = htons((uint8_t)(sizeof(switch_rtcp_ext_hdr_t) / 4) - 1); rtcp_bytes += sizeof(switch_rtcp_ext_hdr_t); @@ -2927,7 +2920,6 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_ switch_mutex_lock(rtp_session->write_mutex); rtp_session->remote_addr = remote_addr; - switch_cp_addr(rtp_session->rtp_from_addr, rtp_session->remote_addr); if (change_adv_addr) { rtp_session->remote_host_str = switch_core_strdup(rtp_session->pool, host); @@ -3734,7 +3726,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_ssrc(switch_rtp_t *rtp_session, u SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_ssrc(switch_rtp_t *rtp_session, uint32_t ssrc) { rtp_session->remote_ssrc = ssrc; - + rtp_session->flags[SWITCH_RTP_FLAG_DETECT_SSRC] = 0; return SWITCH_STATUS_SUCCESS; } @@ -4005,6 +3997,7 @@ SWITCH_DECLARE(switch_rtp_t *) switch_rtp_new(const char *rx_host, rtp_session->rx_host = switch_core_strdup(rtp_session->pool, rx_host); rtp_session->rx_port = rx_port; switch_rtp_set_flag(rtp_session, SWITCH_RTP_FLAG_FLUSH); + switch_rtp_set_flag(rtp_session, SWITCH_RTP_FLAG_DETECT_SSRC); } else { switch_rtp_release_port(rx_host, rx_port); } @@ -4106,9 +4099,15 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_video_buffer_size(switch_rtp_t *r } if (!max_frames) { - max_frames = 50; + max_frames = rtp_session->last_max_vb_frames; + } + + if (!max_frames || frames >= max_frames) { + max_frames = frames + 8; } + rtp_session->last_max_vb_frames = max_frames; + if (!rtp_session->vb) { switch_jb_create(&rtp_session->vb, SJB_VIDEO, frames, max_frames, rtp_session->pool); switch_jb_set_session(rtp_session->vb, rtp_session->session); @@ -5251,6 +5250,17 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t rtp_session->missed_count = 0; switch_cp_addr(rtp_session->rtp_from_addr, rtp_session->from_addr); rtp_session->last_rtp_hdr = rtp_session->recv_msg.header; + + + if (rtp_session->flags[SWITCH_RTP_FLAG_DETECT_SSRC]) { + //if (rtp_session->remote_ssrc != rtp_session->stats.rtcp.peer_ssrc && rtp_session->stats.rtcp.peer_ssrc) { + // rtp_session->remote_ssrc = rtp_session->stats.rtcp.peer_ssrc; + //} + + if (rtp_session->remote_ssrc != rtp_session->last_rtp_hdr.ssrc && rtp_session->last_rtp_hdr.ssrc) { + rtp_session->remote_ssrc = ntohl(rtp_session->last_rtp_hdr.ssrc); + } + } } } @@ -5802,7 +5812,7 @@ static void handle_nack(switch_rtp_t *rtp_session, uint32_t nack) send_msg->header.pt, ntohl(send_msg->header.ts), ntohs(send_msg->header.seq), send_msg->header.m); } - //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "RE----SEND %u\n", ntohs(send_msg->header.seq)); + //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "RE----SEND %u\n", ntohs(send_msg->header.seq)); switch_rtp_write_raw(rtp_session, (void *) send_msg, &bytes, SWITCH_FALSE); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Cannot send NACK for seq %u\n", ntohs(seq)); @@ -5826,7 +5836,7 @@ static void handle_nack(switch_rtp_t *rtp_session, uint32_t nack) send_msg->header.pt, ntohl(send_msg->header.ts), ntohs(send_msg->header.seq), send_msg->header.m); } - //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "RE----SEND %u\n", ntohs(send_msg->header.seq)); + //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "RE----SEND %u\n", ntohs(send_msg->header.seq)); switch_rtp_write_raw(rtp_session, (void *) &send_msg, &bytes, SWITCH_FALSE); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Cannot send NACK for seq %u\n", ntohs(seq) + i); diff --git a/src/switch_vpx.c b/src/switch_vpx.c index ebfe51da97..9ad4ed8da5 100644 --- a/src/switch_vpx.c +++ b/src/switch_vpx.c @@ -42,6 +42,12 @@ // #define DEBUG_VP9 +#ifdef DEBUG_VP9 +#define VPX_SWITCH_LOG_LEVEL SWITCH_LOG_ERROR +#else +#define VPX_SWITCH_LOG_LEVEL SWITCH_LOG_DEBUG1 +#endif + #define SLICE_SIZE SWITCH_DEFAULT_VIDEO_SIZE #define KEY_FRAME_MIN_FREQ 250000 @@ -291,6 +297,7 @@ struct vpx_context { int got_start_frame; uint32_t last_received_timestamp; switch_bool_t last_received_complete_picture; + uint16_t last_received_seq; int need_key_frame; int need_encoder_reset; int need_decoder_reset; @@ -299,6 +306,7 @@ struct vpx_context { switch_memory_pool_t *pool; switch_buffer_t *pbuffer; switch_time_t start_time; + switch_image_t *patch_img; }; typedef struct vpx_context vpx_context_t; @@ -332,6 +340,7 @@ static switch_status_t init_decoder(switch_codec_t *codec) context->last_ts = 0; context->last_received_timestamp = 0; context->last_received_complete_picture = 0; + context->last_received_seq = 0; context->decoder_init = 1; context->got_key_frame = 0; context->no_key_frame = 0; @@ -405,7 +414,7 @@ static switch_status_t init_encoder(switch_codec_t *codec) config->g_lag_in_frames = 0; config->kf_max_dist = 360;//2000; threads = cpus / 4; - if (threads < 0) threads = 1; + if (threads < 1) threads = 1; config->g_threads = threads; if (context->is_vp9) { @@ -965,7 +974,8 @@ static switch_status_t buffer_vp9_packets(vpx_context_t *context, switch_frame_t int len = 0; #ifdef DEBUG_VP9 - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%02x %02x %02x %02x m=%d len=%4d " + switch_log_printf(SWITCH_CHANNEL_LOG, frame->m ? SWITCH_LOG_ERROR : SWITCH_LOG_INFO, + "[%02x %02x %02x %02x] m=%d len=%4d seq=%d ts=%u ssrc=%u " "have_pid=%d " "have_p_layer=%d " "have_layer_ind=%d " @@ -974,7 +984,7 @@ static switch_status_t buffer_vp9_packets(vpx_context_t *context, switch_frame_t "end=%d " "have_ss=%d " "zero=%d\n", - *data, *(data+1), *(data+2), *(data+3), frame->m, frame->datalen, + *data, *(data+1), *(data+2), *(data+3), frame->m, frame->datalen, frame->seq, frame->timestamp, frame->ssrc, desc->have_pid, desc->have_p_layer, desc->have_layer_ind, @@ -1000,7 +1010,7 @@ static switch_status_t buffer_vp9_packets(vpx_context_t *context, switch_frame_t vp9++; #ifdef DEBUG_VP9 - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "have pid: %d start=%d end=%d\n", pid, desc->start, desc->end); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "have pid: %d start=%d end=%d\n", pid, desc->start, desc->end); #endif } @@ -1071,12 +1081,7 @@ static switch_status_t buffer_vp9_packets(vpx_context_t *context, switch_frame_t goto end; } - if (switch_buffer_inuse(context->vpx_packet_buffer)) { // middle packet - if (desc->start) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "got invalid vp9 packet, packet loss? resetting buffer\n"); - switch_buffer_zero(context->vpx_packet_buffer); - } - } else { // start packet + if (!switch_buffer_inuse(context->vpx_packet_buffer)) { // start packet if (!desc->start) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got invalid vp9 packet, packet loss? waiting for a start packet\n"); goto end; @@ -1089,7 +1094,7 @@ static switch_status_t buffer_vp9_packets(vpx_context_t *context, switch_frame_t end: #ifdef DEBUG_VP9 - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "buffered %d bytes, buffer size: %" SWITCH_SIZE_T_FMT "\n", len, switch_buffer_inuse(context->vpx_packet_buffer)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "buffered %d bytes, buffer size: %" SWITCH_SIZE_T_FMT "\n", len, switch_buffer_inuse(context->vpx_packet_buffer)); #endif return SWITCH_STATUS_SUCCESS; @@ -1114,11 +1119,16 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t * is_keyframe = IS_VP9_KEY_FRAME(*(unsigned char *)frame->data); is_start = IS_VP9_START_PKT(*(unsigned char *)frame->data); -#ifdef DEBUG_VP9 if (is_keyframe) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "================Got a key frame!!!!========================\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, VPX_SWITCH_LOG_LEVEL, "================Got a key frame!!!!========================\n"); } -#endif + + if (context->last_received_seq && context->last_received_seq + 1 != frame->seq) { + switch_log_printf(SWITCH_CHANNEL_LOG, VPX_SWITCH_LOG_LEVEL, "Packet loss detected last=%d got=%d lost=%d\n", context->last_received_seq, frame->seq, frame->seq - context->last_received_seq); + if (is_keyframe && context->vpx_packet_buffer) switch_buffer_zero(context->vpx_packet_buffer); + } + + context->last_received_seq = frame->seq; } else { // vp8 is_start = (*(unsigned char *)frame->data & 0x10); is_keyframe = IS_VP8_KEY_FRAME((uint8_t *)frame->data); @@ -1213,8 +1223,15 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t * err = vpx_codec_decode(decoder, data, (unsigned int)len, NULL, 0); if (err != VPX_CODEC_OK) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Error decoding %" SWITCH_SIZE_T_FMT " bytes, [%d:%s:%s]\n", + switch_log_printf(SWITCH_CHANNEL_LOG, VPX_SWITCH_LOG_LEVEL, "Error decoding %" SWITCH_SIZE_T_FMT " bytes, [%d:%s:%s]\n", len, err, vpx_codec_error(decoder), vpx_codec_error_detail(decoder)); + + + if (err == VPX_CODEC_MEM_ERROR) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "VPX MEM ERROR, resetting decoder!\n"); + context->need_decoder_reset = 1; + } + switch_goto_status(SWITCH_STATUS_RESTART, end); } @@ -1264,6 +1281,12 @@ end: switch_set_flag(frame, SFF_WAIT_KEY_FRAME); } + if (frame->img && (codec->flags & SWITCH_CODEC_FLAG_VIDEO_PATCHING)) { + switch_img_free(&context->patch_img); + switch_img_copy(frame->img, &context->patch_img); + frame->img = context->patch_img; + } + return status; } @@ -1326,6 +1349,9 @@ static switch_status_t switch_vpx_destroy(switch_codec_t *codec) vpx_context_t *context = (vpx_context_t *)codec->private_info; if (context) { + + switch_img_free(&context->patch_img); + if ((codec->flags & SWITCH_CODEC_FLAG_ENCODE)) { vpx_codec_destroy(&context->encoder); }