Merge remote branch 'origin/v1.2.stable' into v1.2.stable-em_management

This commit is contained in:
Moises Silva 2013-10-22 10:06:42 -04:00
commit 7a3cc7c9af
31 changed files with 832 additions and 201 deletions

View File

@ -3,7 +3,7 @@ AC_DEFUN([AX_COMPILER_VENDOR],
AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
[ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown
# note: don't check for gcc first since some other compilers define __GNUC__
for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ clang:__clang__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do
vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
#if !($vencpp)

View File

@ -82,7 +82,6 @@ dialplans/mod_dialplan_xml
#endpoints/mod_dingaling
#endpoints/mod_gsmopen
#endpoints/mod_h323
#endpoints/mod_html5
#endpoints/mod_khomp
endpoints/mod_loopback
#endpoints/mod_opal

View File

@ -1 +1 @@
1.2.11
1.2.14

View File

@ -3,10 +3,10 @@
# Must change all of the below together
# For a release, set revision for that tagged release as well and uncomment
AC_INIT([freeswitch], [1.2.13], bugs@freeswitch.org)
AC_INIT([freeswitch], [1.2.14], bugs@freeswitch.org)
AC_SUBST(SWITCH_VERSION_MAJOR, [1])
AC_SUBST(SWITCH_VERSION_MINOR, [2])
AC_SUBST(SWITCH_VERSION_MICRO, [13])
AC_SUBST(SWITCH_VERSION_MICRO, [14])
AC_SUBST(SWITCH_VERSION_REVISION, [])
AC_SUBST(SWITCH_VERSION_REVISION_HUMAN, [])
@ -167,11 +167,19 @@ SWITCH_AM_LDFLAGS="-lm"
#set SOLINK variable based on compiler and host
if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then
SOLINK="-Bdynamic -dy -G"
elif test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
elif test "x${ax_cv_c_compiler_vendor}" = "xclang" ; then
case "$host" in
*darwin12.*|*darwin11.*|*darwin10.*)
*darwin*)
SOLINK="-dynamic -force-flat-namespace"
;;
*)
AC_ERROR([Please update configure.in with SOLINK values for your compiler])
;;
esac
elif test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
case "$host" in
# older Xcode test for darwin, Xcode 4/5 use clang above
*darwin*)
SOLINK="-dynamic -bundle -force-flat-namespace"
;;
@ -185,7 +193,6 @@ elif test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
else
AC_ERROR([Please update configure.in with SOLINK values for your compiler])
fi
# set DYNAMIC_LIB_EXTEN
# we should really be using libtool so we don't need to do this
case "$host" in
@ -716,6 +723,17 @@ if test x"$ac_cv_gcc_declaration_after_statement" = xyes; then
fi
CFLAGS="$saved_CFLAGS"
if test "x${ax_cv_c_compiler_vendor}" = "xclang" ; then
# Next check added for Xcode 5 and systems with clang 5 llvm 3.3 or above, extended offset must be off
AC_CACHE_CHECK([whether compiler supports -Wextended-offsetof], [ac_cv_clang_extended_offsetof], [
AC_TRY_COMPILE([],[return 0;],[ac_cv_clang_extended_offsetof=yes],[ac_cv_clang_extended_offsetof=no])
])
AC_MSG_RESULT($ac_cv_clang_extended_offsetof)
if test x"$ac_cv_clang_extended_offsetof" = xyes; then
APR_ADDTO(CFLAGS, -Wno-extended-offsetof)
fi
fi
# Tested and fixed lot of modules, but some are untested. Will be added back when the core team decide it ready
# Untested modules : mod_osp mod_soundtouch mod_sangoma_codec mod_dingaling mod_opal mod_skypopen mod_h323 mod_khomp
# mod_unimrcp mod_cepstral mod_erlang_event mod_snmp mod_perl mod_java mod_managed

1
debian/.gitignore vendored
View File

@ -5,6 +5,7 @@
/files
/modules.conf
/modules_.conf
/freeswitch-all.*
/freeswitch-autotools.install
/freeswitch-mod-*.install
/freeswitch-conf-*.install

106
debian/bootstrap.sh vendored
View File

@ -6,7 +6,7 @@ mod_dir="../src/mod"
conf_dir="../conf"
lang_dir="../conf/vanilla/lang"
fs_description="FreeSWITCH is a scalable open source cross-platform telephony platform designed to route and interconnect popular communication protocols using audio, video, text or any other form of media."
mod_build_depends="."
mod_build_depends="." mod_depends="." mod_recommends="." mod_suggests="."
supported_distros="squeeze wheezy jessie sid"
avoid_mods=(
applications/mod_limit
@ -204,6 +204,32 @@ EOF
print_core_control () {
cat <<EOF
Package: freeswitch-all
Architecture: any
Provides: freeswitch, libfreeswitch1, freeswitch-doc, freeswitch-init
Replaces: freeswitch (<= \${binary:Version}),
libfreeswitch1 (<= \${binary:Version}),
freeswitch-doc (<= \${binary:Version}),
freeswitch-sysvinit (<= \${binary:Version}),
freeswitch-systemd (<= \${binary:Version})
Breaks: freeswitch (<= \${binary:Version}),
libfreeswitch1 (<= \${binary:Version}),
freeswitch-doc (<= \${binary:Version}),
freeswitch-sysvinit (<= \${binary:Version}),
freeswitch-systemd (<= \${binary:Version})
Depends: \${shlibs:Depends}, \${perl:Depends}, \${misc:Depends},
freeswitch-music-default (>= 1.0.8),
freeswitch-sounds-en-us-callie (>= 1.0.25) | freeswitch-sounds,
$(debian_wrap "${mod_depends}")
Recommends:
$(debian_wrap "${mod_recommends}")
Suggests: freeswitch-all-dbg,
$(debian_wrap "${mod_suggests}")
Description: Cross-Platform Scalable Multi-Protocol Soft Switch
$(debian_wrap "${fs_description}")
.
This package contains FreeSWITCH and all modules and extras.
Package: freeswitch
Architecture: any
Depends: \${shlibs:Depends}, \${perl:Depends}, \${misc:Depends},
@ -616,6 +642,16 @@ Description: Cross-Platform Scalable Multi-Protocol Soft Switch
This is a metapackage which depends on all mod_say languages for
FreeSWITCH.
Package: freeswitch-all-dbg
Section: debug
Priority: extra
Architecture: any
Depends: \${misc:Depends}, freeswitch (= \${binary:Version})
Description: debugging symbols for FreeSWITCH
$(debian_wrap "${fs_description}")
.
This package contains debugging symbols for FreeSWITCH.
Package: freeswitch-dbg
Section: debug
Priority: extra
@ -890,6 +926,7 @@ gencontrol_per_cat () {
geninstall_per_mod () {
local f=freeswitch-${module_name//_/-}.install
(print_edit_warning; print_mod_install "$module_name") > $f
print_mod_install "$module_name" >> freeswitch-all.install
test -f $f.tmpl && cat $f.tmpl >> $f
}
@ -912,6 +949,7 @@ genconf () {
local p=freeswitch-conf-${conf//_/-}
local f=$p.install
(print_edit_warning; print_conf_install) > $f
print_conf_install >> freeswitch-all.install
test -f $f.tmpl && cat $f.tmpl >> $f
local f=$p.lintian-overrides
(print_edit_warning; print_conf_overrides "$p") > $f
@ -923,26 +961,50 @@ genlang () {
local p=freeswitch-lang-${lang//_/-}
local f=$p.install
(print_edit_warning; print_lang_install) > $f
print_lang_install >> freeswitch-all.install
test -f $f.tmpl && cat $f.tmpl >> $f
local f=$p.lintian-overrides
(print_edit_warning; print_lang_overrides "$p") > $f
test -f $f.tmpl && cat $f.tmpl >> $f
}
accumulate_build_depends () {
accumulate_mod_deps () {
local x=""
# build-depends
if [ -n "$(eval echo \$build_depends_$codename)" ]; then
x="$(eval echo \$build_depends_$codename)"
else
x="${build_depends}"
fi
else x="${build_depends}"; fi
if [ -n "$x" ]; then
if [ ! "$mod_build_depends" = "." ]; then
mod_build_depends="${mod_build_depends}, ${x}"
else
mod_build_depends="${x}"
fi
fi
else mod_build_depends="${x}"; fi; fi
# depends
if [ -n "$(eval echo \$depends_$codename)" ]; then
x="$(eval echo \$depends_$codename)"
else x="${depends}"; fi
x="$(echo "$x" | sed 's/, \?/\n/g' | grep -v '^freeswitch' | tr '\n' ',' | sed -e 's/,$//' -e 's/,/, /g')"
if [ -n "$x" ]; then
if [ ! "$mod_depends" = "." ]; then
mod_depends="${mod_depends}, ${x}"
else mod_depends="${x}"; fi; fi
# recommends
if [ -n "$(eval echo \$recommends_$codename)" ]; then
x="$(eval echo \$recommends_$codename)"
else x="${recommends}"; fi
x="$(echo "$x" | sed 's/, \?/\n/g' | grep -v '^freeswitch' | tr '\n' ',' | sed -e 's/,$//' -e 's/,/, /g')"
if [ -n "$x" ]; then
if [ ! "$mod_recommends" = "." ]; then
mod_recommends="${mod_recommends}, ${x}"
else mod_recommends="${x}"; fi; fi
# suggests
if [ -n "$(eval echo \$suggests_$codename)" ]; then
x="$(eval echo \$suggests_$codename)"
else x="${suggests}"; fi
x="$(echo "$x" | sed 's/, \?/\n/g' | grep -v '^freeswitch' | tr '\n' ',' | sed -e 's/,$//' -e 's/,/, /g')"
if [ -n "$x" ]; then
if [ ! "$mod_suggests" = "." ]; then
mod_suggests="${mod_suggests}, ${x}"
else mod_suggests="${x}"; fi; fi
}
genmodctl_new_mod () {
@ -1108,10 +1170,13 @@ echo "Generating control-modules.gen as sanity check..." >&2
map_modules ':' 'genmodctl_cat' 'genmodctl_mod' \
) > control-modules.gen
echo "Accumulating build dependencies from modules..." >&2
map_modules 'mod_filter' '' 'accumulate_build_depends'
echo "Accumulating dependencies from modules..." >&2
map_modules 'mod_filter' '' 'accumulate_mod_deps'
echo "Generating debian/..." >&2
> control
> freeswitch-all.install
(print_edit_warning; print_mod_overrides "freeswitch-all") \
> freeswitch-all.lintian-overrides
(print_edit_warning; print_source_control; print_core_control) >> control
echo "Generating debian/ (conf)..." >&2
(echo "### conf"; echo) >> control
@ -1125,6 +1190,25 @@ print_edit_warning > modules_.conf
map_modules "mod_filter" \
"gencontrol_per_cat genmodules_per_cat" \
"gencontrol_per_mod geninstall_per_mod genoverrides_per_mod genmodules_per_mod"
echo "Generating debian/ (-all package)..." >&2
grep -e '^Package:' control | grep -v '^freeswitch-all$' | while xread l; do
m="${l#*: }"
f=$m.install
if [ -s $f ]; then
grep -v '^##\|^$' $f | while xread x; do
if ! grep -e "$x" freeswitch-all.install >/dev/null; then
printf '%s\n' "$x" >> freeswitch-all.install
fi
done
fi
done
for x in postinst postrm preinst prerm; do
cp -a freeswitch.$x freeswitch-all.$x
done
cp -a freeswitch-doc.docs freeswitch-all.docs
#cp -a freeswitch-systemd.freeswitch.service freeswitch-all.freeswitch.service
cp -a freeswitch-sysvinit.freeswitch.default freeswitch-all.freeswitch.default
cp -a freeswitch-sysvinit.freeswitch.init freeswitch-all.freeswitch.init
echo "Generating additional lintian overrides..." >&2
grep -e '^Package:' control | while xread l; do

View File

@ -229,7 +229,7 @@ Description: Voicemail detection
Module: applications/mod_voicemail
Description: Voicemail
This module provides a voicemail system.
Depends: mail-transport-agent
Depends: ssmtp | mail-transport-agent
Module: applications/mod_voicemail_ivr
Description: Voicemail IVR
@ -395,10 +395,6 @@ Description: mod_h323
Adds mod_h323.
Build-Depends: libopenh323-dev | libh323plus-dev, libpt-dev
Module: endpoints/mod_html5
Description: HTML5 endpoint module
This module adds support for HTML5 technologies such as WebRTC.
Module: endpoints/mod_khomp
Description: mod_khomp
Adds mod_khomp.

1
debian/copyright vendored
View File

@ -1765,7 +1765,6 @@ License: GPL-2+
Files: src/mod/endpoints/mod_rtmp/rtmp.c
src/mod/endpoints/mod_rtmp/mod_rtmp.[ch]
src/mod/endpoints/mod_rtmp/rtmp_sig.c
src/mod/endpoints/mod_html5/mod_html5.c
src/mod/endpoints/mod_rtmp/rtmp_tcp.c
Copyright: 2011-2012, Barracuda Networks Inc.
License: MPL-1.1

View File

@ -0,0 +1,2 @@
debian/tmp/usr/perl/freeswitch.pm /usr/lib/perl5
debian/tmp/usr/perl/freeswitch.so /usr/lib/perl5/auto/freeswitch

1
debian/rules vendored
View File

@ -104,6 +104,7 @@ override_dh_auto_install:
override_dh_installinit:
dh_installinit -pfreeswitch-sysvinit --name=freeswitch
dh_installinit -pfreeswitch-all --name=freeswitch
debian-bootstrap: debian/.stamp-bootstrap
debian/.stamp-bootstrap:

View File

@ -28,26 +28,34 @@ rm -rf aclocal.m4 libtool.m4 ltsugar.m4 autom4te*.cache
$libtoolize --copy --automake
#
# Build aclocal.m4 from libtool's libtool.m4
# find libtool.m4
#
if [ -f libtool.m4 ]; then
ltfile=libtool.m4
else
if [ ! -f libtool.m4 ]; then
ltpath=`dirname $libtoolize`
ltfile=${LIBTOOL_M4-`cd $ltpath/../share/aclocal ; pwd`/libtool.m4}
if [ -f $ltfile ]; then
echo "libtool.m4 found at $ltfile"
cp $ltfile libtool.m4
else
echo "libtool.m4 not found - aborting!"
exit 1
fi
fi
echo "Incorporating $ltfile into aclocal.m4 ..."
#
# Build aclocal.m4 from libtool's m4 files
#
echo "dnl THIS FILE IS AUTOMATICALLY GENERATED BY buildconf.sh" > aclocal.m4
echo "dnl edits here will be lost" >> aclocal.m4
cat $ltfile >> aclocal.m4
if [ -f ltsugar.m4 ]; then
echo "Incorporating ltsugar.m4 into aclocal.m4 ..."
cat ltsugar.m4 >> aclocal.m4
fi
# Clean up again
rm -f libtool.m4 ltsugar.m4
for m4file in libtool.m4 ltsugar.m4 ltoptions.m4 ltversion.m4 lt~obsolete.m4
do
if [ -f $m4file ]; then
echo "Incorporating $m4file into aclocal.m4 ..."
cat $m4file >> aclocal.m4
rm -f $m4file
fi
done
cross_compile_warning="warning: AC_TRY_RUN called without default to allow cross compiling"

View File

@ -12,6 +12,7 @@ dnl
AC_INIT(Makefile.in)
AC_CONFIG_AUX_DIR(conftools)
AC_CONFIG_MACRO_DIR(.)
dnl
dnl Follow the GNU/Linux convention of odd number minor version for

View File

@ -80,6 +80,15 @@ esac
#set SOLINK variable based on compiler and host
if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then
SOLINK="-Bdynamic -dy -G"
elif test "x${ax_cv_c_compiler_vendor}" = "xclang" ; then
case "$host" in
*darwin*)
SOLINK="-dynamic -bundle -force-flat-namespace"
;;
*)
AC_ERROR([Please update configure.in with SOLINK values for your compiler])
;;
esac
elif test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then
case "$host" in
*darwin*)

View File

@ -1 +1 @@
Fri Sep 20 00:39:20 CDT 2013
Tue Oct 8 23:05:34 CDT 2013

View File

@ -640,15 +640,17 @@ static void print_media(sdp_printer_t *p,
print_key(p, m->m_key);
for (rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
if (!rm->rm_predef || p->pr_all_rtpmaps)
if (rm->rm_encoding && *rm->rm_encoding && (!rm->rm_predef || p->pr_all_rtpmaps)) {
sdp_printf(p, "a=rtpmap:%u %s/%lu%s%s" CRLF,
rm->rm_pt, rm->rm_encoding, rm->rm_rate,
rm->rm_params ? "/" : "",
rm->rm_params ? rm->rm_params : "");
if (rm->rm_fmtp)
}
if (rm->rm_fmtp) {
sdp_printf(p, "a=fmtp:%u %s" CRLF,
rm->rm_pt, rm->rm_fmtp);
}
}
if (!p->pr_mode_manual && !m->m_rejected &&
(m->m_mode != (unsigned int)session_mode || p->pr_mode_always)) {

3
src/mod/.gitignore vendored
View File

@ -36,7 +36,6 @@
/codecs/mod_vp8/Makefile
/dialplans/mod_dialplan_asterisk/Makefile
/dialplans/mod_dialplan_xml/Makefile
/endpoints/mod_html5/mod_html5.log
/endpoints/mod_portaudio/Makefile
/endpoints/mod_portaudio/Makefile.in
/endpoints/mod_portaudio/mod_portaudio.log
@ -49,8 +48,6 @@
/endpoints/mod_sofia/Makefile
/endpoints/mod_sofia/Makefile.in
/endpoints/mod_sofia/mod_sofia.log
/endpoints/mod_html5/Makefile
/endpoints/mod_html5/Makefile.in
/event_handlers/mod_erlang_event/Makefile
/event_handlers/mod_event_socket/Makefile
/formats/mod_native_file/Makefile

View File

@ -1321,11 +1321,11 @@ SWITCH_STANDARD_API(echo_function)
SWITCH_STANDARD_API(stun_function)
{
char *stun_ip = NULL;
char *src_ip = NULL;
switch_port_t stun_port = (switch_port_t) SWITCH_STUN_DEFAULT_PORT;
char *p;
char ip_buf[256] = "";
char *ip = NULL;
char *pip = NULL;
switch_port_t port = 0;
switch_memory_pool_t *pool = NULL;
char *error = "";
@ -1346,7 +1346,7 @@ SWITCH_STANDARD_API(stun_function)
switch_assert(stun_ip);
port = argv[1] ? atoi(argv[1]) : 0;
src_ip = argv[1];
if ((p = strchr(stun_ip, ':'))) {
int iport;
@ -1359,12 +1359,19 @@ SWITCH_STANDARD_API(stun_function)
p = stun_ip;
}
if (p && (pip = strchr(p, ' '))) {
*pip++ = '\0';
if (!zstr(src_ip) && (p = strchr(src_ip, ':'))) {
int iport;
*p++ = '\0';
iport = atoi(p);
if (iport > 0 && iport < 0xFFFF) {
port = (switch_port_t) iport;
}
} else if (!zstr(src_ip)) {
ip = src_ip;
}
if (pip) {
switch_copy_string(ip_buf, pip, sizeof(ip_buf));
if ( !zstr(src_ip) ) {
switch_copy_string(ip_buf, src_ip, sizeof(ip_buf));
} else {
switch_find_local_ip(ip_buf, sizeof(ip_buf), NULL, AF_INET);
}
@ -6150,7 +6157,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
SWITCH_ADD_API(commands_api_interface, "sql_escape", "Escape a string to prevent sql injection", sql_escape, SQL_ESCAPE_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "status", "Show current status", status_function, "");
SWITCH_ADD_API(commands_api_interface, "strftime_tz", "Display formatted time of timezone", strftime_tz_api_function, "<timezone_name> [<epoch>|][format string]");
SWITCH_ADD_API(commands_api_interface, "stun", "Execute STUN lookup", stun_function, "<stun_server>[:port]");
SWITCH_ADD_API(commands_api_interface, "stun", "Execute STUN lookup", stun_function, "<stun_server>[:port] [<source_ip>[:<source_port]]");
SWITCH_ADD_API(commands_api_interface, "system", "Execute a system command", system_function, SYSTEM_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "time_test", "Show time jitter", time_test_function, "<mss> [count]");
SWITCH_ADD_API(commands_api_interface, "timer_test", "Exercise FS timer", timer_test_function, TIMER_TEST_SYNTAX);

View File

@ -283,6 +283,17 @@ struct vid_helper {
int up;
};
struct conference_obj;
/* Record Node */
typedef struct conference_record {
struct conference_obj *conference;
char *path;
switch_memory_pool_t *pool;
switch_bool_t autorec;
struct conference_record *next;
} conference_record_t;
/* Conference Object */
typedef struct conference_obj {
char *name;
@ -348,7 +359,7 @@ typedef struct conference_obj {
int pin_retries;
int broadcast_chat_messages;
int comfort_noise_level;
int is_recording;
int auto_recording;
int record_count;
int video_running;
int ivr_dtmf_timeout;
@ -381,6 +392,7 @@ typedef struct conference_obj {
cdr_event_mode_t cdr_event_mode;
struct vid_helper vh[2];
struct vid_helper mh;
conference_record_t *rec_node_head;
} conference_obj_t;
/* Relationship with another member */
@ -416,6 +428,7 @@ struct conference_member {
switch_codec_t write_codec;
char *rec_path;
switch_time_t rec_time;
conference_record_t *rec;
uint8_t *frame;
uint8_t *last_frame;
uint32_t frame_size;
@ -450,13 +463,6 @@ struct conference_member {
switch_thread_t *input_thread;
};
/* Record Node */
typedef struct conference_record {
conference_obj_t *conference;
char *path;
switch_memory_pool_t *pool;
} conference_record_t;
typedef enum {
CONF_API_SUB_ARGS_SPLIT,
CONF_API_SUB_MEMBER_TARGET,
@ -524,7 +530,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
static switch_status_t chat_send(switch_event_t *message_event);
static void launch_conference_record_thread(conference_obj_t *conference, char *path);
static void launch_conference_record_thread(conference_obj_t *conference, char *path, switch_bool_t autorec);
static int launch_conference_video_bridge_thread(conference_member_t *member_a, conference_member_t *member_b);
static void launch_conference_video_mirror_thread(conference_member_t *member_a);
@ -1211,7 +1217,7 @@ static conference_member_t *conference_member_get(conference_obj_t *conference,
}
/* stop the specified recording */
static switch_status_t conference_record_stop(conference_obj_t *conference, char *path)
static switch_status_t conference_record_stop(conference_obj_t *conference, switch_stream_handle_t *stream, char *path)
{
conference_member_t *member = NULL;
int count = 0;
@ -1220,10 +1226,21 @@ static switch_status_t conference_record_stop(conference_obj_t *conference, char
switch_mutex_lock(conference->member_mutex);
for (member = conference->members; member; member = member->next) {
if (switch_test_flag(member, MFLAG_NOCHANNEL) && (!path || !strcmp(path, member->rec_path))) {
if (member->rec && member->rec->autorec) {
stream->write_function(stream, "Stopped AUTO recording file %s (Auto Recording Now Disabled)\n", member->rec_path);
conference->auto_record = 0;
} else {
stream->write_function(stream, "Stopped recording file %s\n", member->rec_path);
}
switch_clear_flag_locked(member, MFLAG_RUNNING);
count++;
}
}
conference->record_count -= count;
switch_mutex_unlock(conference->member_mutex);
return count;
}
@ -1965,7 +1982,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
globals.threads++;
switch_mutex_unlock(globals.hash_mutex);
conference->is_recording = 0;
conference->auto_recording = 0;
conference->record_count = 0;
@ -2105,15 +2122,15 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
}
/* Start recording if there's more than one participant. */
if (conference->auto_record && !conference->is_recording && conference->count > 1) {
conference->is_recording = 1;
if (conference->auto_record && !conference->auto_recording && conference->count > 1) {
conference->auto_recording++;
conference->record_count++;
imember = conference->members;
if (imember) {
switch_channel_t *channel = switch_core_session_get_channel(imember->session);
char *rfile = switch_channel_expand_variables(channel, conference->auto_record);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Auto recording file: %s\n", rfile);
launch_conference_record_thread(conference, rfile);
launch_conference_record_thread(conference, rfile, SWITCH_TRUE);
if (rfile != conference->auto_record) {
conference->record_filename = switch_core_strdup(conference->pool, rfile);
switch_safe_free(rfile);
@ -3877,7 +3894,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
int16_t *data_buf;
switch_file_handle_t fh = { 0 };
conference_member_t smember = { 0 }, *member;
conference_record_t *rec = (conference_record_t *) obj;
conference_record_t *rp, *last = NULL, *rec = (conference_record_t *) obj;
conference_obj_t *conference = rec->conference;
uint32_t samples = switch_samples_per_packet(conference->rate, conference->interval);
uint32_t mux_used;
@ -3915,7 +3932,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
fh.samplerate = conference->rate;
member->id = next_member_id();
member->pool = rec->pool;
member->rec = rec;
member->frame_size = SWITCH_RECOMMENDED_BUFFER_SIZE;
member->frame = switch_core_alloc(member->pool, member->frame_size);
member->mux_frame = switch_core_alloc(member->pool, member->frame_size);
@ -4058,8 +4075,6 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
switch_mutex_unlock(member->audio_out_mutex);
}
conference->is_recording = 0;
switch_safe_free(data_buf);
switch_core_timer_destroy(&timer);
conference_del_member(conference, member);
@ -4078,6 +4093,23 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
switch_event_fire(&event);
}
if (rec->autorec && conference->auto_recording) {
conference->auto_recording--;
}
switch_mutex_lock(conference->flag_mutex);
for (rp = conference->rec_node_head; rp; rp = rp->next) {
if (rec == rp) {
if (last) {
last->next = rp->next;
} else {
conference->rec_node_head = rp->next;
}
}
}
switch_mutex_unlock(conference->flag_mutex);
if (rec->pool) {
switch_memory_pool_t *pool = rec->pool;
rec = NULL;
@ -6177,11 +6209,20 @@ static switch_status_t conf_api_sub_transfer(conference_obj_t *conference, switc
static switch_status_t conf_api_sub_check_record(conference_obj_t *conference, switch_stream_handle_t *stream, int arc, char **argv)
{
if (conference->is_recording) {
stream->write_function(stream, "Record file %s\n", conference->record_filename);
} else {
conference_record_t *rec;
int x = 0;
switch_mutex_lock(conference->flag_mutex);
for (rec = conference->rec_node_head; rec; rec = rec->next) {
stream->write_function(stream, "Record file %s%s%s\n", rec->path, rec->autorec ? " " : "", rec->autorec ? "(Auto)" : "");
x++;
}
if (!x) {
stream->write_function(stream, "Conference is not being recorded.\n");
}
switch_mutex_unlock(conference->flag_mutex);
return SWITCH_STATUS_SUCCESS;
}
@ -6190,19 +6231,20 @@ static switch_status_t conf_api_sub_record(conference_obj_t *conference, switch_
switch_assert(conference != NULL);
switch_assert(stream != NULL);
if (argc <= 2)
if (argc <= 2) {
return SWITCH_STATUS_GENERR;
}
stream->write_function(stream, "Record file %s\n", argv[2]);
conference->record_filename = switch_core_strdup(conference->pool, argv[2]);
conference->record_count++;
launch_conference_record_thread(conference, argv[2]);
launch_conference_record_thread(conference, argv[2], SWITCH_FALSE);
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t conf_api_sub_norecord(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
{
int all;
int all, before = conference->record_count, ttl = 0;
switch_event_t *event;
switch_assert(conference != NULL);
@ -6212,15 +6254,10 @@ static switch_status_t conf_api_sub_norecord(conference_obj_t *conference, switc
return SWITCH_STATUS_GENERR;
all = (strcasecmp(argv[2], "all") == 0);
stream->write_function(stream, "Stop recording file %s\n", argv[2]);
if (!conference_record_stop(conference, all ? NULL : argv[2]) && !all) {
if (!conference_record_stop(conference, stream, all ? NULL : argv[2]) && !all) {
stream->write_function(stream, "non-existant recording '%s'\n", argv[2]);
} else {
if (all) {
conference->record_count = 0;
} else {
conference->record_count--;
}
if (test_eflag(conference, EFLAG_RECORD) &&
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_add_event_data(conference, event);
@ -6231,6 +6268,9 @@ static switch_status_t conf_api_sub_norecord(conference_obj_t *conference, switc
}
}
ttl = before - conference->record_count;
stream->write_function(stream, "Stopped recording %d file%s\n", ttl, ttl == 1 ? "" : "s");
return SWITCH_STATUS_SUCCESS;
}
@ -6282,6 +6322,13 @@ static switch_status_t conf_api_sub_recording(conference_obj_t *conference, swit
switch_assert(conference != NULL);
switch_assert(stream != NULL);
if (argc > 2 && argc <= 3) {
if (strcasecmp(argv[2], "stop") == 0 || strcasecmp(argv[2], "check") == 0) {
argv[3] = "all";
argc++;
}
}
if (argc <= 3) {
/* It means that old syntax is used */
return conf_api_sub_record(conference,stream,argc,argv);
@ -8023,7 +8070,7 @@ static void launch_conference_video_mirror_thread(conference_member_t *member_a)
launch_thread_detached(conference_video_mirror_thread_run, pool, &conference->mh);
}
static void launch_conference_record_thread(conference_obj_t *conference, char *path)
static void launch_conference_record_thread(conference_obj_t *conference, char *path, switch_bool_t autorec)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
@ -8042,11 +8089,15 @@ static void launch_conference_record_thread(conference_obj_t *conference, char *
return;
}
conference->is_recording = 1;
rec->conference = conference;
rec->path = switch_core_strdup(pool, path);
rec->pool = pool;
rec->autorec = autorec;
switch_mutex_lock(conference->flag_mutex);
rec->next = conference->rec_node_head;
conference->rec_node_head = rec;
switch_mutex_unlock(conference->flag_mutex);
switch_threadattr_create(&thd_attr, rec->pool);
switch_threadattr_detach_set(thd_attr, 1);

View File

@ -283,10 +283,17 @@ SWITCH_STANDARD_APP(clear_digit_action_function)
{
//switch_channel_t *channel = switch_core_session_get_channel(session);
switch_ivr_dmachine_t *dmachine;
char *realm = switch_core_session_strdup(session, data);
char *realm = NULL;
char *target_str;
switch_digit_action_target_t target = DIGIT_TARGET_SELF;
if (zstr((char *)data)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "clear_digit_action called with no args");
return;
}
realm = switch_core_session_strdup(session, data);
if ((target_str = strchr(realm, ','))) {
*target_str++ = '\0';
target = str2target(target_str);
@ -4615,6 +4622,7 @@ static switch_status_t file_string_file_read(switch_file_handle_t *handle, void
return status;
}
static switch_status_t file_string_file_write(switch_file_handle_t *handle, void *data, size_t *len)
{
file_string_context_t *context = handle->private_info;
@ -4633,10 +4641,101 @@ static switch_status_t file_string_file_write(switch_file_handle_t *handle, void
return status;
}
static switch_status_t file_url_file_seek(switch_file_handle_t *handle, unsigned int *cur_sample, int64_t samples, int whence)
{
switch_file_handle_t *fh = handle->private_info;
return switch_core_file_seek(fh, cur_sample, samples, whence);
}
static switch_status_t file_url_file_close(switch_file_handle_t *handle)
{
switch_file_handle_t *fh = handle->private_info;
if (switch_test_flag(fh, SWITCH_FILE_OPEN)) {
switch_core_file_close(fh);
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t file_url_file_read(switch_file_handle_t *handle, void *data, size_t *len)
{
switch_file_handle_t *fh = handle->private_info;
return switch_core_file_read(fh, data, len);
}
static switch_status_t file_url_file_open(switch_file_handle_t *handle, const char *path)
{
switch_file_handle_t *fh = switch_core_alloc(handle->memory_pool, sizeof(*fh));
switch_status_t status;
char *url_host;
char *url_path;
if (zstr(path)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NULL path\n");
return SWITCH_STATUS_FALSE;
}
/* parse and check host */
url_host = switch_core_strdup(handle->memory_pool, path);
if (!(url_path = strchr(url_host, '/'))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing path\n");
return SWITCH_STATUS_FALSE;
}
*url_path = '\0';
/* TODO allow this host */
if (!zstr(url_host) && strcasecmp(url_host, "localhost")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not localhost\n");
return SWITCH_STATUS_FALSE;
}
/* decode and check path */
url_path++;
if (zstr(url_path)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "empty path\n");
return SWITCH_STATUS_FALSE;
}
if (strstr(url_path, "%2f") || strstr(url_path, "%2F")) {
/* don't allow %2f or %2F encoding (/) */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "encoded slash is not allowed\n");
return SWITCH_STATUS_FALSE;
}
url_path = switch_core_sprintf(handle->memory_pool, "/%s", url_path);
switch_url_decode(url_path);
/* TODO convert to native file separators? */
handle->private_info = fh;
status = switch_core_file_open(fh, url_path, handle->channels, handle->samplerate, handle->flags, NULL);
if (status == SWITCH_STATUS_SUCCESS) {
handle->samples = fh->samples;
handle->cur_samplerate = fh->samplerate;
handle->cur_channels = fh->channels;
handle->format = fh->format;
handle->sections = fh->sections;
handle->seekable = fh->seekable;
handle->speed = fh->speed;
handle->interval = fh->interval;
handle->max_samples = 0;
if (switch_test_flag(fh, SWITCH_FILE_NATIVE)) {
switch_set_flag(handle, SWITCH_FILE_NATIVE);
} else {
switch_clear_flag(handle, SWITCH_FILE_NATIVE);
}
}
return status;
}
static switch_status_t file_url_file_write(switch_file_handle_t *handle, void *data, size_t *len)
{
switch_file_handle_t *fh = handle->private_info;
return switch_core_file_write(fh, data, len);
}
/* Registration */
static char *file_string_supported_formats[SWITCH_MAX_CODECS] = { 0 };
static char *file_url_supported_formats[SWITCH_MAX_CODECS] = { 0 };
/* /FILE STRING INTERFACE */
@ -5504,6 +5603,17 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
file_interface->file_write = file_string_file_write;
file_interface->file_seek = file_string_file_seek;
file_url_supported_formats[0] = "file";
file_interface = (switch_file_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
file_interface->interface_name = modname;
file_interface->extens = file_url_supported_formats;
file_interface->file_open = file_url_file_open;
file_interface->file_close = file_url_file_close;
file_interface->file_read = file_url_file_read;
file_interface->file_write = file_url_file_write;
file_interface->file_seek = file_url_file_seek;
error_endpoint_interface = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
error_endpoint_interface->interface_name = "error";

View File

@ -3078,10 +3078,17 @@ static switch_status_t deliver_vm(vm_profile_t *profile,
vm_cc_num = switch_separate_string(vm_cc_dup, ',', vm_cc_list, (sizeof(vm_cc_list) / sizeof(vm_cc_list[0])));
for (vm_cc_i=0; vm_cc_i<vm_cc_num; vm_cc_i++) {
char *cmd, *val;
const char *vm_cc_current = vm_cc_list[vm_cc_i];
char *cmd = switch_mprintf("%s %s %s '%s' %s@%s %s",
val = strdup(caller_id_name);
switch_url_decode(val);
cmd = switch_mprintf("%s %s %s '%s' %s@%s %s",
vm_cc_current, file_path, caller_id_number,
caller_id_name, myid, domain_name, read_flags);
val, myid, domain_name, read_flags);
free(val);
if (voicemail_inject(cmd, session) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Sent Carbon Copy to %s\n", vm_cc_current);

View File

@ -21,12 +21,12 @@ $(MODNAME).lo: $(FLITE_A)
$(FLITE_DIR):
$(GETLIB) $(FLITE)-current.tar.bz2
$(FLITE_BUILDDIR)/Makefile: $(FLITE_DIR)
$(FLITE_BUILDDIR)/.stamp-configure: $(FLITE_DIR)
mkdir -p $(FLITE_BUILDDIR)
cd $(FLITE_BUILDDIR) && $(DEFAULT_VARS) $(FLITE_DIR)/configure $(DEFAULT_ARGS) --srcdir=$(FLITE_DIR) --with-audio=none --with-pic --disable-shared
$(TOUCH_TARGET)
test -f Makefile && touch $@
$(FLITE_A): $(FLITE_DIR) $(FLITE_BUILDDIR)/Makefile
$(FLITE_A): $(FLITE_DIR) $(FLITE_BUILDDIR)/.stamp-configure
cd $(FLITE_BUILDDIR) && $(MAKE) -j1
test -d $(FLITE_LIBDIR) || mkdir $(FLITE_LIBDIR)
TARGET_OS=`grep TARGET_OS $(FLITE_BUILDDIR)/config/config | sed "s/^.*= //"` ;\

View File

@ -15,11 +15,11 @@ install: $(LICSERVER) $(VALIDATOR) $(MOD)
$(LICSERVER) $(VALIDATOR) $(MOD): $(G729INSTALLER)
$(SHELL) $(G729INSTALLER) $(bindir) $(moddir) nobanner
$(ECHO)
$(ECHO)
$(ECHO) Now you can activate your license by running $(MAKE) mod_com_g729-activate
$(ECHO)
$(ECHO)
@echo
@echo
@echo Now you can activate your license by running $(MAKE) mod_com_g729-activate
@echo
@echo
$(G729INSTALLER):
rm -f $(top_srcdir)/libs/fsg729-*-installer*

View File

@ -709,6 +709,10 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
}
tech_pvt->write_frame = (switch_frame_t *) pop;
switch_clear_flag(tech_pvt->write_frame, SFF_RAW_RTP);
tech_pvt->write_frame->timestamp = 0;
tech_pvt->write_frame->codec = &tech_pvt->read_codec;
*frame = tech_pvt->write_frame;
tech_pvt->packet_count++;

View File

@ -718,6 +718,8 @@ struct private_object {
sofia_private_t *sofia_private;
uint8_t flags[TFLAG_MAX];
switch_payload_t agreed_pt;
int channels;
int adv_channels;
switch_payload_t audio_recv_pt;
switch_payload_t video_recv_pt;
switch_core_session_t *session;

View File

@ -39,6 +39,15 @@
switch_cache_db_handle_t *_sofia_glue_get_db_handle(sofia_profile_t *profile, const char *file, const char *func, int line);
#define sofia_glue_get_db_handle(_p) _sofia_glue_get_db_handle(_p, __FILE__, __SWITCH_FUNC__, __LINE__)
static int get_channels(const switch_codec_implementation_t *imp)
{
if (!strcasecmp(imp->iananame, "opus")) {
return 2; /* IKR???*/
}
return imp->number_of_channels;
}
void sofia_glue_set_udptl_image_sdp(private_object_t *tech_pvt, switch_t38_options_t *t38_options, int insist)
{
char buf[2048] = "";
@ -308,8 +317,15 @@ static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen,
}
if (tech_pvt->ianacodes[i] > 95 || verbose_sdp) {
int channels = get_channels(imp);
if (channels > 1) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d %s/%d/%d\n", tech_pvt->ianacodes[i], imp->iananame, rate, channels);
} else {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d %s/%d\n", tech_pvt->ianacodes[i], imp->iananame, rate);
}
}
if (fmtp) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->ianacodes[i], fmtp);
@ -530,7 +546,15 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "\n");
rate = tech_pvt->rm_rate;
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d\n", tech_pvt->agreed_pt, tech_pvt->rm_encoding, rate);
if (tech_pvt->adv_channels > 1) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d/%d\n",
tech_pvt->agreed_pt, tech_pvt->rm_encoding, rate, tech_pvt->adv_channels);
} else {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d\n",
tech_pvt->agreed_pt, tech_pvt->rm_encoding, rate);
}
if (fmtp_out) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->agreed_pt, fmtp_out);
}
@ -735,6 +759,7 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch
const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
char *fmtp = NULL;
uint32_t ianacode = tech_pvt->ianacodes[i];
int channels = 1;
if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
continue;
@ -751,9 +776,15 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch
rate = imp->samples_per_second;
}
channels = get_channels(imp);
if (channels > 1) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d/%d\n", ianacode, imp->iananame,
imp->samples_per_second, channels);
} else {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d\n", ianacode, imp->iananame,
imp->samples_per_second);
}
if (!zstr(ov_fmtp)) {
fmtp = (char *) ov_fmtp;
@ -4414,7 +4445,6 @@ int sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly)
switch_channel_stop_broadcast(b_channel);
switch_channel_wait_for_flag(b_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL);
}
switch_core_session_rwunlock(b_session);
}
sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
@ -5316,6 +5346,23 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
tech_pvt->audio_recv_pt = (switch_payload_t)map->rm_pt;
if (!strcasecmp((char *) map->rm_encoding, "opus")) {
if (tech_pvt->channels == 1) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid SDP for opus. Don't ask.. but it needs a /2\n");
tech_pvt->adv_channels = 1;
} else {
tech_pvt->adv_channels = 2; /* IKR ???*/
}
if (!zstr((char *) map->rm_fmtp) && switch_stristr("stereo=1", (char *) map->rm_fmtp)) {
tech_pvt->channels = 2;
} else {
tech_pvt->channels = 1;
}
} else {
tech_pvt->adv_channels = tech_pvt->channels;
}
if (!switch_true(mirror) &&
switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND &&
(!sofia_test_flag(tech_pvt, TFLAG_REINVITE) || sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_REINVITE))) {

View File

@ -128,6 +128,8 @@ struct rayo_call {
switch_time_t idle_start_time;
/** 1 if joined to call, 2 if joined to mixer */
int joined;
/** pending join */
iks *pending_join_request;
/** ID of joined party TODO this will be many mixers / calls */
const char *joined_id;
/** set if response needs to be sent to IQ request */
@ -937,6 +939,15 @@ static void rayo_call_cleanup(struct rayo_actor *actor)
RAYO_SEND_MESSAGE_DUP(actor, rayo_call_get_dcp_jid(call), revent);
}
/* lost the race: pending join failed... send IQ result to client now. */
if (call->pending_join_request) {
iks *request = call->pending_join_request;
iks *result = iks_new_error_detailed(request, STANZA_ERROR_ITEM_NOT_FOUND, "call ended");
call->pending_join_request = NULL;
RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
iks_delete(call->pending_join_request);
}
iks_delete(revent);
switch_event_destroy(&event);
}
@ -1068,6 +1079,7 @@ static struct rayo_call *rayo_call_init(struct rayo_call *call, switch_memory_po
call->joined = 0;
call->joined_id = NULL;
call->ringing_sent = 0;
call->pending_join_request = NULL;
switch_core_hash_init(&call->pcps, pool);
switch_safe_free(call_jid);
@ -1292,6 +1304,17 @@ static struct rayo_peer_server *rayo_peer_server_create(const char *jid)
return rserver;
}
/**
* Check if message sender has control of offered call.
* @param call the Rayo call
* @param msg the message
* @return 1 if sender has call control, 0 if sender does not have control
*/
static int has_call_control(struct rayo_call *call, struct rayo_message *msg)
{
return (!strcmp(rayo_call_get_dcp_jid(call), msg->from_jid) || is_internal_message(msg) || is_admin_client_message(msg));
}
/**
* Check if message sender has control of offered call. Take control if nobody else does.
* @param call the Rayo call
@ -1299,7 +1322,7 @@ static struct rayo_peer_server *rayo_peer_server_create(const char *jid)
* @param msg the message
* @return 1 if sender has call control
*/
static int has_call_control(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg)
static int take_call_control(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg)
{
int control = 0;
@ -1313,7 +1336,7 @@ static int has_call_control(struct rayo_call *call, switch_core_session_t *sessi
control = 1;
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rayo_call_get_uuid(call)), SWITCH_LOG_INFO, "%s has control of call\n", rayo_call_get_dcp_jid(call));
}
} else if (!strcmp(rayo_call_get_dcp_jid(call), msg->from_jid) || is_internal_message(msg) || is_admin_client_message(msg)) {
} else if (has_call_control(call, msg)) {
control = 1;
}
@ -1358,7 +1381,7 @@ static iks *rayo_call_command_ok(struct rayo_call *call, switch_core_session_t *
if (bad) {
response = iks_new_error(node, STANZA_ERROR_BAD_REQUEST);
} else if (!has_call_control(call, session, msg)) {
} else if (!take_call_control(call, session, msg)) {
response = iks_new_error(node, STANZA_ERROR_CONFLICT);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, %s conflict\n", msg->from_jid, RAYO_JID(call));
}
@ -1711,13 +1734,14 @@ static iks *on_rayo_hangup(struct rayo_actor *call, struct rayo_message *msg, vo
* Join calls together
* @param call the call that joins
* @param session the session
* @param node the join request
* @param msg the rayo join message
* @param call_uri to join
* @param media mode (direct/bridge)
* @return the response
*/
static iks *join_call(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *call_uri, const char *media)
static iks *join_call(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg, const char *call_uri, const char *media)
{
iks *node = msg->payload;
iks *response = NULL;
/* take call out of media path if media = "direct" */
const char *bypass = !strcmp("direct", media) ? "true" : "false";
@ -1727,6 +1751,9 @@ static iks *join_call(struct rayo_call *call, switch_core_session_t *session, ik
if (!b_call) {
/* not a rayo call */
response = iks_new_error_detailed(node, STANZA_ERROR_SERVICE_UNAVAILABLE, "b-leg is not a rayo call");
} else if (!has_call_control(b_call, msg)) {
/* not allowed to join to this call */
response = iks_new_error(node, STANZA_ERROR_NOT_ALLOWED);
} else if (b_call->joined) {
/* don't support multiple joined calls */
response = iks_new_error_detailed(node, STANZA_ERROR_CONFLICT, "multiple joined calls not supported");
@ -1737,10 +1764,13 @@ static iks *join_call(struct rayo_call *call, switch_core_session_t *session, ik
if (switch_false(bypass)) {
switch_channel_pre_answer(switch_core_session_get_channel(session));
}
if (switch_ivr_uuid_bridge(rayo_call_get_uuid(call), rayo_call_get_uuid(b_call)) == SWITCH_STATUS_SUCCESS) {
response = iks_new_iq_result(node);
} else {
response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to bridge call");
call->pending_join_request = iks_copy(node);
if (switch_ivr_uuid_bridge(rayo_call_get_uuid(call), rayo_call_get_uuid(b_call)) != SWITCH_STATUS_SUCCESS) {
iks *request = call->pending_join_request;
iks *result = iks_new_error_detailed(request, STANZA_ERROR_ITEM_NOT_FOUND, "failed to bridge call");
call->pending_join_request = NULL;
RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
iks_delete(call->pending_join_request);
}
RAYO_UNLOCK(b_call);
}
@ -1749,40 +1779,99 @@ static iks *join_call(struct rayo_call *call, switch_core_session_t *session, ik
/**
* Execute command on session's conference
* @param session to execute conference API on
* @param conf_name of conference
* @param command to send to conference
* @param node IQ request
* @return response on failure
*/
static void exec_conference_api(switch_core_session_t *session, const char *conf_name, const char *command)
static iks *exec_conference_api(switch_core_session_t *session, const char *conf_name, const char *command, iks *node)
{
iks *response = NULL;
switch_stream_handle_t stream = { 0 };
const char *conf_member_id = switch_channel_get_variable(switch_core_session_get_channel(session), "conference_member_id");
SWITCH_STANDARD_STREAM(stream);
switch_api_execute("conference", switch_core_session_sprintf(session, "%s %s %s", conf_name, command, conf_member_id), NULL, &stream);
if (!zstr(stream.data) && strncmp("OK", stream.data, 2)) {
response = iks_new_error_detailed_printf(node, STANZA_ERROR_SERVICE_UNAVAILABLE, "%s", stream.data);
}
switch_safe_free(stream.data);
return response;
}
/**
* Execute conference app on session
* @param session to execute conference API on
* @param command to send to conference (conference name, member flags, etc)
* @param node IQ request
* @return response on failure
*/
static iks *exec_conference_app(switch_core_session_t *session, const char *command, iks *node)
{
iks *response = NULL;
switch_event_t *execute_event = NULL;
switch_channel_t *channel = switch_core_session_get_channel(session);
/* conference requires local media on channel */
if (!switch_channel_media_ready(channel) && switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
/* shit */
response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to start media");
return response;
}
/* send execute conference event to session */
if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute");
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", "conference");
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", command);
//switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event_uuid", uuid);
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true");
if (!switch_channel_test_flag(channel, CF_PROXY_MODE)) {
switch_channel_set_flag(channel, CF_BLOCK_BROADCAST_UNTIL_MEDIA);
}
if (switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to join mixer (queue event failed)");
if (execute_event) {
switch_event_destroy(&execute_event);
}
return response;
}
}
return response;
}
/**
* Join call to a mixer
* @param call the call that joins
* @param session the session
* @param node the join request
* @param msg the join request
* @param mixer_name the mixer to join
* @param direction the media direction
* @return the response
*/
static iks *join_mixer(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *mixer_name, const char *direction)
static iks *join_mixer(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg, const char *mixer_name, const char *direction)
{
iks *node = msg->payload;
iks *response = NULL;
if (call->joined_id) {
/* adjust join conference params */
if (!strcmp("duplex", direction)) {
exec_conference_api(session, mixer_name, "unmute");
exec_conference_api(session, mixer_name, "undeaf");
if ((response = exec_conference_api(session, mixer_name, "unmute", node)) ||
(response = exec_conference_api(session, mixer_name, "undeaf", node))) {
return response;
}
} else if (!strcmp("recv", direction)) {
exec_conference_api(session, mixer_name, "mute");
exec_conference_api(session, mixer_name, "undeaf");
if ((response = exec_conference_api(session, mixer_name, "mute", node)) ||
(response = exec_conference_api(session, mixer_name, "undeaf", node))) {
return response;
}
} else {
exec_conference_api(session, mixer_name, "unmute");
exec_conference_api(session, mixer_name, "deaf");
if ((response = exec_conference_api(session, mixer_name, "unmute", node)) ||
(response = exec_conference_api(session, mixer_name, "deaf", node))) {
return response;
}
}
response = iks_new_iq_result(node);
} else {
@ -1793,10 +1882,12 @@ static iks *join_mixer(struct rayo_call *call, switch_core_session_t *session, i
} else if (!strcmp("recv", direction)) {
conf_args = switch_core_session_sprintf(session, "%s+flags{mute}", conf_args);
}
if (switch_core_session_execute_application_async(session, "conference", conf_args) == SWITCH_STATUS_SUCCESS) {
response = iks_new_iq_result(node);
} else {
response = iks_new_error_detailed(node, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed execute conference app");
call->pending_join_request = iks_copy(node);
response = exec_conference_app(session, conf_args, node);
if (response) {
iks_delete(call->pending_join_request);
call->pending_join_request = NULL;
}
}
return response;
@ -1806,14 +1897,13 @@ static iks *join_mixer(struct rayo_call *call, switch_core_session_t *session, i
* Handle <iq><join> request
* @param call the Rayo call
* @param session the session
* @param node the <iq> node
* @param msg the rayo join message
*/
static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
{
iks *node = msg->payload;
switch_core_session_t *session = (switch_core_session_t *)session_data;
iks *response = NULL;
iks *join = iks_find(node, "join");
iks *join = iks_find(msg->payload, "join");
const char *join_id;
const char *mixer_name;
const char *call_uri;
@ -1821,7 +1911,7 @@ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void
/* validate input attributes */
if (!VALIDATE_RAYO_JOIN(join)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Bad join attrib\n");
response = iks_new_error(node, STANZA_ERROR_BAD_REQUEST);
response = iks_new_error(msg->payload, STANZA_ERROR_BAD_REQUEST);
goto done;
}
mixer_name = iks_find_attrib(join, "mixer-name");
@ -1835,29 +1925,35 @@ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void
/* can't join both mixer and call */
if (!zstr(mixer_name) && !zstr(call_uri)) {
response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "mixer-name and call-uri are mutually exclusive");
response = iks_new_error_detailed(msg->payload, STANZA_ERROR_BAD_REQUEST, "mixer-name and call-uri are mutually exclusive");
goto done;
}
/* need to join *something* */
if (zstr(mixer_name) && zstr(call_uri)) {
response = iks_new_error_detailed(node, STANZA_ERROR_BAD_REQUEST, "mixer-name or call-uri is required");
response = iks_new_error_detailed(msg->payload, STANZA_ERROR_BAD_REQUEST, "mixer-name or call-uri is required");
goto done;
}
if ((RAYO_CALL(call)->joined == JOINED_CALL) ||
(RAYO_CALL(call)->joined == JOINED_MIXER && strcmp(RAYO_CALL(call)->joined_id, join_id))) {
/* already joined */
response = iks_new_error_detailed(node, STANZA_ERROR_CONFLICT, "call is already joined");
response = iks_new_error_detailed(msg->payload, STANZA_ERROR_CONFLICT, "call is already joined");
goto done;
}
if (RAYO_CALL(call)->pending_join_request) {
/* don't allow concurrent join requests */
response = iks_new_error_detailed(msg->payload, STANZA_ERROR_UNEXPECTED_REQUEST, "(un)join request is pending");
goto done;
}
if (!zstr(mixer_name)) {
/* join conference */
response = join_mixer(RAYO_CALL(call), session, node, mixer_name, iks_find_attrib(join, "direction"));
response = join_mixer(RAYO_CALL(call), session, msg, mixer_name, iks_find_attrib(join, "direction"));
} else {
/* bridge calls */
response = join_call(RAYO_CALL(call), session, node, call_uri, iks_find_attrib(join, "media"));
response = join_call(RAYO_CALL(call), session, msg, call_uri, iks_find_attrib(join, "media"));
}
done:
@ -1868,20 +1964,18 @@ done:
* unjoin call to a bridge
* @param call the call that unjoined
* @param session the session
* @param node the unjoin request
* @param msg the unjoin request
* @param call_uri the b-leg xmpp URI
* @return the response
*/
static iks *unjoin_call(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *call_uri)
static iks *unjoin_call(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg, const char *call_uri)
{
iks *node = msg->payload;
iks *response = NULL;
const char *bleg_uuid = switch_channel_get_variable(switch_core_session_get_channel(session), SWITCH_BRIDGE_UUID_VARIABLE);
const char *bleg_uri = switch_core_session_sprintf(session, "xmpp:%s@%s", bleg_uuid ? bleg_uuid : "", RAYO_JID(globals.server));
/* bleg must match call_uri */
if (!zstr(bleg_uri) && !strcmp(bleg_uri, call_uri)) {
if (!strcmp(call_uri, call->joined_id)) {
/* unbridge call */
response = iks_new_iq_result(node);
call->pending_join_request = iks_copy(node);
switch_ivr_park_session(session);
} else {
/* not bridged or wrong b-leg URI */
@ -1895,15 +1989,16 @@ static iks *unjoin_call(struct rayo_call *call, switch_core_session_t *session,
* unjoin call to a mixer
* @param call the call that unjoined
* @param session the session
* @param node the unjoin request
* @param msg the unjoin request
* @param mixer_name the mixer name
* @return the response
*/
static iks *unjoin_mixer(struct rayo_call *call, switch_core_session_t *session, iks *node, const char *mixer_name)
static iks *unjoin_mixer(struct rayo_call *call, switch_core_session_t *session, struct rayo_message *msg, const char *mixer_name)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
const char *conf_member_id = switch_channel_get_variable(channel, "conference_member_id");
const char *conf_name = switch_channel_get_variable(channel, "conference_name");
iks *node = msg->payload;
iks *response = NULL;
/* not conferenced, or wrong conference */
@ -1916,11 +2011,12 @@ static iks *unjoin_mixer(struct rayo_call *call, switch_core_session_t *session,
goto done;
}
/* kick the member */
response = exec_conference_api(session, mixer_name, "hup", node);
if (!response) {
/* ack command */
response = iks_new_iq_result(node);
/* kick the member */
exec_conference_api(session, mixer_name, "hup");
}
done:
@ -1935,31 +2031,39 @@ done:
*/
static iks *on_rayo_unjoin(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
{
iks *node = msg->payload;
switch_core_session_t *session = (switch_core_session_t *)session_data;
iks *response = NULL;
iks *unjoin = iks_find(node, "unjoin");
iks *unjoin = iks_find(msg->payload, "unjoin");
const char *call_uri = iks_find_attrib(unjoin, "call-uri");
const char *mixer_name = iks_find_attrib(unjoin, "mixer-name");
if (!zstr(call_uri) && !zstr(mixer_name)) {
response = iks_new_error(node, STANZA_ERROR_BAD_REQUEST);
response = iks_new_error(msg->payload, STANZA_ERROR_BAD_REQUEST);
} else if (RAYO_CALL(call)->pending_join_request) {
/* need to let pending request finish first */
response = iks_new_error_detailed(msg->payload, STANZA_ERROR_UNEXPECTED_REQUEST, "(un)join request is pending");
} else if (!RAYO_CALL(call)->joined) {
/* not joined to anything */
response = iks_new_error(node, STANZA_ERROR_SERVICE_UNAVAILABLE);
response = iks_new_error_detailed(msg->payload, STANZA_ERROR_SERVICE_UNAVAILABLE, "not joined to anything");
} else if (RAYO_CALL(call)->joined == JOINED_MIXER && !zstr(call_uri)) {
/* joined to mixer, not call */
response = iks_new_error_detailed(msg->payload, STANZA_ERROR_SERVICE_UNAVAILABLE, "not joined to call");
} else if (RAYO_CALL(call)->joined == JOINED_CALL && !zstr(mixer_name)) {
/* joined to call, not mixer */
response = iks_new_error_detailed(msg->payload, STANZA_ERROR_SERVICE_UNAVAILABLE, "not joined to mixer");
} else if (!zstr(call_uri)) {
response = unjoin_call(RAYO_CALL(call), session, node, call_uri);
response = unjoin_call(RAYO_CALL(call), session, msg, call_uri);
} else if (!zstr(mixer_name)) {
response = unjoin_mixer(RAYO_CALL(call), session, node, mixer_name);
response = unjoin_mixer(RAYO_CALL(call), session, msg, mixer_name);
} else {
/* unjoin everything */
if (RAYO_CALL(call)->joined == JOINED_MIXER) {
response = unjoin_mixer(RAYO_CALL(call), session, node, RAYO_CALL(call)->joined_id);
response = unjoin_mixer(RAYO_CALL(call), session, msg, RAYO_CALL(call)->joined_id);
} else if (RAYO_CALL(call)->joined == JOINED_CALL) {
response = unjoin_call(RAYO_CALL(call), session, node, RAYO_CALL(call)->joined_id);
response = unjoin_call(RAYO_CALL(call), session, msg, RAYO_CALL(call)->joined_id);
} else {
/* shouldn't happen */
response = iks_new_error(node, STANZA_ERROR_INTERNAL_SERVER_ERROR);
response = iks_new_error(msg->payload, STANZA_ERROR_INTERNAL_SERVER_ERROR);
}
}
@ -2501,6 +2605,15 @@ static void on_mixer_add_member_event(struct rayo_mixer *mixer, switch_event_t *
call->joined = JOINED_MIXER;
call->joined_id = switch_core_strdup(RAYO_POOL(call), rayo_mixer_get_name(mixer));
/* send IQ result to client now. */
if (call->pending_join_request) {
iks *request = call->pending_join_request;
iks *result = iks_new_iq_result(request);
call->pending_join_request = NULL;
RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
iks_delete(request);
}
/* send mixer joined event to member DCP */
add_member_event = iks_new_presence("joined", RAYO_NS, RAYO_JID(call), call->dcp_jid);
x = iks_find(add_member_event, "joined");
@ -2661,31 +2774,53 @@ static void on_call_bridge_event(struct rayo_client *rclient, switch_event_t *ev
struct rayo_call *b_call;
if (call) {
/* send A-leg event */
iks *revent = iks_new_presence("joined", RAYO_NS,
switch_event_get_header(event, "variable_rayo_call_jid"),
switch_event_get_header(event, "variable_rayo_dcp_jid"));
iks *joined = iks_find(revent, "joined");
iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server));
iks *revent;
iks *joined;
call->joined = JOINED_CALL;
call->joined_id = switch_core_strdup(RAYO_POOL(call), b_uuid);
call->joined_id = switch_core_sprintf(RAYO_POOL(call), "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server));
RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
/* send IQ result to client now. */
if (call->pending_join_request) {
iks *request = call->pending_join_request;
iks *result = iks_new_iq_result(request);
call->pending_join_request = NULL;
RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
iks_delete(request);
}
/* send B-leg event */
b_call = RAYO_CALL_LOCATE_BY_ID(b_uuid);
if (b_call) {
b_call->joined = JOINED_CALL;
b_call->joined_id = switch_core_sprintf(RAYO_POOL(b_call), "xmpp:%s@s", a_uuid, RAYO_JID(globals.server));
/* send IQ result to client now. */
if (b_call->pending_join_request) {
iks *request = b_call->pending_join_request;
iks *result = iks_new_iq_result(request);
b_call->pending_join_request = NULL;
RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
iks_delete(request);
}
/* send B-leg event */
revent = iks_new_presence("joined", RAYO_NS, RAYO_JID(b_call), rayo_call_get_dcp_jid(b_call));
joined = iks_find(revent, "joined");
iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", a_uuid, RAYO_JID(globals.server));
b_call->joined = JOINED_CALL;
b_call->joined_id = switch_core_strdup(RAYO_POOL(b_call), a_uuid);
RAYO_SEND_MESSAGE(b_call, rayo_call_get_dcp_jid(b_call), revent);
RAYO_UNLOCK(b_call);
}
/* send A-leg event */
revent = iks_new_presence("joined", RAYO_NS,
switch_event_get_header(event, "variable_rayo_call_jid"),
switch_event_get_header(event, "variable_rayo_dcp_jid"));
joined = iks_find(revent, "joined");
iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server));
RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
RAYO_UNLOCK(call);
}
}
@ -2703,33 +2838,85 @@ static void on_call_unbridge_event(struct rayo_client *rclient, switch_event_t *
struct rayo_call *b_call;
if (call) {
/* send A-leg event */
iks *revent = iks_new_presence("unjoined", RAYO_NS,
switch_event_get_header(event, "variable_rayo_call_jid"),
switch_event_get_header(event, "variable_rayo_dcp_jid"));
iks *joined = iks_find(revent, "unjoined");
iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server));
RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
iks *revent;
iks *joined;
call->joined = 0;
call->joined_id = NULL;
/* send B-leg event */
/* send IQ result to client now. */
if (call->pending_join_request) {
iks *request = call->pending_join_request;
iks *result = iks_new_iq_result(request);
call->pending_join_request = NULL;
RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result);
iks_delete(request);
}
b_call = RAYO_CALL_LOCATE_BY_ID(b_uuid);
if (b_call) {
b_call->joined = 0;
b_call->joined_id = NULL;
/* send IQ result to client now. */
if (b_call->pending_join_request) {
iks *request = b_call->pending_join_request;
iks *result = iks_new_iq_result(request);
b_call->pending_join_request = NULL;
RAYO_SEND_REPLY(b_call, iks_find_attrib_soft(request, "from"), result);
iks_delete(request);
}
/* send B-leg event */
revent = iks_new_presence("unjoined", RAYO_NS, RAYO_JID(b_call), rayo_call_get_dcp_jid(b_call));
joined = iks_find(revent, "unjoined");
iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", a_uuid, RAYO_JID(globals.server));
RAYO_SEND_MESSAGE(b_call, rayo_call_get_dcp_jid(b_call), revent);
b_call->joined = 0;
b_call->joined_id = NULL;
RAYO_UNLOCK(b_call);
}
/* send A-leg event */
revent = iks_new_presence("unjoined", RAYO_NS,
switch_event_get_header(event, "variable_rayo_call_jid"),
switch_event_get_header(event, "variable_rayo_dcp_jid"));
joined = iks_find(revent, "unjoined");
iks_insert_attrib_printf(joined, "call-uri", "xmpp:%s@%s", b_uuid, RAYO_JID(globals.server));
RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent);
RAYO_UNLOCK(call);
}
}
/**
* Handle call execute application event
* @param rclient the Rayo client
* @param event the execute event
*/
static void on_call_execute_event(struct rayo_client *rclient, switch_event_t *event)
{
struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
if (call) {
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_ID(call)), SWITCH_LOG_DEBUG, "Application %s execute\n", switch_event_get_header(event, "Application"));
RAYO_UNLOCK(call);
}
}
/**
* Handle call execute application complete event
* @param rclient the Rayo client
* @param event the execute complete event
*/
static void on_call_execute_complete_event(struct rayo_client *rclient, switch_event_t *event)
{
struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID"));
if (call) {
const char *app = switch_event_get_header(event, "Application");
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_ID(call)), SWITCH_LOG_DEBUG, "Application %s execute complete: %s \n",
app,
switch_event_get_header(event, "Application-Response"));
RAYO_UNLOCK(call);
}
}
/**
* Handle events to deliver to client connection
@ -2756,6 +2943,12 @@ static void rayo_client_handle_event(struct rayo_client *rclient, switch_event_t
case SWITCH_EVENT_CHANNEL_UNBRIDGE:
on_call_unbridge_event(rclient, event);
break;
case SWITCH_EVENT_CHANNEL_EXECUTE:
on_call_execute_event(rclient, event);
break;
case SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE:
on_call_execute_complete_event(rclient, event);
break;
default:
/* don't care */
break;
@ -2881,7 +3074,9 @@ static switch_status_t rayo_call_on_read_frame(switch_core_session_t *session, s
switch_time_t idle_start = call->idle_start_time;
int idle_duration_ms = (now - idle_start) / 1000;
/* detect idle session (rayo-client has stopped controlling call) and terminate call */
if (!rayo_call_is_joined(call) && idle_duration_ms > globals.max_idle_ms) {
if (rayo_call_is_joined(call)) {
call->idle_start_time = now;
} else if (idle_duration_ms > globals.max_idle_ms) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Ending abandoned call. idle_duration_ms = %i ms\n", idle_duration_ms);
switch_channel_hangup(channel, RAYO_CAUSE_HANGUP);
}
@ -2974,8 +3169,9 @@ done:
if (ok) {
switch_channel_set_variable(channel, "hangup_after_bridge", "false");
switch_channel_set_variable(channel, "transfer_after_bridge", "false");
switch_channel_set_variable(channel, "transfer_after_bridge", "");
switch_channel_set_variable(channel, "park_after_bridge", "true");
switch_channel_set_variable(channel, "hold_hangup_xfer_exten", "foo"); /* Icky hack to prevent unjoin of call on hold from hanging up b-leg. park_after_bridge will take precedence over the transfer_after_bridge variable that gets set by this var */
switch_channel_set_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE, "-1"); /* required so that output mixing works */
switch_core_event_hook_add_read_frame(session, rayo_call_on_read_frame);
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
@ -3828,6 +4024,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_rayo_load)
switch_event_bind(modname, SWITCH_EVENT_CHANNEL_ANSWER, NULL, route_call_event, NULL);
switch_event_bind(modname, SWITCH_EVENT_CHANNEL_BRIDGE, NULL, route_call_event, NULL);
switch_event_bind(modname, SWITCH_EVENT_CHANNEL_UNBRIDGE, NULL, route_call_event, NULL);
switch_event_bind(modname, SWITCH_EVENT_CHANNEL_EXECUTE, NULL, route_call_event, NULL);
switch_event_bind(modname, SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE, NULL, route_call_event, NULL);
switch_event_bind(modname, SWITCH_EVENT_CHANNEL_DESTROY, NULL, on_call_end_event, NULL);

View File

@ -692,11 +692,14 @@ static int get_file_from_macro(struct ssml_parser *parsed_data, char *to_say)
static int get_file_from_voice(struct ssml_parser *parsed_data, char *to_say)
{
struct ssml_node *cur_node = parsed_data->cur_node;
if (cur_node->tts_voice) {
char *file = switch_core_sprintf(parsed_data->pool, "%s%s", cur_node->tts_voice->prefix, to_say);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding <%s>: \"%s\"\n", cur_node->tag_name, file);
parsed_data->files[parsed_data->num_files].name = file;
parsed_data->files[parsed_data->num_files++].prefix = NULL;
return 1;
}
return 0;
}
/**
@ -708,7 +711,7 @@ static int process_cdata_tts(struct ssml_parser *parsed_data, char *data, size_t
if (!len) {
return IKS_OK;
}
if (cur_node && cur_node->tts_voice && parsed_data->num_files < parsed_data->max_files) {
if (cur_node && parsed_data->num_files < parsed_data->max_files) {
int i = 0;
int empty = 1;
char *to_say;
@ -728,7 +731,9 @@ static int process_cdata_tts(struct ssml_parser *parsed_data, char *data, size_t
to_say[len] = '\0';
if (!cur_node->say_macro || !get_file_from_macro(parsed_data, to_say)) {
/* use voice instead */
get_file_from_voice(parsed_data, to_say);
if (!get_file_from_voice(parsed_data, to_say)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No TTS voices available to render text!\n");
}
}
free(to_say);
return IKS_OK;

View File

@ -2600,7 +2600,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void)
switch_nat_shutdown();
}
switch_xml_destroy();
switch_core_session_uninit();
switch_console_shutdown();
switch_channel_global_uninit();
@ -2610,6 +2609,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Finalizing Shutdown.\n");
switch_log_shutdown();
switch_core_session_uninit();
switch_core_unset_variables();
switch_core_memory_stop();

View File

@ -2480,8 +2480,8 @@ void switch_core_session_init(switch_memory_pool_t *pool)
switch_queue_create(&session_manager.thread_queue, 100000, session_manager.memory_pool);
switch_threadattr_create(&thd_attr, session_manager.memory_pool);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&session_manager.manager_thread, thd_attr, switch_core_session_thread_pool_manager, NULL, session_manager.memory_pool);
session_manager.ready = 1;
switch_thread_create(&session_manager.manager_thread, thd_attr, switch_core_session_thread_pool_manager, NULL, session_manager.memory_pool);
}
}
@ -2491,16 +2491,17 @@ void switch_core_session_uninit(void)
int sanity = 100;
switch_status_t st = SWITCH_STATUS_FALSE;
switch_core_hash_destroy(&session_manager.session_table);
session_manager.ready = 0;
switch_thread_join(&st, session_manager.manager_thread);
wake_queue();
while(session_manager.running && --sanity > 0) {
switch_queue_interrupt_all(session_manager.thread_queue);
switch_yield(100000);
}
switch_thread_join(&st, session_manager.manager_thread);
switch_core_hash_destroy(&session_manager.session_table);
}
SWITCH_DECLARE(switch_app_log_t *) switch_core_session_get_app_log(switch_core_session_t *session)

View File

@ -2777,7 +2777,7 @@ static void do_2833(switch_rtp_t *rtp_session, switch_core_session_t *session)
rtp_session->dtmf_data.out_digit_dur = rdigit->duration;
rtp_session->dtmf_data.out_digit = rdigit->digit;
rtp_session->dtmf_data.out_digit_packet[0] = (unsigned char) switch_char_to_rfc2833(rdigit->digit);
rtp_session->dtmf_data.out_digit_packet[1] = 7;
rtp_session->dtmf_data.out_digit_packet[1] = 13;
rtp_session->dtmf_data.out_digit_packet[2] = (unsigned char) (rtp_session->dtmf_data.out_digit_sub_sofar >> 8);
rtp_session->dtmf_data.out_digit_packet[3] = (unsigned char) rtp_session->dtmf_data.out_digit_sub_sofar;

82
support-d/gl Executable file
View File

@ -0,0 +1,82 @@
#!/usr/bin/perl
my $pager = `which less` || `which more`;
my $tmpdir = "/tmp/FSJIRA";
system("mkdir -p $tmpdir");
my $cmd = "git log " . join(" ", @ARGV);
open(CMD, "$cmd |");
open(PAGER, "|$pager");
select PAGER;
while(my $line = <CMD>) {
print $line;
if ($line =~ /([A-Z]+\-[0-9]+)/) {
my $bug = $1;
my $txt = bugtxt($bug);
if ($txt) {
print "=" x 80 . "\n";
print $txt;
print "=" x 80 . "\n";
}
}
}
close(CMD);
close(PAGER);
sub catfile($) {
my $file = shift;
open(I, $file) or return;
$/ = undef;
my $txt = <I>;
$/ = "\n";
close(I);
return $txt;
}
sub bugtxt($)
{
my $bug = shift or return "";
my $now = time;
my $tmp;
$bug =~ s/\.\.//g;
$bug =~ s/^\///g;
$bug =~ s/~//g;
$bug =~ s/[^a-zA-Z0-9\-]//g;
$tmp = "$tmpdir/$bug.txt";
if(-f $tmp) {
return catfile($tmp);
}
my $cmd = "wget -q http://jira.freeswitch.org/si/jira.issueviews:issue-xml/$bug/$bug.xml -O $tmp";
system($cmd);
my $txt = catfile($tmp);
my ($a,$title) = $txt =~ /\<title\>(.*?)\<\/title\>/smg;
my ($status) = $txt =~ /\<status.*?\>(.*?)\<\/status\>/smg;
my ($a,$des) = $txt =~ /\<description\>(.*?)\<\/description\>/smg;
my ($alogin, $aname) = $txt =~ /\<assignee username=\"([^\"]+)\"\>(.*?)\<\/assignee\>/smg;
my ($rlogin, $rname) = $txt =~ /\<reporter username=\"([^\"]+)\"\>(.*?)\<\/reporter\>/smg;
if ($rname && $aname) {
my $data = "$title\nReporter: $rname [$rlogin]\nAssignee: $aname [$alogin]\nStatus: $status\nhttp://jira.freeswitch.org/browse/$bug\n";
open(O, ">$tmp");
print O $data;
close(O);
return $data;
} else {
unlink($tmp);
}
}