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"/> + + + + + +