diff --git a/Makefile.am b/Makefile.am
index 8d35068c35..37a01d27fb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -349,7 +349,7 @@ scripts/fsxs: scripts/fsxs.in
-e "s|@INCLUDES\@|-I$(prefix)/include|" \
-e "s|@SOLINK\@|$(SOLINK)|" \
-e "s|@LDFLAGS\@|-L$(prefix)/lib|" \
- -e "s|@LIBS\@|`./libs/apr/apr-1-config --libs` `./libs/apr-util/apu-1-config --libs`|" \
+ -e "s|@LIBS\@||" \
$(top_srcdir)/scripts/fsxs.in > scripts/fsxs
##
diff --git a/build/modules.conf.in b/build/modules.conf.in
index 2be000f6b3..84a9e9a74d 100644
--- a/build/modules.conf.in
+++ b/build/modules.conf.in
@@ -78,6 +78,7 @@ event_handlers/mod_cdr_sqlite
#event_handlers/mod_cdr_pg_csv
#event_handlers/mod_radius_cdr
#event_handlers/mod_erlang_event
+#event_handlers/mod_snmp
formats/mod_native_file
formats/mod_sndfile
#formats/mod_shout
diff --git a/conf/autoload_configs/easyroute.conf.xml b/conf/autoload_configs/easyroute.conf.xml
index 7cd490942f..350a50989b 100644
--- a/conf/autoload_configs/easyroute.conf.xml
+++ b/conf/autoload_configs/easyroute.conf.xml
@@ -11,6 +11,9 @@
+
+
+
+
diff --git a/conf/lang/en/dir/sounds.xml b/conf/lang/en/dir/sounds.xml
index 2bdc1492ec..15ecec304a 100644
--- a/conf/lang/en/dir/sounds.xml
+++ b/conf/lang/en/dir/sounds.xml
@@ -16,7 +16,7 @@
-
+
@@ -24,7 +24,7 @@
-
+
diff --git a/freeswitch-sounds-en-us-callie.spec b/freeswitch-sounds-en-us-callie.spec
new file mode 100644
index 0000000000..c4764570f5
--- /dev/null
+++ b/freeswitch-sounds-en-us-callie.spec
@@ -0,0 +1,339 @@
+##############################################################################
+# Copyright and license
+##############################################################################
+#
+# Spec file for package freeswitch-sounds-en-us-callie (version 1.0.12-8)
+#
+# Copyright (c) 2009 Patrick Laimbock
+# Some fixes and additions (c) 2011 Michal Bielicki
+# This file and all modifications and additions to the pristine
+# package are under the same license as the package itself.
+#
+
+##############################################################################
+# Determine distribution
+##############################################################################
+
+%define is_rhel5 %(test -f /etc/redhat-release && egrep -q 'release 5' /etc/redhat-release && echo 1 || echo 0)
+
+##############################################################################
+# Set variables
+##############################################################################
+
+%define version 1.0.14
+%define release 1
+
+%define fsname freeswitch
+# you could add a version number to be more strict
+
+%define prefix /opt/freeswitch
+%define _prefix %{prefix}
+
+##############################################################################
+# General
+##############################################################################
+
+Summary: FreeSWITCH en-us Callie prompts
+Name: freeswitch-sounds-en-us-callie
+Version: %{version}
+Release: %{release}%{?dist}
+License: MPL
+Group: Applications/Communications
+Packager: Patrick Laimbock
+URL: http://www.freeswitch.org
+Source0:http://files.freeswitch.org/%{name}-48000-%{version}.tar.gz
+BuildArch: noarch
+BuildRequires: sox
+Requires: freeswitch
+Requires: freeswitch-sounds-en-us-callie-48000
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+%description
+FreeSWITCH 48kHz en-us Callie prompts plus, during the installation,
+it will also install locally generated 8KHz, 16KHz and 32KHz prompts
+
+%package -n freeswitch-sounds-en-us-callie-8000
+Summary: FreeSWITCH 8kHz en-us Callie prompts
+Group: Applications/Communications
+BuildArch: noarch
+Requires: %{fsname}
+
+%description -n freeswitch-sounds-en-us-callie-8000
+FreeSWITCH 8kHz en-us Callie prompts
+
+%package -n freeswitch-sounds-en-us-callie-16000
+Summary: FreeSWITCH 16kHz en-us Callie prompts
+Group: Applications/Communications
+BuildArch: noarch
+Requires: %{fsname}
+
+%description -n freeswitch-sounds-en-us-callie-16000
+FreeSWITCH 16kHz en-us Callie prompts
+
+%package -n freeswitch-sounds-en-us-callie-32000
+Summary: FreeSWITCH 32kHz en-us Callie prompts
+Group: Applications/Communications
+BuildArch: noarch
+Requires: %{fsname}
+
+%description -n freeswitch-sounds-en-us-callie-32000
+FreeSWITCH 32kHz en-us Callie prompts
+
+%package -n freeswitch-sounds-en-us-callie-48000
+Summary: FreeSWITCH 48kHz en-us Callie prompts
+Group: Applications/Communications
+BuildArch: noarch
+Requires: %{fsname}
+
+%description -n freeswitch-sounds-en-us-callie-48000
+FreeSWITCH 48kHz en-us Callie prompts
+
+%package -n freeswitch-sounds-en-us-callie-all
+Summary: FreeSWITCH en-us Callie prompts
+Group: Applications/Communications
+BuildArch: noarch
+Requires: %{fsname}
+Requires: freeswitch-sounds-en-us-callie-8000 = %{version}
+Requires: freeswitch-sounds-en-us-callie-16000 = %{version}
+Requires: freeswitch-sounds-en-us-callie-32000 = %{version}
+Requires: freeswitch-sounds-en-us-callie-48000 = %{version}
+
+%description -n freeswitch-sounds-en-us-callie-all
+FreeSWITCH Callie prompts package that pulls in the 8KHz, 16KHz,
+32KHz and 48KHz RPMs
+
+##############################################################################
+# Prep
+##############################################################################
+
+%prep
+%setup -b0 -q -n en
+mkdir -p ./usr/callie
+# create buildsounds-callie.sh script in working dir
+echo '#!/bin/bash
+
+sounds_location=$1
+for rate in 32000 16000 8000
+do
+ for i in ascii base256 conference currency digits directory ivr misc phonetic-ascii time voicemail zrtp
+ do
+ mkdir -p $sounds_location/$i/$rate
+ for f in `find $sounds_location/$i/48000 -name \*.wav`
+ do
+ echo "generating" $sounds_location/$i/$rate/`basename $f`
+ sox $f -r $rate $sounds_location/$i/$rate/`basename $f`
+ done
+ done
+done' > ./us/callie/buildsounds-callie.sh
+%{__chmod} 0750 ./us/callie/buildsounds-callie.sh
+
+##############################################################################
+# Build
+##############################################################################
+
+%build
+# nothing to do here
+
+##############################################################################
+# Install
+##############################################################################
+
+%install
+[ "%{buildroot}" != '/' ] && rm -rf %{buildroot}
+
+# create the sounds directories
+%{__install} -d -m 0750 %{buildroot}%{_prefix}/sounds/en/us/callie
+
+pushd us/callie
+# first install the 48KHz sounds
+%{__cp} -prv ./* %{buildroot}%{_prefix}/sounds/en/us/callie
+# now resample the 48KHz ones to 8KHz, 16KHz and 32KHz
+./buildsounds-callie.sh %{buildroot}%{_prefix}/sounds/en/us/callie
+popd
+
+##############################################################################
+# Clean
+##############################################################################
+
+%clean
+[ "%{buildroot}" != '/' ] && rm -rf %{buildroot}
+
+##############################################################################
+# Post
+##############################################################################
+
+%post
+# generate the 8KHz, 16KHz and 32KHz prompts from the 48KHz ones
+cd %{_prefix}/sounds/en/us/callie
+./buildsounds-callie.sh %{_prefix}/sounds/en/us/callie
+
+##############################################################################
+# Postun
+##############################################################################
+
+%postun
+# you could check if there are sound files in 8000/ or
+# 16000/ or 32000/ and remove them *only* if the files
+# do not belong to an rpm
+
+##############################################################################
+# Files
+##############################################################################
+
+%files
+%defattr(-,root,root)
+%attr(0750,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/buildsounds-callie.sh
+
+%files -n freeswitch-sounds-en-us-callie-8000
+%defattr(-,root,root,-)
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/ascii/8000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/base256/8000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/conference/8000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/currency/8000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/digits/8000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/directory/8000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/ivr/8000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/misc/8000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/phonetic-ascii/8000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/time/8000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/voicemail/8000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/zrtp/8000
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/ascii/8000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/base256/8000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/conference/8000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/currency/8000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/digits/8000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/directory/8000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/ivr/8000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/misc/8000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/phonetic-ascii/8000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/time/8000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/voicemail/8000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/zrtp/8000/*.wav
+
+%files -n freeswitch-sounds-en-us-callie-16000
+%defattr(-,root,root,-)
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/ascii/16000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/base256/16000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/conference/16000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/currency/16000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/digits/16000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/directory/16000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/ivr/16000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/misc/16000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/phonetic-ascii/16000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/time/16000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/voicemail/16000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/zrtp/16000
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/ascii/16000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/base256/16000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/conference/16000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/currency/16000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/digits/16000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/directory/16000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/ivr/16000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/misc/16000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/phonetic-ascii/16000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/time/16000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/voicemail/16000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/zrtp/16000/*.wav
+
+%files -n freeswitch-sounds-en-us-callie-32000
+%defattr(-,root,root,-)
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/ascii/32000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/base256/32000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/conference/32000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/currency/32000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/digits/32000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/directory/32000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/ivr/32000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/misc/32000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/phonetic-ascii/32000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/time/32000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/voicemail/32000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/zrtp/32000
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/ascii/32000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/base256/32000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/conference/32000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/currency/32000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/digits/32000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/directory/32000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/ivr/32000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/misc/32000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/phonetic-ascii/32000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/time/32000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/voicemail/32000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/zrtp/32000/*.wav
+
+%files -n freeswitch-sounds-en-us-callie-48000
+%defattr(-,root,root,-)
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/ascii/48000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/base256/48000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/conference/48000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/currency/48000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/digits/48000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/directory/48000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/ivr/48000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/misc/48000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/phonetic-ascii/48000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/time/48000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/voicemail/48000
+%attr(0750,freeswitch,daemon) %dir %{_prefix}/sounds/en/us/callie/zrtp/48000
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/ascii/48000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/base256/48000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/conference/48000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/currency/48000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/digits/48000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/directory/48000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/ivr/48000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/misc/48000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/phonetic-ascii/48000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/time/48000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/voicemail/48000/*.wav
+%attr(0640,freeswitch,daemon) %{_prefix}/sounds/en/us/callie/zrtp/48000/*.wav
+
+%files -n freeswitch-sounds-en-us-callie-all
+
+##############################################################################
+# Changelog
+##############################################################################
+
+%changelog
+* Tue Jan 18 2011 Michal Bielicki - 1.0.14-1
+- bump up version
+- include script into freeswitch core
+- include specfile into freeswitch core
+- runtime does not require sox, only building
+
+* Thu Dec 17 2009 Patrick Laimbock - 1.0.12-8
+- update perms and user/group to sync with the old situation
+
+* Wed Dec 16 2009 Patrick Laimbock - 1.0.12-7
+- make main package require freeswitch-sounds-en-us-callie-48000 and
+- generate the 8KHz, 16KHz and 32KHz sounds from there
+- add license to spec file
+
+* Wed Dec 16 2009 Patrick Laimbock - 1.0.12-5
+- put 48KHz in a separate package and let the main package Require 48KHz
+- and then use the script to generate the 8KHz, 16KHz and 32KHz sounds
+
+* Wed Dec 16 2009 Patrick Laimbock - 1.0.12-4
+- add freeswitch-sounds-en-us-callie-all package that pulls in the 8KHz,
+- 16KHz, 32KHz and 48KHz RPM packages
+
+* Tue Dec 15 2009 Patrick Laimbock - 1.0.12-3
+- override subpackage name with -n so it no longer builds an empty main RPM
+- rework spec file
+- add sox as a requirement
+- run buildsounds-callie.sh in post to generate 8KHz, 16KHz and 32KHz prompts
+
+* Tue Dec 15 2009 Patrick Laimbock - 1.0.12-2
+- can't override Name in subpackage so put all versions in RPM subpackages
+- with an empty main RPM package
+
+* Tue Dec 15 2009 Patrick Laimbock - 1.0.12-1
+- create spec file with the following requirement:
+- source only contains the 48KHz sound prompts
+- during build the 48KHz sound prompts are resampled to 8KHz, 16KHz and 32KHz
+- the 8KHz, 16KHz, 32KHz and 48KHz sound prompts are packaged separately
+
diff --git a/freeswitch.spec b/freeswitch.spec
index 66db65c698..7fb9f80d8e 100644
--- a/freeswitch.spec
+++ b/freeswitch.spec
@@ -53,7 +53,7 @@ Vendor: http://www.freeswitch.org/
# Source files and where to get them
#
######################################################################################################################
-Source0: http://files.freeswitch.org/%{name}-%{version}.tar.bz2
+Source0: http://files.freeswitch.org/%{name}-%{version}.tar.bz2
Source1: http://files.freeswitch.org/downloads/libs/celt-0.7.1.tar.gz
Source2: http://files.freeswitch.org/downloads/libs/flite-1.3.99-latest.tar.gz
Source3: http://files.freeswitch.org/downloads/libs/lame-3.97.tar.gz
@@ -89,8 +89,13 @@ BuildRequires: libtool >= 1.5.17
BuildRequires: ncurses-devel
BuildRequires: openssl-devel
BuildRequires: perl
+%if 0%{?fedora_version} >= 8
+BuildRequires: perl-ExtUtils-Embed
+%endif
BuildRequires: pkgconfig
+%if %{_vendor} == redhat && 0%{?fedora} <= 6
BuildRequires: termcap
+%endif
BuildRequires: unixODBC-devel
BuildRequires: gdbm-devel
BuildRequires: db4-devel
@@ -893,7 +898,7 @@ fi
%files python
%defattr(-,freeswitch,daemon)
%{prefix}/mod/mod_python*.so*
-%attr(0644, root, bin) /usr/lib/python2.4/site-packages/freeswitch.py*
+%attr(0644, root, bin) /usr/lib/python*/site-packages/freeswitch.py*
%dir %attr(0750, freeswitch, daemon) %{prefix}/conf/autoload_configs
%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/python.conf.xml
@@ -951,6 +956,8 @@ fi
#
######################################################################################################################
%changelog
+* Tue Jan 18 2011 - michal.bielicki@seventhsignal.de
+- Fedora adjustments
* Fri Oct 15 2010 - michal.bielicki@seventhsignal.de
- added mod_curl
* Sat Oct 09 2010 - michal.bielicki@seventhsignal.de
diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am
index 2ab5c29e18..96f1c9a10f 100644
--- a/libs/freetdm/Makefile.am
+++ b/libs/freetdm/Makefile.am
@@ -94,6 +94,7 @@ library_include_HEADERS = \
$(SRC)/include/ftdm_declare.h \
$(SRC)/include/ftdm_threadmutex.h \
$(SRC)/include/ftdm_os.h \
+ $(SRC)/include/ftdm_call_utils.h \
$(SRC)/include/ftdm_dso.h
lib_LTLIBRARIES = libfreetdm.la
diff --git a/libs/freetdm/TODO b/libs/freetdm/TODO
index 6b8ef8f826..6b4cf71f5f 100644
--- a/libs/freetdm/TODO
+++ b/libs/freetdm/TODO
@@ -11,3 +11,12 @@
cannot be shown to end users, we already provide extensive logging for problem
troubleshooting.
+- Implement threaded IO.
+ Currently IO modules only work on-demand, where the user (ie, FreeSWITCH) drives the read/write
+ of media. If the user stops reading, some functions are not possible
+ (DTMF detection or Hangup tone detection). It would be useful to implement a FreeTDM mode
+ where the media is driven by a group of threads that are always reading (and possibly writing)
+ then when the user does ftdm_channel_read(), the media would be read from the buffers filled
+ by the media thread and not from the underlying IO device, this gives a chance to FreeTDM to
+ still perform hangup detection or other media services even if the application is not reading.
+
diff --git a/libs/freetdm/docs/io_modules.txt b/libs/freetdm/docs/io_modules.txt
new file mode 100644
index 0000000000..a164bbb249
--- /dev/null
+++ b/libs/freetdm/docs/io_modules.txt
@@ -0,0 +1,13 @@
+Last Updated: Jan 19, 2011
+
+== BACKGROUND ==
+
+The IO module provides an abstracted IO interface to FreeTDM.
+
+== SHUTDOWN ==
+Upon global shutdown, for each channel FIO_CLOSE_FUNCTION will be called.
+When FIO_CLOSE_FUNCTION is called, all waiters on this channel shall be signalled.
+If FIO_WAIT_FUNCTION is called on a function that has already been closed, this function shall return FTDM_TIMEOUT without blocking.
+FIO_CHANNEL_DESTROY will eventually be called, and IO module is responsible for clearing all internal states and free allocated memory upon channel destroy.
+
+
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index 6bfa37576c..b5f9fab93d 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -404,39 +404,39 @@ static __inline__ void ftdm_std_free(void *pool, void *ptr)
free(ptr);
}
-static void ftdm_set_echocancel_call_begin(ftdm_channel_t *chan)
+FT_DECLARE(void) ftdm_set_echocancel_call_begin(ftdm_channel_t *chan)
{
ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan);
if (ftdm_channel_test_feature(chan, FTDM_CHANNEL_FEATURE_HWEC)) {
if (ftdm_channel_test_feature(chan, FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE)) {
+ /* If the ec is disabled on idle, we need to enable it unless is a digital call */
if (caller_data->bearer_capability != FTDM_BEARER_CAP_64K_UNRESTRICTED) {
+ ftdm_log_chan(chan, FTDM_LOG_DEBUG, "Enabling ec for call in channel state %s\n", ftdm_channel_state2str(chan->state));
ftdm_channel_command(chan, FTDM_COMMAND_ENABLE_ECHOCANCEL, NULL);
}
} else {
+ /* If the ec is enabled on idle, we do nothing unless is a digital call that needs it disabled */
if (caller_data->bearer_capability == FTDM_BEARER_CAP_64K_UNRESTRICTED) {
+ ftdm_log_chan(chan, FTDM_LOG_DEBUG, "Disabling ec for digital call in channel state %s\n", ftdm_channel_state2str(chan->state));
ftdm_channel_command(chan, FTDM_COMMAND_DISABLE_ECHOCANCEL, NULL);
}
}
}
}
-static void ftdm_set_echocancel_call_end(ftdm_channel_t *chan)
+FT_DECLARE(void) ftdm_set_echocancel_call_end(ftdm_channel_t *chan)
{
- ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan);
if (ftdm_channel_test_feature(chan, FTDM_CHANNEL_FEATURE_HWEC)) {
if (ftdm_channel_test_feature(chan, FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE)) {
- if (caller_data->bearer_capability != FTDM_BEARER_CAP_64K_UNRESTRICTED) {
- ftdm_channel_command(chan, FTDM_COMMAND_DISABLE_ECHOCANCEL, NULL);
- }
+ ftdm_log_chan(chan, FTDM_LOG_DEBUG, "Disabling ec on call end in channel state %s\n", ftdm_channel_state2str(chan->state));
+ ftdm_channel_command(chan, FTDM_COMMAND_DISABLE_ECHOCANCEL, NULL);
} else {
- if (caller_data->bearer_capability == FTDM_BEARER_CAP_64K_UNRESTRICTED) {
- ftdm_channel_command(chan, FTDM_COMMAND_ENABLE_ECHOCANCEL, NULL);
- }
+ ftdm_log_chan(chan, FTDM_LOG_DEBUG, "Enabling ec back on call end in channel state %s\n", ftdm_channel_state2str(chan->state));
+ ftdm_channel_command(chan, FTDM_COMMAND_ENABLE_ECHOCANCEL, NULL);
}
}
}
-
FT_DECLARE_DATA ftdm_memory_handler_t g_ftdm_mem_handler =
{
/*.pool =*/ NULL,
@@ -2417,8 +2417,6 @@ static ftdm_status_t _ftdm_channel_call_place_nl(const char *file, const char *f
ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "null channel");
ftdm_assert_return(ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND), FTDM_FAIL, "Call place, but outbound flag not set\n");
- ftdm_set_echocancel_call_begin(ftdmchan);
-
if (!ftdmchan->span->outgoing_call) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "outgoing_call method not implemented in this span!\n");
status = FTDM_ENOSYS;
@@ -5548,20 +5546,46 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
}
break;
+ case FTDM_SIGEVENT_PROGRESS_MEDIA:
+ {
+ /* test signaling module compliance */
+ if (sigmsg->channel->state != FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
+ ftdm_log_chan(sigmsg->channel, FTDM_LOG_WARNING, "FTDM_SIGEVENT_PROGRESS_MEDIA sent in state %s\n", ftdm_channel_state2str(sigmsg->channel->state));
+ }
+ }
+ break;
+
+ case FTDM_SIGEVENT_UP:
+ {
+ /* test signaling module compliance */
+ if (sigmsg->channel->state != FTDM_CHANNEL_STATE_UP) {
+ ftdm_log_chan(sigmsg->channel, FTDM_LOG_WARNING, "FTDM_SIGEVENT_UP sent in state %s\n", ftdm_channel_state2str(sigmsg->channel->state));
+ }
+ }
+ break;
+
case FTDM_SIGEVENT_STOP:
- if (!ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_CALL_STARTED)) {
- /* this happens for FXS devices which blindly send SIGEVENT_STOP, we should fix it there ... */
- ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Ignoring SIGEVENT_STOP since user never knew about a call in this channel\n");
- goto done;
- }
- if (ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_USER_HANGUP)) {
- ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Ignoring SIGEVENT_STOP since user already requested hangup\n");
- goto done;
- }
- if (sigmsg->channel->state == FTDM_CHANNEL_STATE_TERMINATING) {
- ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Scheduling safety hangup timer\n");
- /* if the user does not move us to hangup in 2 seconds, we will do it ourselves */
- ftdm_sched_timer(globals.timingsched, "safety-hangup", FORCE_HANGUP_TIMER, execute_safety_hangup, sigmsg->channel, &sigmsg->channel->hangup_timer);
+ {
+ /* TODO: we could test for compliance here and check the state is FTDM_CHANNEL_STATE_TERMINATING
+ * but several modules need to be updated first */
+
+ /* if the call was never started, do not send SIGEVENT_STOP
+ this happens for FXS devices in ftmod_analog which blindly send SIGEVENT_STOP, we should fix it there ... */
+ if (!ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_CALL_STARTED)) {
+ ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Ignoring SIGEVENT_STOP since user never knew about a call in this channel\n");
+ goto done;
+ }
+
+ if (ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_USER_HANGUP)) {
+ ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Ignoring SIGEVENT_STOP since user already requested hangup\n");
+ goto done;
+ }
+
+ if (sigmsg->channel->state == FTDM_CHANNEL_STATE_TERMINATING) {
+ ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Scheduling safety hangup timer\n");
+ /* if the user does not move us to hangup in 2 seconds, we will do it ourselves */
+ ftdm_sched_timer(globals.timingsched, "safety-hangup", FORCE_HANGUP_TIMER, execute_safety_hangup, sigmsg->channel, &sigmsg->channel->hangup_timer);
+ }
}
break;
diff --git a/libs/freetdm/src/ftdm_state.c b/libs/freetdm/src/ftdm_state.c
index 574d85845b..de62c0f0e7 100644
--- a/libs/freetdm/src/ftdm_state.c
+++ b/libs/freetdm/src/ftdm_state.c
@@ -70,13 +70,13 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_complete_state(const char *file, const c
if (state == FTDM_CHANNEL_STATE_PROGRESS) {
ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
- } else if (state == FTDM_CHANNEL_STATE_UP) {
- ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
- ftdm_set_flag(fchan, FTDM_CHANNEL_MEDIA);
- ftdm_set_flag(fchan, FTDM_CHANNEL_ANSWERED);
} else if (state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
- ftdm_set_flag(fchan, FTDM_CHANNEL_MEDIA);
+ ftdm_test_and_set_media(fchan);
+ } else if (state == FTDM_CHANNEL_STATE_UP) {
+ ftdm_set_flag(fchan, FTDM_CHANNEL_PROGRESS);
+ ftdm_set_flag(fchan, FTDM_CHANNEL_ANSWERED);
+ ftdm_test_and_set_media(fchan);
} else if (state == FTDM_CHANNEL_STATE_DIALING) {
ftdm_sigmsg_t msg;
memset(&msg, 0, sizeof(msg));
diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
index 434417726b..0217a5172a 100644
--- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
+++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
@@ -295,7 +295,7 @@ static ftdm_call_cause_t ftdm_r2_cause_to_ftdm_cause(ftdm_channel_t *fchan, open
case OR2_CAUSE_GLARE:
return FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL;
}
- ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Mapping openr2 cause %d to unspecified\n", cause);
+ ftdm_log_chan(fchan, FTDM_LOG_NOTICE, "Mapping openr2 cause %d to unspecified\n", cause);
return FTDM_CAUSE_NORMAL_UNSPECIFIED;
}
@@ -647,9 +647,6 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
return;
}
- /* mark the channel in use (so no outgoing calls can be placed here) */
- ftdm_channel_use(ftdmchan);
-
memset(ftdmchan->caller_data.dnis.digits, 0, sizeof(ftdmchan->caller_data.collected));
memset(ftdmchan->caller_data.ani.digits, 0, sizeof(ftdmchan->caller_data.collected));
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
index f2afd1cf9c..df528ae9c1 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
@@ -394,8 +394,7 @@ static void *ftdm_sangoma_isdn_dchan_run(ftdm_thread_t *me, void *obj)
default:
ftdm_log_chan_msg(dchan, FTDM_LOG_CRIT, "Unhandled IO event\n");
}
- }
- ftdm_channel_close(&dchan);
+ }
return NULL;
}
@@ -677,6 +676,9 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm
/*OUTBOUND...so we were told by the line of this so noifiy the user*/
sigev.event_id = FTDM_SIGEVENT_PROCEED;
ftdm_span_send_signal(ftdmchan->span, &sigev);
+ if (sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY)) {
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ }
} else {
if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
/* By default, we do not send a progress indicator in the proceed */
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
index 58fcc07040..80dc73f0fa 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
@@ -112,6 +112,11 @@ typedef enum {
SNGISDN_OPT_FALSE = 2,
} sngisdn_opt_t;
+typedef enum {
+ SNGISDN_EARLY_MEDIA_ON_PROCEED = (1 << 0),
+ SNGISDN_EARLY_MEDIA_ON_PROGRESS = (1 << 1),
+ SNGISDN_EARLY_MEDIA_ON_ALERT= (1 << 2),
+} sngisdn_early_media_opt_t;
typedef enum {
SNGISDN_AVAIL_DOWN = 1,
@@ -188,7 +193,8 @@ typedef struct sngisdn_span_data {
uint8_t span_id;
uint8_t tei;
uint8_t min_digits;
- uint8_t trace_flags; /* TODO: change to flags, so we can use ftdm_test_flag etc.. */
+ uint8_t trace_flags; /* TODO change to bit map of sngisdn_tracetype_t */
+ uint8_t early_media_flags; /* bit map of ftdm_sngisdn_early_media_opt_t */
uint8_t overlap_dial;
uint8_t setup_arb;
uint8_t facility_ie_decode;
@@ -196,10 +202,10 @@ typedef struct sngisdn_span_data {
int8_t facility_timeout;
uint8_t num_local_numbers;
uint8_t ignore_cause_value;
- uint8_t raw_trace_q931;
- uint8_t raw_trace_q921;
+ uint8_t raw_trace_q931; /* TODO: combine with trace_flags */
+ uint8_t raw_trace_q921; /* TODO: combine with trace_flags */
uint8_t timer_t3;
- uint8_t restart_opt;
+ uint8_t restart_opt;
char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS];
ftdm_sched_t *sched;
ftdm_queue_t *event_queue;
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c
index aad68e15d1..bd5b13bfec 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c
@@ -192,6 +192,24 @@ static ftdm_status_t parse_signalling(const char* signalling, ftdm_span_t *span)
return FTDM_SUCCESS;
}
+static ftdm_status_t parse_early_media(const char* opt, ftdm_span_t *span)
+{
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
+ if (!strcasecmp(opt, "on-proceed")) {
+ signal_data->early_media_flags |= SNGISDN_EARLY_MEDIA_ON_PROCEED;
+ } else if (!strcasecmp(opt, "on-progress")) {
+ signal_data->early_media_flags |= SNGISDN_EARLY_MEDIA_ON_PROGRESS;
+ } else if (!strcasecmp(opt, "on-alert")) {
+ signal_data->early_media_flags |= SNGISDN_EARLY_MEDIA_ON_ALERT;
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "Unsupported early-media option %s\n", opt);
+ return FTDM_FAIL;
+ }
+ ftdm_log(FTDM_LOG_DEBUG, "Early media opt:0x%x\n", signal_data->early_media_flags);
+ return FTDM_SUCCESS;
+}
+
+
static ftdm_status_t set_switchtype_defaults(ftdm_span_t *span)
{
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
@@ -249,6 +267,7 @@ static ftdm_status_t set_switchtype_defaults(ftdm_span_t *span)
return FTDM_SUCCESS;
}
+
ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span)
{
unsigned paramindex;
@@ -351,10 +370,14 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
parse_yesno(var, val, &signal_data->raw_trace_q931);
} else if (!strcasecmp(var, "q921-raw-trace")) {
parse_yesno(var, val, &signal_data->raw_trace_q921);
+ } else if (!strcasecmp(var, "early-media-override")) {
+ if (parse_early_media(val, span) != FTDM_SUCCESS) {
+ return FTDM_FAIL;
+ }
} else {
ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var);
}
- }
+ } /* for (paramindex = 0; ftdm_parameters[paramindex].var; paramindex++) */
if (signal_data->switchtype == SNGISDN_SWITCH_INVALID) {
ftdm_log(FTDM_LOG_ERROR, "%s: switchtype not specified", span->name);
@@ -366,10 +389,11 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_
}
if (span->default_caller_data.bearer_layer1 == FTDM_INVALID_INT_PARM) {
- if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN) {
- span->default_caller_data.bearer_layer1 = IN_UIL1_G711ULAW;
- } else {
+ if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN ||
+ signal_data->switchtype == SNGISDN_SWITCH_QSIG) {
span->default_caller_data.bearer_layer1 = IN_UIL1_G711ALAW;
+ } else {
+ span->default_caller_data.bearer_layer1 = IN_UIL1_G711ULAW;
}
}
return FTDM_SUCCESS;
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
index 7b7c748c7a..0b52011d42 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
@@ -167,12 +167,12 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
char retrieved_str[255];
ret_val = sng_isdn_retrieve_facility_caller_name(conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len, retrieved_str);
- /*
- return values for "sng_isdn_retrieve_facility_information_following":
- If there will be no information following, or fails to decode IE, returns -1
- If there will be no information following, but current FACILITY IE contains a caller name, returns 0
- If there will be information following, returns 1
- */
+ /*
+ return values for "sng_isdn_retrieve_facility_information_following":
+ If there will be no information following, or fails to decode IE, returns -1
+ If there will be no information following, but current FACILITY IE contains a caller name, returns 0
+ If there will be information following, returns 1
+ */
if (ret_val == 1) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Expecting Caller name in FACILITY\n");
@@ -346,6 +346,7 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info;
ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
CnStEvnt *cnStEvnt = &sngisdn_event->event.cnStEvnt;
@@ -384,7 +385,7 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
case FTDM_CHANNEL_STATE_DIALING:
case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
- case FTDM_CHANNEL_STATE_RINGING:
+ case FTDM_CHANNEL_STATE_RINGING:
if (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Early media available\n");
sngisdn_set_flag(sngisdn_info, FLAG_MEDIA_READY);
@@ -393,16 +394,34 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
}
switch (evntType) {
case MI_CALLPROC:
+ if (!sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY) &&
+ (signal_data->early_media_flags & SNGISDN_EARLY_MEDIA_ON_PROCEED)) {
+
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Early media override on proceed\n");
+ sngisdn_set_flag(sngisdn_info, FLAG_MEDIA_READY);
+ }
if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROCEED);
}
break;
case MI_ALERTING:
+ if (!sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY) &&
+ (signal_data->early_media_flags & SNGISDN_EARLY_MEDIA_ON_ALERT)) {
+
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Early media override on alert\n");
+ sngisdn_set_flag(sngisdn_info, FLAG_MEDIA_READY);
+ }
if (ftdmchan->state == FTDM_CHANNEL_STATE_PROCEED) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RINGING);
}
break;
case MI_PROGRESS:
+ if (!sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY) &&
+ (signal_data->early_media_flags & SNGISDN_EARLY_MEDIA_ON_PROGRESS)) {
+
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Early media override on progress\n");
+ sngisdn_set_flag(sngisdn_info, FLAG_MEDIA_READY);
+ }
if (sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY)) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
} else if (ftdmchan->state != FTDM_CHANNEL_STATE_PROGRESS) {
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
index 9c1b7baf79..64147b7d75 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
@@ -881,18 +881,27 @@ ftdm_status_t set_bear_cap_ie(ftdm_channel_t *ftdmchan, BearCap *bearCap)
bearCap->usrInfoLyr1Prot.pres = PRSNT_NODEF;
bearCap->usrInfoLyr1Prot.val = sngisdn_get_usrInfoLyr1Prot_from_user(ftdmchan->caller_data.bearer_layer1);
- if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN &&
- bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ULAW) {
-
- /* We are bridging a call from T1 */
- bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ALAW;
-
- } else if (bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ALAW) {
-
- /* We are bridging a call from E1 */
- bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ULAW;
+ switch (signal_data->switchtype) {
+ case SNGISDN_SWITCH_NI2:
+ case SNGISDN_SWITCH_4ESS:
+ case SNGISDN_SWITCH_5ESS:
+ case SNGISDN_SWITCH_DMS100:
+ case SNGISDN_SWITCH_INSNET:
+ if (bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ALAW) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Overriding bearer cap to u-law\n");
+ bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ULAW;
+ }
+ break;
+ case SNGISDN_SWITCH_EUROISDN:
+ case SNGISDN_SWITCH_QSIG:
+ if (bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ULAW) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Overriding bearer cap to a-law\n");
+ bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ALAW;
+ }
+ break;
}
+
bearCap->lyr1Ident.pres = PRSNT_NODEF;
bearCap->lyr1Ident.val = IN_L1_IDENT;
}
diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
index 1f2ad84d72..e08fd61f3b 100644
--- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
+++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
@@ -230,6 +230,8 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start
ftdm_channel_t *chan;
ftdm_socket_t sockfd = FTDM_INVALID_SOCKET;
const char *dtmf = "none";
+ const char *hwec_str = "none";
+ const char *hwec_idle = "none";
if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == FTDM_TRUNK_T1 && x == 24) {
#ifdef LIBSANGOMA_VERSION
sockfd = __tdmv_api_open_span_chan(spanno, x);
@@ -237,7 +239,11 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start
ftdm_log(FTDM_LOG_ERROR, "span %d channel %d cannot be configured as smg_prid_nfas, you need to compile freetdm with newer libsangoma\n", spanno, x);
#endif
} else {
+#ifdef LIBSANGOMA_VERSION
+ sockfd = __tdmv_api_open_span_chan(spanno, x);
+#else
sockfd = tdmv_api_open_span_chan(spanno, x);
+#endif
}
if (sockfd == FTDM_INVALID_SOCKET) {
@@ -271,6 +277,8 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start
|| type == FTDM_CHAN_TYPE_B) {
int err;
+ hwec_str = "unavailable";
+ hwec_idle = "enabled";
dtmf = "software";
err = sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
@@ -289,6 +297,7 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start
err = sangoma_tdm_get_hw_ec(chan->sockfd, &tdm_api);
if (err > 0) {
+ hwec_str = "available";
ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_HWEC);
}
@@ -296,6 +305,7 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start
err = sangoma_tdm_get_hwec_persist_status(chan->sockfd, &tdm_api);
if (err == 0) {
ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE);
+ hwec_idle = "disabled";
}
#else
if (span->trunk_type == FTDM_TRUNK_BRI || span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
@@ -365,7 +375,8 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start
ftdm_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
}
configured++;
- ftdm_log_chan(chan, FTDM_LOG_INFO, "Configured wanpipe device fd:%d DTMF: %s\n", sockfd, dtmf);
+ ftdm_log_chan(chan, FTDM_LOG_INFO, "Configured wanpipe device FD: %d, DTMF: %s, HWEC: %s, HWEC_IDLE: %s\n",
+ sockfd, dtmf, hwec_str, hwec_idle);
} else {
ftdm_log(FTDM_LOG_ERROR, "ftdm_span_add_channel failed for wanpipe span %d channel %d\n", spanno, x);
@@ -653,6 +664,8 @@ static FIO_COMMAND_FUNCTION(wanpipe_command)
}
}
break;
+ case FTDM_COMMAND_DISABLE_ECHOTRAIN: { err = 0; }
+ break;
case FTDM_COMMAND_ENABLE_DTMF_DETECT:
{
#ifdef WP_API_FEATURE_DTMF_EVENTS
@@ -1257,20 +1270,18 @@ static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fc
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type) {
case WP_API_EVENT_LINK_STATUS:
{
-#if 0
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
- *event_id = FTDM_OOB_ALARM_CLEAR;
+ /* *event_id = FTDM_OOB_ALARM_CLEAR; */
+ ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe link connected event\n");
break;
default:
- *event_id = FTDM_OOB_ALARM_TRAP;
+ /* *event_id = FTDM_OOB_ALARM_TRAP; */
+ ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe link disconnected event\n");
break;
};
-#else
/* The WP_API_EVENT_ALARM event should be used to clear alarms */
- ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe link status event\n", ftdm_oob_event2str(*event_id));
*event_id = FTDM_OOB_NOOP;
-#endif
}
break;
diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h
index 2666a26df2..aed40541a3 100644
--- a/libs/freetdm/src/include/freetdm.h
+++ b/libs/freetdm/src/include/freetdm.h
@@ -82,8 +82,12 @@ typedef enum {
FTDM_CAUSE_UNALLOCATED = 1,
FTDM_CAUSE_NO_ROUTE_TRANSIT_NET = 2,
FTDM_CAUSE_NO_ROUTE_DESTINATION = 3,
+ FTDM_CAUSE_SEND_SPECIAL_INFO_TONE = 4,
+ FTDM_CAUSE_MISDIALED_TRUNK_PREFIX = 5,
FTDM_CAUSE_CHANNEL_UNACCEPTABLE = 6,
FTDM_CAUSE_CALL_AWARDED_DELIVERED = 7,
+ FTDM_CAUSE_PREEMPTION = 8,
+ FTDM_CAUSE_PREEMPTION_CIRCUIT_RESERVED = 9,
FTDM_CAUSE_NORMAL_CLEARING = 16,
FTDM_CAUSE_USER_BUSY = 17,
FTDM_CAUSE_NO_USER_RESPONSE = 18,
@@ -100,23 +104,38 @@ typedef enum {
FTDM_CAUSE_NORMAL_UNSPECIFIED = 31,
FTDM_CAUSE_NORMAL_CIRCUIT_CONGESTION = 34,
FTDM_CAUSE_NETWORK_OUT_OF_ORDER = 38,
+ FTDM_CAUSE_PERMANENT_FRAME_MODE_CONNECTION_OOS = 39,
+ FTDM_CAUSE_PERMANENT_FRAME_MODE_OPERATIONAL = 40,
FTDM_CAUSE_NORMAL_TEMPORARY_FAILURE = 41,
FTDM_CAUSE_SWITCH_CONGESTION = 42,
FTDM_CAUSE_ACCESS_INFO_DISCARDED = 43,
FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL = 44,
FTDM_CAUSE_PRE_EMPTED = 45,
+ FTDM_CAUSE_PRECEDENCE_CALL_BLOCKED = 46,
+ FTDM_CAUSE_RESOURCE_UNAVAILABLE_UNSPECIFIED = 47,
+ FTDM_CAUSE_QOS_NOT_AVAILABLE = 49,
FTDM_CAUSE_FACILITY_NOT_SUBSCRIBED = 50,
- FTDM_CAUSE_OUTGOING_CALL_BARRED = 52,
- FTDM_CAUSE_INCOMING_CALL_BARRED = 54,
+ FTDM_CAUSE_OUTGOING_CALL_BARRED = 53,
+ FTDM_CAUSE_INCOMING_CALL_BARRED = 55,
FTDM_CAUSE_BEARERCAPABILITY_NOTAUTH = 57,
FTDM_CAUSE_BEARERCAPABILITY_NOTAVAIL = 58,
+ FTDM_CAUSE_INCONSISTENCY_IN_INFO = 62,
FTDM_CAUSE_SERVICE_UNAVAILABLE = 63,
FTDM_CAUSE_BEARERCAPABILITY_NOTIMPL = 65,
FTDM_CAUSE_CHAN_NOT_IMPLEMENTED = 66,
FTDM_CAUSE_FACILITY_NOT_IMPLEMENTED = 69,
+ FTDM_CAUSE_ONLY_DIGITAL_INFO_BC_AVAIL = 70,
FTDM_CAUSE_SERVICE_NOT_IMPLEMENTED = 79,
FTDM_CAUSE_INVALID_CALL_REFERENCE = 81,
+ FTDM_CAUSE_IDENTIFIED_CHAN_NOT_EXIST = 82,
+ FTDM_CAUSE_SUSPENDED_CALL_EXISTS_BUT_CALL_ID_DOES_NOT = 83,
+ FTDM_CAUSE_CALL_ID_IN_USE = 84,
+ FTDM_CAUSE_NO_CALL_SUSPENDED = 85,
+ FTDM_CAUSE_CALL_WITH_CALL_ID_CLEARED = 86,
+ FTDM_CAUSE_USER_NOT_CUG = 87,
FTDM_CAUSE_INCOMPATIBLE_DESTINATION = 88,
+ FTDM_CAUSE_NON_EXISTENT_CUG = 90,
+ FTDM_CAUSE_INVALID_TRANSIT_NETWORK_SELECTION = 91,
FTDM_CAUSE_INVALID_MSG_UNSPECIFIED = 95,
FTDM_CAUSE_MANDATORY_IE_MISSING = 96,
FTDM_CAUSE_MESSAGE_TYPE_NONEXIST = 97,
@@ -126,6 +145,7 @@ typedef enum {
FTDM_CAUSE_WRONG_CALL_STATE = 101,
FTDM_CAUSE_RECOVERY_ON_TIMER_EXPIRE = 102,
FTDM_CAUSE_MANDATORY_IE_LENGTH_ERROR = 103,
+ FTDM_CAUSE_MSG_WITH_UNRECOGNIZED_PARAM_DISCARDED = 110,
FTDM_CAUSE_PROTOCOL_ERROR = 111,
FTDM_CAUSE_INTERWORKING = 127,
FTDM_CAUSE_SUCCESS = 142,
@@ -171,7 +191,7 @@ FTDM_STR2ENUM_P(ftdm_str2ftdm_chan_type, ftdm_chan_type2str, ftdm_chan_type_t)
#define FTDM_IS_VOICE_CHANNEL(fchan) ((fchan)->type != FTDM_CHAN_TYPE_DQ921 && (fchan)->type != FTDM_CHAN_TYPE_DQ931)
/*! \brief Test if a channel is a D-channel */
-#define FTDM_IS_DCHAN(ftdm_chan) ((fchan)->type == FTDM_CHAN_TYPE_DQ921 || (fchan)->type == FTDM_CHAN_TYPE_DQ931)
+#define FTDM_IS_DCHAN(fchan) ((fchan)->type == FTDM_CHAN_TYPE_DQ921 || (fchan)->type == FTDM_CHAN_TYPE_DQ931)
/*! \brief Test if a channel is digital channel */
#define FTDM_IS_DIGITAL_CHANNEL(fchan) ((fchan)->span->trunk_type == FTDM_TRUNK_E1 || \
@@ -410,7 +430,7 @@ typedef enum {
} ftdm_signal_event_t;
#define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROCEED", "RINGING", "PROGRESS", \
"PROGRESS_MEDIA", "ALARM_TRAP", "ALARM_CLEAR", \
- "COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "COLLISION", "FACILITY", \
+ "COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "FACILITY", \
"TRACE", "TRACE_RAW", "INDICATION_COMPLETED", "DIALING", "INVALID"
/*! \brief Move from string to ftdm_signal_event_t and viceversa */
FTDM_STR2ENUM_P(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t)
@@ -574,84 +594,84 @@ typedef struct ftdm_iterator ftdm_iterator_t;
/*! \brief Channel commands that can be executed through ftdm_channel_command() */
typedef enum {
- FTDM_COMMAND_NOOP,
- FTDM_COMMAND_SET_INTERVAL,
- FTDM_COMMAND_GET_INTERVAL,
- FTDM_COMMAND_SET_CODEC,
- FTDM_COMMAND_GET_CODEC,
- FTDM_COMMAND_SET_NATIVE_CODEC,
- FTDM_COMMAND_GET_NATIVE_CODEC,
- FTDM_COMMAND_ENABLE_DTMF_DETECT,
- FTDM_COMMAND_DISABLE_DTMF_DETECT,
- FTDM_COMMAND_SEND_DTMF,
- FTDM_COMMAND_SET_DTMF_ON_PERIOD,
- FTDM_COMMAND_GET_DTMF_ON_PERIOD,
- FTDM_COMMAND_SET_DTMF_OFF_PERIOD,
- FTDM_COMMAND_GET_DTMF_OFF_PERIOD,
- FTDM_COMMAND_GENERATE_RING_ON,
- FTDM_COMMAND_GENERATE_RING_OFF,
- FTDM_COMMAND_OFFHOOK,
- FTDM_COMMAND_ONHOOK,
- FTDM_COMMAND_FLASH,
- FTDM_COMMAND_WINK,
- FTDM_COMMAND_ENABLE_PROGRESS_DETECT,
- FTDM_COMMAND_DISABLE_PROGRESS_DETECT,
+ FTDM_COMMAND_NOOP = 0,
+ FTDM_COMMAND_SET_INTERVAL = 1,
+ FTDM_COMMAND_GET_INTERVAL = 2,
+ FTDM_COMMAND_SET_CODEC = 3,
+ FTDM_COMMAND_GET_CODEC = 4,
+ FTDM_COMMAND_SET_NATIVE_CODEC = 5,
+ FTDM_COMMAND_GET_NATIVE_CODEC = 6,
+ FTDM_COMMAND_ENABLE_DTMF_DETECT = 7,
+ FTDM_COMMAND_DISABLE_DTMF_DETECT = 8,
+ FTDM_COMMAND_SEND_DTMF = 9,
+ FTDM_COMMAND_SET_DTMF_ON_PERIOD = 10,
+ FTDM_COMMAND_GET_DTMF_ON_PERIOD = 11,
+ FTDM_COMMAND_SET_DTMF_OFF_PERIOD = 12,
+ FTDM_COMMAND_GET_DTMF_OFF_PERIOD = 13,
+ FTDM_COMMAND_GENERATE_RING_ON = 14,
+ FTDM_COMMAND_GENERATE_RING_OFF = 15,
+ FTDM_COMMAND_OFFHOOK = 16,
+ FTDM_COMMAND_ONHOOK = 17,
+ FTDM_COMMAND_FLASH = 18,
+ FTDM_COMMAND_WINK = 19,
+ FTDM_COMMAND_ENABLE_PROGRESS_DETECT = 20,
+ FTDM_COMMAND_DISABLE_PROGRESS_DETECT = 21,
/*!< Start tracing input and output from channel to the given file */
- FTDM_COMMAND_TRACE_INPUT,
- FTDM_COMMAND_TRACE_OUTPUT,
+ FTDM_COMMAND_TRACE_INPUT = 22,
+ FTDM_COMMAND_TRACE_OUTPUT = 23,
/*!< Stop both Input and Output trace, closing the files */
- FTDM_COMMAND_TRACE_END_ALL,
+ FTDM_COMMAND_TRACE_END_ALL = 24,
/*!< Enable DTMF debugging */
- FTDM_COMMAND_ENABLE_DEBUG_DTMF,
+ FTDM_COMMAND_ENABLE_DEBUG_DTMF = 25,
/*!< Disable DTMF debugging (if not disabled explicitly, it is disabled automatically when calls hangup) */
- FTDM_COMMAND_DISABLE_DEBUG_DTMF,
+ FTDM_COMMAND_DISABLE_DEBUG_DTMF = 26,
/*!< Start dumping all input to a circular buffer. The size of the circular buffer can be specified, default used otherwise */
- FTDM_COMMAND_ENABLE_INPUT_DUMP,
+ FTDM_COMMAND_ENABLE_INPUT_DUMP = 27,
/*!< Stop dumping all input to a circular buffer. */
- FTDM_COMMAND_DISABLE_INPUT_DUMP,
+ FTDM_COMMAND_DISABLE_INPUT_DUMP = 28,
/*!< Start dumping all output to a circular buffer. The size of the circular buffer can be specified, default used otherwise */
- FTDM_COMMAND_ENABLE_OUTPUT_DUMP,
+ FTDM_COMMAND_ENABLE_OUTPUT_DUMP = 29,
/*!< Stop dumping all output to a circular buffer. */
- FTDM_COMMAND_DISABLE_OUTPUT_DUMP,
+ FTDM_COMMAND_DISABLE_OUTPUT_DUMP = 30,
/*!< Dump the current input circular buffer to the specified FILE* structure */
- FTDM_COMMAND_DUMP_INPUT,
+ FTDM_COMMAND_DUMP_INPUT = 31,
/*!< Dump the current output circular buffer to the specified FILE* structure */
- FTDM_COMMAND_DUMP_OUTPUT,
+ FTDM_COMMAND_DUMP_OUTPUT = 32,
- FTDM_COMMAND_ENABLE_CALLERID_DETECT,
- FTDM_COMMAND_DISABLE_CALLERID_DETECT,
- FTDM_COMMAND_ENABLE_ECHOCANCEL,
- FTDM_COMMAND_DISABLE_ECHOCANCEL,
- FTDM_COMMAND_ENABLE_ECHOTRAIN,
- FTDM_COMMAND_DISABLE_ECHOTRAIN,
- FTDM_COMMAND_SET_CAS_BITS,
- FTDM_COMMAND_GET_CAS_BITS,
- FTDM_COMMAND_SET_RX_GAIN,
- FTDM_COMMAND_GET_RX_GAIN,
- FTDM_COMMAND_SET_TX_GAIN,
- FTDM_COMMAND_GET_TX_GAIN,
- FTDM_COMMAND_FLUSH_TX_BUFFERS,
- FTDM_COMMAND_FLUSH_RX_BUFFERS,
- FTDM_COMMAND_FLUSH_BUFFERS,
- FTDM_COMMAND_FLUSH_IOSTATS,
- FTDM_COMMAND_SET_PRE_BUFFER_SIZE,
- FTDM_COMMAND_SET_LINK_STATUS,
- FTDM_COMMAND_GET_LINK_STATUS,
- FTDM_COMMAND_ENABLE_LOOP,
- FTDM_COMMAND_DISABLE_LOOP,
- FTDM_COMMAND_SET_RX_QUEUE_SIZE,
- FTDM_COMMAND_SET_TX_QUEUE_SIZE,
- FTDM_COMMAND_SET_POLARITY,
+ FTDM_COMMAND_ENABLE_CALLERID_DETECT = 33,
+ FTDM_COMMAND_DISABLE_CALLERID_DETECT = 34,
+ FTDM_COMMAND_ENABLE_ECHOCANCEL = 35,
+ FTDM_COMMAND_DISABLE_ECHOCANCEL = 36,
+ FTDM_COMMAND_ENABLE_ECHOTRAIN = 37,
+ FTDM_COMMAND_DISABLE_ECHOTRAIN = 38,
+ FTDM_COMMAND_SET_CAS_BITS = 39,
+ FTDM_COMMAND_GET_CAS_BITS = 40,
+ FTDM_COMMAND_SET_RX_GAIN = 41,
+ FTDM_COMMAND_GET_RX_GAIN = 42,
+ FTDM_COMMAND_SET_TX_GAIN = 43,
+ FTDM_COMMAND_GET_TX_GAIN = 44,
+ FTDM_COMMAND_FLUSH_TX_BUFFERS = 45,
+ FTDM_COMMAND_FLUSH_RX_BUFFERS = 46,
+ FTDM_COMMAND_FLUSH_BUFFERS = 47,
+ FTDM_COMMAND_FLUSH_IOSTATS = 48,
+ FTDM_COMMAND_SET_PRE_BUFFER_SIZE = 49,
+ FTDM_COMMAND_SET_LINK_STATUS = 50,
+ FTDM_COMMAND_GET_LINK_STATUS = 51,
+ FTDM_COMMAND_ENABLE_LOOP = 52,
+ FTDM_COMMAND_DISABLE_LOOP = 53,
+ FTDM_COMMAND_SET_RX_QUEUE_SIZE = 54,
+ FTDM_COMMAND_SET_TX_QUEUE_SIZE = 55,
+ FTDM_COMMAND_SET_POLARITY = 56,
FTDM_COMMAND_COUNT,
} ftdm_command_t;
diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h
index 4fd8ec64ea..7cf0934f57 100644
--- a/libs/freetdm/src/include/private/ftdm_core.h
+++ b/libs/freetdm/src/include/private/ftdm_core.h
@@ -132,8 +132,8 @@ extern "C" {
#define ftdm_channel_test_feature(obj, flag) ((obj)->features & flag)
-#define ftdm_channel_set_feature(obj, flag) (obj)->features |= (flag)
-#define ftdm_channel_clear_feature(obj, flag) (obj)->features &= ~(flag)
+#define ftdm_channel_set_feature(obj, flag) (obj)->features = (ftdm_channel_feature_t)((obj)->features | flag)
+#define ftdm_channel_clear_feature(obj, flag) (obj)->features = (ftdm_channel_feature_t)((obj)->features & ( ~(flag) ))
#define ftdm_channel_set_member_locked(obj, _m, _v) ftdm_mutex_lock(obj->mutex); obj->_m = _v; ftdm_mutex_unlock(obj->mutex)
/*!
@@ -622,6 +622,9 @@ FT_DECLARE(ftdm_status_t) ftdm_span_trigger_signals(const ftdm_span_t *span);
/*! \brief clear the tone detector state */
FT_DECLARE(void) ftdm_channel_clear_detected_tones(ftdm_channel_t *ftdmchan);
+/* start/stop echo cancelling at the beginning/end of a call */
+FT_DECLARE(void) ftdm_set_echocancel_call_begin(ftdm_channel_t *chan);
+FT_DECLARE(void) ftdm_set_echocancel_call_end(ftdm_channel_t *chan);
/*!
\brief Assert condition
@@ -677,6 +680,14 @@ FT_DECLARE(void) ftdm_channel_clear_detected_tones(ftdm_channel_t *ftdmchan);
#define ftdm_span_lock(span) ftdm_mutex_lock(span->mutex)
#define ftdm_span_unlock(span) ftdm_mutex_unlock(span->mutex)
+#define ftdm_test_and_set_media(fchan) \
+ do { \
+ if (!ftdm_test_flag((fchan), FTDM_CHANNEL_MEDIA)) { \
+ ftdm_set_flag((fchan), FTDM_CHANNEL_MEDIA); \
+ ftdm_set_echocancel_call_begin((fchan)); \
+ } \
+ } while (0);
+
FT_DECLARE_DATA extern const char *FTDM_LEVEL_NAMES[9];
static __inline__ void ftdm_abort(void)
diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h
index 3bc986d7f6..9e8df1f5f2 100644
--- a/libs/freetdm/src/include/private/ftdm_types.h
+++ b/libs/freetdm/src/include/private/ftdm_types.h
@@ -227,16 +227,11 @@ typedef enum {
#define FTDM_CHANNEL_OUTBOUND (1ULL << 18)
#define FTDM_CHANNEL_SUSPENDED (1ULL << 19)
#define FTDM_CHANNEL_3WAY (1ULL << 20)
-
-/* this 3 flags are really nonsense used by boost module only, as soon
- * as we deprecate/delete boost module we can get rid of them
- * ==================
- * */
#define FTDM_CHANNEL_PROGRESS (1ULL << 21)
+/*!< There is media on the channel already */
#define FTDM_CHANNEL_MEDIA (1ULL << 22)
+/*!< The channel was answered */
#define FTDM_CHANNEL_ANSWERED (1ULL << 23)
-/* ================== */
-
#define FTDM_CHANNEL_MUTE (1ULL << 24)
#define FTDM_CHANNEL_USE_RX_GAIN (1ULL << 25)
#define FTDM_CHANNEL_USE_TX_GAIN (1ULL << 26)
diff --git a/libs/spandsp/spandsp.pc.in b/libs/spandsp/spandsp.pc.in
index 86a50ff62a..1a91ba04e1 100644
--- a/libs/spandsp/spandsp.pc.in
+++ b/libs/spandsp/spandsp.pc.in
@@ -1,5 +1,5 @@
prefix=@prefix@
-exec_prefix=@exec_prefix@
+exec_prefix=@prefix@
libdir=@libdir@
includedir=@includedir@
diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h
index 2c4de14334..a1a93c6ac8 100644
--- a/src/include/switch_utils.h
+++ b/src/include/switch_utils.h
@@ -192,7 +192,7 @@ static inline char switch_itodtmf(char i)
r = i + 55;
}
- return r;
+ return r + 48;
}
static inline int switch_dtmftoi(char *s)
diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c
index 2d9341a598..e6a47bf1ec 100644
--- a/src/mod/applications/mod_conference/mod_conference.c
+++ b/src/mod/applications/mod_conference/mod_conference.c
@@ -477,6 +477,7 @@ static switch_status_t conference_add_event_member_data(conference_member_t *mem
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Mute-Detect", "%s", switch_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false" );
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-ID", "%u", member->id);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-Type", "%s", switch_test_flag(member, MFLAG_MOD) ? "moderator" : "member");
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Energy-Level", "%d", member->energy_level);
return status;
}
@@ -5596,6 +5597,7 @@ SWITCH_STANDARD_APP(conference_function)
char pin_buf[80] = "";
int pin_retries = 3; /* XXX - this should be configurable - i'm too lazy to do it right now... */
int pin_valid = 0;
+ int be_friendly = 0;
switch_status_t status = SWITCH_STATUS_SUCCESS;
char *supplied_pin_value;
@@ -5630,19 +5632,23 @@ SWITCH_STANDARD_APP(conference_function)
switch_status_t pstatus = SWITCH_STATUS_FALSE;
/* be friendly */
- if (conference->pin_sound) {
- pstatus = conference_local_play_file(conference, session, conference->pin_sound, 20, pin_buf, sizeof(pin_buf));
- } else if (conference->tts_engine && conference->tts_voice) {
- pstatus =
- switch_ivr_speak_text(session, conference->tts_engine, conference->tts_voice, "please enter the conference pin number", NULL);
- } else {
- pstatus = switch_ivr_speak_text(session, "flite", "slt", "please enter the conference pin number", NULL);
+ if (!be_friendly) {
+ if (conference->pin_sound) {
+ pstatus = conference_local_play_file(conference, session, conference->pin_sound, 20, pin_buf, sizeof(pin_buf));
+ } else if (conference->tts_engine && conference->tts_voice) {
+ pstatus =
+ switch_ivr_speak_text(session, conference->tts_engine, conference->tts_voice, "please enter the conference pin number", NULL);
+ } else {
+ pstatus = switch_ivr_speak_text(session, "flite", "slt", "please enter the conference pin number", NULL);
+ }
+
+ if (pstatus != SWITCH_STATUS_SUCCESS && pstatus != SWITCH_STATUS_BREAK) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot ask the user for a pin, ending call");
+ switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ }
}
- if (pstatus != SWITCH_STATUS_SUCCESS && pstatus != SWITCH_STATUS_BREAK) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot ask the user for a pin, ending call");
- switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
- }
+ be_friendly = 1;
/* wait for them if neccessary */
if (strlen(pin_buf) < strlen(dpin)) {
@@ -5659,13 +5665,12 @@ SWITCH_STANDARD_APP(conference_function)
pin_valid = (status == SWITCH_STATUS_SUCCESS && strcmp(pin_buf, dpin) == 0);
if (!pin_valid) {
- /* zero the collected pin */
- memset(pin_buf, 0, sizeof(pin_buf));
-
/* more friendliness */
if (conference->bad_pin_sound) {
conference_local_play_file(conference, session, conference->bad_pin_sound, 20, pin_buf, sizeof(pin_buf));
}
+ /* zero the collected pin */
+ memset(pin_buf, 0, sizeof(pin_buf));
}
pin_retries--;
}
diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c
index 41417255bb..5a3be0328d 100755
--- a/src/mod/applications/mod_dptools/mod_dptools.c
+++ b/src/mod/applications/mod_dptools/mod_dptools.c
@@ -2982,6 +2982,8 @@ static switch_call_cause_t user_outgoing_channel(switch_core_session_t *session,
}
}
}
+ switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_user", user);
+ switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_domain", domain);
if (!dest) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No dial-string available, please check your user directory.\n");
diff --git a/src/mod/applications/mod_easyroute/mod_easyroute.c b/src/mod/applications/mod_easyroute/mod_easyroute.c
index 481df958cf..75b4712f2d 100644
--- a/src/mod/applications/mod_easyroute/mod_easyroute.c
+++ b/src/mod/applications/mod_easyroute/mod_easyroute.c
@@ -65,6 +65,7 @@ static struct {
switch_mutex_t *mutex;
char *custom_query;
switch_odbc_handle_t *master_odbc;
+ int odbc_num_retries;
} globals;
SWITCH_MODULE_LOAD_FUNCTION(mod_easyroute_load);
@@ -120,6 +121,8 @@ static switch_status_t load_config(void)
set_global_default_gateway(val);
} else if (!strcasecmp(var, "custom-query")) {
set_global_custom_query(val);
+ } else if (!strcasecmp(var, "odbc-retries")) {
+ globals.odbc_num_retries = atoi(val);
}
}
}
@@ -143,6 +146,9 @@ static switch_status_t load_config(void)
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opened ODBC Database!\n");
}
+ if (globals.odbc_num_retries) {
+ switch_odbc_set_num_retries(globals.master_odbc, globals.odbc_num_retries);
+ }
if (switch_odbc_handle_connect(globals.master_odbc) != SWITCH_ODBC_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open ODBC Database!\n");
status = SWITCH_STATUS_FALSE;
@@ -205,7 +211,7 @@ static switch_status_t route_lookup(char *dn, easyroute_results_t *results, int
switch_mutex_lock(globals.mutex);
}
/* Do the Query */
- if (switch_odbc_handle_callback_exec(globals.master_odbc, sql, route_callback, &pdata, NULL) == SWITCH_ODBC_SUCCESS) {
+ if (globals.master_odbc && switch_odbc_handle_callback_exec(globals.master_odbc, sql, route_callback, &pdata, NULL) == SWITCH_ODBC_SUCCESS) {
char tmp_profile[129];
char tmp_gateway[129];
@@ -418,7 +424,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_easyroute_load)
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_easyroute_shutdown)
{
- switch_odbc_handle_disconnect(globals.master_odbc);
+ if (globals.master_odbc) {
+ switch_odbc_handle_disconnect(globals.master_odbc);
+ switch_odbc_handle_destroy(&globals.master_odbc);
+ }
switch_safe_free(globals.db_username);
switch_safe_free(globals.db_password);
switch_safe_free(globals.db_dsn);
diff --git a/src/mod/applications/mod_voicemail/mod_voicemail.c b/src/mod/applications/mod_voicemail/mod_voicemail.c
index 1799e5c7dc..76870f75b9 100644
--- a/src/mod/applications/mod_voicemail/mod_voicemail.c
+++ b/src/mod/applications/mod_voicemail/mod_voicemail.c
@@ -311,6 +311,7 @@ static void destroy_profile(const char *profile_name, switch_bool_t block)
/* Static buffer, 2 bytes */
static switch_xml_config_string_options_t config_dtmf = { NULL, 2, "[0-9#\\*]" };
+static switch_xml_config_string_options_t config_dtmf_optional = { NULL, 2, "[0-9#\\*]?" };
static switch_xml_config_string_options_t config_login_keys = { NULL, 16, "[0-9#\\*]*" };
static switch_xml_config_string_options_t config_file_ext = { NULL, 10, NULL };
static switch_xml_config_int_options_t config_int_0_10000 = { SWITCH_TRUE, 0, SWITCH_TRUE, 10000 };
@@ -520,8 +521,8 @@ vm_profile_t *profile_set_config(vm_profile_t *profile)
SWITCH_CONFIG_SET_ITEM(profile->config[i++], "urgent-key", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE,
&profile->urgent_key, "*", &config_dtmf, NULL, NULL);
SWITCH_CONFIG_SET_ITEM(profile->config[i++], "operator-key", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE,
- &profile->operator_key, "", &config_dtmf, NULL, NULL);
- SWITCH_CONFIG_SET_ITEM(profile->config[i++], "vmain-key", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE, &profile->vmain_key, "", &config_dtmf, NULL, NULL);
+ &profile->operator_key, "", &config_dtmf_optional, NULL, NULL);
+ SWITCH_CONFIG_SET_ITEM(profile->config[i++], "vmain-key", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE, &profile->vmain_key, "", &config_dtmf_optional, NULL, NULL);
SWITCH_CONFIG_SET_ITEM(profile->config[i++], "vmain-extension", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE,
&profile->vmain_ext, "", &profile->config_str_pool, NULL, NULL);
SWITCH_CONFIG_SET_ITEM(profile->config[i++], "forward-key", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE,
diff --git a/src/mod/codecs/mod_celt/mod_celt.c b/src/mod/codecs/mod_celt/mod_celt.c
index 37983f3683..8d36b6af12 100644
--- a/src/mod/codecs/mod_celt/mod_celt.c
+++ b/src/mod/codecs/mod_celt/mod_celt.c
@@ -53,8 +53,8 @@ static switch_status_t switch_celt_init(switch_codec_t *codec, switch_codec_flag
return SWITCH_STATUS_FALSE;
}
- context->mode_object = celt_mode_create(codec->implementation->actual_samples_per_second, codec->implementation->samples_per_packet, NULL);
-
+ context->frame_size = codec->implementation->samples_per_packet;
+ context->mode_object = celt_mode_create(codec->implementation->actual_samples_per_second, context->frame_size, NULL);
context->bytes_per_packet = (codec->implementation->bits_per_second * context->frame_size / codec->implementation->actual_samples_per_second + 4) / 8;
/*
@@ -106,15 +106,22 @@ static switch_status_t switch_celt_encode(switch_codec_t *codec,
unsigned int *flag)
{
struct celt_context *context = codec->private_info;
+ int bytes = 0;
if (!context) {
return SWITCH_STATUS_FALSE;
}
- *encoded_data_len = (uint32_t) celt_encode(context->encoder_object, (void *) decoded_data, codec->implementation->samples_per_packet,
- (unsigned char *) encoded_data, context->bytes_per_packet);
+ bytes = (uint32_t) celt_encode(context->encoder_object, (void *) decoded_data, codec->implementation->samples_per_packet,
+ (unsigned char *) encoded_data, context->bytes_per_packet);
- return SWITCH_STATUS_SUCCESS;
+ if (bytes > 0) {
+ *encoded_data_len = (uint32_t) bytes;
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Encoder Error!\n");
+ return SWITCH_STATUS_GENERR;
}
static switch_status_t switch_celt_decode(switch_codec_t *codec,
@@ -152,23 +159,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_celt_load)
SWITCH_ADD_CODEC(codec_interface, "CELT ultra-low delay");
- switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
- 114, /* the IANA code number */
- "CELT", /* the IANA code name */
- NULL, /* default fmtp to send (can be overridden by the init function) */
- 32000, /* samples transferred per second */
- 32000, /* actual samples transferred per second */
- 32000, /* bits transferred per second */
- 10000, /* number of microseconds per frame */
- 320, /* number of samples per frame */
- 640, /* number of bytes per frame decompressed */
- 0, /* number of bytes per frame compressed */
- 1, /* number of channels represented */
- 1, /* number of frames per network packet */
- switch_celt_init, /* function to initialize a codec handle using this implementation */
- switch_celt_encode, /* function to encode raw data into encoded data */
- switch_celt_decode, /* function to decode encoded data into raw data */
- switch_celt_destroy); /* deinitalize a codec handle using this implementation */
ms_per_frame = 2000;
samples_per_frame = 96;
bytes_per_frame = 192;
diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c
index 94fef61181..19125c600b 100644
--- a/src/mod/endpoints/mod_sofia/sofia_presence.c
+++ b/src/mod/endpoints/mod_sofia/sofia_presence.c
@@ -630,6 +630,11 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
char *probe_user = NULL, *probe_euser, *probe_host, *p;
struct dialog_helper dh = { { 0 } };
+ if (strcasecmp(proto, SOFIA_CHAT_PROTO) != 0) {
+ goto done;
+ }
+
+
if (!to || !(probe_user = strdup(to))) {
goto done;
}
@@ -2405,6 +2410,20 @@ void sofia_presence_handle_sip_i_subscribe(int status,
switch_event_fire(&sevent);
}
+ } else if (to_user && (strcasecmp(proto, SOFIA_CHAT_PROTO) != 0)) {
+ if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", proto);
+ switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "long", profile->name);
+ switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
+ switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "to", "%s%s%s@%s", proto, "+", to_user, to_host);
+ switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto-specific-event-name", event);
+ switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
+ switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "event_type", "presence");
+ switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
+ switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
+ switch_event_fire(&sevent);
+
+ }
} else {
if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c
index f644ff772b..631cbdb14b 100644
--- a/src/mod/endpoints/mod_sofia/sofia_reg.c
+++ b/src/mod/endpoints/mod_sofia/sofia_reg.c
@@ -1139,7 +1139,13 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
switch_url_encode(my_contact_str, path_encoded + 20, path_encoded_len - 20);
reg_desc = "Registered(AUTO-NAT-2.0)";
exptime = 30;
- switch_snprintf(contact_str + strlen(contact_str), sizeof(contact_str) - strlen(contact_str), "%s", path_encoded);
+
+ /* place fs_path (the encoded path) inside the <...> of the contact string, if possible */
+ if (contact_str[strlen(contact_str) - 1] == '>') {
+ switch_snprintf(contact_str + strlen(contact_str) - 1, sizeof(contact_str) - strlen(contact_str) + 1, "%s>", path_encoded);
+ } else {
+ switch_snprintf(contact_str + strlen(contact_str), sizeof(contact_str) - strlen(contact_str), "%s", path_encoded);
+ }
free(path_encoded);
} else {
if (*received_data && sofia_test_pflag(profile, PFLAG_RECIEVED_IN_NAT_REG_CONTACT)) {
diff --git a/src/mod/event_handlers/mod_erlang_event/ei_helpers.c b/src/mod/event_handlers/mod_erlang_event/ei_helpers.c
index a99b52074c..db4f7780e0 100644
--- a/src/mod/event_handlers/mod_erlang_event/ei_helpers.c
+++ b/src/mod/event_handlers/mod_erlang_event/ei_helpers.c
@@ -111,6 +111,7 @@ void ei_encode_switch_event_headers(ei_x_buff * ebuf, switch_event_t *event)
for (hp = event->headers; hp; hp = hp->next) {
ei_x_encode_tuple_header(ebuf, 2);
_ei_x_encode_string(ebuf, hp->name);
+ switch_url_decode(hp->value);
_ei_x_encode_string(ebuf, hp->value);
}
diff --git a/src/mod/event_handlers/mod_erlang_event/handle_msg.c b/src/mod/event_handlers/mod_erlang_event/handle_msg.c
index 9ae15277fd..87f91fc51b 100644
--- a/src/mod/event_handlers/mod_erlang_event/handle_msg.c
+++ b/src/mod/event_handlers/mod_erlang_event/handle_msg.c
@@ -778,7 +778,7 @@ static switch_status_t handle_msg_bind(listener_t *listener, erlang_msg * msg, e
binding->process.pid = msg->from;
binding->listener = listener;
- switch_thread_rwlock_wrlock(globals.listener_rwlock);
+ switch_thread_rwlock_wrlock(globals.bindings_rwlock);
for (ptr = bindings.head; ptr && ptr->next; ptr = ptr->next);
@@ -789,7 +789,7 @@ static switch_status_t handle_msg_bind(listener_t *listener, erlang_msg * msg, e
}
switch_xml_set_binding_sections(bindings.search_binding, switch_xml_get_binding_sections(bindings.search_binding) | section);
- switch_thread_rwlock_unlock(globals.listener_rwlock);
+ switch_thread_rwlock_unlock(globals.bindings_rwlock);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "sections %d\n", switch_xml_get_binding_sections(bindings.search_binding));
diff --git a/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.c b/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.c
index 8d3c594b75..900b9655ff 100644
--- a/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.c
+++ b/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.c
@@ -90,7 +90,7 @@ static void remove_binding(listener_t *listener, erlang_pid * pid)
{
struct erlang_binding *ptr, *lst = NULL;
- switch_thread_rwlock_wrlock(globals.listener_rwlock);
+ switch_thread_rwlock_wrlock(globals.bindings_rwlock);
switch_xml_set_binding_sections(bindings.search_binding, SWITCH_XML_SECTION_MAX);
@@ -100,7 +100,7 @@ static void remove_binding(listener_t *listener, erlang_pid * pid)
if (ptr->next) {
bindings.head = ptr->next;
} else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removed all (only?) listeners\n");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removed all (only?) binding\n");
bindings.head = NULL;
break;
}
@@ -111,13 +111,13 @@ static void remove_binding(listener_t *listener, erlang_pid * pid)
lst->next = NULL;
}
}
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removed listener\n");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removed binding\n");
} else {
switch_xml_set_binding_sections(bindings.search_binding, switch_xml_get_binding_sections(bindings.search_binding) | ptr->section);
}
}
- switch_thread_rwlock_unlock(globals.listener_rwlock);
+ switch_thread_rwlock_unlock(globals.bindings_rwlock);
}
@@ -381,6 +381,8 @@ static switch_xml_t erlang_fetch(const char *sectionstr, const char *tag_name, c
section = switch_xml_parse_section_string((char *) sectionstr);
+ switch_thread_rwlock_rdlock(globals.bindings_rwlock);
+
for (ptr = bindings.head; ptr; ptr = ptr->next) {
if (ptr->section != section)
continue;
@@ -417,6 +419,8 @@ static switch_xml_t erlang_fetch(const char *sectionstr, const char *tag_name, c
switch_mutex_unlock(ptr->listener->sock_mutex);
}
+ switch_thread_rwlock_unlock(globals.bindings_rwlock);
+
ei_x_free(&buf);
if (!p) {
@@ -532,6 +536,7 @@ static switch_status_t notify_new_session(listener_t *listener, session_elem_t *
session_element->uuid_str);
}
+ switch_event_destroy(&call_event);
ei_x_free(&lbuf);
return SWITCH_STATUS_SUCCESS;
}
@@ -1637,6 +1642,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_erlang_event_load)
memset(&prefs, 0, sizeof(prefs));
switch_thread_rwlock_create(&globals.listener_rwlock, pool);
+ switch_thread_rwlock_create(&globals.bindings_rwlock, pool);
switch_mutex_init(&globals.fetch_reply_mutex, SWITCH_MUTEX_DEFAULT, pool);
switch_mutex_init(&globals.listener_count_mutex, SWITCH_MUTEX_UNNESTED, pool);
switch_core_hash_init(&globals.fetch_reply_hash, pool);
diff --git a/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.h b/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.h
index dacfbd661b..121e7b4f95 100644
--- a/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.h
+++ b/src/mod/event_handlers/mod_erlang_event/mod_erlang_event.h
@@ -161,6 +161,7 @@ struct api_command_struct {
struct globals_struct {
switch_thread_rwlock_t *listener_rwlock;
+ switch_thread_rwlock_t *bindings_rwlock;
switch_event_node_t *node;
switch_mutex_t *ref_mutex;
switch_mutex_t *fetch_reply_mutex;
diff --git a/src/mod/event_handlers/mod_snmp/FREESWITCH-MIB b/src/mod/event_handlers/mod_snmp/FREESWITCH-MIB
new file mode 100644
index 0000000000..9584c8bac3
--- /dev/null
+++ b/src/mod/event_handlers/mod_snmp/FREESWITCH-MIB
@@ -0,0 +1,110 @@
+FREESWITCH-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ OBJECT-TYPE, MODULE-IDENTITY,
+ Integer32, Gauge32, Counter32, Counter64, TimeTicks,
+ enterprises,
+ FROM SNMPv2-SMI
+
+ DisplayString
+ FROM SNMPv2-TC
+;
+
+
+freeswitch MODULE-IDENTITY
+ LAST-UPDATED "201101170000Z"
+ ORGANIZATION "www.freeswitch.org"
+ CONTACT-INFO
+ "Primary contact: Anthony Minessale II
+ Email: anthm@freeswitch.org"
+ DESCRIPTION
+ "This file defines the private FreeSWITCH SNMP MIB extensions."
+ REVISION "201101170000Z"
+ DESCRIPTION
+ "First draft by daniel.swarbrick@seventhsignal.de"
+ ::= { enterprises 27880 }
+
+
+core OBJECT IDENTIFIER ::= { freeswitch 1 }
+mod-sofia OBJECT IDENTIFIER ::= { freeswitch 1001 }
+mod-skinny OBJECT IDENTIFIER ::= { freeswitch 1002 }
+
+
+identity OBJECT IDENTIFIER ::= { core 1 }
+
+versionString OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "FreeSWITCH version as a string"
+ ::= { identity 1 }
+
+uuid OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "FreeSWITCH core UUID"
+ ::= { identity 2 }
+
+
+systemStats OBJECT IDENTIFIER ::= { core 2 }
+
+uptime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "FreeSWITCH process uptime in hundredths of seconds"
+ ::= { systemStats 1 }
+
+sessionsSinceStartup OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Number of sessions since FreeSWITCH process was started"
+ ::= { systemStats 2 }
+
+currentSessions OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Currently active sessions"
+ ::= { systemStats 3 }
+
+maxSessions OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Maximum permissible active sessions"
+ ::= { systemStats 4 }
+
+currentCalls OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Currently active calls"
+ ::= { systemStats 5 }
+
+sessionsPerSecond OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Current sessions per second"
+ ::= { systemStats 6 }
+
+maxSessionsPerSecond OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Maximum permissible sessions per second"
+ ::= { systemStats 7 }
+
+END
diff --git a/src/mod/event_handlers/mod_snmp/Makefile b/src/mod/event_handlers/mod_snmp/Makefile
new file mode 100644
index 0000000000..1d8827daf1
--- /dev/null
+++ b/src/mod/event_handlers/mod_snmp/Makefile
@@ -0,0 +1,7 @@
+include ../../../../build/modmake.rules
+
+LOCAL_CFLAGS=-I `net-snmp-config --cflags`
+LOCAL_LDFLAGS=`net-snmp-config --agent-libs`
+LOCAL_OBJS=subagent.o
+
+local_depend: $(LOCAL_OBJS)
diff --git a/src/mod/event_handlers/mod_snmp/mod_snmp.c b/src/mod/event_handlers/mod_snmp/mod_snmp.c
new file mode 100644
index 0000000000..040e82b602
--- /dev/null
+++ b/src/mod/event_handlers/mod_snmp/mod_snmp.c
@@ -0,0 +1,138 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2011, Anthony Minessale II
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Daniel Swarbrick
+ * Stefan Knoblich
+ *
+ * mod_snmp.c -- SNMP AgentX Subagent Module
+ *
+ */
+#include
+
+#include
+#include
+#include
+
+#include "subagent.h"
+
+static struct {
+ switch_memory_pool_t *pool;
+ int shutdown;
+} globals;
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_snmp_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_snmp_shutdown);
+SWITCH_MODULE_RUNTIME_FUNCTION(mod_snmp_runtime);
+SWITCH_MODULE_DEFINITION(mod_snmp, mod_snmp_load, mod_snmp_shutdown, mod_snmp_runtime);
+
+
+static int snmp_callback_log(int major, int minor, void *serverarg, void *clientarg)
+{
+ struct snmp_log_message *slm = (struct snmp_log_message *) serverarg;
+ switch_log_printf(SWITCH_CHANNEL_LOG, slm->priority, "%s", slm->msg);
+ return SNMP_ERR_NOERROR;
+}
+
+
+static switch_state_handler_table_t state_handlers = {
+ /*.on_init */ NULL,
+ /*.on_routing */ NULL,
+ /*.on_execute */ NULL,
+ /*.on_hangup */ NULL,
+ /*.on_exchange_media */ NULL,
+ /*.on_soft_execute */ NULL,
+ /*.on_consume_media */ NULL,
+ /*.on_hibernate */ NULL,
+ /*.on_reset */ NULL,
+ /*.on_park */ NULL,
+ /*.on_reporting */ NULL
+};
+
+
+static switch_status_t load_config(switch_memory_pool_t *pool)
+{
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+ memset(&globals, 0, sizeof(globals));
+ globals.pool = pool;
+
+ return status;
+}
+
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_snmp_load)
+{
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+ load_config(pool);
+
+ switch_core_add_state_handler(&state_handlers);
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+ /* Register callback function so we get Net-SNMP logging handled by FreeSWITCH */
+ snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, snmp_callback_log, NULL);
+ snmp_enable_calllog();
+
+ netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1);
+ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1);
+
+ init_agent("mod_snmp");
+ init_subagent();
+ init_snmp("mod_snmp");
+
+ return status;
+}
+
+
+SWITCH_MODULE_RUNTIME_FUNCTION(mod_snmp_runtime)
+{
+ /* block on select() */
+ agent_check_and_process(1);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_snmp_shutdown)
+{
+ globals.shutdown = 1;
+ switch_core_remove_state_handler(&state_handlers);
+
+ snmp_shutdown("mod_snmp");
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
diff --git a/src/mod/event_handlers/mod_snmp/subagent.c b/src/mod/event_handlers/mod_snmp/subagent.c
new file mode 100644
index 0000000000..8a9f2dac21
--- /dev/null
+++ b/src/mod/event_handlers/mod_snmp/subagent.c
@@ -0,0 +1,189 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2011, Anthony Minessale II
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Daniel Swarbrick
+ * Stefan Knoblich
+ *
+ * mod_snmp.c -- SNMP AgentX Subagent Module
+ *
+ */
+#include
+#include
+
+#include
+#include
+#include
+#include "subagent.h"
+
+
+static oid identity_oid[] = { 1,3,6,1,4,1,27880,1,1 };
+static oid systemStats_oid[] = { 1,3,6,1,4,1,27880,1,2 };
+
+/* identity sub-IDs - these must match MIB */
+enum {
+ versionString_oid = 1,
+ uuid_oid
+};
+
+
+/* systemStats sub-IDs - these must match MIB */
+enum {
+ uptime_oid = 1,
+ sessionsSinceStartup_oid,
+ currentSessions_oid,
+ maxSessions_oid,
+ currentCalls_oid,
+ sessionsPerSecond_oid,
+ maxSessionsPerSecond_oid
+};
+
+
+void init_subagent(void)
+{
+ DEBUGMSGTL(("init_nstAgentSubagentObject", "Initializing\n"));
+
+ netsnmp_register_handler(netsnmp_create_handler_registration("identity", handle_identity, identity_oid, OID_LENGTH(identity_oid), HANDLER_CAN_RONLY));
+ netsnmp_register_handler(netsnmp_create_handler_registration("systemStats", handle_systemStats, systemStats_oid, OID_LENGTH(systemStats_oid), HANDLER_CAN_RONLY));
+}
+
+
+int handle_identity(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests)
+{
+ static char const version[] = SWITCH_VERSION_FULL;
+ char uuid[40] = "";
+ netsnmp_request_info *request = NULL;
+ oid subid;
+
+ switch(reqinfo->mode) {
+ case MODE_GET:
+ for (request = requests; request; request = request->next) {
+ subid = request->requestvb->name[OID_LENGTH(systemStats_oid)];
+
+ switch (subid) {
+ case versionString_oid:
+ snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) &version, strlen(version));
+ break;
+ case uuid_oid:
+ strncpy(uuid, switch_core_get_uuid(), sizeof(uuid));
+ snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) &uuid, strlen(uuid));
+ break;
+ default:
+ snmp_log(LOG_WARNING, "Unregistered OID-suffix requested (%d)\n", (int) subid);
+ netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
+ }
+ }
+ break;
+
+ case MODE_GETNEXT:
+ snmp_log(LOG_ERR, "MODE_GETNEXT not supported (yet)\n");
+ break;
+
+ default:
+ /* we should never get here, so this is a really bad error */
+ snmp_log(LOG_ERR, "Unknown mode (%d) in handle_versionString\n", reqinfo->mode );
+ return SNMP_ERR_GENERR;
+ }
+
+ return SNMP_ERR_NOERROR;
+}
+
+
+int handle_systemStats(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests)
+{
+ netsnmp_request_info *request = NULL;
+ oid subid;
+ switch_time_t uptime;
+ uint32_t int_val;
+
+ switch(reqinfo->mode) {
+ case MODE_GET:
+ for (request = requests; request; request = request->next) {
+ subid = request->requestvb->name[OID_LENGTH(systemStats_oid)];
+
+ switch (subid) {
+ case uptime_oid:
+ uptime = switch_core_uptime() / 10000;
+ snmp_set_var_typed_value(requests->requestvb, ASN_TIMETICKS, (u_char *) &uptime, sizeof(uptime));
+ break;
+ case sessionsSinceStartup_oid:
+ int_val = switch_core_session_id() - 1;
+ snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER, (u_char *) &int_val, sizeof(int_val));
+ break;
+ case currentSessions_oid:
+ int_val = switch_core_session_count();
+ snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val));
+ break;
+ case maxSessions_oid:
+ switch_core_session_ctl(SCSC_MAX_SESSIONS, &int_val);;
+ snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val));
+ break;
+ case currentCalls_oid:
+ /*
+ * This is zero for now, since there is no convenient way to get total call
+ * count (not to be confused with session count), without touching the
+ * database.
+ */
+ int_val = 0;
+ snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val));
+ break;
+ case sessionsPerSecond_oid:
+ switch_core_session_ctl(SCSC_LAST_SPS, &int_val);
+ snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val));
+ break;
+ case maxSessionsPerSecond_oid:
+ switch_core_session_ctl(SCSC_SPS, &int_val);
+ snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, (u_char *) &int_val, sizeof(int_val));
+ break;
+ default:
+ snmp_log(LOG_WARNING, "Unregistered OID-suffix requested (%d)\n", (int) subid);
+ netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
+ }
+ }
+ break;
+
+ case MODE_GETNEXT:
+ snmp_log(LOG_ERR, "MODE_GETNEXT not supported (yet)\n");
+ break;
+
+ default:
+ /* we should never get here, so this is a really bad error */
+ snmp_log(LOG_ERR, "Unknown mode (%d) in handle_systemStats\n", reqinfo->mode);
+ return SNMP_ERR_GENERR;
+ }
+
+ return SNMP_ERR_NOERROR;
+}
+
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
diff --git a/src/mod/event_handlers/mod_snmp/subagent.h b/src/mod/event_handlers/mod_snmp/subagent.h
new file mode 100644
index 0000000000..8a57d8a9f7
--- /dev/null
+++ b/src/mod/event_handlers/mod_snmp/subagent.h
@@ -0,0 +1,8 @@
+#ifndef subagent_H
+#define subagent_H
+
+void init_subagent(void);
+Netsnmp_Node_Handler handle_identity;
+Netsnmp_Node_Handler handle_systemStats;
+
+#endif /* subagent_H */
diff --git a/src/mod/formats/mod_shout/mod_shout.c b/src/mod/formats/mod_shout/mod_shout.c
index a4965c4d67..377cfe520c 100644
--- a/src/mod/formats/mod_shout/mod_shout.c
+++ b/src/mod/formats/mod_shout/mod_shout.c
@@ -584,7 +584,11 @@ static void launch_write_stream_thread(shout_context_t *context)
}
#define TC_BUFFER_SIZE 1024 * 32
-#define MPGERROR() {err = "MPG123 Error at __FILE__:__LINE__."; mpg123err = mpg123_strerror(context->mh); goto error; }
+
+#define CONCAT_LOCATION(_x,_y) _x ":" #_y
+#define MAKE_LOCATION(_x,_y) CONCAT_LOCATION(_x,_y)
+#define HERE MAKE_LOCATION(__FILE__, __LINE__)
+#define MPGERROR() {err = "MPG123 Error at " HERE "."; mpg123err = mpg123_strerror(context->mh); goto error; }
static switch_status_t shout_file_open(switch_file_handle_t *handle, const char *path)
{
shout_context_t *context;
diff --git a/src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c b/src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c
index a439ab8203..78d97ce259 100644
--- a/src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c
+++ b/src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c
@@ -340,7 +340,7 @@ static switch_status_t my_on_reporting(switch_core_session_t *session)
switch_yield(globals.delay * 1000000);
}
- destUrl = switch_mprintf("%s?uuid=%s", globals.urls[globals.url_index], switch_core_session_get_uuid(session));
+ destUrl = switch_mprintf("%s?uuid=%s%s", globals.urls[globals.url_index], a_prefix, switch_core_session_get_uuid(session));
curl_easy_setopt(curl_handle, CURLOPT_URL, destUrl);
if (!strncasecmp(destUrl, "https", 5)) {
diff --git a/src/switch_apr.c b/src/switch_apr.c
index 4c99662f45..3798d6e2dc 100644
--- a/src/switch_apr.c
+++ b/src/switch_apr.c
@@ -833,7 +833,7 @@ SWITCH_DECLARE(switch_status_t) switch_socket_recvfrom(switch_sockaddr_t *from,
*/
}
- if (r == 35) {
+ if (r == 35 || r == 730035) {
r = SWITCH_STATUS_BREAK;
}
diff --git a/src/switch_core.c b/src/switch_core.c
index b531111a6d..43fb36d705 100644
--- a/src/switch_core.c
+++ b/src/switch_core.c
@@ -151,13 +151,21 @@ static void check_ip(void)
SWITCH_STANDARD_SCHED_FUNC(heartbeat_callback)
{
send_heartbeat();
- check_ip();
/* reschedule this task */
task->runtime = switch_epoch_time_now(NULL) + 20;
}
+SWITCH_STANDARD_SCHED_FUNC(check_ip_callback)
+{
+ check_ip();
+
+ /* reschedule this task */
+ task->runtime = switch_epoch_time_now(NULL) + 60;
+}
+
+
SWITCH_DECLARE(switch_status_t) switch_core_set_console(const char *console)
{
if ((runtime.console = fopen(console, "a")) == 0) {
@@ -1357,6 +1365,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc
switch_scheduler_add_task(switch_epoch_time_now(NULL), heartbeat_callback, "heartbeat", "core", 0, NULL, SSHF_NONE | SSHF_NO_DEL);
+ switch_scheduler_add_task(switch_epoch_time_now(NULL), check_ip_callback, "check_ip", "core", 0, NULL, SSHF_NONE | SSHF_NO_DEL | SSHF_OWN_THREAD);
+
switch_uuid_get(&uuid);
switch_uuid_format(runtime.uuid_str, &uuid);
diff --git a/src/switch_core_file.c b/src/switch_core_file.c
index c00756ffc6..19f23546f0 100644
--- a/src/switch_core_file.c
+++ b/src/switch_core_file.c
@@ -391,10 +391,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh,
if ((status = fh->file_interface->file_write(fh, fh->pre_buffer_data, &blen)) != SWITCH_STATUS_SUCCESS) {
*len = 0;
}
- fh->samples_out += blen;
}
}
+ fh->samples_out += orig_len;
return status;
} else {
switch_status_t status;
diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c
index d156c700fd..78743e6420 100644
--- a/src/switch_ivr_originate.c
+++ b/src/switch_ivr_originate.c
@@ -2755,6 +2755,26 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
}
}
}
+
+ if (session) {
+ switch_channel_set_variable(originate_status[i].peer_channel, "originating_leg_uuid", switch_core_session_get_uuid(session));
+ }
+
+ if ((vvar = switch_channel_get_variable_dup(originate_status[i].peer_channel, "execute_on_originate", SWITCH_FALSE))) {
+ char *app = switch_core_session_strdup(originate_status[i].peer_session, vvar);
+ char *arg = NULL;
+
+ if (strstr(app, "::")) {
+ switch_core_session_execute_application_async(originate_status[i].peer_session, app, arg);
+ } else {
+ if ((arg = strchr(app, ' '))) {
+ *arg++ = '\0';
+ }
+
+ switch_core_session_execute_application(originate_status[i].peer_session, app, arg);
+ }
+
+ }
}
if (table) {
@@ -2773,7 +2793,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
*cause = SWITCH_CAUSE_SUCCESS;
goto outer_for;
}
-
+
if (!switch_core_session_running(originate_status[i].peer_session)) {
if (originate_status[i].per_channel_delay_start) {
switch_channel_set_flag(originate_status[i].peer_channel, CF_BLOCK_STATE);
diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c
index 523dfdeb02..4e9e7b95ca 100644
--- a/src/switch_ivr_play_say.c
+++ b/src/switch_ivr_play_say.c
@@ -372,6 +372,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
switch_event_t *event;
int divisor = 0;
int file_flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT;
+ int restart_limit_on_dtmf = 0;
const char *prefix;
prefix = switch_channel_get_variable(channel, "sound_prefix");
@@ -528,6 +529,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
if (switch_test_flag(fh, SWITCH_FILE_NATIVE)) {
asis = 1;
}
+
+ restart_limit_on_dtmf = switch_true(switch_channel_get_variable(channel, "record_restart_limit_on_dtmf"));
if ((p = switch_channel_get_variable(channel, "RECORD_TITLE"))) {
vval = switch_core_session_strdup(session, p);
@@ -637,6 +640,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
*/
if (switch_channel_has_dtmf(channel)) {
+
+ if (limit && restart_limit_on_dtmf) {
+ start = switch_epoch_time_now(NULL);
+ }
+
if (!args->input_callback && !args->buf && !args->dmachine) {
status = SWITCH_STATUS_BREAK;
break;
diff --git a/src/switch_rtp.c b/src/switch_rtp.c
index 4e5450d7e8..4acadfe2ff 100644
--- a/src/switch_rtp.c
+++ b/src/switch_rtp.c
@@ -32,6 +32,7 @@
*/
//#define DEBUG_2833
//#define RTP_DEBUG_WRITE_DELTA
+//#define DEBUG_MISSED_SEQ
#include
#include
#undef PACKAGE_NAME
@@ -245,6 +246,9 @@ struct switch_rtp {
switch_time_t send_time;
switch_byte_t auto_adj_used;
uint8_t pause_jb;
+ uint16_t last_seq;
+ switch_time_t last_read_time;
+ switch_size_t last_flush_packet_count;
};
struct switch_rtcp_senderinfo {
@@ -256,6 +260,180 @@ struct switch_rtcp_senderinfo {
unsigned oc:32;
};
+typedef enum {
+ RESULT_CONTINUE,
+ RESULT_GOTO_END,
+ RESULT_GOTO_RECVFROM,
+ RESULT_GOTO_TIMERCHECK
+} handle_rfc2833_result_t;
+
+static handle_rfc2833_result_t handle_rfc2833(switch_rtp_t *rtp_session, switch_size_t bytes, int *do_cng)
+{
+#ifdef DEBUG_2833
+ if (rtp_session->dtmf_data.in_digit_sanity && !(rtp_session->dtmf_data.in_digit_sanity % 100)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sanity %d\n", rtp_session->dtmf_data.in_digit_sanity);
+ }
+#endif
+
+ if (rtp_session->dtmf_data.in_digit_sanity && !--rtp_session->dtmf_data.in_digit_sanity) {
+ rtp_session->dtmf_data.last_digit = 0;
+ rtp_session->dtmf_data.in_digit_ts = 0;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed DTMF sanity check.\n");
+ }
+
+ /* RFC2833 ... like all RFC RE: VoIP, guaranteed to drive you to insanity!
+ We know the real rules here, but if we enforce them, it's an interop nightmare so,
+ we put up with as much as we can so we don't have to deal with being punished for
+ doing it right. Nice guys finish last!
+ */
+ if (bytes > rtp_header_len && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) &&
+ !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833) && rtp_session->recv_te && rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
+ switch_size_t len = bytes - rtp_header_len;
+ unsigned char *packet = (unsigned char *) rtp_session->recv_msg.body;
+ int end;
+ uint16_t duration;
+ char key;
+ uint16_t in_digit_seq;
+ uint32_t ts;
+
+ if (!(packet[0] || packet[1] || packet[2] || packet[3]) && len >= 8) {
+ packet += 4;
+ len -= 4;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "DTMF payload offset by 4 bytes.\n");
+ }
+
+ if (!(packet[0] || packet[1] || packet[2] || packet[3])) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed DTMF payload check.\n");
+ rtp_session->dtmf_data.last_digit = 0;
+ rtp_session->dtmf_data.in_digit_ts = 0;
+ }
+
+ end = packet[1] & 0x80 ? 1 : 0;
+ duration = (packet[2] << 8) + packet[3];
+ key = switch_rfc2833_to_char(packet[0]);
+ in_digit_seq = ntohs((uint16_t) rtp_session->recv_msg.header.seq);
+ ts = htonl(rtp_session->recv_msg.header.ts);
+
+ if (in_digit_seq < rtp_session->dtmf_data.in_digit_seq) {
+ if (rtp_session->dtmf_data.in_digit_seq - in_digit_seq > 100) {
+ rtp_session->dtmf_data.in_digit_seq = 0;
+ }
+ }
+#ifdef DEBUG_2833
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "packet[%d]: %02x %02x %02x %02x\n", (int) len, (unsigned) packet[0], (unsigned)
+ packet[1], (unsigned) packet[2], (unsigned) packet[3]);
+#endif
+
+ if (in_digit_seq > rtp_session->dtmf_data.in_digit_seq) {
+
+ rtp_session->dtmf_data.in_digit_seq = in_digit_seq;
+#ifdef DEBUG_2833
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "read: %c %u %u %u %u %d %d %s\n",
+ key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq,
+ ts, duration, rtp_session->recv_msg.header.m, end, end && !rtp_session->dtmf_data.in_digit_ts ? "ignored" : "");
+#endif
+
+ if (!rtp_session->dtmf_data.in_digit_queued && (rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION) &&
+ rtp_session->dtmf_data.in_digit_ts) {
+ switch_dtmf_t dtmf = { key, switch_core_min_dtmf_duration(0) };
+#ifdef DEBUG_2833
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Early Queuing digit %c:%d\n", dtmf.digit, dtmf.duration / 8);
+#endif
+ switch_rtp_queue_rfc2833_in(rtp_session, &dtmf);
+ rtp_session->dtmf_data.in_digit_queued = 1;
+ }
+
+ /* only set sanity if we do NOT ignore the packet */
+ if (rtp_session->dtmf_data.in_digit_ts) {
+ rtp_session->dtmf_data.in_digit_sanity = 2000;
+ }
+
+ if (rtp_session->dtmf_data.last_duration > duration &&
+ rtp_session->dtmf_data.last_duration > 0xFC17 && ts == rtp_session->dtmf_data.in_digit_ts) {
+ rtp_session->dtmf_data.flip++;
+ }
+
+ if (end) {
+ if (rtp_session->dtmf_data.in_digit_ts) {
+ switch_dtmf_t dtmf = { key, duration };
+
+ if (ts > rtp_session->dtmf_data.in_digit_ts) {
+ dtmf.duration += (ts - rtp_session->dtmf_data.in_digit_ts);
+ }
+ if (rtp_session->dtmf_data.flip) {
+ dtmf.duration += rtp_session->dtmf_data.flip * 0xFFFF;
+ rtp_session->dtmf_data.flip = 0;
+#ifdef DEBUG_2833
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "you're welcome!\n");
+#endif
+ }
+#ifdef DEBUG_2833
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "done digit=%c ts=%u start_ts=%u dur=%u ddur=%u\n",
+ dtmf.digit, ts, rtp_session->dtmf_data.in_digit_ts, duration, dtmf.duration);
+#endif
+
+ if (!(rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION) && !rtp_session->dtmf_data.in_digit_queued) {
+#ifdef DEBUG_2833
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Queuing digit %c:%d\n", dtmf.digit, dtmf.duration / 8);
+#endif
+ switch_rtp_queue_rfc2833_in(rtp_session, &dtmf);
+ }
+
+ rtp_session->dtmf_data.last_digit = rtp_session->dtmf_data.first_digit;
+
+ rtp_session->dtmf_data.in_digit_ts = 0;
+ rtp_session->dtmf_data.in_digit_sanity = 0;
+ rtp_session->dtmf_data.in_digit_queued = 0;
+ *do_cng = 1;
+ } else {
+ if (!switch_rtp_ready(rtp_session)) {
+ return RESULT_GOTO_END;
+ }
+ switch_cond_next();
+ return RESULT_GOTO_RECVFROM;
+ }
+
+ } else if (!rtp_session->dtmf_data.in_digit_ts) {
+ rtp_session->dtmf_data.in_digit_ts = ts;
+ rtp_session->dtmf_data.first_digit = key;
+ rtp_session->dtmf_data.in_digit_sanity = 2000;
+ }
+
+ rtp_session->dtmf_data.last_duration = duration;
+ } else {
+#ifdef DEBUG_2833
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "drop: %c %u %u %u %u %d %d\n",
+ key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq, ts, duration, rtp_session->recv_msg.header.m, end);
+#endif
+ switch_cond_next();
+ return RESULT_GOTO_RECVFROM;
+ }
+ }
+
+ if (bytes && rtp_session->dtmf_data.in_digit_ts) {
+ if (!switch_rtp_ready(rtp_session)) {
+ return RESULT_GOTO_END;
+ }
+
+ if (!rtp_session->dtmf_data.in_interleaved && rtp_session->recv_msg.header.pt != rtp_session->recv_te) {
+ /* Drat, they are sending audio still as well as DTMF ok fine..... *sigh* */
+ rtp_session->dtmf_data.in_interleaved = 1;
+ }
+
+ if (rtp_session->dtmf_data.in_interleaved || (rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION)) {
+ if (rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
+ return RESULT_GOTO_RECVFROM;
+ }
+ } else {
+ *do_cng = 1;
+ return RESULT_GOTO_TIMERCHECK;
+ }
+ }
+
+ return RESULT_CONTINUE;
+}
+
static int global_init = 0;
static int rtp_common_write(switch_rtp_t *rtp_session,
rtp_msg_t *send_msg, void *data, uint32_t datalen, switch_payload_t payload, uint32_t timestamp, switch_frame_flag_t *flags);
@@ -2157,6 +2335,15 @@ static void do_flush(switch_rtp_t *rtp_session)
bytes = sizeof(rtp_msg_t);
status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, &bytes);
if (bytes) {
+ int do_cng = 0;
+
+ /* Make sure to handle RFC2833 packets, even if we're flushing the packets */
+ if (bytes > rtp_header_len && rtp_session->recv_te && rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
+ handle_rfc2833(rtp_session, bytes, &do_cng);
+#ifdef DEBUG_2833
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "*** RTP packet handled in flush loop ***\n");
+#endif
+ }
flushed++;
@@ -2195,7 +2382,52 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
*bytes = sizeof(rtp_msg_t);
status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, bytes);
ts = ntohl(rtp_session->recv_msg.header.ts);
-
+
+ if (*bytes ) {
+ uint16_t seq = ntohs((uint16_t) rtp_session->recv_msg.header.seq);
+
+ if (rtp_session->last_seq && rtp_session->last_seq+1 != seq) {
+#ifdef DEBUG_MISSED_SEQ
+ switch_size_t flushed_packets_diff = rtp_session->stats.inbound.flush_packet_count - rtp_session->last_flush_packet_count;
+ switch_size_t num_missed = (switch_size_t)seq - (rtp_session->last_seq+1);
+
+ if (num_missed == 1) { /* We missed one packet */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missed one RTP frame with sequence [%d]%s. Time since last read [%d]\n",
+ rtp_session->last_seq+1, (flushed_packets_diff == 1) ? " (flushed by FS)" : " (missed)",
+ rtp_session->last_read_time ? switch_micro_time_now()-rtp_session->last_read_time : 0);
+ } else { /* We missed multiple packets */
+ if (flushed_packets_diff == 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+ "Missed %d RTP frames from sequence [%d] to [%d] (missed). Time since last read [%d]\n",
+ num_missed, rtp_session->last_seq+1, seq-1,
+ rtp_session->last_read_time ? switch_micro_time_now()-rtp_session->last_read_time : 0);
+ } else if (flushed_packets_diff == num_missed) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+ "Missed %d RTP frames from sequence [%d] to [%d] (flushed by FS). Time since last read [%d]\n",
+ num_missed, rtp_session->last_seq+1, seq-1,
+ rtp_session->last_read_time ? switch_micro_time_now()-rtp_session->last_read_time : 0);
+ } else if (num_missed > flushed_packets_diff) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+ "Missed %d RTP frames from sequence [%d] to [%d] (%d packets flushed by FS, %d packets missed)."
+ " Time since last read [%d]\n",
+ num_missed, rtp_session->last_seq+1, seq-1,
+ flushed_packets_diff, num_missed-flushed_packets_diff,
+ rtp_session->last_read_time ? switch_micro_time_now()-rtp_session->last_read_time : 0);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+ "Missed %d RTP frames from sequence [%d] to [%d] (%d packets flushed by FS). Time since last read [%d]\n",
+ num_missed, rtp_session->last_seq+1, seq-1,
+ flushed_packets_diff, rtp_session->last_read_time ? switch_micro_time_now()-rtp_session->last_read_time : 0);
+ }
+ }
+#endif
+ }
+ rtp_session->last_seq = seq;
+ }
+
+ rtp_session->last_flush_packet_count = rtp_session->stats.inbound.flush_packet_count;
+ rtp_session->last_read_time = switch_micro_time_now();
+
if (*bytes && (!rtp_session->recv_te || rtp_session->recv_msg.header.pt != rtp_session->recv_te) &&
ts && !rtp_session->jb && !rtp_session->pause_jb && ts == rtp_session->last_cng_ts) {
/* we already sent this frame..... */
@@ -2494,13 +2726,6 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
}
}
- if (rtp_session->recv_msg.header.pt != 13 &&
- rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
- (!rtp_session->cng_pt || rtp_session->recv_msg.header.pt != rtp_session->cng_pt) &&
- rtp_session->recv_msg.header.pt != rtp_session->payload) {
- /* drop frames of incorrect payload number and return CNG frame instead */
- return_cng_frame();
- }
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP) && rtp_session->rtcp_read_pollfd) {
rtcp_poll_status = switch_poll(rtp_session->rtcp_read_pollfd, 1, &rtcp_fdr, 0);
@@ -2579,6 +2804,15 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
goto end;
}
+ if (bytes && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_UDPTL) &&
+ rtp_session->recv_msg.header.pt != 13 &&
+ rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
+ (!rtp_session->cng_pt || rtp_session->recv_msg.header.pt != rtp_session->cng_pt) &&
+ rtp_session->recv_msg.header.pt != rtp_session->payload) {
+ /* drop frames of incorrect payload number and return CNG frame instead */
+ return_cng_frame();
+ }
+
if (!bytes && (io_flags & SWITCH_IO_FLAG_NOBLOCK)) {
rtp_session->missed_count = 0;
ret = 0;
@@ -2835,173 +3069,20 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
bytes = sbytes;
}
-#ifdef DEBUG_2833
- if (rtp_session->dtmf_data.in_digit_sanity && !(rtp_session->dtmf_data.in_digit_sanity % 100)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sanity %d\n", rtp_session->dtmf_data.in_digit_sanity);
- }
-#endif
- if (rtp_session->dtmf_data.in_digit_sanity && !--rtp_session->dtmf_data.in_digit_sanity) {
- rtp_session->dtmf_data.last_digit = 0;
- rtp_session->dtmf_data.in_digit_ts = 0;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed DTMF sanity check.\n");
- }
-
- /* RFC2833 ... like all RFC RE: VoIP, guaranteed to drive you to insanity!
- We know the real rules here, but if we enforce them, it's an interop nightmare so,
- we put up with as much as we can so we don't have to deal with being punished for
- doing it right. Nice guys finish last!
- */
- if (bytes > rtp_header_len && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) &&
- !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833) && rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
- switch_size_t len = bytes - rtp_header_len;
- unsigned char *packet = (unsigned char *) rtp_session->recv_msg.body;
- int end;
- uint16_t duration;
- char key;
- uint16_t in_digit_seq;
- uint32_t ts;
-
-
- if (!(packet[0] || packet[1] || packet[2] || packet[3]) && len >= 8) {
- packet += 4;
- len -= 4;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "DTMF payload offset by 4 bytes.\n");
- }
-
- if (!(packet[0] || packet[1] || packet[2] || packet[3])) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed DTMF payload check.\n");
- rtp_session->dtmf_data.last_digit = 0;
- rtp_session->dtmf_data.in_digit_ts = 0;
- }
-
- end = packet[1] & 0x80 ? 1 : 0;
- duration = (packet[2] << 8) + packet[3];
- key = switch_rfc2833_to_char(packet[0]);
- in_digit_seq = ntohs((uint16_t) rtp_session->recv_msg.header.seq);
- ts = htonl(rtp_session->recv_msg.header.ts);
-
- if (in_digit_seq < rtp_session->dtmf_data.in_digit_seq) {
- if (rtp_session->dtmf_data.in_digit_seq - in_digit_seq > 100) {
- rtp_session->dtmf_data.in_digit_seq = 0;
- }
- }
-#ifdef DEBUG_2833
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "packet[%d]: %02x %02x %02x %02x\n", (int) len, (unsigned) packet[0], (unsigned)
- packet[1], (unsigned) packet[2], (unsigned) packet[3]);
-#endif
-
- if (in_digit_seq > rtp_session->dtmf_data.in_digit_seq) {
-
- rtp_session->dtmf_data.in_digit_seq = in_digit_seq;
-#ifdef DEBUG_2833
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "read: %c %u %u %u %u %d %d %s\n",
- key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq,
- ts, duration, rtp_session->recv_msg.header.m, end, end && !rtp_session->dtmf_data.in_digit_ts ? "ignored" : "");
-#endif
-
- if (!rtp_session->dtmf_data.in_digit_queued && (rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION) &&
- rtp_session->dtmf_data.in_digit_ts) {
- switch_dtmf_t dtmf = { key, switch_core_min_dtmf_duration(0) };
-#ifdef DEBUG_2833
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Early Queuing digit %c:%d\n", dtmf.digit, dtmf.duration / 8);
-#endif
- switch_rtp_queue_rfc2833_in(rtp_session, &dtmf);
- rtp_session->dtmf_data.in_digit_queued = 1;
- }
-
- /* only set sanity if we do NOT ignore the packet */
- if (rtp_session->dtmf_data.in_digit_ts) {
- rtp_session->dtmf_data.in_digit_sanity = 2000;
- }
-
- if (rtp_session->dtmf_data.last_duration > duration &&
- rtp_session->dtmf_data.last_duration > 0xFC17 && ts == rtp_session->dtmf_data.in_digit_ts) {
- rtp_session->dtmf_data.flip++;
- }
-
- if (end) {
- if (rtp_session->dtmf_data.in_digit_ts) {
- switch_dtmf_t dtmf = { key, duration };
-
- if (ts > rtp_session->dtmf_data.in_digit_ts) {
- dtmf.duration += (ts - rtp_session->dtmf_data.in_digit_ts);
- }
- if (rtp_session->dtmf_data.flip) {
- dtmf.duration += rtp_session->dtmf_data.flip * 0xFFFF;
- rtp_session->dtmf_data.flip = 0;
-#ifdef DEBUG_2833
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "you're welcome!\n");
-#endif
- }
-#ifdef DEBUG_2833
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "done digit=%c ts=%u start_ts=%u dur=%u ddur=%u\n",
- dtmf.digit, ts, rtp_session->dtmf_data.in_digit_ts, duration, dtmf.duration);
-#endif
-
- if (!(rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION) && !rtp_session->dtmf_data.in_digit_queued) {
-#ifdef DEBUG_2833
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Queuing digit %c:%d\n", dtmf.digit, dtmf.duration / 8);
-#endif
- switch_rtp_queue_rfc2833_in(rtp_session, &dtmf);
- }
-
- rtp_session->dtmf_data.last_digit = rtp_session->dtmf_data.first_digit;
-
- rtp_session->dtmf_data.in_digit_ts = 0;
- rtp_session->dtmf_data.in_digit_sanity = 0;
- rtp_session->dtmf_data.in_digit_queued = 0;
- do_cng = 1;
- } else {
- if (!switch_rtp_ready(rtp_session)) {
- goto end;
- }
- switch_cond_next();
- goto recvfrom;
- }
-
- } else if (!rtp_session->dtmf_data.in_digit_ts) {
- rtp_session->dtmf_data.in_digit_ts = ts;
- rtp_session->dtmf_data.first_digit = key;
- rtp_session->dtmf_data.in_digit_sanity = 2000;
- }
-
- rtp_session->dtmf_data.last_duration = duration;
- } else {
-#ifdef DEBUG_2833
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "drop: %c %u %u %u %u %d %d\n",
- key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq, ts, duration, rtp_session->recv_msg.header.m, end);
-#endif
- switch_cond_next();
- goto recvfrom;
- }
- }
-
- if (rtp_session->dtmf_data.in_digit_ts) {
-
- }
-
-
- if (bytes && rtp_session->dtmf_data.in_digit_ts) {
- if (!switch_rtp_ready(rtp_session)) {
- goto end;
- }
-
- if (!rtp_session->dtmf_data.in_interleaved && rtp_session->recv_msg.header.pt != rtp_session->recv_te) {
- /* Drat, they are sending audio still as well as DTMF ok fine..... *sigh* */
- rtp_session->dtmf_data.in_interleaved = 1;
- }
-
- if (rtp_session->dtmf_data.in_interleaved || (rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION)) {
- if (rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
- goto recvfrom;
- }
- } else {
- return_cng_frame();
- }
+ /* Handle incoming RFC2833 packets */
+ switch (handle_rfc2833(rtp_session, bytes, &do_cng)) {
+ case RESULT_GOTO_END:
+ goto end;
+ case RESULT_GOTO_RECVFROM:
+ goto recvfrom;
+ case RESULT_GOTO_TIMERCHECK:
+ goto timer_check;
+ case RESULT_CONTINUE:
+ goto result_continue;
}
+ result_continue:
timer_check:
if (do_cng) {
diff --git a/w32/Setup/Product.wxs b/w32/Setup/Product.wxs
index 2f072aa8ca..1de2ec204d 100644
--- a/w32/Setup/Product.wxs
+++ b/w32/Setup/Product.wxs
@@ -57,6 +57,9 @@
WorkingDirectory="INSTALLLOCATION"/>
+
+
+
+
+
+