[Pkg-voip-commits] [pjproject] 01/10: New upstream version 2.7~dfsg
Bernhard Schmidt
berni at moszumanska.debian.org
Thu Oct 5 21:38:12 UTC 2017
This is an automated email from the git hooks/post-receive script.
berni pushed a commit to branch master
in repository pjproject.
commit 59b652f7449a8c9b17291d78125c0a5c4ff8e022
Author: Bernhard Schmidt <berni at debian.org>
Date: Thu Oct 5 13:53:21 2017 +0200
New upstream version 2.7~dfsg
---
aconfigure | 226 ++-
aconfigure.ac | 124 +-
build.mak.in | 5 +-
.../vs/pjproject-vs14-win32-common-defaults.props | 5 +-
.../vs/pjproject-vs14-win64-common-defaults.props | 5 +-
configure-android | 66 +-
configure-iphone | 11 +-
pjlib-util/include/pjlib-util/stun_simple.h | 7 +-
pjlib-util/src/pjlib-util/base64.c | 12 +-
pjlib-util/src/pjlib-util/cli_telnet.c | 5 +-
pjlib-util/src/pjlib-util/pcap.c | 4 +-
pjlib-util/src/pjlib-util/resolver.c | 6 +-
pjlib-util/src/pjlib-util/srv_resolver.c | 28 +-
pjlib-util/src/pjlib-util/stun_simple_client.c | 17 +-
pjlib-util/src/pjlib-util/xml.c | 3 +-
pjlib/include/pj/compat/ctype.h | 6 +-
pjlib/include/pj/config.h | 34 +-
pjlib/include/pj/ctype.h | 4 +-
pjlib/include/pj/sock.h | 20 +-
pjlib/src/pj/guid_android.c | 9 +-
pjlib/src/pj/hash.c | 7 +-
pjlib/src/pj/log.c | 6 +-
pjlib/src/pj/os_info.c | 5 +-
pjlib/src/pj/os_timestamp_posix.c | 18 +-
pjlib/src/pj/sock_bsd.c | 5 +-
pjlib/src/pj/sock_common.c | 81 +-
pjlib/src/pj/sock_qos_bsd.c | 4 +-
pjlib/src/pj/sock_qos_darwin.c | 4 +-
pjlib/src/pj/ssl_sock_dump.c | 4 +-
pjlib/src/pj/ssl_sock_ossl.c | 230 +++-
pjlib/src/pjlib-test/exception.c | 8 +-
pjmedia/build/Makefile | 4 +-
pjmedia/build/os-auto.mak.in | 18 +-
pjmedia/build/pjmedia.vcproj | 1320 ++++++++++--------
pjmedia/build/pjmedia_codec.vcxproj | 7 +-
pjmedia/build/pjmedia_codec.vcxproj.filters | 6 +
pjmedia/include/pjmedia-codec.h | 4 +-
pjmedia/include/pjmedia-codec/bcg729.h | 121 ++
pjmedia/include/pjmedia-codec/config.h | 54 +-
pjmedia/include/pjmedia-codec/config_auto.h.in | 7 +-
pjmedia/include/pjmedia-codec/h264_packetizer.h | 9 +-
pjmedia/include/pjmedia-codec/types.h | 10 +-
pjmedia/include/pjmedia-codec/vid_toolbox.h | 71 +
pjmedia/include/pjmedia/config.h | 61 +-
pjmedia/include/pjmedia/errno.h | 20 +-
pjmedia/include/pjmedia/transport_ice.h | 50 +-
pjmedia/include/pjmedia/transport_srtp.h | 160 ++-
pjmedia/src/pjmedia-audiodev/alsa_dev.c | 83 +-
pjmedia/src/pjmedia-codec/audio_codecs.c | 9 +-
pjmedia/src/pjmedia-codec/bcg729.c | 622 +++++++++
pjmedia/src/pjmedia-codec/h264_packetizer.c | 37 +-
pjmedia/src/pjmedia-codec/l16.c | 11 +-
pjmedia/src/pjmedia-codec/opus.c | 11 +-
pjmedia/src/pjmedia-codec/vid_toolbox.m | 1263 +++++++++++++++++
pjmedia/src/pjmedia-videodev/colorbar_dev.c | 5 +-
pjmedia/src/pjmedia-videodev/darwin_dev.m | 16 +-
pjmedia/src/pjmedia-videodev/dshow_dev.c | 8 +-
pjmedia/src/pjmedia/avi_player.c | 6 +-
pjmedia/src/pjmedia/echo_webrtc.c | 7 +-
pjmedia/src/pjmedia/errno.c | 7 +-
pjmedia/src/pjmedia/format.c | 4 +-
pjmedia/src/pjmedia/sdp_neg.c | 30 +-
pjmedia/src/pjmedia/stream_info.c | 4 +-
pjmedia/src/pjmedia/transport_ice.c | 171 ++-
pjmedia/src/pjmedia/transport_srtp.c | 1192 +++++++---------
pjmedia/src/pjmedia/transport_srtp_dtls.c | 1442 ++++++++++++++++++++
pjmedia/src/pjmedia/transport_srtp_sdes.c | 712 ++++++++++
pjmedia/src/pjmedia/transport_udp.c | 65 +-
pjmedia/src/pjmedia/vid_codec_util.c | 3 +-
pjmedia/src/pjmedia/vid_port.c | 19 +-
pjmedia/src/pjmedia/wav_player.c | 4 +-
pjmedia/src/test/mips_test.c | 4 +-
pjmedia/src/test/sdp_neg_test.c | 6 +-
pjmedia/src/test/vid_codec_test.c | 19 +-
pjnath/include/pjnath/ice_strans.h | 11 +-
pjnath/src/pjnath-test/ice_test.c | 5 +-
pjnath/src/pjnath/ice_session.c | 73 +-
pjnath/src/pjnath/ice_strans.c | 154 ++-
pjnath/src/pjnath/nat_detect.c | 17 +-
pjnath/src/pjnath/turn_session.c | 19 +-
pjnath/src/pjnath/turn_sock.c | 28 +-
pjsip-apps/build/Samples.mak | 2 +
pjsip-apps/build/pjsua.vcproj | 530 +++----
pjsip-apps/build/pjsua.vcxproj | 18 +-
.../src/3rdparty_media_sample/alt_pjsua_aud.c | 6 +-
.../android/gradle/wrapper/gradle-wrapper.jar | Bin 53636 -> 0 bytes
.../src/pjsua/bb10/assets/images/teluu-logo.png | Bin 78108 -> 0 bytes
.../src/pjsua/ios/ipjsua.xcodeproj/project.pbxproj | 20 +
.../src/pjsua/ios/ipjsua/Default-568h at 2x.png | Bin 18594 -> 0 bytes
pjsip-apps/src/pjsua/ios/ipjsua/Default.png | Bin 6540 -> 0 bytes
pjsip-apps/src/pjsua/ios/ipjsua/Default at 2x.png | Bin 16107 -> 0 bytes
pjsip-apps/src/pjsua/ios/ipjsua/Reachability.h | 64 +
pjsip-apps/src/pjsua/ios/ipjsua/Reachability.m | 242 ++++
pjsip-apps/src/pjsua/ios/ipjsua/ipjsua-Info.plist | 4 +
.../src/pjsua/ios/ipjsua/ipjsuaAppDelegate.m | 56 +-
pjsip-apps/src/pjsua/pjsua_app_cli.c | 76 +-
pjsip-apps/src/pjsua/pjsua_app_common.c | 6 +-
.../winrt/cli/comp/pjsua_cli_uwp_comp.vcxproj | 2 +-
.../src/pjsua/winrt/cli/uwp/Assets/teluu-logo.png | Bin 78108 -> 0 bytes
.../src/pjsua/winrt/cli/wp8/Assets/teluu-logo.png | Bin 78108 -> 0 bytes
.../src/pjsua/winrt/cli/wp8/pjsua_cli_wp8.csproj | 39 +-
.../pjsua/winrt/gui/uwp/VoipBackEnd/ApiLock.cpp | 18 -
.../src/pjsua/winrt/gui/uwp/VoipBackEnd/ApiLock.h | 21 -
pjsip-apps/src/pygui/account.py | 408 +++---
pjsip-apps/src/pygui/accountsetting.py | 676 ++++-----
pjsip-apps/src/pygui/application.py | 968 ++++++-------
pjsip-apps/src/pygui/buddy.py | 234 ++--
pjsip-apps/src/pygui/call.py | 146 +-
pjsip-apps/src/pygui/chat.py | 1009 +++++++-------
pjsip-apps/src/pygui/chatgui.py | 768 +++++------
pjsip-apps/src/pygui/endpoint.py | 38 +-
pjsip-apps/src/pygui/log.py | 185 +--
pjsip-apps/src/samples/encdec.c | 4 +-
pjsip-apps/src/samples/pjsua2_demo.cpp | 11 +-
pjsip-apps/src/samples/streamutil.c | 239 +++-
pjsip-apps/src/samples/vid_streamutil.c | 26 +-
.../java/org/pjsip/pjsua2/app/MainActivity.java | 55 +-
.../src/main/java/org/pjsip/pjsua2/app/MyApp.java | 27 +-
.../java/android/gradle/wrapper/gradle-wrapper.jar | Bin 53636 -> 0 bytes
pjsip-apps/src/swig/java/sample.java | 5 +-
pjsip-apps/src/swig/python/Makefile | 18 +-
pjsip-apps/src/swig/python/setup.py | 34 +-
pjsip-apps/src/swig/python/test.py | 267 ++--
pjsip-apps/src/swig/symbols.i | 4 +
pjsip-apps/src/swig/symbols.lst | 2 +-
pjsip/include/pjsip-simple/evsub.h | 14 +-
pjsip/include/pjsip-ua/sip_inv.h | 28 +-
pjsip/include/pjsip/sip_config.h | 14 +-
pjsip/include/pjsip/sip_multipart.h | 17 +-
pjsip/include/pjsip/sip_transaction.h | 21 +-
pjsip/include/pjsip/sip_transport.h | 19 +-
pjsip/include/pjsip/sip_transport_tcp.h | 53 +-
pjsip/include/pjsip/sip_transport_tls.h | 63 +-
pjsip/include/pjsip/sip_transport_udp.h | 47 +-
pjsip/include/pjsip/sip_uri.h | 4 +-
pjsip/include/pjsua-lib/pjsua.h | 267 +++-
pjsip/include/pjsua-lib/pjsua_internal.h | 15 +-
pjsip/include/pjsua2/account.hpp | 64 +-
pjsip/include/pjsua2/call.hpp | 11 +-
pjsip/include/pjsua2/endpoint.hpp | 148 +-
pjsip/include/pjsua2/media.hpp | 73 +-
pjsip/src/pjsip-simple/evsub.c | 14 +-
pjsip/src/pjsip-simple/evsub_msg.c | 4 +-
pjsip/src/pjsip-ua/sip_inv.c | 22 +-
pjsip/src/pjsip-ua/sip_timer.c | 50 +-
pjsip/src/pjsip/sip_auth_client.c | 4 +-
pjsip/src/pjsip/sip_dialog.c | 30 +-
pjsip/src/pjsip/sip_multipart.c | 49 +-
pjsip/src/pjsip/sip_resolve.c | 8 +-
pjsip/src/pjsip/sip_transaction.c | 64 +-
pjsip/src/pjsip/sip_transport.c | 44 +-
pjsip/src/pjsip/sip_transport_tcp.c | 476 ++++---
pjsip/src/pjsip/sip_transport_tls.c | 505 ++++---
pjsip/src/pjsip/sip_transport_udp.c | 36 +-
pjsip/src/pjsip/sip_ua_layer.c | 6 +-
pjsip/src/pjsip/sip_util.c | 10 +-
pjsip/src/pjsua-lib/pjsua_acc.c | 248 +++-
pjsip/src/pjsua-lib/pjsua_aud.c | 5 +-
pjsip/src/pjsua-lib/pjsua_call.c | 24 +-
pjsip/src/pjsua-lib/pjsua_core.c | 371 ++++-
pjsip/src/pjsua-lib/pjsua_media.c | 287 ++--
pjsip/src/pjsua-lib/pjsua_pres.c | 3 +-
pjsip/src/pjsua-lib/pjsua_vid.c | 24 +-
pjsip/src/pjsua2/account.cpp | 35 +-
pjsip/src/pjsua2/call.cpp | 8 +-
pjsip/src/pjsua2/endpoint.cpp | 91 +-
pjsip/src/pjsua2/media.cpp | 159 ++-
pjsip/src/pjsua2/util.hpp | 4 +-
third_party/build/gsm/config.h | 1 +
third_party/build/os-auto.mak.in | 20 +-
third_party/build/speex/config.h | 2 +
third_party/build/srtp/libsrtp.vcproj | 386 +++++-
third_party/build/srtp/libsrtp.vcxproj | 34 -
third_party/build/srtp/libsrtp.vcxproj.filters | 48 -
third_party/build/srtp/srtp_config.h | 11 +-
third_party/build/yuv/Makefile | 6 +-
third_party/build/yuv/Notes.txt | 19 +-
version.mak | 2 +-
178 files changed, 13819 insertions(+), 5335 deletions(-)
diff --git a/aconfigure b/aconfigure
index 8e2051d..72963db 100755
--- a/aconfigure
+++ b/aconfigure
@@ -627,6 +627,7 @@ ac_webrtc_cflags
ac_webrtc_instset
ac_no_webrtc
ac_no_yuv
+ac_no_bcg729
opus_present
opus_h_present
ac_no_opus
@@ -673,6 +674,7 @@ ac_qt_cflags
ac_pjmedia_video_has_qt
ac_darwin_cflags
ac_pjmedia_video_has_ios_opengl
+ac_pjmedia_video_has_vtoolbox
ac_pjmedia_video_has_darwin
ac_android_cflags
ac_pjmedia_video_has_android
@@ -688,6 +690,7 @@ ac_external_webrtc
ac_external_yuv
ac_srtp_shutdown_present
ac_srtp_deinit_present
+ac_external_srtp_lib
ac_external_srtp
ac_external_gsm
ac_external_speex
@@ -824,6 +827,8 @@ with_silk
enable_silk
with_opus
enable_opus
+with_bcg729
+enable_bcg729
enable_libyuv
enable_libwebrtc
'
@@ -1493,6 +1498,7 @@ Optional Features:
--disable-opus Exclude OPUS support from the build (default:
autodetect)
+ --disable-bcg729 Disable bcg729 (default: not disabled)
--disable-libyuv Exclude libyuv in the build
--disable-libwebrtc Exclude libwebrtc in the build
@@ -1545,6 +1551,7 @@ Optional Packages:
Specify alternate libvo-amrwbenc prefix
--with-silk=DIR Specify alternate SILK prefix
--with-opus=DIR Specify alternate OPUS prefix
+ --with-bcg729=DIR Specify alternate bcg729 prefix
Some influential environment variables:
CC C compiler command
@@ -5415,6 +5422,18 @@ fi
+case $target in
+ *android*)
+ ac_fn_c_check_header_mongrel "$LINENO" "linux/android_alarm.h" "ac_cv_header_linux_android_alarm_h" "$ac_includes_default"
+if test "x$ac_cv_header_linux_android_alarm_h" = xyes; then :
+ $as_echo "#define PJ_HAS_ANDROID_ALARM_H 1" >>confdefs.h
+
+fi
+
+
+ ;;
+esac
+
ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r"
if test "x$ac_cv_func_localtime_r" = xyes; then :
$as_echo "#define PJ_HAS_LOCALTIME_R 1" >>confdefs.h
@@ -5829,12 +5848,16 @@ case $target in
ac_os_objs="$ac_os_objs file_access_unistd.o file_io_ansi.o os_core_unix.o os_error_unix.o os_time_unix.o os_timestamp_posix.o"
case $target in
*-apple-darwin_ios*)
- ac_os_objs="$ac_os_objs os_info_iphone.o"
+ ac_os_objs="$ac_os_objs os_info_iphone.o os_core_darwin.o"
+ ;;
+ *darwin*)
+ ac_os_objs="$ac_os_objs os_core_darwin.o"
;;
esac
# QoS
case $target in
*darwin*)
+ ac_os_objs="$ac_os_objs sock_qos_darwin.o sock_qos_bsd.o"
;;
*)
ac_os_objs="$ac_os_objs sock_qos_bsd.o"
@@ -5856,12 +5879,6 @@ case $target in
;;
esac
-case $target in
- *darwin*)
- ac_os_objs="$ac_os_objs sock_qos_darwin.o os_core_darwin.o"
- ;;
-esac
-
ac_external_speex=0
@@ -5979,6 +5996,7 @@ fi
ac_external_srtp=0
+
# Check whether --with-external-srtp was given.
if test "${with_external_srtp+set}" = set; then :
withval=$with_external_srtp;
@@ -5988,6 +6006,25 @@ if test "${with_external_srtp+set}" = set; then :
$as_echo_n "checking if external SRTP devkit is installed... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
+#include <srtp2/srtp.h>
+
+int
+main ()
+{
+srtp_init();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes: version 2.x" >&5
+$as_echo "yes: version 2.x" >&6; }
+ ac_external_srtp="2"
+ ac_external_srtp_lib="srtp2"
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
#include <srtp/srtp.h>
int
@@ -5999,32 +6036,36 @@ srtp_init();
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes!!" >&5
-$as_echo "yes!!" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes: version 1.x" >&5
+$as_echo "yes: version 1.x" >&6; }
ac_external_srtp="1"
+ ac_external_srtp_lib="srtp"
else
as_fn_error $? "Unable to use SRTP. If SRTP development files are not available in the default locations, use CFLAGS and LDFLAGS env var to set the include/lib paths" "$LINENO" 5
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
fi
-if test "x$ac_external_srtp" = "x1"; then
+if test "x$ac_external_srtp" != "x0"; then
ac_srtp_deinit_present=0
ac_srtp_shutdown_present=0
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for srtp_deinit in -lsrtp" >&5
-$as_echo_n "checking for srtp_deinit in -lsrtp... " >&6; }
-if ${ac_cv_lib_srtp_srtp_deinit+:} false; then :
+ as_ac_Lib=`$as_echo "ac_cv_lib_$ac_external_srtp_lib''_srtp_deinit" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for srtp_deinit in -l$ac_external_srtp_lib" >&5
+$as_echo_n "checking for srtp_deinit in -l$ac_external_srtp_lib... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsrtp $LIBS"
+LIBS="-l$ac_external_srtp_lib $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -6044,28 +6085,30 @@ return srtp_deinit ();
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_srtp_srtp_deinit=yes
+ eval "$as_ac_Lib=yes"
else
- ac_cv_lib_srtp_srtp_deinit=no
+ eval "$as_ac_Lib=no"
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_srtp_srtp_deinit" >&5
-$as_echo "$ac_cv_lib_srtp_srtp_deinit" >&6; }
-if test "x$ac_cv_lib_srtp_srtp_deinit" = xyes; then :
+eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
ac_srtp_deinit_present=1
fi
if test "x$ac_srtp_deinit_present" != "x1"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for srtp_shutdown in -lsrtp" >&5
-$as_echo_n "checking for srtp_shutdown in -lsrtp... " >&6; }
-if ${ac_cv_lib_srtp_srtp_shutdown+:} false; then :
+ as_ac_Lib=`$as_echo "ac_cv_lib_$ac_external_srtp_lib''_srtp_shutdown" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for srtp_shutdown in -l$ac_external_srtp_lib" >&5
+$as_echo_n "checking for srtp_shutdown in -l$ac_external_srtp_lib... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsrtp $LIBS"
+LIBS="-l$ac_external_srtp_lib $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -6085,17 +6128,18 @@ return srtp_shutdown ();
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_srtp_srtp_shutdown=yes
+ eval "$as_ac_Lib=yes"
else
- ac_cv_lib_srtp_srtp_shutdown=no
+ eval "$as_ac_Lib=no"
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_srtp_srtp_shutdown" >&5
-$as_echo "$ac_cv_lib_srtp_srtp_shutdown" >&6; }
-if test "x$ac_cv_lib_srtp_srtp_shutdown" = xyes; then :
+eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
ac_srtp_shutdown_present=1
fi
@@ -6421,6 +6465,7 @@ $as_echo "Checking if OpenGL ES 2 is available... no" >&6; }
+
SAVED_LIBS="$LIBS"
LIBS="-framework AVFoundation -framework CoreGraphics -framework QuartzCore -framework CoreVideo -framework CoreMedia"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -6441,6 +6486,25 @@ else
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
+ LIBS="-framework VideoToolbox"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_pjmedia_video_has_vtoolbox=yes
+else
+ ac_pjmedia_video_has_vtoolbox=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
LIBS="-framework OpenGLES"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -6470,6 +6534,15 @@ $as_echo "Checking if AVFoundation framework is available... yes" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if AVFoundation framework is available... no" >&5
$as_echo "Checking if AVFoundation framework is available... no" >&6; }
fi
+ if test "$ac_pjmedia_video_has_vtoolbox" = "yes"; then
+ #ac_darwin_cflags+=" -DPJMEDIA_HAS_VID_TOOLBOX_CODEC=1"
+ LIBS="$LIBS -framework VideoToolbox"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if VideoToolbox framework is available... yes" >&5
+$as_echo "Checking if VideoToolbox framework is available... yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if VideoToolbox framework is available... no" >&5
+$as_echo "Checking if VideoToolbox framework is available... no" >&6; }
+ fi
if test "$ac_pjmedia_video_has_ios_opengl" = "yes"; then
ac_darwin_cflags+=" -DPJMEDIA_VIDEO_DEV_HAS_IOS_OPENGL=1"
LIBS="$LIBS -framework OpenGLES"
@@ -7901,13 +7974,15 @@ $as_echo "OpenSSL library found, SSL support enabled" >&6; }
# support, to enable cryptos such as AES GCM.
# EVP_CIPHER_CTX is now opaque in OpenSSL 1.1.0, libsrtp 1.5.4 uses it as a transparent type.
+ # Update 2.7: our bundled libsrtp has been upgraded to 2.1.0,
+ # so we can omit EVP_CIPHER_CTX definition check now.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <openssl/evp.h>
int
main ()
{
-EVP_CIPHER_CTX ctx;EVP_aes_128_gcm();
+EVP_CIPHER_CTX *ctx;EVP_aes_128_gcm();
;
return 0;
}
@@ -8416,6 +8491,99 @@ fi
+# Check whether --with-bcg729 was given.
+if test "${with_bcg729+set}" = set; then :
+ withval=$with_bcg729;
+else
+ with_bcg729=no
+
+fi
+
+
+if test "x$ac_cross_compile" != "x" -a "x$with_bcg729" = "xno"; then
+ enable_bcg729=no
+fi
+
+
+# Check whether --enable-bcg729 was given.
+if test "${enable_bcg729+set}" = set; then :
+ enableval=$enable_bcg729;
+ if test "$enable_bcg729" = "no"; then
+ ac_no_bcg729=1
+ $as_echo "#define PJMEDIA_HAS_BCG729 0" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if bcg729 is disabled... yes" >&5
+$as_echo "Checking if bcg729 is disabled... yes" >&6; }
+ fi
+
+else
+
+ if test "x$with_bcg729" != "xno" -a "x$with_bcg729" != "x"; then
+ BCG729_PREFIX=$with_bcg729
+ BCG729_CFLAGS="-I$BCG729_PREFIX/include"
+ BCG729_LDFLAGS="-L$BCG729_PREFIX/lib"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using bcg729 prefix... $with_bcg729" >&5
+$as_echo "Using bcg729 prefix... $with_bcg729" >&6; }
+ else
+ BCG729_CFLAGS=""
+ BCG729_LDFLAGS=""
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking bcg729 usability" >&5
+$as_echo_n "checking bcg729 usability... " >&6; }
+
+ BCG729_LIBS="-lbcg729"
+
+ SAVED_LIBS="$LIBS"
+ SAVED_LDFLAGS="$LDFLAGS"
+ SAVED_CFLAGS="$CFLAGS"
+
+ LIBS="$BCG729_LIBS $LIBS"
+ LDFLAGS="$BCG729_LDFLAGS $LDFLAGS"
+ CFLAGS="$BCG729_CFLAGS $CFLAGS"
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <bcg729/encoder.h>
+ #include <bcg729/decoder.h>
+
+int
+main ()
+{
+initBcg729EncoderChannel(0);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ $as_echo "#define PJMEDIA_HAS_BCG729 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+
+else
+
+ ac_no_bcg729=1
+ $as_echo "#define PJMEDIA_HAS_BCG729 0" >>confdefs.h
+
+ LIBS="$SAVED_LIBS"
+ LDFLAGS="$SAVED_LDFLAGS"
+ CFLAGS="$SAVED_CFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+
+fi
+
+
+
+
# Check whether --enable-libyuv was given.
if test "${enable_libyuv+set}" = set; then :
enableval=$enable_libyuv; if test "$enable_libyuv" = "no"; then
diff --git a/aconfigure.ac b/aconfigure.ac
index 508d308..46009c7 100644
--- a/aconfigure.ac
+++ b/aconfigure.ac
@@ -266,6 +266,12 @@ AC_CHECK_HEADER(net/if.h,[AC_DEFINE(PJ_HAS_NET_IF_H,1)],[],
#endif
])
+case $target in
+ *android*)
+ AC_CHECK_HEADER(linux/android_alarm.h,[AC_DEFINE(PJ_HAS_ANDROID_ALARM_H,1)])
+ ;;
+esac
+
AC_CHECK_FUNC(localtime_r,[AC_DEFINE(PJ_HAS_LOCALTIME_R,1)])
AC_MSG_RESULT([Setting PJ_OS_NAME to $target])
@@ -462,12 +468,16 @@ case $target in
ac_os_objs="$ac_os_objs file_access_unistd.o file_io_ansi.o os_core_unix.o os_error_unix.o os_time_unix.o os_timestamp_posix.o"
case $target in
*-apple-darwin_ios*)
- ac_os_objs="$ac_os_objs os_info_iphone.o"
+ ac_os_objs="$ac_os_objs os_info_iphone.o os_core_darwin.o"
+ ;;
+ *darwin*)
+ ac_os_objs="$ac_os_objs os_core_darwin.o"
;;
esac
# QoS
case $target in
*darwin*)
+ ac_os_objs="$ac_os_objs sock_qos_darwin.o sock_qos_bsd.o"
;;
*)
ac_os_objs="$ac_os_objs sock_qos_bsd.o"
@@ -489,12 +499,6 @@ case $target in
;;
esac
-case $target in
- *darwin*)
- ac_os_objs="$ac_os_objs sock_qos_darwin.o os_core_darwin.o"
- ;;
-esac
-
dnl ##########################################
dnl #
dnl # PJMEDIA
@@ -560,6 +564,7 @@ AC_ARG_WITH(external-gsm,
dnl # Use external SRTP installation
AC_SUBST(ac_external_srtp,0)
+AC_SUBST(ac_external_srtp_lib)
AC_ARG_WITH(external-srtp,
AS_HELP_STRING([--with-external-srtp],
[Use external SRTP development files, not the one in "third_party" directory. When this option is set, make sure that SRTP is accessible to use (hint: use CFLAGS and LDFLAGS env var to set the include/lib paths)]),
@@ -567,24 +572,32 @@ AC_ARG_WITH(external-srtp,
if test "x$with_external_srtp" != "xno"; then
# Test SRTP installation
AC_MSG_CHECKING([if external SRTP devkit is installed])
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <srtp/srtp.h>
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <srtp2/srtp.h>
]],
[srtp_init();])],
- [AC_MSG_RESULT(yes!!)
+ [AC_MSG_RESULT(yes: version 2.x)
+ ac_external_srtp="2"
+ ac_external_srtp_lib="srtp2"
+ ],
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <srtp/srtp.h>
+ ]],
+ [srtp_init();])],
+ [AC_MSG_RESULT(yes: version 1.x)
ac_external_srtp="1"
+ ac_external_srtp_lib="srtp"
],
- [AC_MSG_ERROR([Unable to use SRTP. If SRTP development files are not available in the default locations, use CFLAGS and LDFLAGS env var to set the include/lib paths])])
+ [AC_MSG_ERROR([Unable to use SRTP. If SRTP development files are not available in the default locations, use CFLAGS and LDFLAGS env var to set the include/lib paths])])])
fi
]
)
dnl # For external SRTP, check availability of srtp_deinit() or srtp_shutdown()
-if test "x$ac_external_srtp" = "x1"; then
+if test "x$ac_external_srtp" != "x0"; then
AC_SUBST(ac_srtp_deinit_present,0)
AC_SUBST(ac_srtp_shutdown_present,0)
- AC_CHECK_LIB(srtp,srtp_deinit,[ac_srtp_deinit_present=1])
+ AC_CHECK_LIB($ac_external_srtp_lib,srtp_deinit,[ac_srtp_deinit_present=1])
if test "x$ac_srtp_deinit_present" != "x1"; then
- AC_CHECK_LIB(srtp,srtp_shutdown,[ac_srtp_shutdown_present=1])
+ AC_CHECK_LIB($ac_external_srtp_lib,srtp_shutdown,[ac_srtp_shutdown_present=1])
fi
fi
@@ -806,6 +819,7 @@ else
*darwin*)
ac_pjmedia_video=darwin_os
AC_SUBST(ac_pjmedia_video_has_darwin)
+ AC_SUBST(ac_pjmedia_video_has_vtoolbox)
AC_SUBST(ac_pjmedia_video_has_ios_opengl)
AC_SUBST(ac_darwin_cflags)
SAVED_LIBS="$LIBS"
@@ -813,6 +827,10 @@ else
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [])],
[ac_pjmedia_video_has_darwin=yes],
[ac_pjmedia_video_has_darwin=no])
+ LIBS="-framework VideoToolbox"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [])],
+ [ac_pjmedia_video_has_vtoolbox=yes],
+ [ac_pjmedia_video_has_vtoolbox=no])
LIBS="-framework OpenGLES"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [])],
[ac_pjmedia_video_has_ios_opengl=yes],
@@ -825,6 +843,13 @@ else
else
AC_MSG_RESULT([Checking if AVFoundation framework is available... no])
fi
+ if test "$ac_pjmedia_video_has_vtoolbox" = "yes"; then
+ #ac_darwin_cflags+=" -DPJMEDIA_HAS_VID_TOOLBOX_CODEC=1"
+ LIBS="$LIBS -framework VideoToolbox"
+ AC_MSG_RESULT([Checking if VideoToolbox framework is available... yes])
+ else
+ AC_MSG_RESULT([Checking if VideoToolbox framework is available... no])
+ fi
if test "$ac_pjmedia_video_has_ios_opengl" = "yes"; then
ac_darwin_cflags+=" -DPJMEDIA_VIDEO_DEV_HAS_IOS_OPENGL=1"
LIBS="$LIBS -framework OpenGLES"
@@ -1563,8 +1588,10 @@ AC_ARG_ENABLE(ssl,
# support, to enable cryptos such as AES GCM.
# EVP_CIPHER_CTX is now opaque in OpenSSL 1.1.0, libsrtp 1.5.4 uses it as a transparent type.
+ # Update 2.7: our bundled libsrtp has been upgraded to 2.1.0,
+ # so we can omit EVP_CIPHER_CTX definition check now.
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <openssl/evp.h>]],
- [EVP_CIPHER_CTX ctx;EVP_aes_128_gcm();])],
+ [EVP_CIPHER_CTX *ctx;EVP_aes_128_gcm();])],
[AC_CHECK_LIB(crypto,EVP_aes_128_gcm,[ac_ssl_has_aes_gcm=1])])
if test "x$ac_ssl_has_aes_gcm" = "x1"; then
AC_MSG_RESULT([OpenSSL has AES GCM support, SRTP will use OpenSSL])
@@ -1767,6 +1794,75 @@ AC_ARG_ENABLE(opus,
fi
])
+dnl # bcg729 prefix
+AC_ARG_WITH(bcg729,
+ AS_HELP_STRING([--with-bcg729=DIR],
+ [Specify alternate bcg729 prefix]),
+ [],
+ [with_bcg729=no]
+ )
+
+dnl # Do not use default bcg729 installation if we are cross-compiling
+if test "x$ac_cross_compile" != "x" -a "x$with_bcg729" = "xno"; then
+ enable_bcg729=no
+fi
+
+dnl # bcg729
+AC_SUBST(ac_no_bcg729)
+AC_ARG_ENABLE(bcg729,
+ AS_HELP_STRING([--disable-bcg729],
+ [Disable bcg729 (default: not disabled)]),
+ [
+ if test "$enable_bcg729" = "no"; then
+ [ac_no_bcg729=1]
+ AC_DEFINE(PJMEDIA_HAS_BCG729,0)
+ AC_MSG_RESULT([Checking if bcg729 is disabled... yes])
+ fi
+ ],
+ [
+ if test "x$with_bcg729" != "xno" -a "x$with_bcg729" != "x"; then
+ BCG729_PREFIX=$with_bcg729
+ BCG729_CFLAGS="-I$BCG729_PREFIX/include"
+ BCG729_LDFLAGS="-L$BCG729_PREFIX/lib"
+ AC_MSG_RESULT([Using bcg729 prefix... $with_bcg729])
+ else
+ BCG729_CFLAGS=""
+ BCG729_LDFLAGS=""
+ fi
+
+ AC_MSG_CHECKING([bcg729 usability])
+
+ BCG729_LIBS="-lbcg729"
+
+ SAVED_LIBS="$LIBS"
+ SAVED_LDFLAGS="$LDFLAGS"
+ SAVED_CFLAGS="$CFLAGS"
+
+ LIBS="$BCG729_LIBS $LIBS"
+ LDFLAGS="$BCG729_LDFLAGS $LDFLAGS"
+ CFLAGS="$BCG729_CFLAGS $CFLAGS"
+
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <bcg729/encoder.h>
+ #include <bcg729/decoder.h>
+ ]],
+ [initBcg729EncoderChannel(0);]
+ )],
+ [
+ AC_DEFINE(PJMEDIA_HAS_BCG729,1)
+ AC_MSG_RESULT(ok)
+ ],
+ [
+ [ac_no_bcg729=1]
+ AC_DEFINE(PJMEDIA_HAS_BCG729,0)
+ LIBS="$SAVED_LIBS"
+ LDFLAGS="$SAVED_LDFLAGS"
+ CFLAGS="$SAVED_CFLAGS"
+ AC_MSG_RESULT(no)
+ ])
+
+ ])
+
+
dnl # Include libyuv
AC_SUBST(ac_no_yuv)
AC_ARG_ENABLE(libyuv,
diff --git a/build.mak.in b/build.mak.in
index eb28663..6c263a9 100644
--- a/build.mak.in
+++ b/build.mak.in
@@ -28,9 +28,9 @@ export APP_THIRD_PARTY_EXT :=
export APP_THIRD_PARTY_LIBS :=
export APP_THIRD_PARTY_LIB_FILES :=
-ifeq (@ac_external_srtp@,1)
+ifneq (@ac_external_srtp@,0)
# External SRTP library
-APP_THIRD_PARTY_EXT += -lsrtp
+APP_THIRD_PARTY_EXT += -l at ac_external_srtp_lib@
else
APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libsrtp-$(LIB_SUFFIX)
ifeq ($(PJ_SHARED_LIBRARIES),)
@@ -180,6 +180,7 @@ AC_PJMEDIA_VIDEO_HAS_QT = @ac_pjmedia_video_has_qt@
# Darwin (Mac and iOS)
AC_PJMEDIA_VIDEO_HAS_DARWIN = @ac_pjmedia_video_has_darwin@
+AC_PJMEDIA_VIDEO_HAS_VTOOLBOX = @ac_pjmedia_video_has_vtoolbox@
AC_PJMEDIA_VIDEO_HAS_IOS_OPENGL = @ac_pjmedia_video_has_ios_opengl@
DARWIN_CFLAGS = @ac_darwin_cflags@
diff --git a/build/vs/pjproject-vs14-win32-common-defaults.props b/build/vs/pjproject-vs14-win32-common-defaults.props
index 549ff61..87f0281 100644
--- a/build/vs/pjproject-vs14-win32-common-defaults.props
+++ b/build/vs/pjproject-vs14-win32-common-defaults.props
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ImportGroup Label="PropertySheets">
+ <ImportGroup Label="PropertySheets">
</ImportGroup>
<PropertyGroup Label="UserMacros">
<TargetCPU>i386</TargetCPU>
@@ -13,6 +13,9 @@
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
+ <Lib>
+ <AdditionalOptions>/ignore:4221</AdditionalOptions>
+ </Lib>
</ItemDefinitionGroup>
<ItemGroup>
<BuildMacro Include="TargetCPU">
diff --git a/build/vs/pjproject-vs14-win64-common-defaults.props b/build/vs/pjproject-vs14-win64-common-defaults.props
index f4e91fc..8b825a8 100644
--- a/build/vs/pjproject-vs14-win64-common-defaults.props
+++ b/build/vs/pjproject-vs14-win64-common-defaults.props
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ImportGroup Label="PropertySheets">
+ <ImportGroup Label="PropertySheets">
</ImportGroup>
<PropertyGroup Label="UserMacros">
<TargetCPU>x86_64</TargetCPU>
@@ -13,6 +13,9 @@
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX64</TargetMachine>
</Link>
+ <Lib>
+ <AdditionalOptions>/ignore:4221</AdditionalOptions>
+ </Lib>
</ItemDefinitionGroup>
<ItemGroup>
<BuildMacro Include="TargetCPU">
diff --git a/configure-android b/configure-android
index 9197b16..25b862a 100755
--- a/configure-android
+++ b/configure-android
@@ -26,7 +26,7 @@ if test "$*" = "--help" -o "$*" = "-h"; then
echo " IGNORE_CFLAGS Optionally specify compilation flags to be ignored."
echo " Each grepped flag that satisfies the criteria will"
echo " be ignored. Default:"
- echo " IGNORE_CFLAGS=\"\-M\|\-f*stack\|\-f*alias\""
+ echo " IGNORE_CFLAGS=\"\-M\|\-f*stack\|\-f*alias\|\-\<g\>\""
echo " Only used when --use-ndk-cflags is specified."
echo ""
exit 0
@@ -58,8 +58,10 @@ fi
if test "$1" = "--use-ndk-cflags"; then
shift
ADD_CFLAGS="1"
+ ADD_NDK_TOOLCHAIN="0"
+ ADD_NDK_TARGET="0"
if test "x${IGNORE_CFLAGS}" = "x"; then
- IGNORE_CFLAGS="\-M\|\-f*stack\|\-f*alias"
+ IGNORE_CFLAGS="\-M\|\-f*stack\|\-f*alias\|\-\<g\>"
fi
if test -f ${ANDROID_NDK_ROOT}/build/ndk-build; then
@@ -74,6 +76,10 @@ if test "$1" = "--use-ndk-cflags"; then
exit 1
fi
+ echo "====="
+ echo "NDK_OUT : ${NDK_OUT}"
+ echo "====="
+
for i in $NDK_OUT; do
if test "x${NDK_CXX}" != "x" -a "$i" = "-o"; then break; fi
@@ -84,19 +90,30 @@ if test "$1" = "--use-ndk-cflags"; then
fi
NDK_CXXFLAGS="${NDK_CXXFLAGS} $i"
fi
-
# Parse NDK CFLAGS
if test "x${NDK_CC}" != "x" -a "x`echo $i|grep 'dummy'`" = "x" -a "${ADD_CFLAGS}" = "1"; then
if test "$i" = "-c"; then ADD_CFLAGS="0"; else
if test "x`echo $i|grep ${IGNORE_CFLAGS}`" = "x"; then
+ if test "${ADD_NDK_TOOLCHAIN}" = "0" -a "x`echo $i|grep '\-gcc-toolchain'`" != "x"; then
+ ADD_NDK_TOOLCHAIN="1"
+ elif test "${ADD_NDK_TARGET}" = "0" -a "x`echo $i|grep '\-target'`" != "x"; then
+ ADD_NDK_TARGET="1"
+ elif test "${ADD_NDK_TOOLCHAIN}" = "1"; then
+ NDK_TOOLCHAIN="$i"
+ ADD_NDK_TOOLCHAIN="2"
+ elif test "${ADD_NDK_TARGET}" = "1"; then
+ NDK_TARGET="$i"
+ ADD_NDK_TARGET="2"
+ fi
NDK_CFLAGS="${NDK_CFLAGS} $i"
fi
fi
fi
-
- # Find gcc toolchain
- if test "x${NDK_CC}" = "x" -a "x`echo $i | grep 'gcc'`" != "x"; then
- NDK_CC=$i
+ # Find gcc or clang toolchain
+ if test "x${NDK_CC}" = "x"; then
+ if test "x`echo $i | grep 'gcc'`" != "x" -o "x`echo $i | grep 'clang'`" != "x"; then
+ NDK_CC=$i
+ fi
fi
# Find g++ toolchain
if test "x`echo $i | grep 'g++'`" != "x"; then
@@ -104,6 +121,8 @@ if test "$1" = "--use-ndk-cflags"; then
fi
done
+ echo "NDK_CC : ${NDK_CC}"
+
# Get target host from NDK toolchain dir name
TARGET_HOST=`echo ${NDK_CC} | sed -e 's/.*\/toolchains\/\([^\/]*\).*/\1/'`
@@ -116,13 +135,22 @@ if test "$1" = "--use-ndk-cflags"; then
TARGET_HOST="${TARGET_HOST}-linux-android"
fi
+ # Set the binutils
+ if test "x${NDK_TOOLCHAIN}" = "x"; then
+ export AR=`echo ${NDK_CXX}|sed 's/-g++/-ar/'`;
+ export RANLIB=`echo ${NDK_CXX}|sed 's/-g++/-ranlib/'`;
+ export LDFLAGS="${LDFLAGS} --sysroot=${ANDROID_SYSROOT}"
+ else
+ #export AR="${NDK_TOOLCHAIN}/bin/${NDK_TARGET}-ar"
+ #export RANLIB="${NDK_TOOLCHAIN}/bin/${NDK_TARGET}-ranlib"
+ TARGET_HOST="arm-linux-androideabi"
+ export LDFLAGS="${LDFLAGS} --sysroot=${ANDROID_SYSROOT} -target ${NDK_TARGET} -gcc-toolchain ${NDK_TOOLCHAIN}"
+ fi
+
export TARGET_ABI="${TARGET_ABI}"
export CC="${NDK_CC}"
export CXX="${NDK_CXX}"
- export AR=`echo ${NDK_CXX}|sed 's/-g++/-ar/'`;
- export RANLIB=`echo ${NDK_CXX}|sed 's/-g++/-ranlib/'`;
- export LDFLAGS="${LDFLAGS} --sysroot=${ANDROID_SYSROOT}"
export LIBS="${LIBS} -lc -lgcc -ldl"
export CFLAGS="${NDK_CFLAGS} ${CFLAGS}"
export CPPFLAGS="${CFLAGS} -fexceptions -frtti"
@@ -172,11 +200,19 @@ fi
# C++ STL
# Note: STL for pjsua2 sample app is specified in pjsip-apps/src/swig/java/android/jni/Application.mk
-# gnustl
-STDCPP_TC_VER=`ls -d ${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/[0-9]* | sort -gr | head -1`
-STDCPP_CFLAGS="-I${STDCPP_TC_VER}/include -I${STDCPP_TC_VER}/libs/${TARGET_ABI}/include"
-STDCPP_LIBS="-lgnustl_static"
-STDCPP_LDFLAGS="-L${STDCPP_TC_VER}/libs/${TARGET_ABI}/"
+if test "x${NDK_TOOLCHAIN}" = "x"; then
+ # gnustl
+ STDCPP_TC_VER=`ls -d ${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/[0-9]* | sort -gr | head -1`
+ STDCPP_CFLAGS="-I${STDCPP_TC_VER}/include -I${STDCPP_TC_VER}/libs/${TARGET_ABI}/include"
+ STDCPP_LIBS="-lgnustl_static"
+ STDCPP_LDFLAGS="-L${STDCPP_TC_VER}/libs/${TARGET_ABI}/"
+else
+ # llvm
+ STDCPP_TC="${ANDROID_NDK_ROOT}/sources/cxx-stl/llvm-libc++"
+ STDCPP_CFLAGS="-I${STDCPP_TC}/include"
+ STDCPP_LIBS="-lc++_static -lc++abi"
+ STDCPP_LDFLAGS="-L${STDCPP_TC}/libs/${TARGET_ABI}/"
+fi
# stlport
#STDCPP_CFLAGS="-I${ANDROID_NDK_ROOT}/sources/cxx-stl/stlport/stlport"
diff --git a/configure-iphone b/configure-iphone
index 56ecbdc..9e93c8e 100755
--- a/configure-iphone
+++ b/configure-iphone
@@ -119,11 +119,13 @@ fi
export ARCH_VAL=`echo ${ARCH} | sed 's/\-arch //' | sed -e 's/^[ \t]*//;s/[ \t]*$//' `
if test "${MIN_IOS}" = ""; then
- MIN_IOS="7.0"
- echo "$F: MIN_IOS is not specified, choosing ${MIN_IOS}"
- CFLAGS="${CFLAGS} -miphoneos-version-min=${MIN_IOS}"
- LDFLAGS="${LDFLAGS} -miphoneos-version-min=${MIN_IOS}"
+ MIN_IOS_VER="7.0"
+ echo "$F: MIN_IOS is not specified, choosing ${MIN_IOS_VER}"
+ MIN_IOS="-miphoneos-version-min=${MIN_IOS_VER}"
fi
+CFLAGS="${CFLAGS} ${MIN_IOS}"
+LDFLAGS="${LDFLAGS} ${MIN_IOS}"
+
# Set CXX if not set
if test "${CXX}" = ""; then
@@ -145,6 +147,7 @@ export CPP="${CC} ${ARCH} -E -isysroot ${SDKPATH}"
# Print settings
if test "1" = "1"; then
echo "$F: calling ./aconfigure with env vars:"
+ echo " MIN_IOS = ${MIN_IOS}"
echo " CC = ${CC}"
echo " CXX = ${CXX}"
echo " SDKPATH = ${SDKPATH}"
diff --git a/pjlib-util/include/pjlib-util/stun_simple.h b/pjlib-util/include/pjlib-util/stun_simple.h
index a0b1b69..69df41d 100644
--- a/pjlib-util/include/pjlib-util/stun_simple.h
+++ b/pjlib-util/include/pjlib-util/stun_simple.h
@@ -1,4 +1,4 @@
-/* $Id: stun_simple.h 4224 2012-08-09 05:21:25Z nanang $ */
+/* $Id: stun_simple.h 5636 2017-08-02 02:51:59Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -210,6 +210,11 @@ typedef struct pjstun_setting
* insert magic cookie (specified in RFC 5389) in the transaction ID.
*/
pj_bool_t use_stun2;
+
+ /**
+ * Address family of the STUN servers.
+ */
+ int af;
/**
* Host name or IP address string of the first STUN server.
diff --git a/pjlib-util/src/pjlib-util/base64.c b/pjlib-util/src/pjlib-util/base64.c
index 5e31a12..87a9b24 100644
--- a/pjlib-util/src/pjlib-util/base64.c
+++ b/pjlib-util/src/pjlib-util/base64.c
@@ -1,4 +1,4 @@
-/* $Id: base64.c 4713 2014-01-23 08:13:11Z nanang $ */
+/* $Id: base64.c 5589 2017-05-04 05:22:44Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -124,14 +124,16 @@ PJ_DEF(pj_status_t) pj_base64_encode(const pj_uint8_t *input, int in_len,
PJ_DEF(pj_status_t) pj_base64_decode(const pj_str_t *input,
pj_uint8_t *out, int *out_len)
{
- const char *buf = input->ptr;
- int len = (int)input->slen;
+ const char *buf;
+ int len;
int i, j, k;
int c[4];
PJ_ASSERT_RETURN(input && out && out_len, PJ_EINVAL);
- while (buf[len-1] == '=' && len)
+ buf = input->ptr;
+ len = (int)input->slen;
+ while (len && buf[len-1] == '=')
--len;
PJ_ASSERT_RETURN(*out_len >= PJ_BASE64_TO_BASE256_LEN(len),
@@ -161,7 +163,7 @@ PJ_DEF(pj_status_t) pj_base64_decode(const pj_str_t *input,
out[j++] = (pj_uint8_t)(((c[2] & 0x03)<<6) | (c[3] & 0x3F));
}
- pj_assert(j < *out_len);
+ pj_assert(j <= *out_len);
*out_len = j;
return PJ_SUCCESS;
diff --git a/pjlib-util/src/pjlib-util/cli_telnet.c b/pjlib-util/src/pjlib-util/cli_telnet.c
index c6ce6ef..da3806e 100644
--- a/pjlib-util/src/pjlib-util/cli_telnet.c
+++ b/pjlib-util/src/pjlib-util/cli_telnet.c
@@ -1491,13 +1491,14 @@ static pj_bool_t telnet_sess_on_data_read(pj_activesock_t *asock,
switch (sess->parse_state) {
case ST_CR:
sess->parse_state = ST_NORMAL;
- if (*cdata == 0 || *cdata == '\n')
+ if (*cdata == 0 || *cdata == '\n') {
pj_mutex_unlock(sess->smutex);
is_valid = handle_return(sess);
if (!is_valid)
return PJ_FALSE;
pj_mutex_lock(sess->smutex);
- break;
+ }
+ break;
case ST_NORMAL:
if (*cdata == IAC) {
sess->parse_state = ST_IAC;
diff --git a/pjlib-util/src/pjlib-util/pcap.c b/pjlib-util/src/pjlib-util/pcap.c
index 0117a04..5a2a687 100644
--- a/pjlib-util/src/pjlib-util/pcap.c
+++ b/pjlib-util/src/pjlib-util/pcap.c
@@ -1,4 +1,4 @@
-/* $Id: pcap.c 5311 2016-05-20 04:17:00Z ming $ */
+/* $Id: pcap.c 5605 2017-06-15 02:18:17Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -90,6 +90,8 @@ struct pj_pcap_file
pj_pcap_filter filter;
};
+#pragma pack()
+
/* Init default filter */
PJ_DEF(void) pj_pcap_filter_default(pj_pcap_filter *filter)
{
diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c
index a628f12..34926dc 100644
--- a/pjlib-util/src/pjlib-util/resolver.c
+++ b/pjlib-util/src/pjlib-util/resolver.c
@@ -1,4 +1,4 @@
-/* $Id: resolver.c 5534 2017-01-19 07:41:25Z nanang $ */
+/* $Id: resolver.c 5612 2017-07-04 00:06:22Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -766,8 +766,10 @@ static pj_status_t transmit_query(pj_dns_resolver *resolver,
}
}
- if (send_cnt == 0)
+ if (send_cnt == 0) {
+ pj_timer_heap_cancel(resolver->timer, &q->timer_entry);
return PJLIB_UTIL_EDNSNOWORKINGNS;
+ }
++q->transmit_cnt;
diff --git a/pjlib-util/src/pjlib-util/srv_resolver.c b/pjlib-util/src/pjlib-util/srv_resolver.c
index a29a3df..5680943 100644
--- a/pjlib-util/src/pjlib-util/srv_resolver.c
+++ b/pjlib-util/src/pjlib-util/srv_resolver.c
@@ -1,4 +1,4 @@
-/* $Id: srv_resolver.c 5536 2017-01-23 01:34:12Z riza $ */
+/* $Id: srv_resolver.c 5635 2017-08-01 07:49:34Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -407,8 +407,9 @@ static void build_server_entries(pj_dns_srv_async_query *query_job,
for (i=0; i<query_job->srv_cnt; ++i) {
pj_in_addr addr;
pj_in6_addr addr6;
+ unsigned cnt = query_job->srv[i].addr_cnt;
- if (query_job->srv[i].addr_cnt != 0) {
+ if (cnt != 0) {
/* IP address already resolved */
continue;
}
@@ -417,7 +418,6 @@ static void build_server_entries(pj_dns_srv_async_query *query_job,
pj_inet_pton(pj_AF_INET(), &query_job->srv[i].target_name,
&addr) == PJ_SUCCESS)
{
- unsigned cnt = query_job->srv[i].addr_cnt;
pj_sockaddr_init(pj_AF_INET(), &query_job->srv[i].addr[cnt],
NULL, query_job->srv[i].port);
query_job->srv[i].addr[cnt].ipv4.sin_addr = addr;
@@ -427,7 +427,6 @@ static void build_server_entries(pj_dns_srv_async_query *query_job,
pj_inet_pton(pj_AF_INET6(), &query_job->srv[i].target_name,
&addr6) == PJ_SUCCESS)
{
- unsigned cnt = query_job->srv[i].addr_cnt;
pj_sockaddr_init(pj_AF_INET6(), &query_job->srv[i].addr[cnt],
NULL, query_job->srv[i].port);
query_job->srv[i].addr[cnt].ipv6.sin6_addr = addr6;
@@ -480,6 +479,15 @@ static pj_status_t resolve_hostnames(pj_dns_srv_async_query *query_job)
for (i=0; i<query_job->srv_cnt; ++i) {
struct srv_target *srv = &query_job->srv[i];
+ if (srv->addr_cnt != 0) {
+ /*
+ * This query is already counted as resolved because of the
+ * additional records in the SRV response or the target name
+ * is an IP address exception in build_server_entries().
+ */
+ continue;
+ }
+
PJ_LOG(5, (query_job->objname,
"Starting async DNS A query_job for %.*s",
(int)srv->target_name.slen,
@@ -493,7 +501,7 @@ static pj_status_t resolve_hostnames(pj_dns_srv_async_query *query_job)
status = PJ_SUCCESS;
- /* Start DNA A record query */
+ /* Start DNS A record query */
if ((query_job->option & PJ_DNS_SRV_RESOLVE_AAAA_ONLY) == 0)
{
if ((query_job->option & PJ_DNS_SRV_RESOLVE_AAAA) != 0) {
@@ -511,7 +519,7 @@ static pj_status_t resolve_hostnames(pj_dns_srv_async_query *query_job)
&srv->common, &srv->q_a);
}
- /* Start DNA AAAA record query */
+ /* Start DNS AAAA record query */
if (status == PJ_SUCCESS &&
(query_job->option & PJ_DNS_SRV_RESOLVE_AAAA) != 0)
{
@@ -654,6 +662,10 @@ static void dns_callback(void *user_data,
pj_bool_t is_type_a, srv_completed;
pj_dns_addr_record rec;
+ /* Avoid warning: potentially uninitialized local variable 'rec' */
+ rec.alias.slen = 0;
+ rec.addr_count = 0;
+
/* Clear outstanding job */
if (common->type == PJ_DNS_TYPE_A) {
srv_completed = (srv->q_aaaa == NULL);
@@ -683,8 +695,8 @@ static void dns_callback(void *user_data,
query_job->domain_part.ptr,
status,
pj_strerror(status,errmsg,sizeof(errmsg)).ptr));
- }
- }
+ }
+ }
/* Check that we really have answer */
if (status==PJ_SUCCESS && pkt->hdr.anscount != 0) {
diff --git a/pjlib-util/src/pjlib-util/stun_simple_client.c b/pjlib-util/src/pjlib-util/stun_simple_client.c
index 894bee1..9e41ab7 100644
--- a/pjlib-util/src/pjlib-util/stun_simple_client.c
+++ b/pjlib-util/src/pjlib-util/stun_simple_client.c
@@ -1,4 +1,4 @@
-/* $Id: stun_simple_client.c 5311 2016-05-20 04:17:00Z ming $ */
+/* $Id: stun_simple_client.c 5636 2017-08-02 02:51:59Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -63,7 +63,7 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr2(pj_pool_factory *pf,
unsigned srv_cnt;
const pj_str_t *srv1, *srv2;
int port1, port2;
- pj_sockaddr_in srv_addr[2];
+ pj_sockaddr srv_addr[2];
int i, send_cnt = 0, nfds;
pj_pool_t *pool;
struct query_rec {
@@ -116,20 +116,19 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr2(pj_pool_factory *pf,
TRACE_((THIS_FILE, " Binding request created."));
/* Resolve servers. */
- status = pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1);
+ status = pj_sockaddr_init(opt->af, &srv_addr[0], srv1, (pj_uint16_t)port1);
if (status != PJ_SUCCESS)
goto on_error;
srv_cnt = 1;
if (srv2 && port2) {
- status = pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2);
+ status = pj_sockaddr_init(opt->af, &srv_addr[1], srv2,
+ (pj_uint16_t)port2);
if (status != PJ_SUCCESS)
goto on_error;
- if (srv_addr[1].sin_addr.s_addr != srv_addr[0].sin_addr.s_addr &&
- srv_addr[1].sin_port != srv_addr[0].sin_port)
- {
+ if (pj_sockaddr_cmp(&srv_addr[1], &srv_addr[0]) != 0) {
srv_cnt++;
}
}
@@ -181,7 +180,7 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr2(pj_pool_factory *pf,
sent_len = out_msg_len;
status = pj_sock_sendto(sock[i], out_msg, &sent_len, 0,
(pj_sockaddr_t*)&srv_addr[j],
- sizeof(pj_sockaddr_in));
+ pj_sockaddr_get_len(&srv_addr[j]));
}
}
@@ -221,7 +220,7 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr2(pj_pool_factory *pf,
int sock_idx, srv_idx;
pj_ssize_t len;
pjstun_msg msg;
- pj_sockaddr_in addr;
+ pj_sockaddr addr;
int addrlen = sizeof(addr);
pjstun_mapped_addr_attr *attr;
char recv_buf[128];
diff --git a/pjlib-util/src/pjlib-util/xml.c b/pjlib-util/src/pjlib-util/xml.c
index 3d4d16f..aae2023 100644
--- a/pjlib-util/src/pjlib-util/xml.c
+++ b/pjlib-util/src/pjlib-util/xml.c
@@ -1,4 +1,4 @@
-/* $Id: xml.c 5206 2015-12-03 11:43:58Z nanang $ */
+/* $Id: xml.c 5570 2017-03-22 00:26:34Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -248,6 +248,7 @@ static int xml_print_node( const pj_xml_node *node, int indent,
if (node->content.slen==0 &&
node->node_head.next==(pj_xml_node*)&node->node_head)
{
+ if (SIZE_LEFT() < 3) return -1;
*p++ = ' ';
*p++ = '/';
*p++ = '>';
diff --git a/pjlib/include/pj/compat/ctype.h b/pjlib/include/pj/compat/ctype.h
index a79a1a0..d66808c 100644
--- a/pjlib/include/pj/compat/ctype.h
+++ b/pjlib/include/pj/compat/ctype.h
@@ -1,4 +1,4 @@
-/* $Id: ctype.h 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: ctype.h 5599 2017-06-05 03:31:18Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -41,9 +41,5 @@
# define toupper(c) (((c) >= 'a' && (c) <= 'z') ? (c)-('a'-'A') : (c))
#endif
-#ifndef isblank
-# define isblank(c) (c==' ' || c=='\t')
-#endif
-
#endif /* __PJ_COMPAT_CTYPE_H__ */
diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h
index 6b149e9..b3dd6d7 100644
--- a/pjlib/include/pj/config.h
+++ b/pjlib/include/pj/config.h
@@ -1,4 +1,4 @@
-/* $Id: config.h 5550 2017-01-26 02:29:59Z nanang $ */
+/* $Id: config.h 5661 2017-09-25 04:20:21Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -472,6 +472,33 @@
#endif
/**
+ * Log sender width.
+ *
+ * Default: 22 (for 64-bit machines), 14 otherwise
+ */
+#ifndef PJ_LOG_SENDER_WIDTH
+# if PJ_HAS_STDINT_H
+# include <stdint.h>
+# if (UINTPTR_MAX == 0xffffffffffffffff)
+# define PJ_LOG_SENDER_WIDTH 22
+# else
+# define PJ_LOG_SENDER_WIDTH 14
+# endif
+# else
+# define PJ_LOG_SENDER_WIDTH 14
+# endif
+#endif
+
+/**
+ * Log thread name width.
+ *
+ * Default: 12
+ */
+#ifndef PJ_LOG_THREAD_WIDTH
+# define PJ_LOG_THREAD_WIDTH 12
+#endif
+
+/**
* Colorfull terminal (for logging etc).
*
* Default: 1
@@ -882,6 +909,9 @@
# if defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE && _WIN32_WCE >= 0x502
/* Windows Mobile 6 or later */
# define PJ_QOS_IMPLEMENTATION PJ_QOS_WM
+# elif defined(PJ_DARWINOS)
+ /* Darwin OS (e.g: iOS, MacOS, tvOS) */
+# define PJ_QOS_IMPLEMENTATION PJ_QOS_DARWIN
# endif
#endif
@@ -1260,7 +1290,7 @@ PJ_BEGIN_DECL
#define PJ_VERSION_NUM_MAJOR 2
/** PJLIB version minor number. */
-#define PJ_VERSION_NUM_MINOR 6
+#define PJ_VERSION_NUM_MINOR 7
/** PJLIB version revision number. */
#define PJ_VERSION_NUM_REV 0
diff --git a/pjlib/include/pj/ctype.h b/pjlib/include/pj/ctype.h
index 08adde8..f36cd4b 100644
--- a/pjlib/include/pj/ctype.h
+++ b/pjlib/include/pj/ctype.h
@@ -1,4 +1,4 @@
-/* $Id: ctype.h 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: ctype.h 5599 2017-06-05 03:31:18Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -109,7 +109,7 @@ PJ_INLINE(int) pj_isupper(unsigned char c) { return isupper(c); }
* @return Non-zero value if c is a either a space (' ') or horizontal
* tab ('\\t') character.
*/
-PJ_INLINE(int) pj_isblank(unsigned char c) { return isblank(c); }
+PJ_INLINE(int) pj_isblank(unsigned char c) { return (c==' ' || c=='\t'); }
/**
* Converts character to lowercase.
diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h
index b1c2a98..19e25d3 100644
--- a/pjlib/include/pj/sock.h
+++ b/pjlib/include/pj/sock.h
@@ -1,4 +1,4 @@
-/* $Id: sock.h 5444 2016-10-05 09:07:17Z riza $ */
+/* $Id: sock.h 5636 2017-08-02 02:51:59Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -933,6 +933,24 @@ PJ_DECL(void) pj_sockaddr_copy_addr(pj_sockaddr *dst,
*/
PJ_DECL(void) pj_sockaddr_cp(pj_sockaddr_t *dst, const pj_sockaddr_t *src);
+/*
+ * If the source's and desired address family matches, copy the address,
+ * otherwise synthesize a new address with the desired address family,
+ * from the source address. This can be useful to generate an IPv4-mapped
+ * IPv6 address.
+ *
+ * @param dst_af Desired address family.
+ * @param dst Destination socket address, invalid if synthesis is
+ * required and failed.
+ * @param src Source socket address.
+ *
+ * @return PJ_SUCCESS on success, or the error status
+ * if synthesis is required and failed.
+ */
+PJ_DECL(pj_status_t) pj_sockaddr_synthesize(int dst_af,
+ pj_sockaddr_t *dst,
+ const pj_sockaddr_t *src);
+
/**
* Get the IP address of an IPv4 socket address.
* The address is returned as 32bit value in host byte order.
diff --git a/pjlib/src/pj/guid_android.c b/pjlib/src/pj/guid_android.c
index 7d2b0db..7ade013 100644
--- a/pjlib/src/pj/guid_android.c
+++ b/pjlib/src/pj/guid_android.c
@@ -1,4 +1,4 @@
-/* $Id: guid_android.c 5272 2016-04-01 02:34:48Z riza $ */
+/* $Id: guid_android.c 5563 2017-03-07 03:28:56Z riza $ */
/*
* Copyright (C) 2015-2016 Teluu Inc. (http://www.teluu.com)
*
@@ -69,8 +69,8 @@ PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)
if (!jni_env)
goto on_error;
- uuid_class = (jclass)(*jni_env)->NewGlobalRef(jni_env,
- (*jni_env)->FindClass(jni_env, "java/util/UUID"));
+ uuid_class = (*jni_env)->FindClass(jni_env, "java/util/UUID");
+
if (uuid_class == 0)
goto on_error;
@@ -106,6 +106,9 @@ PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)
pj_strncpy(str, &native_str, PJ_GUID_STRING_LENGTH);
(*jni_env)->ReleaseStringUTFChars(jni_env, uuid_string, native_string);
+ (*jni_env)->DeleteLocalRef(jni_env, javaUuid);
+ (*jni_env)->DeleteLocalRef(jni_env, uuid_class);
+ (*jni_env)->DeleteLocalRef(jni_env, uuid_string);
detach_jvm(attached);
return str;
diff --git a/pjlib/src/pj/hash.c b/pjlib/src/pj/hash.c
index e87a855..808337c 100644
--- a/pjlib/src/pj/hash.c
+++ b/pjlib/src/pj/hash.c
@@ -1,4 +1,4 @@
-/* $Id: hash.c 5494 2016-12-07 03:24:16Z ming $ */
+/* $Id: hash.c 5600 2017-06-05 07:27:45Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -77,9 +77,10 @@ PJ_DEF(pj_uint32_t) pj_hash_calc_tolower( pj_uint32_t hval,
long i;
for (i=0; i<key->slen; ++i) {
- char lower = (char)pj_tolower(key->ptr[i]);
+ int lower = pj_tolower(key->ptr[i]);
if (result)
- result[i] = lower;
+ result[i] = (char)lower;
+
hval = hval * PJ_HASH_MULTIPLIER + lower;
}
diff --git a/pjlib/src/pj/log.c b/pjlib/src/pj/log.c
index 123853e..fb20d2f 100644
--- a/pjlib/src/pj/log.c
+++ b/pjlib/src/pj/log.c
@@ -1,4 +1,4 @@
-/* $Id: log.c 4761 2014-02-24 09:02:44Z nanang $ */
+/* $Id: log.c 5554 2017-02-20 00:57:15Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -380,7 +380,7 @@ PJ_DEF(void) pj_log( const char *sender, int level,
pre += pj_utoa_pad(ptime.msec, pre, 3, '0');
}
if (log_decor & PJ_LOG_HAS_SENDER) {
- enum { SENDER_WIDTH = 14 };
+ enum { SENDER_WIDTH = PJ_LOG_SENDER_WIDTH };
pj_size_t sender_len = strlen(sender);
if (pre!=log_buffer) *pre++ = ' ';
if (sender_len <= SENDER_WIDTH) {
@@ -395,7 +395,7 @@ PJ_DEF(void) pj_log( const char *sender, int level,
}
}
if (log_decor & PJ_LOG_HAS_THREAD_ID) {
- enum { THREAD_WIDTH = 12 };
+ enum { THREAD_WIDTH = PJ_LOG_THREAD_WIDTH };
const char *thread_name = pj_thread_get_name(pj_thread_this());
pj_size_t thread_len = strlen(thread_name);
*pre++ = ' ';
diff --git a/pjlib/src/pj/os_info.c b/pjlib/src/pj/os_info.c
index f3e7bc0..8ce2885 100644
--- a/pjlib/src/pj/os_info.c
+++ b/pjlib/src/pj/os_info.c
@@ -1,4 +1,4 @@
-/* $Id: os_info.c 5539 2017-01-23 04:32:34Z nanang $ */
+/* $Id: os_info.c 5635 2017-08-01 07:49:34Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -99,7 +99,8 @@ static char *ver_info(pj_uint32_t ver, char *buf)
static pj_uint32_t parse_version(char *str)
{
- int i, maxtok, found_idx;
+ int i, maxtok;
+ pj_ssize_t found_idx;
pj_uint32_t version = 0;
pj_str_t in_str = pj_str(str);
pj_str_t token, delim;
diff --git a/pjlib/src/pj/os_timestamp_posix.c b/pjlib/src/pj/os_timestamp_posix.c
index 7ed8d9d..1b8296b 100644
--- a/pjlib/src/pj/os_timestamp_posix.c
+++ b/pjlib/src/pj/os_timestamp_posix.c
@@ -1,4 +1,4 @@
-/* $Id: os_timestamp_posix.c 5501 2016-12-19 03:01:55Z nanang $ */
+/* $Id: os_timestamp_posix.c 5574 2017-03-29 05:07:47Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -163,12 +163,16 @@ PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
#elif defined(__ANDROID__)
#include <errno.h>
-#include <linux/android_alarm.h>
-#include <fcntl.h>
#include <time.h>
+#if defined(PJ_HAS_ANDROID_ALARM_H) && PJ_HAS_ANDROID_ALARM_H != 0
+# include <linux/android_alarm.h>
+# include <fcntl.h>
+#endif
+
#define NSEC_PER_SEC 1000000000
+#if defined(ANDROID_ALARM_GET_TIME)
static int s_alarm_fd = -1;
void close_alarm_fd()
@@ -177,12 +181,14 @@ void close_alarm_fd()
close(s_alarm_fd);
s_alarm_fd = -1;
}
+#endif
PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
{
struct timespec tp;
int err = -1;
+#if defined(ANDROID_ALARM_GET_TIME)
if (s_alarm_fd == -1) {
int fd = open("/dev/alarm", O_RDONLY);
if (fd >= 0) {
@@ -195,10 +201,14 @@ PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
err = ioctl(s_alarm_fd,
ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &tp);
}
+#elif defined(CLOCK_BOOTTIME)
+ err = clock_gettime(CLOCK_BOOTTIME, &tp);
+#endif
if (err != 0) {
/* Fallback to CLOCK_MONOTONIC if /dev/alarm is not found, or
- * getting ANDROID_ALARM_ELAPSED_REALTIME fails.
+ * getting ANDROID_ALARM_ELAPSED_REALTIME fails, or
+ * CLOCK_BOOTTIME fails.
*/
err = clock_gettime(CLOCK_MONOTONIC, &tp);
}
diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c
index e0066a6..f49a79b 100644
--- a/pjlib/src/pj/sock_bsd.c
+++ b/pjlib/src/pj/sock_bsd.c
@@ -1,4 +1,4 @@
-/* $Id: sock_bsd.c 5544 2017-01-24 05:41:05Z nanang $ */
+/* $Id: sock_bsd.c 5590 2017-05-09 02:39:08Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -62,7 +62,8 @@ const pj_uint16_t PJ_SOCK_RDM = SOCK_RDM;
const pj_uint16_t PJ_SOL_SOCKET = SOL_SOCKET;
#ifdef SOL_IP
const pj_uint16_t PJ_SOL_IP = SOL_IP;
-#elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64)
+#elif (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_WIN64) && PJ_WIN64) || \
+ (defined (IPPROTO_IP))
const pj_uint16_t PJ_SOL_IP = IPPROTO_IP;
#else
const pj_uint16_t PJ_SOL_IP = 0;
diff --git a/pjlib/src/pj/sock_common.c b/pjlib/src/pj/sock_common.c
index 72eefc9..b94446a 100644
--- a/pjlib/src/pj/sock_common.c
+++ b/pjlib/src/pj/sock_common.c
@@ -1,4 +1,4 @@
-/* $Id: sock_common.c 5485 2016-11-17 04:38:25Z ming $ */
+/* $Id: sock_common.c 5644 2017-09-04 04:12:50Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -134,15 +134,16 @@ PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
if (str_addr && str_addr->slen) {
addr->sin_addr = pj_inet_addr(str_addr);
if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
- pj_hostent he;
- pj_status_t rc;
+ pj_addrinfo ai;
+ unsigned count = 1;
+ pj_status_t status;
- rc = pj_gethostbyname(str_addr, &he);
- if (rc == 0) {
- addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
+ status = pj_getaddrinfo(pj_AF_INET(), str_addr, &count, &ai);
+ if (status==PJ_SUCCESS) {
+ pj_memcpy(&addr->sin_addr, &ai.ai_addr.ipv4.sin_addr,
+ sizeof(addr->sin_addr));
} else {
- addr->sin_addr.s_addr = PJ_INADDR_NONE;
- return rc;
+ return status;
}
}
@@ -416,6 +417,40 @@ PJ_DEF(void) pj_sockaddr_cp(pj_sockaddr_t *dst, const pj_sockaddr_t *src)
}
/*
+ * Synthesize address.
+ */
+PJ_DEF(pj_status_t) pj_sockaddr_synthesize(int dst_af,
+ pj_sockaddr_t *dst,
+ const pj_sockaddr_t *src)
+{
+ char ip_addr_buf[PJ_INET6_ADDRSTRLEN];
+ unsigned int count = 1;
+ pj_addrinfo ai[1];
+ pj_str_t ip_addr;
+ pj_status_t status;
+
+ /* Validate arguments */
+ PJ_ASSERT_RETURN(src && dst, PJ_EINVAL);
+
+ if (dst_af == ((const pj_sockaddr *)src)->addr.sa_family) {
+ pj_sockaddr_cp(dst, src);
+ return PJ_SUCCESS;
+ }
+
+ pj_sockaddr_print(src, ip_addr_buf, sizeof(ip_addr_buf), 0);
+ ip_addr = pj_str(ip_addr_buf);
+
+ /* Try to synthesize address using pj_getaddrinfo(). */
+ status = pj_getaddrinfo(dst_af, &ip_addr, &count, ai);
+ if (status == PJ_SUCCESS && count > 0) {
+ pj_sockaddr_cp(dst, &ai[0].ai_addr);
+ pj_sockaddr_set_port(dst, pj_sockaddr_get_port(src));
+ }
+
+ return status;
+}
+
+/*
* Set port number of pj_sockaddr_in
*/
PJ_DEF(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr,
@@ -793,17 +828,25 @@ PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr)
#if !defined(PJ_GETHOSTIP_DISABLE_LOCAL_RESOLUTION) || \
PJ_GETHOSTIP_DISABLE_LOCAL_RESOLUTION == 0
/* Get hostname's IP address */
- count = 1;
- status = pj_getaddrinfo(af, pj_gethostname(), &count, &ai);
- if (status == PJ_SUCCESS) {
- pj_assert(ai.ai_addr.addr.sa_family == (pj_uint16_t)af);
- pj_sockaddr_copy_addr(&cand_addr[cand_cnt], &ai.ai_addr);
- pj_sockaddr_set_port(&cand_addr[cand_cnt], 0);
- cand_weight[cand_cnt] += WEIGHT_HOSTNAME;
- ++cand_cnt;
-
- TRACE_((THIS_FILE, "hostname IP is %s",
- pj_sockaddr_print(&ai.ai_addr, strip, sizeof(strip), 0)));
+ {
+ const pj_str_t *hostname = pj_gethostname();
+ count = 1;
+
+ if (hostname->slen > 0)
+ status = pj_getaddrinfo(af, hostname, &count, &ai);
+ else
+ status = PJ_ERESOLVE;
+
+ if (status == PJ_SUCCESS) {
+ pj_assert(ai.ai_addr.addr.sa_family == (pj_uint16_t)af);
+ pj_sockaddr_copy_addr(&cand_addr[cand_cnt], &ai.ai_addr);
+ pj_sockaddr_set_port(&cand_addr[cand_cnt], 0);
+ cand_weight[cand_cnt] += WEIGHT_HOSTNAME;
+ ++cand_cnt;
+
+ TRACE_((THIS_FILE, "hostname IP is %s",
+ pj_sockaddr_print(&ai.ai_addr, strip, sizeof(strip), 0)));
+ }
}
#else
PJ_UNUSED_ARG(ai);
diff --git a/pjlib/src/pj/sock_qos_bsd.c b/pjlib/src/pj/sock_qos_bsd.c
index bbbf6fc..3161bd0 100644
--- a/pjlib/src/pj/sock_qos_bsd.c
+++ b/pjlib/src/pj/sock_qos_bsd.c
@@ -1,4 +1,4 @@
-/* $Id: sock_qos_bsd.c 5444 2016-10-05 09:07:17Z riza $ */
+/* $Id: sock_qos_bsd.c 5635 2017-08-01 07:49:34Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -103,7 +103,7 @@ PJ_DEF(pj_status_t) pj_sock_get_qos_params(pj_sock_t sock,
pj_qos_params *p_param)
{
pj_status_t last_err = PJ_ENOTSUP;
- int val, optlen;
+ int val = 0, optlen;
pj_sockaddr sa;
int salen = sizeof(salen);
pj_status_t status;
diff --git a/pjlib/src/pj/sock_qos_darwin.c b/pjlib/src/pj/sock_qos_darwin.c
index 7a8fa50..4d929b7 100644
--- a/pjlib/src/pj/sock_qos_darwin.c
+++ b/pjlib/src/pj/sock_qos_darwin.c
@@ -1,4 +1,4 @@
-/* $Id: sock_qos_darwin.c 5445 2016-10-05 09:52:39Z riza $ */
+/* $Id: sock_qos_darwin.c 5658 2017-09-25 02:25:39Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -26,7 +26,7 @@
* using Darwin-specific SO_NET_SERVICE_TYPE if available, and IP_TOS/
* IPV6_TCLASS as fallback.
*/
-#if !defined(PJ_QOS_IMPLEMENTATION) || PJ_QOS_IMPLEMENTATION==PJ_QOS_IOS
+#if defined(PJ_QOS_IMPLEMENTATION) && PJ_QOS_IMPLEMENTATION==PJ_QOS_DARWIN
#include <sys/socket.h>
diff --git a/pjlib/src/pj/ssl_sock_dump.c b/pjlib/src/pj/ssl_sock_dump.c
index 17da5ac..3a93a62 100644
--- a/pjlib/src/pj/ssl_sock_dump.c
+++ b/pjlib/src/pj/ssl_sock_dump.c
@@ -1,4 +1,4 @@
-/* $Id: ssl_sock_dump.c 4910 2014-09-01 06:32:50Z riza $ */
+/* $Id: ssl_sock_dump.c 5659 2017-09-25 02:58:42Z riza $ */
/*
* Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -105,8 +105,6 @@ PJ_DEF(pj_ssize_t) pj_ssl_cert_info_dump(const pj_ssl_cert_info *ci,
/* Subject alternative name extension */
if (ci->subj_alt_name.cnt) {
- unsigned i;
-
len = pj_ansi_snprintf(p, end-p, "%ssubjectAltName extension\n",
indent);
CHECK_BUF_LEN();
diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
index 7b00132..0a5eee4 100644
--- a/pjlib/src/pj/ssl_sock_ossl.c
+++ b/pjlib/src/pj/ssl_sock_ossl.c
@@ -1,4 +1,4 @@
-/* $Id: ssl_sock_ossl.c 5544 2017-01-24 05:41:05Z nanang $ */
+/* $Id: ssl_sock_ossl.c 5648 2017-09-14 05:03:45Z riza $ */
/*
* Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -51,7 +51,6 @@
#include <openssl/err.h>
#include <openssl/x509v3.h>
#include <openssl/rand.h>
-#include <openssl/engine.h>
#include <openssl/opensslconf.h>
#if !defined(OPENSSL_NO_EC) && OPENSSL_VERSION_NUMBER >= 0x1000200fL
@@ -116,6 +115,10 @@ static unsigned get_nid_from_cid(unsigned cid)
# define OPENSSL_NO_SSL2 /* seems to be removed in 1.1.0 */
# define M_ASN1_STRING_data(x) ASN1_STRING_get0_data(x)
# define M_ASN1_STRING_length(x) ASN1_STRING_length(x)
+# if defined(OPENSSL_API_COMPAT) && OPENSSL_API_COMPAT >= 0x10100000L
+# define X509_get_notBefore(x) X509_get0_notBefore(x)
+# define X509_get_notAfter(x) X509_get0_notAfter(x)
+# endif
#else
# define SSL_CIPHER_get_id(c) (c)->id
# define SSL_set_session(ssl, s) (ssl)->session = (s)
@@ -123,9 +126,15 @@ static unsigned get_nid_from_cid(unsigned cid)
#ifdef _MSC_VER
-# pragma comment( lib, "libeay32")
-# pragma comment( lib, "ssleay32")
-# pragma comment( lib, "crypt32")
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+# pragma comment(lib, "libcrypto")
+# pragma comment(lib, "libssl")
+# pragma comment(lib, "crypt32")
+# else
+# pragma comment(lib, "libeay32")
+# pragma comment(lib, "ssleay32")
+# endif
+# define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
#endif
@@ -144,7 +153,8 @@ static unsigned get_nid_from_cid(unsigned cid)
enum ssl_state {
SSL_STATE_NULL,
SSL_STATE_HANDSHAKING,
- SSL_STATE_ESTABLISHED
+ SSL_STATE_ESTABLISHED,
+ SSL_STATE_ERROR
};
/*
@@ -291,14 +301,104 @@ static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock);
/* Expected maximum value of reason component in OpenSSL error code */
#define MAX_OSSL_ERR_REASON 1200
-static pj_status_t STATUS_FROM_SSL_ERR(pj_ssl_sock_t *ssock,
- unsigned long err)
+
+static char *SSLErrorString (int err)
{
- pj_status_t status;
+ switch (err) {
+ case SSL_ERROR_NONE:
+ return "SSL_ERROR_NONE";
+ case SSL_ERROR_ZERO_RETURN:
+ return "SSL_ERROR_ZERO_RETURN";
+ case SSL_ERROR_WANT_READ:
+ return "SSL_ERROR_WANT_READ";
+ case SSL_ERROR_WANT_WRITE:
+ return "SSL_ERROR_WANT_WRITE";
+ case SSL_ERROR_WANT_CONNECT:
+ return "SSL_ERROR_WANT_CONNECT";
+ case SSL_ERROR_WANT_ACCEPT:
+ return "SSL_ERROR_WANT_ACCEPT";
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ return "SSL_ERROR_WANT_X509_LOOKUP";
+ case SSL_ERROR_SYSCALL:
+ return "SSL_ERROR_SYSCALL";
+ case SSL_ERROR_SSL:
+ return "SSL_ERROR_SSL";
+ default:
+ return "SSL_ERROR_UNKNOWN";
+ }
+}
- /* General SSL error, dig more from OpenSSL error queue */
- if (err == SSL_ERROR_SSL)
- err = ERR_get_error();
+#define ERROR_LOG(msg, err) \
+ PJ_LOG(2,("SSL", "%s (%s): Level: %d err: <%lu> <%s-%s-%s> len: %d", \
+ msg, action, level, err, \
+ (ERR_lib_error_string(err)? ERR_lib_error_string(err): "???"), \
+ (ERR_func_error_string(err)? ERR_func_error_string(err):"???"),\
+ (ERR_reason_error_string(err)? \
+ ERR_reason_error_string(err): "???"), len));
+
+static void SSLLogErrors(char * action, int ret, int ssl_err, int len)
+{
+ char *ssl_err_str = SSLErrorString(ssl_err);
+
+ if (!action) {
+ action = "UNKNOWN";
+ }
+
+ switch (ssl_err) {
+ case SSL_ERROR_SYSCALL:
+ {
+ unsigned long err2 = ERR_get_error();
+ if (err2) {
+ int level = 0;
+ while (err2) {
+ ERROR_LOG("SSL_ERROR_SYSCALL", err2);
+ level++;
+ err2 = ERR_get_error();
+ }
+ } else if (ret == 0) {
+ /* An EOF was observed that violates the protocol */
+
+ /* The TLS/SSL handshake was not successful but was shut down
+ * controlled and by the specifications of the TLS/SSL protocol.
+ */
+ } else if (ret == -1) {
+ /* BIO error - look for more info in errno... */
+ char errStr[250] = "";
+ strerror_r(errno, errStr, sizeof(errStr));
+ /* for now - continue logging these if they occur.... */
+ PJ_LOG(4,("SSL", "BIO error, SSL_ERROR_SYSCALL (%s): "
+ "errno: <%d> <%s> len: %d",
+ action, errno, errStr, len));
+ } else {
+ /* ret!=0 & ret!=-1 & nothing on error stack - is this valid??? */
+ PJ_LOG(2,("SSL", "SSL_ERROR_SYSCALL (%s) ret: %d len: %d",
+ action, ret, len));
+ }
+ break;
+ }
+ case SSL_ERROR_SSL:
+ {
+ unsigned long err2 = ERR_get_error();
+ int level = 0;
+
+ while (err2) {
+ ERROR_LOG("SSL_ERROR_SSL", err2);
+ level++;
+ err2 = ERR_get_error();
+ }
+ break;
+ }
+ default:
+ PJ_LOG(2,("SSL", "%lu [%s] (%s) ret: %d len: %d",
+ ssl_err, ssl_err_str, action, ret, len));
+ break;
+ }
+}
+
+
+static pj_status_t GET_STATUS_FROM_SSL_ERR(unsigned long err)
+{
+ pj_status_t status;
/* OpenSSL error range is much wider than PJLIB errno space, so
* if it exceeds the space, only the error reason will be kept.
@@ -310,13 +410,49 @@ static pj_status_t STATUS_FROM_SSL_ERR(pj_ssl_sock_t *ssock,
status = ERR_GET_REASON(err);
status += PJ_SSL_ERRNO_START;
- ssock->last_err = err;
return status;
}
+/* err contains ERR_get_error() status */
+static pj_status_t STATUS_FROM_SSL_ERR(char *action, pj_ssl_sock_t *ssock,
+ unsigned long err)
+{
+ int level = 0;
+ int len = 0; //dummy
+
+ ERROR_LOG("STATUS_FROM_SSL_ERR", err);
+ level++;
+
+ /* General SSL error, dig more from OpenSSL error queue */
+ if (err == SSL_ERROR_SSL) {
+ err = ERR_get_error();
+ ERROR_LOG("STATUS_FROM_SSL_ERR", err);
+ }
+
+ ssock->last_err = err;
+ return GET_STATUS_FROM_SSL_ERR(err);
+}
+
+/* err contains SSL_get_error() status */
+static pj_status_t STATUS_FROM_SSL_ERR2(char *action, pj_ssl_sock_t *ssock,
+ int ret, int err, int len)
+{
+ unsigned long ssl_err = err;
+
+ if (err == SSL_ERROR_SSL) {
+ ssl_err = ERR_peek_error();
+ }
+
+ /* Dig for more from OpenSSL error queue */
+ SSLLogErrors(action, ret, err, len);
+
+ ssock->last_err = ssl_err;
+ return GET_STATUS_FROM_SSL_ERR(ssl_err);
+}
+
static pj_status_t GET_SSL_STATUS(pj_ssl_sock_t *ssock)
{
- return STATUS_FROM_SSL_ERR(ssock, ERR_get_error());
+ return STATUS_FROM_SSL_ERR("status", ssock, ERR_get_error());
}
@@ -399,8 +535,12 @@ static pj_status_t init_openssl(void)
pj_assert(status == PJ_SUCCESS);
/* Init OpenSSL lib */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_library_init();
SSL_load_error_strings();
+#else
+ OPENSSL_init_ssl(0, NULL);
+#endif
#if OPENSSL_VERSION_NUMBER < 0x009080ffL
/* This is now synonym of SSL_library_init() */
OpenSSL_add_all_algorithms();
@@ -416,6 +556,7 @@ static pj_status_t init_openssl(void)
int nid;
const char *cname;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
meth = (SSL_METHOD*)SSLv23_server_method();
if (!meth)
meth = (SSL_METHOD*)TLSv1_server_method();
@@ -427,6 +568,12 @@ static pj_status_t init_openssl(void)
if (!meth)
meth = (SSL_METHOD*)SSLv2_server_method();
#endif
+
+#else
+ /* Specific version methods are deprecated in 1.1.0 */
+ meth = (SSL_METHOD*)TLS_method();
+#endif
+
pj_assert(meth);
ctx=SSL_CTX_new(meth);
@@ -644,6 +791,7 @@ static pj_status_t create_ssl(pj_ssl_sock_t *ssock)
ssock->param.proto = PJ_SSL_SOCK_PROTO_SSL23;
/* Determine SSL method to use */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
switch (ssock->param.proto) {
case PJ_SSL_SOCK_PROTO_TLS1:
ssl_method = (SSL_METHOD*)TLSv1_method();
@@ -659,6 +807,10 @@ static pj_status_t create_ssl(pj_ssl_sock_t *ssock)
#endif
break;
}
+#else
+ /* Specific version methods are deprecated in 1.1.0 */
+ ssl_method = (SSL_METHOD*)TLS_method();
+#endif
if (!ssl_method) {
ssl_method = (SSL_METHOD*)SSLv23_method();
@@ -918,7 +1070,14 @@ static void destroy_ssl(pj_ssl_sock_t *ssock)
{
/* Destroy SSL instance */
if (ssock->ossl_ssl) {
- SSL_shutdown(ssock->ossl_ssl);
+ /**
+ * Avoid calling SSL_shutdown() if handshake wasn't completed.
+ * OpenSSL 1.0.2f complains if SSL_shutdown() is called during an
+ * SSL handshake, while previous versions always return 0.
+ */
+ if (SSL_in_init(ssock->ossl_ssl) == 0) {
+ SSL_shutdown(ssock->ossl_ssl);
+ }
SSL_free(ssock->ossl_ssl); /* this will also close BIOs */
ssock->ossl_ssl = NULL;
}
@@ -1491,7 +1650,7 @@ static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
unsigned long err;
err = ERR_get_error();
if (err != SSL_ERROR_NONE)
- status = STATUS_FROM_SSL_ERR(ssock, err);
+ status = STATUS_FROM_SSL_ERR("connecting", ssock, err);
}
reset_ssl_sock_state(ssock);
}
@@ -1810,11 +1969,11 @@ static pj_status_t do_handshake(pj_ssl_sock_t *ssock)
}
if (err < 0) {
- err = SSL_get_error(ssock->ossl_ssl, err);
- if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ)
+ int err2 = SSL_get_error(ssock->ossl_ssl, err);
+ if (err2 != SSL_ERROR_NONE && err2 != SSL_ERROR_WANT_READ)
{
/* Handshake fails */
- status = STATUS_FROM_SSL_ERR(ssock, err);
+ status = STATUS_FROM_SSL_ERR2("Handshake", ssock, err, err2, 0);
return status;
}
}
@@ -1890,6 +2049,7 @@ static pj_bool_t asock_on_data_read (pj_activesock_t *asock,
read_data_t *buf = *(OFFSET_OF_READ_DATA_PTR(ssock, data));
void *data_ = (pj_int8_t*)buf->data + buf->len;
int size_ = (int)(ssock->read_size - buf->len);
+ int len = size_;
/* SSL_read() may write some data to BIO write when re-negotiation
* is on progress, so let's protect it with write mutex.
@@ -1906,6 +2066,10 @@ static pj_bool_t asock_on_data_read (pj_activesock_t *asock,
if (size_ > 0)
buf->len += size_;
+ if (status != PJ_SUCCESS) {
+ ssock->ssl_state = SSL_STATE_ERROR;
+ }
+
ret = (*ssock->param.cb.on_data_read)(ssock, buf->data,
buf->len, status,
&remainder_);
@@ -1938,10 +2102,22 @@ static pj_bool_t asock_on_data_read (pj_activesock_t *asock,
*/
if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ)
{
- /* Reset SSL socket state, then return PJ_FALSE */
- status = STATUS_FROM_SSL_ERR(ssock, err);
- reset_ssl_sock_state(ssock);
- goto on_error;
+ if (err == SSL_ERROR_SYSCALL && size_ == -1 &&
+ ERR_peek_error() == 0 && errno == 0)
+ {
+ status = STATUS_FROM_SSL_ERR2("Read", ssock, size_,
+ err, len);
+ PJ_LOG(4,("SSL", "SSL_read() = -1, with "
+ "SSL_ERROR_SYSCALL, no SSL error, "
+ "and errno = 0 - skip BIO error"));
+ /* Ignore these errors */
+ } else {
+ /* Reset SSL socket state, then return PJ_FALSE */
+ status = STATUS_FROM_SSL_ERR2("Read", ssock, size_,
+ err, len);
+ reset_ssl_sock_state(ssock);
+ goto on_error;
+ }
}
status = do_handshake(ssock);
@@ -2657,7 +2833,11 @@ PJ_DEF(pj_status_t) pj_ssl_sock_get_info (pj_ssl_sock_t *ssock,
/* Current cipher */
cipher = SSL_get_current_cipher(ssock->ossl_ssl);
- info->cipher = (SSL_CIPHER_get_id(cipher) & 0x00FFFFFF);
+ if (cipher) {
+ info->cipher = (SSL_CIPHER_get_id(cipher) & 0x00FFFFFF);
+ } else {
+ info->cipher = PJ_TLS_UNKNOWN_CIPHER;
+ }
/* Remote address */
pj_sockaddr_cp(&info->remote_addr, &ssock->rem_addr);
@@ -2825,7 +3005,7 @@ static pj_status_t ssl_write(pj_ssl_sock_t *ssock,
status = PJ_EBUSY;
} else {
/* Some problem occured */
- status = STATUS_FROM_SSL_ERR(ssock, err);
+ status = STATUS_FROM_SSL_ERR2("Write", ssock, nwritten, err, size);
}
} else {
/* nwritten < *size, shouldn't happen, unless write BIO cannot hold
diff --git a/pjlib/src/pjlib-test/exception.c b/pjlib/src/pjlib-test/exception.c
index 6d80331..e74640a 100644
--- a/pjlib/src/pjlib-test/exception.c
+++ b/pjlib/src/pjlib-test/exception.c
@@ -1,4 +1,4 @@
-/* $Id: exception.c 5060 2015-04-10 11:47:48Z nanang $ */
+/* $Id: exception.c 5646 2017-09-08 11:16:09Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -168,9 +168,11 @@ static int test(void)
PJ_CATCH_ANY {
switch (PJ_GET_EXCEPTION()) {
case ID_1:
- if (!rc) rc = -30; break;
+ if (!rc) rc = -30;
+ break;
case ID_2:
- if (!rc) rc = 0; break;
+ if (!rc) rc = 0;
+ break;
default:
if (!rc) rc = -40;
break;
diff --git a/pjmedia/build/Makefile b/pjmedia/build/Makefile
index 97ba731..dd5d94f 100644
--- a/pjmedia/build/Makefile
+++ b/pjmedia/build/Makefile
@@ -162,9 +162,9 @@ export PJMEDIA_TEST_LDFLAGS += $(PJMEDIA_CODEC_LDLIB) \
$(PJMEDIA_VIDEODEV_LDLIB) \
$(PJMEDIA_AUDIODEV_LDLIB) \
$(PJMEDIA_LDLIB) \
- $(PJLIB_LDLIB) \
- $(PJLIB_UTIL_LDLIB) \
$(PJNATH_LDLIB) \
+ $(PJLIB_UTIL_LDLIB) \
+ $(PJLIB_LDLIB) \
$(_LDFLAGS)
export PJMEDIA_TEST_EXE:=pjmedia-test-$(TARGET_NAME)$(HOST_EXE)
diff --git a/pjmedia/build/os-auto.mak.in b/pjmedia/build/os-auto.mak.in
index 4754030..f998f66 100644
--- a/pjmedia/build/os-auto.mak.in
+++ b/pjmedia/build/os-auto.mak.in
@@ -71,6 +71,7 @@ AC_NO_G722_CODEC=@ac_no_g722_codec@
AC_NO_G7221_CODEC=@ac_no_g7221_codec@
AC_NO_OPENCORE_AMRNB=@ac_no_opencore_amrnb@
AC_NO_OPENCORE_AMRWB=@ac_no_opencore_amrwb@
+AC_NO_BCG729=@ac_no_bcg729@
export CODEC_OBJS=
@@ -100,7 +101,7 @@ else
export CFLAGS += -I$(THIRD_PARTY)/build/speex -I$(THIRD_PARTY)/speex/include
export CODEC_OBJS += speex_codec.o
-ifneq (@ac_no_speex_aec@,1)
+ifeq (@ac_no_speex_aec@,)
export PJMEDIA_OBJS += echo_speex.o
endif
@@ -139,13 +140,17 @@ export CODEC_OBJS += opencore_amr.o
endif
endif
+ifeq ($(AC_NO_BCG729),)
+export CODEC_OBJS += bcg729.o
+endif
+
#
# SRTP
#
-ifeq (@ac_external_srtp@,1)
+ifneq (@ac_external_srtp@,0)
# External SRTP
-export CFLAGS += -DPJMEDIA_EXTERNAL_SRTP=1
+export CFLAGS += -DPJMEDIA_EXTERNAL_SRTP=@ac_external_srtp@
# SRTP srtp_deinit()/srtp_shutdown() API availability settings
export CFLAGS += -DPJMEDIA_SRTP_HAS_DEINIT=@ac_srtp_deinit_present@ \
-DPJMEDIA_SRTP_HAS_SHUTDOWN=@ac_srtp_shutdown_present@
@@ -275,6 +280,13 @@ export PJMEDIA_VIDEODEV_OBJS += darwin_dev.o
endif
#
+# VideoToolbox codec
+#
+ifeq ($(AC_PJMEDIA_VIDEO_HAS_VTOOLBOX),yes)
+export CODEC_OBJS += vid_toolbox.o
+endif
+
+#
# iOS OpenGL video device
#
ifeq ($(AC_PJMEDIA_VIDEO_HAS_IOS_OPENGL),yes)
diff --git a/pjmedia/build/pjmedia.vcproj b/pjmedia/build/pjmedia.vcproj
index 7c02018..670b5cf 100644
--- a/pjmedia/build/pjmedia.vcproj
+++ b/pjmedia/build/pjmedia.vcproj
@@ -11,13 +11,13 @@
Name="Win32"
/>
<Platform
- Name="Pocket PC 2003 (ARMV4)"
+ Name="x64"
/>
<Platform
- Name="Smartphone 2003 (ARMV4)"
+ Name="Pocket PC 2003 (ARMV4)"
/>
<Platform
- Name="x64"
+ Name="Smartphone 2003 (ARMV4)"
/>
<Platform
Name="Windows Mobile 6 Standard SDK (ARMV4I)"
@@ -93,11 +93,12 @@
/>
</Configuration>
<Configuration
- Name="Release|Pocket PC 2003 (ARMV4)"
+ Name="Release|x64"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
+ UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -113,11 +114,11 @@
/>
<Tool
Name="VCMIDLTool"
+ TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
- AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
+ AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
/>
@@ -132,7 +133,6 @@
/>
<Tool
Name="VCLibrarianTool"
- OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -144,26 +144,19 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles=""
- />
- <DebuggerTool
- />
</Configuration>
<Configuration
- Name="Release|Smartphone 2003 (ARMV4)"
+ Name="Debug|Win32"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
+ UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -182,8 +175,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
- AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
+ AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
/>
@@ -198,7 +190,7 @@
/>
<Tool
Name="VCLibrarianTool"
- OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).lib"
+ IgnoreDefaultLibraryNames=""
/>
<Tool
Name="VCALinkTool"
@@ -210,24 +202,16 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles=""
- />
- <DebuggerTool
- />
</Configuration>
<Configuration
- Name="Debug|Win32"
+ Name="Debug|x64"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
@@ -246,12 +230,14 @@
/>
<Tool
Name="VCMIDLTool"
+ TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
+ DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -283,11 +269,12 @@
/>
</Configuration>
<Configuration
- Name="Debug|Pocket PC 2003 (ARMV4)"
+ Name="Debug-Static|Win32"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
+ UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -306,8 +293,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
- AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
+ AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
/>
@@ -322,7 +308,6 @@
/>
<Tool
Name="VCLibrarianTool"
- OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -334,26 +319,19 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles=""
- />
- <DebuggerTool
- />
</Configuration>
<Configuration
- Name="Debug|Smartphone 2003 (ARMV4)"
+ Name="Debug-Static|x64"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
+ UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -369,13 +347,14 @@
/>
<Tool
Name="VCMIDLTool"
+ TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
- AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
+ AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
+ DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -388,7 +367,6 @@
/>
<Tool
Name="VCLibrarianTool"
- OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -400,24 +378,16 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles=""
- />
- <DebuggerTool
- />
</Configuration>
<Configuration
- Name="Debug-Static|Win32"
+ Name="Release-Dynamic|Win32"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
@@ -472,11 +442,12 @@
/>
</Configuration>
<Configuration
- Name="Debug-Static|Pocket PC 2003 (ARMV4)"
+ Name="Release-Dynamic|x64"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
+ UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -492,11 +463,11 @@
/>
<Tool
Name="VCMIDLTool"
+ TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
- AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
+ AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
/>
@@ -511,7 +482,6 @@
/>
<Tool
Name="VCLibrarianTool"
- OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -523,26 +493,19 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles=""
- />
- <DebuggerTool
- />
</Configuration>
<Configuration
- Name="Debug-Static|Smartphone 2003 (ARMV4)"
+ Name="Debug-Dynamic|Win32"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
+ UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -561,8 +524,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
- AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
+ AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
/>
@@ -577,7 +539,6 @@
/>
<Tool
Name="VCLibrarianTool"
- OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -589,24 +550,16 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles=""
- />
- <DebuggerTool
- />
</Configuration>
<Configuration
- Name="Release-Dynamic|Win32"
+ Name="Debug-Dynamic|x64"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
@@ -625,12 +578,14 @@
/>
<Tool
Name="VCMIDLTool"
+ TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
+ DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -661,11 +616,12 @@
/>
</Configuration>
<Configuration
- Name="Release-Dynamic|Pocket PC 2003 (ARMV4)"
+ Name="Release-Static|Win32"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"
+ UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -684,8 +640,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
- AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
+ AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
/>
@@ -700,7 +655,6 @@
/>
<Tool
Name="VCLibrarianTool"
- OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -712,26 +666,19 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles=""
- />
- <DebuggerTool
- />
</Configuration>
<Configuration
- Name="Release-Dynamic|Smartphone 2003 (ARMV4)"
+ Name="Release-Static|x64"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
+ UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -747,11 +694,11 @@
/>
<Tool
Name="VCMIDLTool"
+ TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
- AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
+ AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
/>
@@ -766,7 +713,6 @@
/>
<Tool
Name="VCLibrarianTool"
- OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -778,27 +724,18 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles=""
- />
- <DebuggerTool
- />
</Configuration>
<Configuration
- Name="Debug-Dynamic|Win32"
+ Name="Release|Pocket PC 2003 (ARMV4)"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
- UseOfMFC="0"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -817,7 +754,8 @@
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
+ ExecutionBucket="7"
+ AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
/>
@@ -832,6 +770,7 @@
/>
<Tool
Name="VCLibrarianTool"
+ OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -843,16 +782,24 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles=""
+ />
+ <DebuggerTool
+ />
</Configuration>
<Configuration
- Name="Debug-Dynamic|Pocket PC 2003 (ARMV4)"
+ Name="Release|Smartphone 2003 (ARMV4)"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="1"
>
@@ -889,7 +836,7 @@
/>
<Tool
Name="VCLibrarianTool"
- OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).lib"
+ OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -916,9 +863,9 @@
/>
</Configuration>
<Configuration
- Name="Debug-Dynamic|Smartphone 2003 (ARMV4)"
+ Name="Debug|Pocket PC 2003 (ARMV4)"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="1"
>
@@ -955,7 +902,7 @@
/>
<Tool
Name="VCLibrarianTool"
- OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).lib"
+ OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -982,12 +929,11 @@
/>
</Configuration>
<Configuration
- Name="Release-Static|Win32"
+ Name="Debug|Smartphone 2003 (ARMV4)"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"
- UseOfMFC="0"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -1006,7 +952,8 @@
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
+ ExecutionBucket="7"
+ AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
/>
@@ -1021,6 +968,7 @@
/>
<Tool
Name="VCLibrarianTool"
+ OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -1032,16 +980,24 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles=""
+ />
+ <DebuggerTool
+ />
</Configuration>
<Configuration
- Name="Release-Static|Pocket PC 2003 (ARMV4)"
+ Name="Debug-Static|Pocket PC 2003 (ARMV4)"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="1"
>
@@ -1105,9 +1061,9 @@
/>
</Configuration>
<Configuration
- Name="Release-Static|Smartphone 2003 (ARMV4)"
+ Name="Debug-Static|Smartphone 2003 (ARMV4)"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="1"
>
@@ -1171,12 +1127,11 @@
/>
</Configuration>
<Configuration
- Name="Release|x64"
+ Name="Release-Dynamic|Pocket PC 2003 (ARMV4)"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
- UseOfMFC="0"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -1192,11 +1147,11 @@
/>
<Tool
Name="VCMIDLTool"
- TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
+ ExecutionBucket="7"
+ AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
/>
@@ -1211,6 +1166,7 @@
/>
<Tool
Name="VCLibrarianTool"
+ OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -1222,19 +1178,26 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles=""
+ />
+ <DebuggerTool
+ />
</Configuration>
<Configuration
- Name="Debug|x64"
+ Name="Release-Dynamic|Smartphone 2003 (ARMV4)"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
- UseOfMFC="0"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -1250,14 +1213,13 @@
/>
<Tool
Name="VCMIDLTool"
- TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
+ ExecutionBucket="7"
+ AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
- DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -1270,7 +1232,7 @@
/>
<Tool
Name="VCLibrarianTool"
- IgnoreDefaultLibraryNames=""
+ OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -1282,19 +1244,26 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles=""
+ />
+ <DebuggerTool
+ />
</Configuration>
<Configuration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Pocket PC 2003 (ARMV4)"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
- UseOfMFC="0"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -1310,14 +1279,13 @@
/>
<Tool
Name="VCMIDLTool"
- TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
+ ExecutionBucket="7"
+ AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
- DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -1330,6 +1298,7 @@
/>
<Tool
Name="VCLibrarianTool"
+ OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -1341,19 +1310,26 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles=""
+ />
+ <DebuggerTool
+ />
</Configuration>
<Configuration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|Smartphone 2003 (ARMV4)"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
- UseOfMFC="0"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -1369,11 +1345,11 @@
/>
<Tool
Name="VCMIDLTool"
- TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
+ ExecutionBucket="7"
+ AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
/>
@@ -1388,6 +1364,7 @@
/>
<Tool
Name="VCLibrarianTool"
+ OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -1399,19 +1376,26 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles=""
+ />
+ <DebuggerTool
+ />
</Configuration>
<Configuration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Pocket PC 2003 (ARMV4)"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
- UseOfMFC="0"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -1427,14 +1411,13 @@
/>
<Tool
Name="VCMIDLTool"
- TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
+ ExecutionBucket="7"
+ AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
- DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -1447,6 +1430,7 @@
/>
<Tool
Name="VCLibrarianTool"
+ OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -1458,19 +1442,26 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles=""
+ />
+ <DebuggerTool
+ />
</Configuration>
<Configuration
- Name="Release-Static|x64"
+ Name="Release-Static|Smartphone 2003 (ARMV4)"
ConfigurationType="4"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
- UseOfMFC="0"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -1486,11 +1477,11 @@
/>
<Tool
Name="VCMIDLTool"
- TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="../include;../../pjlib/include;"../../pjlib-util/include";../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include,../../third_party/webrtc/src;../..;"$(DXSDK_DIR)include""
+ ExecutionBucket="7"
+ AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../../third_party/build/srtp,../../third_party/srtp/include,../../third_party/srtp/crypto/include,../../third_party/yuv/include,../../third_party/webrtc/src;../.."
PreprocessorDefinitions="_LIB;"
PrecompiledHeaderFile=""
/>
@@ -1505,6 +1496,7 @@
/>
<Tool
Name="VCLibrarianTool"
+ OutputFile="..\lib\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).lib"
/>
<Tool
Name="VCALinkTool"
@@ -1516,11 +1508,19 @@
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles=""
+ />
+ <DebuggerTool
+ />
</Configuration>
<Configuration
Name="Release|Windows Mobile 6 Standard SDK (ARMV4I)"
@@ -3127,7 +3127,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3136,7 +3136,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3145,7 +3145,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3154,7 +3154,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3163,7 +3163,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3172,7 +3172,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3181,7 +3181,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3190,7 +3190,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3199,7 +3199,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3208,7 +3208,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3239,7 +3239,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3248,7 +3248,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3257,7 +3257,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3266,7 +3266,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3275,7 +3275,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3284,7 +3284,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3293,7 +3293,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3302,7 +3302,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3311,7 +3311,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3320,7 +3320,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3359,7 +3359,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3368,7 +3368,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3377,7 +3377,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3386,7 +3386,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3395,7 +3395,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3404,7 +3404,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3413,7 +3413,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3422,7 +3422,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3431,7 +3431,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3440,7 +3440,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3471,7 +3471,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3480,7 +3480,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3489,7 +3489,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3498,7 +3498,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3507,7 +3507,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3516,7 +3516,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3525,7 +3525,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3534,7 +3534,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3543,7 +3543,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3552,7 +3552,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3583,7 +3583,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3592,7 +3592,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3601,7 +3601,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3610,7 +3610,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3619,7 +3619,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3628,7 +3628,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3637,7 +3637,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3646,7 +3646,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3655,7 +3655,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3664,7 +3664,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3699,7 +3699,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3708,7 +3708,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3717,7 +3717,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3726,7 +3726,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3735,7 +3735,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3744,7 +3744,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3753,7 +3753,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3762,7 +3762,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3771,7 +3771,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3780,7 +3780,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3827,7 +3827,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3836,7 +3836,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3845,7 +3845,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3854,7 +3854,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3863,7 +3863,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3872,7 +3872,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3881,7 +3881,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3890,7 +3890,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3899,7 +3899,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3908,7 +3908,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3939,7 +3939,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3948,7 +3948,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3957,7 +3957,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3966,7 +3966,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3975,7 +3975,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3984,7 +3984,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3993,7 +3993,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4002,7 +4002,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4011,7 +4011,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4020,7 +4020,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4051,7 +4051,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4060,7 +4060,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4069,7 +4069,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4078,7 +4078,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4087,7 +4087,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4096,7 +4096,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4105,7 +4105,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4114,7 +4114,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4123,7 +4123,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4132,7 +4132,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4163,7 +4163,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4172,7 +4172,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4181,7 +4181,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4190,7 +4190,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4199,7 +4199,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4208,7 +4208,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4217,7 +4217,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4226,7 +4226,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4235,7 +4235,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4244,7 +4244,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4279,7 +4279,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4288,7 +4288,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4297,7 +4297,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4306,7 +4306,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4315,7 +4315,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4324,7 +4324,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4333,7 +4333,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4342,7 +4342,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4351,7 +4351,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4360,7 +4360,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4391,7 +4391,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4400,7 +4400,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4409,7 +4409,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4418,7 +4418,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4427,7 +4427,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4436,7 +4436,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4445,7 +4445,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4454,7 +4454,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4463,7 +4463,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4472,7 +4472,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4515,7 +4515,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4524,7 +4524,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4533,7 +4533,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4542,7 +4542,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4551,7 +4551,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4560,7 +4560,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4569,7 +4569,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4578,7 +4578,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4587,7 +4587,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4596,7 +4596,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4627,7 +4627,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4636,7 +4636,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4645,7 +4645,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4654,7 +4654,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4663,7 +4663,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4672,7 +4672,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4681,7 +4681,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4690,7 +4690,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4699,7 +4699,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4708,7 +4708,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4739,7 +4739,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4748,7 +4748,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4757,7 +4757,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4766,7 +4766,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4775,7 +4775,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4784,7 +4784,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4793,7 +4793,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4802,7 +4802,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4811,7 +4811,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4820,7 +4820,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4851,7 +4851,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4860,7 +4860,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4869,7 +4869,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4878,7 +4878,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4887,7 +4887,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4896,7 +4896,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4905,7 +4905,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4914,7 +4914,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4923,7 +4923,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4932,7 +4932,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4963,7 +4963,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4972,7 +4972,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4981,7 +4981,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -4990,7 +4990,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -4999,7 +4999,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5008,7 +5008,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5017,7 +5017,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5026,7 +5026,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5035,7 +5035,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5044,7 +5044,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5075,7 +5075,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5084,7 +5084,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5093,7 +5093,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5102,7 +5102,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5111,7 +5111,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5120,7 +5120,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5129,7 +5129,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5138,7 +5138,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5147,7 +5147,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5156,7 +5156,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5187,7 +5187,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5196,7 +5196,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5205,7 +5205,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5214,7 +5214,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5223,7 +5223,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5232,7 +5232,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5241,7 +5241,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5250,7 +5250,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5259,7 +5259,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5268,7 +5268,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5299,7 +5299,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5308,7 +5308,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5317,7 +5317,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5326,7 +5326,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5335,7 +5335,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5344,7 +5344,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5353,7 +5353,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5362,7 +5362,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5371,7 +5371,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5380,7 +5380,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5415,7 +5415,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5424,7 +5424,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5433,7 +5433,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5442,7 +5442,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5451,7 +5451,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5460,7 +5460,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5469,7 +5469,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5478,7 +5478,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5487,7 +5487,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5496,7 +5496,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5535,7 +5535,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5544,7 +5544,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5553,7 +5553,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5562,7 +5562,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5571,7 +5571,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5580,7 +5580,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5589,7 +5589,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5598,7 +5598,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5607,7 +5607,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5616,7 +5616,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5651,7 +5651,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5660,7 +5660,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5669,7 +5669,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5678,7 +5678,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5687,7 +5687,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5696,7 +5696,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5705,7 +5705,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5714,7 +5714,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5723,7 +5723,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5732,7 +5732,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5763,7 +5763,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5772,7 +5772,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5781,7 +5781,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5790,7 +5790,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5799,7 +5799,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5808,7 +5808,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5817,7 +5817,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5826,7 +5826,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5835,7 +5835,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5844,7 +5844,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5875,7 +5875,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5884,7 +5884,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5893,7 +5893,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5902,7 +5902,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5911,7 +5911,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5920,7 +5920,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5929,7 +5929,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5938,7 +5938,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5947,7 +5947,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5956,7 +5956,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -5987,7 +5987,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -5996,7 +5996,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6005,7 +6005,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6014,7 +6014,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6023,7 +6023,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6032,7 +6032,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6041,7 +6041,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6050,7 +6050,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6059,7 +6059,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6068,7 +6068,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6099,7 +6099,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6108,7 +6108,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6117,7 +6117,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6126,7 +6126,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6135,7 +6135,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6144,7 +6144,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6153,7 +6153,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6162,7 +6162,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6171,7 +6171,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6180,7 +6180,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6215,7 +6215,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6224,7 +6224,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6233,7 +6233,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6242,7 +6242,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6251,7 +6251,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6260,7 +6260,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6269,7 +6269,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6278,7 +6278,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6287,7 +6287,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6296,7 +6296,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6327,7 +6327,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6336,7 +6336,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6345,7 +6345,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6354,7 +6354,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6363,7 +6363,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6372,7 +6372,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6381,7 +6381,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6390,7 +6390,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6399,7 +6399,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6408,7 +6408,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6443,7 +6443,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6452,7 +6452,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6461,7 +6461,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6470,7 +6470,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6479,7 +6479,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6488,7 +6488,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6497,7 +6497,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6506,7 +6506,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6515,7 +6515,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6524,7 +6524,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6563,7 +6563,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6572,7 +6572,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6581,7 +6581,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6590,7 +6590,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6599,7 +6599,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6608,7 +6608,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6617,7 +6617,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6626,7 +6626,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6635,7 +6635,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6644,7 +6644,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6679,55 +6679,210 @@
>
</File>
<File
- RelativePath="..\src\pjmedia\transport_udp.c"
+ RelativePath="..\src\pjmedia\transport_srtp_dtls.c"
>
<FileConfiguration
Name="Release|Win32"
+ ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
+ ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Static|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Static|x64"
+ ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release-Dynamic|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Dynamic|x64"
+ ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Debug-Dynamic|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Dynamic|x64"
+ ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release-Static|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Static|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\pjmedia\transport_srtp_sdes.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Static|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Static|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Dynamic|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Dynamic|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Dynamic|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Dynamic|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Static|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Static|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\pjmedia\transport_udp.c"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6745,6 +6900,15 @@
/>
</FileConfiguration>
<FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
Name="Debug|x64"
>
<Tool
@@ -6754,6 +6918,15 @@
/>
</FileConfiguration>
<FileConfiguration
+ Name="Debug-Static|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
Name="Debug-Static|x64"
>
<Tool
@@ -6763,6 +6936,15 @@
/>
</FileConfiguration>
<FileConfiguration
+ Name="Release-Dynamic|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
Name="Release-Dynamic|x64"
>
<Tool
@@ -6772,6 +6954,15 @@
/>
</FileConfiguration>
<FileConfiguration
+ Name="Debug-Dynamic|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
Name="Debug-Dynamic|x64"
>
<Tool
@@ -6781,6 +6972,15 @@
/>
</FileConfiguration>
<FileConfiguration
+ Name="Release-Static|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
Name="Release-Static|x64"
>
<Tool
@@ -6835,7 +7035,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6844,7 +7044,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6853,7 +7053,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6862,7 +7062,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6871,7 +7071,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6880,7 +7080,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6889,7 +7089,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6898,7 +7098,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6907,7 +7107,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6916,7 +7116,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6947,7 +7147,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6956,7 +7156,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6965,7 +7165,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6974,7 +7174,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -6983,7 +7183,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -6992,7 +7192,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -7001,7 +7201,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -7010,7 +7210,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -7019,7 +7219,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -7028,7 +7228,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -7059,7 +7259,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -7068,7 +7268,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -7077,7 +7277,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -7086,7 +7286,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -7095,7 +7295,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -7104,7 +7304,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -7113,7 +7313,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -7122,7 +7322,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -7131,7 +7331,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -7140,7 +7340,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -7171,7 +7371,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -7180,7 +7380,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -7189,7 +7389,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -7198,7 +7398,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -7207,7 +7407,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -7216,7 +7416,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -7225,7 +7425,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -7234,7 +7434,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -7243,7 +7443,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -7252,7 +7452,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
diff --git a/pjmedia/build/pjmedia_codec.vcxproj b/pjmedia/build/pjmedia_codec.vcxproj
index de4ecd3..ba1cb98 100644
--- a/pjmedia/build/pjmedia_codec.vcxproj
+++ b/pjmedia/build/pjmedia_codec.vcxproj
@@ -194,8 +194,9 @@
<!-- Override the PlatformToolset -->
<PropertyGroup>
<PlatformToolset>$(BuildToolset)</PlatformToolset>
- <CharacterSet Condition="'$(API_Family)'!='WinDesktop'"></CharacterSet>
- </PropertyGroup>
+ <CharacterSet Condition="'$(API_Family)'!='WinDesktop'">
+ </CharacterSet>
+ </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
@@ -510,6 +511,7 @@
<ItemGroup>
<ClCompile Include="..\src\pjmedia-codec\amr_sdp_match.c" />
<ClCompile Include="..\src\pjmedia-codec\audio_codecs.c" />
+ <ClCompile Include="..\src\pjmedia-codec\bcg729.c" />
<ClCompile Include="..\src\pjmedia-codec\ffmpeg_vid_codecs.c" />
<ClCompile Include="..\src\pjmedia-codec\g722.c" />
<ClCompile Include="..\src\pjmedia-codec\g7221.c" />
@@ -534,6 +536,7 @@
<ClInclude Include="..\include\pjmedia-codec\amr_helper.h" />
<ClInclude Include="..\include\pjmedia-codec\amr_sdp_match.h" />
<ClInclude Include="..\include\pjmedia-codec\audio_codecs.h" />
+ <ClInclude Include="..\include\pjmedia-codec\bcg729.h" />
<ClInclude Include="..\include\pjmedia-codec\config.h" />
<ClInclude Include="..\include\pjmedia-codec\ffmpeg_vid_codecs.h" />
<ClInclude Include="..\include\pjmedia-codec\g722.h" />
diff --git a/pjmedia/build/pjmedia_codec.vcxproj.filters b/pjmedia/build/pjmedia_codec.vcxproj.filters
index 9f3a2fb..3ca6db4 100644
--- a/pjmedia/build/pjmedia_codec.vcxproj.filters
+++ b/pjmedia/build/pjmedia_codec.vcxproj.filters
@@ -74,6 +74,9 @@
<ClCompile Include="..\src\pjmedia-codec\opus.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\src\pjmedia-codec\bcg729.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\pjmedia-codec\g722\g722_dec.h">
@@ -145,5 +148,8 @@
<ClInclude Include="..\include\pjmedia-codec\opus.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="..\include\pjmedia-codec\bcg729.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
diff --git a/pjmedia/include/pjmedia-codec.h b/pjmedia/include/pjmedia-codec.h
index 256f127..1c7d612 100644
--- a/pjmedia/include/pjmedia-codec.h
+++ b/pjmedia/include/pjmedia-codec.h
@@ -1,4 +1,4 @@
-/* $Id: pjmedia-codec.h 5239 2016-02-04 06:11:58Z ming $ */
+/* $Id: pjmedia-codec.h 5630 2017-07-19 10:29:10Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -35,10 +35,12 @@
#include <pjmedia-codec/g7221.h>
#include <pjmedia-codec/ipp_codecs.h>
#include <pjmedia-codec/opencore_amr.h>
+#include <pjmedia-codec/vid_toolbox.h>
#include <pjmedia-codec/openh264.h>
#include <pjmedia-codec/passthrough.h>
#include <pjmedia-codec/silk.h>
#include <pjmedia-codec/opus.h>
+#include <pjmedia-codec/bcg729.h>
#endif /* __PJMEDIA_CODEC_PJMEDIA_CODEC_H__ */
diff --git a/pjmedia/include/pjmedia-codec/bcg729.h b/pjmedia/include/pjmedia-codec/bcg729.h
new file mode 100644
index 0000000..3f10e91
--- /dev/null
+++ b/pjmedia/include/pjmedia-codec/bcg729.h
@@ -0,0 +1,121 @@
+/* $Id: bcg729.h 5630 2017-07-19 10:29:10Z riza $ */
+/*
+ * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJMEDIA_CODEC_BCG729_H__
+#define __PJMEDIA_CODEC_BCG729_H__
+
+/**
+ * @file bcg729.h
+ * @brief BCG729 codec.
+ */
+
+#include <pjmedia-codec/types.h>
+
+/**
+ * @defgroup PJMED_BCG729 BCG729 Codec
+ * @ingroup PJMEDIA_CODEC_CODECS
+ * @brief Implementation of BCG729 codecs.
+ * @{
+ *
+ * This section describes functions to initialize and register BCG729 codec
+ * factory to the codec manager. After the codec factory has been registered,
+ * application can use @ref PJMEDIA_CODEC API to manipulate the codec.
+ *
+ * This codec factory contains G.729 codec.
+ *
+ * \section pjmedia_codec_bcg729 BCG729
+ *
+ * BCG729 is compliant with ITU-T G.729 and Annexes A, B specifications.
+ *
+ * BCGG729 supports 16-bit PCM audio signal with sampling rate 8000Hz,
+ * frame length 10ms, and resulting in bitrate 8000bps.
+ *
+ * \subsection codec_setting Codec Settings
+ *
+ * General codec settings for this codec such as VAD and PLC can be
+ * manipulated through the <tt>setting</tt> field in #pjmedia_codec_param.
+ * Please see the documentation of #pjmedia_codec_param for more info.
+ *
+ * Note that G.729 VAD status should be signalled in SDP, see more
+ * description below.
+ *
+ * \subsubsection annexb Annex B
+ *
+ * The capability of VAD/DTX is specified in Annex B.
+ *
+ * By default, Annex B is enabled. This default setting of Annex B can
+ * be modified using #pjmedia_codec_mgr_set_default_param().
+ *
+ * In #pjmedia_codec_param, Annex B is configured via VAD setting and
+ * format parameter "annexb" in the SDP "a=fmtp" attribute in
+ * decoding fmtp field. Valid values are "yes" and "no",
+ * the implementation default is "yes". When this parameter is omitted
+ * in the SDP, the value will be "yes" (RFC 4856 Section 2.1.9).
+ *
+ * Here is an example of modifying default setting of Annex B to
+ * be disabled using #pjmedia_codec_mgr_set_default_param():
+ \code
+ pjmedia_codec_param param;
+
+ pjmedia_codec_mgr_get_default_param(.., ¶m);
+ ...
+ // Set VAD
+ param.setting.vad = 0;
+ // Set SDP format parameter
+ param.setting.dec_fmtp.cnt = 1;
+ param.setting.dec_fmtp.param[0].name = pj_str("annexb");
+ param.setting.dec_fmtp.param[0].val = pj_str("no");
+ ...
+ pjmedia_codec_mgr_set_default_param(.., ¶m);
+ \endcode
+ *
+ * \note
+ * The difference of Annex B status in SDP offer/answer may be considered as
+ * incompatible codec in SDP negotiation.
+ *
+ */
+
+PJ_BEGIN_DECL
+
+/**
+ * Initialize and register BCG729 codec factory to pjmedia endpoint.
+ *
+ * @param endpt The pjmedia endpoint.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_codec_bcg729_init(pjmedia_endpt *endpt);
+
+/**
+ * Unregister BCG729 codec factory from pjmedia endpoint and deinitialize
+ * the BCG729 codec library.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_codec_bcg729_deinit(void);
+
+
+PJ_END_DECL
+
+
+/**
+ * @}
+ */
+
+#endif /* __PJMEDIA_CODEC_BCG729_H__ */
+
diff --git a/pjmedia/include/pjmedia-codec/config.h b/pjmedia/include/pjmedia-codec/config.h
index 1a7b4c9..7816082 100644
--- a/pjmedia/include/pjmedia-codec/config.h
+++ b/pjmedia/include/pjmedia-codec/config.h
@@ -1,4 +1,4 @@
-/* $Id: config.h 5304 2016-05-17 16:14:36Z riza $ */
+/* $Id: config.h 5632 2017-07-27 06:45:48Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -51,6 +51,38 @@
/**
+ * Settings to enable L16 codec 8KHz, mono. By default it is disabled.
+ */
+#ifndef PJMEDIA_CODEC_L16_HAS_8KHZ_MONO
+# define PJMEDIA_CODEC_L16_HAS_8KHZ_MONO 0
+#endif
+
+
+/**
+ * Settings to enable L16 codec 8KHz, stereo. By default it is disabled.
+ */
+#ifndef PJMEDIA_CODEC_L16_HAS_8KHZ_STEREO
+# define PJMEDIA_CODEC_L16_HAS_8KHZ_STEREO 0
+#endif
+
+
+/**
+ * Settings to enable L16 codec 16KHz, mono. By default it is disabled.
+ */
+#ifndef PJMEDIA_CODEC_L16_HAS_16KHZ_MONO
+# define PJMEDIA_CODEC_L16_HAS_16KHZ_MONO 0
+#endif
+
+
+/**
+ * Settings to enable L16 codec 16KHz, stereo. By default it is disabled.
+ */
+#ifndef PJMEDIA_CODEC_L16_HAS_16KHZ_STEREO
+# define PJMEDIA_CODEC_L16_HAS_16KHZ_STEREO 0
+#endif
+
+
+/**
* Unless specified otherwise, GSM codec is included by default.
*/
#ifndef PJMEDIA_HAS_GSM_CODEC
@@ -469,6 +501,17 @@
# define PJMEDIA_CODEC_OPUS_DEFAULT_CBR PJ_FALSE
#endif
+
+/**
+ * Enable G.729 codec using BCG729 backend.
+ *
+ * Default: 0
+ */
+#ifndef PJMEDIA_HAS_BCG729
+# define PJMEDIA_HAS_BCG729 0
+#endif
+
+
/**
* Specify if FFMPEG codecs are available.
*
@@ -500,10 +543,15 @@
/**
* Enable FFMPEG H264 codec (requires libx264).
*
- * Default: 0
+ * Default: disabled when OpenH264 is used, otherwise it is set to
+ * PJMEDIA_HAS_FFMPEG_VID_CODEC
*/
#ifndef PJMEDIA_HAS_FFMPEG_CODEC_H264
-# define PJMEDIA_HAS_FFMPEG_CODEC_H264 PJMEDIA_HAS_FFMPEG_VID_CODEC
+# if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
+# define PJMEDIA_HAS_FFMPEG_CODEC_H264 0
+# else
+# define PJMEDIA_HAS_FFMPEG_CODEC_H264 PJMEDIA_HAS_FFMPEG_VID_CODEC
+# endif
#endif
/**
diff --git a/pjmedia/include/pjmedia-codec/config_auto.h.in b/pjmedia/include/pjmedia-codec/config_auto.h.in
index 4f36770..94cca97 100644
--- a/pjmedia/include/pjmedia-codec/config_auto.h.in
+++ b/pjmedia/include/pjmedia-codec/config_auto.h.in
@@ -1,4 +1,4 @@
-/* $Id: config_auto.h.in 5239 2016-02-04 06:11:58Z ming $ */
+/* $Id: config_auto.h.in 5630 2017-07-19 10:29:10Z riza $ */
/*
* Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -89,6 +89,11 @@
#undef PJMEDIA_HAS_OPUS_CODEC
#endif
+/* G.729 codec with BCG729 backend */
+#ifndef PJMEDIA_HAS_BCG729
+#undef PJMEDIA_HAS_BCG729
+#endif
+
#endif /* __PJMEDIA_CODEC_CONFIG_AUTO_H_ */
diff --git a/pjmedia/include/pjmedia-codec/h264_packetizer.h b/pjmedia/include/pjmedia-codec/h264_packetizer.h
index 4e26180..d0a39d6 100644
--- a/pjmedia/include/pjmedia-codec/h264_packetizer.h
+++ b/pjmedia/include/pjmedia-codec/h264_packetizer.h
@@ -1,4 +1,4 @@
-/* $Id: h264_packetizer.h 3664 2011-07-19 03:42:28Z nanang $ */
+/* $Id: h264_packetizer.h 5603 2017-06-08 06:23:56Z ming $ */
/*
* Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
*
@@ -84,6 +84,13 @@ typedef struct pjmedia_h264_packetizer_cfg
* Default: PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED
*/
pjmedia_h264_packetizer_mode mode;
+
+ /**
+ * NAL start code size used for unpacketizing.
+ * Valid options are 3 (0, 0, 1) or 4 (0, 0, 0, 1).
+ * Default: 3 (0, 0, 1)
+ */
+ unsigned unpack_nal_start;
}
pjmedia_h264_packetizer_cfg;
diff --git a/pjmedia/include/pjmedia-codec/types.h b/pjmedia/include/pjmedia-codec/types.h
index 880b71c..5524c6d 100644
--- a/pjmedia/include/pjmedia-codec/types.h
+++ b/pjmedia/include/pjmedia-codec/types.h
@@ -1,4 +1,4 @@
-/* $Id: types.h 5239 2016-02-04 06:11:58Z ming $ */
+/* $Id: types.h 5632 2017-07-27 06:45:48Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -84,12 +84,20 @@ enum pjmedia_audio_pt
PJMEDIA_RTP_PT_G7221_RSV1, /**< G722.1 reserve */
PJMEDIA_RTP_PT_G7221_RSV2, /**< G722.1 reserve */
PJMEDIA_RTP_PT_OPUS, /**< OPUS */
+#if PJMEDIA_CODEC_L16_HAS_8KHZ_MONO
PJMEDIA_RTP_PT_L16_8KHZ_MONO, /**< L16 @ 8KHz, mono */
+#endif
+#if PJMEDIA_CODEC_L16_HAS_8KHZ_STEREO
PJMEDIA_RTP_PT_L16_8KHZ_STEREO, /**< L16 @ 8KHz, stereo */
+#endif
//PJMEDIA_RTP_PT_L16_11KHZ_MONO, /**< L16 @ 11KHz, mono */
//PJMEDIA_RTP_PT_L16_11KHZ_STEREO, /**< L16 @ 11KHz, stereo */
+#if PJMEDIA_CODEC_L16_HAS_16KHZ_MONO
PJMEDIA_RTP_PT_L16_16KHZ_MONO, /**< L16 @ 16KHz, mono */
+#endif
+#if PJMEDIA_CODEC_L16_HAS_16KHZ_STEREO
PJMEDIA_RTP_PT_L16_16KHZ_STEREO, /**< L16 @ 16KHz, stereo */
+#endif
//PJMEDIA_RTP_PT_L16_22KHZ_MONO, /**< L16 @ 22KHz, mono */
//PJMEDIA_RTP_PT_L16_22KHZ_STEREO, /**< L16 @ 22KHz, stereo */
//PJMEDIA_RTP_PT_L16_32KHZ_MONO, /**< L16 @ 32KHz, mono */
diff --git a/pjmedia/include/pjmedia-codec/vid_toolbox.h b/pjmedia/include/pjmedia-codec/vid_toolbox.h
new file mode 100644
index 0000000..abf7e81
--- /dev/null
+++ b/pjmedia/include/pjmedia-codec/vid_toolbox.h
@@ -0,0 +1,71 @@
+/* $Id: vid_toolbox.h 5603 2017-06-08 06:23:56Z ming $ */
+/*
+ * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJMEDIA_CODEC_VID_TOOLBOX_H__
+#define __PJMEDIA_CODEC_VID_TOOLBOX_H__
+
+#include <pjmedia-codec/types.h>
+#include <pjmedia/vid_codec.h>
+
+/**
+ * @file pjmedia-codec/vid_toolbox.h
+ * @brief Video Toolbox codec
+ */
+
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJMEDIA_CODEC_VID_TOOLBOX Video Toolbox Codec
+ * @ingroup PJMEDIA_CODEC_VID_CODECS
+ * @{
+ *
+ * Video Toolbox H.264 codec wrapper for Mac and iOS.
+ */
+
+/**
+ * Initialize and register Video Toolbox codec factory.
+ *
+ * @param mgr The video codec manager instance where this codec will
+ * be registered to. Specify NULL to use default instance
+ * (in that case, an instance of video codec manager must
+ * have been created beforehand).
+ * @param pf Pool factory.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_codec_vid_toolbox_init(pjmedia_vid_codec_mgr *mgr,
+ pj_pool_factory *pf);
+
+/**
+ * Unregister Video Toolbox video codecs factory from the video codec manager
+ * and deinitialize the codec library.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_codec_vid_toolbox_deinit(void);
+
+
+/**
+ * @} PJMEDIA_CODEC_VIDEO_TOOLBOX
+ */
+
+
+PJ_END_DECL
+
+#endif /* __PJMEDIA_CODEC_VID_TOOLBOX_H__ */
diff --git a/pjmedia/include/pjmedia/config.h b/pjmedia/include/pjmedia/config.h
index 0b6e9ff..d60c155 100644
--- a/pjmedia/include/pjmedia/config.h
+++ b/pjmedia/include/pjmedia/config.h
@@ -1,4 +1,4 @@
-/* $Id: config.h 5418 2016-08-15 07:32:29Z riza $ */
+/* $Id: config.h 5643 2017-08-22 04:59:57Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -743,6 +743,20 @@
/**
+ * This specifies if the SDP negotiator should compare its content before
+ * incrementing the origin version on the subsequent offer/answer.
+ * If this is set to 1, origin version will only by incremented if the
+ * new offer/answer is different than the previous one. For backward
+ * compatibility and performance this is set to 0.
+ *
+ * Default is 0 (No)
+ */
+#ifndef PJMEDIA_SDP_NEG_COMPARE_BEFORE_INC_VERSION
+# define PJMEDIA_SDP_NEG_COMPARE_BEFORE_INC_VERSION 0
+#endif
+
+
+/**
* Support for sending and decoding RTCP port in SDP (RFC 3605).
* Default is equal to PJMEDIA_ADVERTISE_RTCP setting.
*/
@@ -953,6 +967,36 @@
/**
+ * Enable session description for SRTP keying.
+ *
+ * By default it is enabled.
+ */
+#ifndef PJMEDIA_SRTP_HAS_SDES
+# define PJMEDIA_SRTP_HAS_SDES 1
+#endif
+
+
+/**
+ * Enable DTLS for SRTP keying.
+ *
+ * Default value: 0 (disabled)
+ */
+#ifndef PJMEDIA_SRTP_HAS_DTLS
+# define PJMEDIA_SRTP_HAS_DTLS 0
+#endif
+
+
+/**
+ * Set OpenSSL ciphers for DTLS-SRTP.
+ *
+ * Default value: "DEFAULT"
+ */
+#ifndef PJMEDIA_SRTP_DTLS_OSSL_CIPHERS
+# define PJMEDIA_SRTP_DTLS_OSSL_CIPHERS "DEFAULT"
+#endif
+
+
+/**
* Maximum number of SRTP cryptos.
*
* Default: 16
@@ -1335,10 +1379,17 @@
* Maximum video payload size. Note that this must not be greater than
* PJMEDIA_MAX_MTU.
*
- * Default: (PJMEDIA_MAX_MTU - 100)
- */
-#ifndef PJMEDIA_MAX_VID_PAYLOAD_SIZE
-# define PJMEDIA_MAX_VID_PAYLOAD_SIZE (PJMEDIA_MAX_MTU - 100)
+ * Default: (PJMEDIA_MAX_MTU - 20 - (128+16)) if SRTP is enabled,
+ * otherwise (PJMEDIA_MAX_MTU - 20).
+ * Note that (128+16) constant value is taken from libSRTP macro
+ * SRTP_MAX_TRAILER_LEN.
+ */
+#ifndef PJMEDIA_MAX_VID_PAYLOAD_SIZE
+# if PJMEDIA_HAS_SRTP
+# define PJMEDIA_MAX_VID_PAYLOAD_SIZE (PJMEDIA_MAX_MTU - 20 - (128+16))
+# else
+# define PJMEDIA_MAX_VID_PAYLOAD_SIZE (PJMEDIA_MAX_MTU - 20)
+# endif
#endif
diff --git a/pjmedia/include/pjmedia/errno.h b/pjmedia/include/pjmedia/errno.h
index 2b5d4ff..507bf0a 100644
--- a/pjmedia/include/pjmedia/errno.h
+++ b/pjmedia/include/pjmedia/errno.h
@@ -1,4 +1,4 @@
-/* $Id: errno.h 5489 2016-11-23 08:15:49Z riza $ */
+/* $Id: errno.h 5597 2017-06-03 09:22:34Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -622,6 +622,24 @@ PJ_BEGIN_DECL
*/
#define PJMEDIA_SRTP_ESDPREQSECTP (PJMEDIA_ERRNO_START+229) /* 220229 */
+/**
+ * @hideinitializer
+ * No matching SRTP crypto-suite after DTLS nego.
+ */
+#define PJMEDIA_SRTP_DTLS_ENOCRYPTO (PJMEDIA_ERRNO_START+240) /* 220240 */
+
+/**
+ * @hideinitializer
+ * No certificate supplied by peer in DTLS nego.
+ */
+#define PJMEDIA_SRTP_DTLS_EPEERNOCERT (PJMEDIA_ERRNO_START+241) /* 220241 */
+
+/**
+ * @hideinitializer
+ * Fingerprint from signalling not match to actual fingerprint.
+ */
+#define PJMEDIA_SRTP_DTLS_EFPNOTMATCH (PJMEDIA_ERRNO_START+242) /* 220242 */
+
#endif /* PJMEDIA_HAS_SRTP */
diff --git a/pjmedia/include/pjmedia/transport_ice.h b/pjmedia/include/pjmedia/transport_ice.h
index c7555cb..9944b3e 100644
--- a/pjmedia/include/pjmedia/transport_ice.h
+++ b/pjmedia/include/pjmedia/transport_ice.h
@@ -1,4 +1,4 @@
-/* $Id: transport_ice.h 4606 2013-10-01 05:00:57Z ming $ */
+/* $Id: transport_ice.h 5597 2017-06-03 09:22:34Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -59,6 +59,21 @@ typedef struct pjmedia_ice_cb
pj_ice_strans_op op,
pj_status_t status);
+ /**
+ * This callback will be called when ICE negotiation completes, with
+ * application user data. Note that if both callbacks are implemented,
+ * only this callback will be invoked.
+ *
+ * @param tp PJMEDIA ICE transport.
+ * @param op The operation
+ * @param status Operation status.
+ * @param user_data User data for this callback.
+ */
+ void (*on_ice_complete2)(pjmedia_transport *tp,
+ pj_ice_strans_op op,
+ pj_status_t status,
+ void *user_data);
+
} pjmedia_ice_cb;
@@ -230,6 +245,39 @@ PJ_DECL(pj_status_t) pjmedia_ice_create3(pjmedia_endpt *endpt,
*/
PJ_DECL(pj_grp_lock_t *) pjmedia_ice_get_grp_lock(pjmedia_transport *tp);
+
+/**
+ * Add application to receive ICE notifications from the specified ICE media
+ * transport.
+ *
+ * @param tp The ICE media transport.
+ * @param cb The ICE specific callbacks.
+ * @param user_data Optional application user data.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_ice_add_ice_cb(pjmedia_transport *tp,
+ const pjmedia_ice_cb *cb,
+ void *user_data);
+
+
+/**
+ * Remove application to stop receiving ICE notifications from the specified
+ * ICE media transport.
+ *
+ * @param tp The ICE media transport.
+ * @param cb The ICE specific callbacks.
+ * @param user_data Optional application user data. The same user data
+ * passed to pjmedia_ice_add_ice_cb(), this is for
+ * validation purpose.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_ice_remove_ice_cb(pjmedia_transport *tp,
+ const pjmedia_ice_cb *cb,
+ void *user_data);
+
+
PJ_END_DECL
diff --git a/pjmedia/include/pjmedia/transport_srtp.h b/pjmedia/include/pjmedia/transport_srtp.h
index cabe20c..4a3a92b 100644
--- a/pjmedia/include/pjmedia/transport_srtp.h
+++ b/pjmedia/include/pjmedia/transport_srtp.h
@@ -1,4 +1,4 @@
-/* $Id: transport_srtp.h 5412 2016-08-08 09:09:29Z ming $ */
+/* $Id: transport_srtp.h 5621 2017-07-05 05:37:24Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -130,6 +130,48 @@ typedef enum pjmedia_srtp_use
/**
+ * This enumeration specifies SRTP keying methods.
+ */
+typedef enum pjmedia_srtp_keying_method
+{
+ /**
+ * Session Description (SDES).
+ */
+ PJMEDIA_SRTP_KEYING_SDES,
+
+ /**
+ * DTLS-SRTP.
+ */
+ PJMEDIA_SRTP_KEYING_DTLS_SRTP,
+
+ /**
+ * Number of keying method.
+ */
+ PJMEDIA_SRTP_KEYINGS_COUNT
+
+} pjmedia_srtp_keying_method;
+
+
+/**
+ * Structure containing callbacks to receive SRTP notifications.
+ */
+typedef struct pjmedia_srtp_cb
+{
+ /**
+ * This callback will be called when SRTP negotiation completes. This
+ * callback will be invoked when the negotiation is done outside of
+ * the SDP signalling, such as in DTLS-SRTP.
+ *
+ * @param tp PJMEDIA SRTP transport.
+ * @param status Operation status.
+ */
+ void (*on_srtp_nego_complete)(pjmedia_transport *tp,
+ pj_status_t status);
+
+} pjmedia_srtp_cb;
+
+
+/**
* Settings to be given when creating SRTP transport. Application should call
* #pjmedia_srtp_setting_default() to initialize this structure with its
* default values.
@@ -139,23 +181,54 @@ typedef struct pjmedia_srtp_setting
/**
* Specify the usage policy. Default is PJMEDIA_SRTP_OPTIONAL.
*/
- pjmedia_srtp_use use;
+ pjmedia_srtp_use use;
/**
* Specify whether the SRTP transport should close the member transport
* when it is destroyed. Default: PJ_TRUE.
*/
- pj_bool_t close_member_tp;
+ pj_bool_t close_member_tp;
/**
* Specify the number of crypto suite settings.
*/
- unsigned crypto_count;
+ unsigned crypto_count;
/**
* Specify individual crypto suite setting.
+ * Notes for DTLS-SRTP keying:
+ * - Currently only supports these cryptos: AES_CM_128_HMAC_SHA1_80,
+ * AES_CM_128_HMAC_SHA1_32, AEAD_AES_256_GCM, and AEAD_AES_128_GCM.
+ * - SRTP key is not configurable.
+ */
+ pjmedia_srtp_crypto crypto[PJMEDIA_SRTP_MAX_CRYPTOS];
+
+ /**
+ * Specify the number of enabled keying methods.
+ * Default is PJMEDIA_SRTP_MAX_KEYINGS (all enabled).
+ */
+ unsigned keying_count;
+
+ /**
+ * Specify enabled keying methods and its priority order. Keying method
+ * with higher priority will be given earlier chance to process the SDP,
+ * for example as currently only one keying is supported in the SDP offer,
+ * keying with first priority will be likely used in the SDP offer.
+ *
+ * Default is that all supported keying methods (i.e: currently SDES and
+ * DTLS-SRTP) will be enabled and with priority order: SDES, DTLS-SRTP.
+ */
+ pjmedia_srtp_keying_method keying[PJMEDIA_SRTP_KEYINGS_COUNT];
+
+ /**
+ * Specify SRTP callback.
+ */
+ pjmedia_srtp_cb cb;
+
+ /**
+ * Specify SRTP transport user data.
*/
- pjmedia_srtp_crypto crypto[PJMEDIA_SRTP_MAX_CRYPTOS];
+ void *user_data;
} pjmedia_srtp_setting;
@@ -195,6 +268,39 @@ typedef struct pjmedia_srtp_info
/**
+ * This structure specifies DTLS-SRTP negotiation parameters.
+ */
+typedef struct pjmedia_srtp_dtls_nego_param
+{
+ /**
+ * Fingerprint of remote certificate, should be formatted as
+ * "SHA-256/1 XX:XX:XX...". If this is not set, fingerprint verification
+ * will not be performed.
+ */
+ pj_str_t rem_fingerprint;
+
+ /**
+ * Remote address and port.
+ */
+ pj_sockaddr rem_addr;
+
+ /**
+ * Remote RTCP address and port.
+ */
+ pj_sockaddr rem_rtcp;
+
+ /**
+ * Set to PJ_TRUE if our role is active. Active role will initiates
+ * the DTLS negotiation. Passive role will wait for incoming DTLS
+ * negotiation packet.
+ */
+ pj_bool_t is_role_active;
+
+} pjmedia_srtp_dtls_nego_param;
+
+
+
+/**
* Initialize SRTP library. This function should be called before
* any SRTP functions, however calling #pjmedia_transport_srtp_create()
* will also invoke this function. This function will also register SRTP
@@ -235,6 +341,50 @@ PJ_DECL(pj_status_t) pjmedia_transport_srtp_create(
const pjmedia_srtp_setting *opt,
pjmedia_transport **p_tp);
+/**
+ * Get fingerprint of local DTLS-SRTP certificate.
+ *
+ * @param srtp The SRTP transport.
+ * @param hash Fingerprint hash algorithm, currently valid values are
+ * "SHA-256" and "SHA-1".
+ * @param buf Buffer for fingerprint output. The output will be
+ * formatted as "SHA-256/1 XX:XX:XX..." and null terminated.
+ * @param len On input, the size of the buffer.
+ * On output, the length of the fingerprint.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_transport_srtp_dtls_get_fingerprint(
+ pjmedia_transport *srtp,
+ const char *hash,
+ char *buf, pj_size_t *len);
+
+
+/**
+ * Manually start DTLS-SRTP negotiation with the given parameters. Application
+ * only needs to call this function when the SRTP transport is used without
+ * SDP offer/answer. When SDP offer/answer framework is used, the DTLS-SRTP
+ * negotiation will be handled by pjmedia_transport_media_create(),
+ * pjmedia_transport_media_start(), pjmedia_transport_media_encode_sdp(), and
+ * pjmedia_transport_media_stop().
+ *
+ * When the negotiation completes, application will be notified via SRTP
+ * callback on_srtp_nego_complete(), if set. If the negotiation is successful,
+ * SRTP will be automatically started.
+ *
+ * Note that if the SRTP member transport is an ICE transport, application
+ * should only call this function after ICE negotiation is completed
+ * successfully.
+ *
+ * @param srtp The SRTP transport.
+ * @param param DTLS-SRTP nego parameter.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_transport_srtp_dtls_start_nego(
+ pjmedia_transport *srtp,
+ const pjmedia_srtp_dtls_nego_param *param);
+
/**
* Manually start SRTP session with the given parameters. Application only
diff --git a/pjmedia/src/pjmedia-audiodev/alsa_dev.c b/pjmedia/src/pjmedia-audiodev/alsa_dev.c
index 3a2d190..3748aed 100644
--- a/pjmedia/src/pjmedia-audiodev/alsa_dev.c
+++ b/pjmedia/src/pjmedia-audiodev/alsa_dev.c
@@ -1,4 +1,4 @@
-/* $Id: alsa_dev.c 5452 2016-10-07 01:56:22Z ming $ */
+/* $Id: alsa_dev.c 5646 2017-09-08 11:16:09Z ming $ */
/*
* Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2007-2009 Keystream AB and Konftel AB, All rights reserved.
@@ -44,6 +44,7 @@
#define MAX_SOUND_CARDS 5
#define MAX_SOUND_DEVICES_PER_CARD 5
#define MAX_DEVICES 32
+#define MAX_MIX_NAME_LEN 64
/* Set to 1 to enable tracing */
#if 0
@@ -97,6 +98,7 @@ struct alsa_factory
unsigned dev_cnt;
pjmedia_aud_dev_info devs[MAX_DEVICES];
+ char pb_mixer_name[MAX_MIX_NAME_LEN];
};
struct alsa_stream
@@ -270,6 +272,44 @@ static pj_status_t add_dev (struct alsa_factory *af, const char *dev_name)
return PJ_SUCCESS;
}
+static void get_mixer_name(struct alsa_factory *af)
+{
+ snd_mixer_t *handle;
+ snd_mixer_elem_t *elem;
+
+ if (snd_mixer_open(&handle, 0) < 0)
+ return;
+
+ if (snd_mixer_attach(handle, "default") < 0) {
+ snd_mixer_close(handle);
+ return;
+ }
+
+ if (snd_mixer_selem_register(handle, NULL, NULL) < 0) {
+ snd_mixer_close(handle);
+ return;
+ }
+
+ if (snd_mixer_load(handle) < 0) {
+ snd_mixer_close(handle);
+ return;
+ }
+
+ for (elem = snd_mixer_first_elem(handle); elem;
+ elem = snd_mixer_elem_next(elem))
+ {
+ if (snd_mixer_selem_is_active(elem) &&
+ snd_mixer_selem_has_playback_volume(elem))
+ {
+ pj_ansi_strncpy(af->pb_mixer_name, snd_mixer_selem_get_name(elem),
+ sizeof(af->pb_mixer_name));
+ TRACE_((THIS_FILE, "Playback mixer name: %s", af->pb_mixer_name));
+ break;
+ }
+ }
+ snd_mixer_close(handle);
+}
+
/* Create ALSA audio driver. */
pjmedia_aud_dev_factory* pjmedia_alsa_factory(pj_pool_factory *pf)
@@ -356,6 +396,9 @@ static pj_status_t alsa_factory_refresh(pjmedia_aud_dev_factory *f)
n++;
}
+ /* Get the mixer name */
+ get_mixer_name(af);
+
/* Install error handler after enumeration, otherwise we'll get many
* error messages about invalid card/device ID.
*/
@@ -892,9 +935,41 @@ static pj_status_t alsa_stream_set_cap(pjmedia_aud_stream *strm,
pjmedia_aud_dev_cap cap,
const void *value)
{
- PJ_UNUSED_ARG(strm);
- PJ_UNUSED_ARG(cap);
- PJ_UNUSED_ARG(value);
+ struct alsa_factory *af = ((struct alsa_stream*)strm)->af;
+
+ if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING && af->pb_mixer_name) {
+ pj_ssize_t min, max;
+ snd_mixer_t *handle;
+ snd_mixer_selem_id_t *sid;
+ snd_mixer_elem_t* elem;
+ unsigned vol = *(unsigned*)value;
+
+ if (snd_mixer_open(&handle, 0) < 0)
+ return PJMEDIA_EAUD_SYSERR;
+
+ if (snd_mixer_attach(handle, "default") < 0)
+ return PJMEDIA_EAUD_SYSERR;
+
+ if (snd_mixer_selem_register(handle, NULL, NULL) < 0)
+ return PJMEDIA_EAUD_SYSERR;
+
+ if (snd_mixer_load(handle) < 0)
+ return PJMEDIA_EAUD_SYSERR;
+
+ snd_mixer_selem_id_alloca(&sid);
+ snd_mixer_selem_id_set_index(sid, 0);
+ snd_mixer_selem_id_set_name(sid, af->pb_mixer_name);
+ elem = snd_mixer_find_selem(handle, sid);
+ if (!elem)
+ return PJMEDIA_EAUD_SYSERR;
+
+ snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
+ if (snd_mixer_selem_set_playback_volume_all(elem, vol * max / 100) < 0)
+ return PJMEDIA_EAUD_SYSERR;
+
+ snd_mixer_close(handle);
+ return PJ_SUCCESS;
+ }
return PJMEDIA_EAUD_INVCAP;
}
diff --git a/pjmedia/src/pjmedia-codec/audio_codecs.c b/pjmedia/src/pjmedia-codec/audio_codecs.c
index 9be00fc..0cf467a 100644
--- a/pjmedia/src/pjmedia-codec/audio_codecs.c
+++ b/pjmedia/src/pjmedia-codec/audio_codecs.c
@@ -1,4 +1,4 @@
-/* $Id: audio_codecs.c 5239 2016-02-04 06:11:58Z ming $ */
+/* $Id: audio_codecs.c 5630 2017-07-19 10:29:10Z riza $ */
/*
* Copyright (C) 2011-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -128,6 +128,13 @@ pjmedia_codec_register_audio_codecs(pjmedia_endpt *endpt,
return status;
#endif
+#if PJMEDIA_HAS_BCG729
+ /* Register BCG729 */
+ status = pjmedia_codec_bcg729_init(endpt);
+ if (status != PJ_SUCCESS)
+ return status;
+#endif
+
return PJ_SUCCESS;
}
diff --git a/pjmedia/src/pjmedia-codec/bcg729.c b/pjmedia/src/pjmedia-codec/bcg729.c
new file mode 100644
index 0000000..3e28b74
--- /dev/null
+++ b/pjmedia/src/pjmedia-codec/bcg729.c
@@ -0,0 +1,622 @@
+/* $Id: bcg729.c 5630 2017-07-19 10:29:10Z riza $ */
+/*
+ * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <pjmedia-codec/bcg729.h>
+#include <pjmedia/codec.h>
+#include <pjmedia/endpoint.h>
+#include <pjmedia/errno.h>
+#include <pjmedia/port.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/log.h>
+
+#if defined(PJMEDIA_HAS_BCG729) && (PJMEDIA_HAS_BCG729!=0)
+
+#include <bcg729/encoder.h>
+#include <bcg729/decoder.h>
+
+#define THIS_FILE "bcg729.c"
+
+/* Prototypes for BCG729 factory */
+static pj_status_t bcg729_test_alloc(pjmedia_codec_factory *factory,
+ const pjmedia_codec_info *id);
+static pj_status_t bcg729_default_attr(pjmedia_codec_factory *factory,
+ const pjmedia_codec_info *id,
+ pjmedia_codec_param *attr);
+static pj_status_t bcg729_enum_codecs (pjmedia_codec_factory *factory,
+ unsigned *count,
+ pjmedia_codec_info codecs[]);
+static pj_status_t bcg729_alloc_codec(pjmedia_codec_factory *factory,
+ const pjmedia_codec_info *id,
+ pjmedia_codec **p_codec);
+static pj_status_t bcg729_dealloc_codec(pjmedia_codec_factory *factory,
+ pjmedia_codec *codec);
+
+/* Prototypes for BCG729 implementation. */
+static pj_status_t bcg729_codec_init(pjmedia_codec *codec,
+ pj_pool_t *pool );
+static pj_status_t bcg729_codec_open(pjmedia_codec *codec,
+ pjmedia_codec_param *attr);
+static pj_status_t bcg729_codec_close(pjmedia_codec *codec);
+static pj_status_t bcg729_codec_modify(pjmedia_codec *codec,
+ const pjmedia_codec_param *attr);
+static pj_status_t bcg729_codec_parse(pjmedia_codec *codec,
+ void *pkt,
+ pj_size_t pkt_size,
+ const pj_timestamp *timestamp,
+ unsigned *frame_cnt,
+ pjmedia_frame frames[]);
+static pj_status_t bcg729_codec_encode(pjmedia_codec *codec,
+ const struct pjmedia_frame *input,
+ unsigned output_buf_len,
+ struct pjmedia_frame *output);
+static pj_status_t bcg729_codec_decode(pjmedia_codec *codec,
+ const struct pjmedia_frame *input,
+ unsigned output_buf_len,
+ struct pjmedia_frame *output);
+static pj_status_t bcg729_codec_recover(pjmedia_codec *codec,
+ unsigned output_buf_len,
+ struct pjmedia_frame *output);
+
+/* Codec const. */
+#define G729_TAG "G729"
+#define G729_CLOCK_RATE 8000
+#define G729_CHANNEL_COUNT 1
+#define G729_SAMPLES_PER_FRAME 80
+#define G729_DEFAULT_BIT_RATE 8000
+#define G729_MAX_BIT_RATE 11800
+#define G729_FRAME_PER_PACKET 2
+#define G729_FRAME_SIZE 10
+
+/* Definition for BCG729 codec operations. */
+static pjmedia_codec_op bcg729_op =
+{
+ &bcg729_codec_init,
+ &bcg729_codec_open,
+ &bcg729_codec_close,
+ &bcg729_codec_modify,
+ &bcg729_codec_parse,
+ &bcg729_codec_encode,
+ &bcg729_codec_decode,
+ &bcg729_codec_recover
+};
+
+/* Definition for BCG729 codec factory operations. */
+static pjmedia_codec_factory_op bcg729_factory_op =
+{
+ &bcg729_test_alloc,
+ &bcg729_default_attr,
+ &bcg729_enum_codecs,
+ &bcg729_alloc_codec,
+ &bcg729_dealloc_codec,
+ &pjmedia_codec_bcg729_deinit
+};
+
+
+/* BCG729 factory private data */
+static struct bcg729_factory
+{
+ pjmedia_codec_factory base;
+ pjmedia_endpt *endpt;
+ pj_pool_t *pool;
+ pj_mutex_t *mutex;
+} bcg729_factory;
+
+
+/* BCG729 codec private data. */
+typedef struct bcg729_private
+{
+ pj_pool_t *pool; /**< Pool for each instance. */
+
+ bcg729EncoderChannelContextStruct *encoder;
+ bcg729DecoderChannelContextStruct *decoder;
+
+ pj_bool_t vad_enabled;
+ pj_bool_t plc_enabled;
+} bcg729_private;
+
+
+PJ_DEF(pj_status_t) pjmedia_codec_bcg729_init(pjmedia_endpt *endpt)
+{
+ pjmedia_codec_mgr *codec_mgr;
+ pj_status_t status;
+
+ if (bcg729_factory.endpt != NULL) {
+ /* Already initialized. */
+ return PJ_SUCCESS;
+ }
+
+ /* Init factory */
+ pj_bzero(&bcg729_factory, sizeof(bcg729_factory));
+ bcg729_factory.base.op = &bcg729_factory_op;
+ bcg729_factory.base.factory_data = NULL;
+ bcg729_factory.endpt = endpt;
+
+ /* Create pool */
+ bcg729_factory.pool = pjmedia_endpt_create_pool(endpt, "bcg729", 4000,
+ 4000);
+ if (!bcg729_factory.pool)
+ return PJ_ENOMEM;
+
+ /* Create mutex. */
+ status = pj_mutex_create_simple(bcg729_factory.pool, "bcg729",
+ &bcg729_factory.mutex);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Get the codec manager. */
+ codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
+ if (!codec_mgr) {
+ status = PJ_EINVALIDOP;
+ goto on_error;
+ }
+
+ /* Register codec factory to endpoint. */
+ status = pjmedia_codec_mgr_register_factory(codec_mgr,
+ &bcg729_factory.base);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ PJ_LOG(4,(THIS_FILE, "BCG729 codec initialized"));
+ return PJ_SUCCESS;
+
+on_error:
+ if (bcg729_factory.mutex) {
+ pj_mutex_destroy(bcg729_factory.mutex);
+ bcg729_factory.mutex = NULL;
+ }
+ if (bcg729_factory.pool) {
+ pj_pool_release(bcg729_factory.pool);
+ bcg729_factory.pool = NULL;
+ }
+
+ return status;
+}
+
+/*
+ * Unregister BCG729 codec factory from pjmedia endpoint and deinitialize
+ * the BCG729 codec library.
+ */
+PJ_DEF(pj_status_t) pjmedia_codec_bcg729_deinit(void)
+{
+ pjmedia_codec_mgr *codec_mgr;
+ pj_status_t status;
+
+ if (bcg729_factory.endpt == NULL) {
+ /* Not registered. */
+ return PJ_SUCCESS;
+ }
+
+ /* Lock mutex. */
+ pj_mutex_lock(bcg729_factory.mutex);
+
+ /* Get the codec manager. */
+ codec_mgr = pjmedia_endpt_get_codec_mgr(bcg729_factory.endpt);
+ if (!codec_mgr) {
+ bcg729_factory.endpt = NULL;
+ pj_mutex_unlock(bcg729_factory.mutex);
+ return PJ_EINVALIDOP;
+ }
+
+ /* Unregister bcg729 codec factory. */
+ status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
+ &bcg729_factory.base);
+ bcg729_factory.endpt = NULL;
+
+ /* Destroy mutex. */
+ pj_mutex_unlock(bcg729_factory.mutex);
+ pj_mutex_destroy(bcg729_factory.mutex);
+ bcg729_factory.mutex = NULL;
+
+ /* Release pool. */
+ pj_pool_release(bcg729_factory.pool);
+ bcg729_factory.pool = NULL;
+
+ return status;
+}
+
+
+/*
+ * Check if factory can allocate the specified codec.
+ */
+static pj_status_t bcg729_test_alloc(pjmedia_codec_factory *factory,
+ const pjmedia_codec_info *info )
+{
+ pj_str_t g729_tag = pj_str(G729_TAG);
+ PJ_UNUSED_ARG(factory);
+ PJ_ASSERT_RETURN(factory==&bcg729_factory.base, PJ_EINVAL);
+
+ /* Type MUST be audio. */
+ if (info->type != PJMEDIA_TYPE_AUDIO)
+ return PJMEDIA_CODEC_EUNSUP;
+
+ /* Check encoding name. */
+ if (pj_stricmp(&info->encoding_name, &g729_tag) != 0)
+ return PJMEDIA_CODEC_EUNSUP;
+
+ /* Channel count must be one */
+ if (info->channel_cnt != G729_CHANNEL_COUNT)
+ return PJMEDIA_CODEC_EUNSUP;
+
+ /* Check clock-rate */
+ if (info->clock_rate != G729_CLOCK_RATE)
+ return PJMEDIA_CODEC_EUNSUP;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Generate default attribute.
+ */
+static pj_status_t bcg729_default_attr(pjmedia_codec_factory *factory,
+ const pjmedia_codec_info *id,
+ pjmedia_codec_param *attr )
+{
+ PJ_ASSERT_RETURN(factory==&bcg729_factory.base, PJ_EINVAL);
+
+ if (id->pt != PJMEDIA_RTP_PT_G729)
+ return PJMEDIA_CODEC_EUNSUP;
+
+ pj_bzero(attr, sizeof(pjmedia_codec_param));
+ attr->info.pt = PJMEDIA_RTP_PT_G729;
+ attr->info.channel_cnt = G729_CHANNEL_COUNT;
+ attr->info.clock_rate = G729_CLOCK_RATE;
+ attr->info.avg_bps = G729_DEFAULT_BIT_RATE;
+ attr->info.max_bps = G729_MAX_BIT_RATE;
+
+ attr->info.pcm_bits_per_sample = G729_FRAME_PER_PACKET * 8;
+ attr->info.frm_ptime = (pj_uint16_t)
+ (G729_SAMPLES_PER_FRAME * 1000 /
+ G729_CHANNEL_COUNT /
+ G729_CLOCK_RATE);
+ attr->setting.frm_per_pkt = G729_FRAME_PER_PACKET;
+
+ /* Default flags. */
+ attr->setting.plc = 1;
+ attr->setting.penh= 0;
+ attr->setting.vad = 1;
+ attr->setting.cng = attr->setting.vad;
+
+ if (attr->setting.vad == 0) {
+ attr->setting.dec_fmtp.cnt = 1;
+ pj_strset2(&attr->setting.dec_fmtp.param[0].name, "annexb");
+ pj_strset2(&attr->setting.dec_fmtp.param[0].val, "no");
+ }
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Enum codecs supported by this factory.
+ */
+static pj_status_t bcg729_enum_codecs(pjmedia_codec_factory *factory,
+ unsigned *count,
+ pjmedia_codec_info codecs[])
+{
+ PJ_ASSERT_RETURN(factory==&bcg729_factory.base, PJ_EINVAL);
+ PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
+
+ pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
+ codecs[0].encoding_name = pj_str(G729_TAG);
+ codecs[0].pt = PJMEDIA_RTP_PT_G729;
+ codecs[0].type = PJMEDIA_TYPE_AUDIO;
+ codecs[0].clock_rate = G729_CLOCK_RATE;
+ codecs[0].channel_cnt = G729_CHANNEL_COUNT;
+
+ *count = 1;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Allocate a new BCG729 codec instance.
+ */
+static pj_status_t bcg729_alloc_codec(pjmedia_codec_factory *factory,
+ const pjmedia_codec_info *id,
+ pjmedia_codec **p_codec)
+{
+ pj_pool_t *pool;
+ pjmedia_codec *codec;
+ bcg729_private *bcg729_data;
+
+ PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
+ PJ_ASSERT_RETURN(factory == &bcg729_factory.base, PJ_EINVAL);
+
+ pj_mutex_lock(bcg729_factory.mutex);
+
+ /* Create pool for codec instance */
+ pool = pjmedia_endpt_create_pool(bcg729_factory.endpt, "bcg729", 512, 512);
+
+ /* Allocate codec */
+ codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
+ codec->op = &bcg729_op;
+ codec->factory = factory;
+ codec->codec_data = PJ_POOL_ZALLOC_T(pool, bcg729_private);
+ bcg729_data = (bcg729_private*) codec->codec_data;
+ bcg729_data->pool = pool;
+
+ pj_mutex_unlock(bcg729_factory.mutex);
+
+ *p_codec = codec;
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Free codec.
+ */
+static pj_status_t bcg729_dealloc_codec(pjmedia_codec_factory *factory,
+ pjmedia_codec *codec )
+{
+ bcg729_private *bcg729_data;
+
+ PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
+ PJ_ASSERT_RETURN(factory == &bcg729_factory.base, PJ_EINVAL);
+
+ bcg729_data = (bcg729_private*)codec->codec_data;
+
+ /* Close codec, if it's not closed. */
+ if (bcg729_data->encoder || bcg729_data->decoder) {
+ bcg729_codec_close(codec);
+ }
+
+ pj_pool_release(bcg729_data->pool);
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Init codec.
+ */
+static pj_status_t bcg729_codec_init(pjmedia_codec *codec,
+ pj_pool_t *pool )
+{
+ PJ_UNUSED_ARG(codec);
+ PJ_UNUSED_ARG(pool);
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Open codec.
+ */
+static pj_status_t bcg729_codec_open(pjmedia_codec *codec,
+ pjmedia_codec_param *attr )
+{
+ bcg729_private *bcg729_data;
+ unsigned i;
+
+ PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
+
+ bcg729_data = (bcg729_private*) codec->codec_data;
+
+ /* Already open? */
+ if (bcg729_data->encoder && bcg729_data->decoder)
+ return PJ_SUCCESS;
+
+ bcg729_data->vad_enabled = (attr->setting.vad != 0);
+ bcg729_data->plc_enabled = (attr->setting.plc != 0);
+
+ /* Check if G729 Annex B is signaled to be disabled */
+ for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
+ if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].name, "annexb")==0)
+ {
+ if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].val, "no")==0)
+ {
+ attr->setting.vad = 0;
+ bcg729_data->vad_enabled = PJ_FALSE;
+ }
+ break;
+ }
+ }
+
+ bcg729_data->encoder = initBcg729EncoderChannel(
+ bcg729_data->vad_enabled?1:0);
+ if (!bcg729_data->encoder)
+ return PJMEDIA_CODEC_EFAILED;
+
+ bcg729_data->decoder = initBcg729DecoderChannel();
+ if (!bcg729_data->decoder)
+ return PJMEDIA_CODEC_EFAILED;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Close codec.
+ */
+static pj_status_t bcg729_codec_close( pjmedia_codec *codec )
+{
+ bcg729_private *bcg729_data;
+
+ PJ_ASSERT_RETURN(codec, PJ_EINVAL);
+
+ bcg729_data = (bcg729_private *)codec->codec_data;
+
+ if (bcg729_data->encoder) {
+ closeBcg729EncoderChannel(bcg729_data->encoder);
+ bcg729_data->encoder = NULL;
+ }
+ if (bcg729_data->decoder) {
+ closeBcg729DecoderChannel(bcg729_data->decoder);
+ bcg729_data->decoder = NULL;
+ }
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Get frames in the packet.
+ */
+static pj_status_t bcg729_codec_parse(pjmedia_codec *codec,
+ void *pkt,
+ pj_size_t pkt_size,
+ const pj_timestamp *ts,
+ unsigned *frame_cnt,
+ pjmedia_frame frames[])
+{
+ unsigned count = 0;
+ PJ_UNUSED_ARG(codec);
+
+ PJ_ASSERT_RETURN(codec && ts && frames && frame_cnt, PJ_EINVAL);
+
+ while (pkt_size >= G729_FRAME_SIZE && count < *frame_cnt) {
+ frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
+ frames[count].buf = pkt;
+ frames[count].size = G729_FRAME_SIZE;
+ frames[count].timestamp.u64 = ts->u64 + count * G729_SAMPLES_PER_FRAME;
+
+ pkt = ((char*)pkt) + 10;
+ pkt_size -= 10;
+
+ ++count;
+ }
+
+ *frame_cnt = count;
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Modify codec settings.
+ */
+static pj_status_t bcg729_codec_modify(pjmedia_codec *codec,
+ const pjmedia_codec_param *attr )
+{
+ PJ_UNUSED_ARG(codec);
+ PJ_UNUSED_ARG(attr);
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Encode frame.
+ */
+static pj_status_t bcg729_codec_encode(pjmedia_codec *codec,
+ const struct pjmedia_frame *input,
+ unsigned output_buf_len,
+ struct pjmedia_frame *output)
+{
+ bcg729_private *bcg729_data;
+ pj_int16_t *pcm_in;
+ unsigned nsamples;
+ pj_uint8_t stream_len;
+
+ PJ_ASSERT_RETURN(codec && input && output_buf_len && output, PJ_EINVAL);
+
+ bcg729_data = (bcg729_private*)codec->codec_data;
+ pcm_in = (pj_int16_t*)input->buf;
+
+ /* Check frame in size */
+ nsamples = input->size >> 1;
+ output->size = 0;
+
+ /* Encode */
+ while (nsamples >= G729_SAMPLES_PER_FRAME) {
+ bcg729Encoder(bcg729_data->encoder, pcm_in,
+ (unsigned char*)output->buf + output->size, &stream_len);
+
+ pcm_in += G729_SAMPLES_PER_FRAME;
+ nsamples -= G729_SAMPLES_PER_FRAME;
+
+ if (stream_len == 0) {
+ /* Untransmitted */
+ break;
+ } else {
+ output->size += stream_len;
+ if (stream_len == 2) {
+ /* SID */
+ break;
+ }
+ }
+ }
+
+ output->type = PJMEDIA_FRAME_TYPE_AUDIO;
+ output->timestamp = input->timestamp;
+
+ return PJ_SUCCESS;
+}
+
+
+static pj_status_t bcg729_codec_decode(pjmedia_codec *codec,
+ const struct pjmedia_frame *input,
+ unsigned output_buf_len,
+ struct pjmedia_frame *output)
+{
+ bcg729_private *bcg729_data;
+
+ PJ_ASSERT_RETURN(codec && input && output_buf_len && output, PJ_EINVAL);
+
+ bcg729_data = (struct bcg729_private*) codec->codec_data;
+
+ bcg729Decoder(bcg729_data->decoder,
+ (unsigned char*)input->buf,
+ G729_FRAME_SIZE,
+ 0,
+ 0,
+ 0,
+ (short*)output->buf);
+
+ output->size = G729_SAMPLES_PER_FRAME * G729_FRAME_PER_PACKET;
+ output->type = PJMEDIA_FRAME_TYPE_AUDIO;
+ output->timestamp = input->timestamp;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Recover lost frame.
+ */
+static pj_status_t bcg729_codec_recover(pjmedia_codec *codec,
+ unsigned output_buf_len,
+ struct pjmedia_frame *output)
+{
+ bcg729_private *bcg729_data;
+
+ PJ_ASSERT_RETURN(codec && output_buf_len && output, PJ_EINVAL);
+
+ bcg729_data = (struct bcg729_private*) codec->codec_data;
+
+ output->size = G729_SAMPLES_PER_FRAME * G729_FRAME_PER_PACKET;
+ output->type = PJMEDIA_FRAME_TYPE_AUDIO;
+
+ if (bcg729_data->plc_enabled) {
+ bcg729Decoder(bcg729_data->decoder,
+ NULL,
+ G729_FRAME_SIZE,
+ 1,
+ 0,
+ 0,
+ (short*)output->buf);
+ } else {
+ pjmedia_zero_samples((pj_int16_t*)output->buf, G729_SAMPLES_PER_FRAME);
+ }
+
+ return PJ_SUCCESS;
+}
+
+#endif /* PJMEDIA_HAS_BCG729 */
diff --git a/pjmedia/src/pjmedia-codec/h264_packetizer.c b/pjmedia/src/pjmedia-codec/h264_packetizer.c
index 9b22334..0007b10 100644
--- a/pjmedia/src/pjmedia-codec/h264_packetizer.c
+++ b/pjmedia/src/pjmedia-codec/h264_packetizer.c
@@ -1,4 +1,4 @@
-/* $Id: h264_packetizer.c 4537 2013-06-19 06:47:43Z riza $ */
+/* $Id: h264_packetizer.c 5603 2017-06-08 06:23:56Z ming $ */
/*
* Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
*
@@ -94,7 +94,9 @@ PJ_DEF(pj_status_t) pjmedia_h264_packetizer_create(
if (cfg &&
cfg->mode != PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED &&
- cfg->mode != PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL)
+ cfg->mode != PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL &&
+ cfg->unpack_nal_start != 0 && cfg->unpack_nal_start != 3 &&
+ cfg->unpack_nal_start != 4)
{
return PJ_ENOTSUP;
}
@@ -102,9 +104,12 @@ PJ_DEF(pj_status_t) pjmedia_h264_packetizer_create(
p_ = PJ_POOL_ZALLOC_T(pool, pjmedia_h264_packetizer);
if (cfg) {
pj_memcpy(&p_->cfg, cfg, sizeof(*cfg));
+ if (p_->cfg.unpack_nal_start == 0)
+ p_->cfg.unpack_nal_start = 3;
} else {
p_->cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED;
p_->cfg.mtu = PJMEDIA_MAX_VID_PAYLOAD_SIZE;
+ p_->cfg.unpack_nal_start = 3;
}
*p = p_;
@@ -347,11 +352,13 @@ PJ_DEF(pj_status_t) pjmedia_h264_unpacketize(pjmedia_h264_packetizer *pktz,
pj_size_t bits_len,
unsigned *bits_pos)
{
- const pj_uint8_t nal_start_code[3] = {0, 0, 1};
+ const pj_uint8_t nal_start[4] = {0, 0, 0, 1};
+ const pj_uint8_t *nal_start_code;
enum { MIN_PAYLOAD_SIZE = 2 };
pj_uint8_t nal_type;
- PJ_UNUSED_ARG(pktz);
+ nal_start_code = nal_start + PJ_ARRAY_SIZE(nal_start) -
+ pktz->cfg.unpack_nal_start;
#if DBG_UNPACKETIZE
if (*bits_pos == 0 && payload_len) {
@@ -384,15 +391,15 @@ PJ_DEF(pj_status_t) pjmedia_h264_unpacketize(pjmedia_h264_packetizer *pktz,
pj_uint8_t *p = bits + *bits_pos;
/* Validate bitstream length */
- if (bits_len-*bits_pos < payload_len+PJ_ARRAY_SIZE(nal_start_code)) {
+ if (bits_len-*bits_pos < payload_len+pktz->cfg.unpack_nal_start) {
/* Insufficient bistream buffer, discard this payload */
- pj_assert(!"Insufficient H.263 bitstream buffer");
+ pj_assert(!"Insufficient H.264 bitstream buffer");
return PJ_ETOOSMALL;
}
/* Write NAL unit start code */
- pj_memcpy(p, &nal_start_code, PJ_ARRAY_SIZE(nal_start_code));
- p += PJ_ARRAY_SIZE(nal_start_code);
+ pj_memcpy(p, nal_start_code, pktz->cfg.unpack_nal_start);
+ p += pktz->cfg.unpack_nal_start;
/* Write NAL unit */
pj_memcpy(p, payload, payload_len);
@@ -419,7 +426,7 @@ PJ_DEF(pj_status_t) pjmedia_h264_unpacketize(pjmedia_h264_packetizer *pktz,
/* Validate bitstream length */
if (bits_len - *bits_pos < payload_len + 32) {
/* Insufficient bistream buffer, discard this payload */
- pj_assert(!"Insufficient H.263 bitstream buffer");
+ pj_assert(!"Insufficient H.264 bitstream buffer");
return PJ_ETOOSMALL;
}
@@ -432,8 +439,8 @@ PJ_DEF(pj_status_t) pjmedia_h264_unpacketize(pjmedia_h264_packetizer *pktz,
pj_uint16_t tmp_nal_size;
/* Write NAL unit start code */
- pj_memcpy(p, &nal_start_code, PJ_ARRAY_SIZE(nal_start_code));
- p += PJ_ARRAY_SIZE(nal_start_code);
+ pj_memcpy(p, nal_start_code, pktz->cfg.unpack_nal_start);
+ p += pktz->cfg.unpack_nal_start;
/* Get NAL unit size */
tmp_nal_size = (*q << 8) | *(q+1);
@@ -470,9 +477,9 @@ PJ_DEF(pj_status_t) pjmedia_h264_unpacketize(pjmedia_h264_packetizer *pktz,
p = bits + *bits_pos;
/* Validate bitstream length */
- if (bits_len-*bits_pos < payload_len+PJ_ARRAY_SIZE(nal_start_code)) {
+ if (bits_len-*bits_pos < payload_len+pktz->cfg.unpack_nal_start) {
/* Insufficient bistream buffer, drop this packet */
- pj_assert(!"Insufficient H.263 bitstream buffer");
+ pj_assert(!"Insufficient H.264 bitstream buffer");
pktz->unpack_prev_lost = PJ_TRUE;
return PJ_ETOOSMALL;
}
@@ -486,8 +493,8 @@ PJ_DEF(pj_status_t) pjmedia_h264_unpacketize(pjmedia_h264_packetizer *pktz,
/* Fill bitstream */
if (S) {
/* This is the first part, write NAL unit start code */
- pj_memcpy(p, &nal_start_code, PJ_ARRAY_SIZE(nal_start_code));
- p += PJ_ARRAY_SIZE(nal_start_code);
+ pj_memcpy(p, nal_start_code, pktz->cfg.unpack_nal_start);
+ p += pktz->cfg.unpack_nal_start;
/* Write NAL unit octet */
*p++ = (NRI << 5) | TYPE;
diff --git a/pjmedia/src/pjmedia-codec/l16.c b/pjmedia/src/pjmedia-codec/l16.c
index e9d1493..1f09c83 100644
--- a/pjmedia/src/pjmedia-codec/l16.c
+++ b/pjmedia/src/pjmedia-codec/l16.c
@@ -1,4 +1,4 @@
-/* $Id: l16.c 5153 2015-08-07 09:22:32Z ming $ */
+/* $Id: l16.c 5632 2017-07-27 06:45:48Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -312,6 +312,7 @@ static pj_status_t l16_enum_codecs( pjmedia_codec_factory *factory,
++count;
}
+#if PJMEDIA_CODEC_L16_HAS_8KHZ_MONO
if (count < *max_count) {
/* 8KHz mono */
codecs[count].type = PJMEDIA_TYPE_AUDIO;
@@ -321,7 +322,9 @@ static pj_status_t l16_enum_codecs( pjmedia_codec_factory *factory,
codecs[count].channel_cnt = 1;
++count;
}
+#endif
+#if PJMEDIA_CODEC_L16_HAS_8KHZ_STEREO
if (count < *max_count) {
/* 8KHz stereo */
codecs[count].type = PJMEDIA_TYPE_AUDIO;
@@ -331,6 +334,7 @@ static pj_status_t l16_enum_codecs( pjmedia_codec_factory *factory,
codecs[count].channel_cnt = 2;
++count;
}
+#endif
// disable some L16 modes
#if 0
@@ -355,6 +359,7 @@ static pj_status_t l16_enum_codecs( pjmedia_codec_factory *factory,
}
#endif
+#if PJMEDIA_CODEC_L16_HAS_16KHZ_MONO
if (count < *max_count) {
/* 16000 Hz mono */
codecs[count].type = PJMEDIA_TYPE_AUDIO;
@@ -364,8 +369,9 @@ static pj_status_t l16_enum_codecs( pjmedia_codec_factory *factory,
codecs[count].channel_cnt = 1;
++count;
}
+#endif
-
+#if PJMEDIA_CODEC_L16_HAS_16KHZ_STEREO
if (count < *max_count) {
/* 16000 Hz stereo */
codecs[count].type = PJMEDIA_TYPE_AUDIO;
@@ -375,6 +381,7 @@ static pj_status_t l16_enum_codecs( pjmedia_codec_factory *factory,
codecs[count].channel_cnt = 2;
++count;
}
+#endif
// disable some L16 modes
#if 0
diff --git a/pjmedia/src/pjmedia-codec/opus.c b/pjmedia/src/pjmedia-codec/opus.c
index 78d15bb..34433ff 100644
--- a/pjmedia/src/pjmedia-codec/opus.c
+++ b/pjmedia/src/pjmedia-codec/opus.c
@@ -1,4 +1,4 @@
-/* $Id: opus.c 5374 2016-07-01 08:22:14Z riza $ */
+/* $Id: opus.c 5659 2017-09-25 02:58:42Z riza $ */
/*
* Copyright (C) 2015-2016 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2012-2015 Zaark Technology AB
@@ -457,6 +457,7 @@ static pj_status_t factory_default_attr( pjmedia_codec_factory *factory,
const pjmedia_codec_info *ci,
pjmedia_codec_param *attr )
{
+ PJ_UNUSED_ARG(factory);
TRACE_((THIS_FILE, "%s:%d: - TRACE", __FUNCTION__, __LINE__));
pj_bzero(attr, sizeof(pjmedia_codec_param));
@@ -520,6 +521,7 @@ static pj_status_t factory_alloc_codec( pjmedia_codec_factory *factory,
struct opus_data *opus_data;
struct opus_codec_factory *f = (struct opus_codec_factory*) factory;
+ PJ_UNUSED_ARG(ci);
TRACE_((THIS_FILE, "%s:%d: - TRACE", __FUNCTION__, __LINE__));
pool = pjmedia_endpt_create_pool(f->endpt, "opus", 512, 512);
@@ -931,6 +933,8 @@ static pj_status_t codec_decode( pjmedia_codec *codec,
pjmedia_frame *inframe;
int fec = 0;
+ PJ_UNUSED_ARG(output_buf_len);
+
pj_mutex_lock (opus_data->mutex);
if (opus_data->dec_frame_index == -1) {
@@ -1018,13 +1022,14 @@ static pj_status_t codec_recover( pjmedia_codec *codec,
int decoded_samples;
pjmedia_frame *inframe;
+ PJ_UNUSED_ARG(output_buf_len);
pj_mutex_lock (opus_data->mutex);
if (opus_data->dec_frame_index == -1) {
/* Recover the first packet? Don't think so, fill it with zeroes. */
pj_uint16_t samples_per_frame;
- samples_per_frame = (opus_data->cfg.sample_rate *
- opus_data->ptime) / 1000;
+ samples_per_frame = (pj_uint16_t)(opus_data->cfg.sample_rate *
+ opus_data->ptime) / 1000;
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
output->size = samples_per_frame << 1;
pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame);
diff --git a/pjmedia/src/pjmedia-codec/vid_toolbox.m b/pjmedia/src/pjmedia-codec/vid_toolbox.m
new file mode 100644
index 0000000..55b799a
--- /dev/null
+++ b/pjmedia/src/pjmedia-codec/vid_toolbox.m
@@ -0,0 +1,1263 @@
+/* $Id: vid_toolbox.m 5625 2017-07-07 10:59:25Z ming $ */
+/*
+ * Copyright (C)2017 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjmedia-codec/vid_toolbox.h>
+#include <pjmedia-codec/h264_packetizer.h>
+#include <pjmedia/vid_codec_util.h>
+#include <pjmedia/errno.h>
+#include <pj/log.h>
+
+#if defined(PJMEDIA_HAS_VID_TOOLBOX_CODEC) && \
+ PJMEDIA_HAS_VID_TOOLBOX_CODEC != 0 && \
+ defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
+
+#import <Foundation/Foundation.h>
+#import <VideoToolbox/VideoToolbox.h>
+
+#include "TargetConditionals.h"
+
+#define THIS_FILE "vid_toolbox.m"
+
+#if (defined(PJ_DARWINOS) && PJ_DARWINOS != 0 && TARGET_OS_IPHONE)
+# define DEFAULT_WIDTH 352
+# define DEFAULT_HEIGHT 288
+#else
+# define DEFAULT_WIDTH 720
+# define DEFAULT_HEIGHT 480
+#endif
+
+#define DEFAULT_FPS 15
+#define DEFAULT_AVG_BITRATE 256000
+#define DEFAULT_MAX_BITRATE 256000
+
+#define MAX_RX_WIDTH 1200
+#define MAX_RX_HEIGHT 800
+
+#define SPS_PPS_BUF_SIZE 32
+
+/* For better compatibility with other codecs (OpenH264 and x264),
+ * we decode the whole packets at once.
+ */
+#define DECODE_WHOLE PJ_TRUE
+
+/* Maximum duration from one key frame to the next (in seconds). */
+#define KEYFRAME_INTERVAL 5
+
+/*
+ * Factory operations.
+ */
+static pj_status_t vtool_test_alloc(pjmedia_vid_codec_factory *factory,
+ const pjmedia_vid_codec_info *info );
+static pj_status_t vtool_default_attr(pjmedia_vid_codec_factory *factory,
+ const pjmedia_vid_codec_info *info,
+ pjmedia_vid_codec_param *attr );
+static pj_status_t vtool_enum_info(pjmedia_vid_codec_factory *factory,
+ unsigned *count,
+ pjmedia_vid_codec_info codecs[]);
+static pj_status_t vtool_alloc_codec(pjmedia_vid_codec_factory *factory,
+ const pjmedia_vid_codec_info *info,
+ pjmedia_vid_codec **p_codec);
+static pj_status_t vtool_dealloc_codec(pjmedia_vid_codec_factory *factory,
+ pjmedia_vid_codec *codec );
+
+
+/*
+ * Codec operations
+ */
+static pj_status_t vtool_codec_init(pjmedia_vid_codec *codec,
+ pj_pool_t *pool );
+static pj_status_t vtool_codec_open(pjmedia_vid_codec *codec,
+ pjmedia_vid_codec_param *param );
+static pj_status_t vtool_codec_close(pjmedia_vid_codec *codec);
+static pj_status_t vtool_codec_modify(pjmedia_vid_codec *codec,
+ const pjmedia_vid_codec_param *param);
+static pj_status_t vtool_codec_get_param(pjmedia_vid_codec *codec,
+ pjmedia_vid_codec_param *param);
+static pj_status_t vtool_codec_encode_begin(pjmedia_vid_codec *codec,
+ const pjmedia_vid_encode_opt *opt,
+ const pjmedia_frame *input,
+ unsigned out_size,
+ pjmedia_frame *output,
+ pj_bool_t *has_more);
+static pj_status_t vtool_codec_encode_more(pjmedia_vid_codec *codec,
+ unsigned out_size,
+ pjmedia_frame *output,
+ pj_bool_t *has_more);
+static pj_status_t vtool_codec_decode(pjmedia_vid_codec *codec,
+ pj_size_t count,
+ pjmedia_frame packets[],
+ unsigned out_size,
+ pjmedia_frame *output);
+
+/* Definition for Video Toolbox codecs operations. */
+static pjmedia_vid_codec_op vtool_codec_op =
+{
+ &vtool_codec_init,
+ &vtool_codec_open,
+ &vtool_codec_close,
+ &vtool_codec_modify,
+ &vtool_codec_get_param,
+ &vtool_codec_encode_begin,
+ &vtool_codec_encode_more,
+ &vtool_codec_decode,
+ NULL
+};
+
+/* Definition for Video Toolbox codecs factory operations. */
+static pjmedia_vid_codec_factory_op vtool_factory_op =
+{
+ &vtool_test_alloc,
+ &vtool_default_attr,
+ &vtool_enum_info,
+ &vtool_alloc_codec,
+ &vtool_dealloc_codec
+};
+
+
+static struct vtool_factory
+{
+ pjmedia_vid_codec_factory base;
+ pjmedia_vid_codec_mgr *mgr;
+ pj_pool_factory *pf;
+ pj_pool_t *pool;
+} vtool_factory;
+
+
+typedef struct vtool_codec_data
+{
+ pjmedia_vid_codec *codec;
+ pj_pool_t *pool;
+ pjmedia_vid_codec_param *prm;
+ pj_bool_t whole;
+ pjmedia_h264_packetizer *pktz;
+
+ /* Encoder */
+ VTCompressionSessionRef enc;
+ void *enc_buf;
+ unsigned enc_buf_size;
+
+ unsigned enc_input_size;
+ unsigned enc_wxh;
+ unsigned enc_fps;
+ unsigned enc_frm_cnt;
+ unsigned enc_frame_size;
+ unsigned enc_processed;
+ pj_bool_t enc_is_keyframe;
+
+ /* Decoder */
+ VTDecompressionSessionRef dec;
+ pj_uint8_t *dec_buf;
+ unsigned dec_buf_size;
+ CMFormatDescriptionRef dec_format;
+
+ unsigned dec_sps_size;
+ unsigned dec_pps_size;
+ unsigned char dec_sps[SPS_PPS_BUF_SIZE];
+ unsigned char dec_pps[SPS_PPS_BUF_SIZE];
+
+ pjmedia_frame *dec_frame;
+ pj_bool_t dec_fmt_change;
+} vtool_codec_data;
+
+/* Prototypes */
+static OSStatus create_decoder(struct vtool_codec_data *vtool_data);
+
+PJ_DEF(pj_status_t) pjmedia_codec_vid_toolbox_init(pjmedia_vid_codec_mgr *mgr,
+ pj_pool_factory *pf)
+{
+ const pj_str_t h264_name = { (char*)"H264", 4};
+ pj_status_t status;
+
+ if (vtool_factory.pool != NULL) {
+ /* Already initialized. */
+ return PJ_SUCCESS;
+ }
+
+ if (!mgr) mgr = pjmedia_vid_codec_mgr_instance();
+ PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
+
+ /* Create Video Toolbox codec factory. */
+ vtool_factory.base.op = &vtool_factory_op;
+ vtool_factory.base.factory_data = NULL;
+ vtool_factory.mgr = mgr;
+ vtool_factory.pf = pf;
+ vtool_factory.pool = pj_pool_create(pf, "vtoolfactory", 256, 256, NULL);
+ if (!vtool_factory.pool)
+ return PJ_ENOMEM;
+
+ /* Registering format match for SDP negotiation */
+ status = pjmedia_sdp_neg_register_fmt_match_cb(
+ &h264_name,
+ &pjmedia_vid_codec_h264_match_sdp);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Register codec factory to codec manager. */
+ status = pjmedia_vid_codec_mgr_register_factory(mgr,
+ &vtool_factory.base);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ PJ_LOG(4,(THIS_FILE, "Video Toolbox codec initialized"));
+
+ /* Done. */
+ return PJ_SUCCESS;
+
+on_error:
+ pj_pool_release(vtool_factory.pool);
+ vtool_factory.pool = NULL;
+ return status;
+}
+
+/*
+ * Unregister Video Toolbox codecs factory from pjmedia endpoint.
+ */
+PJ_DEF(pj_status_t) pjmedia_codec_vid_toolbox_deinit(void)
+{
+ pj_status_t status = PJ_SUCCESS;
+
+ if (vtool_factory.pool == NULL) {
+ /* Already deinitialized */
+ return PJ_SUCCESS;
+ }
+
+ /* Unregister Video Toolbox codecs factory. */
+ status = pjmedia_vid_codec_mgr_unregister_factory(vtool_factory.mgr,
+ &vtool_factory.base);
+
+ /* Destroy pool. */
+ pj_pool_release(vtool_factory.pool);
+ vtool_factory.pool = NULL;
+
+ return status;
+}
+
+static pj_status_t vtool_test_alloc(pjmedia_vid_codec_factory *factory,
+ const pjmedia_vid_codec_info *info )
+{
+ PJ_ASSERT_RETURN(factory == &vtool_factory.base, PJ_EINVAL);
+
+ if (info->fmt_id == PJMEDIA_FORMAT_H264 &&
+ info->pt != 0)
+ {
+ return PJ_SUCCESS;
+ }
+
+ return PJMEDIA_CODEC_EUNSUP;
+}
+
+static pj_status_t vtool_default_attr(pjmedia_vid_codec_factory *factory,
+ const pjmedia_vid_codec_info *info,
+ pjmedia_vid_codec_param *attr )
+{
+ PJ_ASSERT_RETURN(factory == &vtool_factory.base, PJ_EINVAL);
+ PJ_ASSERT_RETURN(info && attr, PJ_EINVAL);
+
+ pj_bzero(attr, sizeof(pjmedia_vid_codec_param));
+
+ attr->dir = PJMEDIA_DIR_ENCODING_DECODING;
+ attr->packing = PJMEDIA_VID_PACKING_PACKETS;
+
+ /* Encoded format */
+ pjmedia_format_init_video(&attr->enc_fmt, PJMEDIA_FORMAT_H264,
+ DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_FPS, 1);
+
+ /* Decoded format */
+ pjmedia_format_init_video(&attr->dec_fmt, PJMEDIA_FORMAT_I420,
+ DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_FPS, 1);
+
+ /* Decoding fmtp */
+ attr->dec_fmtp.cnt = 2;
+ attr->dec_fmtp.param[0].name = pj_str((char*)"profile-level-id");
+ attr->dec_fmtp.param[0].val = pj_str((char*)"42e01e");
+ attr->dec_fmtp.param[1].name = pj_str((char*)" packetization-mode");
+ attr->dec_fmtp.param[1].val = pj_str((char*)"1");
+
+ /* Bitrate */
+ attr->enc_fmt.det.vid.avg_bps = DEFAULT_AVG_BITRATE;
+ attr->enc_fmt.det.vid.max_bps = DEFAULT_MAX_BITRATE;
+
+ /* Encoding MTU */
+ attr->enc_mtu = PJMEDIA_MAX_VID_PAYLOAD_SIZE;
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t vtool_enum_info(pjmedia_vid_codec_factory *factory,
+ unsigned *count,
+ pjmedia_vid_codec_info info[])
+{
+ PJ_ASSERT_RETURN(info && *count > 0, PJ_EINVAL);
+ PJ_ASSERT_RETURN(factory == &vtool_factory.base, PJ_EINVAL);
+
+ *count = 1;
+ info->fmt_id = PJMEDIA_FORMAT_H264;
+ info->pt = PJMEDIA_RTP_PT_H264;
+ info->encoding_name = pj_str((char*)"H264");
+ info->encoding_desc = pj_str((char*)"Video Toolbox codec");
+ info->clock_rate = 90000;
+ info->dir = PJMEDIA_DIR_ENCODING_DECODING;
+ info->dec_fmt_id_cnt = 1;
+ info->dec_fmt_id[0] = PJMEDIA_FORMAT_I420;
+ info->packings = PJMEDIA_VID_PACKING_PACKETS |
+ PJMEDIA_VID_PACKING_WHOLE;
+ info->fps_cnt = 3;
+ info->fps[0].num = 15;
+ info->fps[0].denum = 1;
+ info->fps[1].num = 25;
+ info->fps[1].denum = 1;
+ info->fps[2].num = 30;
+ info->fps[2].denum = 1;
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t vtool_alloc_codec(pjmedia_vid_codec_factory *factory,
+ const pjmedia_vid_codec_info *info,
+ pjmedia_vid_codec **p_codec)
+{
+ pj_pool_t *pool;
+ pjmedia_vid_codec *codec;
+ vtool_codec_data *vtool_data;
+
+ PJ_ASSERT_RETURN(factory == &vtool_factory.base && info && p_codec,
+ PJ_EINVAL);
+
+ *p_codec = NULL;
+
+ pool = pj_pool_create(vtool_factory.pf, "vtool%p", 512, 512, NULL);
+ if (!pool)
+ return PJ_ENOMEM;
+
+ /* codec instance */
+ codec = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_codec);
+ codec->factory = factory;
+ codec->op = &vtool_codec_op;
+
+ /* codec data */
+ vtool_data = PJ_POOL_ZALLOC_T(pool, vtool_codec_data);
+ vtool_data->pool = pool;
+ vtool_data->codec = codec;
+ codec->codec_data = vtool_data;
+
+ *p_codec = codec;
+ return PJ_SUCCESS;
+}
+
+static pj_status_t vtool_dealloc_codec(pjmedia_vid_codec_factory *factory,
+ pjmedia_vid_codec *codec )
+{
+ vtool_codec_data *vtool_data;
+
+ PJ_ASSERT_RETURN(codec, PJ_EINVAL);
+
+ PJ_UNUSED_ARG(factory);
+
+ vtool_data = (vtool_codec_data*) codec->codec_data;
+ pj_pool_release(vtool_data->pool);
+ return PJ_SUCCESS;
+}
+
+static pj_status_t vtool_codec_init(pjmedia_vid_codec *codec,
+ pj_pool_t *pool )
+{
+ PJ_ASSERT_RETURN(codec && pool, PJ_EINVAL);
+ PJ_UNUSED_ARG(codec);
+ PJ_UNUSED_ARG(pool);
+ return PJ_SUCCESS;
+}
+
+static void encode_cb(void *outputCallbackRefCon,
+ void *sourceFrameRefCon,
+ OSStatus status,
+ VTEncodeInfoFlags infoFlags,
+ CMSampleBufferRef sampleBuffer)
+{
+ struct vtool_codec_data *vtool_data;
+ const pj_uint8_t start_code[] = { 0, 0, 0, 1 };
+ const int code_size = PJ_ARRAY_SIZE(start_code);
+ const int avcc_size = sizeof(uint32_t);
+ CFArrayRef array;
+ CFDictionaryRef dict = NULL;
+ CMBlockBufferRef block_buf;
+ size_t offset = 0, length = 0;
+ size_t buf_pos;
+ char *data, *buf;
+
+ /* This callback can be called from another, unregistered thread.
+ * So do not call pjlib functions here.
+ */
+
+ if (status != noErr || !CMSampleBufferDataIsReady(sampleBuffer)) return;
+
+ vtool_data = (struct vtool_codec_data *)outputCallbackRefCon;
+ vtool_data->enc_is_keyframe = PJ_FALSE;
+ buf = vtool_data->enc_buf;
+
+ /* Check if the encoded frame is keyframe */
+ array = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, true);
+ if (array) dict = (CFDictionaryRef)CFArrayGetValueAtIndex(array, 0);
+ if (dict && !CFDictionaryContainsKey(dict,kCMSampleAttachmentKey_NotSync))
+ vtool_data->enc_is_keyframe = PJ_TRUE;
+
+ if (vtool_data->enc_is_keyframe) {
+ CMFormatDescriptionRef format;
+ size_t enc_sps_size, enc_sps_cnt;
+ size_t enc_pps_size, enc_pps_cnt;
+ const uint8_t *enc_sps, *enc_pps;
+ OSStatus status;
+
+ format = CMSampleBufferGetFormatDescription(sampleBuffer);
+
+ /* Get SPS */
+ status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
+ format, 0, &enc_sps, &enc_sps_size, &enc_sps_cnt, 0 );
+ if (status != noErr) return;
+
+ /* Get PPS */
+ status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
+ format, 1, &enc_pps, &enc_pps_size, &enc_pps_cnt, 0 );
+ if (status != noErr) return;
+
+ /* Append SPS and PPS to output frame */
+ pj_assert (enc_sps_size + enc_pps_size + 2 * code_size <=
+ vtool_data->enc_buf_size);
+ pj_memcpy(buf + offset, start_code, code_size);
+ offset += code_size;
+ pj_memcpy(buf + offset, enc_sps, enc_sps_size);
+ offset += enc_sps_size;
+ pj_memcpy(buf + offset, start_code, code_size);
+ offset += code_size;
+ pj_memcpy(buf + offset, enc_pps, enc_pps_size);
+ offset += enc_pps_size;
+ }
+
+ pj_assert(CMSampleBufferGetNumSamples(sampleBuffer) == 1);
+
+ /* Get data pointer of the encoded frame */
+ block_buf = CMSampleBufferGetDataBuffer(sampleBuffer);
+ status = CMBlockBufferGetDataPointer(block_buf, 0, &length, NULL, &data);
+ if (status != noErr || (offset + length) > vtool_data->enc_buf_size)
+ return;
+
+ pj_assert(CMBlockBufferIsRangeContiguous(block_buf, 0, length));
+ pj_assert(length == CMBlockBufferGetDataLength(block_buf));
+
+ buf_pos = 0;
+ while (buf_pos < length - avcc_size) {
+ uint32_t data_length;
+
+ /* Get data length and copy the data to the output buffer */
+ pj_memcpy(&data_length, data + buf_pos, avcc_size);
+ data_length = pj_ntohl(data_length);
+ pj_assert(buf_pos + data_length + avcc_size <= length);
+ pj_memcpy(buf + offset, data + buf_pos, data_length + avcc_size);
+
+ /* Replace data length with NAL start code */
+ pj_memcpy(buf + offset, start_code, code_size);
+
+ buf_pos += avcc_size + data_length;
+ offset += avcc_size + data_length;
+ }
+ vtool_data->enc_frame_size = offset;
+}
+
+static pj_status_t vtool_codec_open(pjmedia_vid_codec *codec,
+ pjmedia_vid_codec_param *codec_param )
+{
+ vtool_codec_data *vtool_data;
+ pjmedia_vid_codec_param *param;
+ pjmedia_h264_packetizer_cfg pktz_cfg;
+ pjmedia_vid_codec_h264_fmtp h264_fmtp;
+ pj_status_t status;
+ CMVideoCodecType codec_type;
+ CFDictionaryRef supported_prop;
+ OSStatus ret;
+
+ PJ_ASSERT_RETURN(codec && codec_param, PJ_EINVAL);
+
+ PJ_LOG(5,(THIS_FILE, "Opening codec.."));
+
+ vtool_data = (vtool_codec_data*) codec->codec_data;
+ vtool_data->prm = pjmedia_vid_codec_param_clone( vtool_data->pool,
+ codec_param);
+ param = vtool_data->prm;
+
+ /* Parse remote fmtp */
+ pj_bzero(&h264_fmtp, sizeof(h264_fmtp));
+ status = pjmedia_vid_codec_h264_parse_fmtp(¶m->enc_fmtp, &h264_fmtp);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Apply SDP fmtp to format in codec param */
+ if (!param->ignore_fmtp) {
+ status = pjmedia_vid_codec_h264_apply_fmtp(param);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ pj_bzero(&pktz_cfg, sizeof(pktz_cfg));
+ pktz_cfg.mtu = param->enc_mtu;
+ pktz_cfg.unpack_nal_start = 4;
+ /* Packetization mode */
+ if (h264_fmtp.packetization_mode == 0)
+ pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL;
+ else if (h264_fmtp.packetization_mode == 1)
+ pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED;
+ else
+ return PJ_ENOTSUP;
+ /* Video Toolbox encoder doesn't support setting maximum slice size,
+ * so we cannot use single NAL mode since the NAL size likely
+ * exceeds the MTU.
+ */
+ pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED;
+
+ status = pjmedia_h264_packetizer_create(vtool_data->pool, &pktz_cfg,
+ &vtool_data->pktz);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ vtool_data->whole = (param->packing == PJMEDIA_VID_PACKING_WHOLE);
+ if (1) {
+ /* Init format info and apply-param of encoder */
+ const pjmedia_video_format_info *enc_vfi;
+ pjmedia_video_apply_fmt_param enc_vafp;
+
+ enc_vfi = pjmedia_get_video_format_info(NULL,codec_param->dec_fmt.id);
+ if (!enc_vfi)
+ return PJ_EINVAL;
+
+ pj_bzero(&enc_vafp, sizeof(enc_vafp));
+ enc_vafp.size = codec_param->enc_fmt.det.vid.size;
+ enc_vafp.buffer = NULL;
+ status = (*enc_vfi->apply_fmt)(enc_vfi, &enc_vafp);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ vtool_data->enc_wxh = codec_param->enc_fmt.det.vid.size.w *
+ codec_param->enc_fmt.det.vid.size.h;
+ vtool_data->enc_input_size = enc_vafp.framebytes;
+ if (!vtool_data->whole) {
+ vtool_data->enc_buf_size = (unsigned)enc_vafp.framebytes;
+ vtool_data->enc_buf = pj_pool_alloc(vtool_data->pool,
+ vtool_data->enc_buf_size);
+ }
+ }
+
+ /* Create encoder session */
+ codec_type = kCMVideoCodecType_H264;
+ ret = VTCompressionSessionCreate(NULL, (int)param->enc_fmt.det.vid.size.w,
+ (int)param->enc_fmt.det.vid.size.h,
+ kCMVideoCodecType_H264, NULL, NULL,
+ NULL, encode_cb, vtool_data,
+ &vtool_data->enc);
+ if (ret != noErr) {
+ PJ_LOG(4,(THIS_FILE, "VTCompressionCreate failed, ret=%d", ret));
+ return PJMEDIA_CODEC_EFAILED;
+ }
+
+#define SET_PROPERTY(sess, prop, val) \
+{ \
+ ret = VTSessionSetProperty(sess, prop, val); \
+ if (ret != noErr) \
+ PJ_LOG(5,(THIS_FILE, "Failed to set session property %s", #prop)); \
+}
+
+ SET_PROPERTY(vtool_data->enc,
+ kVTCompressionPropertyKey_ProfileLevel,
+ kVTProfileLevel_H264_Baseline_AutoLevel);
+ SET_PROPERTY(vtool_data->enc, kVTCompressionPropertyKey_RealTime,
+ kCFBooleanTrue);
+ SET_PROPERTY(vtool_data->enc,
+ kVTCompressionPropertyKey_AllowFrameReordering,
+ kCFBooleanFalse);
+ SET_PROPERTY(vtool_data->enc,
+ kVTCompressionPropertyKey_AverageBitRate,
+ (__bridge CFTypeRef)@(param->enc_fmt.det.vid.avg_bps));
+ vtool_data->enc_fps = param->enc_fmt.det.vid.fps.num /
+ param->enc_fmt.det.vid.fps.denum;
+ SET_PROPERTY(vtool_data->enc,
+ kVTCompressionPropertyKey_ExpectedFrameRate,
+ (__bridge CFTypeRef)@(vtool_data->enc_fps));
+ SET_PROPERTY(vtool_data->enc,
+ kVTCompressionPropertyKey_DataRateLimits,
+ ((__bridge CFArrayRef) // [Bytes, second]
+ @[@(param->enc_fmt.det.vid.max_bps >> 3), @(1)]));
+ SET_PROPERTY(vtool_data->enc,
+ kVTCompressionPropertyKey_MaxKeyFrameInterval,
+ (__bridge CFTypeRef)@(KEYFRAME_INTERVAL *
+ param->enc_fmt.det.vid.fps.num /
+ param->enc_fmt.det.vid.fps.denum));
+ SET_PROPERTY(vtool_data->enc,
+ kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration,
+ (__bridge CFTypeRef)@(KEYFRAME_INTERVAL));
+
+ ret = VTSessionCopySupportedPropertyDictionary(vtool_data->enc,
+ &supported_prop);
+ if (ret == noErr &&
+ CFDictionaryContainsKey(supported_prop,
+ kVTCompressionPropertyKey_MaxH264SliceBytes))
+ {
+ /* kVTCompressionPropertyKey_MaxH264SliceBytes is not yet supported
+ * by Apple. We leave it here for possible future enhancements.
+ SET_PROPERTY(vtool_data->enc,
+ kVTCompressionPropertyKey_MaxH264SliceBytes,
+ // param->enc_mtu - NAL_HEADER_ADD_0X30BYTES
+ (__bridge CFTypeRef)@(param->enc_mtu - 50));
+ */
+ }
+
+ VTCompressionSessionPrepareToEncodeFrames(vtool_data->enc);
+
+ /* If available, use the "sprop-parameter-sets" fmtp from remote SDP
+ * to create the decoder.
+ */
+ if (h264_fmtp.sprop_param_sets_len) {
+ const pj_uint8_t start_code[3] = {0, 0, 1};
+ const int code_size = PJ_ARRAY_SIZE(start_code);
+ unsigned i, j;
+
+ for (i = h264_fmtp.sprop_param_sets_len-code_size; i >= code_size;
+ i--)
+ {
+ pj_bool_t found = PJ_TRUE;
+ for (j = 0; j < code_size; j++) {
+ if (h264_fmtp.sprop_param_sets[i+j] != start_code[j]) {
+ found = PJ_FALSE;
+ break;
+ }
+ }
+ }
+
+ if (i >= code_size) {
+ vtool_data->dec_sps_size = i - code_size;
+ pj_memcpy(vtool_data->dec_sps,
+ &h264_fmtp.sprop_param_sets[code_size],
+ vtool_data->dec_sps_size);
+
+ vtool_data->dec_pps_size = h264_fmtp.sprop_param_sets_len -
+ code_size-i;
+ pj_memcpy(vtool_data->dec_pps,
+ &h264_fmtp.sprop_param_sets[i + code_size],
+ vtool_data->dec_pps_size);
+
+ create_decoder(vtool_data);
+ }
+ }
+
+ /* Create decoder buffer */
+ vtool_data->dec_buf_size = (MAX_RX_WIDTH * MAX_RX_HEIGHT * 3 >> 1) +
+ (MAX_RX_WIDTH);
+ vtool_data->dec_buf = (pj_uint8_t*)pj_pool_alloc(vtool_data->pool,
+ vtool_data->dec_buf_size);
+
+ /* Need to update param back after values are negotiated */
+ pj_memcpy(codec_param, param, sizeof(*codec_param));
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t vtool_codec_close(pjmedia_vid_codec *codec)
+{
+ struct vtool_codec_data *vtool_data;
+
+ PJ_ASSERT_RETURN(codec, PJ_EINVAL);
+
+ vtool_data = (vtool_codec_data*) codec->codec_data;
+
+ if (vtool_data->enc) {
+ VTCompressionSessionInvalidate(vtool_data->enc);
+ CFRelease(vtool_data->enc);
+ vtool_data->enc = NULL;
+ }
+
+ if (vtool_data->dec) {
+ VTDecompressionSessionInvalidate(vtool_data->dec);
+ CFRelease(vtool_data->dec);
+ vtool_data->dec = NULL;
+ }
+
+ if (vtool_data->dec_format)
+ CFRelease(vtool_data->dec_format);
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t vtool_codec_modify(pjmedia_vid_codec *codec,
+ const pjmedia_vid_codec_param *param)
+{
+ PJ_ASSERT_RETURN(codec && param, PJ_EINVAL);
+ PJ_UNUSED_ARG(codec);
+ PJ_UNUSED_ARG(param);
+ return PJ_EINVALIDOP;
+}
+
+static pj_status_t vtool_codec_get_param(pjmedia_vid_codec *codec,
+ pjmedia_vid_codec_param *param)
+{
+ struct vtool_codec_data *vtool_data;
+
+ PJ_ASSERT_RETURN(codec && param, PJ_EINVAL);
+
+ vtool_data = (vtool_codec_data*) codec->codec_data;
+ pj_memcpy(param, vtool_data->prm, sizeof(*param));
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t vtool_codec_encode_begin(pjmedia_vid_codec *codec,
+ const pjmedia_vid_encode_opt *opt,
+ const pjmedia_frame *input,
+ unsigned out_size,
+ pjmedia_frame *output,
+ pj_bool_t *has_more)
+{
+ struct vtool_codec_data *vtool_data;
+ CMTime ts, dur;
+ CVImageBufferRef image_buf;
+ void *base_addr[3];
+ size_t plane_w[3], plane_h[3], plane_bpr[3];
+ NSDictionary *frm_prop = NULL;
+ OSStatus ret;
+
+ PJ_ASSERT_RETURN(codec && input && out_size && output && has_more,
+ PJ_EINVAL);
+
+ vtool_data = (vtool_codec_data*) codec->codec_data;
+
+ base_addr[0] = input->buf;
+ base_addr[1] = input->buf + vtool_data->enc_wxh;
+ base_addr[2] = base_addr[1] + (vtool_data->enc_wxh >> 2);
+ plane_w[0] = vtool_data->prm->enc_fmt.det.vid.size.w;
+ plane_h[0] = vtool_data->prm->enc_fmt.det.vid.size.h;
+ plane_w[1] = plane_w[2] = vtool_data->prm->enc_fmt.det.vid.size.w >> 1;
+ plane_h[1] = plane_h[2] = vtool_data->prm->enc_fmt.det.vid.size.h >> 1;
+ plane_bpr[0] = vtool_data->prm->enc_fmt.det.vid.size.w;
+ plane_bpr[1] = plane_bpr[2] = vtool_data->prm->enc_fmt.det.vid.size.w >> 1;
+
+#if TARGET_OS_IPHONE
+ ret = CVPixelBufferCreate(NULL,
+ vtool_data->prm->enc_fmt.det.vid.size.w,
+ vtool_data->prm->enc_fmt.det.vid.size.h,
+ kCVPixelFormatType_420YpCbCr8Planar, /* I420 */
+ NULL, &image_buf);
+ if (ret == noErr) {
+ size_t i, count;
+
+ CVPixelBufferLockBaseAddress(image_buf, 0);
+
+ count = CVPixelBufferGetPlaneCount(image_buf);
+ for (i = 0; i < count; i++) {
+ void *ptr = CVPixelBufferGetBaseAddressOfPlane(image_buf, i);
+ size_t bpr = CVPixelBufferGetBytesPerRow(image_buf);
+
+ pj_assert(bpr = plane_bpr[i]);
+ pj_memcpy(ptr, base_addr[i], plane_bpr[i] * plane_h[i]);
+ }
+
+ CVPixelBufferUnlockBaseAddress(image_buf, 0);
+ }
+#else
+ ret = CVPixelBufferCreateWithPlanarBytes(NULL,
+ vtool_data->prm->enc_fmt.det.vid.size.w,
+ vtool_data->prm->enc_fmt.det.vid.size.h,
+ kCVPixelFormatType_420YpCbCr8Planar, /* I420 */
+ NULL, vtool_data->enc_input_size,
+ 3, /* number of planes of I420 */
+ base_addr,
+ (size_t *)plane_w, (size_t *)plane_h, (size_t *)plane_bpr,
+ NULL, NULL, NULL, &image_buf);
+#endif
+
+ if (ret != noErr) {
+ PJ_LOG(4,(THIS_FILE, "Failed to create pixel buffer"));
+ return PJMEDIA_CODEC_EFAILED;
+ }
+
+ ts = CMTimeMake(++vtool_data->enc_frm_cnt, vtool_data->enc_fps);
+ dur = CMTimeMake(1, vtool_data->enc_fps);
+ vtool_data->enc_frame_size = vtool_data->enc_processed = 0;
+
+ if (vtool_data->whole) {
+ vtool_data->enc_buf = output->buf;
+ vtool_data->enc_buf_size = out_size;
+ }
+
+ if (opt && opt->force_keyframe) {
+ frm_prop = @{ (__bridge NSString *)
+ kVTEncodeFrameOptionKey_ForceKeyFrame: @YES };
+ }
+
+ ret = VTCompressionSessionEncodeFrame(vtool_data->enc, image_buf,
+ ts, dur,
+ (__bridge CFDictionaryRef)frm_prop,
+ NULL, NULL);
+ if (ret != noErr) {
+ PJ_LOG(4,(THIS_FILE, "Failed to encode frame %d", ret));
+ CVPixelBufferRelease(image_buf);
+ return PJMEDIA_CODEC_EFAILED;
+ }
+
+ /* EncodeFrame is async, so tell it to finish the encoding. */
+ ts.flags = kCMTimeFlags_Indefinite;
+ ret = VTCompressionSessionCompleteFrames(vtool_data->enc, ts);
+ if (ret != noErr) {
+ PJ_LOG(4,(THIS_FILE, "Failed to complete encoding %d", ret));
+ CVPixelBufferRelease(image_buf);
+ return PJMEDIA_CODEC_EFAILED;
+ }
+
+ CVPixelBufferRelease(image_buf);
+
+ if (vtool_data->whole) {
+ *has_more = PJ_FALSE;
+ output->size = vtool_data->enc_frame_size;
+ return PJ_SUCCESS;
+ }
+
+ return vtool_codec_encode_more(codec, out_size, output, has_more);
+}
+
+
+static pj_status_t vtool_codec_encode_more(pjmedia_vid_codec *codec,
+ unsigned out_size,
+ pjmedia_frame *output,
+ pj_bool_t *has_more)
+{
+ struct vtool_codec_data *vtool_data;
+ const pj_uint8_t *payload;
+ pj_size_t payload_len;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(codec && out_size && output && has_more,
+ PJ_EINVAL);
+
+ vtool_data = (vtool_codec_data*) codec->codec_data;
+
+ if (vtool_data->enc_processed >= vtool_data->enc_frame_size) {
+ /* No more frame */
+ *has_more = PJ_FALSE;
+ output->size = 0;
+ output->type = PJMEDIA_FRAME_TYPE_NONE;
+
+ return PJ_SUCCESS;
+ }
+
+ /* We have outstanding frame in packetizer */
+ status = pjmedia_h264_packetize(vtool_data->pktz,
+ (pj_uint8_t*)vtool_data->enc_buf,
+ vtool_data->enc_frame_size,
+ &vtool_data->enc_processed,
+ &payload, &payload_len);
+ if (status != PJ_SUCCESS) {
+ /* Reset */
+ vtool_data->enc_frame_size = vtool_data->enc_processed = 0;
+ *has_more = (vtool_data->enc_processed < vtool_data->enc_frame_size);
+
+ PJ_PERROR(4,(THIS_FILE, status, "pjmedia_h264_packetize() error"));
+ return status;
+ }
+
+ PJ_ASSERT_RETURN(payload_len <= out_size, PJMEDIA_CODEC_EFRMTOOSHORT);
+
+ output->type = PJMEDIA_FRAME_TYPE_VIDEO;
+ pj_memcpy(output->buf, payload, payload_len);
+ output->size = payload_len;
+ if (vtool_data->enc_is_keyframe)
+ output->bit_info |= PJMEDIA_VID_FRM_KEYFRAME;
+
+ *has_more = (vtool_data->enc_processed < vtool_data->enc_frame_size);
+ return PJ_SUCCESS;
+}
+
+
+/* Copy I420 frame from source to destination and clip if necessary */
+static int process_i420(CVImageBufferRef src_buf, pj_uint8_t *dst)
+{
+ pj_uint8_t *pdst = dst;
+ pj_size_t i, count;
+
+ count = CVPixelBufferGetPlaneCount(src_buf);
+ for (i = 0; i < count; i++) {
+ pj_uint8_t *psrc;
+ pj_size_t src_w, dst_w, h;
+
+ psrc = CVPixelBufferGetBaseAddressOfPlane(src_buf, i);
+ src_w = CVPixelBufferGetBytesPerRowOfPlane(src_buf, i);
+ dst_w = CVPixelBufferGetWidthOfPlane(src_buf, i);
+ h = CVPixelBufferGetHeightOfPlane(src_buf, i);
+
+ /* Check if clipping is required */
+ if (src_w == dst_w) {
+ pj_size_t plane_size = dst_w * h;
+ pj_memcpy(pdst, psrc, plane_size);
+ pdst += plane_size;
+ } else {
+ pj_size_t j = 0;
+ for (; j < h; ++j) {
+ pj_memcpy(pdst, psrc, dst_w);
+ pdst += dst_w;
+ psrc += src_w;
+ }
+ }
+ }
+
+ return (pdst - dst);
+}
+
+
+static void decode_cb(void *decompressionOutputRefCon,
+ void *sourceFrameRefCon,
+ OSStatus status,
+ VTDecodeInfoFlags infoFlags,
+ CVImageBufferRef imageBuffer,
+ CMTime presentationTimeStamp,
+ CMTime presentationDuration)
+{
+ struct vtool_codec_data *vtool_data;
+ pj_size_t width, height, len;
+
+ /* This callback can be called from another, unregistered thread.
+ * So do not call pjlib functions here.
+ */
+
+ if (status != noErr) return;
+
+ vtool_data = (struct vtool_codec_data *)decompressionOutputRefCon;
+
+ CVPixelBufferLockBaseAddress(imageBuffer,0);
+
+ width = CVPixelBufferGetWidth(imageBuffer);
+ height = CVPixelBufferGetHeight(imageBuffer);
+
+ /* Detect format change */
+ if (width != vtool_data->prm->dec_fmt.det.vid.size.w ||
+ height != vtool_data->prm->dec_fmt.det.vid.size.h)
+ {
+ vtool_data->dec_fmt_change = PJ_TRUE;
+ vtool_data->prm->dec_fmt.det.vid.size.w = width;
+ vtool_data->prm->dec_fmt.det.vid.size.h = height;
+ } else {
+ vtool_data->dec_fmt_change = PJ_FALSE;
+ }
+
+ len = process_i420(imageBuffer, (pj_uint8_t *)vtool_data->dec_frame->buf);
+ vtool_data->dec_frame->size = len;
+
+ CVPixelBufferUnlockBaseAddress(imageBuffer,0);
+}
+
+static OSStatus create_decoder(struct vtool_codec_data *vtool_data)
+{
+ uint8_t *param_ptrs[2] = {vtool_data->dec_sps,
+ vtool_data->dec_pps};
+ const size_t param_sizes[2] = {vtool_data->dec_sps_size,
+ vtool_data->dec_pps_size};
+ const int code_size = 4; // PJ_ARRAY_SIZE(start_code);
+ CMFormatDescriptionRef dec_format;
+ VTDecompressionOutputCallbackRecord cbr;
+ NSDictionary *dst_attr;
+ OSStatus ret;
+
+ /* Create video format description based on H264 SPS and PPS
+ * parameters.
+ */
+ ret = CMVideoFormatDescriptionCreateFromH264ParameterSets(
+ kCFAllocatorDefault, 2,
+ (const uint8_t * const *)param_ptrs,
+ param_sizes, code_size, &dec_format);
+ if (ret != noErr) {
+ PJ_LOG(4,(THIS_FILE, "Failed to create video format "
+ "description %d", ret));
+ return ret;
+ }
+
+ if (!vtool_data->dec ||
+ !CMFormatDescriptionEqual(dec_format, vtool_data->dec_format))
+ {
+ if (vtool_data->dec_format)
+ CFRelease(vtool_data->dec_format);
+ vtool_data->dec_format = dec_format;
+ } else {
+ CFRelease(dec_format);
+ return noErr;
+ }
+
+ cbr.decompressionOutputCallback = decode_cb;
+ cbr.decompressionOutputRefCon = vtool_data;
+
+ if (vtool_data->dec) {
+ VTDecompressionSessionInvalidate(vtool_data->dec);
+ CFRelease(vtool_data->dec);
+ vtool_data->dec = NULL;
+ }
+
+ dst_attr = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt: /* I420 */
+ kCVPixelFormatType_420YpCbCr8Planar],
+ kCVPixelBufferPixelFormatTypeKey,
+ nil];
+ ret = VTDecompressionSessionCreate(NULL, vtool_data->dec_format, NULL,
+ (__bridge CFDictionaryRef)dst_attr,
+ &cbr, &vtool_data->dec);
+ if (ret != noErr) {
+ PJ_LOG(3,(THIS_FILE, "Failed to create decompression session %d",
+ ret));
+ }
+
+ SET_PROPERTY(vtool_data->dec, kVTCompressionPropertyKey_RealTime,
+ kCFBooleanTrue);
+#if !TARGET_OS_IPHONE
+ SET_PROPERTY(vtool_data->dec,
+ kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder,
+ kCFBooleanTrue);
+#endif
+
+ return ret;
+}
+
+static pj_status_t vtool_codec_decode(pjmedia_vid_codec *codec,
+ pj_size_t count,
+ pjmedia_frame packets[],
+ unsigned out_size,
+ pjmedia_frame *output)
+{
+ struct vtool_codec_data *vtool_data;
+ const pj_uint8_t start_code[] = { 0, 0, 0, 1 };
+ const int code_size = PJ_ARRAY_SIZE(start_code);
+ pj_bool_t has_frame = PJ_FALSE;
+ unsigned buf_pos, whole_len = 0;
+ unsigned i, frm_cnt;
+ pj_status_t status = PJ_SUCCESS;
+ pj_bool_t decode_whole = DECODE_WHOLE;
+ OSStatus ret;
+
+ PJ_ASSERT_RETURN(codec && count && packets && out_size && output,
+ PJ_EINVAL);
+ PJ_ASSERT_RETURN(output->buf, PJ_EINVAL);
+
+ vtool_data = (vtool_codec_data*) codec->codec_data;
+
+ /*
+ * Step 1: unpacketize the packets/frames
+ */
+ whole_len = 0;
+ if (vtool_data->whole) {
+ for (i=0; i<count; ++i) {
+ if (whole_len + packets[i].size > vtool_data->dec_buf_size) {
+ PJ_LOG(4,(THIS_FILE, "Decoding buffer overflow"));
+ status = PJMEDIA_CODEC_EFRMTOOSHORT;
+ break;
+ }
+
+ pj_memcpy( vtool_data->dec_buf + whole_len,
+ (pj_uint8_t*)packets[i].buf,
+ packets[i].size);
+ whole_len += packets[i].size;
+ }
+
+ } else {
+ for (i=0; i<count; ++i) {
+ if (whole_len + packets[i].size + code_size >
+ vtool_data->dec_buf_size)
+ {
+ PJ_LOG(4,(THIS_FILE, "Decoding buffer overflow [1]"));
+ status = PJMEDIA_CODEC_EFRMTOOSHORT;
+ break;
+ }
+
+ status = pjmedia_h264_unpacketize( vtool_data->pktz,
+ (pj_uint8_t*)packets[i].buf,
+ packets[i].size,
+ vtool_data->dec_buf,
+ vtool_data->dec_buf_size,
+ &whole_len);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(4,(THIS_FILE, status, "Unpacketize error"));
+ continue;
+ }
+ }
+ }
+
+ if (whole_len + code_size > vtool_data->dec_buf_size ||
+ whole_len <= code_size + 1)
+ {
+ PJ_LOG(4,(THIS_FILE, "Decoding buffer overflow or unpacketize error "
+ "size: %d, buffer: %d", whole_len,
+ vtool_data->dec_buf_size));
+ status = PJMEDIA_CODEC_EFRMTOOSHORT;
+ }
+
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ /* Dummy NAL sentinel */
+ pj_memcpy(vtool_data->dec_buf + whole_len, start_code, code_size);
+
+ /*
+ * Step 2: parse the individual NAL and give to decoder
+ */
+ buf_pos = 0;
+ for ( frm_cnt=0; ; ++frm_cnt) {
+ uint32_t frm_size, nalu_type, data_length;
+ unsigned char *start;
+
+ for (i = code_size - 1; buf_pos + i < whole_len; i++) {
+ if (vtool_data->dec_buf[buf_pos + i] == 0 &&
+ vtool_data->dec_buf[buf_pos + i + 1] == 0 &&
+ vtool_data->dec_buf[buf_pos + i + 2] == 0 &&
+ vtool_data->dec_buf[buf_pos + i + 3] == 1)
+ {
+ break;
+ }
+ }
+
+ frm_size = i;
+ start = vtool_data->dec_buf + buf_pos;
+ nalu_type = (start[code_size] & 0x1F);
+
+#if TARGET_OS_IPHONE
+ /* On iOS, packets preceded by SEI frame (type 6), such as the ones
+ * sent by Mac VideoToolbox encoder will cause DecodeFrame to fail
+ * with -12911 (kVTVideoDecoderMalfunctionErr). The workaround
+ * is to decode the whole packets at once.
+ */
+ if (nalu_type == 6)
+ decode_whole = PJ_TRUE;
+#endif
+
+ /* AVCC format requires us to replace the start code header
+ * on this NAL with its frame size.
+ */
+ data_length = pj_htonl(frm_size - code_size);
+ pj_memcpy(start, &data_length, sizeof (data_length));
+
+ if (nalu_type == 7) {
+ /* NALU type 7 is the SPS parameter NALU */
+ vtool_data->dec_sps_size = frm_size - code_size;
+ pj_memcpy(vtool_data->dec_sps, &start[code_size],
+ vtool_data->dec_sps_size);
+ } else if (nalu_type == 8) {
+ /* NALU type 8 is the PPS parameter NALU */
+ vtool_data->dec_pps_size = frm_size - code_size;
+ pj_memcpy(vtool_data->dec_pps, &start[code_size],
+ vtool_data->dec_pps_size);
+
+ ret = create_decoder(vtool_data);
+ } else if (vtool_data->dec &&
+ (!decode_whole || (buf_pos + frm_size >= whole_len)))
+ {
+ CMBlockBufferRef block_buf = NULL;
+ CMSampleBufferRef sample_buf = NULL;
+
+ if (decode_whole) {
+ /* We decode all the packets at once. */
+ frm_size = whole_len;
+ start = vtool_data->dec_buf;
+ }
+
+ /* Create a block buffer from the NALU */
+ ret = CMBlockBufferCreateWithMemoryBlock(NULL,
+ start, frm_size,
+ kCFAllocatorNull, NULL,
+ 0, frm_size,
+ 0, &block_buf);
+ if (ret == noErr) {
+ const size_t sample_size = frm_size;
+ ret = CMSampleBufferCreate(kCFAllocatorDefault,
+ block_buf, true, NULL, NULL,
+ vtool_data->dec_format,
+ 1, 0, NULL, 1,
+ &sample_size, &sample_buf);
+ if (ret != noErr) {
+ PJ_LOG(4,(THIS_FILE, "Failed to create sample buffer"));
+ CFRelease(block_buf);
+ }
+ } else {
+ PJ_LOG(4,(THIS_FILE, "Failed to create block buffer"));
+ }
+
+ if (ret == noErr) {
+ vtool_data->dec_frame = output;
+ ret = VTDecompressionSessionDecodeFrame(
+ vtool_data->dec, sample_buf, 0,
+ NULL, NULL);
+ if (ret != noErr) {
+ PJ_LOG(5,(THIS_FILE, "Failed to decode frame %d of size "
+ "%d: %d", nalu_type, frm_size,
+ ret));
+ } else {
+ has_frame = PJ_TRUE;
+ output->type = PJMEDIA_FRAME_TYPE_VIDEO;
+ output->timestamp = packets[0].timestamp;
+
+ /* Broadcast format changed event */
+ if (vtool_data->dec_fmt_change) {
+ pjmedia_event event;
+
+ PJ_LOG(4,(THIS_FILE, "Frame size changed to %dx%d",
+ vtool_data->prm->dec_fmt.det.vid.size.w,
+ vtool_data->prm->dec_fmt.det.vid.size.h));
+
+ /* Broadcast format changed event */
+ pjmedia_event_init(&event, PJMEDIA_EVENT_FMT_CHANGED,
+ &output->timestamp, codec);
+ event.data.fmt_changed.dir = PJMEDIA_DIR_DECODING;
+ pjmedia_format_copy(&event.data.fmt_changed.new_fmt,
+ &vtool_data->prm->dec_fmt);
+ pjmedia_event_publish(NULL, codec, &event,
+ PJMEDIA_EVENT_PUBLISH_DEFAULT);
+ }
+ }
+
+ CFRelease(block_buf);
+ CFRelease(sample_buf);
+ }
+ }
+
+ if (buf_pos + frm_size >= whole_len)
+ break;
+
+ buf_pos += frm_size;
+ }
+
+on_return:
+ if (!has_frame) {
+ pjmedia_event event;
+
+ /* Broadcast missing keyframe event */
+ pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_MISSING,
+ &packets[0].timestamp, codec);
+ pjmedia_event_publish(NULL, codec, &event,
+ PJMEDIA_EVENT_PUBLISH_DEFAULT);
+
+ PJ_LOG(5,(THIS_FILE, "Decode couldn't produce picture, "
+ "input nframes=%d, concatenated size=%d bytes",
+ count, whole_len));
+
+ output->type = PJMEDIA_FRAME_TYPE_NONE;
+ output->size = 0;
+ output->timestamp = packets[0].timestamp;
+ }
+
+ return PJ_SUCCESS;
+}
+
+#endif /* PJMEDIA_HAS_VID_TOOLBOX_CODEC */
diff --git a/pjmedia/src/pjmedia-videodev/colorbar_dev.c b/pjmedia/src/pjmedia-videodev/colorbar_dev.c
index 06ac181..3cabf52 100644
--- a/pjmedia/src/pjmedia-videodev/colorbar_dev.c
+++ b/pjmedia/src/pjmedia-videodev/colorbar_dev.c
@@ -1,4 +1,4 @@
-/* $Id: colorbar_dev.c 5534 2017-01-19 07:41:25Z nanang $ */
+/* $Id: colorbar_dev.c 5659 2017-09-25 02:58:42Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -599,7 +599,6 @@ static pj_status_t spectrum_run(struct cbar_stream *d, pj_uint8_t *p,
if (d->vfi->plane_cnt == 1) {
for (i = 0; i < 3; ++i) {
- pj_uint8_t *ptr;
unsigned j, k, inc_ptr;
pj_size_t dot_size = DOT_SIZE;
@@ -621,7 +620,7 @@ static pj_status_t spectrum_run(struct cbar_stream *d, pj_uint8_t *p,
pj_size_t offset_p = 0;
for (i = 0; i < 3; ++i) {
- pj_uint8_t *ptr, c;
+ pj_uint8_t c;
unsigned j;
pj_size_t dot_size = DOT_SIZE;
diff --git a/pjmedia/src/pjmedia-videodev/darwin_dev.m b/pjmedia/src/pjmedia-videodev/darwin_dev.m
index ffd7fe9..5b402c3 100644
--- a/pjmedia/src/pjmedia-videodev/darwin_dev.m
+++ b/pjmedia/src/pjmedia-videodev/darwin_dev.m
@@ -1,4 +1,4 @@
-/* $Id: darwin_dev.m 5498 2016-12-16 04:05:44Z ming $ */
+/* $Id: darwin_dev.m 5628 2017-07-18 11:55:25Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -890,9 +890,9 @@ static pj_status_t darwin_factory_create_stream(
#if TARGET_OS_IPHONE
/* Create renderer stream here */
- status = darwin_init_view(strm);
- if (status != PJ_SUCCESS)
- goto on_error;
+ dispatch_sync_on_main_queue(^{
+ darwin_init_view(strm);
+ });
if (!strm->vout_delegate) {
strm->vout_delegate = [VOutDelegate alloc];
@@ -999,12 +999,12 @@ static pj_status_t darwin_stream_set_cap(pjmedia_vid_dev_stream *s,
return PJ_EINVALIDOP;
#if TARGET_OS_IPHONE
- /* Create view, if none */
- if (!strm->render_view)
- darwin_init_view(strm);
-
/* Preview layer instantiation should be in main thread! */
dispatch_sync_on_main_queue(^{
+ /* Create view, if none */
+ if (!strm->render_view)
+ darwin_init_view(strm);
+
/* Create preview layer */
AVCaptureVideoPreviewLayer *prev_layer =
[[AVCaptureVideoPreviewLayer alloc]
diff --git a/pjmedia/src/pjmedia-videodev/dshow_dev.c b/pjmedia/src/pjmedia-videodev/dshow_dev.c
index 5d9b307..189845e 100644
--- a/pjmedia/src/pjmedia-videodev/dshow_dev.c
+++ b/pjmedia/src/pjmedia-videodev/dshow_dev.c
@@ -1,4 +1,4 @@
-/* $Id: dshow_dev.c 4962 2014-11-19 07:44:39Z riza $ */
+/* $Id: dshow_dev.c 5560 2017-02-24 04:21:07Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -1065,8 +1065,10 @@ static pj_status_t dshow_stream_stop(pjmedia_vid_dev_stream *strm)
for (i=0; !stream->cap_thread_exited && i<100; ++i)
pj_thread_sleep(10);
}
- for (i=0; !stream->rend_thread_exited && i<100; ++i)
- pj_thread_sleep(10);
+ if (stream->param.dir & PJMEDIA_DIR_RENDER) {
+ for (i=0; !stream->rend_thread_exited && i<100; ++i)
+ pj_thread_sleep(10);
+ }
if (stream->dgraph.media_filter)
IMediaFilter_Stop(stream->dgraph.media_filter);
diff --git a/pjmedia/src/pjmedia/avi_player.c b/pjmedia/src/pjmedia/avi_player.c
index c5b0396..32a7523 100644
--- a/pjmedia/src/pjmedia/avi_player.c
+++ b/pjmedia/src/pjmedia/avi_player.c
@@ -1,4 +1,4 @@
-/* $Id: avi_player.c 5544 2017-01-24 05:41:05Z nanang $ */
+/* $Id: avi_player.c 5659 2017-09-25 02:58:42Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -612,15 +612,13 @@ static pj_status_t avi_get_frame(pjmedia_port *this_port,
pjmedia_frame *frame)
{
struct avi_reader_port *fport = (struct avi_reader_port*)this_port;
- pj_status_t status;
+ pj_status_t status = PJ_SUCCESS;
pj_ssize_t size_read = 0, size_to_read = 0;
pj_assert(fport->base.info.signature == SIGNATURE);
/* We encountered end of file */
if (fport->eof) {
- pj_status_t status = PJ_SUCCESS;
-
PJ_LOG(5,(THIS_FILE, "File port %.*s EOF",
(int)fport->base.info.name.slen,
fport->base.info.name.ptr));
diff --git a/pjmedia/src/pjmedia/echo_webrtc.c b/pjmedia/src/pjmedia/echo_webrtc.c
index 512d06e..862fddc 100644
--- a/pjmedia/src/pjmedia/echo_webrtc.c
+++ b/pjmedia/src/pjmedia/echo_webrtc.c
@@ -1,4 +1,4 @@
-/* $Id: echo_webrtc.c 5432 2016-08-26 01:59:53Z ming $ */
+/* $Id: echo_webrtc.c 5659 2017-09-25 02:58:42Z riza $ */
/*
* Copyright (C) 2011-2015 Teluu Inc. (http://www.teluu.com)
*
@@ -283,6 +283,9 @@ PJ_DEF(pj_status_t) webrtc_aec_cancel_echo( void *state,
const sample * buf_ptr;
sample * out_buf_ptr;
+ PJ_UNUSED_ARG(options);
+ PJ_UNUSED_ARG(reserved);
+
/* Sanity checks */
PJ_ASSERT_RETURN(echo && rec_frm && play_frm, PJ_EINVAL);
@@ -328,7 +331,7 @@ PJ_DEF(pj_status_t) webrtc_aec_cancel_echo( void *state,
#else
status = WebRtcAec_Process(echo->AEC_inst, &buf_ptr,
echo->channel_count, &out_buf_ptr,
- echo->subframe_len, echo->tail, 0);
+ echo->subframe_len, (int16_t)echo->tail, 0);
#endif
if (status != 0) {
print_webrtc_aec_error("Process echo", echo->AEC_inst);
diff --git a/pjmedia/src/pjmedia/errno.c b/pjmedia/src/pjmedia/errno.c
index aeb0b8a..f7c3766 100644
--- a/pjmedia/src/pjmedia/errno.c
+++ b/pjmedia/src/pjmedia/errno.c
@@ -1,4 +1,4 @@
-/* $Id: errno.c 5489 2016-11-23 08:15:49Z riza $ */
+/* $Id: errno.c 5597 2017-06-03 09:22:34Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -165,7 +165,10 @@ static const struct
PJ_BUILD_ERR( PJMEDIA_SRTP_ESDPINCRYPTOTAG, "Invalid SRTP crypto tag" ),
PJ_BUILD_ERR( PJMEDIA_SRTP_ESDPINTRANSPORT, "Invalid SDP media transport for SRTP" ),
PJ_BUILD_ERR( PJMEDIA_SRTP_ESDPREQCRYPTO, "SRTP crypto attribute required" ),
- PJ_BUILD_ERR( PJMEDIA_SRTP_ESDPREQSECTP, "Secure transport required in SDP media descriptor" )
+ PJ_BUILD_ERR( PJMEDIA_SRTP_ESDPREQSECTP, "Secure transport required in SDP media descriptor" ),
+ PJ_BUILD_ERR( PJMEDIA_SRTP_DTLS_ENOCRYPTO, "No matching SRTP crypto-suite after DTLS nego" ),
+ PJ_BUILD_ERR( PJMEDIA_SRTP_DTLS_EPEERNOCERT,"No certificate supplied by peer in DTLS nego" ),
+ PJ_BUILD_ERR( PJMEDIA_SRTP_DTLS_EFPNOTMATCH,"Fingerprint from signalling not match to actual fingerprint" )
#endif
};
diff --git a/pjmedia/src/pjmedia/format.c b/pjmedia/src/pjmedia/format.c
index 0b1eedb..a6f61c5 100644
--- a/pjmedia/src/pjmedia/format.c
+++ b/pjmedia/src/pjmedia/format.c
@@ -1,4 +1,4 @@
-/* $Id: format.c 4785 2014-03-10 09:01:18Z nanang $ */
+/* $Id: format.c 5642 2017-08-17 02:48:38Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -118,7 +118,7 @@ PJ_DEF(void) pjmedia_format_init_video( pjmedia_format *fmt,
vafp.size = fmt->det.vid.size;
vfi->apply_fmt(vfi, &vafp);
- bps = (pj_uint32_t)vafp.framebytes * fps_num * (pj_size_t)8 / fps_denum;
+ bps = (pj_uint32_t)((pj_uint64_t)vafp.framebytes * fps_num * 8 / fps_denum);
fmt->det.vid.avg_bps = fmt->det.vid.max_bps = bps;
}
}
diff --git a/pjmedia/src/pjmedia/sdp_neg.c b/pjmedia/src/pjmedia/sdp_neg.c
index 83859f7..7ea5ec1 100644
--- a/pjmedia/src/pjmedia/sdp_neg.c
+++ b/pjmedia/src/pjmedia/sdp_neg.c
@@ -1,4 +1,4 @@
-/* $Id: sdp_neg.c 5170 2015-08-25 08:45:46Z nanang $ */
+/* $Id: sdp_neg.c 5619 2017-07-05 03:57:53Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -334,7 +334,7 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2(
*/
pj_strdup(pool, &new_offer->origin.user, &old_offer->origin.user);
new_offer->origin.id = old_offer->origin.id;
- new_offer->origin.version = old_offer->origin.version + 1;
+
pj_strdup(pool, &new_offer->origin.net_type, &old_offer->origin.net_type);
pj_strdup(pool, &new_offer->origin.addr_type,&old_offer->origin.addr_type);
pj_strdup(pool, &new_offer->origin.addr, &old_offer->origin.addr);
@@ -399,6 +399,17 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2(
}
/* New_offer fixed */
+#if PJMEDIA_SDP_NEG_COMPARE_BEFORE_INC_VERSION
+ new_offer->origin.version = old_offer->origin.version;
+
+ if (pjmedia_sdp_session_cmp(new_offer, neg->initial_sdp, 0) != PJ_SUCCESS)
+ {
+ ++new_offer->origin.version;
+ }
+#else
+ new_offer->origin.version = old_offer->origin.version + 1;
+#endif
+
neg->initial_sdp_tmp = neg->initial_sdp;
neg->initial_sdp = new_offer;
neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, new_offer);
@@ -1474,12 +1485,21 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_negotiate( pj_pool_t *pool,
else
active_ver = neg->initial_sdp->origin.version;
+#if PJMEDIA_SDP_NEG_COMPARE_BEFORE_INC_VERSION
+ answer->origin.version = active_ver;
+
+ if ((neg->active_local_sdp == NULL) ||
+ (pjmedia_sdp_session_cmp(answer, neg->active_local_sdp, 0)
+ != PJ_SUCCESS))
+ {
+ ++answer->origin.version;
+ }
+#else
+ answer->origin.version = active_ver + 1;
+#endif
/* Only update active SDPs when negotiation is successfull */
neg->active_local_sdp = answer;
neg->active_remote_sdp = neg->neg_remote_sdp;
-
- /* Increment SDP version */
- neg->active_local_sdp->origin.version = ++active_ver;
}
}
diff --git a/pjmedia/src/pjmedia/stream_info.c b/pjmedia/src/pjmedia/stream_info.c
index 879610b..bb02e0c 100644
--- a/pjmedia/src/pjmedia/stream_info.c
+++ b/pjmedia/src/pjmedia/stream_info.c
@@ -1,4 +1,4 @@
-/* $Id: stream_info.c 5419 2016-08-15 09:59:09Z nanang $ */
+/* $Id: stream_info.c 5597 2017-06-03 09:22:34Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -419,7 +419,7 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
si->proto = PJMEDIA_TP_PROTO_RTP_AVP;
- } else if (pj_stricmp(&local_m->desc.transport, &ID_RTP_SAVP) == 0) {
+ } else if (pj_stristr(&local_m->desc.transport, &ID_RTP_SAVP)) {
si->proto = PJMEDIA_TP_PROTO_RTP_SAVP;
diff --git a/pjmedia/src/pjmedia/transport_ice.c b/pjmedia/src/pjmedia/transport_ice.c
index 4df522b..67dc55a 100644
--- a/pjmedia/src/pjmedia/transport_ice.c
+++ b/pjmedia/src/pjmedia/transport_ice.c
@@ -1,4 +1,4 @@
-/* $Id: transport_ice.c 5534 2017-01-19 07:41:25Z nanang $ */
+/* $Id: transport_ice.c 5635 2017-08-01 07:49:34Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -46,6 +46,14 @@ struct sdp_state
pj_ice_sess_role local_role; /* Our role */
};
+/* ICE listener */
+typedef struct ice_listener
+{
+ PJ_DECL_LIST_MEMBER(struct ice_listener);
+ pjmedia_ice_cb cb;
+ void *user_data;
+} ice_listener;
+
struct transport_ice
{
pjmedia_transport base;
@@ -56,6 +64,8 @@ struct transport_ice
pj_ice_strans *ice_st;
pjmedia_ice_cb cb;
+ ice_listener listener;
+ ice_listener listener_empty;
unsigned media_option;
pj_bool_t initial_sdp;
@@ -66,6 +76,7 @@ struct transport_ice
pj_sockaddr remote_rtp;
pj_sockaddr remote_rtcp;
unsigned addr_len; /**< Length of addresses. */
+ unsigned rem_rtp_cnt; /**< How many pkt from this addr. */
pj_bool_t use_ice;
pj_sockaddr rtp_src_addr; /**< Actual source RTP address. */
@@ -147,6 +158,11 @@ static void ice_on_ice_complete(pj_ice_strans *ice_st,
pj_ice_strans_op op,
pj_status_t status);
+/*
+ * Clean up ICE resources.
+ */
+static void tp_ice_on_destroy(void *arg);
+
static pjmedia_transport_op transport_ice_op =
{
@@ -243,6 +259,8 @@ PJ_DEF(pj_status_t) pjmedia_ice_create3(pjmedia_endpt *endpt,
tp_ice->initial_sdp = PJ_TRUE;
tp_ice->oa_role = ROLE_NONE;
tp_ice->use_ice = PJ_FALSE;
+ pj_list_init(&tp_ice->listener);
+ pj_list_init(&tp_ice->listener_empty);
pj_memcpy(&ice_st_cfg, cfg, sizeof(pj_ice_strans_cfg));
if (cb)
@@ -277,6 +295,13 @@ PJ_DEF(pj_status_t) pjmedia_ice_create3(pjmedia_endpt *endpt,
return status;
}
+ /* Sync to ICE */
+ {
+ pj_grp_lock_t *grp_lock = pj_ice_strans_get_grp_lock(tp_ice->ice_st);
+ pj_grp_lock_add_ref(grp_lock);
+ pj_grp_lock_add_handler(grp_lock, pool, tp_ice, &tp_ice_on_destroy);
+ }
+
/* Done */
return PJ_SUCCESS;
}
@@ -287,6 +312,77 @@ PJ_DEF(pj_grp_lock_t *) pjmedia_ice_get_grp_lock(pjmedia_transport *tp)
return pj_ice_strans_get_grp_lock(((struct transport_ice *)tp)->ice_st);
}
+
+/*
+ * Add application to receive ICE notifications from the specified ICE media
+ * transport.
+ */
+PJ_DEF(pj_status_t) pjmedia_ice_add_ice_cb( pjmedia_transport *tp,
+ const pjmedia_ice_cb *cb,
+ void *user_data)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*)tp;
+ ice_listener *il;
+ pj_grp_lock_t *grp_lock;
+
+ PJ_ASSERT_RETURN(tp && cb, PJ_EINVAL);
+ grp_lock = pjmedia_ice_get_grp_lock(tp);
+ PJ_ASSERT_RETURN(grp_lock, PJ_EINVAL);
+
+ pj_grp_lock_acquire(grp_lock);
+
+ if (!pj_list_empty(&tp_ice->listener_empty)) {
+ il = tp_ice->listener_empty.next;
+ pj_list_erase(il);
+ il->cb = *cb;
+ il->user_data = user_data;
+ pj_list_push_back(&tp_ice->listener, il);
+ } else {
+ il = PJ_POOL_ZALLOC_T(tp_ice->pool, ice_listener);
+ pj_list_init(il);
+ il->cb = *cb;
+ il->user_data = user_data;
+ pj_list_push_back(&tp_ice->listener, il);
+ }
+
+ pj_grp_lock_release(grp_lock);
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Remove application to stop receiving ICE notifications the specified
+ * ICE media transport.
+ */
+PJ_DEF(pj_status_t) pjmedia_ice_remove_ice_cb( pjmedia_transport *tp,
+ const pjmedia_ice_cb *cb,
+ void *user_data)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*)tp;
+ ice_listener *il;
+ pj_grp_lock_t *grp_lock;
+
+ PJ_ASSERT_RETURN(tp && cb, PJ_EINVAL);
+ grp_lock = pjmedia_ice_get_grp_lock(tp);
+ PJ_ASSERT_RETURN(grp_lock, PJ_EINVAL);
+
+ pj_grp_lock_acquire(grp_lock);
+
+ for (il=tp_ice->listener.next; il!=&tp_ice->listener; il=il->next) {
+ if (pj_memcmp(&il->cb, cb, sizeof(cb))==0 && il->user_data==user_data)
+ break;
+ }
+ if (il != &tp_ice->listener) {
+ pj_list_erase(il);
+ pj_list_push_back(&tp_ice->listener_empty, il);
+ }
+
+ pj_grp_lock_release(grp_lock);
+
+ return (il != &tp_ice->listener? PJ_SUCCESS : PJ_ENOTFOUND);
+}
+
/* Disable ICE when SDP from remote doesn't contain a=candidate line */
static void set_no_ice(struct transport_ice *tp_ice, const char *reason,
pj_status_t err)
@@ -672,7 +768,8 @@ static pj_status_t parse_cand(const char *obj_name,
pj_ice_sess_cand *cand)
{
pj_str_t token, delim, host;
- int af, found_idx;
+ int af;
+ pj_ssize_t found_idx;
pj_status_t status = PJNATH_EICEINCANDSDP;
pj_bzero(cand, sizeof(*cand));
@@ -996,13 +1093,13 @@ static pj_status_t verify_ice_sdp(struct transport_ice *tp_ice,
}
/* Detect our role */
- if (current_ice_role==PJ_ICE_SESS_ROLE_CONTROLLING) {
+ if (pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr,
+ &STR_ICE_LITE, NULL) != NULL)
+ {
+ /* Remote is ICE lite, set our role as controlling */
sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLING;
} else {
- if (pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr,
- &STR_ICE_LITE, NULL) != NULL)
- {
- /* Remote is ICE Lite */
+ if (current_ice_role==PJ_ICE_SESS_ROLE_CONTROLLING) {
sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLING;
} else {
sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLED;
@@ -1490,10 +1587,26 @@ static pj_status_t transport_media_start(pjmedia_transport *tp,
PJ_ICE_SESS_ROLE_CONTROLLING);
}
-
/* start ICE */
}
+ /* RFC 5245 section 8.1.1:
+ * If its peer has a lite implementation, an agent MUST use
+ * a regular nomination algorithm.
+ */
+ if (pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr,
+ &STR_ICE_LITE, NULL) != NULL)
+ {
+ pj_ice_sess_options opt;
+ pj_ice_strans_get_options(tp_ice->ice_st, &opt);
+ if (opt.aggressive) {
+ opt.aggressive = PJ_FALSE;
+ pj_ice_strans_set_options(tp_ice->ice_st, &opt);
+ PJ_LOG(4,(tp_ice->base.name, "Forcefully set ICE to use regular "
+ "nomination as remote is lite implementation"));
+ }
+ }
+
/* Now start ICE */
status = start_ice(tp_ice, tmp_pool, rem_sdp, media_index);
if (status != PJ_SUCCESS) {
@@ -1619,6 +1732,7 @@ static pj_status_t transport_attach (pjmedia_transport *tp,
pj_memcpy(&tp_ice->remote_rtp, rem_addr, addr_len);
pj_memcpy(&tp_ice->remote_rtcp, rem_rtcp, addr_len);
tp_ice->addr_len = addr_len;
+ tp_ice->rem_rtp_cnt = 0;
/* Init source RTP & RTCP addresses and counter */
tp_ice->rtp_src_addr = tp_ice->remote_rtp;
@@ -1703,6 +1817,10 @@ static void ice_on_rx_data(pj_ice_strans *ice_st, unsigned comp_id,
pj_bool_t discard = PJ_FALSE;
tp_ice = (struct transport_ice*) pj_ice_strans_get_user_data(ice_st);
+ if (!tp_ice) {
+ /* Destroy on progress */
+ return;
+ }
if (comp_id==1 && tp_ice->rtp_cb) {
@@ -1730,6 +1848,7 @@ static void ice_on_rx_data(pj_ice_strans *ice_st, unsigned comp_id,
{
/* Don't switch while we're receiving from remote_rtp */
tp_ice->rtp_src_cnt = 0;
+ tp_ice->rem_rtp_cnt++;
} else {
++tp_ice->rtp_src_cnt;
@@ -1744,7 +1863,10 @@ static void ice_on_rx_data(pj_ice_strans *ice_st, unsigned comp_id,
}
if (tp_ice->rtp_src_cnt < PJMEDIA_RTP_NAT_PROBATION_CNT) {
- discard = PJ_TRUE;
+ /* Only discard if we have ever received packet from
+ * remote address (remote_rtp).
+ */
+ discard = (tp_ice->rem_rtp_cnt != 0);
} else {
char addr_text[80];
@@ -1833,8 +1955,13 @@ static void ice_on_ice_complete(pj_ice_strans *ice_st,
pj_status_t result)
{
struct transport_ice *tp_ice;
+ ice_listener *il;
tp_ice = (struct transport_ice*) pj_ice_strans_get_user_data(ice_st);
+ if (!tp_ice) {
+ /* Destroy on progress */
+ return;
+ }
pj_perror(5, tp_ice->base.name, result, "ICE operation complete"
" (op=%d%s)", op,
@@ -1844,6 +1971,15 @@ static void ice_on_ice_complete(pj_ice_strans *ice_st,
/* Notify application */
if (tp_ice->cb.on_ice_complete)
(*tp_ice->cb.on_ice_complete)(&tp_ice->base, op, result);
+
+ for (il=tp_ice->listener.next; il!=&tp_ice->listener; il=il->next) {
+ if (il->cb.on_ice_complete2) {
+ (*il->cb.on_ice_complete2)(&tp_ice->base, op, result,
+ il->user_data);
+ } else if (il->cb.on_ice_complete) {
+ (*il->cb.on_ice_complete)(&tp_ice->base, op, result);
+ }
+ }
}
@@ -1865,6 +2001,11 @@ static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
return PJ_SUCCESS;
}
+static void tp_ice_on_destroy(void *arg)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*)arg;
+ pj_pool_safe_release(&tp_ice->pool);
+}
/*
* Destroy ICE media transport.
@@ -1873,13 +2014,21 @@ static pj_status_t transport_destroy(pjmedia_transport *tp)
{
struct transport_ice *tp_ice = (struct transport_ice*)tp;
+ /* Reset callback and user data */
+ pj_bzero(&tp_ice->cb, sizeof(tp_ice->cb));
+ tp_ice->base.user_data = NULL;
+ tp_ice->rtp_cb = NULL;
+ tp_ice->rtcp_cb = NULL;
+
if (tp_ice->ice_st) {
+ pj_grp_lock_t *grp_lock = pj_ice_strans_get_grp_lock(tp_ice->ice_st);
pj_ice_strans_destroy(tp_ice->ice_st);
tp_ice->ice_st = NULL;
+ pj_grp_lock_dec_ref(grp_lock);
+ } else {
+ tp_ice_on_destroy(tp);
}
- pj_pool_safe_release(&tp_ice->pool);
-
return PJ_SUCCESS;
}
diff --git a/pjmedia/src/pjmedia/transport_srtp.c b/pjmedia/src/pjmedia/transport_srtp.c
index 84be1ea..1cc01f0 100644
--- a/pjmedia/src/pjmedia/transport_srtp.c
+++ b/pjmedia/src/pjmedia/transport_srtp.c
@@ -1,4 +1,4 @@
-/* $Id: transport_srtp.c 5520 2017-01-11 04:38:29Z riza $ */
+/* $Id: transport_srtp.c 5656 2017-09-22 02:42:22Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -21,6 +21,7 @@
#include <pjmedia/transport_srtp.h>
#include <pjmedia/endpoint.h>
#include <pjlib-util/base64.h>
+#include <pj/array.h>
#include <pj/assert.h>
#include <pj/ctype.h>
#include <pj/lock.h>
@@ -32,6 +33,7 @@
#if defined(PJ_HAS_SSL_SOCK) && (PJ_HAS_SSL_SOCK != 0)
# include <openssl/rand.h>
+# include <openssl/opensslv.h>
/* Suppress compile warning of OpenSSL deprecation (OpenSSL is deprecated
* since MacOSX 10.7).
@@ -42,10 +44,36 @@
#endif
-#if defined(PJMEDIA_EXTERNAL_SRTP) && (PJMEDIA_EXTERNAL_SRTP != 0)
+#if defined(PJMEDIA_EXTERNAL_SRTP)
+
+#if (PJMEDIA_EXTERNAL_SRTP == 1) /* External SRTP 1.x */
# include <srtp/srtp.h>
# include <srtp/crypto_kernel.h>
-#else
+#define srtp_crypto_policy_t crypto_policy_t
+#define srtp_cipher_type_id_t cipher_type_id_t
+#define srtp_cipher_type_t cipher_type_t
+#define srtp_auth_type_id_t auth_type_id_t
+#define srtp_sec_serv_t sec_serv_t
+#define srtp_err_status_t err_status_t
+#define srtp_err_status_ok err_status_ok
+#define srtp_err_status_replay_old err_status_replay_old
+#define srtp_err_status_replay_fail err_status_replay_fail
+#define srtp_crypto_policy_set_aes_cm_256_hmac_sha1_32 \
+ crypto_policy_set_aes_cm_256_hmac_sha1_32
+#define srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80 \
+ crypto_policy_set_aes_cm_256_hmac_sha1_80
+#define SRTP_NULL_CIPHER NULL_CIPHER
+#define SRTP_NULL_AUTH NULL_AUTH
+#define SRTP_AES_ICM_128 AES_ICM
+#define SRTP_AES_ICM_256 AES_ICM
+#define SRTP_HMAC_SHA1 HMAC_SHA1
+
+#else /* External SRTP 2.x */
+# include <srtp2/srtp.h>
+# include <srtp2/cipher.h>
+#endif
+
+#else /* Bundled SRTP */
# include <srtp.h>
# include <crypto_kernel.h>
#endif
@@ -67,92 +95,114 @@
#define DEACTIVATE_MEDIA(pool, m) pjmedia_sdp_media_deactivate(pool, m)
+#ifdef SRTP_MAX_TRAILER_LEN
+# define MAX_TRAILER_LEN SRTP_MAX_TRAILER_LEN
+#else
+# define MAX_TRAILER_LEN 10
+#endif
+
static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 };
static const pj_str_t ID_RTP_SAVP = { "RTP/SAVP", 8 };
static const pj_str_t ID_INACTIVE = { "inactive", 8 };
static const pj_str_t ID_CRYPTO = { "crypto", 6 };
-typedef void (*crypto_method_t)(crypto_policy_t *policy);
+typedef void (*crypto_method_t)(srtp_crypto_policy_t *policy);
typedef struct crypto_suite
{
char *name;
- cipher_type_id_t cipher_type;
- unsigned cipher_key_len;
- auth_type_id_t auth_type;
+ srtp_cipher_type_id_t cipher_type;
+ unsigned cipher_key_len; /* key + salt length */
+ unsigned cipher_salt_len; /* salt only length */
+ srtp_auth_type_id_t auth_type;
unsigned auth_key_len;
unsigned srtp_auth_tag_len;
unsigned srtcp_auth_tag_len;
- sec_serv_t service;
+ srtp_sec_serv_t service;
/* This is an attempt to validate crypto support by libsrtp, i.e: it should
* raise linking error if the libsrtp does not support the crypto.
*/
- cipher_type_t *ext_cipher_type;
+ srtp_cipher_type_t *ext_cipher_type;
crypto_method_t ext_crypto_method;
} crypto_suite;
-extern cipher_type_t aes_gcm_256_openssl;
-extern cipher_type_t aes_gcm_128_openssl;
-extern cipher_type_t aes_icm_192;
+extern srtp_cipher_type_t srtp_aes_gcm_256_openssl;
+extern srtp_cipher_type_t srtp_aes_gcm_128_openssl;
+extern srtp_cipher_type_t srtp_aes_icm_192;
/* https://www.iana.org/assignments/sdp-security-descriptions/sdp-security-descriptions.xhtml */
static crypto_suite crypto_suites[] = {
/* plain RTP/RTCP (no cipher & no auth) */
- {"NULL", NULL_CIPHER, 0, NULL_AUTH, 0, 0, 0, sec_serv_none},
-#if defined(PJMEDIA_SRTP_HAS_AES_GCM_256) && \
- (PJMEDIA_SRTP_HAS_AES_GCM_256 != 0)
+ {"NULL", SRTP_NULL_CIPHER, 0, SRTP_NULL_AUTH, 0, 0, 0, sec_serv_none},
+
+#if defined(PJMEDIA_SRTP_HAS_AES_GCM_256)&&(PJMEDIA_SRTP_HAS_AES_GCM_256!=0)
+
/* cipher AES_GCM, NULL auth, auth tag len = 16 octets */
- {"AEAD_AES_256_GCM", AES_256_GCM, AES_256_GCM_KEYSIZE_WSALT,
- NULL_AUTH, 0, 16, 16, sec_serv_conf_and_auth, &aes_gcm_256_openssl},
+ {"AEAD_AES_256_GCM", SRTP_AES_GCM_256, 44, 12,
+ SRTP_NULL_AUTH, 0, 16, 16, sec_serv_conf_and_auth,
+ &srtp_aes_gcm_256_openssl},
+
/* cipher AES_GCM, NULL auth, auth tag len = 8 octets */
- {"AEAD_AES_256_GCM_8", AES_256_GCM, AES_256_GCM_KEYSIZE_WSALT,
- NULL_AUTH, 0, 8, 8, sec_serv_conf_and_auth, &aes_gcm_256_openssl},
+ {"AEAD_AES_256_GCM_8", SRTP_AES_GCM_256, 44, 12,
+ SRTP_NULL_AUTH, 0, 8, 8, sec_serv_conf_and_auth,
+ &srtp_aes_gcm_256_openssl},
#endif
-#if defined(PJMEDIA_SRTP_HAS_AES_CM_256) && \
- (PJMEDIA_SRTP_HAS_AES_CM_256 != 0)
- /* cipher AES_CM_256, auth HMAC_SHA1, auth tag len = 10 octets */
- {"AES_256_CM_HMAC_SHA1_80", AES_ICM, 46, HMAC_SHA1, 20, 10, 10,
- sec_serv_conf_and_auth, NULL,
- &crypto_policy_set_aes_cm_256_hmac_sha1_80},
- /* cipher AES_CM_256, auth HMAC_SHA1, auth tag len = 10 octets */
- {"AES_256_CM_HMAC_SHA1_32", AES_ICM, 46, HMAC_SHA1, 20, 4, 10,
- sec_serv_conf_and_auth, NULL,
- &crypto_policy_set_aes_cm_256_hmac_sha1_32},
+#if defined(PJMEDIA_SRTP_HAS_AES_CM_256)&&(PJMEDIA_SRTP_HAS_AES_CM_256!=0)
+
+ /* cipher AES_CM_256, auth SRTP_HMAC_SHA1, auth tag len = 10 octets */
+ {"AES_256_CM_HMAC_SHA1_80", SRTP_AES_ICM_256, 46, 14,
+ SRTP_HMAC_SHA1, 20, 10, 10, sec_serv_conf_and_auth,
+ NULL, &srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80},
+
+ /* cipher AES_CM_256, auth SRTP_HMAC_SHA1, auth tag len = 10 octets */
+ {"AES_256_CM_HMAC_SHA1_32", SRTP_AES_ICM_256, 46, 14,
+ SRTP_HMAC_SHA1, 20, 4, 10, sec_serv_conf_and_auth,
+ NULL, &srtp_crypto_policy_set_aes_cm_256_hmac_sha1_32},
#endif
-#if defined(PJMEDIA_SRTP_HAS_AES_CM_192) && \
- (PJMEDIA_SRTP_HAS_AES_CM_192 != 0)
- /* cipher AES_CM_192, auth HMAC_SHA1, auth tag len = 10 octets */
- {"AES_192_CM_HMAC_SHA1_80", AES_ICM, 38, HMAC_SHA1, 20, 10, 10,
- sec_serv_conf_and_auth, &aes_icm_192},
- /* cipher AES_CM_192, auth HMAC_SHA1, auth tag len = 4 octets */
- {"AES_192_CM_HMAC_SHA1_32", AES_ICM, 38, HMAC_SHA1, 20, 4, 10,
- sec_serv_conf_and_auth, &aes_icm_192},
+#if defined(PJMEDIA_SRTP_HAS_AES_CM_192)&&(PJMEDIA_SRTP_HAS_AES_CM_192!=0)
+
+ /* cipher AES_CM_192, auth SRTP_HMAC_SHA1, auth tag len = 10 octets */
+ {"AES_192_CM_HMAC_SHA1_80", SRTP_AES_ICM_192, 38, 14,
+ SRTP_HMAC_SHA1, 20, 10, 10, sec_serv_conf_and_auth,
+ &srtp_aes_icm_192},
+
+ /* cipher AES_CM_192, auth SRTP_HMAC_SHA1, auth tag len = 4 octets */
+ {"AES_192_CM_HMAC_SHA1_32", SRTP_AES_ICM_192, 38, 14,
+ SRTP_HMAC_SHA1, 20, 4, 10, sec_serv_conf_and_auth,
+ &srtp_aes_icm_192},
#endif
-#if defined(PJMEDIA_SRTP_HAS_AES_GCM_128) && \
- (PJMEDIA_SRTP_HAS_AES_GCM_128 != 0)
+#if defined(PJMEDIA_SRTP_HAS_AES_GCM_128)&&(PJMEDIA_SRTP_HAS_AES_GCM_128!=0)
+
/* cipher AES_GCM, NULL auth, auth tag len = 16 octets */
- {"AEAD_AES_128_GCM", AES_128_GCM, AES_128_GCM_KEYSIZE_WSALT,
- NULL_AUTH, 0, 16, 16, sec_serv_conf_and_auth, &aes_gcm_128_openssl},
+ {"AEAD_AES_128_GCM", SRTP_AES_GCM_128, 28, 12,
+ SRTP_NULL_AUTH, 0, 16, 16, sec_serv_conf_and_auth,
+ &srtp_aes_gcm_128_openssl},
/* cipher AES_GCM, NULL auth, auth tag len = 8 octets */
- {"AEAD_AES_128_GCM_8", AES_128_GCM, AES_128_GCM_KEYSIZE_WSALT,
- NULL_AUTH, 0, 8, 8, sec_serv_conf_and_auth, &aes_gcm_128_openssl},
+ {"AEAD_AES_128_GCM_8", SRTP_AES_GCM_128, 28, 12,
+ SRTP_NULL_AUTH, 0, 8, 8, sec_serv_conf_and_auth,
+ &srtp_aes_gcm_128_openssl},
#endif
-#if defined(PJMEDIA_SRTP_HAS_AES_CM_128) && \
- (PJMEDIA_SRTP_HAS_AES_CM_128 != 0)
- /* cipher AES_CM_128, auth HMAC_SHA1, auth tag len = 10 octets */
- {"AES_CM_128_HMAC_SHA1_80", AES_ICM, 30, HMAC_SHA1, 20, 10, 10,
- sec_serv_conf_and_auth},
- /* cipher AES_CM_128, auth HMAC_SHA1, auth tag len = 4 octets */
- {"AES_CM_128_HMAC_SHA1_32", AES_ICM, 30, HMAC_SHA1, 20, 4, 10,
- sec_serv_conf_and_auth},
+#if defined(PJMEDIA_SRTP_HAS_AES_CM_128)&&(PJMEDIA_SRTP_HAS_AES_CM_128!=0)
+
+ /* cipher AES_CM_128, auth SRTP_HMAC_SHA1, auth tag len = 10 octets */
+ {"AES_CM_128_HMAC_SHA1_80", SRTP_AES_ICM_128, 30, 14,
+ SRTP_HMAC_SHA1, 20, 10, 10, sec_serv_conf_and_auth},
+
+ /* cipher AES_CM_128, auth SRTP_HMAC_SHA1, auth tag len = 4 octets */
+ {"AES_CM_128_HMAC_SHA1_32", SRTP_AES_ICM_128, 30, 14,
+ SRTP_HMAC_SHA1, 20, 4, 10, sec_serv_conf_and_auth},
#endif
+
/*
* F8_128_HMAC_SHA1_8 not supported by libsrtp?
- * {"F8_128_HMAC_SHA1_8", NULL_CIPHER, 0, NULL_AUTH, 0, 0, 0, sec_serv_none}
+ * {"F8_128_HMAC_SHA1_8", NULL_CIPHER, 0, 0, NULL_AUTH, 0, 0, 0,
+ * sec_serv_none}
*/
};
+
+/* SRTP transport */
typedef struct transport_srtp
{
pjmedia_transport base; /**< Base transport interface. */
@@ -191,6 +241,7 @@ typedef struct transport_srtp
/* Transport information */
pjmedia_transport *member_tp; /**< Underlying transport. */
+ pj_bool_t member_tp_attached;
/* SRTP usage policy of peer. This field is updated when media is starting.
* This is useful when SRTP is in optional mode and peer is using mandatory
@@ -203,6 +254,25 @@ typedef struct transport_srtp
* and it may restart when srtp_unprotect() returns err_status_replay_*
*/
unsigned probation_cnt;
+
+ /* SRTP keying methods. The keying is implemented using media transport
+ * abstraction, so it will also be invoked when the SRTP media transport
+ * operation is invoked.
+ *
+ * As there can be multiple keying methods enabled (currently only SDES &
+ * DTLS-SRTP), each keying method will be given the chance to respond to
+ * remote SDP. If any keying operation returns non-success, it will be
+ * removed from the session. And once SRTP key is obtained via a keying
+ * method, any other keying methods will be stopped and destroyed.
+ */
+ unsigned keying_cnt;
+ pjmedia_transport *keying[2];
+
+ /* If not zero, keying nego is ongoing (async-ly, e.g: by DTLS-SRTP).
+ * This field may be updated by keying method.
+ */
+ unsigned keying_pending_cnt;
+
} transport_srtp;
@@ -222,17 +292,17 @@ static void srtp_rtcp_cb( void *user_data, void *pkt, pj_ssize_t size);
*/
static pj_status_t transport_get_info (pjmedia_transport *tp,
pjmedia_transport_info *info);
-static pj_status_t transport_attach (pjmedia_transport *tp,
- void *user_data,
- const pj_sockaddr_t *rem_addr,
- const pj_sockaddr_t *rem_rtcp,
- unsigned addr_len,
- void (*rtp_cb)(void*,
- void*,
- pj_ssize_t),
- void (*rtcp_cb)(void*,
- void*,
- pj_ssize_t));
+//static pj_status_t transport_attach (pjmedia_transport *tp,
+// void *user_data,
+// const pj_sockaddr_t *rem_addr,
+// const pj_sockaddr_t *rem_rtcp,
+// unsigned addr_len,
+// void (*rtp_cb)(void*,
+// void*,
+// pj_ssize_t),
+// void (*rtcp_cb)(void*,
+// void*,
+// pj_ssize_t));
static void transport_detach (pjmedia_transport *tp,
void *strm);
static pj_status_t transport_send_rtp( pjmedia_transport *tp,
@@ -266,13 +336,15 @@ static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
pjmedia_dir dir,
unsigned pct_lost);
static pj_status_t transport_destroy (pjmedia_transport *tp);
+static pj_status_t transport_attach2 (pjmedia_transport *tp,
+ pjmedia_transport_attach_param *param);
static pjmedia_transport_op transport_srtp_op =
{
&transport_get_info,
- &transport_attach,
+ NULL, //&transport_attach,
&transport_detach,
&transport_send_rtp,
&transport_send_rtcp,
@@ -282,9 +354,24 @@ static pjmedia_transport_op transport_srtp_op =
&transport_media_start,
&transport_media_stop,
&transport_simulate_lost,
- &transport_destroy
+ &transport_destroy,
+ &transport_attach2
};
+/* Get crypto index from crypto name */
+static int get_crypto_idx(const pj_str_t* crypto_name);
+
+/* Is crypto empty (i.e: no name or key)? */
+static pj_bool_t srtp_crypto_empty(const pjmedia_srtp_crypto* c);
+
+/* Compare crypto, return zero if same */
+static int srtp_crypto_cmp(const pjmedia_srtp_crypto* c1,
+ const pjmedia_srtp_crypto* c2);
+
+/* Start SRTP */
+static pj_status_t start_srtp(transport_srtp *srtp);
+
+
/* This function may also be used by other module, e.g: pjmedia/errno.c,
* it should have C compatible declaration.
*/
@@ -296,7 +383,7 @@ const char* get_libsrtp_errstr(int err)
{
#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)
static char *liberr[] = {
- "ok", /* err_status_ok = 0 */
+ "ok", /* srtp_err_status_ok = 0 */
"unspecified failure", /* err_status_fail = 1 */
"unsupported parameter", /* err_status_bad_param = 2 */
"couldn't allocate memory", /* err_status_alloc_fail = 3 */
@@ -339,44 +426,83 @@ const char* get_libsrtp_errstr(int err)
#endif
}
+/* SRTP keying method: Session Description */
+#if defined(PJMEDIA_SRTP_HAS_SDES) && (PJMEDIA_SRTP_HAS_SDES != 0)
+# include "transport_srtp_sdes.c"
+#endif
+
+/* SRTP keying method: DTLS */
+#if defined(PJMEDIA_SRTP_HAS_DTLS) && (PJMEDIA_SRTP_HAS_DTLS != 0)
+# include "transport_srtp_dtls.c"
+#else
+PJ_DEF(pj_status_t) pjmedia_transport_srtp_dtls_start_nego(
+ pjmedia_transport *srtp,
+ const pjmedia_srtp_dtls_nego_param *param)
+{
+ PJ_UNUSED_ARG(srtp);
+ PJ_UNUSED_ARG(param);
+ return PJ_ENOTSUP;
+}
+PJ_DEF(pj_status_t) pjmedia_transport_srtp_dtls_get_fingerprint(
+ pjmedia_transport *srtp,
+ const char *hash,
+ char *buf, pj_size_t *len)
+{
+ PJ_UNUSED_ARG(srtp);
+ PJ_UNUSED_ARG(hash);
+ PJ_UNUSED_ARG(buf);
+ PJ_UNUSED_ARG(len);
+ return PJ_ENOTSUP;
+}
+#endif
+
+
static pj_bool_t libsrtp_initialized;
static void pjmedia_srtp_deinit_lib(pjmedia_endpt *endpt);
PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(pjmedia_endpt *endpt)
{
+ pj_status_t status = PJ_SUCCESS;
+
+ if (libsrtp_initialized)
+ return PJ_SUCCESS;
+
#if PJMEDIA_LIBSRTP_AUTO_INIT_DEINIT
- if (libsrtp_initialized == PJ_FALSE) {
- err_status_t err;
+ /* Init libsrtp */
+ {
+ srtp_err_status_t err;
err = srtp_init();
- if (err != err_status_ok) {
+ if (err != srtp_err_status_ok) {
PJ_LOG(4, (THIS_FILE, "Failed to initialize libsrtp: %s",
get_libsrtp_errstr(err)));
return PJMEDIA_ERRNO_FROM_LIBSRTP(err);
}
+ }
+#endif
- if (pjmedia_endpt_atexit(endpt, pjmedia_srtp_deinit_lib) != PJ_SUCCESS)
- {
- /* There will be memory leak when it fails to schedule libsrtp
- * deinitialization, however the memory leak could be harmless,
- * since in modern OS's memory used by an application is released
- * when the application terminates.
- */
- PJ_LOG(4, (THIS_FILE, "Failed to register libsrtp deinit."));
- }
+#if defined(PJMEDIA_SRTP_HAS_DTLS) && (PJMEDIA_SRTP_HAS_DTLS != 0)
+ dtls_init();
+#endif
- libsrtp_initialized = PJ_TRUE;
+ if (pjmedia_endpt_atexit(endpt, pjmedia_srtp_deinit_lib) != PJ_SUCCESS)
+ {
+ /* There will be memory leak when it fails to schedule libsrtp
+ * deinitialization, however the memory leak could be harmless,
+ * since in modern OS's memory used by an application is released
+ * when the application terminates.
+ */
+ PJ_LOG(4, (THIS_FILE, "Failed to register libsrtp deinit."));
}
-#else
- PJ_UNUSED_ARG(endpt);
-#endif
- return PJ_SUCCESS;
+ libsrtp_initialized = PJ_TRUE;
+
+ return status;
}
static void pjmedia_srtp_deinit_lib(pjmedia_endpt *endpt)
{
- err_status_t err;
+ srtp_err_status_t err;
/* Note that currently this SRTP init/deinit is not equipped with
* reference counter, it should be safe as normally there is only
@@ -391,17 +517,24 @@ static void pjmedia_srtp_deinit_lib(pjmedia_endpt *endpt)
# define PJMEDIA_SRTP_HAS_SHUTDOWN 1
#endif
+#if PJMEDIA_LIBSRTP_AUTO_INIT_DEINIT
+
# if defined(PJMEDIA_SRTP_HAS_DEINIT) && PJMEDIA_SRTP_HAS_DEINIT!=0
err = srtp_deinit();
# elif defined(PJMEDIA_SRTP_HAS_SHUTDOWN) && PJMEDIA_SRTP_HAS_SHUTDOWN!=0
err = srtp_shutdown();
# else
- err = err_status_ok;
+ err = srtp_err_status_ok;
# endif
- if (err != err_status_ok) {
+ if (err != srtp_err_status_ok) {
PJ_LOG(4, (THIS_FILE, "Failed to deinitialize libsrtp: %s",
get_libsrtp_errstr(err)));
}
+#endif // PJMEDIA_LIBSRTP_AUTO_INIT_DEINIT
+
+#if defined(PJMEDIA_SRTP_HAS_DTLS) && (PJMEDIA_SRTP_HAS_DTLS != 0)
+ dtls_deinit();
+#endif
libsrtp_initialized = PJ_FALSE;
}
@@ -462,6 +595,14 @@ PJ_DEF(void) pjmedia_srtp_setting_default(pjmedia_srtp_setting *opt)
opt->crypto_count = sizeof(crypto_suites)/sizeof(crypto_suites[0]) - 1;
for (i=0; i<opt->crypto_count; ++i)
opt->crypto[i].name = pj_str(crypto_suites[i+1].name);
+
+ /* Keying method */
+ opt->keying_count = PJMEDIA_SRTP_KEYINGS_COUNT;
+ opt->keying[0] = PJMEDIA_SRTP_KEYING_SDES;
+ opt->keying[1] = PJMEDIA_SRTP_KEYING_DTLS_SRTP;
+
+ /* Just for reminder to add any new keying to the array above */
+ pj_assert(PJMEDIA_SRTP_KEYINGS_COUNT == 2);
}
@@ -549,6 +690,7 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_create(
else
srtp->base.type = PJMEDIA_TRANSPORT_TYPE_UDP;
srtp->base.op = &transport_srtp_op;
+ srtp->base.user_data = srtp->setting.user_data;
/* Set underlying transport */
srtp->member_tp = tp;
@@ -556,6 +698,27 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_create(
/* Initialize peer's SRTP usage mode. */
srtp->peer_use = srtp->setting.use;
+ /* Initialize SRTP keying method. */
+ for (i = 0; i < srtp->setting.keying_count; ++i) {
+ switch(srtp->setting.keying[i]) {
+
+ case PJMEDIA_SRTP_KEYING_SDES:
+#if defined(PJMEDIA_SRTP_HAS_SDES) && (PJMEDIA_SRTP_HAS_SDES != 0)
+ sdes_create(srtp, &srtp->keying[srtp->keying_cnt++]);
+#endif
+ break;
+
+ case PJMEDIA_SRTP_KEYING_DTLS_SRTP:
+#if defined(PJMEDIA_SRTP_HAS_DTLS) && (PJMEDIA_SRTP_HAS_DTLS != 0)
+ dtls_create(srtp, &srtp->keying[srtp->keying_cnt++]);
+#endif
+ break;
+
+ default:
+ break;
+ }
+ }
+
/* Done */
*p_tp = &srtp->base;
@@ -574,7 +737,7 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_start(
transport_srtp *srtp = (transport_srtp*) tp;
srtp_policy_t tx_;
srtp_policy_t rx_;
- err_status_t err;
+ srtp_err_status_t err;
int cr_tx_idx = 0;
int au_tx_idx = 0;
int cr_rx_idx = 0;
@@ -647,7 +810,7 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_start(
tx_.rtcp.auth_tag_len = crypto_suites[au_tx_idx].srtcp_auth_tag_len;
tx_.next = NULL;
err = srtp_create(&srtp->srtp_tx_ctx, &tx_);
- if (err != err_status_ok) {
+ if (err != srtp_err_status_ok) {
status = PJMEDIA_ERRNO_FROM_LIBSRTP(err);
goto on_return;
}
@@ -680,7 +843,7 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_start(
rx_.rtcp.auth_tag_len = crypto_suites[au_rx_idx].srtcp_auth_tag_len;
rx_.next = NULL;
err = srtp_create(&srtp->srtp_rx_ctx, &rx_);
- if (err != err_status_ok) {
+ if (err != srtp_err_status_ok) {
srtp_dealloc(srtp->srtp_tx_ctx);
status = PJMEDIA_ERRNO_FROM_LIBSRTP(err);
goto on_return;
@@ -700,7 +863,7 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_start(
/* TX crypto and key */
b64_len = sizeof(b64);
- status = pj_base64_encode((pj_uint8_t*)tx->key.ptr, tx->key.slen,
+ status = pj_base64_encode((pj_uint8_t*)tx->key.ptr, (int)tx->key.slen,
b64, &b64_len);
if (status != PJ_SUCCESS)
b64_len = pj_ansi_sprintf(b64, "--key too long--");
@@ -717,7 +880,7 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_start(
/* RX crypto and key */
b64_len = sizeof(b64);
- status = pj_base64_encode((pj_uint8_t*)rx->key.ptr, rx->key.slen,
+ status = pj_base64_encode((pj_uint8_t*)rx->key.ptr, (int)rx->key.slen,
b64, &b64_len);
if (status != PJ_SUCCESS)
b64_len = pj_ansi_sprintf(b64, "--key too long--");
@@ -745,7 +908,7 @@ on_return:
PJ_DEF(pj_status_t) pjmedia_transport_srtp_stop(pjmedia_transport *srtp)
{
transport_srtp *p_srtp = (transport_srtp*) srtp;
- err_status_t err;
+ srtp_err_status_t err;
PJ_ASSERT_RETURN(srtp, PJ_EINVAL);
@@ -757,13 +920,13 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_stop(pjmedia_transport *srtp)
}
err = srtp_dealloc(p_srtp->srtp_rx_ctx);
- if (err != err_status_ok) {
+ if (err != srtp_err_status_ok) {
PJ_LOG(4, (p_srtp->pool->obj_name,
"Failed to dealloc RX SRTP context: %s",
get_libsrtp_errstr(err)));
}
err = srtp_dealloc(p_srtp->srtp_tx_ctx);
- if (err != err_status_ok) {
+ if (err != srtp_err_status_ok) {
PJ_LOG(4, (p_srtp->pool->obj_name,
"Failed to dealloc TX SRTP context: %s",
get_libsrtp_errstr(err)));
@@ -778,6 +941,48 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_stop(pjmedia_transport *srtp)
return PJ_SUCCESS;
}
+
+static pj_status_t start_srtp(transport_srtp *srtp)
+{
+ /* Make sure we have the SRTP policies */
+ if (srtp_crypto_empty(&srtp->tx_policy_neg) ||
+ srtp_crypto_empty(&srtp->rx_policy_neg))
+ {
+ srtp->bypass_srtp = PJ_TRUE;
+ srtp->peer_use = PJMEDIA_SRTP_DISABLED;
+ if (srtp->session_inited) {
+ pjmedia_transport_srtp_stop(&srtp->base);
+ }
+
+ return PJ_SUCCESS;
+ }
+
+ /* Reset probation counts */
+ srtp->probation_cnt = PROBATION_CNT_INIT;
+
+ /* Got policy_local & policy_remote, let's initalize the SRTP */
+
+ /* Ticket #1075: media_start() is called whenever media description
+ * gets updated, e.g: call hold, however we should restart SRTP only
+ * when the SRTP policy settings are updated.
+ */
+ if (srtp_crypto_cmp(&srtp->tx_policy_neg, &srtp->tx_policy) ||
+ srtp_crypto_cmp(&srtp->rx_policy_neg, &srtp->rx_policy))
+ {
+ pj_status_t status;
+ status = pjmedia_transport_srtp_start(&srtp->base,
+ &srtp->tx_policy_neg,
+ &srtp->rx_policy_neg);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ srtp->bypass_srtp = PJ_FALSE;
+
+ return PJ_SUCCESS;
+}
+
+
PJ_DEF(pjmedia_transport *) pjmedia_transport_srtp_get_member(
pjmedia_transport *tp)
{
@@ -795,6 +1000,7 @@ static pj_status_t transport_get_info(pjmedia_transport *tp,
transport_srtp *srtp = (transport_srtp*) tp;
pjmedia_srtp_info srtp_info;
int spc_info_idx;
+ unsigned i;
PJ_ASSERT_RETURN(tp && info, PJ_EINVAL);
PJ_ASSERT_RETURN(info->specific_info_cnt <
@@ -814,35 +1020,35 @@ static pj_status_t transport_get_info(pjmedia_transport *tp,
pj_memcpy(&info->spc_info[spc_info_idx].buffer, &srtp_info,
sizeof(srtp_info));
+ /* Invoke get_info() of all keying methods */
+ for (i=0; i < srtp->keying_cnt; i++)
+ pjmedia_transport_get_info(srtp->keying[i], info);
+
return pjmedia_transport_get_info(srtp->member_tp, info);
}
-static pj_status_t transport_attach(pjmedia_transport *tp,
- void *user_data,
- const pj_sockaddr_t *rem_addr,
- const pj_sockaddr_t *rem_rtcp,
- unsigned addr_len,
- void (*rtp_cb) (void*, void*,
- pj_ssize_t),
- void (*rtcp_cb)(void*, void*,
- pj_ssize_t))
+static pj_status_t transport_attach2(pjmedia_transport *tp,
+ pjmedia_transport_attach_param *param)
{
transport_srtp *srtp = (transport_srtp*) tp;
+ pjmedia_transport_attach_param member_param;
pj_status_t status;
- PJ_ASSERT_RETURN(tp && rem_addr && addr_len, PJ_EINVAL);
+ PJ_ASSERT_RETURN(tp && param, PJ_EINVAL);
/* Save the callbacks */
pj_lock_acquire(srtp->mutex);
- srtp->rtp_cb = rtp_cb;
- srtp->rtcp_cb = rtcp_cb;
- srtp->user_data = user_data;
+ srtp->rtp_cb = param->rtp_cb;
+ srtp->rtcp_cb = param->rtcp_cb;
+ srtp->user_data = param->user_data;
pj_lock_release(srtp->mutex);
- /* Attach itself to transport */
- status = pjmedia_transport_attach(srtp->member_tp, srtp, rem_addr,
- rem_rtcp, addr_len, &srtp_rtp_cb,
- &srtp_rtcp_cb);
+ /* Attach self to member transport */
+ member_param = *param;
+ member_param.user_data = srtp;
+ member_param.rtp_cb = &srtp_rtp_cb;
+ member_param.rtcp_cb = &srtp_rtcp_cb;
+ status = pjmedia_transport_attach2(srtp->member_tp, &member_param);
if (status != PJ_SUCCESS) {
pj_lock_acquire(srtp->mutex);
srtp->rtp_cb = NULL;
@@ -852,6 +1058,7 @@ static pj_status_t transport_attach(pjmedia_transport *tp,
return status;
}
+ srtp->member_tp_attached = PJ_TRUE;
return PJ_SUCCESS;
}
@@ -872,6 +1079,7 @@ static void transport_detach(pjmedia_transport *tp, void *strm)
srtp->rtcp_cb = NULL;
srtp->user_data = NULL;
pj_lock_release(srtp->mutex);
+ srtp->member_tp_attached = PJ_FALSE;
}
static pj_status_t transport_send_rtp( pjmedia_transport *tp,
@@ -881,12 +1089,12 @@ static pj_status_t transport_send_rtp( pjmedia_transport *tp,
pj_status_t status;
transport_srtp *srtp = (transport_srtp*) tp;
int len = (int)size;
- err_status_t err;
+ srtp_err_status_t err;
if (srtp->bypass_srtp)
return pjmedia_transport_send_rtp(srtp->member_tp, pkt, size);
- if (size > sizeof(srtp->rtp_tx_buffer) - 10)
+ if (size > sizeof(srtp->rtp_tx_buffer) - MAX_TRAILER_LEN)
return PJ_ETOOBIG;
pj_memcpy(srtp->rtp_tx_buffer, pkt, size);
@@ -899,7 +1107,7 @@ static pj_status_t transport_send_rtp( pjmedia_transport *tp,
err = srtp_protect(srtp->srtp_tx_ctx, srtp->rtp_tx_buffer, &len);
pj_lock_release(srtp->mutex);
- if (err == err_status_ok) {
+ if (err == srtp_err_status_ok) {
status = pjmedia_transport_send_rtp(srtp->member_tp,
srtp->rtp_tx_buffer, len);
} else {
@@ -925,14 +1133,14 @@ static pj_status_t transport_send_rtcp2(pjmedia_transport *tp,
pj_status_t status;
transport_srtp *srtp = (transport_srtp*) tp;
int len = (int)size;
- err_status_t err;
+ srtp_err_status_t err;
if (srtp->bypass_srtp) {
return pjmedia_transport_send_rtcp2(srtp->member_tp, addr, addr_len,
pkt, size);
}
- if (size > sizeof(srtp->rtcp_tx_buffer) - 10)
+ if (size > sizeof(srtp->rtcp_tx_buffer) - (MAX_TRAILER_LEN+4))
return PJ_ETOOBIG;
pj_memcpy(srtp->rtcp_tx_buffer, pkt, size);
@@ -945,7 +1153,7 @@ static pj_status_t transport_send_rtcp2(pjmedia_transport *tp,
err = srtp_protect_rtcp(srtp->srtp_tx_ctx, srtp->rtcp_tx_buffer, &len);
pj_lock_release(srtp->mutex);
- if (err == err_status_ok) {
+ if (err == srtp_err_status_ok) {
status = pjmedia_transport_send_rtcp2(srtp->member_tp, addr, addr_len,
srtp->rtcp_tx_buffer, len);
} else {
@@ -971,9 +1179,15 @@ static pj_status_t transport_destroy (pjmedia_transport *tp)
{
transport_srtp *srtp = (transport_srtp *) tp;
pj_status_t status;
+ unsigned i;
PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+ /* Close keying */
+ for (i=0; i < srtp->keying_cnt; i++)
+ pjmedia_transport_close(srtp->keying[i]);
+
+ /* Close member if configured */
if (srtp->setting.close_member_tp && srtp->member_tp) {
pjmedia_transport_close(srtp->member_tp);
}
@@ -996,8 +1210,8 @@ static pj_status_t transport_destroy (pjmedia_transport *tp)
static void srtp_rtp_cb( void *user_data, void *pkt, pj_ssize_t size)
{
transport_srtp *srtp = (transport_srtp *) user_data;
- int len = size;
- err_status_t err;
+ int len = (int)size;
+ srtp_err_status_t err;
void (*cb)(void*, void*, pj_ssize_t) = NULL;
void *cb_data = NULL;
@@ -1010,6 +1224,26 @@ static void srtp_rtp_cb( void *user_data, void *pkt, pj_ssize_t size)
return;
}
+ /* Give the packet to keying first by invoking its send_rtp() op.
+ * Yes, the usage of send_rtp() is rather hacky, but it is convenient
+ * as the signature suits the purpose and it is ready to use
+ * (no futher registration/setting needed), and it may never be used
+ * by any keying method in the future.
+ */
+ {
+ unsigned i;
+ pj_status_t status;
+ for (i=0; i < srtp->keying_cnt; i++) {
+ if (!srtp->keying[i]->op->send_rtp)
+ continue;
+ status = pjmedia_transport_send_rtp(srtp->keying[i], pkt, size);
+ if (status != PJ_EIGNORED) {
+ /* Packet is already consumed by the keying method */
+ return;
+ }
+ }
+ }
+
/* Make sure buffer is 32bit aligned */
PJ_ASSERT_ON_FAIL( (((pj_ssize_t)pkt) & 0x03)==0, return );
@@ -1024,7 +1258,8 @@ static void srtp_rtp_cb( void *user_data, void *pkt, pj_ssize_t size)
}
err = srtp_unprotect(srtp->srtp_rx_ctx, (pj_uint8_t*)pkt, &len);
if (srtp->probation_cnt > 0 &&
- (err == err_status_replay_old || err == err_status_replay_fail))
+ (err == srtp_err_status_replay_old ||
+ err == srtp_err_status_replay_fail))
{
/* Handle such condition that stream is updated (RTP seq is reinited
* & SRTP is restarted), but some old packets are still coming
@@ -1047,7 +1282,7 @@ static void srtp_rtp_cb( void *user_data, void *pkt, pj_ssize_t size)
}
}
- if (err != err_status_ok) {
+ if (err != srtp_err_status_ok) {
PJ_LOG(5,(srtp->pool->obj_name,
"Failed to unprotect SRTP, pkt size=%d, err=%s",
size, get_libsrtp_errstr(err)));
@@ -1069,8 +1304,8 @@ static void srtp_rtp_cb( void *user_data, void *pkt, pj_ssize_t size)
static void srtp_rtcp_cb( void *user_data, void *pkt, pj_ssize_t size)
{
transport_srtp *srtp = (transport_srtp *) user_data;
- int len = size;
- err_status_t err;
+ int len = (int)size;
+ srtp_err_status_t err;
void (*cb)(void*, void*, pj_ssize_t) = NULL;
void *cb_data = NULL;
@@ -1093,7 +1328,7 @@ static void srtp_rtcp_cb( void *user_data, void *pkt, pj_ssize_t size)
return;
}
err = srtp_unprotect_rtcp(srtp->srtp_rx_ctx, (pj_uint8_t*)pkt, &len);
- if (err != err_status_ok) {
+ if (err != srtp_err_status_ok) {
PJ_LOG(5,(srtp->pool->obj_name,
"Failed to unprotect SRTCP, pkt size=%d, err=%s",
size, get_libsrtp_errstr(err)));
@@ -1109,186 +1344,6 @@ static void srtp_rtcp_cb( void *user_data, void *pkt, pj_ssize_t size)
}
}
-/* Generate crypto attribute, including crypto key.
- * If crypto-suite chosen is crypto NULL, just return PJ_SUCCESS,
- * and set buffer_len = 0.
- */
-static pj_status_t generate_crypto_attr_value(pj_pool_t *pool,
- char *buffer, int *buffer_len,
- pjmedia_srtp_crypto *crypto,
- int tag)
-{
- pj_status_t status;
- int cs_idx = get_crypto_idx(&crypto->name);
- char b64_key[PJ_BASE256_TO_BASE64_LEN(MAX_KEY_LEN)+1];
- int b64_key_len = sizeof(b64_key);
- int print_len;
-
- if (cs_idx == -1)
- return PJMEDIA_SRTP_ENOTSUPCRYPTO;
-
- /* Crypto-suite NULL. */
- if (cs_idx == 0) {
- *buffer_len = 0;
- return PJ_SUCCESS;
- }
-
- /* Generate key if not specified. */
- if (crypto->key.slen == 0) {
- pj_bool_t key_ok;
- char key[MAX_KEY_LEN];
- err_status_t err;
- unsigned i;
-
- PJ_ASSERT_RETURN(MAX_KEY_LEN >= crypto_suites[cs_idx].cipher_key_len,
- PJ_ETOOSMALL);
-
- do {
- key_ok = PJ_TRUE;
-
-
-#if defined(PJ_HAS_SSL_SOCK) && (PJ_HAS_SSL_SOCK != 0)
-
-/* Include OpenSSL libraries for MSVC */
-# ifdef _MSC_VER
-# pragma comment( lib, "libeay32")
-# pragma comment( lib, "ssleay32")
-# endif
-
- err = RAND_bytes((unsigned char*)key,
- crypto_suites[cs_idx].cipher_key_len);
- if (err != 1) {
- PJ_LOG(5,(THIS_FILE, "Failed generating random key"));
- return PJMEDIA_ERRNO_FROM_LIBSRTP(1);
- }
-#else
- err = crypto_get_random((unsigned char*)key,
- crypto_suites[cs_idx].cipher_key_len);
- if (err != err_status_ok) {
- PJ_LOG(5,(THIS_FILE, "Failed generating random key: %s",
- get_libsrtp_errstr(err)));
- return PJMEDIA_ERRNO_FROM_LIBSRTP(err);
- }
-#endif
- for (i=0; i<crypto_suites[cs_idx].cipher_key_len && key_ok; ++i)
- if (key[i] == 0) key_ok = PJ_FALSE;
-
- } while (!key_ok);
- crypto->key.ptr = (char*)
- pj_pool_zalloc(pool,
- crypto_suites[cs_idx].cipher_key_len);
- pj_memcpy(crypto->key.ptr, key, crypto_suites[cs_idx].cipher_key_len);
- crypto->key.slen = crypto_suites[cs_idx].cipher_key_len;
- }
-
- if (crypto->key.slen != (pj_ssize_t)crypto_suites[cs_idx].cipher_key_len)
- return PJMEDIA_SRTP_EINKEYLEN;
-
- /* Key transmitted via SDP should be base64 encoded. */
- status = pj_base64_encode((pj_uint8_t*)crypto->key.ptr, crypto->key.slen,
- b64_key, &b64_key_len);
- if (status != PJ_SUCCESS) {
- PJ_LOG(5,(THIS_FILE, "Failed encoding plain key to base64"));
- return status;
- }
-
- b64_key[b64_key_len] = '\0';
-
- PJ_ASSERT_RETURN(*buffer_len >= (crypto->name.slen + \
- b64_key_len + 16), PJ_ETOOSMALL);
-
- /* Print the crypto attribute value. */
- print_len = pj_ansi_snprintf(buffer, *buffer_len, "%d %s inline:%s",
- tag,
- crypto_suites[cs_idx].name,
- b64_key);
- if (print_len < 1 || print_len >= *buffer_len)
- return PJ_ETOOSMALL;
-
- *buffer_len = print_len;
-
- return PJ_SUCCESS;
-}
-
-/* Parse crypto attribute line */
-static pj_status_t parse_attr_crypto(pj_pool_t *pool,
- const pjmedia_sdp_attr *attr,
- pjmedia_srtp_crypto *crypto,
- int *tag)
-{
- pj_str_t token, delim;
- pj_status_t status;
- int itmp, found_idx;
-
- pj_bzero(crypto, sizeof(*crypto));
-
- /* Tag */
- delim = pj_str(" ");
- found_idx = pj_strtok(&attr->value, &delim, &token, 0);
- if (found_idx == attr->value.slen) {
- PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting tag"));
- return PJMEDIA_SDP_EINATTR;
- }
-
- /* Tag must not use leading zeroes. */
- if (token.slen > 1 && *token.ptr == '0')
- return PJMEDIA_SDP_EINATTR;
-
- /* Tag must be decimal, i.e: contains only digit '0'-'9'. */
- for (itmp = 0; itmp < token.slen; ++itmp)
- if (!pj_isdigit(token.ptr[itmp]))
- return PJMEDIA_SDP_EINATTR;
-
- /* Get tag value. */
- *tag = pj_strtoul(&token);
-
- /* Crypto-suite */
- found_idx = pj_strtok(&attr->value, &delim, &token, found_idx+token.slen);
- if (found_idx == attr->value.slen) {
- PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting crypto suite"));
- return PJMEDIA_SDP_EINATTR;
- }
- crypto->name = token;
-
- /* Key method */
- delim = pj_str(": ");
- found_idx = pj_strtok(&attr->value, &delim, &token, found_idx+token.slen);
- if (found_idx == attr->value.slen) {
- PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting key method"));
- return PJMEDIA_SDP_EINATTR;
- }
- if (pj_stricmp2(&token, "inline")) {
- PJ_LOG(4,(THIS_FILE, "Attribute crypto key method '%.*s' "
- "not supported!", token.slen, token.ptr));
- return PJMEDIA_SDP_EINATTR;
- }
-
- /* Key */
- delim = pj_str("| ");
- found_idx = pj_strtok(&attr->value, &delim, &token, found_idx+token.slen);
- if (found_idx == attr->value.slen) {
- PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting key"));
- return PJMEDIA_SDP_EINATTR;
- }
-
- if (PJ_BASE64_TO_BASE256_LEN(token.slen) > MAX_KEY_LEN) {
- PJ_LOG(4,(THIS_FILE, "Key too long"));
- return PJMEDIA_SRTP_EINKEYLEN;
- }
-
- /* Decode key */
- crypto->key.ptr = (char*) pj_pool_zalloc(pool, MAX_KEY_LEN);
- itmp = MAX_KEY_LEN;
- status = pj_base64_decode(&token, (pj_uint8_t*)crypto->key.ptr,
- &itmp);
- if (status != PJ_SUCCESS) {
- PJ_LOG(4,(THIS_FILE, "Failed decoding crypto key from base64"));
- return status;
- }
- crypto->key.slen = itmp;
-
- return PJ_SUCCESS;
-}
static pj_status_t transport_media_create(pjmedia_transport *tp,
pj_pool_t *sdp_pool,
@@ -1298,59 +1353,57 @@ static pj_status_t transport_media_create(pjmedia_transport *tp,
{
struct transport_srtp *srtp = (struct transport_srtp*) tp;
unsigned member_tp_option;
+ pj_status_t last_err_st = PJ_EBUG;
+ pj_status_t status;
+ unsigned i;
PJ_ASSERT_RETURN(tp, PJ_EINVAL);
pj_bzero(&srtp->rx_policy_neg, sizeof(srtp->rx_policy_neg));
pj_bzero(&srtp->tx_policy_neg, sizeof(srtp->tx_policy_neg));
- srtp->media_option = options;
- member_tp_option = options | PJMEDIA_TPMED_NO_TRANSPORT_CHECKING;
-
- srtp->offerer_side = sdp_remote == NULL;
-
- /* Validations */
- if (srtp->offerer_side) {
-
- if (srtp->setting.use == PJMEDIA_SRTP_DISABLED)
- goto BYPASS_SRTP;
+ srtp->media_option = member_tp_option = options;
+ srtp->offerer_side = (sdp_remote == NULL);
- } else {
-
- pjmedia_sdp_media *m_rem;
-
- m_rem = sdp_remote->media[media_index];
+ if (srtp->offerer_side && srtp->setting.use == PJMEDIA_SRTP_DISABLED)
+ srtp->bypass_srtp = PJ_TRUE;
+ else
+ member_tp_option |= PJMEDIA_TPMED_NO_TRANSPORT_CHECKING;
- /* Nothing to do on inactive media stream */
- if (pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL))
- goto BYPASS_SRTP;
+ status = pjmedia_transport_media_create(srtp->member_tp, sdp_pool,
+ member_tp_option, sdp_remote,
+ media_index);
+ if (status != PJ_SUCCESS || srtp->bypass_srtp)
+ return status;
- /* Validate remote media transport based on SRTP usage option.
- */
- switch (srtp->setting.use) {
- case PJMEDIA_SRTP_DISABLED:
- if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0)
- return PJMEDIA_SRTP_ESDPINTRANSPORT;
- goto BYPASS_SRTP;
- case PJMEDIA_SRTP_OPTIONAL:
- break;
- case PJMEDIA_SRTP_MANDATORY:
- if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0)
- return PJMEDIA_SRTP_ESDPINTRANSPORT;
- break;
+ /* Invoke media_create() of all keying methods */
+ for (i=0; i < srtp->keying_cnt; ) {
+ pj_status_t st;
+ st = pjmedia_transport_media_create(srtp->keying[i], sdp_pool,
+ options, sdp_remote,
+ media_index);
+ if (st != PJ_SUCCESS) {
+ /* This keying method returns error, remove it */
+ pj_array_erase(srtp->keying, sizeof(srtp->keying[0]),
+ srtp->keying_cnt, i);
+ srtp->keying_cnt--;
+ last_err_st = st;
+ continue;
+ } else if (srtp->offerer_side) {
+ /* Currently we can send one keying only in outgoing offer */
+ srtp->keying[0] = srtp->keying[i];
+ srtp->keying_cnt = 1;
+ break;
}
+ ++i;
}
- goto PROPAGATE_MEDIA_CREATE;
-BYPASS_SRTP:
- srtp->bypass_srtp = PJ_TRUE;
- member_tp_option &= ~PJMEDIA_TPMED_NO_TRANSPORT_CHECKING;
+ /* All keying method failed to process remote SDP? */
+ if (srtp->keying_cnt == 0)
+ return last_err_st;
-PROPAGATE_MEDIA_CREATE:
- return pjmedia_transport_media_create(srtp->member_tp, sdp_pool,
- member_tp_option, sdp_remote,
- media_index);
+ return PJ_SUCCESS;
}
static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
@@ -1360,259 +1413,63 @@ static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
unsigned media_index)
{
struct transport_srtp *srtp = (struct transport_srtp*) tp;
- pjmedia_sdp_media *m_rem, *m_loc;
- enum { MAXLEN = 512 };
- char buffer[MAXLEN];
- int buffer_len;
+ pj_status_t last_err_st = PJ_EBUG;
pj_status_t status;
- pjmedia_sdp_attr *attr;
- pj_str_t attr_value;
- unsigned i, j;
+ unsigned i;
PJ_ASSERT_RETURN(tp && sdp_pool && sdp_local, PJ_EINVAL);
pj_bzero(&srtp->rx_policy_neg, sizeof(srtp->rx_policy_neg));
pj_bzero(&srtp->tx_policy_neg, sizeof(srtp->tx_policy_neg));
- srtp->offerer_side = sdp_remote == NULL;
-
- m_rem = sdp_remote ? sdp_remote->media[media_index] : NULL;
- m_loc = sdp_local->media[media_index];
-
- /* Bypass if media transport is not RTP/AVP or RTP/SAVP */
- if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP) != 0 &&
- pj_stricmp(&m_loc->desc.transport, &ID_RTP_SAVP) != 0)
- goto BYPASS_SRTP;
-
- /* If the media is inactive, do nothing. */
- /* No, we still need to process SRTP offer/answer even if the media is
- * marked as inactive, because the transport is still alive in this
- * case (e.g. for keep-alive). See:
- * http://trac.pjsip.org/repos/ticket/1079
- */
- /*
- if (pjmedia_sdp_media_find_attr(m_loc, &ID_INACTIVE, NULL) ||
- (m_rem && pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL)))
- goto BYPASS_SRTP;
- */
-
- /* Check remote media transport & set local media transport
- * based on SRTP usage option.
- */
- if (srtp->offerer_side) {
-
- /* Generate transport */
- switch (srtp->setting.use) {
- case PJMEDIA_SRTP_DISABLED:
- goto BYPASS_SRTP;
- case PJMEDIA_SRTP_OPTIONAL:
- m_loc->desc.transport =
- (srtp->peer_use == PJMEDIA_SRTP_MANDATORY)?
- ID_RTP_SAVP : ID_RTP_AVP;
- break;
- case PJMEDIA_SRTP_MANDATORY:
- m_loc->desc.transport = ID_RTP_SAVP;
- break;
- }
+ srtp->offerer_side = (sdp_remote == NULL);
- /* Generate crypto attribute if not yet */
- if (pjmedia_sdp_media_find_attr(m_loc, &ID_CRYPTO, NULL) == NULL) {
- int tag = 1;
-
- /* Offer only current active crypto if any, otherwise offer all
- * crypto-suites in the setting.
- */
- for (i=0; i<srtp->setting.crypto_count; ++i) {
- if (srtp->tx_policy.name.slen &&
- pj_stricmp(&srtp->tx_policy.name,
- &srtp->setting.crypto[i].name) != 0)
- {
- continue;
- }
-
- buffer_len = MAXLEN;
- status = generate_crypto_attr_value(srtp->pool, buffer, &buffer_len,
- &srtp->setting.crypto[i],
- tag);
- if (status != PJ_SUCCESS)
- return status;
-
- /* If buffer_len==0, just skip the crypto attribute. */
- if (buffer_len) {
- pj_strset(&attr_value, buffer, buffer_len);
- attr = pjmedia_sdp_attr_create(srtp->pool, ID_CRYPTO.ptr,
- &attr_value);
- m_loc->attr[m_loc->attr_count++] = attr;
- ++tag;
- }
- }
- }
+ status = pjmedia_transport_encode_sdp(srtp->member_tp, sdp_pool,
+ sdp_local, sdp_remote, media_index);
+ if (status != PJ_SUCCESS || srtp->bypass_srtp)
+ return status;
- } else {
- /* Answerer side */
-
- pj_assert(sdp_remote && m_rem);
-
- /* Generate transport */
- switch (srtp->setting.use) {
- case PJMEDIA_SRTP_DISABLED:
- if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0)
- return PJMEDIA_SRTP_ESDPINTRANSPORT;
- goto BYPASS_SRTP;
- case PJMEDIA_SRTP_OPTIONAL:
- m_loc->desc.transport = m_rem->desc.transport;
- break;
- case PJMEDIA_SRTP_MANDATORY:
- if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0)
- return PJMEDIA_SRTP_ESDPINTRANSPORT;
- m_loc->desc.transport = ID_RTP_SAVP;
- break;
+ /* Invoke encode_sdp() of all keying methods */
+ for (i=0; i < srtp->keying_cnt; ) {
+ pj_status_t st;
+ st = pjmedia_transport_encode_sdp(srtp->keying[i], sdp_pool,
+ sdp_local, sdp_remote,
+ media_index);
+ if (st != PJ_SUCCESS) {
+ /* This keying method returns error, remove it */
+ pj_array_erase(srtp->keying, sizeof(srtp->keying[0]),
+ srtp->keying_cnt, i);
+ srtp->keying_cnt--;
+ last_err_st = st;
+ continue;
}
- /* Generate crypto attribute if not yet */
- if (pjmedia_sdp_media_find_attr(m_loc, &ID_CRYPTO, NULL) == NULL) {
-
- pjmedia_srtp_crypto tmp_rx_crypto;
- pj_bool_t has_crypto_attr = PJ_FALSE;
- int matched_idx = -1;
- int chosen_tag = 0;
- int tags[64]; /* assume no more than 64 crypto attrs in a media */
- unsigned cr_attr_count = 0;
-
- /* Find supported crypto-suite, get the tag, and assign policy_local */
- for (i=0; i<m_rem->attr_count; ++i) {
- if (pj_stricmp(&m_rem->attr[i]->name, &ID_CRYPTO) != 0)
- continue;
-
- has_crypto_attr = PJ_TRUE;
-
- status = parse_attr_crypto(srtp->pool, m_rem->attr[i],
- &tmp_rx_crypto, &tags[cr_attr_count]);
- if (status != PJ_SUCCESS)
- return status;
-
- /* Check duplicated tag */
- for (j=0; j<cr_attr_count; ++j) {
- if (tags[j] == tags[cr_attr_count]) {
- DEACTIVATE_MEDIA(sdp_pool, m_loc);
- return PJMEDIA_SRTP_ESDPDUPCRYPTOTAG;
- }
- }
-
- if (matched_idx == -1) {
- /* lets see if the crypto-suite offered is supported */
- for (j=0; j<srtp->setting.crypto_count; ++j)
- if (pj_stricmp(&tmp_rx_crypto.name,
- &srtp->setting.crypto[j].name) == 0)
- {
- int cs_idx = get_crypto_idx(&tmp_rx_crypto.name);
-
- if (cs_idx == -1)
- return PJMEDIA_SRTP_ENOTSUPCRYPTO;
-
- /* Force to use test key */
- /* bad keys for snom: */
- //char *hex_test_key = "58b29c5c8f42308120ce857e439f2d"
- // "7810a8b10ad0b1446be5470faea496";
- //char *hex_test_key = "20a26aac7ba062d356ff52b61e3993"
- // "ccb78078f12c64db94b9c294927fd0";
- //pj_str_t *test_key = &srtp->setting.crypto[j].key;
- //char *raw_test_key = pj_pool_zalloc(srtp->pool, 64);
- //hex_string_to_octet_string(
- // raw_test_key,
- // hex_test_key,
- // strlen(hex_test_key));
- //pj_strset(test_key, raw_test_key,
- // crypto_suites[cs_idx].cipher_key_len);
- /* EO Force to use test key */
-
- if (tmp_rx_crypto.key.slen !=
- (int)crypto_suites[cs_idx].cipher_key_len)
- return PJMEDIA_SRTP_EINKEYLEN;
-
- srtp->rx_policy_neg = tmp_rx_crypto;
- chosen_tag = tags[cr_attr_count];
- matched_idx = j;
- break;
- }
- }
- cr_attr_count++;
- }
-
- /* Check crypto negotiation result */
- switch (srtp->setting.use) {
- case PJMEDIA_SRTP_DISABLED:
- pj_assert(!"Should never reach here");
- break;
-
- case PJMEDIA_SRTP_OPTIONAL:
- /* bypass SRTP when no crypto-attr and remote uses RTP/AVP */
- if (!has_crypto_attr &&
- pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0)
- goto BYPASS_SRTP;
- /* bypass SRTP when nothing match and remote uses RTP/AVP */
- else if (matched_idx == -1 &&
- pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0)
- goto BYPASS_SRTP;
- break;
-
- case PJMEDIA_SRTP_MANDATORY:
- /* Do nothing, intentional */
- break;
- }
-
- /* No crypto attr */
- if (!has_crypto_attr) {
- DEACTIVATE_MEDIA(sdp_pool, m_loc);
- return PJMEDIA_SRTP_ESDPREQCRYPTO;
- }
-
- /* No crypto match */
- if (matched_idx == -1) {
- DEACTIVATE_MEDIA(sdp_pool, m_loc);
- return PJMEDIA_SRTP_ENOTSUPCRYPTO;
- }
-
- /* we have to generate crypto answer,
- * with srtp->tx_policy_neg matched the offer
- * and rem_tag contains matched offer tag.
- */
- buffer_len = MAXLEN;
- status = generate_crypto_attr_value(srtp->pool, buffer, &buffer_len,
- &srtp->setting.crypto[matched_idx],
- chosen_tag);
- if (status != PJ_SUCCESS)
- return status;
-
- srtp->tx_policy_neg = srtp->setting.crypto[matched_idx];
-
- /* If buffer_len==0, just skip the crypto attribute. */
- if (buffer_len) {
- pj_strset(&attr_value, buffer, buffer_len);
- attr = pjmedia_sdp_attr_create(sdp_pool, ID_CRYPTO.ptr,
- &attr_value);
- m_loc->attr[m_loc->attr_count++] = attr;
+ if (!srtp_crypto_empty(&srtp->tx_policy_neg) &&
+ !srtp_crypto_empty(&srtp->rx_policy_neg))
+ {
+ /* SRTP nego is done, let's destroy any other keying. */
+ unsigned j;
+ for (j = 0; j < srtp->keying_cnt; ++j) {
+ if (j != i)
+ pjmedia_transport_close(srtp->keying[j]);
}
-
- /* At this point, we get valid rx_policy_neg & tx_policy_neg. */
+ srtp->keying_cnt = 1;
+ srtp->keying[0] = srtp->keying[i];
+ srtp->keying_pending_cnt = 0;
+ break;
}
+ i++;
}
- goto PROPAGATE_MEDIA_CREATE;
-BYPASS_SRTP:
- /* Do not update this flag here as actually the media session hasn't been
- * updated.
- */
- //srtp->bypass_srtp = PJ_TRUE;
+ /* All keying method failed to process remote SDP? */
+ if (srtp->keying_cnt == 0)
+ return last_err_st;
-PROPAGATE_MEDIA_CREATE:
- return pjmedia_transport_encode_sdp(srtp->member_tp, sdp_pool,
- sdp_local, sdp_remote, media_index);
+ return PJ_SUCCESS;
}
-
static pj_status_t transport_media_start(pjmedia_transport *tp,
pj_pool_t *pool,
const pjmedia_sdp_session *sdp_local,
@@ -1620,165 +1477,91 @@ static pj_status_t transport_media_start(pjmedia_transport *tp,
unsigned media_index)
{
struct transport_srtp *srtp = (struct transport_srtp*) tp;
- pjmedia_sdp_media *m_rem, *m_loc;
+ pj_status_t last_err_st = PJ_EBUG;
pj_status_t status;
unsigned i;
PJ_ASSERT_RETURN(tp && pool && sdp_local && sdp_remote, PJ_EINVAL);
- m_rem = sdp_remote->media[media_index];
- m_loc = sdp_local->media[media_index];
-
- if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0)
- srtp->peer_use = PJMEDIA_SRTP_MANDATORY;
- else
- srtp->peer_use = PJMEDIA_SRTP_OPTIONAL;
-
- /* For answerer side, this function will just have to start SRTP */
-
- /* Check remote media transport & set local media transport
- * based on SRTP usage option.
- */
- if (srtp->offerer_side) {
- if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
- if (pjmedia_sdp_media_find_attr(m_rem, &ID_CRYPTO, NULL)) {
- DEACTIVATE_MEDIA(pool, m_loc);
- return PJMEDIA_SRTP_ESDPINCRYPTO;
- }
- goto BYPASS_SRTP;
- } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
- // Regardless the answer's transport type (RTP/AVP or RTP/SAVP),
- // the answer must be processed through in optional mode.
- // Please note that at this point transport type is ensured to be
- // RTP/AVP or RTP/SAVP, see transport_media_create()
- //if (pj_stricmp(&m_rem->desc.transport, &m_loc->desc.transport)) {
- //DEACTIVATE_MEDIA(pool, m_loc);
- //return PJMEDIA_SDP_EINPROTO;
- //}
- } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) {
- if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP)) {
- DEACTIVATE_MEDIA(pool, m_loc);
- return PJMEDIA_SDP_EINPROTO;
- }
- }
- }
-
- if (srtp->offerer_side) {
- /* find supported crypto-suite, get the tag, and assign policy_local */
- pjmedia_srtp_crypto tmp_tx_crypto;
- pj_bool_t has_crypto_attr = PJ_FALSE;
- int rem_tag;
-
- for (i=0; i<m_rem->attr_count; ++i) {
- if (pj_stricmp(&m_rem->attr[i]->name, &ID_CRYPTO) != 0)
- continue;
-
- /* more than one crypto attribute in media answer */
- if (has_crypto_attr) {
- DEACTIVATE_MEDIA(pool, m_loc);
- return PJMEDIA_SRTP_ESDPAMBIGUEANS;
- }
-
- has_crypto_attr = PJ_TRUE;
-
- status = parse_attr_crypto(srtp->pool, m_rem->attr[i],
- &tmp_tx_crypto, &rem_tag);
- if (status != PJ_SUCCESS)
- return status;
-
-
- /* our offer tag is always ordered by setting */
- if (rem_tag < 1 || rem_tag > (int)srtp->setting.crypto_count) {
- DEACTIVATE_MEDIA(pool, m_loc);
- return PJMEDIA_SRTP_ESDPINCRYPTOTAG;
- }
-
- /* match the crypto name */
- if (pj_stricmp(&tmp_tx_crypto.name,
- &srtp->setting.crypto[rem_tag-1].name) != 0)
- {
- DEACTIVATE_MEDIA(pool, m_loc);
- return PJMEDIA_SRTP_ECRYPTONOTMATCH;
- }
+ status = pjmedia_transport_media_start(srtp->member_tp, pool,
+ sdp_local, sdp_remote,
+ media_index);
+ if (status != PJ_SUCCESS || srtp->bypass_srtp)
+ return status;
- srtp->tx_policy_neg = srtp->setting.crypto[rem_tag-1];
- srtp->rx_policy_neg = tmp_tx_crypto;
+ /* Invoke media_start() of all keying methods */
+ for (i=0; i < srtp->keying_cnt; ) {
+ status = pjmedia_transport_media_start(srtp->keying[i], pool,
+ sdp_local, sdp_remote,
+ media_index);
+ if (status != PJ_SUCCESS) {
+ /* This keying method returns error, remove it */
+ pj_array_erase(srtp->keying, sizeof(srtp->keying[0]),
+ srtp->keying_cnt, i);
+ srtp->keying_cnt--;
+ last_err_st = status;
+ continue;
}
- if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
- /* should never reach here */
- goto BYPASS_SRTP;
- } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
- if (!has_crypto_attr)
- goto BYPASS_SRTP;
- } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) {
- if (!has_crypto_attr) {
- DEACTIVATE_MEDIA(pool, m_loc);
- return PJMEDIA_SRTP_ESDPREQCRYPTO;
+ if (!srtp_crypto_empty(&srtp->tx_policy_neg) &&
+ !srtp_crypto_empty(&srtp->rx_policy_neg))
+ {
+ /* SRTP nego is done, let's destroy any other keying. */
+ unsigned j;
+ for (j = 0; j < srtp->keying_cnt; ++j) {
+ if (j != i)
+ pjmedia_transport_close(srtp->keying[j]);
}
+ srtp->keying_cnt = 1;
+ srtp->keying[0] = srtp->keying[i];
+ srtp->keying_pending_cnt = 0;
+ break;
}
- /* At this point, we get valid rx_policy_neg & tx_policy_neg. */
+ i++;
}
- /* Make sure we have the SRTP policies */
- if (srtp_crypto_empty(&srtp->tx_policy_neg) ||
- srtp_crypto_empty(&srtp->rx_policy_neg))
- {
- goto BYPASS_SRTP;
- }
+ /* All keying method failed to process remote SDP? */
+ if (srtp->keying_cnt == 0)
+ return last_err_st;
- /* Reset probation counts */
- srtp->probation_cnt = PROBATION_CNT_INIT;
-
- /* Got policy_local & policy_remote, let's initalize the SRTP */
-
- /* Ticket #1075: media_start() is called whenever media description
- * gets updated, e.g: call hold, however we should restart SRTP only
- * when the SRTP policy settings are updated.
+ /* If SRTP key is being negotiated, just return now.
+ * The keying method should start the SRTP once keying nego is done.
*/
- if (srtp_crypto_cmp(&srtp->tx_policy_neg, &srtp->tx_policy) ||
- srtp_crypto_cmp(&srtp->rx_policy_neg, &srtp->rx_policy))
- {
- status = pjmedia_transport_srtp_start(tp,
- &srtp->tx_policy_neg,
- &srtp->rx_policy_neg);
- if (status != PJ_SUCCESS)
- return status;
- }
-
- srtp->bypass_srtp = PJ_FALSE;
+ if (srtp->keying_pending_cnt)
+ return PJ_SUCCESS;
- goto PROPAGATE_MEDIA_START;
+ /* Start SRTP */
+ status = start_srtp(srtp);
-BYPASS_SRTP:
- srtp->bypass_srtp = PJ_TRUE;
- srtp->peer_use = PJMEDIA_SRTP_DISABLED;
- if (srtp->session_inited) {
- pjmedia_transport_srtp_stop(tp);
- }
-
-PROPAGATE_MEDIA_START:
- return pjmedia_transport_media_start(srtp->member_tp, pool,
- sdp_local, sdp_remote,
- media_index);
+ return status;
}
+
static pj_status_t transport_media_stop(pjmedia_transport *tp)
{
struct transport_srtp *srtp = (struct transport_srtp*) tp;
pj_status_t status;
+ unsigned i;
PJ_ASSERT_RETURN(tp, PJ_EINVAL);
+ /* Invoke media_stop() of all keying methods */
+ for (i=0; i < srtp->keying_cnt; ++i) {
+ pjmedia_transport_media_stop(srtp->keying[i]);
+ }
+
+ /* Invoke media_stop() of member tp */
status = pjmedia_transport_media_stop(srtp->member_tp);
if (status != PJ_SUCCESS)
PJ_LOG(4, (srtp->pool->obj_name,
"SRTP failed stop underlying media transport."));
+ /* Finally, stop SRTP */
return pjmedia_transport_srtp_stop(tp);
}
+
/* Utility */
PJ_DEF(pj_status_t) pjmedia_transport_srtp_decrypt_pkt(pjmedia_transport *tp,
pj_bool_t is_rtp,
@@ -1786,7 +1569,7 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_decrypt_pkt(pjmedia_transport *tp,
int *pkt_len)
{
transport_srtp *srtp = (transport_srtp *)tp;
- err_status_t err;
+ srtp_err_status_t err;
if (srtp->bypass_srtp)
return PJ_SUCCESS;
@@ -1809,7 +1592,7 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_decrypt_pkt(pjmedia_transport *tp,
else
err = srtp_unprotect_rtcp(srtp->srtp_rx_ctx, pkt, pkt_len);
- if (err != err_status_ok) {
+ if (err != srtp_err_status_ok) {
PJ_LOG(5,(srtp->pool->obj_name,
"Failed to unprotect SRTP, pkt size=%d, err=%s",
*pkt_len, get_libsrtp_errstr(err)));
@@ -1817,7 +1600,8 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_decrypt_pkt(pjmedia_transport *tp,
pj_lock_release(srtp->mutex);
- return (err==err_status_ok) ? PJ_SUCCESS : PJMEDIA_ERRNO_FROM_LIBSRTP(err);
+ return (err==srtp_err_status_ok) ? PJ_SUCCESS :
+ PJMEDIA_ERRNO_FROM_LIBSRTP(err);
}
#endif
diff --git a/pjmedia/src/pjmedia/transport_srtp_dtls.c b/pjmedia/src/pjmedia/transport_srtp_dtls.c
new file mode 100644
index 0000000..aee5f3b
--- /dev/null
+++ b/pjmedia/src/pjmedia/transport_srtp_dtls.c
@@ -0,0 +1,1442 @@
+/* $Id: transport_srtp_dtls.c 5635 2017-08-01 07:49:34Z nanang $ */
+/*
+ * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <pjmedia/clock.h>
+#include <pjmedia/sdp.h>
+#include <pjmedia/transport_ice.h>
+#include <pj/errno.h>
+#include <pj/rand.h>
+#include <pj/ssl_sock.h>
+
+/*
+ * Include OpenSSL headers
+ */
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/ssl.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ defined(OPENSSL_API_COMPAT) && OPENSSL_API_COMPAT >= 0x10100000L
+# define X509_get_notBefore(x) X509_getm_notBefore(x)
+# define X509_get_notAfter(x) X509_getm_notAfter(x)
+#endif
+
+/* Set to 1 to enable DTLS-SRTP debugging */
+#define DTLS_DEBUG 0
+
+/* DTLS-SRTP transport op */
+static pj_status_t dtls_media_create (pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ unsigned options,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index);
+static pj_status_t dtls_encode_sdp (pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ pjmedia_sdp_session *sdp_local,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index);
+static pj_status_t dtls_media_start (pjmedia_transport *tp,
+ pj_pool_t *tmp_pool,
+ const pjmedia_sdp_session *sdp_local,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index);
+static pj_status_t dtls_media_stop (pjmedia_transport *tp);
+static pj_status_t dtls_destroy (pjmedia_transport *tp);
+static pj_status_t dtls_on_recv_rtp (pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size);
+
+static void on_ice_complete2(pjmedia_transport *tp,
+ pj_ice_strans_op op,
+ pj_status_t status,
+ void *user_data);
+
+
+static pjmedia_transport_op dtls_op =
+{
+ NULL,
+ NULL,
+ NULL,
+ &dtls_on_recv_rtp, // originally send_rtp()
+ NULL,
+ NULL,
+ &dtls_media_create,
+ &dtls_encode_sdp,
+ &dtls_media_start,
+ &dtls_media_stop,
+ NULL,
+ &dtls_destroy,
+ NULL,
+};
+
+
+typedef enum dtls_setup
+{
+ DTLS_SETUP_UNKNOWN,
+ DTLS_SETUP_ACTPASS,
+ DTLS_SETUP_ACTIVE,
+ DTLS_SETUP_PASSIVE
+} dtls_setup;
+
+
+typedef struct dtls_srtp
+{
+ pjmedia_transport base;
+ pj_pool_t *pool;
+ transport_srtp *srtp;
+
+ dtls_setup setup;
+ unsigned long last_err;
+ pj_bool_t use_ice;
+ pj_bool_t nego_started;
+ pj_str_t rem_fingerprint; /* Remote fingerprint in SDP */
+ pj_status_t rem_fprint_status; /* Fingerprint verif. status */
+ pj_sockaddr rem_addr; /* Remote address (from SDP/RTP)*/
+ pj_sockaddr rem_rtcp; /* Remote RTCP address (SDP) */
+ pj_bool_t pending_start; /* media_start() invoked but DTLS
+ nego not done yet, so start
+ the SRTP once the nego done */
+ pj_bool_t got_keys; /* DTLS nego done & keys ready */
+ pjmedia_srtp_crypto tx_crypto;
+ pjmedia_srtp_crypto rx_crypto;
+
+ char buf[PJMEDIA_MAX_MTU];
+ pjmedia_clock *clock; /* Timer workaround for retrans */
+
+ SSL_CTX *ossl_ctx;
+ SSL *ossl_ssl;
+ BIO *ossl_rbio;
+ BIO *ossl_wbio;
+} dtls_srtp;
+
+
+static const pj_str_t ID_TP_DTLS_SRTP = { "UDP/TLS/RTP/SAVP", 16 };
+static const pj_str_t ID_SETUP = { "setup", 5 };
+static const pj_str_t ID_ACTPASS = { "actpass", 7 };
+static const pj_str_t ID_ACTIVE = { "active", 6 };
+static const pj_str_t ID_PASSIVE = { "passive", 7 };
+static const pj_str_t ID_FINGERPRINT = { "fingerprint", 11 };
+
+
+/* Certificate & private key */
+static X509 *dtls_cert;
+static EVP_PKEY *dtls_priv_key;
+static pj_status_t ssl_generate_cert(X509 **p_cert, EVP_PKEY **p_priv_key);
+
+static pj_status_t dtls_init()
+{
+ /* Make sure OpenSSL library has been initialized */
+ {
+ pj_ssl_cipher ciphers[1];
+ unsigned cipher_num = 1;
+ pj_ssl_cipher_get_availables(ciphers, &cipher_num);
+ }
+
+ /* Generate cert if not yet */
+ if (!dtls_cert) {
+ pj_status_t status;
+ status = ssl_generate_cert(&dtls_cert, &dtls_priv_key);
+ if (status != PJ_SUCCESS) {
+ pj_perror(4, "DTLS-SRTP", status,
+ "Failed generating DTLS certificate");
+ return status;
+ }
+ }
+
+ return PJ_SUCCESS;
+}
+
+static void dtls_deinit()
+{
+ if (dtls_cert) {
+ X509_free(dtls_cert);
+ dtls_cert = NULL;
+
+ EVP_PKEY_free(dtls_priv_key);
+ dtls_priv_key = NULL;
+ }
+}
+
+
+/* Create DTLS-SRTP keying instance */
+static pj_status_t dtls_create(transport_srtp *srtp,
+ pjmedia_transport **p_keying)
+{
+ dtls_srtp *ds;
+ pj_pool_t *pool;
+
+ pool = pj_pool_create(srtp->pool->factory, "dtls%p",
+ 2000, 256, NULL);
+ ds = PJ_POOL_ZALLOC_T(pool, dtls_srtp);
+ ds->pool = pool;
+
+ pj_ansi_strncpy(ds->base.name, pool->obj_name, PJ_MAX_OBJ_NAME);
+ ds->base.type = PJMEDIA_TRANSPORT_TYPE_SRTP;
+ ds->base.op = &dtls_op;
+ ds->base.user_data = srtp;
+ ds->srtp = srtp;
+
+ *p_keying = &ds->base;
+ PJ_LOG(5,(srtp->pool->obj_name, "SRTP keying DTLS-SRTP created"));
+ return PJ_SUCCESS;
+}
+
+
+/**
+ * Mapping from OpenSSL error codes to pjlib error space.
+ */
+#define PJ_SSL_ERRNO_START (PJ_ERRNO_START_USER + \
+ PJ_ERRNO_SPACE_SIZE*6)
+
+#define PJ_SSL_ERRNO_SPACE_SIZE PJ_ERRNO_SPACE_SIZE
+
+/* Expected maximum value of reason component in OpenSSL error code */
+#define MAX_OSSL_ERR_REASON 1200
+
+static pj_status_t STATUS_FROM_SSL_ERR(dtls_srtp *ds,
+ unsigned long err)
+{
+ pj_status_t status;
+
+ /* General SSL error, dig more from OpenSSL error queue */
+ if (err == SSL_ERROR_SSL)
+ err = ERR_get_error();
+
+ /* OpenSSL error range is much wider than PJLIB errno space, so
+ * if it exceeds the space, only the error reason will be kept.
+ * Note that the last native error will be kept as is and can be
+ * retrieved via SSL socket info.
+ */
+ status = ERR_GET_LIB(err)*MAX_OSSL_ERR_REASON + ERR_GET_REASON(err);
+ if (status > PJ_SSL_ERRNO_SPACE_SIZE)
+ status = ERR_GET_REASON(err);
+
+ status += PJ_SSL_ERRNO_START;
+ ds->last_err = err;
+ return status;
+}
+
+
+static pj_status_t GET_SSL_STATUS(dtls_srtp *ds)
+{
+ return STATUS_FROM_SSL_ERR(ds, ERR_get_error());
+}
+
+
+/* SSL cert verification callback. */
+static int verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+ PJ_UNUSED_ARG(preverify_ok);
+ PJ_UNUSED_ARG(x509_ctx);
+ /* Just skip it for now (as usually it's a self-signed cert) */
+ return 1;
+}
+
+/* Get fingerprint from TLS cert, output is formatted for SDP a=fingerprint,
+ * e.g: "SHA-256 XX:XX:XX...". If is_sha256 is true, SHA-256 hash algo will
+ * be used, otherwise it is SHA-1.
+ */
+static pj_status_t ssl_get_fingerprint(X509 *cert, pj_bool_t is_sha256,
+ char *buf, pj_size_t *buf_len)
+{
+ unsigned int len, st_out_len, i;
+ unsigned char tmp[EVP_MAX_MD_SIZE];
+ char *p;
+
+ if (!X509_digest(cert, (is_sha256?EVP_sha256():EVP_sha1()), tmp, &len))
+ return PJ_EUNKNOWN;
+
+ st_out_len = len*3 + (is_sha256? 7 : 5);
+ if (*buf_len < st_out_len + 1)
+ return PJ_ETOOSMALL;
+
+ /* Format fingerprint to "SHA-256 XX:XX:XX..." */
+ p = buf;
+ p += pj_ansi_sprintf(p, "SHA-%s %.2X", (is_sha256?"256":"1"), tmp[0]);
+ for (i=1; i<len; ++i)
+ p += pj_ansi_sprintf(p, ":%.2X", tmp[i]);
+
+ *buf_len = st_out_len;
+
+ return PJ_SUCCESS;
+}
+
+/* Generate self-signed cert */
+static pj_status_t ssl_generate_cert(X509 **p_cert, EVP_PKEY **p_priv_key)
+{
+ BIGNUM *bne = NULL;
+ RSA *rsa_key = NULL;
+ X509_NAME *cert_name = NULL;
+ X509 *cert = NULL;
+ EVP_PKEY *priv_key = NULL;
+
+ /* Create big number */
+ bne = BN_new();
+ if (!bne) goto on_error;
+ if (!BN_set_word(bne, RSA_F4)) goto on_error;
+
+ /* Generate RSA key */
+ rsa_key = RSA_new();
+ if (!rsa_key) goto on_error;
+ if (!RSA_generate_key_ex(rsa_key, 2048, bne, NULL)) goto on_error;
+
+ /* Create private key */
+ priv_key = EVP_PKEY_new();
+ if (!priv_key) goto on_error;
+ if (!EVP_PKEY_assign_RSA(priv_key, rsa_key)) goto on_error;
+ rsa_key = NULL;
+
+ /* Create certificate */
+ cert = X509_new();
+ if (!cert) goto on_error;
+
+ /* Set version to 3 (2 = x509v3) */
+ X509_set_version(cert, 2);
+
+ /* Set serial number */
+ ASN1_INTEGER_set(X509_get_serialNumber(cert), pj_rand());
+
+ /* Set valid period */
+ X509_gmtime_adj(X509_get_notBefore(cert), -60*60*24);
+ X509_gmtime_adj(X509_get_notAfter(cert), 60*60*24*365);
+
+ /* Set subject name */
+ cert_name = X509_get_subject_name(cert);
+ if (!cert_name) goto on_error;
+ if (!X509_NAME_add_entry_by_txt(cert_name, "CN", MBSTRING_ASC,
+ (const unsigned char*)"pjmedia.pjsip.org",
+ -1, -1, 0)) goto on_error;
+
+ /* Set the issuer name (to subject name as this is self-signed cert) */
+ if (!X509_set_issuer_name(cert, cert_name)) goto on_error;
+
+ /* Set the public key */
+ if (!X509_set_pubkey(cert, priv_key)) goto on_error;
+
+ /* Sign with the private key */
+ if (!X509_sign(cert, priv_key, EVP_sha1())) goto on_error;
+
+ /* Free big number */
+ BN_free(bne);
+
+ *p_cert = cert;
+ *p_priv_key = priv_key;
+ return PJ_SUCCESS;
+
+on_error:
+ if (bne) BN_free(bne);
+ if (rsa_key && !priv_key) RSA_free(rsa_key);
+ if (priv_key) EVP_PKEY_free(priv_key);
+ if (cert) X509_free(cert);
+ return PJ_EUNKNOWN;
+}
+
+
+/* Map of OpenSSL-pjmedia SRTP cryptos. Currently OpenSSL seems to
+ * support few cryptos only (based on ssl/d1_srtp.c of OpenSSL 1.1.0c).
+ */
+static char* ossl_profiles[] =
+{
+ "SRTP_AES128_CM_SHA1_80",
+ "SRTP_AES128_CM_SHA1_32",
+ "SRTP_AEAD_AES_256_GCM"
+ "SRTP_AEAD_AES_128_GCM",
+};
+static char* pj_profiles[] =
+{
+ "AES_CM_128_HMAC_SHA1_80",
+ "AES_CM_128_HMAC_SHA1_32",
+ "AEAD_AES_256_GCM"
+ "AEAD_AES_128_GCM",
+};
+
+
+/* Create and initialize new SSL context and instance */
+static pj_status_t ssl_create(dtls_srtp *ds)
+{
+ SSL_CTX *ctx;
+ unsigned i;
+ int mode, rc;
+
+ /* Create DTLS context */
+ ctx = SSL_CTX_new(DTLS_method());
+ if (ctx == NULL) {
+ return GET_SSL_STATUS(ds);
+ }
+
+ /* Set crypto */
+ if (1) {
+ char *p, *end, buf[PJ_ARRAY_SIZE(ossl_profiles)*25];
+ unsigned n;
+
+ p = buf;
+ end = buf + sizeof(buf);
+ for (i=0; i<ds->srtp->setting.crypto_count && p < end; ++i) {
+ pjmedia_srtp_crypto *crypto = &ds->srtp->setting.crypto[i];
+ unsigned j;
+ for (j=0; j<PJ_ARRAY_SIZE(pj_profiles); ++j) {
+ if (!pj_ansi_strcmp(crypto->name.ptr, pj_profiles[j])) {
+ n = pj_ansi_snprintf(p, end-p, ":%s", ossl_profiles[j]);
+ p += n;
+ break;
+ }
+ }
+
+ }
+ rc = SSL_CTX_set_tlsext_use_srtp(ctx, buf+1);
+ pj_assert(rc == 0);
+ }
+
+ /* Set ciphers */
+ SSL_CTX_set_cipher_list(ctx, PJMEDIA_SRTP_DTLS_OSSL_CIPHERS);
+
+ /* Set cert & private key */
+ rc = SSL_CTX_use_certificate(ctx, dtls_cert);
+ pj_assert(rc);
+ rc = SSL_CTX_use_PrivateKey(ctx, dtls_priv_key);
+ pj_assert(rc);
+ rc = SSL_CTX_check_private_key(ctx);
+ pj_assert(rc);
+
+ /* Create SSL instance */
+ ds->ossl_ctx = ctx;
+ ds->ossl_ssl = SSL_new(ds->ossl_ctx);
+ if (ds->ossl_ssl == NULL) {
+ SSL_CTX_free(ctx);
+ return GET_SSL_STATUS(ds);
+ }
+
+ /* Set MTU */
+#ifdef DTLS_CTRL_SET_LINK_MTU
+ if (!SSL_ctrl(ds->ossl_ssl, DTLS_CTRL_SET_LINK_MTU, PJMEDIA_MAX_MTU,
+ NULL))
+ {
+ PJ_LOG(4, (ds->base.name,
+ "Ignored failure in setting MTU to %d (too small?)",
+ PJMEDIA_MAX_MTU));
+ }
+#endif
+
+ /* SSL verification options, must be mutual auth */
+ mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ SSL_set_verify(ds->ossl_ssl, mode, &verify_cb);
+
+ /* Setup SSL BIOs */
+ ds->ossl_rbio = BIO_new(BIO_s_mem());
+ ds->ossl_wbio = BIO_new(BIO_s_mem());
+ (void)BIO_set_close(ds->ossl_rbio, BIO_CLOSE);
+ (void)BIO_set_close(ds->ossl_wbio, BIO_CLOSE);
+ SSL_set_bio(ds->ossl_ssl, ds->ossl_rbio, ds->ossl_wbio);
+
+ return PJ_SUCCESS;
+}
+
+
+/* Destroy SSL context and instance */
+static void ssl_destroy(dtls_srtp *ds)
+{
+ /* Destroy SSL instance */
+ if (ds->ossl_ssl) {
+ SSL_shutdown(ds->ossl_ssl);
+ SSL_free(ds->ossl_ssl); /* this will also close BIOs */
+ ds->ossl_ssl = NULL;
+ }
+
+ /* Destroy SSL context */
+ if (ds->ossl_ctx) {
+ SSL_CTX_free(ds->ossl_ctx);
+ ds->ossl_ctx = NULL;
+ }
+}
+
+static pj_status_t ssl_get_srtp_material(dtls_srtp *ds)
+{
+ unsigned char material[SRTP_MAX_KEY_LEN];
+ SRTP_PROTECTION_PROFILE *profile;
+ int rc, i, crypto_idx = -1;
+ pjmedia_srtp_crypto *tx, *rx;
+ pj_status_t status = PJ_SUCCESS;
+
+ /* Get selected crypto-suite */
+ profile = SSL_get_selected_srtp_profile(ds->ossl_ssl);
+ if (!profile) {
+ status = PJMEDIA_SRTP_DTLS_ENOCRYPTO;
+ goto on_return;
+ }
+
+ tx = &ds->tx_crypto;
+ rx = &ds->rx_crypto;
+ pj_bzero(tx, sizeof(*tx));
+ pj_bzero(rx, sizeof(*rx));
+ for (i=0; i<PJ_ARRAY_SIZE(ossl_profiles); ++i) {
+ if (pj_ansi_stricmp(profile->name, ossl_profiles[i])==0) {
+ pj_strset2(&tx->name, pj_profiles[i]);
+ pj_strset2(&rx->name, pj_profiles[i]);
+ crypto_idx = get_crypto_idx(&tx->name);
+ break;
+ }
+ }
+ if (crypto_idx == -1) {
+ status = PJMEDIA_SRTP_ENOTSUPCRYPTO;
+ goto on_return;
+ }
+
+ /* Get keying material from DTLS nego. There seems to be no info about
+ * material length returned by SSL_export_keying_material()?
+ */
+ rc = SSL_export_keying_material(ds->ossl_ssl, material, sizeof(material),
+ "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0);
+ if (rc == 0) {
+ status = PJMEDIA_SRTP_EINKEYLEN;
+ goto on_return;
+ }
+
+ /* Parse SRTP master key & salt from keying material */
+ {
+ char *p = (char*)material;
+ char *k1, *k2;
+ crypto_suite *cs = &crypto_suites[crypto_idx];
+ unsigned key_len, salt_len;
+
+ key_len = cs->cipher_key_len - cs->cipher_salt_len;
+ salt_len = cs->cipher_salt_len;
+
+ tx->key.ptr = (char*)pj_pool_alloc(ds->pool, key_len+salt_len);
+ tx->key.slen = key_len+salt_len;
+ rx->key.ptr = (char*)pj_pool_alloc(ds->pool, key_len+salt_len);
+ rx->key.slen = key_len+salt_len;
+ if (ds->setup == DTLS_SETUP_ACTIVE) {
+ k1 = tx->key.ptr;
+ k2 = rx->key.ptr;
+ } else {
+ k1 = rx->key.ptr;
+ k2 = tx->key.ptr;
+ }
+ pj_memcpy(k1, p, key_len); p += key_len;
+ pj_memcpy(k2, p, key_len); p += key_len;
+ pj_memcpy(k1+key_len, p, salt_len); p += salt_len;
+ pj_memcpy(k2+key_len, p, salt_len);
+ ds->got_keys = PJ_TRUE;
+ }
+
+on_return:
+ return status;
+}
+
+/* Match remote fingerprint: SDP vs actual */
+static pj_status_t ssl_match_fingerprint(dtls_srtp *ds)
+{
+ X509 *rem_cert;
+ pj_bool_t is_sha256;
+ char buf[128];
+ pj_size_t buf_len = sizeof(buf);
+ pj_status_t status;
+
+ /* Check hash algo, currently we only support SHA-256 & SHA-1 */
+ if (!pj_strncmp2(&ds->rem_fingerprint, "SHA-256 ", 8))
+ is_sha256 = PJ_TRUE;
+ else if (!pj_strncmp2(&ds->rem_fingerprint, "SHA-1 ", 6))
+ is_sha256 = PJ_FALSE;
+ else {
+ PJ_LOG(4,(ds->base.name, "Hash algo specified in remote SDP for "
+ "its DTLS certificate fingerprint is not supported"));
+ return PJ_ENOTSUP;
+ }
+
+ /* Get remote cert & calculate the hash */
+ rem_cert = SSL_get_peer_certificate(ds->ossl_ssl);
+ if (!rem_cert)
+ return PJMEDIA_SRTP_DTLS_EPEERNOCERT;
+
+ status = ssl_get_fingerprint(rem_cert, is_sha256, buf, &buf_len);
+ X509_free(rem_cert);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Do they match? */
+ if (pj_stricmp2(&ds->rem_fingerprint, buf))
+ return PJMEDIA_SRTP_DTLS_EFPNOTMATCH;
+
+ return PJ_SUCCESS;
+}
+
+
+/* Send data to network */
+static pj_status_t send_raw(dtls_srtp *ds, const void *buf, pj_size_t len)
+{
+#if DTLS_DEBUG
+ PJ_LOG(2,(ds->base.name, "DTLS-SRTP sending %d bytes", len));
+#endif
+
+ return pjmedia_transport_send_rtp(ds->srtp->member_tp, buf, len);
+}
+
+
+/* Flush write BIO */
+static pj_status_t ssl_flush_wbio(dtls_srtp *ds)
+{
+ pj_size_t len;
+ pj_status_t status = PJ_SUCCESS;
+
+ /* Check whether there is data to send */
+ if (BIO_ctrl_pending(ds->ossl_wbio) > 0) {
+ /* Yes, get and send it */
+ len = BIO_read(ds->ossl_wbio, ds->buf, sizeof(ds->buf));
+ if (len > 0) {
+ status = send_raw(ds, ds->buf, len);
+ if (status != PJ_SUCCESS) {
+#if DTLS_DEBUG
+ pj_perror(2, ds->base.name, status, "Send error");
+#endif
+ /* This error should be recoverable, remote will retransmit
+ * its packet when not receiving from us.
+ */
+ }
+ }
+ }
+
+ /* Check if handshake has been completed */
+ if (!SSL_is_init_finished(ds->ossl_ssl))
+ return PJ_SUCCESS;
+
+ /* Yes, SSL handshake is done! */
+ PJ_LOG(2,(ds->base.name, "DTLS-SRTP negotiation completed!"));
+
+ /* Stop the retrans clock */
+ if (ds->clock)
+ pjmedia_clock_stop(ds->clock);
+
+ /* Get SRTP key material */
+ status = ssl_get_srtp_material(ds);
+ if (status != PJ_SUCCESS) {
+ pj_perror(4, ds->base.name, status,
+ "Failed to get SRTP material");
+ goto on_return;
+ }
+
+ /* Verify remote fingerprint if we've already got one from SDP */
+ if (ds->rem_fingerprint.slen && ds->rem_fprint_status == PJ_EPENDING) {
+ ds->rem_fprint_status = status = ssl_match_fingerprint(ds);
+ if (status != PJ_SUCCESS) {
+ pj_perror(4, ds->base.name, status,
+ "Fingerprint specified in remote SDP doesn't match "
+ "to actual remote certificate fingerprint!");
+ goto on_return;
+ }
+ }
+
+ /* If media_start() has been called, start SRTP now */
+ if (ds->pending_start) {
+ ds->pending_start = PJ_FALSE;
+ ds->srtp->keying_pending_cnt--;
+
+ /* Copy negotiated policy to SRTP */
+ ds->srtp->tx_policy_neg = ds->tx_crypto;
+ ds->srtp->rx_policy_neg = ds->rx_crypto;
+
+ status = start_srtp(ds->srtp);
+ if (status != PJ_SUCCESS)
+ pj_perror(4, ds->base.name, status, "Failed starting SRTP");
+ }
+
+on_return:
+ if (ds->srtp->setting.cb.on_srtp_nego_complete) {
+ (*ds->srtp->setting.cb.on_srtp_nego_complete)
+ (&ds->srtp->base, status);
+ }
+
+ return status;
+}
+
+
+static void clock_cb(const pj_timestamp *ts, void *user_data)
+{
+ dtls_srtp *ds = (dtls_srtp*)user_data;
+
+ PJ_UNUSED_ARG(ts);
+
+ if (ds->ossl_ssl) {
+ if (DTLSv1_handle_timeout(ds->ossl_ssl) > 0)
+ ssl_flush_wbio(ds);
+ }
+}
+
+
+/* Asynchronous handshake */
+static pj_status_t ssl_handshake(dtls_srtp *ds)
+{
+ pj_status_t status;
+ int err;
+
+ /* Check if handshake has been initiated or even completed */
+ if (ds->nego_started || SSL_is_init_finished(ds->ossl_ssl))
+ return PJ_SUCCESS;
+
+ /* Perform SSL handshake */
+ if (ds->setup == DTLS_SETUP_ACTIVE) {
+ SSL_set_connect_state(ds->ossl_ssl);
+ } else {
+ SSL_set_accept_state(ds->ossl_ssl);
+ }
+ err = SSL_do_handshake(ds->ossl_ssl);
+ if (err < 0) {
+ err = SSL_get_error(ds->ossl_ssl, err);
+ if (err == SSL_ERROR_WANT_READ) {
+ status = ssl_flush_wbio(ds);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+ } else if (err != SSL_ERROR_NONE) {
+ /* Handshake fails */
+ status = STATUS_FROM_SSL_ERR(ds, err);
+ pj_perror(2, ds->base.name, status, "SSL_do_handshake() error");
+ goto on_return;
+ }
+ }
+
+ /* Create and start clock @4Hz for retransmission */
+ if (!ds->clock) {
+ status = pjmedia_clock_create(ds->pool, 4, 1, 1,
+ PJMEDIA_CLOCK_NO_HIGHEST_PRIO, clock_cb,
+ ds, &ds->clock);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+ }
+ status = pjmedia_clock_start(ds->clock);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ /* Finally, DTLS nego started! */
+ ds->nego_started = PJ_TRUE;
+ PJ_LOG(4,(ds->base.name, "DTLS-SRTP negotiation initiated as %s",
+ (ds->setup==DTLS_SETUP_ACTIVE? "client":"server")));
+
+on_return:
+ if (status != PJ_SUCCESS) {
+ if (ds->clock)
+ pjmedia_clock_stop(ds->clock);
+ }
+ return status;
+}
+
+
+/* Parse a=setup & a=fingerprint in remote SDP to update DTLS-SRTP states
+ * 'setup' and 'rem_fingerprint'.
+ * TODO: check those attributes in a=acap too?
+ */
+static pj_status_t parse_setup_finger_attr(dtls_srtp *ds,
+ pj_bool_t rem_as_offerer,
+ const pjmedia_sdp_session *sdp,
+ unsigned media_index)
+{
+ pjmedia_sdp_media *m;
+ pjmedia_sdp_attr *a;
+
+ m = sdp->media[media_index];
+
+ /* Parse a=setup */
+ a = pjmedia_sdp_media_find_attr(m, &ID_SETUP, NULL);
+ if (!a)
+ a = pjmedia_sdp_attr_find(sdp->attr_count,
+ sdp->attr, &ID_SETUP, NULL);
+ if (!a)
+ return PJMEDIA_SRTP_ESDPAMBIGUEANS;
+
+ if (pj_stristr(&a->value, &ID_PASSIVE) ||
+ (rem_as_offerer && pj_stristr(&a->value, &ID_ACTPASS)))
+ {
+ /* Remote offers/answers 'passive' (or offers 'actpass'), so we are
+ * the client.
+ */
+ ds->setup = DTLS_SETUP_ACTIVE;
+ } else if (pj_stristr(&a->value, &ID_ACTIVE)) {
+ /* Remote offers/answers 'active' so we are the server. */
+ ds->setup = DTLS_SETUP_PASSIVE;
+ } else {
+ /* Unknown value set in remote a=setup */
+ return PJMEDIA_SRTP_ESDPAMBIGUEANS;
+ }
+
+ /* Parse a=fingerprint */
+ a = pjmedia_sdp_media_find_attr(m, &ID_FINGERPRINT, NULL);
+ if (!a)
+ a = pjmedia_sdp_attr_find(sdp->attr_count,
+ sdp->attr, &ID_FINGERPRINT,
+ NULL);
+ if (!a) {
+ /* Let's just print warning for now, instead of returning error */
+ PJ_LOG(4,(ds->base.name, "Warning: no fingerprint attribute in "
+ "remote SDP, DTLS verification cannot "
+ "be done!"));
+ } else {
+ pj_str_t rem_fp = a->value;
+ pj_strtrim(&rem_fp);
+ if (pj_stricmp(&ds->rem_fingerprint, &rem_fp))
+ pj_strdup(ds->pool, &ds->rem_fingerprint, &rem_fp);
+ }
+
+ return PJ_SUCCESS;
+}
+
+
+static pj_status_t get_rem_addrs(dtls_srtp *ds,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index)
+{
+ pjmedia_sdp_media *m_rem = sdp_remote->media[media_index];
+ pjmedia_sdp_conn *conn;
+ pjmedia_sdp_attr *a;
+ int af = pj_AF_UNSPEC();
+
+ /* Get RTP address */
+ conn = m_rem->conn ? m_rem->conn : sdp_remote->conn;
+ if (pj_stricmp2(&conn->net_type, "IN")==0) {
+ if (pj_stricmp2(&conn->addr_type, "IP4")==0) {
+ af = pj_AF_INET();
+ } else if (pj_stricmp2(&conn->addr_type, "IP6")==0) {
+ af = pj_AF_INET6();
+ }
+ }
+ if (af != pj_AF_UNSPEC()) {
+ pj_sockaddr_init(af, &ds->rem_addr, &conn->addr,
+ m_rem->desc.port);
+ } else {
+ return PJ_EAFNOTSUP;
+ }
+
+ /* Get RTCP address. If "rtcp" attribute is present in the SDP,
+ * set the RTCP address from that attribute. Otherwise, calculate
+ * from RTP address.
+ */
+ a = pjmedia_sdp_attr_find2(m_rem->attr_count, m_rem->attr,
+ "rtcp", NULL);
+ if (a) {
+ pjmedia_sdp_rtcp_attr rtcp;
+ pj_status_t status;
+ status = pjmedia_sdp_attr_get_rtcp(a, &rtcp);
+ if (status == PJ_SUCCESS) {
+ if (rtcp.addr.slen) {
+ pj_sockaddr_init(af, &ds->rem_rtcp, &rtcp.addr,
+ (pj_uint16_t)rtcp.port);
+ } else {
+ pj_sockaddr_init(af, &ds->rem_rtcp, NULL,
+ (pj_uint16_t)rtcp.port);
+ pj_memcpy(pj_sockaddr_get_addr(&ds->rem_rtcp),
+ pj_sockaddr_get_addr(&ds->rem_addr),
+ pj_sockaddr_get_addr_len(&ds->rem_addr));
+ }
+ }
+ }
+ if (!pj_sockaddr_has_addr(&ds->rem_rtcp)) {
+ int rtcp_port;
+ pj_memcpy(&ds->rem_rtcp, &ds->rem_addr, sizeof(pj_sockaddr));
+ rtcp_port = pj_sockaddr_get_port(&ds->rem_addr) + 1;
+ pj_sockaddr_set_port(&ds->rem_rtcp, (pj_uint16_t)rtcp_port);
+ }
+
+ return PJ_SUCCESS;
+}
+
+/* Check if an incoming packet is a DTLS packet (rfc5764 section 5.1.2) */
+#define IS_DTLS_PKT(pkt, pkt_len) (*(char*)pkt > 19 && *(char*)pkt < 64)
+
+
+/* Received packet (SSL handshake) from socket */
+static pj_status_t ssl_on_recv_packet(dtls_srtp *ds,
+ const void *data, pj_size_t len)
+{
+ char tmp[128];
+ pj_size_t nwritten;
+
+ nwritten = BIO_write(ds->ossl_rbio, data, (int)len);
+ if (nwritten < len) {
+ /* Error? */
+ pj_status_t status;
+ status = GET_SSL_STATUS(ds);
+#if DTLS_DEBUG
+ pj_perror(2, ds->base.name, status, "BIO_write() error");
+#endif
+ return status;
+ }
+
+ /* Consume (and ignore) the packet */
+ while (1) {
+ int rc = SSL_read(ds->ossl_ssl, tmp, sizeof(tmp));
+ if (rc <= 0) {
+#if DTLS_DEBUG
+ pj_status_t status = GET_SSL_STATUS(ds);
+ if (status != PJ_SUCCESS)
+ pj_perror(2, ds->base.name, status, "SSL_read() error");
+#endif
+ break;
+ }
+ }
+
+ /* Flush anything pending in the write BIO */
+ return ssl_flush_wbio(ds);
+}
+
+
+static void on_ice_complete2(pjmedia_transport *tp,
+ pj_ice_strans_op op,
+ pj_status_t status,
+ void *user_data)
+{
+ dtls_srtp *ds = (dtls_srtp*)user_data;
+ pj_assert(ds);
+
+ PJ_UNUSED_ARG(tp);
+
+ if (op == PJ_ICE_STRANS_OP_NEGOTIATION && status == PJ_SUCCESS &&
+ ds->setup == DTLS_SETUP_ACTIVE)
+ {
+ pj_status_t tmp_st;
+ tmp_st = ssl_handshake(ds);
+ if (tmp_st != PJ_SUCCESS)
+ pj_perror(4, ds->base.name, tmp_st, "Failed starting DTLS nego");
+ }
+}
+
+
+/* *************************************
+ *
+ * DTLS-SRTP transport keying operations
+ *
+ * *************************************/
+
+/*
+ * This callback is called by SRTP transport when incoming rtp is received.
+ * Originally this is send_rtp() op.
+ */
+static pj_status_t dtls_on_recv_rtp( pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size)
+{
+ dtls_srtp *ds = (dtls_srtp*)tp;
+
+ if (size < 1 || !IS_DTLS_PKT(pkt, size))
+ return PJ_EIGNORED;
+
+#if DTLS_DEBUG
+ PJ_LOG(2,(ds->base.name, "DTLS-SRTP receiving %d bytes", size));
+#endif
+
+ /* This is DTLS packet, let's process it */
+
+ /* Check remote address info, reattach member tp if changed */
+ if (!ds->use_ice) {
+ pjmedia_transport_info info;
+ pjmedia_transport_get_info(ds->srtp->member_tp, &info);
+ if (pj_sockaddr_cmp(&ds->rem_addr, &info.src_rtp_name)) {
+ pjmedia_transport_attach_param ap;
+
+ pj_bzero(&ap, sizeof(ap));
+ pj_sockaddr_cp(&ds->rem_addr, &info.src_rtp_name);
+ pj_sockaddr_cp(&ap.rem_addr, &ds->rem_addr);
+ ap.addr_len = pj_sockaddr_get_len(&ap.rem_addr);
+ if (pj_sockaddr_has_addr(&ds->rem_rtcp)) {
+ pj_sockaddr_cp(&ap.rem_rtcp, &ds->rem_rtcp);
+ } else {
+ pj_sockaddr_cp(&ap.rem_rtcp, &ds->rem_addr);
+ pj_sockaddr_set_port(&ap.rem_rtcp,
+ pj_sockaddr_get_port(&ds->rem_addr)+1);
+ }
+
+ pjmedia_transport_attach2(&ds->srtp->base, &ap);
+ }
+ }
+
+ /* If our setup is ACTPASS, incoming packet may be a client hello,
+ * so let's update setup to PASSIVE and initiate DTLS handshake.
+ */
+ if (ds->setup == DTLS_SETUP_ACTPASS || ds->setup == DTLS_SETUP_PASSIVE)
+ {
+ pj_status_t status;
+ ds->setup = DTLS_SETUP_PASSIVE;
+ status = ssl_handshake(ds);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ /* Send it to OpenSSL */
+ ssl_on_recv_packet(ds, pkt, size);
+ return PJ_SUCCESS;
+}
+
+static pj_status_t dtls_media_create( pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ unsigned options,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index)
+{
+ dtls_srtp *ds = (dtls_srtp*) tp;
+ pj_status_t status = PJ_SUCCESS;
+
+#if DTLS_DEBUG
+ PJ_LOG(2,(ds->base.name, "dtls_media_create()"));
+#endif
+
+ PJ_UNUSED_ARG(sdp_pool);
+ PJ_UNUSED_ARG(options);
+
+ if (ds->srtp->offerer_side) {
+ /* As offerer: do nothing. */
+ } else {
+ /* As answerer:
+ * Check for DTLS-SRTP support in remote SDP. Detect remote
+ * support of DTLS-SRTP by inspecting remote SDP offer for
+ * UDP/TLS/RTP/SAVP as media transport, this may be presented
+ * in m= line.
+ */
+ pjmedia_sdp_media *m_rem = sdp_remote->media[media_index];
+
+ if (pj_stricmp(&m_rem->desc.transport, &ID_TP_DTLS_SRTP)!=0) {
+ /* Remote doesn't signal DTLS-SRTP */
+ status = PJMEDIA_SRTP_ESDPINTRANSPORT;
+ goto on_return;
+ }
+ }
+
+ /* Init DTLS */
+ if (!ds->ossl_ssl) {
+ status = ssl_create(ds);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+ }
+
+ /* Set remote cert fingerprint verification status to PJ_EPENDING */
+ ds->rem_fprint_status = PJ_EPENDING;
+
+on_return:
+ if (status != PJ_SUCCESS) {
+ pj_perror(4, ds->base.name, status, "dtls_media_create() failed");
+ dtls_destroy(tp);
+ }
+ return status;
+}
+
+static pj_status_t dtls_encode_sdp( pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ pjmedia_sdp_session *sdp_local,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index)
+{
+ dtls_srtp *ds = (dtls_srtp *)tp;
+ pjmedia_sdp_media *m_loc;
+ pjmedia_sdp_attr *a;
+ pj_bool_t use_ice = PJ_FALSE;
+ pj_status_t status = PJ_SUCCESS;
+
+#if DTLS_DEBUG
+ PJ_LOG(2,(ds->base.name, "dtls_encode_sdp()"));
+#endif
+
+ PJ_UNUSED_ARG(sdp_pool);
+
+ m_loc = sdp_local->media[media_index];
+ if (ds->srtp->offerer_side) {
+ /* As offerer */
+
+ /* Add attribute a=setup if none (rfc5763 section 5) */
+ a = pjmedia_sdp_media_find_attr(m_loc, &ID_SETUP, NULL);
+ if (!a)
+ a = pjmedia_sdp_attr_find(sdp_local->attr_count,
+ sdp_local->attr, &ID_SETUP, NULL);
+ if (!a) {
+ pj_str_t val;
+
+ if (ds->setup == DTLS_SETUP_UNKNOWN)
+ ds->setup = DTLS_SETUP_ACTPASS;
+
+ if (ds->setup == DTLS_SETUP_ACTIVE)
+ val = ID_ACTIVE;
+ else if (ds->setup == DTLS_SETUP_PASSIVE)
+ val = ID_PASSIVE;
+ else
+ val = ID_ACTPASS;
+ a = pjmedia_sdp_attr_create(ds->pool, ID_SETUP.ptr, &val);
+ pjmedia_sdp_media_add_attr(m_loc, a);
+ }
+ } else {
+ /* As answerer */
+ dtls_setup last_setup = ds->setup;
+ pj_str_t last_rem_fp = ds->rem_fingerprint;
+
+ /* Parse a=setup and a=fingerprint */
+ status = parse_setup_finger_attr(ds, PJ_TRUE, sdp_remote,
+ media_index);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ /* Add attribute a=setup:active/passive if we are client/server. */
+ a = pjmedia_sdp_attr_create(ds->pool, ID_SETUP.ptr,
+ (ds->setup==DTLS_SETUP_ACTIVE? &ID_ACTIVE:&ID_PASSIVE));
+ pjmedia_sdp_media_add_attr(m_loc, a);
+
+ /* Check if remote signals DTLS re-nego by changing its
+ * setup/fingerprint in SDP.
+ */
+ if ((last_setup != DTLS_SETUP_UNKNOWN && last_setup != ds->setup) ||
+ (last_rem_fp.slen &&
+ pj_memcmp(&last_rem_fp, &ds->rem_fingerprint, sizeof(pj_str_t))))
+ {
+ ssl_destroy(ds);
+ ds->nego_started = PJ_FALSE;
+ ds->got_keys = PJ_FALSE;
+
+ status = ssl_create(ds);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+ }
+ }
+
+ /* Set media transport to UDP/TLS/RTP/SAVP */
+ m_loc->desc.transport = ID_TP_DTLS_SRTP;
+
+ /* Add a=fingerprint attribute, fingerprint of our TLS certificate */
+ {
+ char buf[128];
+ pj_size_t buf_len = sizeof(buf);
+ pj_str_t fp;
+
+ status = ssl_get_fingerprint(dtls_cert, PJ_TRUE, buf, &buf_len);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ pj_strset(&fp, buf, buf_len);
+ a = pjmedia_sdp_attr_create(ds->pool, ID_FINGERPRINT.ptr, &fp);
+ pjmedia_sdp_media_add_attr(m_loc, a);
+ }
+
+ if (ds->got_keys) {
+ /* This is subsequent SDP offer/answer and we already got SRTP keys */
+ goto on_return;
+ }
+
+ /* Attach member transport, so we can receive DTLS init (if our setup
+ * is PASSIVE/ACTPASS) or send DTLS init (if our setup is ACTIVE).
+ */
+ {
+ pjmedia_transport_attach_param ap;
+ pj_bzero(&ap, sizeof(ap));
+
+ if (sdp_remote)
+ get_rem_addrs(ds, sdp_remote, media_index);
+
+ if (pj_sockaddr_has_addr(&ds->rem_addr))
+ pj_sockaddr_cp(&ap.rem_addr, &ds->rem_addr);
+ else
+ pj_sockaddr_init(pj_AF_INET(), &ap.rem_addr, 0, 0);
+
+ if (pj_sockaddr_has_addr(&ds->rem_rtcp))
+ pj_sockaddr_cp(&ap.rem_rtcp, &ds->rem_rtcp);
+ else
+ pj_sockaddr_init(pj_AF_INET(), &ap.rem_rtcp, 0, 0);
+
+ ap.addr_len = pj_sockaddr_get_len(&ap.rem_addr);
+ status = pjmedia_transport_attach2(&ds->srtp->base, &ap);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+ }
+
+ /* If our setup is ACTIVE and member transport is not ICE,
+ * start DTLS nego.
+ */
+ if (ds->setup == DTLS_SETUP_ACTIVE) {
+ pjmedia_transport_info info;
+ pjmedia_ice_transport_info *ice_info;
+
+ pjmedia_transport_info_init(&info);
+ pjmedia_transport_get_info(ds->srtp->member_tp, &info);
+ ice_info = (pjmedia_ice_transport_info*)
+ pjmedia_transport_info_get_spc_info(
+ &info, PJMEDIA_TRANSPORT_TYPE_ICE);
+ use_ice = ice_info && ice_info->comp_cnt;
+ if (!use_ice) {
+ status = ssl_handshake(ds);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+ }
+ }
+
+on_return:
+ if (status != PJ_SUCCESS) {
+ pj_perror(4, ds->base.name, status, "dtls_encode_sdp() failed");
+ dtls_destroy(tp);
+ }
+ return status;
+}
+
+
+static pj_status_t dtls_media_start( pjmedia_transport *tp,
+ pj_pool_t *tmp_pool,
+ const pjmedia_sdp_session *sdp_local,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index)
+{
+ dtls_srtp *ds = (dtls_srtp *)tp;
+ pj_ice_strans_state ice_state;
+ pj_status_t status = PJ_SUCCESS;
+
+#if DTLS_DEBUG
+ PJ_LOG(2,(ds->base.name, "dtls_media_start()"));
+#endif
+
+ PJ_UNUSED_ARG(tmp_pool);
+ PJ_UNUSED_ARG(sdp_local);
+
+ if (ds->srtp->offerer_side) {
+ /* As offerer */
+ dtls_setup last_setup = ds->setup;
+ pj_str_t last_rem_fp = ds->rem_fingerprint;
+
+ /* Parse a=setup and a=fingerprint */
+ status = parse_setup_finger_attr(ds, PJ_FALSE, sdp_remote,
+ media_index);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ /* Check if remote signals DTLS re-nego by changing its
+ * setup/fingerprint in SDP.
+ */
+ if ((last_setup != DTLS_SETUP_ACTPASS && last_setup != ds->setup) ||
+ (last_rem_fp.slen &&
+ pj_memcmp(&last_rem_fp, &ds->rem_fingerprint, sizeof(pj_str_t))))
+ {
+ ssl_destroy(ds);
+ ds->nego_started = PJ_FALSE;
+ ds->got_keys = PJ_FALSE;
+
+ status = ssl_create(ds);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+ }
+ } else {
+ /* As answerer */
+
+ /* Nothing to do? */
+ }
+
+ /* Check and update ICE status */
+ {
+ pjmedia_transport_info info;
+ pjmedia_ice_transport_info *ice_info;
+
+ pjmedia_transport_info_init(&info);
+ pjmedia_transport_get_info(ds->srtp->member_tp, &info);
+ ice_info = (pjmedia_ice_transport_info*)
+ pjmedia_transport_info_get_spc_info(
+ &info, PJMEDIA_TRANSPORT_TYPE_ICE);
+ ds->use_ice = ice_info && ice_info->active;
+ ice_state = ds->use_ice? ice_info->sess_state : 0;
+ }
+
+ /* Check if the background DTLS nego has completed */
+ if (ds->got_keys) {
+ ds->srtp->tx_policy_neg = ds->tx_crypto;
+ ds->srtp->rx_policy_neg = ds->rx_crypto;
+
+ /* Verify remote fingerprint (if available) */
+ if (ds->rem_fingerprint.slen && ds->rem_fprint_status == PJ_EPENDING)
+ {
+ ds->rem_fprint_status = ssl_match_fingerprint(ds);
+ if (ds->rem_fprint_status != PJ_SUCCESS) {
+ pj_perror(4, ds->base.name, ds->rem_fprint_status,
+ "Fingerprint specified in remote SDP doesn't match "
+ "to actual remote certificate fingerprint!");
+ return ds->rem_fprint_status;
+ }
+ }
+
+ return PJ_SUCCESS;
+ }
+
+ /* SRTP key is not ready, SRTP start is pending */
+ ds->srtp->keying_pending_cnt++;
+ ds->pending_start = PJ_TRUE;
+
+ /* If our DTLS setup is ACTIVE:
+ * - start DTLS nego after ICE nego, or
+ * - start it now if there is no ICE.
+ */
+ if (ds->setup == DTLS_SETUP_ACTIVE) {
+ if (ds->use_ice && ice_state < PJ_ICE_STRANS_STATE_RUNNING) {
+ /* Register ourselves to listen to ICE notifications */
+ pjmedia_ice_cb ice_cb;
+ pj_bzero(&ice_cb, sizeof(ice_cb));
+ ice_cb.on_ice_complete2 = &on_ice_complete2;
+ pjmedia_ice_add_ice_cb(ds->srtp->member_tp, &ice_cb, ds);
+ } else {
+ /* This can happen when we are SDP offerer and remote wants
+ * PASSIVE DTLS role.
+ */
+ pjmedia_transport_attach_param ap;
+ pj_bzero(&ap, sizeof(ap));
+
+ /* Attach ourselves to member transport for DTLS nego. */
+ if (!pj_sockaddr_has_addr(&ds->rem_addr))
+ get_rem_addrs(ds, sdp_remote, media_index);
+
+ if (pj_sockaddr_has_addr(&ds->rem_addr))
+ pj_sockaddr_cp(&ap.rem_addr, &ds->rem_addr);
+ else
+ pj_sockaddr_init(pj_AF_INET(), &ap.rem_addr, 0, 0);
+
+ if (pj_sockaddr_has_addr(&ds->rem_rtcp))
+ pj_sockaddr_cp(&ap.rem_rtcp, &ds->rem_rtcp);
+ else
+ pj_sockaddr_init(pj_AF_INET(), &ap.rem_rtcp, 0, 0);
+
+ ap.addr_len = pj_sockaddr_get_len(&ap.rem_addr);
+ status = pjmedia_transport_attach2(&ds->srtp->base, &ap);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ status = ssl_handshake(ds);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+ }
+ }
+
+on_return:
+ if (status != PJ_SUCCESS) {
+ pj_perror(4, ds->base.name, status, "dtls_media_start() failed");
+ dtls_destroy(tp);
+ }
+ return status;
+}
+
+static pj_status_t dtls_media_stop(pjmedia_transport *tp)
+{
+ dtls_srtp *ds = (dtls_srtp *)tp;
+
+#if DTLS_DEBUG
+ PJ_LOG(2,(ds->base.name, "dtls_media_stop()"));
+#endif
+
+ if (ds->clock)
+ pjmedia_clock_stop(ds->clock);
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t dtls_destroy(pjmedia_transport *tp)
+{
+ dtls_srtp *ds = (dtls_srtp *)tp;
+
+#if DTLS_DEBUG
+ PJ_LOG(2,(ds->base.name, "dtls_destroy()"));
+#endif
+
+ if (ds->clock)
+ pjmedia_clock_destroy(ds->clock);
+ ssl_destroy(ds);
+ pj_pool_safe_release(&ds->pool);
+
+ return PJ_SUCCESS;
+}
+
+
+/* Get fingerprint of local DTLS-SRTP certificate. */
+PJ_DEF(pj_status_t) pjmedia_transport_srtp_dtls_get_fingerprint(
+ pjmedia_transport *tp,
+ const char *hash,
+ char *buf, pj_size_t *len)
+{
+ PJ_ASSERT_RETURN(dtls_cert, PJ_EINVALIDOP);
+ PJ_ASSERT_RETURN(tp && hash && buf && len, PJ_EINVAL);
+ PJ_ASSERT_RETURN(pj_ansi_strcmp(hash, "SHA-256")==0 ||
+ pj_ansi_strcmp(hash, "SHA-1")==0, PJ_EINVAL);
+ PJ_UNUSED_ARG(tp);
+
+ return ssl_get_fingerprint(dtls_cert,
+ pj_ansi_strcmp(hash, "SHA-256")==0,
+ buf, len);
+}
+
+
+/* Manually start DTLS-SRTP negotiation (without SDP offer/answer) */
+PJ_DEF(pj_status_t) pjmedia_transport_srtp_dtls_start_nego(
+ pjmedia_transport *tp,
+ const pjmedia_srtp_dtls_nego_param *param)
+{
+ transport_srtp *srtp = (transport_srtp*)tp;
+ dtls_srtp *ds = NULL;
+ unsigned j;
+ pjmedia_transport_attach_param ap;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(tp && param, PJ_EINVAL);
+ PJ_ASSERT_RETURN(pj_sockaddr_has_addr(¶m->rem_addr), PJ_EINVAL);
+
+ /* Find DTLS keying and destroy any other keying. */
+ for (j = 0; j < srtp->keying_cnt; ++j) {
+ if (srtp->keying[j]->op == &dtls_op)
+ ds = (dtls_srtp*)srtp->keying[j];
+ else
+ pjmedia_transport_close(srtp->keying[j]);
+ }
+
+ /* DTLS-SRTP is not enabled */
+ if (!ds)
+ return PJ_ENOTSUP;
+
+ /* Set SRTP keying to DTLS-SRTP only */
+ srtp->keying_cnt = 1;
+ srtp->keying[0] = &ds->base;
+ srtp->keying_pending_cnt = 1;
+
+ /* Apply param to DTLS-SRTP internal states */
+ pj_strdup(ds->pool, &ds->rem_fingerprint, ¶m->rem_fingerprint);
+ ds->rem_fprint_status = PJ_EPENDING;
+ ds->rem_addr = param->rem_addr;
+ ds->rem_rtcp = param->rem_rtcp;
+ ds->setup = param->is_role_active? DTLS_SETUP_ACTIVE:DTLS_SETUP_PASSIVE;
+
+ /* Pending start SRTP */
+ ds->pending_start = PJ_TRUE;
+ srtp->keying_pending_cnt++;
+
+ /* Create SSL */
+ status = ssl_create(ds);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ /* Attach member transport, so we can send/receive DTLS init packets */
+ pj_bzero(&ap, sizeof(ap));
+ pj_sockaddr_cp(&ap.rem_addr, &ds->rem_addr);
+ pj_sockaddr_cp(&ap.rem_rtcp, &ds->rem_rtcp);
+ ap.addr_len = pj_sockaddr_get_len(&ap.rem_addr);
+ status = pjmedia_transport_attach2(&ds->srtp->base, &ap);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ /* Start DTLS handshake */
+ pj_bzero(&srtp->rx_policy_neg, sizeof(srtp->rx_policy_neg));
+ pj_bzero(&srtp->tx_policy_neg, sizeof(srtp->tx_policy_neg));
+ status = ssl_handshake(ds);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+on_return:
+ if (status != PJ_SUCCESS) {
+ ssl_destroy(ds);
+ }
+ return status;
+}
diff --git a/pjmedia/src/pjmedia/transport_srtp_sdes.c b/pjmedia/src/pjmedia/transport_srtp_sdes.c
new file mode 100644
index 0000000..20b16ab
--- /dev/null
+++ b/pjmedia/src/pjmedia/transport_srtp_sdes.c
@@ -0,0 +1,712 @@
+/* $Id: transport_srtp_sdes.c 5635 2017-08-01 07:49:34Z nanang $ */
+/*
+ * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(PJ_HAS_SSL_SOCK) && (PJ_HAS_SSL_SOCK != 0)
+
+/* Include OpenSSL libraries for MSVC */
+# ifdef _MSC_VER
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+# pragma comment(lib, "libcrypto")
+# else
+# pragma comment(lib, "libeay32")
+# pragma comment(lib, "ssleay32")
+# endif
+# endif
+
+#endif
+
+
+#include <pj/rand.h>
+
+
+static pj_status_t sdes_media_create(pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ unsigned options,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index);
+static pj_status_t sdes_encode_sdp (pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ pjmedia_sdp_session *sdp_local,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index);
+static pj_status_t sdes_media_start (pjmedia_transport *tp,
+ pj_pool_t *pool,
+ const pjmedia_sdp_session *sdp_local,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index);
+static pj_status_t sdes_media_stop (pjmedia_transport *tp);
+
+
+static pjmedia_transport_op sdes_op =
+{
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &sdes_media_create,
+ &sdes_encode_sdp,
+ &sdes_media_start,
+ &sdes_media_stop,
+ NULL,
+ NULL
+};
+
+
+static pj_status_t sdes_create(transport_srtp *srtp,
+ pjmedia_transport **p_keying)
+{
+ pjmedia_transport *sdes;
+
+ sdes = PJ_POOL_ZALLOC_T(srtp->pool, pjmedia_transport);
+ pj_ansi_strncpy(sdes->name, srtp->pool->obj_name, PJ_MAX_OBJ_NAME);
+ pj_memcpy(sdes->name, "sdes", 4);
+ sdes->type = PJMEDIA_TRANSPORT_TYPE_SRTP;
+ sdes->op = &sdes_op;
+ sdes->user_data = srtp;
+
+ *p_keying = sdes;
+ PJ_LOG(5,(srtp->pool->obj_name, "SRTP keying SDES created"));
+ return PJ_SUCCESS;
+}
+
+
+/* Generate crypto attribute, including crypto key.
+ * If crypto-suite chosen is crypto NULL, just return PJ_SUCCESS,
+ * and set buffer_len = 0.
+ */
+static pj_status_t generate_crypto_attr_value(pj_pool_t *pool,
+ char *buffer, int *buffer_len,
+ pjmedia_srtp_crypto *crypto,
+ int tag)
+{
+ pj_status_t status;
+ int cs_idx = get_crypto_idx(&crypto->name);
+ char b64_key[PJ_BASE256_TO_BASE64_LEN(MAX_KEY_LEN)+1];
+ int b64_key_len = sizeof(b64_key);
+ int print_len;
+
+ if (cs_idx == -1)
+ return PJMEDIA_SRTP_ENOTSUPCRYPTO;
+
+ /* Crypto-suite NULL. */
+ if (cs_idx == 0) {
+ *buffer_len = 0;
+ return PJ_SUCCESS;
+ }
+
+ /* Generate key if not specified. */
+ if (crypto->key.slen == 0) {
+ pj_bool_t key_ok;
+ char key[MAX_KEY_LEN];
+ unsigned i;
+
+ PJ_ASSERT_RETURN(MAX_KEY_LEN >= crypto_suites[cs_idx].cipher_key_len,
+ PJ_ETOOSMALL);
+
+ do {
+#if defined(PJ_HAS_SSL_SOCK) && (PJ_HAS_SSL_SOCK != 0)
+ int err = RAND_bytes((unsigned char*)key,
+ crypto_suites[cs_idx].cipher_key_len);
+ if (err != 1) {
+ PJ_LOG(5,(THIS_FILE, "Failed generating random key"));
+ return PJMEDIA_ERRNO_FROM_LIBSRTP(1);
+ }
+#else
+ PJ_LOG(3,(THIS_FILE, "Warning: simple random generator is used "
+ "for generating SRTP key"));
+ for (i=0; i<crypto_suites[cs_idx].cipher_key_len; ++i) {
+ pj_timestamp ts;
+ if (pj_rand() % 7 < 2)
+ pj_thread_sleep(pj_rand() % 11);
+ pj_get_timestamp(&ts);
+ key[i] = (char)((pj_rand() + ts.u32.lo) & 0xFF);
+ }
+#endif
+
+ key_ok = PJ_TRUE;
+ for (i=0; i<crypto_suites[cs_idx].cipher_key_len && key_ok; ++i)
+ if (key[i] == 0) key_ok = PJ_FALSE;
+
+ } while (!key_ok);
+ crypto->key.ptr = (char*)
+ pj_pool_zalloc(pool,
+ crypto_suites[cs_idx].cipher_key_len);
+ pj_memcpy(crypto->key.ptr, key, crypto_suites[cs_idx].cipher_key_len);
+ crypto->key.slen = crypto_suites[cs_idx].cipher_key_len;
+ }
+
+ if (crypto->key.slen != (pj_ssize_t)crypto_suites[cs_idx].cipher_key_len)
+ return PJMEDIA_SRTP_EINKEYLEN;
+
+ /* Key transmitted via SDP should be base64 encoded. */
+ status = pj_base64_encode((pj_uint8_t*)crypto->key.ptr, (int)crypto->key.slen,
+ b64_key, &b64_key_len);
+ if (status != PJ_SUCCESS) {
+ PJ_LOG(5,(THIS_FILE, "Failed encoding plain key to base64"));
+ return status;
+ }
+
+ b64_key[b64_key_len] = '\0';
+
+ PJ_ASSERT_RETURN(*buffer_len >= (crypto->name.slen + \
+ b64_key_len + 16), PJ_ETOOSMALL);
+
+ /* Print the crypto attribute value. */
+ print_len = pj_ansi_snprintf(buffer, *buffer_len, "%d %s inline:%s",
+ tag,
+ crypto_suites[cs_idx].name,
+ b64_key);
+ if (print_len < 1 || print_len >= *buffer_len)
+ return PJ_ETOOSMALL;
+
+ *buffer_len = print_len;
+
+ return PJ_SUCCESS;
+}
+
+
+/* Parse crypto attribute line */
+static pj_status_t parse_attr_crypto(pj_pool_t *pool,
+ const pjmedia_sdp_attr *attr,
+ pjmedia_srtp_crypto *crypto,
+ int *tag)
+{
+ pj_str_t token, delim;
+ pj_status_t status;
+ int itmp;
+ pj_ssize_t found_idx;
+
+ pj_bzero(crypto, sizeof(*crypto));
+
+ /* Tag */
+ delim = pj_str(" ");
+ found_idx = pj_strtok(&attr->value, &delim, &token, 0);
+ if (found_idx == attr->value.slen) {
+ PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting tag"));
+ return PJMEDIA_SDP_EINATTR;
+ }
+
+ /* Tag must not use leading zeroes. */
+ if (token.slen > 1 && *token.ptr == '0')
+ return PJMEDIA_SDP_EINATTR;
+
+ /* Tag must be decimal, i.e: contains only digit '0'-'9'. */
+ for (itmp = 0; itmp < token.slen; ++itmp)
+ if (!pj_isdigit(token.ptr[itmp]))
+ return PJMEDIA_SDP_EINATTR;
+
+ /* Get tag value. */
+ *tag = pj_strtoul(&token);
+
+ /* Crypto-suite */
+ found_idx = pj_strtok(&attr->value, &delim, &token, found_idx+token.slen);
+ if (found_idx == attr->value.slen) {
+ PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting crypto suite"));
+ return PJMEDIA_SDP_EINATTR;
+ }
+ pj_strdup(pool, &crypto->name, &token);
+
+ /* Key method */
+ delim = pj_str(": ");
+ found_idx = pj_strtok(&attr->value, &delim, &token, found_idx+token.slen);
+ if (found_idx == attr->value.slen) {
+ PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting key method"));
+ return PJMEDIA_SDP_EINATTR;
+ }
+ if (pj_stricmp2(&token, "inline")) {
+ PJ_LOG(4,(THIS_FILE, "Attribute crypto key method '%.*s' "
+ "not supported!", token.slen, token.ptr));
+ return PJMEDIA_SDP_EINATTR;
+ }
+
+ /* Key */
+ delim = pj_str("| ");
+ found_idx = pj_strtok(&attr->value, &delim, &token, found_idx+token.slen);
+ if (found_idx == attr->value.slen) {
+ PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting key"));
+ return PJMEDIA_SDP_EINATTR;
+ }
+
+ if (PJ_BASE64_TO_BASE256_LEN(token.slen) > MAX_KEY_LEN) {
+ PJ_LOG(4,(THIS_FILE, "Key too long"));
+ return PJMEDIA_SRTP_EINKEYLEN;
+ }
+
+ /* Decode key */
+ crypto->key.ptr = (char*) pj_pool_zalloc(pool, MAX_KEY_LEN);
+ itmp = MAX_KEY_LEN;
+ status = pj_base64_decode(&token, (pj_uint8_t*)crypto->key.ptr,
+ &itmp);
+ if (status != PJ_SUCCESS) {
+ PJ_LOG(4,(THIS_FILE, "Failed decoding crypto key from base64"));
+ return status;
+ }
+ crypto->key.slen = itmp;
+
+ return PJ_SUCCESS;
+}
+
+
+static pj_status_t sdes_media_create( pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ unsigned options,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index)
+{
+ struct transport_srtp *srtp = (struct transport_srtp*)tp->user_data;
+
+ PJ_UNUSED_ARG(options);
+ PJ_UNUSED_ARG(sdp_pool);
+
+ /* Validations */
+ if (srtp->offerer_side) {
+ if (srtp->setting.use == PJMEDIA_SRTP_DISABLED)
+ srtp->bypass_srtp = PJ_TRUE;
+ } else {
+ pjmedia_sdp_media *m_rem = sdp_remote->media[media_index];
+
+ /* Nothing to do on inactive media stream */
+ if (pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL))
+ srtp->bypass_srtp = PJ_TRUE;
+
+ /* Validate remote media transport based on SRTP usage option. */
+ switch (srtp->setting.use) {
+ case PJMEDIA_SRTP_DISABLED:
+ if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0)
+ return PJMEDIA_SRTP_ESDPINTRANSPORT;
+ srtp->bypass_srtp = PJ_TRUE;
+ break;
+ case PJMEDIA_SRTP_OPTIONAL:
+ break;
+ case PJMEDIA_SRTP_MANDATORY:
+ if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0)
+ return PJMEDIA_SRTP_ESDPINTRANSPORT;
+ break;
+ }
+ }
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t sdes_encode_sdp( pjmedia_transport *tp,
+ pj_pool_t *sdp_pool,
+ pjmedia_sdp_session *sdp_local,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index)
+{
+ struct transport_srtp *srtp = (struct transport_srtp*)tp->user_data;
+ pjmedia_sdp_media *m_rem, *m_loc;
+ enum { MAXLEN = 512 };
+ char buffer[MAXLEN];
+ int buffer_len;
+ pj_status_t status;
+ pjmedia_sdp_attr *attr;
+ pj_str_t attr_value;
+ unsigned i, j;
+
+ m_rem = sdp_remote ? sdp_remote->media[media_index] : NULL;
+ m_loc = sdp_local->media[media_index];
+
+ /* Bypass SDES if media transport is not RTP/AVP or RTP/SAVP */
+ if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP) != 0 &&
+ pj_stricmp(&m_loc->desc.transport, &ID_RTP_SAVP) != 0)
+ {
+ return PJ_SUCCESS;
+ }
+
+ /* If the media is inactive, do nothing. */
+ /* No, we still need to process SRTP offer/answer even if the media is
+ * marked as inactive, because the transport is still alive in this
+ * case (e.g. for keep-alive). See:
+ * http://trac.pjsip.org/repos/ticket/1079
+ */
+ /*
+ if (pjmedia_sdp_media_find_attr(m_loc, &ID_INACTIVE, NULL) ||
+ (m_rem && pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL)))
+ goto BYPASS_SRTP;
+ */
+
+ /* Check remote media transport & set local media transport
+ * based on SRTP usage option.
+ */
+ if (srtp->offerer_side) {
+
+ /* Generate transport */
+ switch (srtp->setting.use) {
+ case PJMEDIA_SRTP_DISABLED:
+ pj_assert(!"Shouldn't reach here");
+ return PJ_SUCCESS;
+ case PJMEDIA_SRTP_OPTIONAL:
+ m_loc->desc.transport =
+ (srtp->peer_use == PJMEDIA_SRTP_MANDATORY)?
+ ID_RTP_SAVP : ID_RTP_AVP;
+ break;
+ case PJMEDIA_SRTP_MANDATORY:
+ m_loc->desc.transport = ID_RTP_SAVP;
+ break;
+ }
+
+ /* Generate crypto attribute if not yet */
+ if (pjmedia_sdp_media_find_attr(m_loc, &ID_CRYPTO, NULL) == NULL) {
+ int tag = 1;
+
+ /* Offer only current active crypto if any, otherwise offer all
+ * crypto-suites in the setting.
+ */
+ for (i=0; i<srtp->setting.crypto_count; ++i) {
+ if (srtp->tx_policy.name.slen &&
+ pj_stricmp(&srtp->tx_policy.name,
+ &srtp->setting.crypto[i].name) != 0)
+ {
+ continue;
+ }
+
+ buffer_len = MAXLEN;
+ status = generate_crypto_attr_value(srtp->pool, buffer,
+ &buffer_len,
+ &srtp->setting.crypto[i],
+ tag);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* If buffer_len==0, just skip the crypto attribute. */
+ if (buffer_len) {
+ pj_strset(&attr_value, buffer, buffer_len);
+ attr = pjmedia_sdp_attr_create(srtp->pool, ID_CRYPTO.ptr,
+ &attr_value);
+ m_loc->attr[m_loc->attr_count++] = attr;
+ ++tag;
+ }
+ }
+ }
+
+ } else {
+ /* Answerer side */
+
+ pj_assert(sdp_remote && m_rem);
+
+ /* Generate transport */
+ switch (srtp->setting.use) {
+ case PJMEDIA_SRTP_DISABLED:
+ pj_assert(!"Shouldn't reach here");
+ if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0)
+ return PJMEDIA_SRTP_ESDPINTRANSPORT;
+ return PJ_SUCCESS;
+ case PJMEDIA_SRTP_OPTIONAL:
+ m_loc->desc.transport = m_rem->desc.transport;
+ break;
+ case PJMEDIA_SRTP_MANDATORY:
+ if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0)
+ return PJMEDIA_SRTP_ESDPINTRANSPORT;
+ m_loc->desc.transport = ID_RTP_SAVP;
+ break;
+ }
+
+ /* Generate crypto attribute if not yet */
+ if (pjmedia_sdp_media_find_attr(m_loc, &ID_CRYPTO, NULL) == NULL) {
+
+ pjmedia_srtp_crypto tmp_rx_crypto;
+ pj_bool_t has_crypto_attr = PJ_FALSE;
+ int matched_idx = -1;
+ int chosen_tag = 0;
+ int tags[64]; /* assume no more than 64 crypto attrs in a media */
+ unsigned cr_attr_count = 0;
+
+ /* Find supported crypto-suite, get the tag, and assign
+ * policy_local.
+ */
+ for (i=0; i<m_rem->attr_count; ++i) {
+ if (pj_stricmp(&m_rem->attr[i]->name, &ID_CRYPTO) != 0)
+ continue;
+
+ has_crypto_attr = PJ_TRUE;
+
+ status = parse_attr_crypto(srtp->pool, m_rem->attr[i],
+ &tmp_rx_crypto,
+ &tags[cr_attr_count]);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Check duplicated tag */
+ for (j=0; j<cr_attr_count; ++j) {
+ if (tags[j] == tags[cr_attr_count]) {
+ DEACTIVATE_MEDIA(sdp_pool, m_loc);
+ return PJMEDIA_SRTP_ESDPDUPCRYPTOTAG;
+ }
+ }
+
+ if (matched_idx == -1) {
+ /* lets see if the crypto-suite offered is supported */
+ for (j=0; j<srtp->setting.crypto_count; ++j)
+ if (pj_stricmp(&tmp_rx_crypto.name,
+ &srtp->setting.crypto[j].name) == 0)
+ {
+ int cs_idx = get_crypto_idx(&tmp_rx_crypto.name);
+
+ if (cs_idx == -1)
+ return PJMEDIA_SRTP_ENOTSUPCRYPTO;
+
+ if (tmp_rx_crypto.key.slen !=
+ (int)crypto_suites[cs_idx].cipher_key_len)
+ return PJMEDIA_SRTP_EINKEYLEN;
+
+ srtp->rx_policy_neg = tmp_rx_crypto;
+ chosen_tag = tags[cr_attr_count];
+ matched_idx = j;
+ break;
+ }
+ }
+ cr_attr_count++;
+ }
+
+ /* Check crypto negotiation result */
+ switch (srtp->setting.use) {
+ case PJMEDIA_SRTP_DISABLED:
+ pj_assert(!"Should never reach here");
+ break;
+
+ case PJMEDIA_SRTP_OPTIONAL:
+ /* Bypass SDES if remote uses RTP/AVP and:
+ * - has no crypto-attr, or
+ * - has no matching crypto
+ */
+ if ((!has_crypto_attr || matched_idx == -1) &&
+ pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0)
+ {
+ return PJ_SUCCESS;
+ }
+ break;
+
+ case PJMEDIA_SRTP_MANDATORY:
+ /* Do nothing, intentional */
+ break;
+ }
+
+ /* No crypto attr */
+ if (!has_crypto_attr) {
+ DEACTIVATE_MEDIA(sdp_pool, m_loc);
+ return PJMEDIA_SRTP_ESDPREQCRYPTO;
+ }
+
+ /* No crypto match */
+ if (matched_idx == -1) {
+ DEACTIVATE_MEDIA(sdp_pool, m_loc);
+ return PJMEDIA_SRTP_ENOTSUPCRYPTO;
+ }
+
+ /* we have to generate crypto answer,
+ * with srtp->tx_policy_neg matched the offer
+ * and rem_tag contains matched offer tag.
+ */
+ buffer_len = MAXLEN;
+ status = generate_crypto_attr_value(
+ srtp->pool, buffer, &buffer_len,
+ &srtp->setting.crypto[matched_idx],
+ chosen_tag);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ srtp->tx_policy_neg = srtp->setting.crypto[matched_idx];
+
+ /* If buffer_len==0, just skip the crypto attribute. */
+ if (buffer_len) {
+ pj_strset(&attr_value, buffer, buffer_len);
+ attr = pjmedia_sdp_attr_create(sdp_pool, ID_CRYPTO.ptr,
+ &attr_value);
+ m_loc->attr[m_loc->attr_count++] = attr;
+ }
+
+ /* At this point, we get valid rx_policy_neg & tx_policy_neg. */
+ }
+ }
+
+ return PJ_SUCCESS;
+}
+
+
+static pj_status_t fill_local_crypto(pj_pool_t *pool,
+ const pjmedia_sdp_media *m_loc,
+ pjmedia_srtp_crypto loc_crypto[],
+ int *count)
+{
+ int i;
+ int crypto_count = 0;
+ pj_status_t status = PJ_SUCCESS;
+
+ for (i = 0; i < *count; ++i) {
+ pj_bzero(&loc_crypto[i], sizeof(loc_crypto[i]));
+ }
+
+ for (i = 0; i < (int)m_loc->attr_count; ++i) {
+ pjmedia_srtp_crypto tmp_crypto;
+ int loc_tag;
+
+ if (pj_stricmp(&m_loc->attr[i]->name, &ID_CRYPTO) != 0)
+ continue;
+
+ status = parse_attr_crypto(pool, m_loc->attr[i],
+ &tmp_crypto, &loc_tag);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ if (loc_tag > *count)
+ return PJMEDIA_SRTP_ESDPINCRYPTOTAG;
+
+ loc_crypto[loc_tag-1] = tmp_crypto;
+ ++crypto_count;
+ }
+ *count = crypto_count;
+ return status;
+}
+
+
+static pj_status_t sdes_media_start( pjmedia_transport *tp,
+ pj_pool_t *pool,
+ const pjmedia_sdp_session *sdp_local,
+ const pjmedia_sdp_session *sdp_remote,
+ unsigned media_index)
+{
+ struct transport_srtp *srtp = (struct transport_srtp*)tp->user_data;
+ pjmedia_sdp_media *m_rem, *m_loc;
+ pj_status_t status;
+ unsigned i;
+ pjmedia_srtp_crypto loc_crypto[PJMEDIA_SRTP_MAX_CRYPTOS];
+ int loc_cryto_cnt = PJMEDIA_SRTP_MAX_CRYPTOS;
+
+ m_rem = sdp_remote->media[media_index];
+ m_loc = sdp_local->media[media_index];
+
+ if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0)
+ srtp->peer_use = PJMEDIA_SRTP_MANDATORY;
+ else
+ srtp->peer_use = PJMEDIA_SRTP_OPTIONAL;
+
+ /* For answerer side, this function will just have to start SRTP */
+
+ /* Check remote media transport & set local media transport
+ * based on SRTP usage option.
+ */
+ if (srtp->offerer_side) {
+ if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
+ if (pjmedia_sdp_media_find_attr(m_rem, &ID_CRYPTO, NULL)) {
+ DEACTIVATE_MEDIA(pool, m_loc);
+ return PJMEDIA_SRTP_ESDPINCRYPTO;
+ }
+ return PJ_SUCCESS;
+ } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
+ // Regardless the answer's transport type (RTP/AVP or RTP/SAVP),
+ // the answer must be processed through in optional mode.
+ // Please note that at this point transport type is ensured to be
+ // RTP/AVP or RTP/SAVP, see sdes_media_create()
+ //if (pj_stricmp(&m_rem->desc.transport, &m_loc->desc.transport)) {
+ //DEACTIVATE_MEDIA(pool, m_loc);
+ //return PJMEDIA_SDP_EINPROTO;
+ //}
+ fill_local_crypto(srtp->pool, m_loc, loc_crypto, &loc_cryto_cnt);
+ } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) {
+ if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP)) {
+ DEACTIVATE_MEDIA(pool, m_loc);
+ return PJMEDIA_SDP_EINPROTO;
+ }
+ fill_local_crypto(srtp->pool, m_loc, loc_crypto, &loc_cryto_cnt);
+ }
+ }
+
+ if (srtp->offerer_side) {
+ /* find supported crypto-suite, get the tag, and assign policy_local */
+ pjmedia_srtp_crypto tmp_tx_crypto;
+ pj_bool_t has_crypto_attr = PJ_FALSE;
+ int rem_tag;
+ int j;
+
+ for (i=0; i<m_rem->attr_count; ++i) {
+ if (pj_stricmp(&m_rem->attr[i]->name, &ID_CRYPTO) != 0)
+ continue;
+
+ /* more than one crypto attribute in media answer */
+ if (has_crypto_attr) {
+ DEACTIVATE_MEDIA(pool, m_loc);
+ return PJMEDIA_SRTP_ESDPAMBIGUEANS;
+ }
+
+ has_crypto_attr = PJ_TRUE;
+
+ status = parse_attr_crypto(srtp->pool, m_rem->attr[i],
+ &tmp_tx_crypto, &rem_tag);
+ if (status != PJ_SUCCESS)
+ return status;
+
+
+ /* Tag range check, our tags in the offer must be in the SRTP
+ * setting range, so does the remote answer's. The remote answer's
+ * tag must not exceed the tag range of the local offer.
+ */
+ if (rem_tag < 1 || rem_tag > (int)srtp->setting.crypto_count ||
+ rem_tag > loc_cryto_cnt)
+ {
+ DEACTIVATE_MEDIA(pool, m_loc);
+ return PJMEDIA_SRTP_ESDPINCRYPTOTAG;
+ }
+
+ /* match the crypto name */
+ if (pj_stricmp(&tmp_tx_crypto.name, &loc_crypto[rem_tag-1].name))
+ {
+ DEACTIVATE_MEDIA(pool, m_loc);
+ return PJMEDIA_SRTP_ECRYPTONOTMATCH;
+ }
+
+ /* Find the crypto from the setting. */
+ for (j = 0; j < (int)srtp->setting.crypto_count; ++j) {
+ if (pj_stricmp(&tmp_tx_crypto.name,
+ &srtp->setting.crypto[j].name) == 0)
+ {
+ srtp->tx_policy_neg = srtp->setting.crypto[j];
+ break;
+ }
+ }
+
+ srtp->rx_policy_neg = tmp_tx_crypto;
+ }
+
+ if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
+ /* should never reach here */
+ return PJ_SUCCESS;
+ } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
+ if (!has_crypto_attr)
+ return PJ_SUCCESS;
+ } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) {
+ if (!has_crypto_attr) {
+ DEACTIVATE_MEDIA(pool, m_loc);
+ return PJMEDIA_SRTP_ESDPREQCRYPTO;
+ }
+ }
+
+ /* At this point, we get valid rx_policy_neg & tx_policy_neg. */
+ }
+
+ return PJ_SUCCESS;
+}
+
+static pj_status_t sdes_media_stop(pjmedia_transport *tp)
+{
+ PJ_UNUSED_ARG(tp);
+ return PJ_SUCCESS;
+}
diff --git a/pjmedia/src/pjmedia/transport_udp.c b/pjmedia/src/pjmedia/transport_udp.c
index d0bc173..1fafa3c 100644
--- a/pjmedia/src/pjmedia/transport_udp.c
+++ b/pjmedia/src/pjmedia/transport_udp.c
@@ -1,4 +1,4 @@
-/* $Id: transport_udp.c 5539 2017-01-23 04:32:34Z nanang $ */
+/* $Id: transport_udp.c 5654 2017-09-20 04:34:27Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -55,8 +55,9 @@ struct transport_udp
unsigned options; /**< Transport options. */
unsigned media_options; /**< Transport media options. */
void *user_data; /**< Only valid when attached */
- pj_bool_t attached; /**< Has attachment? */
+ //pj_bool_t attached; /**< Has attachment? */
pj_sockaddr rem_rtp_addr; /**< Remote RTP address */
+ unsigned rem_rtp_cnt; /**< How many pkt from this addr. */
pj_sockaddr rem_rtcp_addr; /**< Remote RTCP address */
int addr_len; /**< Length of addresses. */
void (*rtp_cb)( void*, /**< To report incoming RTP. */
@@ -479,11 +480,16 @@ static void on_rx_rtp( pj_ioqueue_key_t *key,
if (pj_sockaddr_cmp(&udp->rem_rtp_addr, &udp->rtp_src_addr) == 0) {
/* We're still receiving from rem_rtp_addr. Don't switch. */
udp->rtp_src_cnt = 0;
+ udp->rem_rtp_cnt++;
} else {
udp->rtp_src_cnt++;
if (udp->rtp_src_cnt < PJMEDIA_RTP_NAT_PROBATION_CNT) {
- discard = PJ_TRUE;
+ /* Only discard if we have ever received packet from
+ * remote address (rem_rtp_addr).
+ */
+ //discard = PJ_TRUE;
+ discard = (udp->rem_rtp_cnt != 0);
} else {
char addr_text[80];
@@ -529,7 +535,8 @@ static void on_rx_rtp( pj_ioqueue_key_t *key,
}
}
- if (!discard && udp->attached && cb)
+ //if (!discard && udp->attached && cb)
+ if (!discard && cb)
(*cb)(user_data, udp->rtp_pkt, bytes_read);
bytes_read = sizeof(udp->rtp_pkt);
@@ -565,7 +572,8 @@ static void on_rx_rtcp(pj_ioqueue_key_t *key,
cb = udp->rtcp_cb;
user_data = udp->user_data;
- if (udp->attached && cb)
+ //if (udp->attached && cb)
+ if (cb)
(*cb)(user_data, udp->rtcp_pkt, bytes_read);
/* Check if RTCP source address is the same as the configured
@@ -644,12 +652,15 @@ static pj_status_t transport_attach( pjmedia_transport *tp,
{
struct transport_udp *udp = (struct transport_udp*) tp;
const pj_sockaddr *rtcp_addr;
+ pj_sockaddr sock_addr, remote_addr, remote_rtcp;
+ int rem_addr_len;
+ pj_status_t status;
/* Validate arguments */
PJ_ASSERT_RETURN(tp && rem_addr && addr_len, PJ_EINVAL);
/* Must not be "attached" to existing application */
- PJ_ASSERT_RETURN(!udp->attached, PJ_EINVALIDOP);
+ //PJ_ASSERT_RETURN(!udp->attached, PJ_EINVALIDOP);
/* Lock the ioqueue keys to make sure that callbacks are
* not executed. See ticket #844 for details.
@@ -659,19 +670,37 @@ static pj_status_t transport_attach( pjmedia_transport *tp,
/* "Attach" the application: */
+ rem_addr_len = sizeof(pj_sockaddr);
+ pj_sock_getsockname(udp->rtp_sock, &sock_addr, &rem_addr_len);
+
+ /* Synthesize address, if necessary. */
+ status = pj_sockaddr_synthesize(sock_addr.addr.sa_family,
+ &remote_addr, rem_addr);
+ if (status != PJ_SUCCESS) {
+ pj_perror(3, tp->name, status, "Failed to synthesize the correct"
+ "IP address for RTP");
+ }
+ rem_addr_len = pj_sockaddr_get_len(&remote_addr);
+
/* Copy remote RTP address */
- pj_memcpy(&udp->rem_rtp_addr, rem_addr, addr_len);
+ pj_memcpy(&udp->rem_rtp_addr, &remote_addr, rem_addr_len);
/* Copy remote RTP address, if one is specified. */
rtcp_addr = (const pj_sockaddr*) rem_rtcp;
if (rtcp_addr && pj_sockaddr_has_addr(rtcp_addr)) {
- pj_memcpy(&udp->rem_rtcp_addr, rem_rtcp, addr_len);
+ status = pj_sockaddr_synthesize(sock_addr.addr.sa_family,
+ &remote_rtcp, rem_rtcp);
+ if (status != PJ_SUCCESS) {
+ pj_perror(3, tp->name, status, "Failed to synthesize the correct"
+ "IP address for RTCP");
+ }
+ pj_memcpy(&udp->rem_rtcp_addr, &remote_rtcp, rem_addr_len);
} else {
unsigned rtcp_port;
/* Otherwise guess the RTCP address from the RTP address */
- pj_memcpy(&udp->rem_rtcp_addr, rem_addr, addr_len);
+ pj_memcpy(&udp->rem_rtcp_addr, &udp->rem_rtp_addr, rem_addr_len);
rtcp_port = pj_sockaddr_get_port(&udp->rem_rtp_addr) + 1;
pj_sockaddr_set_port(&udp->rem_rtcp_addr, (pj_uint16_t)rtcp_port);
}
@@ -682,22 +711,23 @@ static pj_status_t transport_attach( pjmedia_transport *tp,
udp->user_data = user_data;
/* Save address length */
- udp->addr_len = addr_len;
+ udp->addr_len = rem_addr_len;
/* Last, mark transport as attached */
- udp->attached = PJ_TRUE;
+ //udp->attached = PJ_TRUE;
/* Reset source RTP & RTCP addresses and counter */
pj_bzero(&udp->rtp_src_addr, sizeof(udp->rtp_src_addr));
pj_bzero(&udp->rtcp_src_addr, sizeof(udp->rtcp_src_addr));
udp->rtp_src_cnt = 0;
udp->rtcp_src_cnt = 0;
+ udp->rem_rtp_cnt = 0;
/* Set buffer size for RTP socket */
#if PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE
{
unsigned sobuf_size = PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE;
- pj_status_t status;
+
status = pj_sock_setsockopt_sobuf(udp->rtp_sock, pj_SO_RCVBUF(),
PJ_TRUE, &sobuf_size);
if (status != PJ_SUCCESS) {
@@ -717,7 +747,7 @@ static pj_status_t transport_attach( pjmedia_transport *tp,
#if PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE
{
unsigned sobuf_size = PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE;
- pj_status_t status;
+
status = pj_sock_setsockopt_sobuf(udp->rtp_sock, pj_SO_SNDBUF(),
PJ_TRUE, &sobuf_size);
if (status != PJ_SUCCESS) {
@@ -751,7 +781,8 @@ static void transport_detach( pjmedia_transport *tp,
pj_assert(tp);
- if (udp->attached) {
+ //if (udp->attached) {
+ if (1) {
int i;
/* Lock the ioqueue keys to make sure that callbacks are
@@ -767,7 +798,7 @@ static void transport_detach( pjmedia_transport *tp,
pj_assert(user_data == udp->user_data);
/* First, mark transport as unattached */
- udp->attached = PJ_FALSE;
+ //udp->attached = PJ_FALSE;
/* Clear up application infos from transport */
udp->rtp_cb = NULL;
@@ -800,7 +831,7 @@ static pj_status_t transport_send_rtp( pjmedia_transport *tp,
pj_status_t status;
/* Must be attached */
- PJ_ASSERT_RETURN(udp->attached, PJ_EINVALIDOP);
+ //PJ_ASSERT_RETURN(udp->attached, PJ_EINVALIDOP);
/* Check that the size is supported */
PJ_ASSERT_RETURN(size <= PJMEDIA_MAX_MTU, PJ_ETOOBIG);
@@ -861,7 +892,7 @@ static pj_status_t transport_send_rtcp2(pjmedia_transport *tp,
pj_ssize_t sent;
pj_status_t status;
- PJ_ASSERT_RETURN(udp->attached, PJ_EINVALIDOP);
+ //PJ_ASSERT_RETURN(udp->attached, PJ_EINVALIDOP);
if (addr == NULL) {
addr = &udp->rem_rtcp_addr;
diff --git a/pjmedia/src/pjmedia/vid_codec_util.c b/pjmedia/src/pjmedia/vid_codec_util.c
index 7ef9544..98ab8af 100644
--- a/pjmedia/src/pjmedia/vid_codec_util.c
+++ b/pjmedia/src/pjmedia/vid_codec_util.c
@@ -1,4 +1,4 @@
-/* $Id: vid_codec_util.c 5046 2015-04-06 06:21:41Z nanang $ */
+/* $Id: vid_codec_util.c 5659 2017-09-25 02:58:42Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -429,7 +429,6 @@ PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_parse_fmtp(
const pj_uint8_t start_code[3] = {0, 0, 1};
char *p;
pj_uint8_t *nal;
- pj_status_t status;
/* Find field separator ',' */
tmp_st = sps_st;
diff --git a/pjmedia/src/pjmedia/vid_port.c b/pjmedia/src/pjmedia/vid_port.c
index 15e996a..029f384 100644
--- a/pjmedia/src/pjmedia/vid_port.c
+++ b/pjmedia/src/pjmedia/vid_port.c
@@ -1,4 +1,4 @@
-/* $Id: vid_port.c 5149 2015-08-06 07:10:33Z nanang $ */
+/* $Id: vid_port.c 5595 2017-05-23 02:44:19Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -504,6 +504,14 @@ PJ_DEF(pj_status_t) pjmedia_vid_port_create( pj_pool_t *pool,
PJ_ASSERT_RETURN(vfd->fps.num, PJ_EINVAL);
+ /* Get device info */
+ if (prm->vidparam.dir & PJMEDIA_DIR_CAPTURE)
+ status = pjmedia_vid_dev_get_info(prm->vidparam.cap_id, &di);
+ else
+ status = pjmedia_vid_dev_get_info(prm->vidparam.rend_id, &di);
+ if (status != PJ_SUCCESS)
+ return status;
+
/* Allocate videoport */
vp = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_port);
vp->pool = pj_pool_create(pool->factory, "video port", 500, 500, NULL);
@@ -514,14 +522,6 @@ PJ_DEF(pj_status_t) pjmedia_vid_port_create( pj_pool_t *pool,
vparam = prm->vidparam;
dev_name[0] = '\0';
- /* Get device info */
- if (vp->dir & PJMEDIA_DIR_CAPTURE)
- status = pjmedia_vid_dev_get_info(prm->vidparam.cap_id, &di);
- else
- status = pjmedia_vid_dev_get_info(prm->vidparam.rend_id, &di);
- if (status != PJ_SUCCESS)
- return status;
-
pj_ansi_snprintf(dev_name, sizeof(dev_name), "%s [%s]",
di.name, di.driver);
pjmedia_fourcc_name(vparam.fmt.id, fmt_name);
@@ -586,6 +586,7 @@ PJ_DEF(pj_status_t) pjmedia_vid_port_create( pj_pool_t *pool,
if (status != PJ_SUCCESS)
goto on_error;
+ pjmedia_fourcc_name(vparam.fmt.id, fmt_name);
PJ_LOG(4,(THIS_FILE,
"Device %s opened: format=%s, size=%dx%d @%d:%d fps",
dev_name, fmt_name,
diff --git a/pjmedia/src/pjmedia/wav_player.c b/pjmedia/src/pjmedia/wav_player.c
index 5429c02..d86dd39 100644
--- a/pjmedia/src/pjmedia/wav_player.c
+++ b/pjmedia/src/pjmedia/wav_player.c
@@ -1,4 +1,4 @@
-/* $Id: wav_player.c 5170 2015-08-25 08:45:46Z nanang $ */
+/* $Id: wav_player.c 5635 2017-08-01 07:49:34Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -455,7 +455,7 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_get_info(
return PJ_ENOTSUP;
}
- info->size_bytes = pjmedia_wav_player_get_len(port);
+ info->size_bytes = (pj_uint32_t)pjmedia_wav_player_get_len(port);
info->size_samples = info->size_bytes /
(info->payload_bits_per_sample / 8);
diff --git a/pjmedia/src/test/mips_test.c b/pjmedia/src/test/mips_test.c
index fc71d4f..dbd1dab 100644
--- a/pjmedia/src/test/mips_test.c
+++ b/pjmedia/src/test/mips_test.c
@@ -1,4 +1,4 @@
-/* $Id: mips_test.c 5535 2017-01-19 10:31:38Z riza $ */
+/* $Id: mips_test.c 5607 2017-06-15 03:03:21Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -1172,7 +1172,7 @@ static pj_status_t wsola_discard_get_frame(struct pjmedia_port *this_port,
pjmedia_frame *frame)
{
struct wsola_discard_port *wp = (struct wsola_discard_port*)this_port;
- pj_status_t status;
+ pj_status_t status = PJ_SUCCESS;
while (pjmedia_circ_buf_get_len(wp->circbuf) <
PJMEDIA_PIA_SPF(&wp->base.info) * (CIRC_BUF_FRAME_CNT-1))
diff --git a/pjmedia/src/test/sdp_neg_test.c b/pjmedia/src/test/sdp_neg_test.c
index 5d79697..8b9ed80 100644
--- a/pjmedia/src/test/sdp_neg_test.c
+++ b/pjmedia/src/test/sdp_neg_test.c
@@ -1,4 +1,4 @@
-/* $Id: sdp_neg_test.c 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sdp_neg_test.c 5619 2017-07-05 03:57:53Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -661,7 +661,11 @@ static struct test
NULL,
/* This is how Bob's answer should look like: */
"v=0\r\n"
+#if PJMEDIA_SDP_NEG_COMPARE_BEFORE_INC_VERSION
+ "o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com\r\n"
+#else
"o=bob 2808844564 2808844565 IN IP4 host.biloxi.example.com\r\n"
+#endif
"s=bob\r\n"
"c=IN IP4 host.biloxi.example.com\r\n"
"t=0 0\r\n"
diff --git a/pjmedia/src/test/vid_codec_test.c b/pjmedia/src/test/vid_codec_test.c
index 33ecb08..882bc88 100644
--- a/pjmedia/src/test/vid_codec_test.c
+++ b/pjmedia/src/test/vid_codec_test.c
@@ -1,4 +1,4 @@
-/* $Id: vid_codec_test.c 4815 2014-04-10 10:01:07Z bennylp $ */
+/* $Id: vid_codec_test.c 5659 2017-09-25 02:58:42Z riza $ */
/*
* Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
*
@@ -278,8 +278,7 @@ static int encode_decode_test(pj_pool_t *pool, const char *codec_id,
/* Prepare codec */
{
pj_str_t codec_id_st;
- unsigned info_cnt = 1;
- const pjmedia_vid_codec_info *codec_info;
+ unsigned info_cnt = 1;
/* Lookup codec */
pj_cstr(&codec_id_st, codec_id);
@@ -463,6 +462,13 @@ int vid_codec_test(void)
}
#endif
+#if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_VID_TOOLBOX_CODEC
+ status = pjmedia_codec_vid_toolbox_init(NULL, mem);
+ if (status != PJ_SUCCESS) {
+ return -23;
+ }
+#endif
+
#if PJMEDIA_HAS_FFMPEG_VID_CODEC
status = pjmedia_codec_ffmpeg_vid_init(NULL, mem);
if (status != PJ_SUCCESS)
@@ -483,7 +489,9 @@ int vid_codec_test(void)
goto on_return;
#endif
-#if PJMEDIA_HAS_FFMPEG_VID_CODEC || PJMEDIA_HAS_OPENH264_CODEC
+#if PJMEDIA_HAS_FFMPEG_VID_CODEC || PJMEDIA_HAS_OPENH264_CODEC || \
+ PJMEDIA_HAS_VID_TOOLBOX_CODEC
+
rc = encode_decode_test(pool, "h264", PJMEDIA_VID_PACKING_WHOLE);
if (rc != 0)
goto on_return;
@@ -501,6 +509,9 @@ on_return:
#if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
pjmedia_codec_openh264_vid_deinit();
#endif
+#if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_VID_TOOLBOX_CODEC
+ pjmedia_codec_vid_toolbox_deinit();
+#endif
pjmedia_vid_dev_subsys_shutdown();
pj_pool_release(pool);
pj_log_set_level(orig_log_level);
diff --git a/pjnath/include/pjnath/ice_strans.h b/pjnath/include/pjnath/ice_strans.h
index a091854..7bd2200 100644
--- a/pjnath/include/pjnath/ice_strans.h
+++ b/pjnath/include/pjnath/ice_strans.h
@@ -1,4 +1,4 @@
-/* $Id: ice_strans.h 5339 2016-06-08 03:17:45Z nanang $ */
+/* $Id: ice_strans.h 5562 2017-03-03 02:11:02Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -338,9 +338,12 @@ typedef struct pj_ice_strans_turn_cfg
typedef struct pj_ice_strans_cfg
{
/**
- * Warning: this field is deprecated and will be ignored. Please specify
- * transport address family in STUN and TURN transport setting, i.e:
- * \a stun_tp and \a turn_tp.
+ * The address family which will be used as the default address
+ * in the SDP offer. Setting this to pj_AF_UNSPEC() means that
+ * the address family will not be considered during the process
+ * of default candidate selection.
+ *
+ * The default value is pj_AF_INET() (IPv4).
*/
int af;
diff --git a/pjnath/src/pjnath-test/ice_test.c b/pjnath/src/pjnath-test/ice_test.c
index 4f485a2..9e5e2cb 100644
--- a/pjnath/src/pjnath-test/ice_test.c
+++ b/pjnath/src/pjnath-test/ice_test.c
@@ -1,4 +1,4 @@
-/* $Id: ice_test.c 5534 2017-01-19 07:41:25Z nanang $ */
+/* $Id: ice_test.c 5655 2017-09-20 05:04:25Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -430,6 +430,9 @@ static void ice_on_ice_complete(pj_ice_strans *ice_st,
struct ice_ept *ept;
ept = (struct ice_ept*) pj_ice_strans_get_user_data(ice_st);
+ if (!ept)
+ return;
+
switch (op) {
case PJ_ICE_STRANS_OP_INIT:
ept->result.init_status = status;
diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c
index 3b187d1..9cb6360 100644
--- a/pjnath/src/pjnath/ice_session.c
+++ b/pjnath/src/pjnath/ice_session.c
@@ -1,4 +1,4 @@
-/* $Id: ice_session.c 5534 2017-01-19 07:41:25Z nanang $ */
+/* $Id: ice_session.c 5654 2017-09-20 04:34:27Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -2185,6 +2185,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
pj_ice_sess_cand *lcand;
pj_ice_sess_checklist *clist;
pj_stun_xor_mapped_addr_attr *xaddr;
+ const pj_sockaddr_t *source_addr = src_addr;
unsigned i;
PJ_UNUSED_ARG(stun_sess);
@@ -2286,8 +2287,25 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
* the response match the source IP address and port that the Binding
* Request was sent from.
*/
- if (pj_sockaddr_cmp(&check->rcand->addr, (const pj_sockaddr*)src_addr)!=0)
+ if (check->rcand->addr.addr.sa_family == pj_AF_INET() &&
+ ((pj_sockaddr *)src_addr)->addr.sa_family == pj_AF_INET6())
{
+ /* If the address family is different, we need to check
+ * whether the two addresses are equivalent (i.e. the IPv6
+ * is synthesized from IPv4).
+ */
+ pj_sockaddr synth_addr;
+
+ status = pj_sockaddr_synthesize(pj_AF_INET6(), &synth_addr,
+ &check->rcand->addr);
+ if (status == PJ_SUCCESS &&
+ pj_sockaddr_cmp(&synth_addr, src_addr) == 0)
+ {
+ source_addr = &check->rcand->addr;
+ }
+ }
+
+ if (pj_sockaddr_cmp(&check->rcand->addr, source_addr) != 0) {
status = PJNATH_EICEINSRCADDR;
LOG4((ice->obj_name,
"Check %s%s: connectivity check FAILED: source address mismatch",
@@ -2474,6 +2492,8 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
pj_stun_uint64_attr *role_attr;
pj_stun_tx_data *tdata;
pj_ice_rx_check *rcheck, tmp_rcheck;
+ const pj_sockaddr_t *source_addr = src_addr;
+ unsigned source_addr_len = src_addr_len;
pj_status_t status;
PJ_UNUSED_ARG(pkt);
@@ -2587,10 +2607,53 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
return status;
}
+ if (((pj_sockaddr *)src_addr)->addr.sa_family == pj_AF_INET6()) {
+ unsigned i;
+ unsigned transport_id = ((pj_ice_msg_data*)token)->transport_id;
+ pj_ice_sess_cand *lcand = NULL;
+
+ for (i = 0; i < ice->clist.count; ++i) {
+ pj_ice_sess_check *c = &ice->clist.checks[i];
+ if (c->lcand->comp_id == sd->comp_id &&
+ c->lcand->transport_id == transport_id)
+ {
+ lcand = c->lcand;
+ break;
+ }
+ }
+
+ if (lcand != NULL && lcand->addr.addr.sa_family == pj_AF_INET()) {
+ /* We are behind NAT64, so src_addr is a synthesized IPv6
+ * address. Instead of putting this synth IPv6 address as
+ * the XOR-MAPPED-ADDRESS, we need to find its original
+ * IPv4 address.
+ */
+ for (i = 0; i < ice->rcand_cnt; ++i) {
+ pj_sockaddr synth_addr;
+
+ if (ice->rcand[i].addr.addr.sa_family != pj_AF_INET())
+ continue;
+
+ status = pj_sockaddr_synthesize(pj_AF_INET6(), &synth_addr,
+ &ice->rcand[i].addr);
+ if (status == PJ_SUCCESS &&
+ pj_sockaddr_cmp(src_addr, &synth_addr) == 0)
+ {
+ /* We find the original IPv4 address. */
+ source_addr = &ice->rcand[i].addr;
+ source_addr_len = pj_sockaddr_get_len(source_addr);
+ break;
+ }
+ }
+ }
+ }
+
+
/* Add XOR-MAPPED-ADDRESS attribute */
status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
- PJ_TRUE, src_addr, src_addr_len);
+ PJ_TRUE, source_addr,
+ source_addr_len);
/* Create a msg_data to be associated with this response */
msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
@@ -2619,8 +2682,8 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
/* Init rcheck */
rcheck->comp_id = sd->comp_id;
rcheck->transport_id = ((pj_ice_msg_data*)token)->transport_id;
- rcheck->src_addr_len = src_addr_len;
- pj_sockaddr_cp(&rcheck->src_addr, src_addr);
+ rcheck->src_addr_len = source_addr_len;
+ pj_sockaddr_cp(&rcheck->src_addr, source_addr);
rcheck->use_candidate = (uc_attr != NULL);
rcheck->priority = prio_attr->value;
rcheck->role_attr = role_attr;
diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c
index ab34890..d53bc4d 100644
--- a/pjnath/src/pjnath/ice_strans.c
+++ b/pjnath/src/pjnath/ice_strans.c
@@ -1,4 +1,4 @@
-/* $Id: ice_strans.c 5521 2017-01-11 07:29:46Z nanang $ */
+/* $Id: ice_strans.c 5655 2017-09-20 05:04:25Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -168,6 +168,11 @@ typedef struct pj_ice_strans_comp
unsigned cand_cnt; /**< # of candidates/aliaes. */
pj_ice_sess_cand cand_list[PJ_ICE_ST_MAX_CAND]; /**< Cand array */
+ pj_bool_t ipv4_mapped; /**< Is IPv6 addr mapped to IPv4?*/
+ pj_sockaddr dst_addr; /**< Destination address */
+ pj_sockaddr synth_addr; /**< Synthesized dest address */
+ unsigned synth_addr_len;/**< Synthesized dest addr len */
+
unsigned default_cand; /**< Default candidate. */
} pj_ice_strans_comp;
@@ -231,6 +236,7 @@ PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg)
{
pj_bzero(cfg, sizeof(*cfg));
+ cfg->af = pj_AF_INET();
pj_stun_config_init(&cfg->stun_cfg, NULL, 0, NULL, NULL);
pj_ice_strans_stun_cfg_default(&cfg->stun);
pj_ice_strans_turn_cfg_default(&cfg->turn);
@@ -345,7 +351,12 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st,
for (i=0; i<comp->cand_cnt; ++i) {
if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) {
comp->default_cand = i;
- break;
+ if (ice_st->cfg.af == pj_AF_UNSPEC() ||
+ comp->cand_list[i].base_addr.addr.sa_family ==
+ ice_st->cfg.af)
+ {
+ break;
+ }
}
}
}
@@ -547,7 +558,13 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st,
comp->cand_cnt++;
/* Set default candidate to srflx */
- comp->default_cand = (unsigned)(cand - comp->cand_list);
+ if (comp->cand_list[comp->default_cand].type != PJ_ICE_CAND_TYPE_SRFLX
+ || (ice_st->cfg.af != pj_AF_UNSPEC() &&
+ comp->cand_list[comp->default_cand].base_addr.addr.sa_family
+ != ice_st->cfg.af))
+ {
+ comp->default_cand = (unsigned)(cand - comp->cand_list);
+ }
pj_log_pop_indent();
}
@@ -638,6 +655,17 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st,
pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
cand->type, &cand->base_addr);
+ /* Set default candidate with the preferred default
+ * address family
+ */
+ if (comp->ice_st->cfg.af != pj_AF_UNSPEC() &&
+ addr->addr.sa_family == comp->ice_st->cfg.af &&
+ comp->cand_list[comp->default_cand].base_addr.addr.sa_family !=
+ ice_st->cfg.af)
+ {
+ comp->default_cand = (unsigned)(cand - comp->cand_list);
+ }
+
PJ_LOG(4,(ice_st->obj_name,
"Comp %d/%d: host candidate %s (tpid=%d) added",
comp->comp_id, comp->cand_cnt-1,
@@ -840,6 +868,10 @@ static void destroy_ice_st(pj_ice_strans *ice_st)
ice_st));
pj_log_push_indent();
+ /* Reset callback and user data */
+ pj_bzero(&ice_st->cb, sizeof(ice_st->cb));
+ ice_st->user_data = NULL;
+
pj_grp_lock_acquire(ice_st->grp_lock);
if (ice_st->destroy_req) {
@@ -932,8 +964,8 @@ static void sess_init_update(pj_ice_strans *ice_st)
{
unsigned i;
- /* Ignore if init callback has been called */
- if (ice_st->cb_called)
+ /* Ignore if ICE is destroying or init callback has been called */
+ if (ice_st->destroy_req || ice_st->cb_called)
return;
/* Notify application when all candidates have been gathered */
@@ -1108,6 +1140,15 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
/* Must have address */
pj_assert(pj_sockaddr_has_addr(&cand->addr));
+ /* Skip if we are mapped to IPv4 address and this candidate
+ * is not IPv4.
+ */
+ if (comp->ipv4_mapped &&
+ cand->addr.addr.sa_family != pj_AF_INET())
+ {
+ continue;
+ }
+
/* Add the candidate */
status = pj_ice_sess_add_cand(ice_st->ice, comp->comp_id,
cand->transport_id, cand->type,
@@ -1474,9 +1515,33 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
return (status==PJ_SUCCESS||status==PJ_EPENDING) ?
PJ_SUCCESS : status;
} else {
+ const pj_sockaddr_t *dest_addr;
+ unsigned dest_addr_len;
+
+ if (comp->ipv4_mapped) {
+ if (comp->synth_addr_len == 0 ||
+ pj_sockaddr_cmp(&comp->dst_addr, dst_addr) != 0)
+ {
+ status = pj_sockaddr_synthesize(pj_AF_INET6(),
+ &comp->synth_addr,
+ dst_addr);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ pj_sockaddr_cp(&comp->dst_addr, dst_addr);
+ comp->synth_addr_len = pj_sockaddr_get_len(
+ &comp->synth_addr);
+ }
+ dest_addr = &comp->synth_addr;
+ dest_addr_len = comp->synth_addr_len;
+ } else {
+ dest_addr = dst_addr;
+ dest_addr_len = dst_addr_len;
+ }
+
status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, data,
- (unsigned)data_len, 0, dst_addr,
- dst_addr_len);
+ (unsigned)data_len, 0, dest_addr,
+ dest_addr_len);
return (status==PJ_SUCCESS||status==PJ_EPENDING) ?
PJ_SUCCESS : status;
}
@@ -1494,6 +1559,7 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
pj_time_val t;
unsigned msec;
+ pj_ice_strans_cb cb = ice_st->cb;
pj_grp_lock_add_ref(ice_st->grp_lock);
@@ -1501,7 +1567,7 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
PJ_TIME_VAL_SUB(t, ice_st->start_time);
msec = PJ_TIME_VAL_MSEC(t);
- if (ice_st->cb.on_ice_complete) {
+ if (cb.on_ice_complete) {
if (status != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(status, errmsg, sizeof(errmsg));
@@ -1574,8 +1640,7 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
PJ_ICE_STRANS_STATE_FAILED;
pj_log_push_indent();
- (*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_NEGOTIATION,
- status);
+ (*cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_NEGOTIATION, status);
pj_log_pop_indent();
}
@@ -1623,9 +1688,31 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
status = PJ_EINVALIDOP;
}
} else if (tp_typ == TP_STUN) {
+ const pj_sockaddr_t *dest_addr;
+ unsigned dest_addr_len;
+
+ if (comp->ipv4_mapped) {
+ if (comp->synth_addr_len == 0 ||
+ pj_sockaddr_cmp(&comp->dst_addr, dst_addr) != 0)
+ {
+ status = pj_sockaddr_synthesize(pj_AF_INET6(),
+ &comp->synth_addr, dst_addr);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ pj_sockaddr_cp(&comp->dst_addr, dst_addr);
+ comp->synth_addr_len = pj_sockaddr_get_len(&comp->synth_addr);
+ }
+ dest_addr = &comp->synth_addr;
+ dest_addr_len = comp->synth_addr_len;
+ } else {
+ dest_addr = dst_addr;
+ dest_addr_len = dst_addr_len;
+ }
+
status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL,
pkt, (unsigned)size, 0,
- dst_addr, dst_addr_len);
+ dest_addr, dest_addr_len);
} else {
pj_assert(!"Invalid transport ID");
status = PJ_EINVALIDOP;
@@ -1793,6 +1880,41 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
"srflx address changed";
pj_bool_t dup = PJ_FALSE;
+ if (info.mapped_addr.addr.sa_family == pj_AF_INET() &&
+ cand->base_addr.addr.sa_family == pj_AF_INET6())
+ {
+ /* We get an IPv4 mapped address for our IPv6
+ * host address.
+ */
+ comp->ipv4_mapped = PJ_TRUE;
+
+ /* Find other host candidates with the same (IPv6)
+ * address, and replace it with the new (IPv4)
+ * mapped address.
+ */
+ for (i = 0; i < comp->cand_cnt; ++i) {
+ pj_sockaddr *a1, *a2;
+
+ if (comp->cand_list[i].type != PJ_ICE_CAND_TYPE_HOST)
+ continue;
+
+ a1 = &comp->cand_list[i].addr;
+ a2 = &cand->base_addr;
+ if (pj_memcmp(pj_sockaddr_get_addr(a1),
+ pj_sockaddr_get_addr(a2),
+ pj_sockaddr_get_addr_len(a1)) == 0)
+ {
+ pj_uint16_t port = pj_sockaddr_get_port(a1);
+ pj_sockaddr_cp(a1, &info.mapped_addr);
+ if (port != pj_sockaddr_get_port(a2))
+ pj_sockaddr_set_port(a1, port);
+ pj_sockaddr_cp(&comp->cand_list[i].base_addr, a1);
+ }
+ }
+ pj_sockaddr_cp(&cand->base_addr, &info.mapped_addr);
+ pj_sockaddr_cp(&cand->rel_addr, &info.mapped_addr);
+ }
+
/* Eliminate the srflx candidate if the address is
* equal to other (host) candidates.
*/
@@ -2003,11 +2125,18 @@ static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
cand->status = PJ_SUCCESS;
/* Set default candidate to relay */
- comp->default_cand = (unsigned)(cand - comp->cand_list);
+ if (comp->cand_list[comp->default_cand].type!=PJ_ICE_CAND_TYPE_RELAYED
+ || (comp->ice_st->cfg.af != pj_AF_UNSPEC() &&
+ comp->cand_list[comp->default_cand].addr.addr.sa_family
+ != comp->ice_st->cfg.af))
+ {
+ comp->default_cand = (unsigned)(cand - comp->cand_list);
+ }
/* Prefer IPv4 relay as default candidate for better connectivity
* with IPv4 endpoints.
*/
+ /*
if (cand->addr.addr.sa_family != pj_AF_INET()) {
for (i=0; i<comp->cand_cnt; ++i) {
if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED &&
@@ -2019,6 +2148,7 @@ static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
}
}
}
+ */
PJ_LOG(4,(comp->ice_st->obj_name,
"Comp %d/%d: TURN allocation (tpid=%d) complete, "
diff --git a/pjnath/src/pjnath/nat_detect.c b/pjnath/src/pjnath/nat_detect.c
index 9bf0229..2f46e9c 100644
--- a/pjnath/src/pjnath/nat_detect.c
+++ b/pjnath/src/pjnath/nat_detect.c
@@ -1,4 +1,4 @@
-/* $Id: nat_detect.c 5523 2017-01-12 02:22:18Z nanang $ */
+/* $Id: nat_detect.c 5636 2017-08-02 02:51:59Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -88,6 +88,7 @@ typedef struct nat_detect_session
pj_ioqueue_key_t *key;
pj_sockaddr server;
pj_sockaddr *cur_server;
+ pj_sockaddr cur_addr;
pj_stun_session *stun_sess;
pj_ioqueue_op_key_t read_op, write_op;
@@ -854,11 +855,17 @@ static pj_status_t send_test(nat_detect_session *sess,
if (status != PJ_SUCCESS)
goto on_error;
- /* Configure alternate address */
- if (alt_addr)
- sess->cur_server = (pj_sockaddr*) alt_addr;
- else
+ /* Configure alternate address, synthesize it if necessary */
+ if (alt_addr) {
+ status = pj_sockaddr_synthesize(sess->server.addr.sa_family,
+ &sess->cur_addr, alt_addr);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ sess->cur_server = &sess->cur_addr;
+ } else {
sess->cur_server = &sess->server;
+ }
PJ_LOG(5,(sess->pool->obj_name,
"Performing %s to %s:%d",
diff --git a/pjnath/src/pjnath/turn_session.c b/pjnath/src/pjnath/turn_session.c
index 4022f99..43ca4d0 100644
--- a/pjnath/src/pjnath/turn_session.c
+++ b/pjnath/src/pjnath/turn_session.c
@@ -1,4 +1,4 @@
-/* $Id: turn_session.c 5534 2017-01-19 07:41:25Z nanang $ */
+/* $Id: turn_session.c 5636 2017-08-02 02:51:59Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -628,11 +628,15 @@ PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
goto on_return;
}
+ /* Add reference before async DNS resolution */
+ pj_grp_lock_add_ref(sess->grp_lock);
+
status = pj_dns_srv_resolve(domain, &res_name, default_port,
sess->pool, resolver, opt, sess,
&dns_srv_resolver_cb, NULL);
if (status != PJ_SUCCESS) {
set_state(sess, PJ_TURN_STATE_NULL);
+ pj_grp_lock_dec_ref(sess->grp_lock);
goto on_return;
}
@@ -673,7 +677,7 @@ PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
pj_sockaddr *addr = &sess->srv_addr_list[i];
pj_memcpy(addr, &ai[i].ai_addr, sizeof(pj_sockaddr));
addr->addr.sa_family = sess->af;
- addr->ipv4.sin_port = pj_htons(sess->default_port);
+ pj_sockaddr_set_port(addr, sess->default_port);
}
sess->srv_addr = &sess->srv_addr_list[0];
@@ -1725,6 +1729,7 @@ static void dns_srv_resolver_cb(void *user_data,
if (status != PJ_SUCCESS || sess->pending_destroy) {
set_state(sess, PJ_TURN_STATE_DESTROYING);
sess_shutdown(sess, status);
+ pj_grp_lock_dec_ref(sess->grp_lock);
return;
}
@@ -1773,11 +1778,13 @@ static void dns_srv_resolver_cb(void *user_data,
/* Run pending allocation */
if (sess->pending_alloc) {
- pj_status_t status;
- status = pj_turn_session_alloc(sess, NULL);
- if (status != PJ_SUCCESS)
- on_session_fail(sess, PJ_STUN_ALLOCATE_METHOD, status, NULL);
+ pj_status_t status2;
+ status2 = pj_turn_session_alloc(sess, NULL);
+ if (status2 != PJ_SUCCESS)
+ on_session_fail(sess, PJ_STUN_ALLOCATE_METHOD, status2, NULL);
}
+
+ pj_grp_lock_dec_ref(sess->grp_lock);
}
diff --git a/pjnath/src/pjnath/turn_sock.c b/pjnath/src/pjnath/turn_sock.c
index 9cbe69d..2378575 100644
--- a/pjnath/src/pjnath/turn_sock.c
+++ b/pjnath/src/pjnath/turn_sock.c
@@ -1,4 +1,4 @@
-/* $Id: turn_sock.c 5534 2017-01-19 07:41:25Z nanang $ */
+/* $Id: turn_sock.c 5596 2017-05-24 01:02:07Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -676,11 +676,14 @@ static pj_status_t turn_on_send_pkt(pj_turn_session *sess,
return PJ_EINVALIDOP;
}
- PJ_UNUSED_ARG(dst_addr);
- PJ_UNUSED_ARG(dst_addr_len);
-
- status = pj_activesock_send(turn_sock->active_sock, &turn_sock->send_key,
- pkt, &len, 0);
+ if (turn_sock->conn_type == PJ_TURN_TP_UDP) {
+ status = pj_activesock_sendto(turn_sock->active_sock,
+ &turn_sock->send_key, pkt, &len, 0,
+ dst_addr, dst_addr_len);
+ } else {
+ status = pj_activesock_send(turn_sock->active_sock,
+ &turn_sock->send_key, pkt, &len, 0);
+ }
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
show_err(turn_sock, "socket send()", status);
}
@@ -889,10 +892,15 @@ static void turn_on_state(pj_turn_session *sess,
/* Initiate non-blocking connect */
#if PJ_HAS_TCP
- status=pj_activesock_start_connect(turn_sock->active_sock,
- turn_sock->pool,
- &info.server,
- pj_sockaddr_get_len(&info.server));
+ if (turn_sock->conn_type != PJ_TURN_TP_UDP) {
+ status=pj_activesock_start_connect(
+ turn_sock->active_sock,
+ turn_sock->pool,
+ &info.server,
+ pj_sockaddr_get_len(&info.server));
+ } else {
+ status = PJ_SUCCESS;
+ }
if (status == PJ_SUCCESS) {
on_connect_complete(turn_sock->active_sock, PJ_SUCCESS);
} else if (status != PJ_EPENDING) {
diff --git a/pjsip-apps/build/Samples.mak b/pjsip-apps/build/Samples.mak
index d8769ff..d787104 100644
--- a/pjsip-apps/build/Samples.mak
+++ b/pjsip-apps/build/Samples.mak
@@ -50,8 +50,10 @@ SAMPLES := auddemo \
PJSUA2_SAMPLES := pjsua2_demo
+ifeq ($(findstring android,$(TARGET_NAME)),)
EXES := $(foreach file, $(SAMPLES), $(file)$(HOST_EXE))
PJSUA2_EXES := $(foreach file, $(PJSUA2_SAMPLES), $(file)$(HOST_EXE))
+endif
.PHONY: $(EXES)
.PHONY: $(PJSUA2_EXES)
diff --git a/pjsip-apps/build/pjsua.vcproj b/pjsip-apps/build/pjsua.vcproj
index fcde749..d62208f 100644
--- a/pjsip-apps/build/pjsua.vcproj
+++ b/pjsip-apps/build/pjsua.vcproj
@@ -11,13 +11,13 @@
Name="Win32"
/>
<Platform
- Name="Pocket PC 2003 (ARMV4)"
+ Name="x64"
/>
<Platform
- Name="Smartphone 2003 (ARMV4)"
+ Name="Pocket PC 2003 (ARMV4)"
/>
<Platform
- Name="x64"
+ Name="Smartphone 2003 (ARMV4)"
/>
<Platform
Name="Windows Mobile 6 Standard SDK (ARMV4I)"
@@ -103,12 +103,12 @@
/>
</Configuration>
<Configuration
- Name="Release|Pocket PC 2003 (ARMV4)"
+ Name="Release|x64"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -124,11 +124,12 @@
/>
<Tool
Name="VCMIDLTool"
+ TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
+ PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
/>
<Tool
@@ -142,40 +143,41 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
- OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).exe"
+ AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
+ TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
+ Name="VCManifestTool"
+ />
+ <Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
- Name="VCPostBuildEventTool"
+ Name="VCAppVerifierTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles="pjsua.bmp|$(ProjectDir)\..\src\pjsua\wm\|%CSIDL_PROGRAM_FILES%\$(ProjectName)|0;"
+ <Tool
+ Name="VCWebDeploymentTool"
/>
- <DebuggerTool
+ <Tool
+ Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
- Name="Release|Smartphone 2003 (ARMV4)"
+ Name="Debug|Win32"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -194,8 +196,8 @@
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
+ PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
/>
<Tool
@@ -209,37 +211,38 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
- OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).exe"
+ AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
+ IgnoreDefaultLibraryNames="msvcrt.lib"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
+ Name="VCManifestTool"
+ />
+ <Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
- Name="VCPostBuildEventTool"
+ Name="VCAppVerifierTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles="pjsua.bmp|$(ProjectDir)\..\src\pjsua\wm\|%CSIDL_PROGRAM_FILES%\$(ProjectName)|0;"
+ <Tool
+ Name="VCWebDeploymentTool"
/>
- <DebuggerTool
+ <Tool
+ Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
- Name="Release|x64"
+ Name="Debug|x64"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
@@ -265,6 +268,7 @@
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
+ DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -277,7 +281,8 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
+ AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
+ IgnoreDefaultLibraryNames="msvcrt.lib"
TargetMachine="17"
/>
<Tool
@@ -306,7 +311,7 @@
/>
</Configuration>
<Configuration
- Name="Debug|Win32"
+ Name="Debug-Static|Win32"
ConfigurationType="1"
InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
UseOfMFC="0"
@@ -346,7 +351,6 @@
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
- IgnoreDefaultLibraryNames="msvcrt.lib"
/>
<Tool
Name="VCALinkTool"
@@ -374,12 +378,12 @@
/>
</Configuration>
<Configuration
- Name="Debug|Pocket PC 2003 (ARMV4)"
+ Name="Debug-Static|x64"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -395,12 +399,14 @@
/>
<Tool
Name="VCMIDLTool"
+ TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
+ PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
+ DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -413,40 +419,41 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
- OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).exe"
+ AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
+ TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
+ Name="VCManifestTool"
+ />
+ <Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
- Name="VCPostBuildEventTool"
+ Name="VCAppVerifierTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles="pjsua.bmp|$(ProjectDir)\..\src\pjsua\wm\|%CSIDL_PROGRAM_FILES%\$(ProjectName)|0;"
+ <Tool
+ Name="VCWebDeploymentTool"
/>
- <DebuggerTool
+ <Tool
+ Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
- Name="Debug|Smartphone 2003 (ARMV4)"
+ Name="Release-Dynamic|Win32"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -465,8 +472,8 @@
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
+ PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
/>
<Tool
@@ -480,37 +487,37 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
- OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).exe"
+ AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
+ Name="VCManifestTool"
+ />
+ <Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
- Name="VCPostBuildEventTool"
+ Name="VCAppVerifierTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles="pjsua.bmp|$(ProjectDir)\..\src\pjsua\wm\|%CSIDL_PROGRAM_FILES%\$(ProjectName)|0;"
+ <Tool
+ Name="VCWebDeploymentTool"
/>
- <DebuggerTool
+ <Tool
+ Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
@@ -536,7 +543,6 @@
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
- DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -549,8 +555,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
- IgnoreDefaultLibraryNames="msvcrt.lib"
+ AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
TargetMachine="17"
/>
<Tool
@@ -579,9 +584,9 @@
/>
</Configuration>
<Configuration
- Name="Debug-Static|Win32"
+ Name="Debug-Dynamic|Win32"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
@@ -646,12 +651,12 @@
/>
</Configuration>
<Configuration
- Name="Debug-Static|Pocket PC 2003 (ARMV4)"
+ Name="Debug-Dynamic|x64"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -667,12 +672,14 @@
/>
<Tool
Name="VCMIDLTool"
+ TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
+ PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
+ DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -685,40 +692,41 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
- OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).exe"
+ AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
+ TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
+ Name="VCManifestTool"
+ />
+ <Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
- Name="VCPostBuildEventTool"
+ Name="VCAppVerifierTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles="pjsua.bmp|$(ProjectDir)\..\src\pjsua\wm\|%CSIDL_PROGRAM_FILES%\$(ProjectName)|0;"
+ <Tool
+ Name="VCWebDeploymentTool"
/>
- <DebuggerTool
+ <Tool
+ Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
- Name="Debug-Static|Smartphone 2003 (ARMV4)"
+ Name="Release-Static|Win32"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -737,8 +745,8 @@
/>
<Tool
Name="VCCLCompilerTool"
- ExecutionBucket="7"
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
+ PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
/>
<Tool
@@ -752,37 +760,37 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
- OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).exe"
+ AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
+ Name="VCManifestTool"
+ />
+ <Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
- Name="VCCodeSignTool"
+ Name="VCFxCopTool"
/>
<Tool
- Name="VCPostBuildEventTool"
+ Name="VCAppVerifierTool"
/>
- <DeploymentTool
- ForceDirty="-1"
- RemoteDirectory=""
- RegisterOutput="0"
- AdditionalFiles="pjsua.bmp|$(ProjectDir)\..\src\pjsua\wm\|%CSIDL_PROGRAM_FILES%\$(ProjectName)|0;"
+ <Tool
+ Name="VCWebDeploymentTool"
/>
- <DebuggerTool
+ <Tool
+ Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
- Name="Debug-Static|x64"
+ Name="Release-Static|x64"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
@@ -808,7 +816,6 @@
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
- DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -821,7 +828,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
+ AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
TargetMachine="17"
/>
<Tool
@@ -850,12 +857,12 @@
/>
</Configuration>
<Configuration
- Name="Release-Dynamic|Win32"
+ Name="Release|Pocket PC 2003 (ARMV4)"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -874,8 +881,8 @@
/>
<Tool
Name="VCCLCompilerTool"
+ ExecutionBucket="7"
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
- PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
/>
<Tool
@@ -889,35 +896,35 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
+ AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
+ OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).exe"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
- Name="VCManifestTool"
- />
- <Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
- Name="VCAppVerifierTool"
+ Name="VCPostBuildEventTool"
/>
- <Tool
- Name="VCWebDeploymentTool"
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles="pjsua.bmp|$(ProjectDir)\..\src\pjsua\wm\|%CSIDL_PROGRAM_FILES%\$(ProjectName)|0;"
/>
- <Tool
- Name="VCPostBuildEventTool"
+ <DebuggerTool
/>
</Configuration>
<Configuration
- Name="Release-Dynamic|Pocket PC 2003 (ARMV4)"
+ Name="Release|Smartphone 2003 (ARMV4)"
ConfigurationType="1"
InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
UseOfMFC="0"
@@ -957,7 +964,7 @@
<Tool
Name="VCLinkerTool"
AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
- OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).exe"
+ OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).exe"
/>
<Tool
Name="VCALinkTool"
@@ -984,9 +991,9 @@
/>
</Configuration>
<Configuration
- Name="Release-Dynamic|Smartphone 2003 (ARMV4)"
+ Name="Debug|Pocket PC 2003 (ARMV4)"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="1"
@@ -1024,7 +1031,7 @@
<Tool
Name="VCLinkerTool"
AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
- OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).exe"
+ OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).exe"
/>
<Tool
Name="VCALinkTool"
@@ -1051,12 +1058,12 @@
/>
</Configuration>
<Configuration
- Name="Release-Dynamic|x64"
+ Name="Debug|Smartphone 2003 (ARMV4)"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -1072,12 +1079,11 @@
/>
<Tool
Name="VCMIDLTool"
- TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
+ ExecutionBucket="7"
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
- PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
/>
<Tool
@@ -1091,41 +1097,40 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
- TargetMachine="17"
+ AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
+ OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).exe"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
+ Name="VCXDCMakeTool"
/>
<Tool
- Name="VCAppVerifierTool"
+ Name="VCBscMakeTool"
/>
<Tool
- Name="VCWebDeploymentTool"
+ Name="VCCodeSignTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles="pjsua.bmp|$(ProjectDir)\..\src\pjsua\wm\|%CSIDL_PROGRAM_FILES%\$(ProjectName)|0;"
+ />
+ <DebuggerTool
+ />
</Configuration>
<Configuration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Pocket PC 2003 (ARMV4)"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -1144,8 +1149,8 @@
/>
<Tool
Name="VCCLCompilerTool"
+ ExecutionBucket="7"
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
- PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
/>
<Tool
@@ -1159,37 +1164,37 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
+ AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
+ OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).exe"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
- Name="VCManifestTool"
- />
- <Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
- Name="VCAppVerifierTool"
+ Name="VCPostBuildEventTool"
/>
- <Tool
- Name="VCWebDeploymentTool"
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles="pjsua.bmp|$(ProjectDir)\..\src\pjsua\wm\|%CSIDL_PROGRAM_FILES%\$(ProjectName)|0;"
/>
- <Tool
- Name="VCPostBuildEventTool"
+ <DebuggerTool
/>
</Configuration>
<Configuration
- Name="Debug-Dynamic|Pocket PC 2003 (ARMV4)"
+ Name="Debug-Static|Smartphone 2003 (ARMV4)"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="1"
@@ -1227,7 +1232,7 @@
<Tool
Name="VCLinkerTool"
AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
- OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).exe"
+ OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).exe"
/>
<Tool
Name="VCALinkTool"
@@ -1254,9 +1259,9 @@
/>
</Configuration>
<Configuration
- Name="Debug-Dynamic|Smartphone 2003 (ARMV4)"
+ Name="Release-Dynamic|Pocket PC 2003 (ARMV4)"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="1"
@@ -1294,7 +1299,7 @@
<Tool
Name="VCLinkerTool"
AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
- OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).exe"
+ OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).exe"
/>
<Tool
Name="VCALinkTool"
@@ -1321,12 +1326,12 @@
/>
</Configuration>
<Configuration
- Name="Debug-Dynamic|x64"
+ Name="Release-Dynamic|Smartphone 2003 (ARMV4)"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-common-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -1342,14 +1347,12 @@
/>
<Tool
Name="VCMIDLTool"
- TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
+ ExecutionBucket="7"
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
- PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
- DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -1362,41 +1365,40 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
- TargetMachine="17"
+ AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
+ OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).exe"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
- Name="VCManifestTool"
- />
- <Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
- Name="VCAppVerifierTool"
+ Name="VCPostBuildEventTool"
/>
- <Tool
- Name="VCWebDeploymentTool"
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles="pjsua.bmp|$(ProjectDir)\..\src\pjsua\wm\|%CSIDL_PROGRAM_FILES%\$(ProjectName)|0;"
/>
- <Tool
- Name="VCPostBuildEventTool"
+ <DebuggerTool
/>
</Configuration>
<Configuration
- Name="Release-Static|Win32"
+ Name="Debug-Dynamic|Pocket PC 2003 (ARMV4)"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win32-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -1415,8 +1417,8 @@
/>
<Tool
Name="VCCLCompilerTool"
+ ExecutionBucket="7"
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
- PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
/>
<Tool
@@ -1430,37 +1432,37 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
+ AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
+ OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).exe"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
- Name="VCManifestTool"
- />
- <Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
- Name="VCAppVerifierTool"
+ Name="VCPostBuildEventTool"
/>
- <Tool
- Name="VCWebDeploymentTool"
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles="pjsua.bmp|$(ProjectDir)\..\src\pjsua\wm\|%CSIDL_PROGRAM_FILES%\$(ProjectName)|0;"
/>
- <Tool
- Name="VCPostBuildEventTool"
+ <DebuggerTool
/>
</Configuration>
<Configuration
- Name="Release-Static|Pocket PC 2003 (ARMV4)"
+ Name="Debug-Dynamic|Smartphone 2003 (ARMV4)"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-debug-dynamic-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-common-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="1"
@@ -1498,7 +1500,7 @@
<Tool
Name="VCLinkerTool"
AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
- OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).exe"
+ OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).exe"
/>
<Tool
Name="VCALinkTool"
@@ -1525,7 +1527,7 @@
/>
</Configuration>
<Configuration
- Name="Release-Static|Smartphone 2003 (ARMV4)"
+ Name="Release-Static|Pocket PC 2003 (ARMV4)"
ConfigurationType="1"
InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
UseOfMFC="0"
@@ -1565,7 +1567,7 @@
<Tool
Name="VCLinkerTool"
AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
- OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).exe"
+ OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003ppc-vc$(VSVer)-$(ConfigurationName).exe"
/>
<Tool
Name="VCALinkTool"
@@ -1592,12 +1594,12 @@
/>
</Configuration>
<Configuration
- Name="Release-Static|x64"
+ Name="Release-Static|Smartphone 2003 (ARMV4)"
ConfigurationType="1"
- InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-win64-release-defaults.vsprops"
+ InheritedPropertySheets="..\..\build\vs\pjproject-vs8-release-static-defaults.vsprops;..\..\build\vs\pjproject-vs8-wm2003-release-defaults.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -1613,12 +1615,11 @@
/>
<Tool
Name="VCMIDLTool"
- TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
+ ExecutionBucket="7"
AdditionalIncludeDirectories="../../pjsip/include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include,../../pjnath/include"
- PreprocessorDefinitions="_CONSOLE;"
PrecompiledHeaderFile=""
/>
<Tool
@@ -1632,32 +1633,31 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Iphlpapi.lib dsound.lib dxguid.lib netapi32.lib mswsock.lib ws2_32.lib odbc32.lib odbccp32.lib ole32.lib user32.lib gdi32.lib advapi32.lib"
- TargetMachine="17"
+ AdditionalDependencies="aygshell.lib coredll.lib winsock.lib ws2.lib"
+ OutputFile="..\bin\$(ProjectName)-$(TargetCPU)-wm2003sp-vc$(VSVer)-$(ConfigurationName).exe"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
- Name="VCManifestTool"
- />
- <Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
- Name="VCFxCopTool"
+ Name="VCCodeSignTool"
/>
<Tool
- Name="VCAppVerifierTool"
+ Name="VCPostBuildEventTool"
/>
- <Tool
- Name="VCWebDeploymentTool"
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles="pjsua.bmp|$(ProjectDir)\..\src\pjsua\wm\|%CSIDL_PROGRAM_FILES%\$(ProjectName)|0;"
/>
- <Tool
- Name="VCPostBuildEventTool"
+ <DebuggerTool
/>
</Configuration>
<Configuration
@@ -3301,8 +3301,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|Pocket PC 2003 (ARMV4)"
- ExcludedFromBuild="true"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3311,8 +3310,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|Smartphone 2003 (ARMV4)"
- ExcludedFromBuild="true"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3321,7 +3319,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3330,7 +3328,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3339,8 +3337,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Pocket PC 2003 (ARMV4)"
- ExcludedFromBuild="true"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3349,8 +3346,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Smartphone 2003 (ARMV4)"
- ExcludedFromBuild="true"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3359,7 +3355,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3368,7 +3364,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3377,8 +3373,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Pocket PC 2003 (ARMV4)"
- ExcludedFromBuild="true"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3387,8 +3382,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Smartphone 2003 (ARMV4)"
- ExcludedFromBuild="true"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3397,7 +3391,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Release-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3406,7 +3400,8 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Release|Pocket PC 2003 (ARMV4)"
+ ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
@@ -3415,7 +3410,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Pocket PC 2003 (ARMV4)"
+ Name="Release|Smartphone 2003 (ARMV4)"
ExcludedFromBuild="true"
>
<Tool
@@ -3425,7 +3420,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Smartphone 2003 (ARMV4)"
+ Name="Debug|Pocket PC 2003 (ARMV4)"
ExcludedFromBuild="true"
>
<Tool
@@ -3435,7 +3430,8 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug|Smartphone 2003 (ARMV4)"
+ ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
@@ -3444,7 +3440,8 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Pocket PC 2003 (ARMV4)"
+ ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
@@ -3453,7 +3450,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Pocket PC 2003 (ARMV4)"
+ Name="Debug-Static|Smartphone 2003 (ARMV4)"
ExcludedFromBuild="true"
>
<Tool
@@ -3463,7 +3460,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Smartphone 2003 (ARMV4)"
+ Name="Release-Dynamic|Pocket PC 2003 (ARMV4)"
ExcludedFromBuild="true"
>
<Tool
@@ -3473,7 +3470,8 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Dynamic|Smartphone 2003 (ARMV4)"
+ ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
@@ -3482,7 +3480,8 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Dynamic|Pocket PC 2003 (ARMV4)"
+ ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
@@ -3491,7 +3490,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Pocket PC 2003 (ARMV4)"
+ Name="Debug-Dynamic|Smartphone 2003 (ARMV4)"
ExcludedFromBuild="true"
>
<Tool
@@ -3501,7 +3500,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Smartphone 2003 (ARMV4)"
+ Name="Release-Static|Pocket PC 2003 (ARMV4)"
ExcludedFromBuild="true"
>
<Tool
@@ -3511,7 +3510,8 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|x64"
+ Name="Release-Static|Smartphone 2003 (ARMV4)"
+ ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
@@ -3861,7 +3861,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|Pocket PC 2003 (ARMV4)"
+ Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3870,7 +3870,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|Smartphone 2003 (ARMV4)"
+ Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3879,7 +3879,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release|x64"
+ Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3888,7 +3888,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Win32"
+ Name="Debug-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3897,7 +3897,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Pocket PC 2003 (ARMV4)"
+ Name="Debug-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3906,7 +3906,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|Smartphone 2003 (ARMV4)"
+ Name="Release-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3915,7 +3915,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug|x64"
+ Name="Release-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3924,7 +3924,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Win32"
+ Name="Debug-Dynamic|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3933,7 +3933,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Pocket PC 2003 (ARMV4)"
+ Name="Debug-Dynamic|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3942,7 +3942,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|Smartphone 2003 (ARMV4)"
+ Name="Release-Static|Win32"
>
<Tool
Name="VCCLCompilerTool"
@@ -3951,7 +3951,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Static|x64"
+ Name="Release-Static|x64"
>
<Tool
Name="VCCLCompilerTool"
@@ -3960,7 +3960,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Win32"
+ Name="Release|Pocket PC 2003 (ARMV4)"
>
<Tool
Name="VCCLCompilerTool"
@@ -3969,7 +3969,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Pocket PC 2003 (ARMV4)"
+ Name="Release|Smartphone 2003 (ARMV4)"
>
<Tool
Name="VCCLCompilerTool"
@@ -3978,7 +3978,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|Smartphone 2003 (ARMV4)"
+ Name="Debug|Pocket PC 2003 (ARMV4)"
>
<Tool
Name="VCCLCompilerTool"
@@ -3987,7 +3987,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Dynamic|x64"
+ Name="Debug|Smartphone 2003 (ARMV4)"
>
<Tool
Name="VCCLCompilerTool"
@@ -3996,7 +3996,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Win32"
+ Name="Debug-Static|Pocket PC 2003 (ARMV4)"
>
<Tool
Name="VCCLCompilerTool"
@@ -4005,7 +4005,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Pocket PC 2003 (ARMV4)"
+ Name="Debug-Static|Smartphone 2003 (ARMV4)"
>
<Tool
Name="VCCLCompilerTool"
@@ -4014,7 +4014,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|Smartphone 2003 (ARMV4)"
+ Name="Release-Dynamic|Pocket PC 2003 (ARMV4)"
>
<Tool
Name="VCCLCompilerTool"
@@ -4023,7 +4023,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Debug-Dynamic|x64"
+ Name="Release-Dynamic|Smartphone 2003 (ARMV4)"
>
<Tool
Name="VCCLCompilerTool"
@@ -4032,7 +4032,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Win32"
+ Name="Debug-Dynamic|Pocket PC 2003 (ARMV4)"
>
<Tool
Name="VCCLCompilerTool"
@@ -4041,7 +4041,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Pocket PC 2003 (ARMV4)"
+ Name="Debug-Dynamic|Smartphone 2003 (ARMV4)"
>
<Tool
Name="VCCLCompilerTool"
@@ -4050,7 +4050,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|Smartphone 2003 (ARMV4)"
+ Name="Release-Static|Pocket PC 2003 (ARMV4)"
>
<Tool
Name="VCCLCompilerTool"
@@ -4059,7 +4059,7 @@
/>
</FileConfiguration>
<FileConfiguration
- Name="Release-Static|x64"
+ Name="Release-Static|Smartphone 2003 (ARMV4)"
>
<Tool
Name="VCCLCompilerTool"
diff --git a/pjsip-apps/build/pjsua.vcxproj b/pjsip-apps/build/pjsua.vcxproj
index 69202b4..8dc6d28 100644
--- a/pjsip-apps/build/pjsua.vcxproj
+++ b/pjsip-apps/build/pjsua.vcxproj
@@ -364,7 +364,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
- <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)"</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>msvcrt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
<TargetMachine>MachineX64</TargetMachine>
</Link>
@@ -376,7 +376,7 @@
<PrecompiledHeaderOutputFile />
</ClCompile>
<Link>
- <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)"</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Static|ARM'">
@@ -398,7 +398,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
- <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)"</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
@@ -409,7 +409,7 @@
<PrecompiledHeaderOutputFile />
</ClCompile>
<Link>
- <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)"</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dynamic|ARM'">
@@ -430,7 +430,7 @@
<PrecompiledHeaderOutputFile />
</ClCompile>
<Link>
- <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)"</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
@@ -441,7 +441,7 @@
<PrecompiledHeaderOutputFile />
</ClCompile>
<Link>
- <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)"</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dynamic|ARM'">
@@ -463,7 +463,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
- <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)"</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
@@ -474,7 +474,7 @@
<PrecompiledHeaderOutputFile />
</ClCompile>
<Link>
- <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)"</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-Static|ARM'">
@@ -495,7 +495,7 @@
<PrecompiledHeaderOutputFile />
</ClCompile>
<Link>
- <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)"</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(API_Family)'=='WinDesktop'">Iphlpapi.lib;dsound.lib;dxguid.lib;netapi32.lib;mswsock.lib;ws2_32.lib;odbc32.lib;odbccp32.lib;ole32.lib;user32.lib;gdi32.lib;advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
diff --git a/pjsip-apps/src/3rdparty_media_sample/alt_pjsua_aud.c b/pjsip-apps/src/3rdparty_media_sample/alt_pjsua_aud.c
index 5e0709b..c3c0f0b 100644
--- a/pjsip-apps/src/3rdparty_media_sample/alt_pjsua_aud.c
+++ b/pjsip-apps/src/3rdparty_media_sample/alt_pjsua_aud.c
@@ -1,4 +1,4 @@
-/* $Id: alt_pjsua_aud.c 4793 2014-03-14 04:09:50Z bennylp $ */
+/* $Id: alt_pjsua_aud.c 5657 2017-09-25 02:18:57Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -255,7 +255,9 @@ static void timer_to_send_aud_rtcp(void *user_data)
void pjsua_aud_stop_stream(pjsua_call_media *call_med)
{
/* Detach our RTP/RTCP callbacks from transport */
- pjmedia_transport_detach(call_med->tp, call_med);
+ if (call_med->tp) {
+ pjmedia_transport_detach(call_med->tp, call_med);
+ }
/* TODO: destroy your audio stream here */
}
diff --git a/pjsip-apps/src/pjsua/android/gradle/wrapper/gradle-wrapper.jar b/pjsip-apps/src/pjsua/android/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 13372ae..0000000
Binary files a/pjsip-apps/src/pjsua/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/pjsip-apps/src/pjsua/bb10/assets/images/teluu-logo.png b/pjsip-apps/src/pjsua/bb10/assets/images/teluu-logo.png
deleted file mode 100644
index 97fadb5..0000000
Binary files a/pjsip-apps/src/pjsua/bb10/assets/images/teluu-logo.png and /dev/null differ
diff --git a/pjsip-apps/src/pjsua/ios/ipjsua.xcodeproj/project.pbxproj b/pjsip-apps/src/pjsua/ios/ipjsua.xcodeproj/project.pbxproj
index 1780f86..67c116f 100644
--- a/pjsip-apps/src/pjsua/ios/ipjsua.xcodeproj/project.pbxproj
+++ b/pjsip-apps/src/pjsua/ios/ipjsua.xcodeproj/project.pbxproj
@@ -37,6 +37,10 @@
3AF0582216F050780046B835 /* ipjsuaViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF0582116F050780046B835 /* ipjsuaViewController.m */; };
3AF0582516F050780046B835 /* ipjsuaViewController_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3AF0582316F050780046B835 /* ipjsuaViewController_iPhone.xib */; };
3AF0582816F050780046B835 /* ipjsuaViewController_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3AF0582616F050780046B835 /* ipjsuaViewController_iPad.xib */; };
+ 3AF253001EFBD15E00213893 /* libyuv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AF252FF1EFBD15E00213893 /* libyuv.a */; };
+ 3AF253021EFBD36E00213893 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AF253011EFBD36E00213893 /* VideoToolbox.framework */; };
+ 7485A6AF1F09AAE500122F1A /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 7485A6AE1F09AAE500122F1A /* Reachability.m */; };
+ 7485A6B11F09B2D500122F1A /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7485A6B01F09B2D500122F1A /* SystemConfiguration.framework */; };
E5E991E61B67A45500017E67 /* libg7221codec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5E991D41B67A45500017E67 /* libg7221codec.a */; };
E5E991E71B67A45500017E67 /* libgsmcodec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5E991D51B67A45500017E67 /* libgsmcodec.a */; };
E5E991E81B67A45500017E67 /* libilbccodec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5E991D61B67A45500017E67 /* libilbccodec.a */; };
@@ -93,6 +97,12 @@
3AF0582116F050780046B835 /* ipjsuaViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ipjsuaViewController.m; sourceTree = "<group>"; };
3AF0582416F050780046B835 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ipjsuaViewController_iPhone.xib; sourceTree = "<group>"; };
3AF0582716F050780046B835 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ipjsuaViewController_iPad.xib; sourceTree = "<group>"; };
+ 3AF252FF1EFBD15E00213893 /* libyuv.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libyuv.a; sourceTree = "<group>"; };
+ 3AF253011EFBD36E00213893 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
+ 741C73BA1F0E64AF00887FB6 /* libopenh264.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libopenh264.a; path = "../../../../../../../../../../openh264-1.6.0/lib_armv7/lib/libopenh264.a"; sourceTree = "<group>"; };
+ 7485A6AD1F09AAE500122F1A /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = "<group>"; };
+ 7485A6AE1F09AAE500122F1A /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
+ 7485A6B01F09B2D500122F1A /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
E5E991D41B67A45500017E67 /* libg7221codec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libg7221codec.a; sourceTree = "<group>"; };
E5E991D51B67A45500017E67 /* libgsmcodec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgsmcodec.a; sourceTree = "<group>"; };
E5E991D61B67A45500017E67 /* libilbccodec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libilbccodec.a; sourceTree = "<group>"; };
@@ -118,6 +128,8 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 7485A6B11F09B2D500122F1A /* SystemConfiguration.framework in Frameworks */,
+ 3AF253021EFBD36E00213893 /* VideoToolbox.framework in Frameworks */,
3AB0EC581DA76B39008A0F62 /* libc++.tbd in Frameworks */,
E5E991EC1B67A45500017E67 /* libpjmedia-codec.a in Frameworks */,
3AA31FF818F3FB4C00112C3D /* CFNetwork.framework in Frameworks */,
@@ -126,6 +138,7 @@
3AA31FFB18F3FB4C00112C3D /* CoreImage.framework in Frameworks */,
E5E991F41B67A45500017E67 /* libpjsua2.a in Frameworks */,
3AA31FF618F3FB4C00112C3D /* AudioToolbox.framework in Frameworks */,
+ 3AF253001EFBD15E00213893 /* libyuv.a in Frameworks */,
3AA31FF718F3FB4C00112C3D /* AVFoundation.framework in Frameworks */,
3AA31FFE18F3FB4C00112C3D /* OpenGLES.framework in Frameworks */,
3AA3200018F3FB4C00112C3D /* Foundation.framework in Frameworks */,
@@ -190,6 +203,9 @@
3AF0580716F050770046B835 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 741C73BA1F0E64AF00887FB6 /* libopenh264.a */,
+ 7485A6B01F09B2D500122F1A /* SystemConfiguration.framework */,
+ 3AF253011EFBD36E00213893 /* VideoToolbox.framework */,
3AB0EC571DA76B39008A0F62 /* libc++.tbd */,
3AA31FE918F3FB4C00112C3D /* AudioToolbox.framework */,
3AA31FEA18F3FB4C00112C3D /* AVFoundation.framework */,
@@ -216,6 +232,8 @@
3AF0581816F050780046B835 /* ipjsuaAppDelegate.m */,
3AF0582016F050780046B835 /* ipjsuaViewController.h */,
3AF0582116F050780046B835 /* ipjsuaViewController.m */,
+ 7485A6AD1F09AAE500122F1A /* Reachability.h */,
+ 7485A6AE1F09AAE500122F1A /* Reachability.m */,
3AF0582316F050780046B835 /* ipjsuaViewController_iPhone.xib */,
3AF0582616F050780046B835 /* ipjsuaViewController_iPad.xib */,
3AF0580F16F050780046B835 /* Supporting Files */,
@@ -260,6 +278,7 @@
E5E991E31B67A45500017E67 /* libresample.a */,
E5E991E41B67A45500017E67 /* libspeex.a */,
E5E991E51B67A45500017E67 /* libsrtp.a */,
+ 3AF252FF1EFBD15E00213893 /* libyuv.a */,
);
name = Libraries;
sourceTree = "<group>";
@@ -345,6 +364,7 @@
3ADCCD2E172E40120007BE8E /* pjsua_app_common.c in Sources */,
3ADCCD2F172E40120007BE8E /* pjsua_app_config.c in Sources */,
3ADCCD30172E40120007BE8E /* pjsua_app_legacy.c in Sources */,
+ 7485A6AF1F09AAE500122F1A /* Reachability.m in Sources */,
3ADCCD31172E40120007BE8E /* pjsua_app.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
diff --git a/pjsip-apps/src/pjsua/ios/ipjsua/Default-568h at 2x.png b/pjsip-apps/src/pjsua/ios/ipjsua/Default-568h at 2x.png
deleted file mode 100644
index 0891b7a..0000000
Binary files a/pjsip-apps/src/pjsua/ios/ipjsua/Default-568h at 2x.png and /dev/null differ
diff --git a/pjsip-apps/src/pjsua/ios/ipjsua/Default.png b/pjsip-apps/src/pjsua/ios/ipjsua/Default.png
deleted file mode 100644
index 4c8ca6f..0000000
Binary files a/pjsip-apps/src/pjsua/ios/ipjsua/Default.png and /dev/null differ
diff --git a/pjsip-apps/src/pjsua/ios/ipjsua/Default at 2x.png b/pjsip-apps/src/pjsua/ios/ipjsua/Default at 2x.png
deleted file mode 100644
index 35b84cf..0000000
Binary files a/pjsip-apps/src/pjsua/ios/ipjsua/Default at 2x.png and /dev/null differ
diff --git a/pjsip-apps/src/pjsua/ios/ipjsua/Reachability.h b/pjsip-apps/src/pjsua/ios/ipjsua/Reachability.h
new file mode 100644
index 0000000..50c048c
--- /dev/null
+++ b/pjsip-apps/src/pjsua/ios/ipjsua/Reachability.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ See LICENSE.txt for this sample’s licensing information
+
+ Abstract:
+ Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
+ */
+
+#import <Foundation/Foundation.h>
+#import <SystemConfiguration/SystemConfiguration.h>
+#import <netinet/in.h>
+
+
+typedef enum : NSInteger {
+ NotReachable = 0,
+ ReachableViaWiFi,
+ ReachableViaWWAN
+} NetworkStatus;
+
+#pragma mark IPv6 Support
+//Reachability fully support IPv6. For full details, see ReadMe.md.
+
+
+extern NSString *kReachabilityChangedNotification;
+
+
+ at interface Reachability : NSObject
+
+/*!
+ * Use to check the reachability of a given host name.
+ */
++ (instancetype)reachabilityWithHostName:(NSString *)hostName;
+
+/*!
+ * Use to check the reachability of a given IP address.
+ */
++ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress;
+
+/*!
+ * Checks whether the default route is available. Should be used by applications that do not connect to a particular host.
+ */
++ (instancetype)reachabilityForInternetConnection;
+
+
+#pragma mark reachabilityForLocalWiFi
+//reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information.
+//+ (instancetype)reachabilityForLocalWiFi;
+
+/*!
+ * Start listening for reachability notifications on the current run loop.
+ */
+- (BOOL)startNotifier;
+- (void)stopNotifier;
+
+- (NetworkStatus)currentReachabilityStatus;
+
+/*!
+ * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand.
+ */
+- (BOOL)connectionRequired;
+
+ at end
+
+
diff --git a/pjsip-apps/src/pjsua/ios/ipjsua/Reachability.m b/pjsip-apps/src/pjsua/ios/ipjsua/Reachability.m
new file mode 100644
index 0000000..f081a16
--- /dev/null
+++ b/pjsip-apps/src/pjsua/ios/ipjsua/Reachability.m
@@ -0,0 +1,242 @@
+/*
+ Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ See LICENSE.txt for this sample’s licensing information
+
+ Abstract:
+ Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
+ */
+
+#import <arpa/inet.h>
+#import <ifaddrs.h>
+#import <netdb.h>
+#import <sys/socket.h>
+#import <netinet/in.h>
+
+#import <CoreFoundation/CoreFoundation.h>
+
+#import "Reachability.h"
+
+#pragma mark IPv6 Support
+//Reachability fully support IPv6. For full details, see ReadMe.md.
+
+
+NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";
+
+
+#pragma mark - Supporting functions
+
+#define kShouldPrintReachabilityFlags 1
+
+static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
+{
+#if kShouldPrintReachabilityFlags
+
+ NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
+ (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
+ (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
+
+ (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
+ (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
+ (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
+ (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
+ (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
+ (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
+ (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
+ comment
+ );
+#endif
+}
+
+
+static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
+{
+#pragma unused (target, flags)
+ NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
+ NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
+
+ Reachability* noteObject = (__bridge Reachability *)info;
+ // Post a notification to notify the client that the network reachability changed.
+ [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
+}
+
+
+#pragma mark - Reachability implementation
+
+ at implementation Reachability
+{
+ SCNetworkReachabilityRef _reachabilityRef;
+}
+
++ (instancetype)reachabilityWithHostName:(NSString *)hostName
+{
+ Reachability* returnValue = NULL;
+ SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
+ if (reachability != NULL)
+ {
+ returnValue= [[self alloc] init];
+ if (returnValue != NULL)
+ {
+ returnValue->_reachabilityRef = reachability;
+ }
+ else {
+ CFRelease(reachability);
+ }
+ }
+ return returnValue;
+}
+
+
++ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress
+{
+ SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
+
+ Reachability* returnValue = NULL;
+
+ if (reachability != NULL)
+ {
+ returnValue = [[self alloc] init];
+ if (returnValue != NULL)
+ {
+ returnValue->_reachabilityRef = reachability;
+ }
+ else {
+ CFRelease(reachability);
+ }
+ }
+ return returnValue;
+}
+
+
++ (instancetype)reachabilityForInternetConnection
+{
+ struct sockaddr_in zeroAddress;
+ bzero(&zeroAddress, sizeof(zeroAddress));
+ zeroAddress.sin_len = sizeof(zeroAddress);
+ zeroAddress.sin_family = AF_INET;
+
+ return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
+}
+
+#pragma mark reachabilityForLocalWiFi
+//reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information.
+//+ (instancetype)reachabilityForLocalWiFi
+
+
+
+#pragma mark - Start and stop notifier
+
+- (BOOL)startNotifier
+{
+ BOOL returnValue = NO;
+ SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
+
+ if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
+ {
+ if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
+ {
+ returnValue = YES;
+ }
+ }
+
+ return returnValue;
+}
+
+
+- (void)stopNotifier
+{
+ if (_reachabilityRef != NULL)
+ {
+ SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+ }
+}
+
+
+- (void)dealloc
+{
+ [self stopNotifier];
+ if (_reachabilityRef != NULL)
+ {
+ CFRelease(_reachabilityRef);
+ }
+}
+
+
+#pragma mark - Network Flag Handling
+
+- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
+{
+ PrintReachabilityFlags(flags, "networkStatusForFlags");
+ if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
+ {
+ // The target host is not reachable.
+ return NotReachable;
+ }
+
+ NetworkStatus returnValue = NotReachable;
+
+ if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
+ {
+ /*
+ If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
+ */
+ returnValue = ReachableViaWiFi;
+ }
+
+ if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
+ (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
+ {
+ /*
+ ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
+ */
+
+ if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
+ {
+ /*
+ ... and no [user] intervention is needed...
+ */
+ returnValue = ReachableViaWiFi;
+ }
+ }
+
+ if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
+ {
+ /*
+ ... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
+ */
+ returnValue = ReachableViaWWAN;
+ }
+
+ return returnValue;
+}
+
+
+- (BOOL)connectionRequired
+{
+ NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
+ SCNetworkReachabilityFlags flags;
+
+ if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
+ {
+ return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
+ }
+
+ return NO;
+}
+
+
+- (NetworkStatus)currentReachabilityStatus
+{
+ NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
+ NetworkStatus returnValue = NotReachable;
+ SCNetworkReachabilityFlags flags;
+
+ if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
+ {
+ returnValue = [self networkStatusForFlags:flags];
+ }
+
+ return returnValue;
+}
+
+
+ at end
diff --git a/pjsip-apps/src/pjsua/ios/ipjsua/ipjsua-Info.plist b/pjsip-apps/src/pjsua/ios/ipjsua/ipjsua-Info.plist
index abd5717..d0d19bd 100644
--- a/pjsip-apps/src/pjsua/ios/ipjsua/ipjsua-Info.plist
+++ b/pjsip-apps/src/pjsua/ios/ipjsua/ipjsua-Info.plist
@@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>NSCameraUsageDescription</key>
+ <string>Camera permission required</string>
+ <key>NSMicrophoneUsageDescription</key>
+ <string>Mic permission required</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
diff --git a/pjsip-apps/src/pjsua/ios/ipjsua/ipjsuaAppDelegate.m b/pjsip-apps/src/pjsua/ios/ipjsua/ipjsuaAppDelegate.m
index 416796d..7d54ab5 100644
--- a/pjsip-apps/src/pjsua/ios/ipjsua/ipjsuaAppDelegate.m
+++ b/pjsip-apps/src/pjsua/ios/ipjsua/ipjsuaAppDelegate.m
@@ -27,6 +27,7 @@
#include "../../pjsua_app_config.h"
#import "ipjsuaViewController.h"
+#import "Reachability.h"
@implementation ipjsuaAppDelegate
@@ -39,6 +40,46 @@ static pjsua_app_cfg_t app_cfg;
static bool isShuttingDown;
static char **restartArgv;
static int restartArgc;
+Reachability *internetReach;
+
+- (void) updateWithReachability: (Reachability *)curReach
+{
+ NetworkStatus netStatus = [curReach currentReachabilityStatus];
+ BOOL connectionRequired = [curReach connectionRequired];
+ switch (netStatus) {
+ case NotReachable:
+ PJ_LOG(3,("", "Access Not Available.."));
+ connectionRequired= NO;
+ break;
+ case ReachableViaWiFi:
+ PJ_LOG(3,("", "Reachable WiFi.."));
+ break;
+ case ReachableViaWWAN:
+ PJ_LOG(3,("", "Reachable WWAN.."));
+ break;
+ }
+ if (connectionRequired) {
+ PJ_LOG(3,("", "Connection Required"));
+ }
+}
+
+/* Called by Reachability whenever status changes. */
+- (void)reachabilityChanged: (NSNotification *)note
+{
+ Reachability* curReach = [note object];
+ NSParameterAssert([curReach isKindOfClass: [Reachability class]]);
+ PJ_LOG(3,("", "reachability changed.."));
+ [self updateWithReachability: curReach];
+
+ if ([curReach currentReachabilityStatus] != NotReachable &&
+ ![curReach connectionRequired])
+ {
+ pjsua_ip_change_param param;
+ pjsua_ip_change_param_default(¶m);
+ pjsua_handle_ip_change(¶m);
+ }
+}
+
void displayLog(const char *msg, int len)
{
@@ -155,6 +196,17 @@ static void pjsuaOnAppConfigCb(pjsua_app_config *cfg)
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
+ /* Observe the kNetworkReachabilityChangedNotification. When that
+ * notification is posted, the method "reachabilityChanged" will be called.
+ */
+ [[NSNotificationCenter defaultCenter] addObserver: self
+ selector: @selector(reachabilityChanged:)
+ name: kReachabilityChangedNotification object: nil];
+
+ internetReach = [Reachability reachabilityForInternetConnection];
+ [internetReach startNotifier];
+ [self updateWithReachability: internetReach];
+
app = self;
/* Start pjsua app thread */
@@ -271,7 +323,9 @@ pj_bool_t showNotification(pjsua_call_id call_id)
*/
alert.alertAction = @"Activate app";
- [[UIApplication sharedApplication] presentLocalNotificationNow:alert];
+ dispatch_async(dispatch_get_main_queue(),
+ ^{[[UIApplication sharedApplication]
+ presentLocalNotificationNow:alert];});
}
return PJ_FALSE;
diff --git a/pjsip-apps/src/pjsua/pjsua_app_cli.c b/pjsip-apps/src/pjsua/pjsua_app_cli.c
index 82e3ea1..f833c29 100644
--- a/pjsip-apps/src/pjsua/pjsua_app_cli.c
+++ b/pjsip-apps/src/pjsua/pjsua_app_cli.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_app_cli.c 5542 2017-01-23 06:15:14Z ming $ */
+/* $Id: pjsua_app_cli.c 5659 2017-09-25 02:58:42Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -38,6 +38,7 @@
#define CMD_NETWORK 900
#define CMD_QUIT 110
#define CMD_RESTART 120
+#define CMD_HANDLE_IP_CHANGE 130
/* call level 2 command */
#define CMD_CALL_NEW ((CMD_CALL*10)+1)
@@ -2174,7 +2175,7 @@ static pj_status_t cmd_video_acc_handler(pj_cli_cmd_val *cval)
case CMD_VIDEO_ACC_CAP_ID:
case CMD_VIDEO_ACC_REN_ID:
{
- int dev = pj_strtol(&cval->argv[1]);
+ int dev = (int)pj_strtol(&cval->argv[1]);
if (cmd_id == CMD_VIDEO_ACC_CAP_ID)
acc_cfg.vid_cap_dev = dev;
@@ -2203,7 +2204,7 @@ static pj_status_t cmd_enable_vid_rx(pj_cli_cmd_val *cval)
pjsua_call_vid_strm_op_param_default(¶m);
- param.med_idx = pj_strtol(&cval->argv[2]);
+ param.med_idx = (int)pj_strtol(&cval->argv[2]);
if (pjsua_call_get_stream_info(current_call, param.med_idx, &si) ||
si.type != PJMEDIA_TYPE_VIDEO)
{
@@ -2231,7 +2232,7 @@ static pj_status_t cmd_enable_vid_tx(pj_cli_cmd_val *cval)
pjsua_call_vid_strm_op_param_default(¶m);
- param.med_idx = pj_strtol(&cval->argv[2]);
+ param.med_idx = (int)pj_strtol(&cval->argv[2]);
status = pjsua_call_set_vid_strm(current_call, op, ¶m);
return status;
@@ -2246,7 +2247,8 @@ static pj_status_t cmd_enable_vid_stream(pj_cli_cmd_val *cval,
pjsua_call_vid_strm_op_param_default(¶m);
- param.med_idx = cval->argc > 1 ? pj_strtol(&cval->argv[1]) : -1;
+ param.med_idx = cval->argc > 1 ?
+ (int)pj_strtol(&cval->argv[1]) : -1;
param.dir = PJMEDIA_DIR_ENCODING_DECODING;
return pjsua_call_set_vid_strm(current_call, op, ¶m);
}
@@ -2256,9 +2258,11 @@ static pj_status_t cmd_set_cap_dev_id(pj_cli_cmd_val *cval)
pjsua_call_vid_strm_op_param param;
pjsua_call_vid_strm_op_param_default(¶m);
- param.med_idx = cval->argc > 1? pj_strtol(&cval->argv[1]) : -1;
- param.cap_dev = cval->argc > 2? pj_strtol(&cval->argv[2]) :
- PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
+ param.med_idx = cval->argc > 1?
+ (int)pj_strtol(&cval->argv[1]) : -1;
+ param.cap_dev = cval->argc > 2?
+ (int)pj_strtol(&cval->argv[2]) :
+ PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
return pjsua_call_set_vid_strm(current_call,
PJSUA_CALL_VID_STRM_CHANGE_CAP_DEV,
@@ -2279,7 +2283,7 @@ static pj_status_t cmd_vid_device_refresh()
static pj_status_t cmd_vid_device_preview(pj_cli_cmd_val *cval)
{
- int dev_id = pj_strtol(&cval->argv[2]);
+ int dev_id = (int)pj_strtol(&cval->argv[2]);
pj_bool_t on = (pj_ansi_strnicmp(cval->argv[1].ptr, "On", 2) == 0);
if (on) {
@@ -2339,7 +2343,7 @@ static pj_status_t cmd_vid_codec_list()
static pj_status_t cmd_set_vid_codec_prio(pj_cli_cmd_val *cval)
{
- int prio = pj_strtol(&cval->argv[2]);
+ int prio = (int)pj_strtol(&cval->argv[2]);
pj_status_t status;
status = pjsua_vid_codec_set_priority(&cval->argv[1], (pj_uint8_t)prio);
@@ -2355,8 +2359,8 @@ static pj_status_t cmd_set_vid_codec_fps(pj_cli_cmd_val *cval)
int M, N;
pj_status_t status;
- M = pj_strtol(&cval->argv[2]);
- N = pj_strtol(&cval->argv[3]);
+ M = (int)pj_strtol(&cval->argv[2]);
+ N = (int)pj_strtol(&cval->argv[3]);
status = pjsua_vid_codec_get_param(&cval->argv[1], &cp);
if (status == PJ_SUCCESS) {
cp.enc_fmt.det.vid.fps.num = M;
@@ -2375,8 +2379,8 @@ static pj_status_t cmd_set_vid_codec_bitrate(pj_cli_cmd_val *cval)
int M, N;
pj_status_t status;
- M = pj_strtol(&cval->argv[2]);
- N = pj_strtol(&cval->argv[3]);
+ M = (int)pj_strtol(&cval->argv[2]);
+ N = (int)pj_strtol(&cval->argv[3]);
status = pjsua_vid_codec_get_param(&cval->argv[1], &cp);
if (status == PJ_SUCCESS) {
cp.enc_fmt.det.vid.avg_bps = M * 1000;
@@ -2395,8 +2399,8 @@ static pj_status_t cmd_set_vid_codec_size(pj_cli_cmd_val *cval)
int M, N;
pj_status_t status;
- M = pj_strtol(&cval->argv[2]);
- N = pj_strtol(&cval->argv[3]);
+ M = (int)pj_strtol(&cval->argv[2]);
+ N = (int)pj_strtol(&cval->argv[3]);
status = pjsua_vid_codec_get_param(&cval->argv[1], &cp);
if (status == PJ_SUCCESS) {
cp.enc_fmt.det.vid.size.w = M;
@@ -2437,27 +2441,27 @@ static pj_status_t cmd_arrange_vid_win()
static pj_status_t cmd_show_vid_win(pj_cli_cmd_val *cval, pj_bool_t show)
{
- pjsua_vid_win_id wid = pj_strtol(&cval->argv[1]);
+ pjsua_vid_win_id wid = (int)pj_strtol(&cval->argv[1]);
return pjsua_vid_win_set_show(wid, show);
}
static pj_status_t cmd_move_vid_win(pj_cli_cmd_val *cval)
{
- pjsua_vid_win_id wid = pj_strtol(&cval->argv[1]);
+ pjsua_vid_win_id wid = (int)pj_strtol(&cval->argv[1]);
pjmedia_coord pos;
- pos.x = pj_strtol(&cval->argv[2]);
- pos.y = pj_strtol(&cval->argv[3]);
+ pos.x = (int)pj_strtol(&cval->argv[2]);
+ pos.y = (int)pj_strtol(&cval->argv[3]);
return pjsua_vid_win_set_pos(wid, &pos);
}
static pj_status_t cmd_resize_vid_win(pj_cli_cmd_val *cval)
{
- pjsua_vid_win_id wid = pj_strtol(&cval->argv[1]);
+ pjsua_vid_win_id wid = (int)pj_strtol(&cval->argv[1]);
pjmedia_rect_size size;
- size.w = pj_strtol(&cval->argv[2]);
- size.h = pj_strtol(&cval->argv[3]);
+ size.w = (int)pj_strtol(&cval->argv[2]);
+ size.h = (int)pj_strtol(&cval->argv[3]);
return pjsua_vid_win_set_size(wid, &size);
}
@@ -2584,6 +2588,17 @@ static pj_status_t cmd_quit_handler(pj_cli_cmd_val *cval)
return PJ_SUCCESS;
}
+static pj_status_t cmd_ip_change_handler(pj_cli_cmd_val *cval)
+{
+ pjsua_ip_change_param param;
+ PJ_UNUSED_ARG(cval);
+
+ pjsua_ip_change_param_default(¶m);
+ pjsua_handle_ip_change(¶m);
+
+ return PJ_SUCCESS;
+}
+
/*
* Syntax error handler for parser.
*/
@@ -2899,7 +2914,7 @@ static pj_status_t add_config_command(pj_cli_t *c)
}
#if PJSUA_HAS_VIDEO
-static pj_status_t add_video_command(pj_cli_t *cli)
+static pj_status_t add_video_command(pj_cli_t *c)
{
char* video_command =
"<CMD name='video' id='600' desc='Video commands'>"
@@ -3038,7 +3053,7 @@ static pj_status_t add_video_command(pj_cli_t *cli)
"</CMD>";
pj_str_t xml = pj_str(video_command);
- return pj_cli_add_cmd_from_xml(cli, NULL,
+ return pj_cli_add_cmd_from_xml(c, NULL,
&xml, cmd_video_handler,
NULL, get_choice_value);
}
@@ -3065,11 +3080,15 @@ static pj_status_t add_other_command(pj_cli_t *c)
" <ARG name='options4' type='string' desc='Options' optional='1'/>"
"</CMD>";
+ char* ip_change_command =
+ "<CMD name='ip_change' id='130' desc='Handle IP change'/>";
+
pj_status_t status;
pj_str_t sleep_xml = pj_str(sleep_command);
pj_str_t network_xml = pj_str(network_command);
pj_str_t shutdown_xml = pj_str(shutdown_command);
pj_str_t restart_xml = pj_str(restart_command);
+ pj_str_t ip_change_xml = pj_str(ip_change_command);
status = pj_cli_add_cmd_from_xml(c, NULL,
&sleep_xml, cmd_sleep_handler,
@@ -3094,6 +3113,13 @@ static pj_status_t add_other_command(pj_cli_t *c)
&restart_xml, cmd_restart_handler,
NULL, NULL);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ status = pj_cli_add_cmd_from_xml(c, NULL,
+ &ip_change_xml, cmd_ip_change_handler,
+ NULL, NULL);
+
return status;
}
diff --git a/pjsip-apps/src/pjsua/pjsua_app_common.c b/pjsip-apps/src/pjsua/pjsua_app_common.c
index 0cebce1..a5ffe04 100644
--- a/pjsip-apps/src/pjsua/pjsua_app_common.c
+++ b/pjsip-apps/src/pjsua/pjsua_app_common.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_app_common.c 5461 2016-10-14 04:53:07Z ming $ */
+/* $Id: pjsua_app_common.c 5626 2017-07-18 00:43:43Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -290,7 +290,7 @@ void vid_print_dev(int id, const pjmedia_vid_dev_info *vdi, const char *title)
if (vdi->caps & (1 << i)) {
const char *capname = pjmedia_vid_dev_cap_name(1 << i, NULL);
if (capname) {
- int tmp_len = strlen(capname);
+ int tmp_len = (int)strlen(capname);
if ((int)sizeof(capnames) - st_len <= tmp_len)
break;
@@ -308,7 +308,7 @@ void vid_print_dev(int id, const pjmedia_vid_dev_info *vdi, const char *title)
const pjmedia_video_format_info *vfi =
pjmedia_get_video_format_info(NULL, vdi->fmt[i].id);
if (vfi) {
- int tmp_len = strlen(vfi->name);
+ int tmp_len = (int)strlen(vfi->name);
if ((int)sizeof(formats) - st_len <= tmp_len) {
st_len = -1;
break;
diff --git a/pjsip-apps/src/pjsua/winrt/cli/comp/pjsua_cli_uwp_comp.vcxproj b/pjsip-apps/src/pjsua/winrt/cli/comp/pjsua_cli_uwp_comp.vcxproj
index c58969d..7a94ba7 100644
--- a/pjsip-apps/src/pjsua/winrt/cli/comp/pjsua_cli_uwp_comp.vcxproj
+++ b/pjsip-apps/src/pjsua/winrt/cli/comp/pjsua_cli_uwp_comp.vcxproj
@@ -271,7 +271,7 @@
</ItemDefinitionGroup>
<!--Don't build this project unless it's for UWP-->
<Import Condition="'$(API_Family)'=='UWP'" Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
- <Import Condition="'$(API_Family)'!='UWP'" Project="..\..\..\..\..\..\..\build\vs\pjproject-vs14-build-targets.targets" />
+ <Import Condition="'$(API_Family)'!='UWP'" Project="..\..\..\..\..\..\build\vs\pjproject-vs14-build-targets.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
diff --git a/pjsip-apps/src/pjsua/winrt/cli/uwp/Assets/teluu-logo.png b/pjsip-apps/src/pjsua/winrt/cli/uwp/Assets/teluu-logo.png
deleted file mode 100644
index 97fadb5..0000000
Binary files a/pjsip-apps/src/pjsua/winrt/cli/uwp/Assets/teluu-logo.png and /dev/null differ
diff --git a/pjsip-apps/src/pjsua/winrt/cli/wp8/Assets/teluu-logo.png b/pjsip-apps/src/pjsua/winrt/cli/wp8/Assets/teluu-logo.png
deleted file mode 100644
index 97fadb5..0000000
Binary files a/pjsip-apps/src/pjsua/winrt/cli/wp8/Assets/teluu-logo.png and /dev/null differ
diff --git a/pjsip-apps/src/pjsua/winrt/cli/wp8/pjsua_cli_wp8.csproj b/pjsip-apps/src/pjsua/winrt/cli/wp8/pjsua_cli_wp8.csproj
index f08a562..c99304d 100644
--- a/pjsip-apps/src/pjsua/winrt/cli/wp8/pjsua_cli_wp8.csproj
+++ b/pjsip-apps/src/pjsua/winrt/cli/wp8/pjsua_cli_wp8.csproj
@@ -64,7 +64,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' Or '$(Configuration)|$(Platform)' == 'Release|Win32' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>Bin\x86\Release</OutputPath>
@@ -74,6 +74,27 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>Bin\x64\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>Bin\x64\Release</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|ARM' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
@@ -123,12 +144,16 @@
<ItemGroup>
<Content Include="Assets\teluu-logo.png" />
</ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\comp\pjsua_cli_wp8_comp.vcxproj">
- <Project>{e75efd41-c7f5-44c8-8ff1-a310d920989d}</Project>
- <Name>pjsua_cli_wp8_comp</Name>
- </ProjectReference>
- </ItemGroup>
+ <Choose>
+ <When Condition="'$(API_Family)'=='WinPhone8'">
+ <ItemGroup>
+ <ProjectReference Include="..\comp\pjsua_cli_wp8_comp.vcxproj">
+ <Project>{e75efd41-c7f5-44c8-8ff1-a310d920989d}</Project>
+ <Name>pjsua_cli_wp8_comp</Name>
+ </ProjectReference>
+ </ItemGroup>
+ </When>
+ </Choose>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).$(TargetFrameworkVersion).Overrides.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
diff --git a/pjsip-apps/src/pjsua/winrt/gui/uwp/VoipBackEnd/ApiLock.cpp b/pjsip-apps/src/pjsua/winrt/gui/uwp/VoipBackEnd/ApiLock.cpp
deleted file mode 100644
index c081223..0000000
--- a/pjsip-apps/src/pjsua/winrt/gui/uwp/VoipBackEnd/ApiLock.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- Copyright (c) 2012 Microsoft Corporation. All rights reserved.
- Use of this sample source code is subject to the terms of the Microsoft license
- agreement under which you licensed this sample source code and is provided AS-IS.
- If you did not accept the terms of the license agreement, you are not authorized
- to use this sample source code. For the terms of the license, please see the
- license agreement between you and Microsoft.
-
-*/
-#include "pch.h"
-#include "ApiLock.h"
-
-namespace VoipBackEnd
-{
- // A mutex used to protect objects accessible from the API surface exposed by this DLL
- std::recursive_mutex g_apiLock;
-}
-
diff --git a/pjsip-apps/src/pjsua/winrt/gui/uwp/VoipBackEnd/ApiLock.h b/pjsip-apps/src/pjsua/winrt/gui/uwp/VoipBackEnd/ApiLock.h
deleted file mode 100644
index 9994930..0000000
--- a/pjsip-apps/src/pjsua/winrt/gui/uwp/VoipBackEnd/ApiLock.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- Copyright (c) 2012 Microsoft Corporation. All rights reserved.
- Use of this sample source code is subject to the terms of the Microsoft license
- agreement under which you licensed this sample source code and is provided AS-IS.
- If you did not accept the terms of the license agreement, you are not authorized
- to use this sample source code. For the terms of the license, please see the
- license agreement between you and Microsoft.
-
- To see all Code Samples for Windows Phone, visit http://go.microsoft.com/fwlink/?LinkID=219604
-
-*/
-#pragma once
-#include <mutex>
-
-
-namespace VoipBackEnd
-{
- // A mutex used to protect objects accessible from the API surface exposed by this DLL
- extern std::recursive_mutex g_apiLock;
-}
-
diff --git a/pjsip-apps/src/pygui/account.py b/pjsip-apps/src/pygui/account.py
index 1bc91b4..728420e 100644
--- a/pjsip-apps/src/pygui/account.py
+++ b/pjsip-apps/src/pygui/account.py
@@ -1,4 +1,4 @@
-# $Id: account.py 4704 2014-01-16 05:30:46Z ming $
+# $Id: account.py 5638 2017-08-02 09:45:09Z riza $
#
# pjsua Python GUI Demo
#
@@ -20,13 +20,13 @@
#
import sys
if sys.version_info[0] >= 3: # Python 3
- import tkinter as tk
- from tkinter import ttk
- from tkinter import messagebox as msgbox
+ import tkinter as tk
+ from tkinter import ttk
+ from tkinter import messagebox as msgbox
else:
- import Tkinter as tk
- import tkMessageBox as msgbox
- import ttk
+ import Tkinter as tk
+ import tkMessageBox as msgbox
+ import ttk
import random
import pjsua2 as pj
@@ -36,204 +36,206 @@ import application
import call
import chat as ch
+write=sys.stdout.write
+
# Account class
class Account(pj.Account):
- """
- High level Python Account object, derived from pjsua2's Account object.
- """
- def __init__(self, app):
- pj.Account.__init__(self)
- self.app = app
- self.randId = random.randint(1, 9999)
- self.cfg = pj.AccountConfig()
- self.cfgChanged = False
- self.buddyList = []
- self.chatList = []
- self.deleting = False
-
- def findChat(self, uri_str):
- uri = ch.ParseSipUri(uri_str)
- if not uri: return None
-
- for chat in self.chatList:
- if chat.isUriParticipant(uri) and chat.isPrivate():
- return chat
- return None
-
- def newChat(self, uri_str):
- uri = ch.ParseSipUri(uri_str)
- if not uri: return None
-
- chat = ch.Chat(self.app, self, uri)
- self.chatList.append(chat)
- self.app.updateWindowMenu()
- return chat
-
- def statusText(self):
- status = '?'
- if self.isValid():
- ai = self.getInfo()
- if ai.regLastErr:
- status = self.app.ep.utilStrError(ai.regLastErr)
- elif ai.regIsActive:
- if ai.onlineStatus:
- if len(ai.onlineStatusText):
- status = ai.onlineStatusText
- else:
- status = "Online"
- else:
- status = "Registered"
- else:
- if ai.regIsConfigured:
- if ai.regStatus/100 == 2:
- status = "Unregistered"
- else:
- status = ai.regStatusText
- else:
- status = "Doesn't register"
- else:
- status = '- not created -'
- return status
-
- def onRegState(self, prm):
- self.app.updateAccount(self)
-
- def onIncomingCall(self, prm):
- c = call.Call(self, call_id=prm.callId)
- call_prm = pj.CallOpParam()
- call_prm.statusCode = 180
- c.answer(call_prm)
- ci = c.getInfo()
- msg = "Incoming call for account '%s'" % self.cfg.idUri
- if msgbox.askquestion(msg, "Accept call from '%s'?" % (ci.remoteUri), default=msgbox.YES) == u'yes':
- call_prm.statusCode = 200
- c.answer(call_prm)
-
- # find/create chat instance
- chat = self.findChat(ci.remoteUri)
- if not chat: chat = self.newChat(ci.remoteUri)
-
- chat.showWindow()
- chat.registerCall(ci.remoteUri, c)
- chat.updateCallState(c, ci)
- else:
- c.hangup(call_prm)
-
- def onInstantMessage(self, prm):
- chat = self.findChat(prm.fromUri)
- if not chat: chat = self.newChat(prm.fromUri)
-
- chat.showWindow()
- chat.addMessage(prm.fromUri, prm.msgBody)
-
- def onInstantMessageStatus(self, prm):
- if prm.code/100 == 2: return
-
- chat = self.findChat(prm.toUri)
- if not chat:
- print "=== IM status to '%s' cannot find chat" % prm.toUri
- return
-
- chat.addMessage(None, "Failed sending message to '%s': %s" % (prm.toUri, prm.reason))
-
- def onTypingIndication(self, prm):
- chat = self.findChat(prm.fromUri)
- if not chat:
- print "=== Incoming typing indication from '%s' cannot find chat" % prm.fromUri
- return
-
- chat.setTypingIndication(prm.fromUri, prm.isTyping)
-
-
+ """
+ High level Python Account object, derived from pjsua2's Account object.
+ """
+ def __init__(self, app):
+ pj.Account.__init__(self)
+ self.app = app
+ self.randId = random.randint(1, 9999)
+ self.cfg = pj.AccountConfig()
+ self.cfgChanged = False
+ self.buddyList = []
+ self.chatList = []
+ self.deleting = False
+
+ def findChat(self, uri_str):
+ uri = ch.ParseSipUri(uri_str)
+ if not uri: return None
+
+ for chat in self.chatList:
+ if chat.isUriParticipant(uri) and chat.isPrivate():
+ return chat
+ return None
+
+ def newChat(self, uri_str):
+ uri = ch.ParseSipUri(uri_str)
+ if not uri: return None
+
+ chat = ch.Chat(self.app, self, uri)
+ self.chatList.append(chat)
+ self.app.updateWindowMenu()
+ return chat
+
+ def statusText(self):
+ status = '?'
+ if self.isValid():
+ ai = self.getInfo()
+ if ai.regLastErr:
+ status = self.app.ep.utilStrError(ai.regLastErr)
+ elif ai.regIsActive:
+ if ai.onlineStatus:
+ if len(ai.onlineStatusText):
+ status = ai.onlineStatusText
+ else:
+ status = "Online"
+ else:
+ status = "Registered"
+ else:
+ if ai.regIsConfigured:
+ if ai.regStatus/100 == 2:
+ status = "Unregistered"
+ else:
+ status = ai.regStatusText
+ else:
+ status = "Doesn't register"
+ else:
+ status = '- not created -'
+ return status
+
+ def onRegState(self, prm):
+ self.app.updateAccount(self)
+
+ def onIncomingCall(self, prm):
+ c = call.Call(self, call_id=prm.callId)
+ call_prm = pj.CallOpParam()
+ call_prm.statusCode = 180
+ c.answer(call_prm)
+ ci = c.getInfo()
+ msg = "Incoming call for account '%s'" % self.cfg.idUri
+ if msgbox.askquestion(msg, "Accept call from '%s'?" % (ci.remoteUri), default=msgbox.YES) == u'yes':
+ call_prm.statusCode = 200
+ c.answer(call_prm)
+
+ # find/create chat instance
+ chat = self.findChat(ci.remoteUri)
+ if not chat: chat = self.newChat(ci.remoteUri)
+
+ chat.showWindow()
+ chat.registerCall(ci.remoteUri, c)
+ chat.updateCallState(c, ci)
+ else:
+ c.hangup(call_prm)
+
+ def onInstantMessage(self, prm):
+ chat = self.findChat(prm.fromUri)
+ if not chat: chat = self.newChat(prm.fromUri)
+
+ chat.showWindow()
+ chat.addMessage(prm.fromUri, prm.msgBody)
+
+ def onInstantMessageStatus(self, prm):
+ if prm.code/100 == 2: return
+
+ chat = self.findChat(prm.toUri)
+ if not chat:
+ write("=== IM status to " + prm.toUri + "cannot find chat\r\n")
+ return
+
+ chat.addMessage(None, "Failed sending message to '%s': %s" % (prm.toUri, prm.reason))
+
+ def onTypingIndication(self, prm):
+ chat = self.findChat(prm.fromUri)
+ if not chat:
+ write("=== Incoming typing indication from " + prm.fromUri + "cannot find chat\r\n")
+ return
+
+ chat.setTypingIndication(prm.fromUri, prm.isTyping)
+
+
# Account frame, to list accounts
class AccountListFrame(ttk.Frame):
- """
- This implements a Frame which contains account list and buttons to operate
- on them (Add, Modify, Delete, etc.).
- """
- def __init__(self, parent, app, acc_list = []):
- ttk.Frame.__init__(self, parent, name='acclist')
- self.app = app
- self.accList = acc_list
- self.accDeletedList = []
- self.pack(expand='yes', fill='both')
- self._createWidgets()
- for acc in self.accList:
- self._showAcc(acc)
-
- def _createWidgets(self):
- self.tv = ttk.Treeview(self, columns=('ID', 'Registrar', 'Default'), selectmode='browse')
- self.tv.heading('#0', text='Priority')
- self.tv.heading(0, text='ID')
- self.tv.heading(1, text='Registrar')
- self.tv.heading(2, text='Default?')
- self.tv.column('#0', width=60)
- self.tv.column(0, width=300)
- self.tv.column(1, width=200)
- self.tv.column(2, width=60)
- self.tv.grid(column=0, row=0, rowspan=4, padx=5, pady=5)
-
- ttk.Button(self, text='Add..', command=self._onBtnAdd).grid(column=1, row=0, padx=5)
- ttk.Button(self, text='Settings..', command=self._onBtnSettings).grid(column=1, row=1)
- ttk.Button(self, text='Set Default', command=self._onBtnSetDefault).grid(column=1, row=2)
- ttk.Button(self, text='Delete..', command=self._onBtnDelete).grid(column=1, row=3)
-
- def _showAcc(self, acc):
- is_default = 'Yes' if acc.isValid() and acc.isDefault() else ''
- values = (acc.cfg.idUri, acc.cfg.regConfig.registrarUri, is_default)
- self.tv.insert('', 0, str(acc.randId), open=True, text=str(acc.cfg.priority), values=values)
-
- def updateAccount(self, acc):
- is_default = 'Yes' if acc.isValid() and acc.isDefault() else ''
- values = (acc.cfg.idUri, acc.cfg.regConfig.registrarUri, is_default)
- self.tv.item(str(acc.randId), text=str(acc.cfg.priority), values=values)
-
- def _getSelectedAcc(self):
- items = self.tv.selection()
- if not items:
- return None
- iid = int(items[0])
- return [acc for acc in self.accList if acc.randId==iid][0]
-
- def _onBtnAdd(self):
- cfg = pj.AccountConfig()
- dlg = accountsetting.Dialog(self.master, cfg)
- if dlg.doModal():
- acc = Account(self.app)
- acc.cfg = cfg
- self._showAcc(acc)
- self.accList.append(acc)
- self.cfgChanged = True
-
- def _onBtnSettings(self):
- acc = self._getSelectedAcc()
- if not acc:
- return
- dlg = accountsetting.Dialog(self.master, acc.cfg)
- if dlg.doModal():
- self.updateAccount(acc)
- self.cfgChanged = True
-
- def _onBtnDelete(self):
- acc = self._getSelectedAcc()
- if not acc:
- return
- msg = "Do you really want to delete account '%s'" % acc.cfg.idUri
- if msgbox.askquestion('Delete account?', msg, default=msgbox.NO) != u'yes':
- return
- self.accList.remove(acc)
- self.accDeletedList.append(acc)
- self.tv.delete( (str(acc.randId),) )
-
- def _onBtnSetDefault(self):
- acc = self._getSelectedAcc()
- if not acc:
- return
- if acc.isValid():
- acc.setDefault()
- for acc in self.accList:
- self.updateAccount(acc)
-
-
+ """
+ This implements a Frame which contains account list and buttons to operate
+ on them (Add, Modify, Delete, etc.).
+ """
+ def __init__(self, parent, app, acc_list = []):
+ ttk.Frame.__init__(self, parent, name='acclist')
+ self.app = app
+ self.accList = acc_list
+ self.accDeletedList = []
+ self.pack(expand='yes', fill='both')
+ self._createWidgets()
+ for acc in self.accList:
+ self._showAcc(acc)
+
+ def _createWidgets(self):
+ self.tv = ttk.Treeview(self, columns=('ID', 'Registrar', 'Default'), selectmode='browse')
+ self.tv.heading('#0', text='Priority')
+ self.tv.heading(0, text='ID')
+ self.tv.heading(1, text='Registrar')
+ self.tv.heading(2, text='Default?')
+ self.tv.column('#0', width=60)
+ self.tv.column(0, width=300)
+ self.tv.column(1, width=200)
+ self.tv.column(2, width=60)
+ self.tv.grid(column=0, row=0, rowspan=4, padx=5, pady=5)
+
+ ttk.Button(self, text='Add..', command=self._onBtnAdd).grid(column=1, row=0, padx=5)
+ ttk.Button(self, text='Settings..', command=self._onBtnSettings).grid(column=1, row=1)
+ ttk.Button(self, text='Set Default', command=self._onBtnSetDefault).grid(column=1, row=2)
+ ttk.Button(self, text='Delete..', command=self._onBtnDelete).grid(column=1, row=3)
+
+ def _showAcc(self, acc):
+ is_default = 'Yes' if acc.isValid() and acc.isDefault() else ''
+ values = (acc.cfg.idUri, acc.cfg.regConfig.registrarUri, is_default)
+ self.tv.insert('', 0, str(acc.randId), open=True, text=str(acc.cfg.priority), values=values)
+
+ def updateAccount(self, acc):
+ is_default = 'Yes' if acc.isValid() and acc.isDefault() else ''
+ values = (acc.cfg.idUri, acc.cfg.regConfig.registrarUri, is_default)
+ self.tv.item(str(acc.randId), text=str(acc.cfg.priority), values=values)
+
+ def _getSelectedAcc(self):
+ items = self.tv.selection()
+ if not items:
+ return None
+ iid = int(items[0])
+ return [acc for acc in self.accList if acc.randId==iid][0]
+
+ def _onBtnAdd(self):
+ cfg = pj.AccountConfig()
+ dlg = accountsetting.Dialog(self.master, cfg)
+ if dlg.doModal():
+ acc = Account(self.app)
+ acc.cfg = cfg
+ self._showAcc(acc)
+ self.accList.append(acc)
+ self.cfgChanged = True
+
+ def _onBtnSettings(self):
+ acc = self._getSelectedAcc()
+ if not acc:
+ return
+ dlg = accountsetting.Dialog(self.master, acc.cfg)
+ if dlg.doModal():
+ self.updateAccount(acc)
+ self.cfgChanged = True
+
+ def _onBtnDelete(self):
+ acc = self._getSelectedAcc()
+ if not acc:
+ return
+ msg = "Do you really want to delete account '%s'" % acc.cfg.idUri
+ if msgbox.askquestion('Delete account?', msg, default=msgbox.NO) != u'yes':
+ return
+ self.accList.remove(acc)
+ self.accDeletedList.append(acc)
+ self.tv.delete( (str(acc.randId),) )
+
+ def _onBtnSetDefault(self):
+ acc = self._getSelectedAcc()
+ if not acc:
+ return
+ if acc.isValid():
+ acc.setDefault()
+ for acc in self.accList:
+ self.updateAccount(acc)
+
+
if __name__ == '__main__':
- application.main()
+ application.main()
diff --git a/pjsip-apps/src/pygui/accountsetting.py b/pjsip-apps/src/pygui/accountsetting.py
index 92cf2c4..26e4afc 100644
--- a/pjsip-apps/src/pygui/accountsetting.py
+++ b/pjsip-apps/src/pygui/accountsetting.py
@@ -1,4 +1,4 @@
-# $Id: accountsetting.py 4704 2014-01-16 05:30:46Z ming $
+# $Id: accountsetting.py 5638 2017-08-02 09:45:09Z riza $
#
# pjsua Python GUI Demo
#
@@ -20,350 +20,350 @@
#
import sys
if sys.version_info[0] >= 3: # Python 3
- import tkinter as tk
- from tkinter import ttk
- from tkinter import messagebox as msgbox
+ import tkinter as tk
+ from tkinter import ttk
+ from tkinter import messagebox as msgbox
else:
- import Tkinter as tk
- import tkMessageBox as msgbox
- import ttk
+ import Tkinter as tk
+ import tkMessageBox as msgbox
+ import ttk
import pjsua2 as pj
import endpoint
import application
class Dialog(tk.Toplevel):
- """
- This implements account settings dialog to manipulate account settings.
- """
- def __init__(self, parent, cfg):
- tk.Toplevel.__init__(self, parent)
- self.transient(parent)
- self.parent = parent
- self.geometry("+100+100")
- self.title('Account settings')
-
- self.frm = ttk.Frame(self)
- self.frm.pack(expand='yes', fill='both')
-
- self.isOk = False
- self.cfg = cfg
-
- self.createWidgets()
-
- def doModal(self):
- if self.parent:
- self.parent.wait_window(self)
- else:
- self.wait_window(self)
- return self.isOk
-
- def createWidgets(self):
- # The notebook
- self.frm.rowconfigure(0, weight=1)
- self.frm.rowconfigure(1, weight=0)
- self.frm.columnconfigure(0, weight=1)
- self.frm.columnconfigure(1, weight=1)
- self.wTab = ttk.Notebook(self.frm)
- self.wTab.grid(column=0, row=0, columnspan=2, padx=10, pady=10, ipadx=20, ipady=20, sticky=tk.N+tk.S+tk.W+tk.E)
-
- # Main buttons
- btnOk = ttk.Button(self.frm, text='Ok', command=self.onOk)
- btnOk.grid(column=0, row=1, sticky=tk.E, padx=20, pady=10)
- btnCancel = ttk.Button(self.frm, text='Cancel', command=self.onCancel)
- btnCancel.grid(column=1, row=1, sticky=tk.W, padx=20, pady=10)
-
- # Tabs
- self.createBasicTab()
- self.createSipTab()
- self.createMediaTab()
- self.createMediaNatTab()
-
- def createBasicTab(self):
- # Prepare the variables to set/receive values from GUI
- self.cfgPriority = tk.IntVar(value=self.cfg.priority)
- self.cfgAccId = tk.StringVar(value=self.cfg.idUri)
- self.cfgRegistrar = tk.StringVar(value=self.cfg.regConfig.registrarUri)
- self.cfgRegisterOnAdd = tk.IntVar(value=self.cfg.regConfig.registerOnAdd)
- self.cfgUsername = tk.StringVar()
- self.cfgPassword = tk.StringVar()
- if len(self.cfg.sipConfig.authCreds):
- self.cfgUsername.set( self.cfg.sipConfig.authCreds[0].username )
- self.cfgPassword.set( self.cfg.sipConfig.authCreds[0].data )
- self.cfgProxy = tk.StringVar()
- if len(self.cfg.sipConfig.proxies):
- self.cfgProxy.set( self.cfg.sipConfig.proxies[0] )
-
- # Build the tab page
- frm = ttk.Frame(self.frm)
- frm.columnconfigure(0, weight=1)
- frm.columnconfigure(1, weight=2)
- row = 0
- ttk.Label(frm, text='Priority:').grid(row=row, column=0, sticky=tk.E, pady=2)
- tk.Spinbox(frm, from_=0, to=9, textvariable=self.cfgPriority, width=2).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Label(frm, text='ID (URI):').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Entry(frm, textvariable=self.cfgAccId, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Label(frm, text='Registrar URI:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Entry(frm, textvariable=self.cfgRegistrar, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Checkbutton(frm, text='Register on add', variable=self.cfgRegisterOnAdd).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Label(frm, text='Optional proxy URI:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Entry(frm, textvariable=self.cfgProxy, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Label(frm, text='Auth username:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Entry(frm, textvariable=self.cfgUsername, width=16).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Label(frm, text='Password:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Entry(frm, textvariable=self.cfgPassword, show='*', width=16).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
-
- self.wTab.add(frm, text='Basic Settings')
-
-
- def createSipTab(self):
- # Prepare the variables to set/receive values from GUI
- self.cfgPrackUse = tk.IntVar(value=self.cfg.callConfig.prackUse)
- self.cfgTimerUse = tk.IntVar(value=self.cfg.callConfig.timerUse)
- self.cfgTimerExpires = tk.IntVar(value=self.cfg.callConfig.timerSessExpiresSec)
- self.cfgPublish = tk.BooleanVar(value=self.cfg.presConfig.publishEnabled)
- self.cfgMwiEnabled = tk.BooleanVar(value=self.cfg.mwiConfig.enabled)
- self.cfgEnableContactRewrite = tk.BooleanVar(value=self.cfg.natConfig.contactRewriteUse != 0)
- self.cfgEnableViaRewrite = tk.BooleanVar(value=self.cfg.natConfig.viaRewriteUse != 0)
- self.cfgEnableSdpRewrite = tk.BooleanVar(value=self.cfg.natConfig.sdpNatRewriteUse != 0)
- self.cfgEnableSipOutbound = tk.BooleanVar(value=self.cfg.natConfig.sipOutboundUse != 0)
- self.cfgKaInterval = tk.IntVar(value=self.cfg.natConfig.udpKaIntervalSec)
-
- # Build the tab page
- frm = ttk.Frame(self.frm)
- frm.columnconfigure(0, weight=1)
- frm.columnconfigure(1, weight=2)
- row = 0
- ttk.Label(frm, text='100rel/PRACK:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Radiobutton(frm, text='Only offer PRACK', value=pj.PJSUA_100REL_NOT_USED, variable=self.cfgPrackUse).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Radiobutton(frm, text='Offer and use if remote supports', value=pj.PJSUA_100REL_OPTIONAL, variable=self.cfgPrackUse).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Radiobutton(frm, text='Required', value=pj.PJSUA_100REL_MANDATORY, variable=self.cfgPrackUse).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Label(frm, text='Session Timer:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Radiobutton(frm, text='Not offered', value=pj.PJSUA_SIP_TIMER_INACTIVE, variable=self.cfgTimerUse).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Radiobutton(frm, text='Optional', value=pj.PJSUA_SIP_TIMER_OPTIONAL, variable=self.cfgTimerUse).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Radiobutton(frm, text='Required', value=pj.PJSUA_SIP_TIMER_REQUIRED, variable=self.cfgTimerUse).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Radiobutton(frm, text="Always use", value=pj.PJSUA_SIP_TIMER_ALWAYS, variable=self.cfgTimerUse).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Label(frm, text='Session Timer Expiration:').grid(row=row, column=0, sticky=tk.E, pady=2)
- tk.Spinbox(frm, from_=90, to=7200, textvariable=self.cfgTimerExpires, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
- ttk.Label(frm, text='(seconds)').grid(row=row, column=1, sticky=tk.E)
- row += 1
- ttk.Label(frm, text='Presence:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Checkbutton(frm, text='Enable PUBLISH', variable=self.cfgPublish).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Label(frm, text='Message Waiting Indication:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Checkbutton(frm, text='Enable MWI', variable=self.cfgMwiEnabled).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Label(frm, text='NAT Traversal:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Checkbutton(frm, text='Enable Contact Rewrite', variable=self.cfgEnableContactRewrite).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Checkbutton(frm, text='Enable Via Rewrite', variable=self.cfgEnableViaRewrite).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Checkbutton(frm, text='Enable SDP IP Address Rewrite', variable=self.cfgEnableSdpRewrite).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Checkbutton(frm, text='Enable SIP Outbound Extension', variable=self.cfgEnableSipOutbound).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Label(frm, text='UDP Keep-Alive Interval:').grid(row=row, column=0, sticky=tk.E, pady=2)
- tk.Spinbox(frm, from_=0, to=3600, textvariable=self.cfgKaInterval, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
- ttk.Label(frm, text='(seconds) Zero to disable.').grid(row=row, column=1, sticky=tk.E)
-
-
- self.wTab.add(frm, text='SIP Features')
-
- def createMediaTab(self):
- # Prepare the variables to set/receive values from GUI
- self.cfgMedPort = tk.IntVar(value=self.cfg.mediaConfig.transportConfig.port)
- self.cfgMedPortRange = tk.IntVar(value=self.cfg.mediaConfig.transportConfig.portRange)
- self.cfgMedLockCodec = tk.BooleanVar(value=self.cfg.mediaConfig.lockCodecEnabled)
- self.cfgMedSrtp = tk.IntVar(value=self.cfg.mediaConfig.srtpUse)
- self.cfgMedSrtpSecure = tk.IntVar(value=self.cfg.mediaConfig.srtpSecureSignaling)
- self.cfgMedIpv6 = tk.BooleanVar(value=self.cfg.mediaConfig.ipv6Use==pj.PJSUA_IPV6_ENABLED)
-
- # Build the tab page
- frm = ttk.Frame(self.frm)
- frm.columnconfigure(0, weight=1)
- frm.columnconfigure(1, weight=21)
- row = 0
- ttk.Label(frm, text='Secure RTP (SRTP):').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Radiobutton(frm, text='Disable', value=pj.PJMEDIA_SRTP_DISABLED, variable=self.cfgMedSrtp).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Radiobutton(frm, text='Mandatory', value=pj.PJMEDIA_SRTP_MANDATORY, variable=self.cfgMedSrtp).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Radiobutton(frm, text='Optional (non-standard)', value=pj.PJMEDIA_SRTP_OPTIONAL, variable=self.cfgMedSrtp).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Label(frm, text='SRTP signaling:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Radiobutton(frm, text='Does not require secure signaling', value=0, variable=self.cfgMedSrtpSecure).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Radiobutton(frm, text='Require secure next hop (TLS)', value=1, variable=self.cfgMedSrtpSecure).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Radiobutton(frm, text='Require secure end-to-end (SIPS)', value=2, variable=self.cfgMedSrtpSecure).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Label(frm, text='RTP transport start port:').grid(row=row, column=0, sticky=tk.E, pady=2)
- tk.Spinbox(frm, from_=0, to=65535, textvariable=self.cfgMedPort, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
- ttk.Label(frm, text='(0: any)').grid(row=row, column=1, sticky=tk.E, pady=2)
- row += 1
- ttk.Label(frm, text='Port range:').grid(row=row, column=0, sticky=tk.E, pady=2)
- tk.Spinbox(frm, from_=0, to=65535, textvariable=self.cfgMedPortRange, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
- ttk.Label(frm, text='(0: not limited)').grid(row=row, column=1, sticky=tk.E, pady=2)
- row += 1
- ttk.Label(frm, text='Lock codec:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Checkbutton(frm, text='Enable', variable=self.cfgMedLockCodec).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Label(frm, text='Use IPv6:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Checkbutton(frm, text='Yes', variable=self.cfgMedIpv6).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
-
- self.wTab.add(frm, text='Media settings')
-
- def createMediaNatTab(self):
- # Prepare the variables to set/receive values from GUI
- self.cfgSipUseStun = tk.IntVar(value = self.cfg.natConfig.sipStunUse)
- self.cfgMediaUseStun = tk.IntVar(value = self.cfg.natConfig.mediaStunUse)
- self.cfgIceEnabled = tk.BooleanVar(value = self.cfg.natConfig.iceEnabled)
- self.cfgIceAggressive = tk.BooleanVar(value = self.cfg.natConfig.iceAggressiveNomination)
- self.cfgAlwaysUpdate = tk.BooleanVar(value = True if self.cfg.natConfig.iceAlwaysUpdate else False)
- self.cfgIceNoHostCands = tk.BooleanVar(value = True if self.cfg.natConfig.iceMaxHostCands == 0 else False)
- self.cfgTurnEnabled = tk.BooleanVar(value = self.cfg.natConfig.turnEnabled)
- self.cfgTurnServer = tk.StringVar(value = self.cfg.natConfig.turnServer)
- self.cfgTurnConnType = tk.IntVar(value = self.cfg.natConfig.turnConnType)
- self.cfgTurnUser = tk.StringVar(value = self.cfg.natConfig.turnUserName)
- self.cfgTurnPasswd = tk.StringVar(value = self.cfg.natConfig.turnPassword)
-
- # Build the tab page
- frm = ttk.Frame(self.frm)
- frm.columnconfigure(0, weight=1)
- frm.columnconfigure(1, weight=2)
- row = 0
- ttk.Label(frm, text='SIP STUN Usage:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Radiobutton(frm, text='Default', value=pj.PJSUA_STUN_USE_DEFAULT, variable=self.cfgSipUseStun).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Radiobutton(frm, text='Disable', value=pj.PJSUA_STUN_USE_DISABLED, variable=self.cfgSipUseStun).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Label(frm, text='Media STUN Usage:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Radiobutton(frm, text='Default', value=pj.PJSUA_STUN_USE_DEFAULT, variable=self.cfgMediaUseStun).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Radiobutton(frm, text='Disable', value=pj.PJSUA_STUN_USE_DISABLED, variable=self.cfgMediaUseStun).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Label(frm, text='ICE:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Checkbutton(frm, text='Enable', variable=self.cfgIceEnabled).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Checkbutton(frm, text='Use aggresive nomination', variable=self.cfgIceAggressive).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Checkbutton(frm, text='Always re-INVITE after negotiation', variable=self.cfgAlwaysUpdate).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Checkbutton(frm, text='Disable host candidates', variable=self.cfgIceNoHostCands).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Label(frm, text='TURN:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Checkbutton(frm, text='Enable', variable=self.cfgTurnEnabled).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
- row += 1
- ttk.Label(frm, text='TURN server:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Entry(frm, textvariable=self.cfgTurnServer, width=20).grid(row=row, column=1, sticky=tk.W, padx=6)
- ttk.Label(frm, text='host[:port]').grid(row=row, column=1, sticky=tk.E, pady=6)
- row += 1
- ttk.Label(frm, text='TURN connection:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Radiobutton(frm, text='UDP', value=pj.PJ_TURN_TP_UDP, variable=self.cfgTurnConnType).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Radiobutton(frm, text='TCP', value=pj.PJ_TURN_TP_TCP, variable=self.cfgTurnConnType).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Label(frm, text='TURN username:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Entry(frm, textvariable=self.cfgTurnUser, width=16).grid(row=row, column=1, sticky=tk.W, padx=6)
- row += 1
- ttk.Label(frm, text='TURN password:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Entry(frm, textvariable=self.cfgTurnPasswd, show='*', width=16).grid(row=row, column=1, sticky=tk.W, padx=6)
-
- self.wTab.add(frm, text='NAT settings')
-
- def onOk(self):
- # Check basic settings
- errors = "";
- if not self.cfgAccId.get():
- errors += "Account ID is required\n"
- if self.cfgAccId.get():
- if not endpoint.validateSipUri(self.cfgAccId.get()):
- errors += "Invalid SIP ID URI: '%s'\n" % (self.cfgAccId.get())
- if self.cfgRegistrar.get():
- if not endpoint.validateSipUri(self.cfgRegistrar.get()):
- errors += "Invalid SIP registrar URI: '%s'\n" % (self.cfgRegistrar.get())
- if self.cfgProxy.get():
- if not endpoint.validateSipUri(self.cfgProxy.get()):
- errors += "Invalid SIP proxy URI: '%s'\n" % (self.cfgProxy.get())
- if self.cfgTurnEnabled.get():
- if not self.cfgTurnServer.get():
- errors += "TURN server is required\n"
- if errors:
- msgbox.showerror("Error detected:", errors)
- return
-
- # Basic settings
- self.cfg.priority = self.cfgPriority.get()
- self.cfg.idUri = self.cfgAccId.get()
- self.cfg.regConfig.registrarUri = self.cfgRegistrar.get()
- self.cfg.regConfig.registerOnAdd = self.cfgRegisterOnAdd.get()
- while len(self.cfg.sipConfig.authCreds):
- self.cfg.sipConfig.authCreds.pop()
- if self.cfgUsername.get():
- cred = pj.AuthCredInfo()
- cred.scheme = "digest"
- cred.realm = "*"
- cred.username = self.cfgUsername.get()
- cred.data = self.cfgPassword.get()
- self.cfg.sipConfig.authCreds.append(cred)
- while len(self.cfg.sipConfig.proxies):
- self.cfg.sipConfig.proxies.pop()
- if self.cfgProxy.get():
- self.cfg.sipConfig.proxies.append(self.cfgProxy.get())
-
- # SIP features
- self.cfg.callConfig.prackUse = self.cfgPrackUse.get()
- self.cfg.callConfig.timerUse = self.cfgTimerUse.get()
- self.cfg.callConfig.timerSessExpiresSec = self.cfgTimerExpires.get()
- self.cfg.presConfig.publishEnabled = self.cfgPublish.get()
- self.cfg.mwiConfig.enabled = self.cfgMwiEnabled.get()
- self.cfg.natConfig.contactRewriteUse = 1 if self.cfgEnableContactRewrite.get() else 0
- self.cfg.natConfig.viaRewriteUse = 1 if self.cfgEnableViaRewrite.get() else 0
- self.cfg.natConfig.sdpNatRewriteUse = 1 if self.cfgEnableSdpRewrite.get() else 0
- self.cfg.natConfig.sipOutboundUse = 1 if self.cfgEnableSipOutbound.get() else 0
- self.cfg.natConfig.udpKaIntervalSec = self.cfgKaInterval.get()
-
- # Media
- self.cfg.mediaConfig.transportConfig.port = self.cfgMedPort.get()
- self.cfg.mediaConfig.transportConfig.portRange = self.cfgMedPortRange.get()
- self.cfg.mediaConfig.lockCodecEnabled = self.cfgMedLockCodec.get()
- self.cfg.mediaConfig.srtpUse = self.cfgMedSrtp.get()
- self.cfg.mediaConfig.srtpSecureSignaling = self.cfgMedSrtpSecure.get()
- self.cfg.mediaConfig.ipv6Use = pj.PJSUA_IPV6_ENABLED if self.cfgMedIpv6.get() else pj.PJSUA_IPV6_DISABLED
-
- # NAT
- self.cfg.natConfig.sipStunUse = self.cfgSipUseStun.get()
- self.cfg.natConfig.mediaStunUse = self.cfgMediaUseStun.get()
- self.cfg.natConfig.iceEnabled = self.cfgIceEnabled.get()
- self.cfg.natConfig.iceAggressiveNomination = self.cfgIceAggressive .get()
- self.cfg.natConfig.iceAlwaysUpdate = self.cfgAlwaysUpdate.get()
- self.cfg.natConfig.iceMaxHostCands = 0 if self.cfgIceNoHostCands.get() else -1
- self.cfg.natConfig.turnEnabled = self.cfgTurnEnabled.get()
- self.cfg.natConfig.turnServer = self.cfgTurnServer.get()
- self.cfg.natConfig.turnConnType = self.cfgTurnConnType.get()
- self.cfg.natConfig.turnUserName = self.cfgTurnUser.get()
- self.cfg.natConfig.turnPasswordType = 0
- self.cfg.natConfig.turnPassword = self.cfgTurnPasswd.get()
-
- self.isOk = True
- self.destroy()
-
- def onCancel(self):
- self.destroy()
+ """
+ This implements account settings dialog to manipulate account settings.
+ """
+ def __init__(self, parent, cfg):
+ tk.Toplevel.__init__(self, parent)
+ self.transient(parent)
+ self.parent = parent
+ self.geometry("+100+100")
+ self.title('Account settings')
+
+ self.frm = ttk.Frame(self)
+ self.frm.pack(expand='yes', fill='both')
+
+ self.isOk = False
+ self.cfg = cfg
+
+ self.createWidgets()
+
+ def doModal(self):
+ if self.parent:
+ self.parent.wait_window(self)
+ else:
+ self.wait_window(self)
+ return self.isOk
+
+ def createWidgets(self):
+ # The notebook
+ self.frm.rowconfigure(0, weight=1)
+ self.frm.rowconfigure(1, weight=0)
+ self.frm.columnconfigure(0, weight=1)
+ self.frm.columnconfigure(1, weight=1)
+ self.wTab = ttk.Notebook(self.frm)
+ self.wTab.grid(column=0, row=0, columnspan=2, padx=10, pady=10, ipadx=20, ipady=20, sticky=tk.N+tk.S+tk.W+tk.E)
+
+ # Main buttons
+ btnOk = ttk.Button(self.frm, text='Ok', command=self.onOk)
+ btnOk.grid(column=0, row=1, sticky=tk.E, padx=20, pady=10)
+ btnCancel = ttk.Button(self.frm, text='Cancel', command=self.onCancel)
+ btnCancel.grid(column=1, row=1, sticky=tk.W, padx=20, pady=10)
+
+ # Tabs
+ self.createBasicTab()
+ self.createSipTab()
+ self.createMediaTab()
+ self.createMediaNatTab()
+
+ def createBasicTab(self):
+ # Prepare the variables to set/receive values from GUI
+ self.cfgPriority = tk.IntVar(value=self.cfg.priority)
+ self.cfgAccId = tk.StringVar(value=self.cfg.idUri)
+ self.cfgRegistrar = tk.StringVar(value=self.cfg.regConfig.registrarUri)
+ self.cfgRegisterOnAdd = tk.BooleanVar(value=self.cfg.regConfig.registerOnAdd)
+ self.cfgUsername = tk.StringVar()
+ self.cfgPassword = tk.StringVar()
+ if len(self.cfg.sipConfig.authCreds):
+ self.cfgUsername.set( self.cfg.sipConfig.authCreds[0].username )
+ self.cfgPassword.set( self.cfg.sipConfig.authCreds[0].data )
+ self.cfgProxy = tk.StringVar()
+ if len(self.cfg.sipConfig.proxies):
+ self.cfgProxy.set( self.cfg.sipConfig.proxies[0] )
+
+ # Build the tab page
+ frm = ttk.Frame(self.frm)
+ frm.columnconfigure(0, weight=1)
+ frm.columnconfigure(1, weight=2)
+ row = 0
+ ttk.Label(frm, text='Priority:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ tk.Spinbox(frm, from_=0, to=9, textvariable=self.cfgPriority, width=2).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Label(frm, text='ID (URI):').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Entry(frm, textvariable=self.cfgAccId, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Label(frm, text='Registrar URI:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Entry(frm, textvariable=self.cfgRegistrar, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Checkbutton(frm, text='Register on add', variable=self.cfgRegisterOnAdd).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Label(frm, text='Optional proxy URI:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Entry(frm, textvariable=self.cfgProxy, width=32).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Label(frm, text='Auth username:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Entry(frm, textvariable=self.cfgUsername, width=16).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Label(frm, text='Password:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Entry(frm, textvariable=self.cfgPassword, show='*', width=16).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+
+ self.wTab.add(frm, text='Basic Settings')
+
+
+ def createSipTab(self):
+ # Prepare the variables to set/receive values from GUI
+ self.cfgPrackUse = tk.IntVar(value=self.cfg.callConfig.prackUse)
+ self.cfgTimerUse = tk.IntVar(value=self.cfg.callConfig.timerUse)
+ self.cfgTimerExpires = tk.IntVar(value=self.cfg.callConfig.timerSessExpiresSec)
+ self.cfgPublish = tk.BooleanVar(value=self.cfg.presConfig.publishEnabled)
+ self.cfgMwiEnabled = tk.BooleanVar(value=self.cfg.mwiConfig.enabled)
+ self.cfgEnableContactRewrite = tk.BooleanVar(value=self.cfg.natConfig.contactRewriteUse != 0)
+ self.cfgEnableViaRewrite = tk.BooleanVar(value=self.cfg.natConfig.viaRewriteUse != 0)
+ self.cfgEnableSdpRewrite = tk.BooleanVar(value=self.cfg.natConfig.sdpNatRewriteUse != 0)
+ self.cfgEnableSipOutbound = tk.BooleanVar(value=self.cfg.natConfig.sipOutboundUse != 0)
+ self.cfgKaInterval = tk.IntVar(value=self.cfg.natConfig.udpKaIntervalSec)
+
+ # Build the tab page
+ frm = ttk.Frame(self.frm)
+ frm.columnconfigure(0, weight=1)
+ frm.columnconfigure(1, weight=2)
+ row = 0
+ ttk.Label(frm, text='100rel/PRACK:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Radiobutton(frm, text='Only offer PRACK', value=pj.PJSUA_100REL_NOT_USED, variable=self.cfgPrackUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Radiobutton(frm, text='Offer and use if remote supports', value=pj.PJSUA_100REL_OPTIONAL, variable=self.cfgPrackUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Radiobutton(frm, text='Required', value=pj.PJSUA_100REL_MANDATORY, variable=self.cfgPrackUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Label(frm, text='Session Timer:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Radiobutton(frm, text='Not offered', value=pj.PJSUA_SIP_TIMER_INACTIVE, variable=self.cfgTimerUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Radiobutton(frm, text='Optional', value=pj.PJSUA_SIP_TIMER_OPTIONAL, variable=self.cfgTimerUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Radiobutton(frm, text='Required', value=pj.PJSUA_SIP_TIMER_REQUIRED, variable=self.cfgTimerUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Radiobutton(frm, text="Always use", value=pj.PJSUA_SIP_TIMER_ALWAYS, variable=self.cfgTimerUse).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Label(frm, text='Session Timer Expiration:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ tk.Spinbox(frm, from_=90, to=7200, textvariable=self.cfgTimerExpires, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+ ttk.Label(frm, text='(seconds)').grid(row=row, column=1, sticky=tk.E)
+ row += 1
+ ttk.Label(frm, text='Presence:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Checkbutton(frm, text='Enable PUBLISH', variable=self.cfgPublish).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Label(frm, text='Message Waiting Indication:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Checkbutton(frm, text='Enable MWI', variable=self.cfgMwiEnabled).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Label(frm, text='NAT Traversal:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Checkbutton(frm, text='Enable Contact Rewrite', variable=self.cfgEnableContactRewrite).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Checkbutton(frm, text='Enable Via Rewrite', variable=self.cfgEnableViaRewrite).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Checkbutton(frm, text='Enable SDP IP Address Rewrite', variable=self.cfgEnableSdpRewrite).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Checkbutton(frm, text='Enable SIP Outbound Extension', variable=self.cfgEnableSipOutbound).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Label(frm, text='UDP Keep-Alive Interval:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ tk.Spinbox(frm, from_=0, to=3600, textvariable=self.cfgKaInterval, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+ ttk.Label(frm, text='(seconds) Zero to disable.').grid(row=row, column=1, sticky=tk.E)
+
+
+ self.wTab.add(frm, text='SIP Features')
+
+ def createMediaTab(self):
+ # Prepare the variables to set/receive values from GUI
+ self.cfgMedPort = tk.IntVar(value=self.cfg.mediaConfig.transportConfig.port)
+ self.cfgMedPortRange = tk.IntVar(value=self.cfg.mediaConfig.transportConfig.portRange)
+ self.cfgMedLockCodec = tk.BooleanVar(value=self.cfg.mediaConfig.lockCodecEnabled)
+ self.cfgMedSrtp = tk.IntVar(value=self.cfg.mediaConfig.srtpUse)
+ self.cfgMedSrtpSecure = tk.IntVar(value=self.cfg.mediaConfig.srtpSecureSignaling)
+ self.cfgMedIpv6 = tk.BooleanVar(value=self.cfg.mediaConfig.ipv6Use==pj.PJSUA_IPV6_ENABLED)
+
+ # Build the tab page
+ frm = ttk.Frame(self.frm)
+ frm.columnconfigure(0, weight=1)
+ frm.columnconfigure(1, weight=21)
+ row = 0
+ ttk.Label(frm, text='Secure RTP (SRTP):').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Radiobutton(frm, text='Disable', value=pj.PJMEDIA_SRTP_DISABLED, variable=self.cfgMedSrtp).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Radiobutton(frm, text='Mandatory', value=pj.PJMEDIA_SRTP_MANDATORY, variable=self.cfgMedSrtp).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Radiobutton(frm, text='Optional (non-standard)', value=pj.PJMEDIA_SRTP_OPTIONAL, variable=self.cfgMedSrtp).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Label(frm, text='SRTP signaling:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Radiobutton(frm, text='Does not require secure signaling', value=0, variable=self.cfgMedSrtpSecure).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Radiobutton(frm, text='Require secure next hop (TLS)', value=1, variable=self.cfgMedSrtpSecure).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Radiobutton(frm, text='Require secure end-to-end (SIPS)', value=2, variable=self.cfgMedSrtpSecure).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Label(frm, text='RTP transport start port:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ tk.Spinbox(frm, from_=0, to=65535, textvariable=self.cfgMedPort, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+ ttk.Label(frm, text='(0: any)').grid(row=row, column=1, sticky=tk.E, pady=2)
+ row += 1
+ ttk.Label(frm, text='Port range:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ tk.Spinbox(frm, from_=0, to=65535, textvariable=self.cfgMedPortRange, width=5).grid(row=row, column=1, sticky=tk.W, padx=6)
+ ttk.Label(frm, text='(0: not limited)').grid(row=row, column=1, sticky=tk.E, pady=2)
+ row += 1
+ ttk.Label(frm, text='Lock codec:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Checkbutton(frm, text='Enable', variable=self.cfgMedLockCodec).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Label(frm, text='Use IPv6:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Checkbutton(frm, text='Yes', variable=self.cfgMedIpv6).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+
+ self.wTab.add(frm, text='Media settings')
+
+ def createMediaNatTab(self):
+ # Prepare the variables to set/receive values from GUI
+ self.cfgSipUseStun = tk.IntVar(value = self.cfg.natConfig.sipStunUse)
+ self.cfgMediaUseStun = tk.IntVar(value = self.cfg.natConfig.mediaStunUse)
+ self.cfgIceEnabled = tk.BooleanVar(value = self.cfg.natConfig.iceEnabled)
+ self.cfgIceAggressive = tk.BooleanVar(value = self.cfg.natConfig.iceAggressiveNomination)
+ self.cfgAlwaysUpdate = tk.BooleanVar(value = True if self.cfg.natConfig.iceAlwaysUpdate else False)
+ self.cfgIceNoHostCands = tk.BooleanVar(value = True if self.cfg.natConfig.iceMaxHostCands == 0 else False)
+ self.cfgTurnEnabled = tk.BooleanVar(value = self.cfg.natConfig.turnEnabled)
+ self.cfgTurnServer = tk.StringVar(value = self.cfg.natConfig.turnServer)
+ self.cfgTurnConnType = tk.IntVar(value = self.cfg.natConfig.turnConnType)
+ self.cfgTurnUser = tk.StringVar(value = self.cfg.natConfig.turnUserName)
+ self.cfgTurnPasswd = tk.StringVar(value = self.cfg.natConfig.turnPassword)
+
+ # Build the tab page
+ frm = ttk.Frame(self.frm)
+ frm.columnconfigure(0, weight=1)
+ frm.columnconfigure(1, weight=2)
+ row = 0
+ ttk.Label(frm, text='SIP STUN Usage:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Radiobutton(frm, text='Default', value=pj.PJSUA_STUN_USE_DEFAULT, variable=self.cfgSipUseStun).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Radiobutton(frm, text='Disable', value=pj.PJSUA_STUN_USE_DISABLED, variable=self.cfgSipUseStun).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Label(frm, text='Media STUN Usage:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Radiobutton(frm, text='Default', value=pj.PJSUA_STUN_USE_DEFAULT, variable=self.cfgMediaUseStun).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Radiobutton(frm, text='Disable', value=pj.PJSUA_STUN_USE_DISABLED, variable=self.cfgMediaUseStun).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Label(frm, text='ICE:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Checkbutton(frm, text='Enable', variable=self.cfgIceEnabled).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Checkbutton(frm, text='Use aggresive nomination', variable=self.cfgIceAggressive).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Checkbutton(frm, text='Always re-INVITE after negotiation', variable=self.cfgAlwaysUpdate).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Checkbutton(frm, text='Disable host candidates', variable=self.cfgIceNoHostCands).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Label(frm, text='TURN:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Checkbutton(frm, text='Enable', variable=self.cfgTurnEnabled).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+ row += 1
+ ttk.Label(frm, text='TURN server:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Entry(frm, textvariable=self.cfgTurnServer, width=20).grid(row=row, column=1, sticky=tk.W, padx=6)
+ ttk.Label(frm, text='host[:port]').grid(row=row, column=1, sticky=tk.E, pady=6)
+ row += 1
+ ttk.Label(frm, text='TURN connection:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Radiobutton(frm, text='UDP', value=pj.PJ_TURN_TP_UDP, variable=self.cfgTurnConnType).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Radiobutton(frm, text='TCP', value=pj.PJ_TURN_TP_TCP, variable=self.cfgTurnConnType).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Label(frm, text='TURN username:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Entry(frm, textvariable=self.cfgTurnUser, width=16).grid(row=row, column=1, sticky=tk.W, padx=6)
+ row += 1
+ ttk.Label(frm, text='TURN password:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Entry(frm, textvariable=self.cfgTurnPasswd, show='*', width=16).grid(row=row, column=1, sticky=tk.W, padx=6)
+
+ self.wTab.add(frm, text='NAT settings')
+
+ def onOk(self):
+ # Check basic settings
+ errors = "";
+ if not self.cfgAccId.get():
+ errors += "Account ID is required\n"
+ if self.cfgAccId.get():
+ if not endpoint.validateSipUri(self.cfgAccId.get()):
+ errors += "Invalid SIP ID URI: '%s'\n" % (self.cfgAccId.get())
+ if self.cfgRegistrar.get():
+ if not endpoint.validateSipUri(self.cfgRegistrar.get()):
+ errors += "Invalid SIP registrar URI: '%s'\n" % (self.cfgRegistrar.get())
+ if self.cfgProxy.get():
+ if not endpoint.validateSipUri(self.cfgProxy.get()):
+ errors += "Invalid SIP proxy URI: '%s'\n" % (self.cfgProxy.get())
+ if self.cfgTurnEnabled.get():
+ if not self.cfgTurnServer.get():
+ errors += "TURN server is required\n"
+ if errors:
+ msgbox.showerror("Error detected:", errors)
+ return
+
+ # Basic settings
+ self.cfg.priority = self.cfgPriority.get()
+ self.cfg.idUri = self.cfgAccId.get()
+ self.cfg.regConfig.registrarUri = self.cfgRegistrar.get()
+ self.cfg.regConfig.registerOnAdd = self.cfgRegisterOnAdd.get()
+ while len(self.cfg.sipConfig.authCreds):
+ self.cfg.sipConfig.authCreds.pop()
+ if self.cfgUsername.get():
+ cred = pj.AuthCredInfo()
+ cred.scheme = "digest"
+ cred.realm = "*"
+ cred.username = self.cfgUsername.get()
+ cred.data = self.cfgPassword.get()
+ self.cfg.sipConfig.authCreds.append(cred)
+ while len(self.cfg.sipConfig.proxies):
+ self.cfg.sipConfig.proxies.pop()
+ if self.cfgProxy.get():
+ self.cfg.sipConfig.proxies.append(self.cfgProxy.get())
+
+ # SIP features
+ self.cfg.callConfig.prackUse = self.cfgPrackUse.get()
+ self.cfg.callConfig.timerUse = self.cfgTimerUse.get()
+ self.cfg.callConfig.timerSessExpiresSec = self.cfgTimerExpires.get()
+ self.cfg.presConfig.publishEnabled = self.cfgPublish.get()
+ self.cfg.mwiConfig.enabled = self.cfgMwiEnabled.get()
+ self.cfg.natConfig.contactRewriteUse = 1 if self.cfgEnableContactRewrite.get() else 0
+ self.cfg.natConfig.viaRewriteUse = 1 if self.cfgEnableViaRewrite.get() else 0
+ self.cfg.natConfig.sdpNatRewriteUse = 1 if self.cfgEnableSdpRewrite.get() else 0
+ self.cfg.natConfig.sipOutboundUse = 1 if self.cfgEnableSipOutbound.get() else 0
+ self.cfg.natConfig.udpKaIntervalSec = self.cfgKaInterval.get()
+
+ # Media
+ self.cfg.mediaConfig.transportConfig.port = self.cfgMedPort.get()
+ self.cfg.mediaConfig.transportConfig.portRange = self.cfgMedPortRange.get()
+ self.cfg.mediaConfig.lockCodecEnabled = self.cfgMedLockCodec.get()
+ self.cfg.mediaConfig.srtpUse = self.cfgMedSrtp.get()
+ self.cfg.mediaConfig.srtpSecureSignaling = self.cfgMedSrtpSecure.get()
+ self.cfg.mediaConfig.ipv6Use = pj.PJSUA_IPV6_ENABLED if self.cfgMedIpv6.get() else pj.PJSUA_IPV6_DISABLED
+
+ # NAT
+ self.cfg.natConfig.sipStunUse = self.cfgSipUseStun.get()
+ self.cfg.natConfig.mediaStunUse = self.cfgMediaUseStun.get()
+ self.cfg.natConfig.iceEnabled = self.cfgIceEnabled.get()
+ self.cfg.natConfig.iceAggressiveNomination = self.cfgIceAggressive .get()
+ self.cfg.natConfig.iceAlwaysUpdate = self.cfgAlwaysUpdate.get()
+ self.cfg.natConfig.iceMaxHostCands = 0 if self.cfgIceNoHostCands.get() else -1
+ self.cfg.natConfig.turnEnabled = self.cfgTurnEnabled.get()
+ self.cfg.natConfig.turnServer = self.cfgTurnServer.get()
+ self.cfg.natConfig.turnConnType = self.cfgTurnConnType.get()
+ self.cfg.natConfig.turnUserName = self.cfgTurnUser.get()
+ self.cfg.natConfig.turnPasswordType = 0
+ self.cfg.natConfig.turnPassword = self.cfgTurnPasswd.get()
+
+ self.isOk = True
+ self.destroy()
+
+ def onCancel(self):
+ self.destroy()
if __name__ == '__main__':
- application.main()
+ application.main()
diff --git a/pjsip-apps/src/pygui/application.py b/pjsip-apps/src/pygui/application.py
index 9672730..342482e 100644
--- a/pjsip-apps/src/pygui/application.py
+++ b/pjsip-apps/src/pygui/application.py
@@ -1,4 +1,4 @@
-# $Id: application.py 4798 2014-03-19 21:20:17Z bennylp $
+# $Id: application.py 5638 2017-08-02 09:45:09Z riza $
#
# pjsua Python GUI Demo
#
@@ -20,13 +20,13 @@
#
import sys
if sys.version_info[0] >= 3: # Python 3
- import tkinter as tk
- from tkinter import ttk
- from tkinter import messagebox as msgbox
+ import tkinter as tk
+ from tkinter import ttk
+ from tkinter import messagebox as msgbox
else:
- import Tkinter as tk
- import tkMessageBox as msgbox
- import ttk
+ import Tkinter as tk
+ import tkMessageBox as msgbox
+ import ttk
import pjsua2 as pj
import log
@@ -44,485 +44,487 @@ import traceback
# in swig/python/Makefile). In my experiment this would crash Python as reported in:
# http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2014-March/017223.html
USE_THREADS = False
-
+
+write=sys.stdout.write
+
class Application(ttk.Frame):
- """
- The Application main frame.
- """
- def __init__(self):
- global USE_THREADS
- ttk.Frame.__init__(self, name='application', width=300, height=500)
- self.pack(expand='yes', fill='both')
- self.master.title('pjsua2 Demo')
- self.master.geometry('500x500+100+100')
-
- # Logger
- self.logger = log.Logger()
-
- # Accounts
- self.accList = []
-
- # GUI variables
- self.showLogWindow = tk.IntVar(value=0)
- self.quitting = False
-
- # Construct GUI
- self._createWidgets()
-
- # Log window
- self.logWindow = log.LogWindow(self)
- self._onMenuShowHideLogWindow()
-
- # Instantiate endpoint
- self.ep = endpoint.Endpoint()
- self.ep.libCreate()
-
- # Default config
- self.appConfig = settings.AppConfig()
- if USE_THREADS:
- self.appConfig.epConfig.uaConfig.threadCnt = 1
- self.appConfig.epConfig.uaConfig.mainThreadOnly = False
- else:
- self.appConfig.epConfig.uaConfig.threadCnt = 0
- self.appConfig.epConfig.uaConfig.mainThreadOnly = True
- self.appConfig.epConfig.logConfig.writer = self.logger
- self.appConfig.epConfig.logConfig.filename = "pygui.log"
- self.appConfig.epConfig.logConfig.fileFlags = pj.PJ_O_APPEND
- self.appConfig.epConfig.logConfig.level = 5
- self.appConfig.epConfig.logConfig.consoleLevel = 5
-
- def saveConfig(self, filename='pygui.js'):
- # Save disabled accounts since they are not listed in self.accList
- disabled_accs = [ac for ac in self.appConfig.accounts if not ac.enabled]
- self.appConfig.accounts = []
-
- # Get account configs from active accounts
- for acc in self.accList:
- acfg = settings.AccConfig()
- acfg.enabled = True
- acfg.config = acc.cfg
- for bud in acc.buddyList:
- acfg.buddyConfigs.append(bud.cfg)
- self.appConfig.accounts.append(acfg)
-
- # Put back disabled accounts
- self.appConfig.accounts.extend(disabled_accs)
- # Save
- self.appConfig.saveFile(filename)
-
- def start(self, cfg_file='pygui.js'):
- global USE_THREADS
- # Load config
- if cfg_file and os.path.exists(cfg_file):
- self.appConfig.loadFile(cfg_file)
-
- if USE_THREADS:
- self.appConfig.epConfig.uaConfig.threadCnt = 1
- self.appConfig.epConfig.uaConfig.mainThreadOnly = False
- else:
- self.appConfig.epConfig.uaConfig.threadCnt = 0
- self.appConfig.epConfig.uaConfig.mainThreadOnly = True
- self.appConfig.epConfig.uaConfig.threadCnt = 0
- self.appConfig.epConfig.uaConfig.mainThreadOnly = True
- self.appConfig.epConfig.logConfig.writer = self.logger
- self.appConfig.epConfig.logConfig.level = 5
- self.appConfig.epConfig.logConfig.consoleLevel = 5
-
- # Initialize library
- self.appConfig.epConfig.uaConfig.userAgent = "pygui-" + self.ep.libVersion().full;
- self.ep.libInit(self.appConfig.epConfig)
- self.master.title('pjsua2 Demo version ' + self.ep.libVersion().full)
-
- # Create transports
- if self.appConfig.udp.enabled:
- self.ep.transportCreate(self.appConfig.udp.type, self.appConfig.udp.config)
- if self.appConfig.tcp.enabled:
- self.ep.transportCreate(self.appConfig.tcp.type, self.appConfig.tcp.config)
- if self.appConfig.tls.enabled:
- self.ep.transportCreate(self.appConfig.tls.type, self.appConfig.tls.config)
-
- # Add accounts
- for cfg in self.appConfig.accounts:
- if cfg.enabled:
- self._createAcc(cfg.config)
- acc = self.accList[-1]
- for buddy_cfg in cfg.buddyConfigs:
- self._createBuddy(acc, buddy_cfg)
-
- # Start library
- self.ep.libStart()
-
- # Start polling
- if not USE_THREADS:
- self._onTimer()
-
- def updateAccount(self, acc):
- if acc.deleting:
- return # ignore
- iid = str(acc.randId)
- text = acc.cfg.idUri
- status = acc.statusText()
-
- values = (status,)
- if self.tv.exists(iid):
- self.tv.item(iid, text=text, values=values)
- else:
- self.tv.insert('', 'end', iid, open=True, text=text, values=values)
-
- def updateBuddy(self, bud):
- iid = 'buddy' + str(bud.randId)
- text = bud.cfg.uri
- status = bud.statusText()
-
- values = (status,)
- if self.tv.exists(iid):
- self.tv.item(iid, text=text, values=values)
- else:
- self.tv.insert(str(bud.account.randId), 'end', iid, open=True, text=text, values=values)
-
- def _createAcc(self, acc_cfg):
- acc = account.Account(self)
- acc.cfg = acc_cfg
- self.accList.append(acc)
- self.updateAccount(acc)
- acc.create(acc.cfg)
- acc.cfgChanged = False
- self.updateAccount(acc)
-
- def _createBuddy(self, acc, buddy_cfg):
- bud = buddy.Buddy(self)
- bud.cfg = buddy_cfg
- bud.account = acc
- bud.create(acc, bud.cfg)
- self.updateBuddy(bud)
- acc.buddyList.append(bud)
-
- def _createWidgets(self):
- self._createAppMenu()
-
- # Main pane, a Treeview
- self.tv = ttk.Treeview(self, columns=('Status'), show='tree')
- self.tv.pack(side='top', fill='both', expand='yes', padx=5, pady=5)
-
- self._createContextMenu()
-
- # Handle close event
- self.master.protocol("WM_DELETE_WINDOW", self._onClose)
-
- def _createAppMenu(self):
- # Main menu bar
- top = self.winfo_toplevel()
- self.menubar = tk.Menu()
- top.configure(menu=self.menubar)
-
- # File menu
- file_menu = tk.Menu(self.menubar, tearoff=False)
- self.menubar.add_cascade(label="File", menu=file_menu)
- file_menu.add_command(label="Add account..", command=self._onMenuAddAccount)
- file_menu.add_checkbutton(label="Show/hide log window", command=self._onMenuShowHideLogWindow, variable=self.showLogWindow)
- file_menu.add_separator()
- file_menu.add_command(label="Settings...", command=self._onMenuSettings)
- file_menu.add_command(label="Save Settings", command=self._onMenuSaveSettings)
- file_menu.add_separator()
- file_menu.add_command(label="Quit", command=self._onMenuQuit)
-
- # Window menu
- self.window_menu = tk.Menu(self.menubar, tearoff=False)
- self.menubar.add_cascade(label="Window", menu=self.window_menu)
-
- # Help menu
- help_menu = tk.Menu(self.menubar, tearoff=False)
- self.menubar.add_cascade(label="Help", menu=help_menu)
- help_menu.add_command(label="About", underline=2, command=self._onMenuAbout)
-
- def _showChatWindow(self, chat_inst):
- chat_inst.showWindow()
-
- def updateWindowMenu(self):
- # Chat windows
- self.window_menu.delete(0, tk.END)
- for acc in self.accList:
- for c in acc.chatList:
- cmd = lambda arg=c: self._showChatWindow(arg)
- self.window_menu.add_command(label=c.title, command=cmd)
-
- def _createContextMenu(self):
- top = self.winfo_toplevel()
-
- # Create Account context menu
- self.accMenu = tk.Menu(top, tearoff=False)
- # Labels, must match with _onAccContextMenu()
- labels = ['Unregister', 'Reregister', 'Add buddy...', '-',
- 'Online', 'Invisible', 'Away', 'Busy', '-',
- 'Settings...', '-',
- 'Delete...']
- for label in labels:
- if label=='-':
- self.accMenu.add_separator()
- else:
- cmd = lambda arg=label: self._onAccContextMenu(arg)
- self.accMenu.add_command(label=label, command=cmd)
-
- # Create Buddy context menu
- # Labels, must match with _onBuddyContextMenu()
- self.buddyMenu = tk.Menu(top, tearoff=False)
- labels = ['Audio call', 'Send instant message', '-',
- 'Subscribe', 'Unsubscribe', '-',
- 'Settings...', '-',
- 'Delete...']
-
- for label in labels:
- if label=='-':
- self.buddyMenu.add_separator()
- else:
- cmd = lambda arg=label: self._onBuddyContextMenu(arg)
- self.buddyMenu.add_command(label=label, command=cmd)
-
- if (top.tk.call('tk', 'windowingsystem')=='aqua'):
- self.tv.bind('<2>', self._onTvRightClick)
- self.tv.bind('<Control-1>', self._onTvRightClick)
- else:
- self.tv.bind('<3>', self._onTvRightClick)
- self.tv.bind('<Double-Button-1>', self._onTvDoubleClick)
-
- def _getSelectedAccount(self):
- items = self.tv.selection()
- if not items:
- return None
- try:
- iid = int(items[0])
- except:
- return None
- accs = [acc for acc in self.accList if acc.randId==iid]
- if not accs:
- return None
- return accs[0]
-
- def _getSelectedBuddy(self):
- items = self.tv.selection()
- if not items:
- return None
- try:
- iid = int(items[0][5:])
- iid_parent = int(self.tv.parent(items[0]))
- except:
- return None
-
- accs = [acc for acc in self.accList if acc.randId==iid_parent]
- if not accs:
- return None
-
- buds = [b for b in accs[0].buddyList if b.randId==iid]
- if not buds:
- return None
-
- return buds[0]
-
- def _onTvRightClick(self, event):
- iid = self.tv.identify_row(event.y)
- #iid = self.tv.identify('item', event.x, event.y)
- if iid:
- self.tv.selection_set( (iid,) )
- acc = self._getSelectedAccount()
- if acc:
- self.accMenu.post(event.x_root, event.y_root)
- else:
- # A buddy is selected
- self.buddyMenu.post(event.x_root, event.y_root)
-
- def _onTvDoubleClick(self, event):
- iid = self.tv.identify_row(event.y)
- if iid:
- self.tv.selection_set( (iid,) )
- acc = self._getSelectedAccount()
- if acc:
- self.cfgChanged = False
- dlg = accountsetting.Dialog(self.master, acc.cfg)
- if dlg.doModal():
- self.updateAccount(acc)
- acc.modify(acc.cfg)
- else:
- bud = self._getSelectedBuddy()
- acc = bud.account
- chat = acc.findChat(bud.cfg.uri)
- if not chat:
- chat = acc.newChat(bud.cfg.uri)
- chat.showWindow()
-
- def _onAccContextMenu(self, label):
- acc = self._getSelectedAccount()
- if not acc:
- return
-
- if label=='Unregister':
- acc.setRegistration(False)
- elif label=='Reregister':
- acc.setRegistration(True)
- elif label=='Online':
- ps = pj.PresenceStatus()
- ps.status = pj.PJSUA_BUDDY_STATUS_ONLINE
- acc.setOnlineStatus(ps)
- elif label=='Invisible':
- ps = pj.PresenceStatus()
- ps.status = pj.PJSUA_BUDDY_STATUS_OFFLINE
- acc.setOnlineStatus(ps)
- elif label=='Away':
- ps = pj.PresenceStatus()
- ps.status = pj.PJSUA_BUDDY_STATUS_ONLINE
- ps.activity = pj.PJRPID_ACTIVITY_AWAY
- ps.note = "Away"
- acc.setOnlineStatus(ps)
- elif label=='Busy':
- ps = pj.PresenceStatus()
- ps.status = pj.PJSUA_BUDDY_STATUS_ONLINE
- ps.activity = pj.PJRPID_ACTIVITY_BUSY
- ps.note = "Busy"
- acc.setOnlineStatus(ps)
- elif label=='Settings...':
- self.cfgChanged = False
- dlg = accountsetting.Dialog(self.master, acc.cfg)
- if dlg.doModal():
- self.updateAccount(acc)
- acc.modify(acc.cfg)
- elif label=='Delete...':
- msg = "Do you really want to delete account '%s'?" % acc.cfg.idUri
- if msgbox.askquestion('Delete account?', msg, default=msgbox.NO) != u'yes':
- return
- iid = str(acc.randId)
- self.accList.remove(acc)
- acc.setRegistration(False)
- acc.deleting = True
- del acc
- self.tv.delete( (iid,) )
- elif label=='Add buddy...':
- cfg = pj.BuddyConfig()
- dlg = buddy.SettingDialog(self.master, cfg)
- if dlg.doModal():
- self._createBuddy(acc, cfg)
- else:
- assert not ("Unknown menu " + label)
-
- def _onBuddyContextMenu(self, label):
- bud = self._getSelectedBuddy()
- if not bud:
- return
- acc = bud.account
-
- if label=='Audio call':
- chat = acc.findChat(bud.cfg.uri)
- if not chat: chat = acc.newChat(bud.cfg.uri)
- chat.showWindow()
- chat.startCall()
- elif label=='Send instant message':
- chat = acc.findChat(bud.cfg.uri)
- if not chat: chat = acc.newChat(bud.cfg.uri)
- chat.showWindow(True)
- elif label=='Subscribe':
- bud.subscribePresence(True)
- elif label=='Unsubscribe':
- bud.subscribePresence(False)
- elif label=='Settings...':
- subs = bud.cfg.subscribe
- uri = bud.cfg.uri
- dlg = buddy.SettingDialog(self.master, bud.cfg)
- if dlg.doModal():
- self.updateBuddy(bud)
- # URI updated?
- if uri != bud.cfg.uri:
- cfg = bud.cfg
- # del old
- iid = 'buddy' + str(bud.randId)
- acc.buddyList.remove(bud)
- del bud
- self.tv.delete( (iid,) )
- # add new
- self._createBuddy(acc, cfg)
- # presence subscribe setting updated
- elif subs != bud.cfg.subscribe:
- bud.subscribePresence(bud.cfg.subscribe)
- elif label=='Delete...':
- msg = "Do you really want to delete buddy '%s'?" % bud.cfg.uri
- if msgbox.askquestion('Delete buddy?', msg, default=msgbox.NO) != u'yes':
- return
- iid = 'buddy' + str(bud.randId)
- acc.buddyList.remove(bud)
- del bud
- self.tv.delete( (iid,) )
- else:
- assert not ("Unknown menu " + label)
-
- def _onTimer(self):
- if not self.quitting:
- self.ep.libHandleEvents(10)
- if not self.quitting:
- self.master.after(50, self._onTimer)
-
- def _onClose(self):
- self.saveConfig()
- self.quitting = True
- self.ep.libDestroy()
- self.ep = None
- self.update()
- self.quit()
-
- def _onMenuAddAccount(self):
- cfg = pj.AccountConfig()
- dlg = accountsetting.Dialog(self.master, cfg)
- if dlg.doModal():
- self._createAcc(cfg)
-
- def _onMenuShowHideLogWindow(self):
- if self.showLogWindow.get():
- self.logWindow.deiconify()
- else:
- self.logWindow.withdraw()
-
- def _onMenuSettings(self):
- dlg = settings.Dialog(self, self.appConfig)
- if dlg.doModal():
- msgbox.showinfo(self.master.title(), 'You need to restart for new settings to take effect')
-
- def _onMenuSaveSettings(self):
- self.saveConfig()
-
- def _onMenuQuit(self):
- self._onClose()
-
- def _onMenuAbout(self):
- msgbox.showinfo(self.master.title(), 'About')
-
+ """
+ The Application main frame.
+ """
+ def __init__(self):
+ global USE_THREADS
+ ttk.Frame.__init__(self, name='application', width=300, height=500)
+ self.pack(expand='yes', fill='both')
+ self.master.title('pjsua2 Demo')
+ self.master.geometry('500x500+100+100')
+
+ # Logger
+ self.logger = log.Logger()
+
+ # Accounts
+ self.accList = []
+
+ # GUI variables
+ self.showLogWindow = tk.IntVar(value=0)
+ self.quitting = False
+
+ # Construct GUI
+ self._createWidgets()
+
+ # Log window
+ self.logWindow = log.LogWindow(self)
+ self._onMenuShowHideLogWindow()
+
+ # Instantiate endpoint
+ self.ep = endpoint.Endpoint()
+ self.ep.libCreate()
+
+ # Default config
+ self.appConfig = settings.AppConfig()
+ if USE_THREADS:
+ self.appConfig.epConfig.uaConfig.threadCnt = 1
+ self.appConfig.epConfig.uaConfig.mainThreadOnly = False
+ else:
+ self.appConfig.epConfig.uaConfig.threadCnt = 0
+ self.appConfig.epConfig.uaConfig.mainThreadOnly = True
+ self.appConfig.epConfig.logConfig.writer = self.logger
+ self.appConfig.epConfig.logConfig.filename = "pygui.log"
+ self.appConfig.epConfig.logConfig.fileFlags = pj.PJ_O_APPEND
+ self.appConfig.epConfig.logConfig.level = 5
+ self.appConfig.epConfig.logConfig.consoleLevel = 5
+
+ def saveConfig(self, filename='pygui.js'):
+ # Save disabled accounts since they are not listed in self.accList
+ disabled_accs = [ac for ac in self.appConfig.accounts if not ac.enabled]
+ self.appConfig.accounts = []
+
+ # Get account configs from active accounts
+ for acc in self.accList:
+ acfg = settings.AccConfig()
+ acfg.enabled = True
+ acfg.config = acc.cfg
+ for bud in acc.buddyList:
+ acfg.buddyConfigs.append(bud.cfg)
+ self.appConfig.accounts.append(acfg)
+
+ # Put back disabled accounts
+ self.appConfig.accounts.extend(disabled_accs)
+ # Save
+ self.appConfig.saveFile(filename)
+
+ def start(self, cfg_file='pygui.js'):
+ global USE_THREADS
+ # Load config
+ if cfg_file and os.path.exists(cfg_file):
+ self.appConfig.loadFile(cfg_file)
+
+ if USE_THREADS:
+ self.appConfig.epConfig.uaConfig.threadCnt = 1
+ self.appConfig.epConfig.uaConfig.mainThreadOnly = False
+ else:
+ self.appConfig.epConfig.uaConfig.threadCnt = 0
+ self.appConfig.epConfig.uaConfig.mainThreadOnly = True
+ self.appConfig.epConfig.uaConfig.threadCnt = 0
+ self.appConfig.epConfig.uaConfig.mainThreadOnly = True
+ self.appConfig.epConfig.logConfig.writer = self.logger
+ self.appConfig.epConfig.logConfig.level = 5
+ self.appConfig.epConfig.logConfig.consoleLevel = 5
+
+ # Initialize library
+ self.appConfig.epConfig.uaConfig.userAgent = "pygui-" + self.ep.libVersion().full;
+ self.ep.libInit(self.appConfig.epConfig)
+ self.master.title('pjsua2 Demo version ' + self.ep.libVersion().full)
+
+ # Create transports
+ if self.appConfig.udp.enabled:
+ self.ep.transportCreate(self.appConfig.udp.type, self.appConfig.udp.config)
+ if self.appConfig.tcp.enabled:
+ self.ep.transportCreate(self.appConfig.tcp.type, self.appConfig.tcp.config)
+ if self.appConfig.tls.enabled:
+ self.ep.transportCreate(self.appConfig.tls.type, self.appConfig.tls.config)
+
+ # Add accounts
+ for cfg in self.appConfig.accounts:
+ if cfg.enabled:
+ self._createAcc(cfg.config)
+ acc = self.accList[-1]
+ for buddy_cfg in cfg.buddyConfigs:
+ self._createBuddy(acc, buddy_cfg)
+
+ # Start library
+ self.ep.libStart()
+
+ # Start polling
+ if not USE_THREADS:
+ self._onTimer()
+
+ def updateAccount(self, acc):
+ if acc.deleting:
+ return # ignore
+ iid = str(acc.randId)
+ text = acc.cfg.idUri
+ status = acc.statusText()
+
+ values = (status,)
+ if self.tv.exists(iid):
+ self.tv.item(iid, text=text, values=values)
+ else:
+ self.tv.insert('', 'end', iid, open=True, text=text, values=values)
+
+ def updateBuddy(self, bud):
+ iid = 'buddy' + str(bud.randId)
+ text = bud.cfg.uri
+ status = bud.statusText()
+
+ values = (status,)
+ if self.tv.exists(iid):
+ self.tv.item(iid, text=text, values=values)
+ else:
+ self.tv.insert(str(bud.account.randId), 'end', iid, open=True, text=text, values=values)
+
+ def _createAcc(self, acc_cfg):
+ acc = account.Account(self)
+ acc.cfg = acc_cfg
+ self.accList.append(acc)
+ self.updateAccount(acc)
+ acc.create(acc.cfg)
+ acc.cfgChanged = False
+ self.updateAccount(acc)
+
+ def _createBuddy(self, acc, buddy_cfg):
+ bud = buddy.Buddy(self)
+ bud.cfg = buddy_cfg
+ bud.account = acc
+ bud.create(acc, bud.cfg)
+ self.updateBuddy(bud)
+ acc.buddyList.append(bud)
+
+ def _createWidgets(self):
+ self._createAppMenu()
+
+ # Main pane, a Treeview
+ self.tv = ttk.Treeview(self, columns=('Status'), show='tree')
+ self.tv.pack(side='top', fill='both', expand='yes', padx=5, pady=5)
+
+ self._createContextMenu()
+
+ # Handle close event
+ self.master.protocol("WM_DELETE_WINDOW", self._onClose)
+
+ def _createAppMenu(self):
+ # Main menu bar
+ top = self.winfo_toplevel()
+ self.menubar = tk.Menu()
+ top.configure(menu=self.menubar)
+
+ # File menu
+ file_menu = tk.Menu(self.menubar, tearoff=False)
+ self.menubar.add_cascade(label="File", menu=file_menu)
+ file_menu.add_command(label="Add account..", command=self._onMenuAddAccount)
+ file_menu.add_checkbutton(label="Show/hide log window", command=self._onMenuShowHideLogWindow, variable=self.showLogWindow)
+ file_menu.add_separator()
+ file_menu.add_command(label="Settings...", command=self._onMenuSettings)
+ file_menu.add_command(label="Save Settings", command=self._onMenuSaveSettings)
+ file_menu.add_separator()
+ file_menu.add_command(label="Quit", command=self._onMenuQuit)
+
+ # Window menu
+ self.window_menu = tk.Menu(self.menubar, tearoff=False)
+ self.menubar.add_cascade(label="Window", menu=self.window_menu)
+
+ # Help menu
+ help_menu = tk.Menu(self.menubar, tearoff=False)
+ self.menubar.add_cascade(label="Help", menu=help_menu)
+ help_menu.add_command(label="About", underline=2, command=self._onMenuAbout)
+
+ def _showChatWindow(self, chat_inst):
+ chat_inst.showWindow()
+
+ def updateWindowMenu(self):
+ # Chat windows
+ self.window_menu.delete(0, tk.END)
+ for acc in self.accList:
+ for c in acc.chatList:
+ cmd = lambda arg=c: self._showChatWindow(arg)
+ self.window_menu.add_command(label=c.title, command=cmd)
+
+ def _createContextMenu(self):
+ top = self.winfo_toplevel()
+
+ # Create Account context menu
+ self.accMenu = tk.Menu(top, tearoff=False)
+ # Labels, must match with _onAccContextMenu()
+ labels = ['Unregister', 'Reregister', 'Add buddy...', '-',
+ 'Online', 'Invisible', 'Away', 'Busy', '-',
+ 'Settings...', '-',
+ 'Delete...']
+ for label in labels:
+ if label=='-':
+ self.accMenu.add_separator()
+ else:
+ cmd = lambda arg=label: self._onAccContextMenu(arg)
+ self.accMenu.add_command(label=label, command=cmd)
+
+ # Create Buddy context menu
+ # Labels, must match with _onBuddyContextMenu()
+ self.buddyMenu = tk.Menu(top, tearoff=False)
+ labels = ['Audio call', 'Send instant message', '-',
+ 'Subscribe', 'Unsubscribe', '-',
+ 'Settings...', '-',
+ 'Delete...']
+
+ for label in labels:
+ if label=='-':
+ self.buddyMenu.add_separator()
+ else:
+ cmd = lambda arg=label: self._onBuddyContextMenu(arg)
+ self.buddyMenu.add_command(label=label, command=cmd)
+
+ if (top.tk.call('tk', 'windowingsystem')=='aqua'):
+ self.tv.bind('<2>', self._onTvRightClick)
+ self.tv.bind('<Control-1>', self._onTvRightClick)
+ else:
+ self.tv.bind('<3>', self._onTvRightClick)
+ self.tv.bind('<Double-Button-1>', self._onTvDoubleClick)
+
+ def _getSelectedAccount(self):
+ items = self.tv.selection()
+ if not items:
+ return None
+ try:
+ iid = int(items[0])
+ except:
+ return None
+ accs = [acc for acc in self.accList if acc.randId==iid]
+ if not accs:
+ return None
+ return accs[0]
+
+ def _getSelectedBuddy(self):
+ items = self.tv.selection()
+ if not items:
+ return None
+ try:
+ iid = int(items[0][5:])
+ iid_parent = int(self.tv.parent(items[0]))
+ except:
+ return None
+
+ accs = [acc for acc in self.accList if acc.randId==iid_parent]
+ if not accs:
+ return None
+
+ buds = [b for b in accs[0].buddyList if b.randId==iid]
+ if not buds:
+ return None
+
+ return buds[0]
+
+ def _onTvRightClick(self, event):
+ iid = self.tv.identify_row(event.y)
+ #iid = self.tv.identify('item', event.x, event.y)
+ if iid:
+ self.tv.selection_set( (iid,) )
+ acc = self._getSelectedAccount()
+ if acc:
+ self.accMenu.post(event.x_root, event.y_root)
+ else:
+ # A buddy is selected
+ self.buddyMenu.post(event.x_root, event.y_root)
+
+ def _onTvDoubleClick(self, event):
+ iid = self.tv.identify_row(event.y)
+ if iid:
+ self.tv.selection_set( (iid,) )
+ acc = self._getSelectedAccount()
+ if acc:
+ self.cfgChanged = False
+ dlg = accountsetting.Dialog(self.master, acc.cfg)
+ if dlg.doModal():
+ self.updateAccount(acc)
+ acc.modify(acc.cfg)
+ else:
+ bud = self._getSelectedBuddy()
+ acc = bud.account
+ chat = acc.findChat(bud.cfg.uri)
+ if not chat:
+ chat = acc.newChat(bud.cfg.uri)
+ chat.showWindow()
+
+ def _onAccContextMenu(self, label):
+ acc = self._getSelectedAccount()
+ if not acc:
+ return
+
+ if label=='Unregister':
+ acc.setRegistration(False)
+ elif label=='Reregister':
+ acc.setRegistration(True)
+ elif label=='Online':
+ ps = pj.PresenceStatus()
+ ps.status = pj.PJSUA_BUDDY_STATUS_ONLINE
+ acc.setOnlineStatus(ps)
+ elif label=='Invisible':
+ ps = pj.PresenceStatus()
+ ps.status = pj.PJSUA_BUDDY_STATUS_OFFLINE
+ acc.setOnlineStatus(ps)
+ elif label=='Away':
+ ps = pj.PresenceStatus()
+ ps.status = pj.PJSUA_BUDDY_STATUS_ONLINE
+ ps.activity = pj.PJRPID_ACTIVITY_AWAY
+ ps.note = "Away"
+ acc.setOnlineStatus(ps)
+ elif label=='Busy':
+ ps = pj.PresenceStatus()
+ ps.status = pj.PJSUA_BUDDY_STATUS_ONLINE
+ ps.activity = pj.PJRPID_ACTIVITY_BUSY
+ ps.note = "Busy"
+ acc.setOnlineStatus(ps)
+ elif label=='Settings...':
+ self.cfgChanged = False
+ dlg = accountsetting.Dialog(self.master, acc.cfg)
+ if dlg.doModal():
+ self.updateAccount(acc)
+ acc.modify(acc.cfg)
+ elif label=='Delete...':
+ msg = "Do you really want to delete account '%s'?" % acc.cfg.idUri
+ if msgbox.askquestion('Delete account?', msg, default=msgbox.NO) != u'yes':
+ return
+ iid = str(acc.randId)
+ self.accList.remove(acc)
+ acc.setRegistration(False)
+ acc.deleting = True
+ del acc
+ self.tv.delete( (iid,) )
+ elif label=='Add buddy...':
+ cfg = pj.BuddyConfig()
+ dlg = buddy.SettingDialog(self.master, cfg)
+ if dlg.doModal():
+ self._createBuddy(acc, cfg)
+ else:
+ assert not ("Unknown menu " + label)
+
+ def _onBuddyContextMenu(self, label):
+ bud = self._getSelectedBuddy()
+ if not bud:
+ return
+ acc = bud.account
+
+ if label=='Audio call':
+ chat = acc.findChat(bud.cfg.uri)
+ if not chat: chat = acc.newChat(bud.cfg.uri)
+ chat.showWindow()
+ chat.startCall()
+ elif label=='Send instant message':
+ chat = acc.findChat(bud.cfg.uri)
+ if not chat: chat = acc.newChat(bud.cfg.uri)
+ chat.showWindow(True)
+ elif label=='Subscribe':
+ bud.subscribePresence(True)
+ elif label=='Unsubscribe':
+ bud.subscribePresence(False)
+ elif label=='Settings...':
+ subs = bud.cfg.subscribe
+ uri = bud.cfg.uri
+ dlg = buddy.SettingDialog(self.master, bud.cfg)
+ if dlg.doModal():
+ self.updateBuddy(bud)
+ # URI updated?
+ if uri != bud.cfg.uri:
+ cfg = bud.cfg
+ # del old
+ iid = 'buddy' + str(bud.randId)
+ acc.buddyList.remove(bud)
+ del bud
+ self.tv.delete( (iid,) )
+ # add new
+ self._createBuddy(acc, cfg)
+ # presence subscribe setting updated
+ elif subs != bud.cfg.subscribe:
+ bud.subscribePresence(bud.cfg.subscribe)
+ elif label=='Delete...':
+ msg = "Do you really want to delete buddy '%s'?" % bud.cfg.uri
+ if msgbox.askquestion('Delete buddy?', msg, default=msgbox.NO) != u'yes':
+ return
+ iid = 'buddy' + str(bud.randId)
+ acc.buddyList.remove(bud)
+ del bud
+ self.tv.delete( (iid,) )
+ else:
+ assert not ("Unknown menu " + label)
+
+ def _onTimer(self):
+ if not self.quitting:
+ self.ep.libHandleEvents(10)
+ if not self.quitting:
+ self.master.after(50, self._onTimer)
+
+ def _onClose(self):
+ self.saveConfig()
+ self.quitting = True
+ self.ep.libDestroy()
+ self.ep = None
+ self.update()
+ self.quit()
+
+ def _onMenuAddAccount(self):
+ cfg = pj.AccountConfig()
+ dlg = accountsetting.Dialog(self.master, cfg)
+ if dlg.doModal():
+ self._createAcc(cfg)
+
+ def _onMenuShowHideLogWindow(self):
+ if self.showLogWindow.get():
+ self.logWindow.deiconify()
+ else:
+ self.logWindow.withdraw()
+
+ def _onMenuSettings(self):
+ dlg = settings.Dialog(self, self.appConfig)
+ if dlg.doModal():
+ msgbox.showinfo(self.master.title(), 'You need to restart for new settings to take effect')
+
+ def _onMenuSaveSettings(self):
+ self.saveConfig()
+
+ def _onMenuQuit(self):
+ self._onClose()
+
+ def _onMenuAbout(self):
+ msgbox.showinfo(self.master.title(), 'About')
+
class ExceptionCatcher:
- """Custom Tk exception catcher, mainly to display more information
- from pj.Error exception
- """
- def __init__(self, func, subst, widget):
- self.func = func
- self.subst = subst
- self.widget = widget
- def __call__(self, *args):
- try:
- if self.subst:
- args = apply(self.subst, args)
- return apply(self.func, args)
- except pj.Error, error:
- print 'Exception:'
- print ' ', error.info()
- print 'Traceback:'
- print traceback.print_stack()
- log.writeLog2(1, 'Exception: ' + error.info() + '\n')
- except Exception, error:
- print 'Exception:'
- print ' ', str(error)
- print 'Traceback:'
- print traceback.print_stack()
- log.writeLog2(1, 'Exception: ' + str(error) + '\n')
+ """Custom Tk exception catcher, mainly to display more information
+ from pj.Error exception
+ """
+ def __init__(self, func, subst, widget):
+ self.func = func
+ self.subst = subst
+ self.widget = widget
+ def __call__(self, *args):
+ try:
+ if self.subst:
+ args = apply(self.subst, args)
+ return apply(self.func, args)
+ except pj.Error as error:
+ write("Exception:\r\n")
+ write(" ," + error.info() + "\r\n")
+ write("Traceback:\r\n")
+ write(traceback.print_stack())
+ log.writeLog2(1, 'Exception: ' + error.info() + '\n')
+ except Exception as error:
+ write("Exception:\r\n")
+ write(" ," + str(error) + "\r\n")
+ write("Traceback:\r\n")
+ write(traceback.print_stack())
+ log.writeLog2(1, 'Exception: ' + str(error) + '\n')
def main():
- #tk.CallWrapper = ExceptionCatcher
- app = Application()
- app.start()
- app.mainloop()
-
+ #tk.CallWrapper = ExceptionCatcher
+ app = Application()
+ app.start()
+ app.mainloop()
+
if __name__ == '__main__':
- main()
+ main()
diff --git a/pjsip-apps/src/pygui/buddy.py b/pjsip-apps/src/pygui/buddy.py
index 6cf7477..4674865 100644
--- a/pjsip-apps/src/pygui/buddy.py
+++ b/pjsip-apps/src/pygui/buddy.py
@@ -1,4 +1,4 @@
-# $Id: buddy.py 4704 2014-01-16 05:30:46Z ming $
+# $Id: buddy.py 5638 2017-08-02 09:45:09Z riza $
#
# pjsua Python GUI Demo
#
@@ -20,13 +20,13 @@
#
import sys
if sys.version_info[0] >= 3: # Python 3
- import tkinter as tk
- from tkinter import ttk
- from tkinter import messagebox as msgbox
+ import tkinter as tk
+ from tkinter import ttk
+ from tkinter import messagebox as msgbox
else:
- import Tkinter as tk
- import tkMessageBox as msgbox
- import ttk
+ import Tkinter as tk
+ import tkMessageBox as msgbox
+ import ttk
import random
import pjsua2 as pj
@@ -35,118 +35,118 @@ import application
# Buddy class
class Buddy(pj.Buddy):
- """
- High level Python Buddy object, derived from pjsua2's Buddy object.
- """
- def __init__(self, app):
- pj.Buddy.__init__(self)
- self.app = app
- self.randId = random.randint(1, 9999)
- self.cfg = None
- self.account = None
-
- def statusText(self):
- bi = self.getInfo()
- status = ''
- if bi.subState == pj.PJSIP_EVSUB_STATE_ACTIVE:
- if bi.presStatus.status == pj.PJSUA_BUDDY_STATUS_ONLINE:
- status = bi.presStatus.statusText
- if not status:
- status = 'Online'
- elif bi.presStatus.status == pj.PJSUA_BUDDY_STATUS_OFFLINE:
- status = 'Offline'
- else:
- status = 'Unknown'
- return status
-
- def onBuddyState(self):
- self.app.updateBuddy(self)
+ """
+ High level Python Buddy object, derived from pjsua2's Buddy object.
+ """
+ def __init__(self, app):
+ pj.Buddy.__init__(self)
+ self.app = app
+ self.randId = random.randint(1, 9999)
+ self.cfg = None
+ self.account = None
+
+ def statusText(self):
+ bi = self.getInfo()
+ status = ''
+ if bi.subState == pj.PJSIP_EVSUB_STATE_ACTIVE:
+ if bi.presStatus.status == pj.PJSUA_BUDDY_STATUS_ONLINE:
+ status = bi.presStatus.statusText
+ if not status:
+ status = 'Online'
+ elif bi.presStatus.status == pj.PJSUA_BUDDY_STATUS_OFFLINE:
+ status = 'Offline'
+ else:
+ status = 'Unknown'
+ return status
+
+ def onBuddyState(self):
+ self.app.updateBuddy(self)
class SettingDialog(tk.Toplevel):
- """
- This implements buddy settings dialog to manipulate buddy settings.
- """
- def __init__(self, parent, cfg):
- tk.Toplevel.__init__(self, parent)
- self.transient(parent)
- self.parent = parent
- self.geometry("+100+100")
- self.title('Buddy settings')
-
- self.frm = ttk.Frame(self)
- self.frm.pack(expand='yes', fill='both')
-
- self.isOk = False
- self.cfg = cfg
-
- self.createWidgets()
-
- def doModal(self):
- if self.parent:
- self.parent.wait_window(self)
- else:
- self.wait_window(self)
- return self.isOk
-
- def createWidgets(self):
- # The notebook
- self.frm.rowconfigure(0, weight=1)
- self.frm.rowconfigure(1, weight=0)
- self.frm.columnconfigure(0, weight=1)
- self.frm.columnconfigure(1, weight=1)
- self.wTab = ttk.Notebook(self.frm)
- self.wTab.grid(column=0, row=0, columnspan=2, padx=5, pady=5, sticky=tk.N+tk.S+tk.W+tk.E)
-
- # Main buttons
- btnOk = ttk.Button(self.frm, text='Ok', command=self.onOk)
- btnOk.grid(column=0, row=1, sticky=tk.E, padx=20, pady=10)
- btnCancel = ttk.Button(self.frm, text='Cancel', command=self.onCancel)
- btnCancel.grid(column=1, row=1, sticky=tk.W, padx=20, pady=10)
-
- # Tabs
- self.createBasicTab()
-
- def createBasicTab(self):
- # Prepare the variables to set/receive values from GUI
- self.cfgUri = tk.StringVar()
- self.cfgUri.set( self.cfg.uri )
- self.cfgSubscribe = tk.IntVar()
- self.cfgSubscribe.set(self.cfg.subscribe)
-
- # Build the tab page
- frm = ttk.Frame(self.frm)
- frm.columnconfigure(0, weight=1)
- frm.columnconfigure(1, weight=2)
- row = 0
- ttk.Label(frm, text='URI:').grid(row=row, column=0, sticky=tk.E, pady=2)
- ttk.Entry(frm, textvariable=self.cfgUri, width=40).grid(row=row, column=1, sticky=tk.W+tk.E, padx=6)
- row += 1
- ttk.Checkbutton(frm, text='Subscribe presence', variable=self.cfgSubscribe).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
-
- self.wTab.add(frm, text='Basic Settings')
-
-
- def onOk(self):
- # Check basic settings
- errors = "";
- if self.cfgUri.get():
- if not endpoint.validateSipUri(self.cfgUri.get()):
- errors += "Invalid Buddy URI: '%s'\n" % (self.cfgUri.get())
-
- if errors:
- msgbox.showerror("Error detected:", errors)
- return
-
- # Basic settings
- self.cfg.uri = self.cfgUri.get()
- self.cfg.subscribe = self.cfgSubscribe.get()
-
- self.isOk = True
- self.destroy()
-
- def onCancel(self):
- self.destroy()
+ """
+ This implements buddy settings dialog to manipulate buddy settings.
+ """
+ def __init__(self, parent, cfg):
+ tk.Toplevel.__init__(self, parent)
+ self.transient(parent)
+ self.parent = parent
+ self.geometry("+100+100")
+ self.title('Buddy settings')
+
+ self.frm = ttk.Frame(self)
+ self.frm.pack(expand='yes', fill='both')
+
+ self.isOk = False
+ self.cfg = cfg
+
+ self.createWidgets()
+
+ def doModal(self):
+ if self.parent:
+ self.parent.wait_window(self)
+ else:
+ self.wait_window(self)
+ return self.isOk
+
+ def createWidgets(self):
+ # The notebook
+ self.frm.rowconfigure(0, weight=1)
+ self.frm.rowconfigure(1, weight=0)
+ self.frm.columnconfigure(0, weight=1)
+ self.frm.columnconfigure(1, weight=1)
+ self.wTab = ttk.Notebook(self.frm)
+ self.wTab.grid(column=0, row=0, columnspan=2, padx=5, pady=5, sticky=tk.N+tk.S+tk.W+tk.E)
+
+ # Main buttons
+ btnOk = ttk.Button(self.frm, text='Ok', command=self.onOk)
+ btnOk.grid(column=0, row=1, sticky=tk.E, padx=20, pady=10)
+ btnCancel = ttk.Button(self.frm, text='Cancel', command=self.onCancel)
+ btnCancel.grid(column=1, row=1, sticky=tk.W, padx=20, pady=10)
+
+ # Tabs
+ self.createBasicTab()
+
+ def createBasicTab(self):
+ # Prepare the variables to set/receive values from GUI
+ self.cfgUri = tk.StringVar()
+ self.cfgUri.set( self.cfg.uri )
+ self.cfgSubscribe = tk.IntVar()
+ self.cfgSubscribe.set(self.cfg.subscribe)
+
+ # Build the tab page
+ frm = ttk.Frame(self.frm)
+ frm.columnconfigure(0, weight=1)
+ frm.columnconfigure(1, weight=2)
+ row = 0
+ ttk.Label(frm, text='URI:').grid(row=row, column=0, sticky=tk.E, pady=2)
+ ttk.Entry(frm, textvariable=self.cfgUri, width=40).grid(row=row, column=1, sticky=tk.W+tk.E, padx=6)
+ row += 1
+ ttk.Checkbutton(frm, text='Subscribe presence', variable=self.cfgSubscribe).grid(row=row, column=1, sticky=tk.W, padx=6, pady=2)
+
+ self.wTab.add(frm, text='Basic Settings')
+
+
+ def onOk(self):
+ # Check basic settings
+ errors = "";
+ if self.cfgUri.get():
+ if not endpoint.validateSipUri(self.cfgUri.get()):
+ errors += "Invalid Buddy URI: '%s'\n" % (self.cfgUri.get())
+
+ if errors:
+ msgbox.showerror("Error detected:", errors)
+ return
+
+ # Basic settings
+ self.cfg.uri = self.cfgUri.get()
+ self.cfg.subscribe = self.cfgSubscribe.get()
+
+ self.isOk = True
+ self.destroy()
+
+ def onCancel(self):
+ self.destroy()
if __name__ == '__main__':
- application.main()
+ application.main()
diff --git a/pjsip-apps/src/pygui/call.py b/pjsip-apps/src/pygui/call.py
index 3215ca8..396df48 100644
--- a/pjsip-apps/src/pygui/call.py
+++ b/pjsip-apps/src/pygui/call.py
@@ -1,4 +1,4 @@
-# $Id: call.py 4757 2014-02-21 07:53:31Z nanang $
+# $Id: call.py 5638 2017-08-02 09:45:09Z riza $
#
# pjsua Python GUI Demo
#
@@ -20,13 +20,13 @@
#
import sys
if sys.version_info[0] >= 3: # Python 3
- import tkinter as tk
- from tkinter import ttk
- from tkinter import messagebox as msgbox
+ import tkinter as tk
+ from tkinter import ttk
+ from tkinter import messagebox as msgbox
else:
- import Tkinter as tk
- import tkMessageBox as msgbox
- import ttk
+ import Tkinter as tk
+ import tkMessageBox as msgbox
+ import ttk
import random
import pjsua2 as pj
@@ -35,72 +35,72 @@ import endpoint as ep
# Call class
class Call(pj.Call):
- """
- High level Python Call object, derived from pjsua2's Call object.
- """
- def __init__(self, acc, peer_uri='', chat=None, call_id = pj.PJSUA_INVALID_ID):
- pj.Call.__init__(self, acc, call_id)
- self.acc = acc
- self.peerUri = peer_uri
- self.chat = chat
- self.connected = False
- self.onhold = False
+ """
+ High level Python Call object, derived from pjsua2's Call object.
+ """
+ def __init__(self, acc, peer_uri='', chat=None, call_id = pj.PJSUA_INVALID_ID):
+ pj.Call.__init__(self, acc, call_id)
+ self.acc = acc
+ self.peerUri = peer_uri
+ self.chat = chat
+ self.connected = False
+ self.onhold = False
+
+ def onCallState(self, prm):
+ ci = self.getInfo()
+ self.connected = ci.state == pj.PJSIP_INV_STATE_CONFIRMED
+ if self.chat:
+ self.chat.updateCallState(self, ci)
+
+ def onCallMediaState(self, prm):
+ ci = self.getInfo()
+ for mi in ci.media:
+ if mi.type == pj.PJMEDIA_TYPE_AUDIO and \
+ (mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE or \
+ mi.status == pj.PJSUA_CALL_MEDIA_REMOTE_HOLD):
+ m = self.getMedia(mi.index)
+ am = pj.AudioMedia.typecastFromMedia(m)
+ # connect ports
+ ep.Endpoint.instance.audDevManager().getCaptureDevMedia().startTransmit(am)
+ am.startTransmit(ep.Endpoint.instance.audDevManager().getPlaybackDevMedia())
+
+ if mi.status == pj.PJSUA_CALL_MEDIA_REMOTE_HOLD and not self.onhold:
+ self.chat.addMessage(None, "'%s' sets call onhold" % (self.peerUri))
+ self.onhold = True
+ elif mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE and self.onhold:
+ self.chat.addMessage(None, "'%s' sets call active" % (self.peerUri))
+ self.onhold = False
+ if self.chat:
+ self.chat.updateCallMediaState(self, ci)
+
+ def onInstantMessage(self, prm):
+ # chat instance should have been initalized
+ if not self.chat: return
+
+ self.chat.addMessage(self.peerUri, prm.msgBody)
+ self.chat.showWindow()
+
+ def onInstantMessageStatus(self, prm):
+ if prm.code/100 == 2: return
+ # chat instance should have been initalized
+ if not self.chat: return
+
+ self.chat.addMessage(None, "Failed sending message to '%s' (%d): %s" % (self.peerUri, prm.code, prm.reason))
+
+ def onTypingIndication(self, prm):
+ # chat instance should have been initalized
+ if not self.chat: return
+
+ self.chat.setTypingIndication(self.peerUri, prm.isTyping)
+
+ def onDtmfDigit(self, prm):
+ #msgbox.showinfo("pygui", 'Got DTMF:' + prm.digit)
+ pass
+
+ def onCallMediaTransportState(self, prm):
+ #msgbox.showinfo("pygui", "Media transport state")
+ pass
- def onCallState(self, prm):
- ci = self.getInfo()
- self.connected = ci.state == pj.PJSIP_INV_STATE_CONFIRMED
- if self.chat:
- self.chat.updateCallState(self, ci)
-
- def onCallMediaState(self, prm):
- ci = self.getInfo()
- for mi in ci.media:
- if mi.type == pj.PJMEDIA_TYPE_AUDIO and \
- (mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE or \
- mi.status == pj.PJSUA_CALL_MEDIA_REMOTE_HOLD):
- m = self.getMedia(mi.index)
- am = pj.AudioMedia.typecastFromMedia(m)
- # connect ports
- ep.Endpoint.instance.audDevManager().getCaptureDevMedia().startTransmit(am)
- am.startTransmit(ep.Endpoint.instance.audDevManager().getPlaybackDevMedia())
- if mi.status == pj.PJSUA_CALL_MEDIA_REMOTE_HOLD and not self.onhold:
- self.chat.addMessage(None, "'%s' sets call onhold" % (self.peerUri))
- self.onhold = True
- elif mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE and self.onhold:
- self.chat.addMessage(None, "'%s' sets call active" % (self.peerUri))
- self.onhold = False
- if self.chat:
- self.chat.updateCallMediaState(self, ci)
-
- def onInstantMessage(self, prm):
- # chat instance should have been initalized
- if not self.chat: return
-
- self.chat.addMessage(self.peerUri, prm.msgBody)
- self.chat.showWindow()
-
- def onInstantMessageStatus(self, prm):
- if prm.code/100 == 2: return
- # chat instance should have been initalized
- if not self.chat: return
-
- self.chat.addMessage(None, "Failed sending message to '%s' (%d): %s" % (self.peerUri, prm.code, prm.reason))
-
- def onTypingIndication(self, prm):
- # chat instance should have been initalized
- if not self.chat: return
-
- self.chat.setTypingIndication(self.peerUri, prm.isTyping)
-
- def onDtmfDigit(self, prm):
- #msgbox.showinfo("pygui", 'Got DTMF:' + prm.digit)
- pass
-
- def onCallMediaTransportState(self, prm):
- #msgbox.showinfo("pygui", "Media transport state")
- pass
-
-
if __name__ == '__main__':
- application.main()
+ application.main()
diff --git a/pjsip-apps/src/pygui/chat.py b/pjsip-apps/src/pygui/chat.py
index 6a5bff0..384c7ea 100644
--- a/pjsip-apps/src/pygui/chat.py
+++ b/pjsip-apps/src/pygui/chat.py
@@ -1,4 +1,4 @@
-# $Id: chat.py 4757 2014-02-21 07:53:31Z nanang $
+# $Id: chat.py 5638 2017-08-02 09:45:09Z riza $
#
# pjsua Python GUI Demo
#
@@ -20,11 +20,11 @@
#
import sys
if sys.version_info[0] >= 3: # Python 3
- import tkinter as tk
- from tkinter import ttk
+ import tkinter as tk
+ from tkinter import ttk
else:
- import Tkinter as tk
- import ttk
+ import Tkinter as tk
+ import ttk
import buddy
import call
@@ -35,510 +35,511 @@ import re
SipUriRegex = re.compile('(sip|sips):([^:;>\@]*)@?([^:;>]*):?([^:;>]*)')
ConfIdx = 1
+write=sys.stdout.write
# Simple SIP uri parser, input URI must have been validated
def ParseSipUri(sip_uri_str):
- m = SipUriRegex.search(sip_uri_str)
- if not m:
- assert(0)
- return None
-
- scheme = m.group(1)
- user = m.group(2)
- host = m.group(3)
- port = m.group(4)
- if host == '':
- host = user
- user = ''
-
- return SipUri(scheme.lower(), user, host.lower(), port)
-
+ m = SipUriRegex.search(sip_uri_str)
+ if not m:
+ assert(0)
+ return None
+
+ scheme = m.group(1)
+ user = m.group(2)
+ host = m.group(3)
+ port = m.group(4)
+ if host == '':
+ host = user
+ user = ''
+
+ return SipUri(scheme.lower(), user, host.lower(), port)
+
class SipUri:
- def __init__(self, scheme, user, host, port):
- self.scheme = scheme
- self.user = user
- self.host = host
- self.port = port
-
- def __cmp__(self, sip_uri):
- if self.scheme == sip_uri.scheme and self.user == sip_uri.user and self.host == sip_uri.host:
- # don't check port, at least for now
- return 0
- return -1
-
- def __str__(self):
- s = self.scheme + ':'
- if self.user: s += self.user + '@'
- s += self.host
- if self.port: s+= ':' + self.port
- return s
-
+ def __init__(self, scheme, user, host, port):
+ self.scheme = scheme
+ self.user = user
+ self.host = host
+ self.port = port
+
+ def __cmp__(self, sip_uri):
+ if self.scheme == sip_uri.scheme and self.user == sip_uri.user and self.host == sip_uri.host:
+ # don't check port, at least for now
+ return 0
+ return -1
+
+ def __str__(self):
+ s = self.scheme + ':'
+ if self.user: s += self.user + '@'
+ s += self.host
+ if self.port: s+= ':' + self.port
+ return s
+
class Chat(gui.ChatObserver):
- def __init__(self, app, acc, uri, call_inst=None):
- self._app = app
- self._acc = acc
- self.title = ''
-
- global ConfIdx
- self.confIdx = ConfIdx
- ConfIdx += 1
-
- # each participant call/buddy instances are stored in call list
- # and buddy list with same index as in particpant list
- self._participantList = [] # list of SipUri
- self._callList = [] # list of Call
- self._buddyList = [] # list of Buddy
-
- self._gui = gui.ChatFrame(self)
- self.addParticipant(uri, call_inst)
-
- def _updateGui(self):
- if self.isPrivate():
- self.title = str(self._participantList[0])
- else:
- self.title = 'Conference #%d (%d participants)' % (self.confIdx, len(self._participantList))
- self._gui.title(self.title)
- self._app.updateWindowMenu()
-
- def _getCallFromUriStr(self, uri_str, op = ''):
- uri = ParseSipUri(uri_str)
- if uri not in self._participantList:
- print "=== %s cannot find participant with URI '%s'" % (op, uri_str)
- return None
- idx = self._participantList.index(uri)
- if idx < len(self._callList):
- return self._callList[idx]
- return None
-
- def _getActiveMediaIdx(self, thecall):
- ci = thecall.getInfo()
- for mi in ci.media:
- if mi.type == pj.PJMEDIA_TYPE_AUDIO and \
- (mi.status != pj.PJSUA_CALL_MEDIA_NONE and \
- mi.status != pj.PJSUA_CALL_MEDIA_ERROR):
- return mi.index
- return -1
-
- def _getAudioMediaFromUriStr(self, uri_str):
- c = self._getCallFromUriStr(uri_str)
- if not c: return None
-
- idx = self._getActiveMediaIdx(c)
- if idx < 0: return None
-
- m = c.getMedia(idx)
- am = pj.AudioMedia.typecastFromMedia(m)
- return am
-
- def _sendTypingIndication(self, is_typing, sender_uri_str=''):
- sender_uri = ParseSipUri(sender_uri_str) if sender_uri_str else None
- type_ind_param = pj.SendTypingIndicationParam()
- type_ind_param.isTyping = is_typing
- for idx, p in enumerate(self._participantList):
- # don't echo back to the original sender
- if sender_uri and p == sender_uri:
- continue
-
- # send via call, if any, or buddy
- target = None
- if self._callList[idx] and self._callList[idx].connected:
- target = self._callList[idx]
- else:
- target = self._buddyList[idx]
- assert(target)
-
- try:
- target.sendTypingIndication(type_ind_param)
- except:
- pass
-
- def _sendInstantMessage(self, msg, sender_uri_str=''):
- sender_uri = ParseSipUri(sender_uri_str) if sender_uri_str else None
- send_im_param = pj.SendInstantMessageParam()
- send_im_param.content = str(msg)
- for idx, p in enumerate(self._participantList):
- # don't echo back to the original sender
- if sender_uri and p == sender_uri:
- continue
-
- # send via call, if any, or buddy
- target = None
- if self._callList[idx] and self._callList[idx].connected:
- target = self._callList[idx]
- else:
- target = self._buddyList[idx]
- assert(target)
-
- try:
- target.sendInstantMessage(send_im_param)
- except:
- # error will be handled via Account::onInstantMessageStatus()
- pass
-
- def isPrivate(self):
- return len(self._participantList) <= 1
-
- def isUriParticipant(self, uri):
- return uri in self._participantList
-
- def registerCall(self, uri_str, call_inst):
- uri = ParseSipUri(uri_str)
- try:
- idx = self._participantList.index(uri)
- bud = self._buddyList[idx]
- self._callList[idx] = call_inst
- call_inst.chat = self
- call_inst.peerUri = bud.cfg.uri
- except:
- assert(0) # idx must be found!
-
- def showWindow(self, show_text_chat = False):
- self._gui.bringToFront()
- if show_text_chat:
- self._gui.textShowHide(True)
-
- def addParticipant(self, uri, call_inst=None):
- # avoid duplication
- if self.isUriParticipant(uri): return
-
- uri_str = str(uri)
-
- # find buddy, create one if not found (e.g: for IM/typing ind),
- # it is a temporary one and not really registered to acc
- bud = None
- try:
- bud = self._acc.findBuddy(uri_str)
- except:
- bud = buddy.Buddy(None)
- bud_cfg = pj.BuddyConfig()
- bud_cfg.uri = uri_str
- bud_cfg.subscribe = False
- bud.create(self._acc, bud_cfg)
- bud.cfg = bud_cfg
- bud.account = self._acc
-
- # update URI from buddy URI
- uri = ParseSipUri(bud.cfg.uri)
-
- # add it
- self._participantList.append(uri)
- self._callList.append(call_inst)
- self._buddyList.append(bud)
- self._gui.addParticipant(str(uri))
- self._updateGui()
-
- def kickParticipant(self, uri):
- if (not uri) or (uri not in self._participantList):
- assert(0)
- return
-
- idx = self._participantList.index(uri)
- del self._participantList[idx]
- del self._callList[idx]
- del self._buddyList[idx]
- self._gui.delParticipant(str(uri))
-
- if self._participantList:
- self._updateGui()
- else:
- self.onCloseWindow()
-
- def addMessage(self, from_uri_str, msg):
- if from_uri_str:
- # print message on GUI
- msg = from_uri_str + ': ' + msg
- self._gui.textAddMessage(msg)
- # now relay to all participants
- self._sendInstantMessage(msg, from_uri_str)
- else:
- self._gui.textAddMessage(msg, False)
-
- def setTypingIndication(self, from_uri_str, is_typing):
- # notify GUI
- self._gui.textSetTypingIndication(from_uri_str, is_typing)
- # now relay to all participants
- self._sendTypingIndication(is_typing, from_uri_str)
-
- def startCall(self):
- self._gui.enableAudio()
- call_param = pj.CallOpParam()
- call_param.opt.audioCount = 1
- call_param.opt.videoCount = 0
- fails = []
- for idx, p in enumerate(self._participantList):
- # just skip if call is instantiated
- if self._callList[idx]:
- continue
-
- uri_str = str(p)
- c = call.Call(self._acc, uri_str, self)
- self._callList[idx] = c
- self._gui.audioUpdateState(uri_str, gui.AudioState.INITIALIZING)
-
- try:
- c.makeCall(uri_str, call_param)
- except:
- self._callList[idx] = None
- self._gui.audioUpdateState(uri_str, gui.AudioState.FAILED)
- fails.append(p)
-
- for p in fails:
- # kick participants with call failure, but spare the last (avoid zombie chat)
- if not self.isPrivate():
- self.kickParticipant(p)
-
- def stopCall(self):
- for idx, p in enumerate(self._participantList):
- self._gui.audioUpdateState(str(p), gui.AudioState.DISCONNECTED)
- c = self._callList[idx]
- if c:
- c.hangup(pj.CallOpParam())
-
- def updateCallState(self, thecall, info = None):
- # info is optional here, just to avoid calling getInfo() twice (in the caller and here)
- if not info: info = thecall.getInfo()
-
- if info.state < pj.PJSIP_INV_STATE_CONFIRMED:
- self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.INITIALIZING)
- elif info.state == pj.PJSIP_INV_STATE_CONFIRMED:
- self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.CONNECTED)
- if not self.isPrivate():
- # inform peer about conference participants
- conf_welcome_str = '\n---\n'
- conf_welcome_str += 'Welcome to the conference, participants:\n'
- conf_welcome_str += '%s (host)\n' % (self._acc.cfg.idUri)
- for p in self._participantList:
- conf_welcome_str += '%s\n' % (str(p))
- conf_welcome_str += '---\n'
- send_im_param = pj.SendInstantMessageParam()
- send_im_param.content = conf_welcome_str
- try:
- thecall.sendInstantMessage(send_im_param)
- except:
- pass
-
- # inform others, including self
- msg = "[Conf manager] %s has joined" % (thecall.peerUri)
- self.addMessage(None, msg)
- self._sendInstantMessage(msg, thecall.peerUri)
-
- elif info.state == pj.PJSIP_INV_STATE_DISCONNECTED:
- if info.lastStatusCode/100 != 2:
- self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.FAILED)
- else:
- self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.DISCONNECTED)
-
- # reset entry in the callList
- try:
- idx = self._callList.index(thecall)
- if idx >= 0: self._callList[idx] = None
- except:
- pass
-
- self.addMessage(None, "Call to '%s' disconnected: %s" % (thecall.peerUri, info.lastReason))
-
- # kick the disconnected participant, but the last (avoid zombie chat)
- if not self.isPrivate():
- self.kickParticipant(ParseSipUri(thecall.peerUri))
-
- # inform others, including self
- msg = "[Conf manager] %s has left" % (thecall.peerUri)
- self.addMessage(None, msg)
- self._sendInstantMessage(msg, thecall.peerUri)
-
- def updateCallMediaState(self, thecall, info = None):
- # info is optional here, just to avoid calling getInfo() twice (in the caller and here)
- if not info: info = thecall.getInfo()
-
- med_idx = self._getActiveMediaIdx(thecall)
- if (med_idx < 0):
- self._gui.audioSetStatsText(thecall.peerUri, 'No active media')
- return
-
- si = thecall.getStreamInfo(med_idx)
- dir_str = ''
- if si.dir == 0:
- dir_str = 'inactive'
- else:
- if si.dir & pj.PJMEDIA_DIR_ENCODING:
- dir_str += 'send '
- if si.dir & pj.PJMEDIA_DIR_DECODING:
- dir_str += 'receive '
- stats_str = "Direction : %s\n" % (dir_str)
- stats_str += "Audio codec : %s (%sHz)" % (si.codecName, si.codecClockRate)
- self._gui.audioSetStatsText(thecall.peerUri, stats_str)
- m = pj.AudioMedia.typecastFromMedia(thecall.getMedia(med_idx))
-
- # make conference
- for c in self._callList:
- if c == thecall:
- continue
- med_idx = self._getActiveMediaIdx(c)
- if med_idx < 0:
- continue
- mm = pj.AudioMedia.typecastFromMedia(c.getMedia(med_idx))
- m.startTransmit(mm)
- mm.startTransmit(m)
-
-
- # ** callbacks from GUI (ChatObserver implementation) **
-
- # Text
- def onSendMessage(self, msg):
- self._sendInstantMessage(msg)
-
- def onStartTyping(self):
- self._sendTypingIndication(True)
-
- def onStopTyping(self):
- self._sendTypingIndication(False)
-
- # Audio
- def onHangup(self, peer_uri_str):
- c = self._getCallFromUriStr(peer_uri_str, "onHangup()")
- if not c: return
- call_param = pj.CallOpParam()
- c.hangup(call_param)
-
- def onHold(self, peer_uri_str):
- c = self._getCallFromUriStr(peer_uri_str, "onHold()")
- if not c: return
- call_param = pj.CallOpParam()
- c.setHold(call_param)
-
- def onUnhold(self, peer_uri_str):
- c = self._getCallFromUriStr(peer_uri_str, "onUnhold()")
- if not c: return
-
- call_param = pj.CallOpParam()
- call_param.opt.audioCount = 1
- call_param.opt.videoCount = 0
- call_param.opt.flag |= pj.PJSUA_CALL_UNHOLD
- c.reinvite(call_param)
-
- def onRxMute(self, peer_uri_str, mute):
- am = self._getAudioMediaFromUriStr(peer_uri_str)
- if not am: return
- if mute:
- am.stopTransmit(ep.Endpoint.instance.audDevManager().getPlaybackDevMedia())
- self.addMessage(None, "Muted audio from '%s'" % (peer_uri_str))
- else:
- am.startTransmit(ep.Endpoint.instance.audDevManager().getPlaybackDevMedia())
- self.addMessage(None, "Unmuted audio from '%s'" % (peer_uri_str))
-
- def onRxVol(self, peer_uri_str, vol_pct):
- am = self._getAudioMediaFromUriStr(peer_uri_str)
- if not am: return
- # pjsua volume range = 0:mute, 1:no adjustment, 2:100% louder
- am.adjustRxLevel(vol_pct/50.0)
- self.addMessage(None, "Adjusted volume level audio from '%s'" % (peer_uri_str))
-
- def onTxMute(self, peer_uri_str, mute):
- am = self._getAudioMediaFromUriStr(peer_uri_str)
- if not am: return
- if mute:
- ep.Endpoint.instance.audDevManager().getCaptureDevMedia().stopTransmit(am)
- self.addMessage(None, "Muted audio to '%s'" % (peer_uri_str))
- else:
- ep.Endpoint.instance.audDevManager().getCaptureDevMedia().startTransmit(am)
- self.addMessage(None, "Unmuted audio to '%s'" % (peer_uri_str))
-
- # Chat room
- def onAddParticipant(self):
- buds = []
- dlg = AddParticipantDlg(None, self._app, buds)
- if dlg.doModal():
- for bud in buds:
- uri = ParseSipUri(bud.cfg.uri)
- self.addParticipant(uri)
- if not self.isPrivate():
- self.startCall()
-
- def onStartAudio(self):
- self.startCall()
-
- def onStopAudio(self):
- self.stopCall()
-
- def onCloseWindow(self):
- self.stopCall()
- # will remove entry from list eventually destroy this chat?
- if self in self._acc.chatList: self._acc.chatList.remove(self)
- self._app.updateWindowMenu()
- # destroy GUI
- self._gui.destroy()
+ def __init__(self, app, acc, uri, call_inst=None):
+ self._app = app
+ self._acc = acc
+ self.title = ''
+
+ global ConfIdx
+ self.confIdx = ConfIdx
+ ConfIdx += 1
+
+ # each participant call/buddy instances are stored in call list
+ # and buddy list with same index as in particpant list
+ self._participantList = [] # list of SipUri
+ self._callList = [] # list of Call
+ self._buddyList = [] # list of Buddy
+
+ self._gui = gui.ChatFrame(self)
+ self.addParticipant(uri, call_inst)
+
+ def _updateGui(self):
+ if self.isPrivate():
+ self.title = str(self._participantList[0])
+ else:
+ self.title = 'Conference #%d (%d participants)' % (self.confIdx, len(self._participantList))
+ self._gui.title(self.title)
+ self._app.updateWindowMenu()
+
+ def _getCallFromUriStr(self, uri_str, op = ''):
+ uri = ParseSipUri(uri_str)
+ if uri not in self._participantList:
+ write("=== "+ op +" cannot find participant with URI '" + uri_str + "'\r\n")
+ return None
+ idx = self._participantList.index(uri)
+ if idx < len(self._callList):
+ return self._callList[idx]
+ return None
+
+ def _getActiveMediaIdx(self, thecall):
+ ci = thecall.getInfo()
+ for mi in ci.media:
+ if mi.type == pj.PJMEDIA_TYPE_AUDIO and \
+ (mi.status != pj.PJSUA_CALL_MEDIA_NONE and \
+ mi.status != pj.PJSUA_CALL_MEDIA_ERROR):
+ return mi.index
+ return -1
+
+ def _getAudioMediaFromUriStr(self, uri_str):
+ c = self._getCallFromUriStr(uri_str)
+ if not c: return None
+
+ idx = self._getActiveMediaIdx(c)
+ if idx < 0: return None
+
+ m = c.getMedia(idx)
+ am = pj.AudioMedia.typecastFromMedia(m)
+ return am
+
+ def _sendTypingIndication(self, is_typing, sender_uri_str=''):
+ sender_uri = ParseSipUri(sender_uri_str) if sender_uri_str else None
+ type_ind_param = pj.SendTypingIndicationParam()
+ type_ind_param.isTyping = is_typing
+ for idx, p in enumerate(self._participantList):
+ # don't echo back to the original sender
+ if sender_uri and p == sender_uri:
+ continue
+
+ # send via call, if any, or buddy
+ target = None
+ if self._callList[idx] and self._callList[idx].connected:
+ target = self._callList[idx]
+ else:
+ target = self._buddyList[idx]
+ assert(target)
+
+ try:
+ target.sendTypingIndication(type_ind_param)
+ except:
+ pass
+
+ def _sendInstantMessage(self, msg, sender_uri_str=''):
+ sender_uri = ParseSipUri(sender_uri_str) if sender_uri_str else None
+ send_im_param = pj.SendInstantMessageParam()
+ send_im_param.content = str(msg)
+ for idx, p in enumerate(self._participantList):
+ # don't echo back to the original sender
+ if sender_uri and p == sender_uri:
+ continue
+
+ # send via call, if any, or buddy
+ target = None
+ if self._callList[idx] and self._callList[idx].connected:
+ target = self._callList[idx]
+ else:
+ target = self._buddyList[idx]
+ assert(target)
+
+ try:
+ target.sendInstantMessage(send_im_param)
+ except:
+ # error will be handled via Account::onInstantMessageStatus()
+ pass
+
+ def isPrivate(self):
+ return len(self._participantList) <= 1
+
+ def isUriParticipant(self, uri):
+ return uri in self._participantList
+
+ def registerCall(self, uri_str, call_inst):
+ uri = ParseSipUri(uri_str)
+ try:
+ idx = self._participantList.index(uri)
+ bud = self._buddyList[idx]
+ self._callList[idx] = call_inst
+ call_inst.chat = self
+ call_inst.peerUri = bud.cfg.uri
+ except:
+ assert(0) # idx must be found!
+
+ def showWindow(self, show_text_chat = False):
+ self._gui.bringToFront()
+ if show_text_chat:
+ self._gui.textShowHide(True)
+
+ def addParticipant(self, uri, call_inst=None):
+ # avoid duplication
+ if self.isUriParticipant(uri): return
+
+ uri_str = str(uri)
+
+ # find buddy, create one if not found (e.g: for IM/typing ind),
+ # it is a temporary one and not really registered to acc
+ bud = None
+ try:
+ bud = self._acc.findBuddy(uri_str)
+ except:
+ bud = buddy.Buddy(None)
+ bud_cfg = pj.BuddyConfig()
+ bud_cfg.uri = uri_str
+ bud_cfg.subscribe = False
+ bud.create(self._acc, bud_cfg)
+ bud.cfg = bud_cfg
+ bud.account = self._acc
+
+ # update URI from buddy URI
+ uri = ParseSipUri(bud.cfg.uri)
+
+ # add it
+ self._participantList.append(uri)
+ self._callList.append(call_inst)
+ self._buddyList.append(bud)
+ self._gui.addParticipant(str(uri))
+ self._updateGui()
+
+ def kickParticipant(self, uri):
+ if (not uri) or (uri not in self._participantList):
+ assert(0)
+ return
+
+ idx = self._participantList.index(uri)
+ del self._participantList[idx]
+ del self._callList[idx]
+ del self._buddyList[idx]
+ self._gui.delParticipant(str(uri))
+
+ if self._participantList:
+ self._updateGui()
+ else:
+ self.onCloseWindow()
+
+ def addMessage(self, from_uri_str, msg):
+ if from_uri_str:
+ # print message on GUI
+ msg = from_uri_str + ': ' + msg
+ self._gui.textAddMessage(msg)
+ # now relay to all participants
+ self._sendInstantMessage(msg, from_uri_str)
+ else:
+ self._gui.textAddMessage(msg, False)
+
+ def setTypingIndication(self, from_uri_str, is_typing):
+ # notify GUI
+ self._gui.textSetTypingIndication(from_uri_str, is_typing)
+ # now relay to all participants
+ self._sendTypingIndication(is_typing, from_uri_str)
+
+ def startCall(self):
+ self._gui.enableAudio()
+ call_param = pj.CallOpParam()
+ call_param.opt.audioCount = 1
+ call_param.opt.videoCount = 0
+ fails = []
+ for idx, p in enumerate(self._participantList):
+ # just skip if call is instantiated
+ if self._callList[idx]:
+ continue
+
+ uri_str = str(p)
+ c = call.Call(self._acc, uri_str, self)
+ self._callList[idx] = c
+ self._gui.audioUpdateState(uri_str, gui.AudioState.INITIALIZING)
+
+ try:
+ c.makeCall(uri_str, call_param)
+ except:
+ self._callList[idx] = None
+ self._gui.audioUpdateState(uri_str, gui.AudioState.FAILED)
+ fails.append(p)
+
+ for p in fails:
+ # kick participants with call failure, but spare the last (avoid zombie chat)
+ if not self.isPrivate():
+ self.kickParticipant(p)
+
+ def stopCall(self):
+ for idx, p in enumerate(self._participantList):
+ self._gui.audioUpdateState(str(p), gui.AudioState.DISCONNECTED)
+ c = self._callList[idx]
+ if c:
+ c.hangup(pj.CallOpParam())
+
+ def updateCallState(self, thecall, info = None):
+ # info is optional here, just to avoid calling getInfo() twice (in the caller and here)
+ if not info: info = thecall.getInfo()
+
+ if info.state < pj.PJSIP_INV_STATE_CONFIRMED:
+ self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.INITIALIZING)
+ elif info.state == pj.PJSIP_INV_STATE_CONFIRMED:
+ self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.CONNECTED)
+ if not self.isPrivate():
+ # inform peer about conference participants
+ conf_welcome_str = '\n---\n'
+ conf_welcome_str += 'Welcome to the conference, participants:\n'
+ conf_welcome_str += '%s (host)\n' % (self._acc.cfg.idUri)
+ for p in self._participantList:
+ conf_welcome_str += '%s\n' % (str(p))
+ conf_welcome_str += '---\n'
+ send_im_param = pj.SendInstantMessageParam()
+ send_im_param.content = conf_welcome_str
+ try:
+ thecall.sendInstantMessage(send_im_param)
+ except:
+ pass
+
+ # inform others, including self
+ msg = "[Conf manager] %s has joined" % (thecall.peerUri)
+ self.addMessage(None, msg)
+ self._sendInstantMessage(msg, thecall.peerUri)
+
+ elif info.state == pj.PJSIP_INV_STATE_DISCONNECTED:
+ if info.lastStatusCode/100 != 2:
+ self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.FAILED)
+ else:
+ self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.DISCONNECTED)
+
+ # reset entry in the callList
+ try:
+ idx = self._callList.index(thecall)
+ if idx >= 0: self._callList[idx] = None
+ except:
+ pass
+
+ self.addMessage(None, "Call to '%s' disconnected: %s" % (thecall.peerUri, info.lastReason))
+
+ # kick the disconnected participant, but the last (avoid zombie chat)
+ if not self.isPrivate():
+ self.kickParticipant(ParseSipUri(thecall.peerUri))
+
+ # inform others, including self
+ msg = "[Conf manager] %s has left" % (thecall.peerUri)
+ self.addMessage(None, msg)
+ self._sendInstantMessage(msg, thecall.peerUri)
+
+ def updateCallMediaState(self, thecall, info = None):
+ # info is optional here, just to avoid calling getInfo() twice (in the caller and here)
+ if not info: info = thecall.getInfo()
+
+ med_idx = self._getActiveMediaIdx(thecall)
+ if (med_idx < 0):
+ self._gui.audioSetStatsText(thecall.peerUri, 'No active media')
+ return
+
+ si = thecall.getStreamInfo(med_idx)
+ dir_str = ''
+ if si.dir == 0:
+ dir_str = 'inactive'
+ else:
+ if si.dir & pj.PJMEDIA_DIR_ENCODING:
+ dir_str += 'send '
+ if si.dir & pj.PJMEDIA_DIR_DECODING:
+ dir_str += 'receive '
+ stats_str = "Direction : %s\n" % (dir_str)
+ stats_str += "Audio codec : %s (%sHz)" % (si.codecName, si.codecClockRate)
+ self._gui.audioSetStatsText(thecall.peerUri, stats_str)
+ m = pj.AudioMedia.typecastFromMedia(thecall.getMedia(med_idx))
+
+ # make conference
+ for c in self._callList:
+ if c == thecall:
+ continue
+ med_idx = self._getActiveMediaIdx(c)
+ if med_idx < 0:
+ continue
+ mm = pj.AudioMedia.typecastFromMedia(c.getMedia(med_idx))
+ m.startTransmit(mm)
+ mm.startTransmit(m)
+
+
+ # ** callbacks from GUI (ChatObserver implementation) **
+
+ # Text
+ def onSendMessage(self, msg):
+ self._sendInstantMessage(msg)
+
+ def onStartTyping(self):
+ self._sendTypingIndication(True)
+
+ def onStopTyping(self):
+ self._sendTypingIndication(False)
+
+ # Audio
+ def onHangup(self, peer_uri_str):
+ c = self._getCallFromUriStr(peer_uri_str, "onHangup()")
+ if not c: return
+ call_param = pj.CallOpParam()
+ c.hangup(call_param)
+
+ def onHold(self, peer_uri_str):
+ c = self._getCallFromUriStr(peer_uri_str, "onHold()")
+ if not c: return
+ call_param = pj.CallOpParam()
+ c.setHold(call_param)
+
+ def onUnhold(self, peer_uri_str):
+ c = self._getCallFromUriStr(peer_uri_str, "onUnhold()")
+ if not c: return
+
+ call_param = pj.CallOpParam()
+ call_param.opt.audioCount = 1
+ call_param.opt.videoCount = 0
+ call_param.opt.flag |= pj.PJSUA_CALL_UNHOLD
+ c.reinvite(call_param)
+
+ def onRxMute(self, peer_uri_str, mute):
+ am = self._getAudioMediaFromUriStr(peer_uri_str)
+ if not am: return
+ if mute:
+ am.stopTransmit(ep.Endpoint.instance.audDevManager().getPlaybackDevMedia())
+ self.addMessage(None, "Muted audio from '%s'" % (peer_uri_str))
+ else:
+ am.startTransmit(ep.Endpoint.instance.audDevManager().getPlaybackDevMedia())
+ self.addMessage(None, "Unmuted audio from '%s'" % (peer_uri_str))
+
+ def onRxVol(self, peer_uri_str, vol_pct):
+ am = self._getAudioMediaFromUriStr(peer_uri_str)
+ if not am: return
+ # pjsua volume range = 0:mute, 1:no adjustment, 2:100% louder
+ am.adjustRxLevel(vol_pct/50.0)
+ self.addMessage(None, "Adjusted volume level audio from '%s'" % (peer_uri_str))
+
+ def onTxMute(self, peer_uri_str, mute):
+ am = self._getAudioMediaFromUriStr(peer_uri_str)
+ if not am: return
+ if mute:
+ ep.Endpoint.instance.audDevManager().getCaptureDevMedia().stopTransmit(am)
+ self.addMessage(None, "Muted audio to '%s'" % (peer_uri_str))
+ else:
+ ep.Endpoint.instance.audDevManager().getCaptureDevMedia().startTransmit(am)
+ self.addMessage(None, "Unmuted audio to '%s'" % (peer_uri_str))
+
+ # Chat room
+ def onAddParticipant(self):
+ buds = []
+ dlg = AddParticipantDlg(None, self._app, buds)
+ if dlg.doModal():
+ for bud in buds:
+ uri = ParseSipUri(bud.cfg.uri)
+ self.addParticipant(uri)
+ if not self.isPrivate():
+ self.startCall()
+
+ def onStartAudio(self):
+ self.startCall()
+
+ def onStopAudio(self):
+ self.stopCall()
+
+ def onCloseWindow(self):
+ self.stopCall()
+ # will remove entry from list eventually destroy this chat?
+ if self in self._acc.chatList: self._acc.chatList.remove(self)
+ self._app.updateWindowMenu()
+ # destroy GUI
+ self._gui.destroy()
class AddParticipantDlg(tk.Toplevel):
- """
- List of buddies
- """
- def __init__(self, parent, app, bud_list):
- tk.Toplevel.__init__(self, parent)
- self.title('Add participants..')
- self.transient(parent)
- self.parent = parent
- self._app = app
- self.buddyList = bud_list
-
- self.isOk = False
-
- self.createWidgets()
-
- def doModal(self):
- if self.parent:
- self.parent.wait_window(self)
- else:
- self.wait_window(self)
- return self.isOk
-
- def createWidgets(self):
- # buddy list
- list_frame = ttk.Frame(self)
- list_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=1, padx=20, pady=20)
- #scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=list_frame.yview)
- #list_frame.config(yscrollcommand=scrl.set)
- #scrl.pack(side=tk.RIGHT, fill=tk.Y)
-
- # draw buddy list
- self.buddies = []
- for acc in self._app.accList:
- self.buddies.append((0, acc.cfg.idUri))
- for bud in acc.buddyList:
- self.buddies.append((1, bud))
-
- self.bud_var = []
- for idx,(flag,bud) in enumerate(self.buddies):
- self.bud_var.append(tk.IntVar())
- if flag==0:
- s = ttk.Separator(list_frame, orient=tk.HORIZONTAL)
- s.pack(fill=tk.X)
- l = tk.Label(list_frame, anchor=tk.W, text="Account '%s':" % (bud))
- l.pack(fill=tk.X)
- else:
- c = tk.Checkbutton(list_frame, anchor=tk.W, text=bud.cfg.uri, variable=self.bud_var[idx])
- c.pack(fill=tk.X)
- s = ttk.Separator(list_frame, orient=tk.HORIZONTAL)
- s.pack(fill=tk.X)
-
- # Ok/cancel buttons
- tail_frame = ttk.Frame(self)
- tail_frame.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1)
-
- btnOk = ttk.Button(tail_frame, text='Ok', default=tk.ACTIVE, command=self.onOk)
- btnOk.pack(side=tk.LEFT, padx=20, pady=10)
- btnCancel = ttk.Button(tail_frame, text='Cancel', command=self.onCancel)
- btnCancel.pack(side=tk.RIGHT, padx=20, pady=10)
-
- def onOk(self):
- self.buddyList[:] = []
- for idx,(flag,bud) in enumerate(self.buddies):
- if not flag: continue
- if self.bud_var[idx].get() and not (bud in self.buddyList):
- self.buddyList.append(bud)
-
- self.isOk = True
- self.destroy()
-
- def onCancel(self):
- self.destroy()
+ """
+ List of buddies
+ """
+ def __init__(self, parent, app, bud_list):
+ tk.Toplevel.__init__(self, parent)
+ self.title('Add participants..')
+ self.transient(parent)
+ self.parent = parent
+ self._app = app
+ self.buddyList = bud_list
+
+ self.isOk = False
+
+ self.createWidgets()
+
+ def doModal(self):
+ if self.parent:
+ self.parent.wait_window(self)
+ else:
+ self.wait_window(self)
+ return self.isOk
+
+ def createWidgets(self):
+ # buddy list
+ list_frame = ttk.Frame(self)
+ list_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=1, padx=20, pady=20)
+ #scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=list_frame.yview)
+ #list_frame.config(yscrollcommand=scrl.set)
+ #scrl.pack(side=tk.RIGHT, fill=tk.Y)
+
+ # draw buddy list
+ self.buddies = []
+ for acc in self._app.accList:
+ self.buddies.append((0, acc.cfg.idUri))
+ for bud in acc.buddyList:
+ self.buddies.append((1, bud))
+
+ self.bud_var = []
+ for idx,(flag,bud) in enumerate(self.buddies):
+ self.bud_var.append(tk.IntVar())
+ if flag==0:
+ s = ttk.Separator(list_frame, orient=tk.HORIZONTAL)
+ s.pack(fill=tk.X)
+ l = tk.Label(list_frame, anchor=tk.W, text="Account '%s':" % (bud))
+ l.pack(fill=tk.X)
+ else:
+ c = tk.Checkbutton(list_frame, anchor=tk.W, text=bud.cfg.uri, variable=self.bud_var[idx])
+ c.pack(fill=tk.X)
+ s = ttk.Separator(list_frame, orient=tk.HORIZONTAL)
+ s.pack(fill=tk.X)
+
+ # Ok/cancel buttons
+ tail_frame = ttk.Frame(self)
+ tail_frame.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1)
+
+ btnOk = ttk.Button(tail_frame, text='Ok', default=tk.ACTIVE, command=self.onOk)
+ btnOk.pack(side=tk.LEFT, padx=20, pady=10)
+ btnCancel = ttk.Button(tail_frame, text='Cancel', command=self.onCancel)
+ btnCancel.pack(side=tk.RIGHT, padx=20, pady=10)
+
+ def onOk(self):
+ self.buddyList[:] = []
+ for idx,(flag,bud) in enumerate(self.buddies):
+ if not flag: continue
+ if self.bud_var[idx].get() and not (bud in self.buddyList):
+ self.buddyList.append(bud)
+
+ self.isOk = True
+ self.destroy()
+
+ def onCancel(self):
+ self.destroy()
diff --git a/pjsip-apps/src/pygui/chatgui.py b/pjsip-apps/src/pygui/chatgui.py
index 1cdf6f9..aebdc22 100644
--- a/pjsip-apps/src/pygui/chatgui.py
+++ b/pjsip-apps/src/pygui/chatgui.py
@@ -1,4 +1,4 @@
-# $Id: chatgui.py 4757 2014-02-21 07:53:31Z nanang $
+# $Id: chatgui.py 5638 2017-08-02 09:45:09Z riza $
#
# pjsua Python GUI Demo
#
@@ -20,401 +20,401 @@
#
import sys
if sys.version_info[0] >= 3: # Python 3
- import tkinter as tk
- from tkinter import ttk
- from tkinter import messagebox as msgbox
+ import tkinter as tk
+ from tkinter import ttk
+ from tkinter import messagebox as msgbox
else:
- import Tkinter as tk
- import ttk
- import tkMessageBox as msgbox
+ import Tkinter as tk
+ import ttk
+ import tkMessageBox as msgbox
class TextObserver:
- def onSendMessage(self, msg):
- pass
- def onStartTyping(self):
- pass
- def onStopTyping(self):
- pass
-
+ def onSendMessage(self, msg):
+ pass
+ def onStartTyping(self):
+ pass
+ def onStopTyping(self):
+ pass
+
class TextFrame(ttk.Frame):
- def __init__(self, master, observer):
- ttk.Frame.__init__(self, master)
- self._observer = observer
- self._isTyping = False
- self._createWidgets()
-
- def _onSendMessage(self, event):
- send_text = self._typingBox.get("1.0", tk.END).strip()
- if send_text == '':
- return
-
- self.addMessage('me: ' + send_text)
- self._typingBox.delete("0.0", tk.END)
- self._onTyping(None)
-
- # notify app for sending message
- self._observer.onSendMessage(send_text)
-
- def _onTyping(self, event):
- # notify app for typing indication
- is_typing = self._typingBox.get("1.0", tk.END).strip() != ''
- if is_typing != self._isTyping:
- self._isTyping = is_typing
- if is_typing:
- self._observer.onStartTyping()
- else:
- self._observer.onStopTyping()
-
- def _createWidgets(self):
- self.rowconfigure(0, weight=1)
- self.rowconfigure(1, weight=0)
- self.rowconfigure(2, weight=0)
- self.columnconfigure(0, weight=1)
- self.columnconfigure(1, weight=0)
-
- self._text = tk.Text(self, width=50, height=30, font=("Arial", "10"))
- self._text.grid(row=0, column=0, sticky='nswe')
- self._text.config(state=tk.DISABLED)
- self._text.tag_config("info", foreground="darkgray", font=("Arial", "9", "italic"))
-
- scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self._text.yview)
- self._text.config(yscrollcommand=scrl.set)
- scrl.grid(row=0, column=1, sticky='nsw')
-
- self._typingBox = tk.Text(self, width=50, height=1, font=("Arial", "10"))
- self._typingBox.grid(row=1, columnspan=2, sticky='we', pady=0)
-
- self._statusBar = tk.Label(self, anchor='w', font=("Arial", "8", "italic"))
- self._statusBar.grid(row=2, columnspan=2, sticky='we')
-
- self._typingBox.bind('<Return>', self._onSendMessage)
- self._typingBox.bind("<Key>", self._onTyping)
- self._typingBox.focus_set()
-
- def addMessage(self, msg, is_chat = True):
- self._text.config(state=tk.NORMAL)
- if is_chat:
- self._text.insert(tk.END, msg+'\r\n')
- else:
- self._text.insert(tk.END, msg+'\r\n', 'info')
- self._text.config(state=tk.DISABLED)
- self._text.yview(tk.END)
-
- def setTypingIndication(self, who, is_typing):
- if is_typing:
- self._statusBar['text'] = "'%s' is typing.." % (who)
- else:
- self._statusBar['text'] = ''
+ def __init__(self, master, observer):
+ ttk.Frame.__init__(self, master)
+ self._observer = observer
+ self._isTyping = False
+ self._createWidgets()
+
+ def _onSendMessage(self, event):
+ send_text = self._typingBox.get("1.0", tk.END).strip()
+ if send_text == '':
+ return
+
+ self.addMessage('me: ' + send_text)
+ self._typingBox.delete("0.0", tk.END)
+ self._onTyping(None)
+
+ # notify app for sending message
+ self._observer.onSendMessage(send_text)
+
+ def _onTyping(self, event):
+ # notify app for typing indication
+ is_typing = self._typingBox.get("1.0", tk.END).strip() != ''
+ if is_typing != self._isTyping:
+ self._isTyping = is_typing
+ if is_typing:
+ self._observer.onStartTyping()
+ else:
+ self._observer.onStopTyping()
+
+ def _createWidgets(self):
+ self.rowconfigure(0, weight=1)
+ self.rowconfigure(1, weight=0)
+ self.rowconfigure(2, weight=0)
+ self.columnconfigure(0, weight=1)
+ self.columnconfigure(1, weight=0)
+
+ self._text = tk.Text(self, width=50, height=30, font=("Arial", "10"))
+ self._text.grid(row=0, column=0, sticky='nswe')
+ self._text.config(state=tk.DISABLED)
+ self._text.tag_config("info", foreground="darkgray", font=("Arial", "9", "italic"))
+
+ scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self._text.yview)
+ self._text.config(yscrollcommand=scrl.set)
+ scrl.grid(row=0, column=1, sticky='nsw')
+
+ self._typingBox = tk.Text(self, width=50, height=1, font=("Arial", "10"))
+ self._typingBox.grid(row=1, columnspan=2, sticky='we', pady=0)
+
+ self._statusBar = tk.Label(self, anchor='w', font=("Arial", "8", "italic"))
+ self._statusBar.grid(row=2, columnspan=2, sticky='we')
+
+ self._typingBox.bind('<Return>', self._onSendMessage)
+ self._typingBox.bind("<Key>", self._onTyping)
+ self._typingBox.focus_set()
+
+ def addMessage(self, msg, is_chat = True):
+ self._text.config(state=tk.NORMAL)
+ if is_chat:
+ self._text.insert(tk.END, msg+'\r\n')
+ else:
+ self._text.insert(tk.END, msg+'\r\n', 'info')
+ self._text.config(state=tk.DISABLED)
+ self._text.yview(tk.END)
+
+ def setTypingIndication(self, who, is_typing):
+ if is_typing:
+ self._statusBar['text'] = "'%s' is typing.." % (who)
+ else:
+ self._statusBar['text'] = ''
class AudioState:
- NULL, INITIALIZING, CONNECTED, DISCONNECTED, FAILED = range(5)
-
+ NULL, INITIALIZING, CONNECTED, DISCONNECTED, FAILED = range(5)
+
class AudioObserver:
- def onHangup(self, peer_uri):
- pass
- def onHold(self, peer_uri):
- pass
- def onUnhold(self, peer_uri):
- pass
- def onRxMute(self, peer_uri, is_muted):
- pass
- def onRxVol(self, peer_uri, vol_pct):
- pass
- def onTxMute(self, peer_uri, is_muted):
- pass
-
+ def onHangup(self, peer_uri):
+ pass
+ def onHold(self, peer_uri):
+ pass
+ def onUnhold(self, peer_uri):
+ pass
+ def onRxMute(self, peer_uri, is_muted):
+ pass
+ def onRxVol(self, peer_uri, vol_pct):
+ pass
+ def onTxMute(self, peer_uri, is_muted):
+ pass
+
class AudioFrame(ttk.Labelframe):
- def __init__(self, master, peer_uri, observer):
- ttk.Labelframe.__init__(self, master, text=peer_uri)
- self.peerUri = peer_uri
- self._observer = observer
- self._initFrame = None
- self._callFrame = None
- self._rxMute = False
- self._txMute = False
- self._state = AudioState.NULL
-
- self._createInitWidgets()
- self._createWidgets()
-
- def updateState(self, state):
- if self._state == state:
- return
-
- if state == AudioState.INITIALIZING:
- self._callFrame.pack_forget()
- self._initFrame.pack(fill=tk.BOTH)
- self._btnCancel.pack(side=tk.TOP)
- self._lblInitState['text'] = 'Intializing..'
-
- elif state == AudioState.CONNECTED:
- self._initFrame.pack_forget()
- self._callFrame.pack(fill=tk.BOTH)
- else:
- self._callFrame.pack_forget()
- self._initFrame.pack(fill=tk.BOTH)
- if state == AudioState.FAILED:
- self._lblInitState['text'] = 'Failed'
- else:
- self._lblInitState['text'] = 'Normal cleared'
- self._btnCancel.pack_forget()
-
- self._btnHold['text'] = 'Hold'
- self._btnHold.config(state=tk.NORMAL)
- self._rxMute = False
- self._txMute = False
- self.btnRxMute['text'] = 'Mute'
- self.btnTxMute['text'] = 'Mute'
- self.rxVol.set(5.0)
-
- # save last state
- self._state = state
-
- def setStatsText(self, stats_str):
- self.stat.config(state=tk.NORMAL)
- self.stat.delete("0.0", tk.END)
- self.stat.insert(tk.END, stats_str)
- self.stat.config(state=tk.DISABLED)
-
- def _onHold(self):
- self._btnHold.config(state=tk.DISABLED)
- # notify app
- if self._btnHold['text'] == 'Hold':
- self._observer.onHold(self.peerUri)
- self._btnHold['text'] = 'Unhold'
- else:
- self._observer.onUnhold(self.peerUri)
- self._btnHold['text'] = 'Hold'
- self._btnHold.config(state=tk.NORMAL)
-
- def _onHangup(self):
- # notify app
- self._observer.onHangup(self.peerUri)
-
- def _onRxMute(self):
- # notify app
- self._rxMute = not self._rxMute
- self._observer.onRxMute(self.peerUri, self._rxMute)
- self.btnRxMute['text'] = 'Unmute' if self._rxMute else 'Mute'
-
- def _onRxVol(self, event):
- # notify app
- vol = self.rxVol.get()
- self._observer.onRxVol(self.peerUri, vol*10.0)
-
- def _onTxMute(self):
- # notify app
- self._txMute = not self._txMute
- self._observer.onTxMute(self.peerUri, self._txMute)
- self.btnTxMute['text'] = 'Unmute' if self._txMute else 'Mute'
-
- def _createInitWidgets(self):
- self._initFrame = ttk.Frame(self)
- #self._initFrame.pack(fill=tk.BOTH)
-
-
- self._lblInitState = tk.Label(self._initFrame, font=("Arial", "12"), text='')
- self._lblInitState.pack(side=tk.TOP, fill=tk.X, expand=1)
-
- # Operation: cancel/kick
- self._btnCancel = ttk.Button(self._initFrame, text = 'Cancel', command=self._onHangup)
- self._btnCancel.pack(side=tk.TOP)
-
- def _createWidgets(self):
- self._callFrame = ttk.Frame(self)
- #self._callFrame.pack(fill=tk.BOTH)
-
- # toolbar
- toolbar = ttk.Frame(self._callFrame)
- toolbar.pack(side=tk.TOP, fill=tk.X)
- self._btnHold = ttk.Button(toolbar, text='Hold', command=self._onHold)
- self._btnHold.pack(side=tk.LEFT, fill=tk.Y)
- #self._btnXfer = ttk.Button(toolbar, text='Transfer..')
- #self._btnXfer.pack(side=tk.LEFT, fill=tk.Y)
- self._btnHangUp = ttk.Button(toolbar, text='Hangup', command=self._onHangup)
- self._btnHangUp.pack(side=tk.LEFT, fill=tk.Y)
-
- # volume tool
- vol_frm = ttk.Frame(self._callFrame)
- vol_frm.pack(side=tk.TOP, fill=tk.X)
-
- self.rxVolFrm = ttk.Labelframe(vol_frm, text='RX volume')
- self.rxVolFrm.pack(side=tk.LEFT, fill=tk.Y)
-
- self.btnRxMute = ttk.Button(self.rxVolFrm, width=8, text='Mute', command=self._onRxMute)
- self.btnRxMute.pack(side=tk.LEFT)
- self.rxVol = tk.Scale(self.rxVolFrm, orient=tk.HORIZONTAL, from_=0.0, to=10.0, showvalue=1) #, tickinterval=10.0, showvalue=1)
- self.rxVol.set(5.0)
- self.rxVol.bind("<ButtonRelease-1>", self._onRxVol)
- self.rxVol.pack(side=tk.LEFT)
-
- self.txVolFrm = ttk.Labelframe(vol_frm, text='TX volume')
- self.txVolFrm.pack(side=tk.RIGHT, fill=tk.Y)
-
- self.btnTxMute = ttk.Button(self.txVolFrm, width=8, text='Mute', command=self._onTxMute)
- self.btnTxMute.pack(side=tk.LEFT)
-
- # stat
- self.stat = tk.Text(self._callFrame, width=10, height=2, bg='lightgray', relief=tk.FLAT, font=("Courier", "9"))
- self.stat.insert(tk.END, 'stat here')
- self.stat.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1)
+ def __init__(self, master, peer_uri, observer):
+ ttk.Labelframe.__init__(self, master, text=peer_uri)
+ self.peerUri = peer_uri
+ self._observer = observer
+ self._initFrame = None
+ self._callFrame = None
+ self._rxMute = False
+ self._txMute = False
+ self._state = AudioState.NULL
+
+ self._createInitWidgets()
+ self._createWidgets()
+
+ def updateState(self, state):
+ if self._state == state:
+ return
+
+ if state == AudioState.INITIALIZING:
+ self._callFrame.pack_forget()
+ self._initFrame.pack(fill=tk.BOTH)
+ self._btnCancel.pack(side=tk.TOP)
+ self._lblInitState['text'] = 'Intializing..'
+
+ elif state == AudioState.CONNECTED:
+ self._initFrame.pack_forget()
+ self._callFrame.pack(fill=tk.BOTH)
+ else:
+ self._callFrame.pack_forget()
+ self._initFrame.pack(fill=tk.BOTH)
+ if state == AudioState.FAILED:
+ self._lblInitState['text'] = 'Failed'
+ else:
+ self._lblInitState['text'] = 'Normal cleared'
+ self._btnCancel.pack_forget()
+
+ self._btnHold['text'] = 'Hold'
+ self._btnHold.config(state=tk.NORMAL)
+ self._rxMute = False
+ self._txMute = False
+ self.btnRxMute['text'] = 'Mute'
+ self.btnTxMute['text'] = 'Mute'
+ self.rxVol.set(5.0)
+
+ # save last state
+ self._state = state
+
+ def setStatsText(self, stats_str):
+ self.stat.config(state=tk.NORMAL)
+ self.stat.delete("0.0", tk.END)
+ self.stat.insert(tk.END, stats_str)
+ self.stat.config(state=tk.DISABLED)
+
+ def _onHold(self):
+ self._btnHold.config(state=tk.DISABLED)
+ # notify app
+ if self._btnHold['text'] == 'Hold':
+ self._observer.onHold(self.peerUri)
+ self._btnHold['text'] = 'Unhold'
+ else:
+ self._observer.onUnhold(self.peerUri)
+ self._btnHold['text'] = 'Hold'
+ self._btnHold.config(state=tk.NORMAL)
+
+ def _onHangup(self):
+ # notify app
+ self._observer.onHangup(self.peerUri)
+
+ def _onRxMute(self):
+ # notify app
+ self._rxMute = not self._rxMute
+ self._observer.onRxMute(self.peerUri, self._rxMute)
+ self.btnRxMute['text'] = 'Unmute' if self._rxMute else 'Mute'
+
+ def _onRxVol(self, event):
+ # notify app
+ vol = self.rxVol.get()
+ self._observer.onRxVol(self.peerUri, vol*10.0)
+
+ def _onTxMute(self):
+ # notify app
+ self._txMute = not self._txMute
+ self._observer.onTxMute(self.peerUri, self._txMute)
+ self.btnTxMute['text'] = 'Unmute' if self._txMute else 'Mute'
+
+ def _createInitWidgets(self):
+ self._initFrame = ttk.Frame(self)
+ #self._initFrame.pack(fill=tk.BOTH)
+
+
+ self._lblInitState = tk.Label(self._initFrame, font=("Arial", "12"), text='')
+ self._lblInitState.pack(side=tk.TOP, fill=tk.X, expand=1)
+
+ # Operation: cancel/kick
+ self._btnCancel = ttk.Button(self._initFrame, text = 'Cancel', command=self._onHangup)
+ self._btnCancel.pack(side=tk.TOP)
+
+ def _createWidgets(self):
+ self._callFrame = ttk.Frame(self)
+ #self._callFrame.pack(fill=tk.BOTH)
+
+ # toolbar
+ toolbar = ttk.Frame(self._callFrame)
+ toolbar.pack(side=tk.TOP, fill=tk.X)
+ self._btnHold = ttk.Button(toolbar, text='Hold', command=self._onHold)
+ self._btnHold.pack(side=tk.LEFT, fill=tk.Y)
+ #self._btnXfer = ttk.Button(toolbar, text='Transfer..')
+ #self._btnXfer.pack(side=tk.LEFT, fill=tk.Y)
+ self._btnHangUp = ttk.Button(toolbar, text='Hangup', command=self._onHangup)
+ self._btnHangUp.pack(side=tk.LEFT, fill=tk.Y)
+
+ # volume tool
+ vol_frm = ttk.Frame(self._callFrame)
+ vol_frm.pack(side=tk.TOP, fill=tk.X)
+
+ self.rxVolFrm = ttk.Labelframe(vol_frm, text='RX volume')
+ self.rxVolFrm.pack(side=tk.LEFT, fill=tk.Y)
+
+ self.btnRxMute = ttk.Button(self.rxVolFrm, width=8, text='Mute', command=self._onRxMute)
+ self.btnRxMute.pack(side=tk.LEFT)
+ self.rxVol = tk.Scale(self.rxVolFrm, orient=tk.HORIZONTAL, from_=0.0, to=10.0, showvalue=1) #, tickinterval=10.0, showvalue=1)
+ self.rxVol.set(5.0)
+ self.rxVol.bind("<ButtonRelease-1>", self._onRxVol)
+ self.rxVol.pack(side=tk.LEFT)
+
+ self.txVolFrm = ttk.Labelframe(vol_frm, text='TX volume')
+ self.txVolFrm.pack(side=tk.RIGHT, fill=tk.Y)
+
+ self.btnTxMute = ttk.Button(self.txVolFrm, width=8, text='Mute', command=self._onTxMute)
+ self.btnTxMute.pack(side=tk.LEFT)
+
+ # stat
+ self.stat = tk.Text(self._callFrame, width=10, height=2, bg='lightgray', relief=tk.FLAT, font=("Courier", "9"))
+ self.stat.insert(tk.END, 'stat here')
+ self.stat.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1)
class ChatObserver(TextObserver, AudioObserver):
- def onAddParticipant(self):
- pass
- def onStartAudio(self):
- pass
- def onStopAudio(self):
- pass
- def onCloseWindow(self):
- pass
-
+ def onAddParticipant(self):
+ pass
+ def onStartAudio(self):
+ pass
+ def onStopAudio(self):
+ pass
+ def onCloseWindow(self):
+ pass
+
class ChatFrame(tk.Toplevel):
- """
- Room
- """
- def __init__(self, observer):
- tk.Toplevel.__init__(self)
- self.protocol("WM_DELETE_WINDOW", self._onClose)
- self._observer = observer
-
- self._text = None
- self._text_shown = True
-
- self._audioEnabled = False
- self._audioFrames = []
- self._createWidgets()
-
- def _createWidgets(self):
- # toolbar
- self.toolbar = ttk.Frame(self)
- self.toolbar.pack(side=tk.TOP, fill=tk.BOTH)
-
- btnText = ttk.Button(self.toolbar, text='Show/hide text', command=self._onShowHideText)
- btnText.pack(side=tk.LEFT, fill=tk.Y)
- btnAudio = ttk.Button(self.toolbar, text='Start/stop audio', command=self._onStartStopAudio)
- btnAudio.pack(side=tk.LEFT, fill=tk.Y)
-
- ttk.Separator(self.toolbar, orient=tk.VERTICAL).pack(side=tk.LEFT, fill=tk.Y, padx = 4)
-
- btnAdd = ttk.Button(self.toolbar, text='Add participant..', command=self._onAddParticipant)
- btnAdd.pack(side=tk.LEFT, fill=tk.Y)
-
- # media frame
- self.media = ttk.Frame(self)
- self.media.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1)
-
- # create Text Chat frame
- self.media_left = ttk.Frame(self.media)
- self._text = TextFrame(self.media_left, self._observer)
- self._text.pack(fill=tk.BOTH, expand=1)
- self.media_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
-
- # create other media frame
- self.media_right = ttk.Frame(self.media)
-
- def _arrangeMediaFrames(self):
- if len(self._audioFrames) == 0:
- self.media_right.pack_forget()
- return
-
- self.media_right.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
- MAX_ROWS = 3
- row_num = 0
- col_num = 1
- for frm in self._audioFrames:
- frm.grid(row=row_num, column=col_num, sticky='nsew', padx=5, pady=5)
- row_num += 1
- if row_num >= MAX_ROWS:
- row_num = 0
- col_num += 1
-
- def _onShowHideText(self):
- self.textShowHide(not self._text_shown)
-
- def _onAddParticipant(self):
- self._observer.onAddParticipant()
-
- def _onStartStopAudio(self):
- self._audioEnabled = not self._audioEnabled
- if self._audioEnabled:
- self._observer.onStartAudio()
- else:
- self._observer.onStopAudio()
- self.enableAudio(self._audioEnabled)
-
- def _onClose(self):
- self._observer.onCloseWindow()
-
- # APIs
-
- def bringToFront(self):
- self.deiconify()
- self.lift()
- self._text._typingBox.focus_set()
-
- def textAddMessage(self, msg, is_chat = True):
- self._text.addMessage(msg, is_chat)
-
- def textSetTypingIndication(self, who, is_typing = True):
- self._text.setTypingIndication(who, is_typing)
-
- def addParticipant(self, participant_uri):
- aud_frm = AudioFrame(self.media_right, participant_uri, self._observer)
- self._audioFrames.append(aud_frm)
-
- def delParticipant(self, participant_uri):
- for aud_frm in self._audioFrames:
- if participant_uri == aud_frm.peerUri:
- self._audioFrames.remove(aud_frm)
- # need to delete aud_frm manually?
- aud_frm.destroy()
- return
-
- def textShowHide(self, show = True):
- if show:
- self.media_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
- self._text._typingBox.focus_set()
- else:
- self.media_left.pack_forget()
- self._text_shown = show
-
- def enableAudio(self, is_enabled = True):
- if is_enabled:
- self._arrangeMediaFrames()
- else:
- self.media_right.pack_forget()
- self._audioEnabled = is_enabled
-
- def audioUpdateState(self, participant_uri, state):
- for aud_frm in self._audioFrames:
- if participant_uri == aud_frm.peerUri:
- aud_frm.updateState(state)
- break
- if state >= AudioState.DISCONNECTED and len(self._audioFrames) == 1:
- self.enableAudio(False)
- else:
- self.enableAudio(True)
-
- def audioSetStatsText(self, participant_uri, stats_str):
- for aud_frm in self._audioFrames:
- if participant_uri == aud_frm.peerUri:
- aud_frm.setStatsText(stats_str)
- break
-
+ """
+ Room
+ """
+ def __init__(self, observer):
+ tk.Toplevel.__init__(self)
+ self.protocol("WM_DELETE_WINDOW", self._onClose)
+ self._observer = observer
+
+ self._text = None
+ self._text_shown = True
+
+ self._audioEnabled = False
+ self._audioFrames = []
+ self._createWidgets()
+
+ def _createWidgets(self):
+ # toolbar
+ self.toolbar = ttk.Frame(self)
+ self.toolbar.pack(side=tk.TOP, fill=tk.BOTH)
+
+ btnText = ttk.Button(self.toolbar, text='Show/hide text', command=self._onShowHideText)
+ btnText.pack(side=tk.LEFT, fill=tk.Y)
+ btnAudio = ttk.Button(self.toolbar, text='Start/stop audio', command=self._onStartStopAudio)
+ btnAudio.pack(side=tk.LEFT, fill=tk.Y)
+
+ ttk.Separator(self.toolbar, orient=tk.VERTICAL).pack(side=tk.LEFT, fill=tk.Y, padx = 4)
+
+ btnAdd = ttk.Button(self.toolbar, text='Add participant..', command=self._onAddParticipant)
+ btnAdd.pack(side=tk.LEFT, fill=tk.Y)
+
+ # media frame
+ self.media = ttk.Frame(self)
+ self.media.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1)
+
+ # create Text Chat frame
+ self.media_left = ttk.Frame(self.media)
+ self._text = TextFrame(self.media_left, self._observer)
+ self._text.pack(fill=tk.BOTH, expand=1)
+ self.media_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
+
+ # create other media frame
+ self.media_right = ttk.Frame(self.media)
+
+ def _arrangeMediaFrames(self):
+ if len(self._audioFrames) == 0:
+ self.media_right.pack_forget()
+ return
+
+ self.media_right.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
+ MAX_ROWS = 3
+ row_num = 0
+ col_num = 1
+ for frm in self._audioFrames:
+ frm.grid(row=row_num, column=col_num, sticky='nsew', padx=5, pady=5)
+ row_num += 1
+ if row_num >= MAX_ROWS:
+ row_num = 0
+ col_num += 1
+
+ def _onShowHideText(self):
+ self.textShowHide(not self._text_shown)
+
+ def _onAddParticipant(self):
+ self._observer.onAddParticipant()
+
+ def _onStartStopAudio(self):
+ self._audioEnabled = not self._audioEnabled
+ if self._audioEnabled:
+ self._observer.onStartAudio()
+ else:
+ self._observer.onStopAudio()
+ self.enableAudio(self._audioEnabled)
+
+ def _onClose(self):
+ self._observer.onCloseWindow()
+
+ # APIs
+
+ def bringToFront(self):
+ self.deiconify()
+ self.lift()
+ self._text._typingBox.focus_set()
+
+ def textAddMessage(self, msg, is_chat = True):
+ self._text.addMessage(msg, is_chat)
+
+ def textSetTypingIndication(self, who, is_typing = True):
+ self._text.setTypingIndication(who, is_typing)
+
+ def addParticipant(self, participant_uri):
+ aud_frm = AudioFrame(self.media_right, participant_uri, self._observer)
+ self._audioFrames.append(aud_frm)
+
+ def delParticipant(self, participant_uri):
+ for aud_frm in self._audioFrames:
+ if participant_uri == aud_frm.peerUri:
+ self._audioFrames.remove(aud_frm)
+ # need to delete aud_frm manually?
+ aud_frm.destroy()
+ return
+
+ def textShowHide(self, show = True):
+ if show:
+ self.media_left.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
+ self._text._typingBox.focus_set()
+ else:
+ self.media_left.pack_forget()
+ self._text_shown = show
+
+ def enableAudio(self, is_enabled = True):
+ if is_enabled:
+ self._arrangeMediaFrames()
+ else:
+ self.media_right.pack_forget()
+ self._audioEnabled = is_enabled
+
+ def audioUpdateState(self, participant_uri, state):
+ for aud_frm in self._audioFrames:
+ if participant_uri == aud_frm.peerUri:
+ aud_frm.updateState(state)
+ break
+ if state >= AudioState.DISCONNECTED and len(self._audioFrames) == 1:
+ self.enableAudio(False)
+ else:
+ self.enableAudio(True)
+
+ def audioSetStatsText(self, participant_uri, stats_str):
+ for aud_frm in self._audioFrames:
+ if participant_uri == aud_frm.peerUri:
+ aud_frm.setStatsText(stats_str)
+ break
+
if __name__ == '__main__':
- root = tk.Tk()
- root.title("Chat")
- root.columnconfigure(0, weight=1)
- root.rowconfigure(0, weight=1)
-
- obs = ChatObserver()
- dlg = ChatFrame(obs)
- #dlg = TextFrame(root)
- #dlg = AudioFrame(root)
-
- #dlg.pack(fill=tk.BOTH, expand=1)
- root.mainloop()
+ root = tk.Tk()
+ root.title("Chat")
+ root.columnconfigure(0, weight=1)
+ root.rowconfigure(0, weight=1)
+
+ obs = ChatObserver()
+ dlg = ChatFrame(obs)
+ #dlg = TextFrame(root)
+ #dlg = AudioFrame(root)
+
+ #dlg.pack(fill=tk.BOTH, expand=1)
+ root.mainloop()
diff --git a/pjsip-apps/src/pygui/endpoint.py b/pjsip-apps/src/pygui/endpoint.py
index 25367f2..08895e2 100644
--- a/pjsip-apps/src/pygui/endpoint.py
+++ b/pjsip-apps/src/pygui/endpoint.py
@@ -1,4 +1,4 @@
-# $Id: endpoint.py 4704 2014-01-16 05:30:46Z ming $
+# $Id: endpoint.py 5638 2017-08-02 09:45:09Z riza $
#
# pjsua Python GUI Demo
#
@@ -20,34 +20,34 @@
#
import sys
if sys.version_info[0] >= 3: # Python 3
- import tkinter as tk
- from tkinter import ttk
- from tkinter import messagebox as msgbox
+ import tkinter as tk
+ from tkinter import ttk
+ from tkinter import messagebox as msgbox
else:
- import Tkinter as tk
- import tkMessageBox as msgbox
- import ttk
+ import Tkinter as tk
+ import tkMessageBox as msgbox
+ import ttk
import pjsua2 as pj
import application
class Endpoint(pj.Endpoint):
- """
- This is high level Python object inherited from pj.Endpoint
- """
- instance = None
- def __init__(self):
- pj.Endpoint.__init__(self)
- Endpoint.instance = self
-
-
+ """
+ This is high level Python object inherited from pj.Endpoint
+ """
+ instance = None
+ def __init__(self):
+ pj.Endpoint.__init__(self)
+ Endpoint.instance = self
+
+
def validateUri(uri):
- return Endpoint.instance.utilVerifyUri(uri) == pj.PJ_SUCCESS
+ return Endpoint.instance.utilVerifyUri(uri) == pj.PJ_SUCCESS
def validateSipUri(uri):
- return Endpoint.instance.utilVerifySipUri(uri) == pj.PJ_SUCCESS
+ return Endpoint.instance.utilVerifySipUri(uri) == pj.PJ_SUCCESS
if __name__ == '__main__':
- application.main()
+ application.main()
diff --git a/pjsip-apps/src/pygui/log.py b/pjsip-apps/src/pygui/log.py
index 0011a3e..ce9cfa7 100644
--- a/pjsip-apps/src/pygui/log.py
+++ b/pjsip-apps/src/pygui/log.py
@@ -1,4 +1,4 @@
-# $Id: log.py 4704 2014-01-16 05:30:46Z ming $
+# $Id: log.py 5638 2017-08-02 09:45:09Z riza $
#
# pjsua Python GUI Demo
#
@@ -20,108 +20,109 @@
#
import sys
if sys.version_info[0] >= 3: # Python 3
- import tkinter as tk
- from tkinter import ttk
- from tkinter import messagebox as msgbox
+ import tkinter as tk
+ from tkinter import ttk
+ from tkinter import messagebox as msgbox
else:
- import Tkinter as tk
- import tkMessageBox as msgbox
- import ttk
+ import Tkinter as tk
+ import tkMessageBox as msgbox
+ import ttk
import pjsua2 as pj
import application
+write=sys.stdout.write
class LogWindow(tk.Toplevel):
- """
- Log window
- """
- instance = None
- def __init__(self, app):
- tk.Toplevel.__init__(self, name='logwnd', width=640, height=480)
- LogWindow.instance = self
- self.app = app
- self.state('withdrawn')
- self.title('Log')
- self._createWidgets()
- self.protocol("WM_DELETE_WINDOW", self._onHide)
-
- def addLog(self, entry):
- """entry fields:
- int level;
- string msg;
- long threadId;
- string threadName;
- """
- self.addLog2(entry.level, entry.msg)
-
- def addLog2(self, level, msg):
- if level==5:
- tags = ('trace',)
- elif level==3:
- tags = ('info',)
- elif level==2:
- tags = ('warning',)
- elif level<=1:
- tags = ('error',)
- else:
- tags = None
- self.text.insert(tk.END, msg, tags)
- self.text.see(tk.END)
-
- def _createWidgets(self):
- self.rowconfigure(0, weight=1)
- self.rowconfigure(1, weight=0)
- self.columnconfigure(0, weight=1)
- self.columnconfigure(1, weight=0)
-
- self.text = tk.Text(self, font=('Courier New', '8'), wrap=tk.NONE, undo=False, padx=4, pady=5)
- self.text.grid(row=0, column=0, sticky='nswe', padx=5, pady=5)
-
- scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self.text.yview)
- self.text.config(yscrollcommand=scrl.set)
- scrl.grid(row=0, column=1, sticky='nsw', padx=5, pady=5)
-
- scrl = ttk.Scrollbar(self, orient=tk.HORIZONTAL, command=self.text.xview)
- self.text.config(xscrollcommand=scrl.set)
- scrl.grid(row=1, column=0, sticky='we', padx=5, pady=5)
-
- self.text.bind("<Key>", self._onKey)
-
- self.text.tag_configure('normal', font=('Courier New', '8'), foreground='black')
- self.text.tag_configure('trace', font=('Courier New', '8'), foreground='#777777')
- self.text.tag_configure('info', font=('Courier New', '8', 'bold'), foreground='black')
- self.text.tag_configure('warning', font=('Courier New', '8', 'bold'), foreground='cyan')
- self.text.tag_configure('error', font=('Courier New', '8', 'bold'), foreground='red')
-
- def _onKey(self, event):
- # Ignore key event to make text widget read-only
- return "break"
-
- def _onHide(self):
- # Hide when close ('x') button is clicked
- self.withdraw()
- self.app.showLogWindow.set(0)
-
-
+ """
+ Log window
+ """
+ instance = None
+ def __init__(self, app):
+ tk.Toplevel.__init__(self, name='logwnd', width=640, height=480)
+ LogWindow.instance = self
+ self.app = app
+ self.state('withdrawn')
+ self.title('Log')
+ self._createWidgets()
+ self.protocol("WM_DELETE_WINDOW", self._onHide)
+
+ def addLog(self, entry):
+ """entry fields:
+ int level;
+ string msg;
+ long threadId;
+ string threadName;
+ """
+ self.addLog2(entry.level, entry.msg)
+
+ def addLog2(self, level, msg):
+ if level==5:
+ tags = ('trace',)
+ elif level==3:
+ tags = ('info',)
+ elif level==2:
+ tags = ('warning',)
+ elif level<=1:
+ tags = ('error',)
+ else:
+ tags = None
+ self.text.insert(tk.END, msg, tags)
+ self.text.see(tk.END)
+
+ def _createWidgets(self):
+ self.rowconfigure(0, weight=1)
+ self.rowconfigure(1, weight=0)
+ self.columnconfigure(0, weight=1)
+ self.columnconfigure(1, weight=0)
+
+ self.text = tk.Text(self, font=('Courier New', '8'), wrap=tk.NONE, undo=False, padx=4, pady=5)
+ self.text.grid(row=0, column=0, sticky='nswe', padx=5, pady=5)
+
+ scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self.text.yview)
+ self.text.config(yscrollcommand=scrl.set)
+ scrl.grid(row=0, column=1, sticky='nsw', padx=5, pady=5)
+
+ scrl = ttk.Scrollbar(self, orient=tk.HORIZONTAL, command=self.text.xview)
+ self.text.config(xscrollcommand=scrl.set)
+ scrl.grid(row=1, column=0, sticky='we', padx=5, pady=5)
+
+ self.text.bind("<Key>", self._onKey)
+
+ self.text.tag_configure('normal', font=('Courier New', '8'), foreground='black')
+ self.text.tag_configure('trace', font=('Courier New', '8'), foreground='#777777')
+ self.text.tag_configure('info', font=('Courier New', '8', 'bold'), foreground='black')
+ self.text.tag_configure('warning', font=('Courier New', '8', 'bold'), foreground='cyan')
+ self.text.tag_configure('error', font=('Courier New', '8', 'bold'), foreground='red')
+
+ def _onKey(self, event):
+ # Ignore key event to make text widget read-only
+ return "break"
+
+ def _onHide(self):
+ # Hide when close ('x') button is clicked
+ self.withdraw()
+ self.app.showLogWindow.set(0)
+
+
def writeLog2(level, msg):
- if LogWindow.instance:
- LogWindow.instance.addLog2(level, msg)
+ if LogWindow.instance:
+ LogWindow.instance.addLog2(level, msg)
def writeLog(entry):
- if LogWindow.instance:
- LogWindow.instance.addLog(entry)
+ if LogWindow.instance:
+ LogWindow.instance.addLog(entry)
class Logger(pj.LogWriter):
- """
- Logger to receive log messages from pjsua2
- """
- def __init__(self):
- pj.LogWriter.__init__(self)
-
- def write(self, entry):
- print entry.msg,
- writeLog(entry)
+ """
+ Logger to receive log messages from pjsua2
+ """
+ def __init__(self):
+ pj.LogWriter.__init__(self)
+
+ def write(self, entry):
+ write(entry.msg + "\r\n")
+ writeLog(entry)
if __name__ == '__main__':
- application.main()
+ application.main()
diff --git a/pjsip-apps/src/samples/encdec.c b/pjsip-apps/src/samples/encdec.c
index c87bd3d..02e7575 100644
--- a/pjsip-apps/src/samples/encdec.c
+++ b/pjsip-apps/src/samples/encdec.c
@@ -1,4 +1,4 @@
-/* $Id: encdec.c 5253 2016-03-04 08:41:42Z bennylp $ */
+/* $Id: encdec.c 5635 2017-08-01 07:49:34Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -176,7 +176,7 @@ static pj_status_t enc_dec_test(const char *codec_id,
continue;
}
- bitstream_size += frm_bit.size;
+ bitstream_size += (unsigned)frm_bit.size;
/* Parse the bitstream (not really necessary for this case
* since we always decode 1 frame, but it's still good
diff --git a/pjsip-apps/src/samples/pjsua2_demo.cpp b/pjsip-apps/src/samples/pjsua2_demo.cpp
index 0198009..06abc8a 100644
--- a/pjsip-apps/src/samples/pjsua2_demo.cpp
+++ b/pjsip-apps/src/samples/pjsua2_demo.cpp
@@ -1,4 +1,4 @@
-/* $Id: pjsua2_demo.cpp 5467 2016-10-21 07:55:41Z nanang $ */
+/* $Id: pjsua2_demo.cpp 5650 2017-09-18 07:10:11Z nanang $ */
/*
* Copyright (C) 2008-2013 Teluu Inc. (http://www.teluu.com)
*
@@ -18,7 +18,6 @@
*/
#include <pjsua2.hpp>
#include <iostream>
-#include <memory>
#include <pj/file_access.h>
#define THIS_FILE "pjsua2_demo.cpp"
@@ -128,7 +127,7 @@ static void mainProg1(Endpoint &ep) throw(Error)
acc_cfg.regConfig.registrarUri = "sip:sip.pjsip.org";
acc_cfg.sipConfig.authCreds.push_back( AuthCredInfo("digest", "*",
"test1", 0, "test1") );
- std::auto_ptr<MyAccount> acc(new MyAccount);
+ MyAccount *acc(new MyAccount);
acc->create(acc_cfg);
pj_thread_sleep(2000);
@@ -148,6 +147,8 @@ static void mainProg1(Endpoint &ep) throw(Error)
// Destroy library
std::cout << "*** PJSUA2 SHUTTING DOWN ***" << std::endl;
+ delete call;
+ delete acc;
}
static void mainProg2() throw(Error)
@@ -307,7 +308,7 @@ static void mainProg4(Endpoint &ep) throw(Error)
// Add account
AccountConfig acc_cfg;
acc_cfg.idUri = "sip:localhost";
- std::auto_ptr<MyAccount> acc(new MyAccount);
+ MyAccount *acc(new MyAccount);
acc->create(acc_cfg);
// Start library
@@ -317,6 +318,8 @@ static void mainProg4(Endpoint &ep) throw(Error)
// Just wait for ENTER key
std::cout << "Press ENTER to quit..." << std::endl;
std::cin.get();
+
+ delete acc;
}
diff --git a/pjsip-apps/src/samples/streamutil.c b/pjsip-apps/src/samples/streamutil.c
index f5196da..110989a 100644
--- a/pjsip-apps/src/samples/streamutil.c
+++ b/pjsip-apps/src/samples/streamutil.c
@@ -1,4 +1,4 @@
-/* $Id: streamutil.c 5311 2016-05-20 04:17:00Z ming $ */
+/* $Id: streamutil.c 5621 2017-07-05 05:37:24Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -41,6 +41,11 @@
#include "util.h"
+/* An experimental feature to add multicast option to this app for providing
+ * the capability to send IP datagrams from a single source to more than
+ * one receivers.
+ */
+#define HAVE_MULTICAST 1
static const char *desc =
" streamutil \n"
@@ -60,6 +65,15 @@ static const char *desc =
" --remote=IP:PORT Set the remote peer. If this option is set, \n"
" the program will transmit RTP audio to the \n"
" specified address. (default: recv only) \n"
+#if HAVE_MULTICAST
+ " --mcast-add=IP Joins the multicast group as specified by \n"
+ " the address. Sample usage: \n"
+ " Sender: \n"
+ " streamutil --remote=[multicast_addr]:[port] \n"
+ " Receivers: \n"
+ " streamutil --local-port=[port] \n"
+ " --mcast-add=[multicast_addr] \n"
+#endif
" --play-file=WAV Send audio from the WAV file instead of from \n"
" the sound device. \n"
" --record-file=WAV Record incoming audio to WAV file instead of \n"
@@ -73,9 +87,11 @@ static const char *desc =
" e.g: AES_CM_128_HMAC_SHA1_80 (default), \n"
" AES_CM_128_HMAC_SHA1_32 \n"
" Use this option along with the TX & RX keys, \n"
- " formated of 60 hex digits (e.g: E148DA..) \n"
+ " formated of 60 hex digits (e.g: E148DA..) \n"
" --srtp-tx-key SRTP key for transmiting \n"
" --srtp-rx-key SRTP key for receiving \n"
+ " --srtp-dtls-client Use DTLS for SRTP keying, as DTLS client \n"
+ " --srtp-dtls-server Use DTLS for SRTP keying, as DTLS server \n"
#endif
"\n"
@@ -92,8 +108,20 @@ static const char *desc =
static void print_stream_stat(pjmedia_stream *stream,
const pjmedia_codec_param *codec_param);
-/* Prototype for LIBSRTP utility in file datatypes.c */
-int hex_string_to_octet_string(char *raw, char *hex, int len);
+/* Hexa string to octet array */
+int my_hex_string_to_octet_string(char *raw, char *hex, int len)
+{
+ int i;
+ for (i = 0; i < len; i+=2) {
+ int tmp;
+ if (i+1 >= len || !pj_isxdigit(hex[i]) || !pj_isxdigit(hex[i+1]))
+ return i;
+ tmp = pj_hex_digit_to_val((unsigned char)hex[i]) << 4;
+ tmp |= pj_hex_digit_to_val((unsigned char)hex[i+1]);
+ raw[i/2] = (char)(tmp & 0xFF);
+ }
+ return len;
+}
/*
* Register all codecs.
@@ -113,11 +141,15 @@ static pj_status_t create_stream( pj_pool_t *pool,
pjmedia_dir dir,
pj_uint16_t local_port,
const pj_sockaddr_in *rem_addr,
+ pj_bool_t mcast,
+ const pj_sockaddr_in *mcast_addr,
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
pj_bool_t use_srtp,
const pj_str_t *crypto_suite,
const pj_str_t *srtp_tx_key,
const pj_str_t *srtp_rx_key,
+ pj_bool_t is_dtls_client,
+ pj_bool_t is_dtls_server,
#endif
pjmedia_stream **p_stream )
{
@@ -157,33 +189,143 @@ static pj_status_t create_stream( pj_pool_t *pool,
pj_sockaddr_in_init(&info.rem_addr.ipv4, &addr, 0);
}
- /* Create media transport */
- status = pjmedia_transport_udp_create(med_endpt, NULL, local_port,
- 0, &transport);
- if (status != PJ_SUCCESS)
- return status;
+ pj_sockaddr_cp(&info.rem_rtcp, &info.rem_addr);
+ pj_sockaddr_set_port(&info.rem_rtcp,
+ pj_sockaddr_get_port(&info.rem_rtcp)+1);
+
+ if (mcast) {
+ pjmedia_sock_info si;
+ int reuse = 1;
+
+ pj_bzero(&si, sizeof(pjmedia_sock_info));
+ si.rtp_sock = si.rtcp_sock = PJ_INVALID_SOCKET;
+
+ /* Create RTP socket */
+ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0,
+ &si.rtp_sock);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ status = pj_sock_setsockopt(si.rtp_sock, pj_SOL_SOCKET(),
+ pj_SO_REUSEADDR(), &reuse, sizeof(reuse));
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Bind RTP socket */
+ status = pj_sockaddr_init(pj_AF_INET(), &si.rtp_addr_name,
+ NULL, local_port);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ status = pj_sock_bind(si.rtp_sock, &si.rtp_addr_name,
+ pj_sockaddr_get_len(&si.rtp_addr_name));
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Create RTCP socket */
+ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0,
+ &si.rtcp_sock);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ status = pj_sock_setsockopt(si.rtcp_sock, pj_SOL_SOCKET(),
+ pj_SO_REUSEADDR(), &reuse, sizeof(reuse));
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Bind RTCP socket */
+ status = pj_sockaddr_init(pj_AF_INET(), &si.rtcp_addr_name,
+ NULL, local_port+1);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ status = pj_sock_bind(si.rtcp_sock, &si.rtcp_addr_name,
+ pj_sockaddr_get_len(&si.rtcp_addr_name));
+ if (status != PJ_SUCCESS)
+ return status;
+
+#ifdef HAVE_MULTICAST
+ {
+ unsigned char loop;
+ struct pj_ip_mreq imr;
+
+ pj_memset(&imr, 0, sizeof(struct pj_ip_mreq));
+ imr.imr_multiaddr.s_addr = mcast_addr->sin_addr.s_addr;
+ imr.imr_interface.s_addr = pj_htonl(PJ_INADDR_ANY);
+ status = pj_sock_setsockopt(si.rtp_sock, pj_SOL_IP(),
+ pj_IP_ADD_MEMBERSHIP(),
+ &imr, sizeof(struct pj_ip_mreq));
+ if (status != PJ_SUCCESS)
+ return status;
+
+ status = pj_sock_setsockopt(si.rtcp_sock, pj_SOL_IP(),
+ pj_IP_ADD_MEMBERSHIP(),
+ &imr, sizeof(struct pj_ip_mreq));
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Disable local reception of local sent packets */
+ loop = 0;
+ pj_sock_setsockopt(si.rtp_sock, pj_SOL_IP(),
+ pj_IP_MULTICAST_LOOP(), &loop, sizeof(loop));
+ pj_sock_setsockopt(si.rtcp_sock, pj_SOL_IP(),
+ pj_IP_MULTICAST_LOOP(), &loop, sizeof(loop));
+ }
+#endif
+
+ /* Create media transport from existing sockets */
+ status = pjmedia_transport_udp_attach( med_endpt, NULL, &si,
+ PJMEDIA_UDP_NO_SRC_ADDR_CHECKING, &transport);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ } else {
+ /* Create media transport */
+ status = pjmedia_transport_udp_create(med_endpt, NULL, local_port,
+ 0, &transport);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
/* Check if SRTP enabled */
if (use_srtp) {
- pjmedia_srtp_crypto tx_plc, rx_plc;
-
status = pjmedia_transport_srtp_create(med_endpt, transport,
NULL, &srtp_tp);
if (status != PJ_SUCCESS)
return status;
- pj_bzero(&tx_plc, sizeof(pjmedia_srtp_crypto));
- pj_bzero(&rx_plc, sizeof(pjmedia_srtp_crypto));
-
- tx_plc.key = *srtp_tx_key;
- tx_plc.name = *crypto_suite;
- rx_plc.key = *srtp_rx_key;
- rx_plc.name = *crypto_suite;
-
- status = pjmedia_transport_srtp_start(srtp_tp, &tx_plc, &rx_plc);
- if (status != PJ_SUCCESS)
- return status;
+ if (is_dtls_client || is_dtls_server) {
+ char fp[128];
+ pj_size_t fp_len = sizeof(fp);
+ pjmedia_srtp_dtls_nego_param dtls_param;
+
+ pjmedia_transport_srtp_dtls_get_fingerprint(srtp_tp, "SHA-256", fp, &fp_len);
+ PJ_LOG(3, (THIS_FILE, "Local cert fingerprint: %s", fp));
+
+ pj_bzero(&dtls_param, sizeof(dtls_param));
+ pj_sockaddr_cp(&dtls_param.rem_addr, rem_addr);
+ pj_sockaddr_cp(&dtls_param.rem_rtcp, rem_addr);
+ dtls_param.is_role_active = is_dtls_client;
+
+ status = pjmedia_transport_srtp_dtls_start_nego(srtp_tp, &dtls_param);
+ if (status != PJ_SUCCESS)
+ return status;
+ } else {
+ pjmedia_srtp_crypto tx_plc, rx_plc;
+
+ pj_bzero(&tx_plc, sizeof(pjmedia_srtp_crypto));
+ pj_bzero(&rx_plc, sizeof(pjmedia_srtp_crypto));
+
+ tx_plc.key = *srtp_tx_key;
+ tx_plc.name = *crypto_suite;
+ rx_plc.key = *srtp_rx_key;
+ rx_plc.name = *crypto_suite;
+
+ status = pjmedia_transport_srtp_start(srtp_tp, &tx_plc, &rx_plc);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
transport = srtp_tp;
}
@@ -241,6 +383,8 @@ int main(int argc, char *argv[])
pj_str_t srtp_tx_key = {NULL, 0};
pj_str_t srtp_rx_key = {NULL, 0};
pj_str_t srtp_crypto_suite = {NULL, 0};
+ pj_bool_t is_dtls_client = PJ_FALSE;
+ pj_bool_t is_dtls_server = PJ_FALSE;
int tmp_key_len;
#endif
@@ -249,15 +393,18 @@ int main(int argc, char *argv[])
pjmedia_codec_param codec_param;
pjmedia_dir dir = PJMEDIA_DIR_DECODING;
pj_sockaddr_in remote_addr;
+ pj_sockaddr_in mcast_addr;
pj_uint16_t local_port = 4000;
char *codec_id = NULL;
char *rec_file = NULL;
char *play_file = NULL;
+ int mcast = 0;
enum {
OPT_CODEC = 'c',
OPT_LOCAL_PORT = 'p',
OPT_REMOTE = 'r',
+ OPT_MCAST = 'm',
OPT_PLAY_FILE = 'w',
OPT_RECORD_FILE = 'R',
OPT_SEND_RECV = 'b',
@@ -268,6 +415,8 @@ int main(int argc, char *argv[])
#endif
OPT_SRTP_TX_KEY = 'x',
OPT_SRTP_RX_KEY = 'y',
+ OPT_SRTP_DTLS_CLIENT = 'd',
+ OPT_SRTP_DTLS_SERVER = 'D',
OPT_HELP = 'h',
};
@@ -275,6 +424,7 @@ int main(int argc, char *argv[])
{ "codec", 1, 0, OPT_CODEC },
{ "local-port", 1, 0, OPT_LOCAL_PORT },
{ "remote", 1, 0, OPT_REMOTE },
+ { "mcast-add", 1, 0, OPT_MCAST },
{ "play-file", 1, 0, OPT_PLAY_FILE },
{ "record-file", 1, 0, OPT_RECORD_FILE },
{ "send-recv", 0, 0, OPT_SEND_RECV },
@@ -284,6 +434,8 @@ int main(int argc, char *argv[])
{ "use-srtp", 2, 0, OPT_USE_SRTP },
{ "srtp-tx-key", 1, 0, OPT_SRTP_TX_KEY },
{ "srtp-rx-key", 1, 0, OPT_SRTP_RX_KEY },
+ { "srtp-dtls-client", 0, 0, OPT_SRTP_DTLS_CLIENT },
+ { "srtp-dtls-server", 0, 0, OPT_SRTP_DTLS_SERVER },
#endif
{ "help", 0, 0, OPT_HELP },
{ NULL, 0, 0, 0 },
@@ -331,6 +483,19 @@ int main(int argc, char *argv[])
}
break;
+ case OPT_MCAST:
+ {
+ pj_str_t ip = pj_str(pj_optarg);
+
+ mcast = 1;
+ status = pj_sockaddr_in_init(&mcast_addr, &ip, 0);
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Invalid mcast address", status);
+ return 1;
+ }
+ }
+ break;
+
case OPT_PLAY_FILE:
play_file = pj_optarg;
break;
@@ -362,16 +527,30 @@ int main(int argc, char *argv[])
break;
case OPT_SRTP_TX_KEY:
- tmp_key_len = hex_string_to_octet_string(tmp_tx_key, pj_optarg,
- (int)strlen(pj_optarg));
+ tmp_key_len = my_hex_string_to_octet_string(tmp_tx_key, pj_optarg,
+ (int)strlen(pj_optarg));
pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
break;
case OPT_SRTP_RX_KEY:
- tmp_key_len = hex_string_to_octet_string(tmp_rx_key, pj_optarg,
- (int)strlen(pj_optarg));
+ tmp_key_len = my_hex_string_to_octet_string(tmp_rx_key, pj_optarg,
+ (int)strlen(pj_optarg));
pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
break;
+ case OPT_SRTP_DTLS_CLIENT:
+ is_dtls_client = PJ_TRUE;
+ if (is_dtls_server) {
+ printf("Error: Cannot be as both DTLS server & client\n");
+ return 1;
+ }
+ break;
+ case OPT_SRTP_DTLS_SERVER:
+ is_dtls_server = PJ_TRUE;
+ if (is_dtls_client) {
+ printf("Error: Cannot be as both DTLS server & client\n");
+ return 1;
+ }
+ break;
#endif
case OPT_HELP:
@@ -387,7 +566,7 @@ int main(int argc, char *argv[])
/* Verify arguments. */
- if (dir & PJMEDIA_DIR_ENCODING) {
+ if (dir & PJMEDIA_DIR_ENCODING || is_dtls_client || is_dtls_server) {
if (remote_addr.sin_addr.s_addr == 0) {
printf("Error: remote address must be set\n");
return 1;
@@ -402,7 +581,8 @@ int main(int argc, char *argv[])
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
/* SRTP validation */
if (use_srtp) {
- if (!srtp_tx_key.slen || !srtp_rx_key.slen)
+ if (!is_dtls_client && !is_dtls_server &&
+ (!srtp_tx_key.slen || !srtp_rx_key.slen))
{
printf("Error: Key for each SRTP stream direction must be set\n");
return 1;
@@ -454,10 +634,11 @@ int main(int argc, char *argv[])
/* Create stream based on program arguments */
status = create_stream(pool, med_endpt, codec_info, dir, local_port,
- &remote_addr,
+ &remote_addr, mcast, &mcast_addr,
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
use_srtp, &srtp_crypto_suite,
&srtp_tx_key, &srtp_rx_key,
+ is_dtls_client, is_dtls_server,
#endif
&stream);
if (status != PJ_SUCCESS)
diff --git a/pjsip-apps/src/samples/vid_streamutil.c b/pjsip-apps/src/samples/vid_streamutil.c
index 2a91433..ca2b5b5 100644
--- a/pjsip-apps/src/samples/vid_streamutil.c
+++ b/pjsip-apps/src/samples/vid_streamutil.c
@@ -1,4 +1,4 @@
-/* $Id: vid_streamutil.c 5311 2016-05-20 04:17:00Z ming $ */
+/* $Id: vid_streamutil.c 5618 2017-07-04 13:00:42Z nanang $ */
/*
* Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
*
@@ -108,8 +108,20 @@ static const char *desc =
static void print_stream_stat(pjmedia_vid_stream *stream,
const pjmedia_vid_codec_param *codec_param);
-/* Prototype for LIBSRTP utility in file datatypes.c */
-int hex_string_to_octet_string(char *raw, char *hex, int len);
+/* Hexa string to octet array */
+int my_hex_string_to_octet_string(char *raw, char *hex, int len)
+{
+ int i;
+ for (i = 0; i < len; i+=2) {
+ int tmp;
+ if (i+1 >= len || !pj_isxdigit(hex[i]) || !pj_isxdigit(hex[i+1]))
+ return i;
+ tmp = pj_hex_digit_to_val((unsigned char)hex[i]) << 4;
+ tmp |= pj_hex_digit_to_val((unsigned char)hex[i+1]);
+ raw[i/2] = (char)(tmp & 0xFF);
+ }
+ return len;
+}
/*
* Register all codecs.
@@ -505,14 +517,14 @@ int main(int argc, char *argv[])
break;
case OPT_SRTP_TX_KEY:
- tmp_key_len = hex_string_to_octet_string(tmp_tx_key, pj_optarg,
- (int)strlen(pj_optarg));
+ tmp_key_len = my_hex_string_to_octet_string(tmp_tx_key, pj_optarg,
+ (int)strlen(pj_optarg));
pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
break;
case OPT_SRTP_RX_KEY:
- tmp_key_len = hex_string_to_octet_string(tmp_rx_key, pj_optarg,
- (int)strlen(pj_optarg));
+ tmp_key_len = my_hex_string_to_octet_string(tmp_rx_key, pj_optarg,
+ (int)strlen(pj_optarg));
pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
break;
#endif
diff --git a/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MainActivity.java b/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MainActivity.java
index cd5c74e..643e4e1 100644
--- a/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MainActivity.java
+++ b/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MainActivity.java
@@ -18,6 +18,7 @@
*/
package org.pjsip.pjsua2.app;
+import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -26,6 +27,8 @@ import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -36,6 +39,8 @@ import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import java.util.ArrayList;
import java.util.HashMap;
@@ -50,6 +55,8 @@ public class MainActivity extends Activity
public static MyCall currentCall = null;
public static MyAccount account = null;
public static AccountConfig accCfg = null;
+ public static MyBroadcastReceiver receiver = null;
+ public static IntentFilter intentFilter = null;
private ListView buddyListView;
private SimpleAdapter buddyListAdapter;
@@ -65,6 +72,39 @@ public class MainActivity extends Activity
public final static int REG_STATE = 3;
public final static int BUDDY_STATE = 4;
public final static int CALL_MEDIA_STATE = 5;
+ public final static int CHANGE_NETWORK = 6;
+ }
+
+ private class MyBroadcastReceiver extends BroadcastReceiver {
+ private String conn_name = "";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (isNetworkChange(context))
+ notifyChangeNetwork();
+ }
+
+ private boolean isNetworkChange(Context context) {
+ boolean network_changed = false;
+ ConnectivityManager connectivity_mgr =
+ ((ConnectivityManager)context.getSystemService(
+ Context.CONNECTIVITY_SERVICE));
+
+ NetworkInfo net_info = connectivity_mgr.getActiveNetworkInfo();
+ if(net_info != null && net_info.isConnectedOrConnecting() &&
+ !conn_name.equalsIgnoreCase(""))
+ {
+ String new_con = net_info.getExtraInfo();
+ if (new_con != null && !new_con.equalsIgnoreCase(conn_name))
+ network_changed = true;
+
+ conn_name = (new_con == null)?"":new_con;
+ } else {
+ if (conn_name.equalsIgnoreCase(""))
+ conn_name = net_info.getExtraInfo();
+ }
+ return network_changed;
+ }
}
private HashMap<String, String> putData(String uri, String status)
@@ -143,7 +183,12 @@ public class MainActivity extends Activity
}
}
);
-
+ if (receiver == null) {
+ receiver = new MyBroadcastReceiver();
+ intentFilter = new IntentFilter(
+ ConnectivityManager.CONNECTIVITY_ACTION);
+ registerReceiver(receiver, intentFilter);
+ }
}
@Override
@@ -263,6 +308,8 @@ public class MainActivity extends Activity
currentCall = call;
showCallActivity();
+ } else if (m.what == MSG_TYPE.CHANGE_NETWORK) {
+ app.handleNetworkChange();
} else {
/* Message not handled */
@@ -576,6 +623,12 @@ public class MainActivity extends Activity
m.sendToTarget();
}
+ public void notifyChangeNetwork()
+ {
+ Message m = Message.obtain(handler, MSG_TYPE.CHANGE_NETWORK, null);
+ m.sendToTarget();
+ }
+
/* === end of MyAppObserver ==== */
}
diff --git a/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MyApp.java b/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MyApp.java
index 50c8401..8159644 100644
--- a/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MyApp.java
+++ b/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MyApp.java
@@ -33,6 +33,7 @@ interface MyAppObserver
abstract void notifyCallState(MyCall call);
abstract void notifyCallMediaState(MyCall call);
abstract void notifyBuddyState(MyBuddy buddy);
+ abstract void notifyChangeNetwork();
}
@@ -66,6 +67,7 @@ class MyCall extends Call
if (ci.getState() ==
pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED)
{
+ MyApp.ep.utilLogWrite(3, "MyCall", this.dump(true, ""));
this.delete();
}
} catch (Exception e) {
@@ -352,12 +354,20 @@ class MyApp {
~(pj_log_decoration.PJ_LOG_HAS_CR.swigValue() |
pj_log_decoration.PJ_LOG_HAS_NEWLINE.swigValue()));
+ /* Write log to file (just uncomment whenever needed) */
+ //String log_path = android.os.Environment.getExternalStorageDirectory().toString();
+ //log_cfg.setFilename(log_path + "/pjsip.log");
+
/* Set ua config. */
UaConfig ua_cfg = epConfig.getUaConfig();
ua_cfg.setUserAgent("Pjsua2 Android " + ep.libVersion().getFull());
- StringVector stun_servers = new StringVector();
- stun_servers.add("stun.pjsip.org");
- ua_cfg.setStunServer(stun_servers);
+
+ /* STUN server. */
+ //StringVector stun_servers = new StringVector();
+ //stun_servers.add("stun.pjsip.org");
+ //ua_cfg.setStunServer(stun_servers);
+
+ /* No worker thread */
if (own_worker_thread) {
ua_cfg.setThreadCnt(0);
ua_cfg.setMainThreadOnly(true);
@@ -525,6 +535,17 @@ class MyApp {
json.delete();
}
+ public void handleNetworkChange()
+ {
+ try{
+ System.out.println("Network change detected");
+ IpChangeParam changeParam = new IpChangeParam();
+ ep.handleIpChange(changeParam);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ }
+
public void deinit()
{
String configPath = appDir + "/" + configName;
diff --git a/pjsip-apps/src/swig/java/android/gradle/wrapper/gradle-wrapper.jar b/pjsip-apps/src/swig/java/android/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 13372ae..0000000
Binary files a/pjsip-apps/src/swig/java/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/pjsip-apps/src/swig/java/sample.java b/pjsip-apps/src/swig/java/sample.java
index 41eb8ff..414fa9a 100644
--- a/pjsip-apps/src/swig/java/sample.java
+++ b/pjsip-apps/src/swig/java/sample.java
@@ -1,4 +1,4 @@
-/* $Id: sample.java 5392 2016-07-20 06:55:11Z riza $ */
+/* $Id: sample.java 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
*
@@ -63,6 +63,9 @@ class MyObserver implements MyAppObserver {
@Override
public void notifyBuddyState(MyBuddy buddy) {}
+
+ @Override
+ public void notifyChangeNetwork() {}
}
class MyShutdownHook extends Thread {
diff --git a/pjsip-apps/src/swig/python/Makefile b/pjsip-apps/src/swig/python/Makefile
index 9417a20..f4fd42b 100644
--- a/pjsip-apps/src/swig/python/Makefile
+++ b/pjsip-apps/src/swig/python/Makefile
@@ -1,5 +1,15 @@
PYTHON_SO=_pjsua2.so
+USE_PYTHON3=1
+
+ifeq ($(USE_PYTHON3),1)
+ PYTHON_EXE=python3
+ PYTHON_PKG_DIR=$(HOME)/.local/lib/python3.6/site-packages
+else
+ PYTHON_EXE=python
+ PYTHON_PKG_DIR=$(HOME)/.local/lib/python2.7/site-packages
+endif
+
#PYTHON_SETUP_FLAGS = --inplace
ifeq ($(OS),Windows_NT)
PYTHON_SETUP_FLAGS += --compiler=mingw32
@@ -16,7 +26,7 @@ SWIG_FLAGS += -w312 $(USE_THREADS)
all: $(PYTHON_SO)
$(PYTHON_SO): pjsua2_wrap.cpp setup.py $(GCC_EXE)
- python setup.py build $(PYTHON_SETUP_FLAGS)
+ $(PYTHON_EXE) setup.py build $(PYTHON_SETUP_FLAGS)
gcc.exe: cc_mingw.c
gcc -o gcc.exe cc_mingw.c
@@ -30,9 +40,9 @@ clean distclean realclean:
rm -f gcc.exe g++.exe
install:
- python setup.py install --user
+ $(PYTHON_EXE) setup.py install --user
uninstall:
- rm -f $(HOME)/.local/lib/python2.7/site-packages/pjsua2*
- rm -f $(HOME)/.local/lib/python2.7/site-packages/_pjsua2*
+ rm -f $(PYTHON_PKG_DIR)/pjsua2*
+ rm -f $(PYTHON_PKG_DIR)/_pjsua2*
diff --git a/pjsip-apps/src/swig/python/setup.py b/pjsip-apps/src/swig/python/setup.py
index 5ef84ed..5498926 100644
--- a/pjsip-apps/src/swig/python/setup.py
+++ b/pjsip-apps/src/swig/python/setup.py
@@ -1,4 +1,4 @@
-# $Id: setup.py 5281 2016-05-03 04:27:07Z nanang $
+# $Id: setup.py 5638 2017-08-02 09:45:09Z riza $
#
# pjsua2 Setup script.
#
@@ -29,35 +29,37 @@ pj_version_major=""
pj_version_minor=""
pj_version_rev=""
pj_version_suffix=""
+write=sys.stdout.write
f = open('../../../../version.mak', 'r')
for line in f:
+ tokens=""
if line.find("export PJ_VERSION_MAJOR") != -1:
- tokens=line.split("=")
- if len(tokens)>1:
- pj_version_major= tokens[1].strip()
+ tokens=line.split("=")
+ if len(tokens)>1:
+ pj_version_major= tokens[1].strip()
elif line.find("export PJ_VERSION_MINOR") != -1:
- tokens=line.split("=")
- if len(tokens)>1:
- pj_version_minor= line.split("=")[1].strip()
+ tokens=line.split("=")
+ if len(tokens)>1:
+ pj_version_minor= line.split("=")[1].strip()
elif line.find("export PJ_VERSION_REV") != -1:
- tokens=line.split("=")
- if len(tokens)>1:
- pj_version_rev= line.split("=")[1].strip()
+ tokens=line.split("=")
+ if len(tokens)>1:
+ pj_version_rev= line.split("=")[1].strip()
elif line.find("export PJ_VERSION_SUFFIX") != -1:
- tokens=line.split("=")
- if len(tokens)>1:
- pj_version_suffix= line.split("=")[1].strip()
+ tokens=line.split("=")
+ if len(tokens)>1:
+ pj_version_suffix= line.split("=")[1].strip()
f.close()
if not pj_version_major:
- print 'Unable to get PJ_VERSION_MAJOR'
+ write("Unable to get PJ_VERSION_MAJOR" + "\r\n")
sys.exit(1)
pj_version = pj_version_major + "." + pj_version_minor
if pj_version_rev:
- pj_version += "." + pj_version_rev
+ pj_version += "." + pj_version_rev
if pj_version_suffix:
- pj_version += "-" + pj_version_suffix
+ pj_version += "-" + pj_version_suffix
#print 'PJ_VERSION = "'+ pj_version + '"'
diff --git a/pjsip-apps/src/swig/python/test.py b/pjsip-apps/src/swig/python/test.py
index 24801ed..635cebc 100644
--- a/pjsip-apps/src/swig/python/test.py
+++ b/pjsip-apps/src/swig/python/test.py
@@ -2,168 +2,171 @@ import pjsua2 as pj
import sys
import time
+write=sys.stdout.write
+
#
# Basic data structure test, to make sure basic struct
# and array operations work
#
def ua_data_test():
- #
- # AuthCredInfo
- #
- print "UA data types test.."
- the_realm = "pjsip.org"
- ci = pj.AuthCredInfo()
- ci.realm = the_realm
- ci.dataType = 20
-
- ci2 = ci
- assert ci.dataType == 20
- assert ci2.realm == the_realm
-
- #
- # UaConfig
- # See here how we manipulate std::vector
- #
- uc = pj.UaConfig()
- uc.maxCalls = 10
- uc.userAgent = "Python"
- uc.nameserver = pj.StringVector(["10.0.0.1", "10.0.0.2"])
- uc.nameserver.append("NS1")
-
- uc2 = uc
- assert uc2.maxCalls == 10
- assert uc2.userAgent == "Python"
- assert len(uc2.nameserver) == 3
- assert uc2.nameserver[0] == "10.0.0.1"
- assert uc2.nameserver[1] == "10.0.0.2"
- assert uc2.nameserver[2] == "NS1"
-
- print " Dumping nameservers: ",
- for s in uc2.nameserver:
- print s,
- print ""
+ #
+ # AuthCredInfo
+ #
+ write("UA data types test..")
+ the_realm = "pjsip.org"
+ ci = pj.AuthCredInfo()
+ ci.realm = the_realm
+ ci.dataType = 20
+
+ ci2 = ci
+ assert ci.dataType == 20
+ assert ci2.realm == the_realm
+
+ #
+ # UaConfig
+ # See here how we manipulate std::vector
+ #
+ uc = pj.UaConfig()
+ uc.maxCalls = 10
+ uc.userAgent = "Python"
+ uc.nameserver = pj.StringVector(["10.0.0.1", "10.0.0.2"])
+ uc.nameserver.append("NS1")
+
+ uc2 = uc
+ assert uc2.maxCalls == 10
+ assert uc2.userAgent == "Python"
+ assert len(uc2.nameserver) == 3
+ assert uc2.nameserver[0] == "10.0.0.1"
+ assert uc2.nameserver[1] == "10.0.0.2"
+ assert uc2.nameserver[2] == "NS1"
+
+ write(" Dumping nameservers: " + "\r\n")
+ for s in uc2.nameserver:
+ write(s + "\r\n")
+ write("\r\n")
#
# Exception test
#
def ua_run_test_exception():
- print "Exception test.."
- ep = pj.Endpoint()
- ep.libCreate()
- got_exception = False
- try:
- ep.natDetectType()
- except pj.Error, e:
- got_exception = True
- print " Got exception: status=%u, reason=%s,\n title=%s,\n srcFile=%s, srcLine=%d" % \
- (e.status, e.reason, e.title, e.srcFile, e.srcLine)
- assert e.status == 370050
- assert e.reason.find("PJNATH_ESTUNINSERVER") >= 0
- assert e.title == "pjsua_detect_nat_type()"
- assert got_exception
+ write("Exception test.." + "\r\n")
+ ep = pj.Endpoint()
+ ep.libCreate()
+ got_exception = False
+ try:
+ ep.natDetectType()
+ except pj.Error as e:
+ #t, e = sys.exc_info()[:2]
+ got_exception = True
+ write(" Got exception: status=%u, reason=%s,\n title=%s,\n srcFile=%s, srcLine=%d" % \
+ (e.status, e.reason, e.title, e.srcFile, e.srcLine) + "\r\n")
+ assert e.status == 370050
+ assert e.reason.find("PJNATH_ESTUNINSERVER") >= 0
+ assert e.title == "pjsua_detect_nat_type()"
+ assert got_exception
#
# Custom log writer
#
class MyLogWriter(pj.LogWriter):
- def write(self, entry):
- print "This is Python:", entry.msg
-
+ def write(self, entry):
+ write("This is Python:" + entry.msg + "\r\n")
+
#
# Testing log writer callback
#
def ua_run_log_test():
- print "Logging test.."
- ep_cfg = pj.EpConfig()
-
- lw = MyLogWriter()
- ep_cfg.logConfig.writer = lw
- ep_cfg.logConfig.decor = ep_cfg.logConfig.decor & ~(pj.PJ_LOG_HAS_CR | pj.PJ_LOG_HAS_NEWLINE)
-
- ep = pj.Endpoint()
- ep.libCreate()
- ep.libInit(ep_cfg)
- ep.libDestroy()
-
+ write("Logging test.." + "\r\n")
+ ep_cfg = pj.EpConfig()
+
+ lw = MyLogWriter()
+ ep_cfg.logConfig.writer = lw
+ ep_cfg.logConfig.decor = ep_cfg.logConfig.decor & ~(pj.PJ_LOG_HAS_CR | pj.PJ_LOG_HAS_NEWLINE)
+
+ ep = pj.Endpoint()
+ ep.libCreate()
+ ep.libInit(ep_cfg)
+ ep.libDestroy()
+
#
# Simple create, init, start, and destroy sequence
#
def ua_run_ua_test():
- print "UA test run.."
- ep_cfg = pj.EpConfig()
-
- ep = pj.Endpoint()
- ep.libCreate()
- ep.libInit(ep_cfg)
- ep.libStart()
-
- print "************* Endpoint started ok, now shutting down... *************"
- ep.libDestroy()
+ write("UA test run.." + "\r\n")
+ ep_cfg = pj.EpConfig()
+
+ ep = pj.Endpoint()
+ ep.libCreate()
+ ep.libInit(ep_cfg)
+ ep.libStart()
+
+ write("************* Endpoint started ok, now shutting down... *************" + "\r\n")
+ ep.libDestroy()
#
# Tone generator
#
def ua_tonegen_test():
- print "UA tonegen test.."
- ep_cfg = pj.EpConfig()
-
- ep = pj.Endpoint()
- ep.libCreate()
- ep.libInit(ep_cfg)
- ep.libStart()
-
- tonegen = pj.ToneGenerator()
- tonegen.createToneGenerator()
-
- tone = pj.ToneDesc()
- tone.freq1 = 400
- tone.freq2 = 600
- tone.on_msec = 1000
- tone.off_msec = 1000
- tones = pj.ToneDescVector()
- tones.append(tone)
-
- digit = pj.ToneDigit()
- digit.digit = '0'
- digit.on_msec = 1000
- digit.off_msec = 1000
- digits = pj.ToneDigitVector()
- digits.append(digit)
-
- adm = ep.audDevManager()
- spk = adm.getPlaybackDevMedia()
-
- tonegen.play(tones, True)
- tonegen.startTransmit(spk)
- time.sleep(5)
-
- tonegen.stop()
- tonegen.playDigits(digits, True)
- time.sleep(5)
-
- dm = tonegen.getDigitMap()
- print dm[0].digit
- dm[0].freq1 = 400
- dm[0].freq2 = 600
- tonegen.setDigitMap(dm)
-
- tonegen.stop()
- tonegen.playDigits(digits, True)
- time.sleep(5)
-
- tonegen = None
-
- ep.libDestroy()
+ write("UA tonegen test.." + "\r\n")
+ ep_cfg = pj.EpConfig()
+
+ ep = pj.Endpoint()
+ ep.libCreate()
+ ep.libInit(ep_cfg)
+ ep.libStart()
+
+ tonegen = pj.ToneGenerator()
+ tonegen.createToneGenerator()
+
+ tone = pj.ToneDesc()
+ tone.freq1 = 400
+ tone.freq2 = 600
+ tone.on_msec = 1000
+ tone.off_msec = 1000
+ tones = pj.ToneDescVector()
+ tones.append(tone)
+
+ digit = pj.ToneDigit()
+ digit.digit = '0'
+ digit.on_msec = 1000
+ digit.off_msec = 1000
+ digits = pj.ToneDigitVector()
+ digits.append(digit)
+
+ adm = ep.audDevManager()
+ spk = adm.getPlaybackDevMedia()
+
+ tonegen.play(tones, True)
+ tonegen.startTransmit(spk)
+ time.sleep(5)
+
+ tonegen.stop()
+ tonegen.playDigits(digits, True)
+ time.sleep(5)
+
+ dm = tonegen.getDigitMap()
+ write(dm[0].digit + "\r\n")
+ dm[0].freq1 = 400
+ dm[0].freq2 = 600
+ tonegen.setDigitMap(dm)
+
+ tonegen.stop()
+ tonegen.playDigits(digits, True)
+ time.sleep(5)
+
+ tonegen = None
+
+ ep.libDestroy()
#
# main()
#
if __name__ == "__main__":
- ua_data_test()
- ua_run_test_exception()
- ua_run_log_test()
- ua_run_ua_test()
- ua_tonegen_test()
- sys.exit(0)
-
-
+ ua_data_test()
+ ua_run_test_exception()
+ ua_run_log_test()
+ ua_run_ua_test()
+ ua_tonegen_test()
+ sys.exit(0)
+
+
diff --git a/pjsip-apps/src/swig/symbols.i b/pjsip-apps/src/swig/symbols.i
index 5edacf2..25d13dc 100644
--- a/pjsip-apps/src/swig/symbols.i
+++ b/pjsip-apps/src/swig/symbols.i
@@ -153,6 +153,8 @@ typedef enum pjsua_sip_timer_use {PJSUA_SIP_TIMER_INACTIVE, PJSUA_SIP_TIMER_OPTI
typedef enum pjsua_ipv6_use {PJSUA_IPV6_DISABLED, PJSUA_IPV6_ENABLED} pjsua_ipv6_use;
+typedef enum pjsua_nat64_opt {PJSUA_NAT64_DISABLED, PJSUA_NAT64_ENABLED} pjsua_nat64_opt;
+
typedef enum pjsua_buddy_status {PJSUA_BUDDY_STATUS_UNKNOWN, PJSUA_BUDDY_STATUS_ONLINE, PJSUA_BUDDY_STATUS_OFFLINE} pjsua_buddy_status;
typedef enum pjsua_call_media_status {PJSUA_CALL_MEDIA_NONE, PJSUA_CALL_MEDIA_ACTIVE, PJSUA_CALL_MEDIA_LOCAL_HOLD, PJSUA_CALL_MEDIA_REMOTE_HOLD, PJSUA_CALL_MEDIA_ERROR} pjsua_call_media_status;
@@ -173,3 +175,5 @@ typedef enum pjsua_create_media_transport_flag {PJSUA_MED_TP_CLOSE_MEMBER = 1} p
typedef enum pjsua_snd_dev_mode {PJSUA_SND_DEV_SPEAKER_ONLY = 1, PJSUA_SND_DEV_NO_IMMEDIATE_OPEN = 2} pjsua_snd_dev_mode;
+typedef enum pjsua_ip_change_op {PJSUA_IP_CHANGE_OP_NULL, PJSUA_IP_CHANGE_OP_RESTART_LIS, PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP, PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT, PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS, PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS} pjsua_ip_change_op;
+
diff --git a/pjsip-apps/src/swig/symbols.lst b/pjsip-apps/src/swig/symbols.lst
index 651e78d..7d1ce17 100644
--- a/pjsip-apps/src/swig/symbols.lst
+++ b/pjsip-apps/src/swig/symbols.lst
@@ -33,4 +33,4 @@ pjsip-simple/evsub.h pjsip_evsub_state
pjsip-ua/sip_inv.h pjsip_inv_state
-pjsua-lib/pjsua.h pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_buddy_status pjsua_call_media_status pjsua_vid_win_id pjsua_call_id pjsua_med_tp_st pjsua_call_vid_strm_op pjsua_vid_req_keyframe_method pjsua_call_flag pjsua_create_media_transport_flag pjsua_snd_dev_mode
+pjsua-lib/pjsua.h pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_nat64_opt pjsua_buddy_status pjsua_call_media_status pjsua_vid_win_id pjsua_call_id pjsua_med_tp_st pjsua_call_vid_strm_op pjsua_vid_req_keyframe_method pjsua_call_flag pjsua_create_media_transport_flag pjsua_snd_dev_mode pjsua_ip_change_op
diff --git a/pjsip/include/pjsip-simple/evsub.h b/pjsip/include/pjsip-simple/evsub.h
index af1f5e6..ce2c307 100644
--- a/pjsip/include/pjsip-simple/evsub.h
+++ b/pjsip/include/pjsip-simple/evsub.h
@@ -1,4 +1,4 @@
-/* $Id: evsub.h 5397 2016-07-26 02:58:44Z nanang $ */
+/* $Id: evsub.h 5558 2017-02-20 01:29:21Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -511,6 +511,18 @@ PJ_DEF(pj_status_t) pjsip_evsub_add_ref(pjsip_evsub *sub);
PJ_DEF(pj_status_t) pjsip_evsub_dec_ref(pjsip_evsub *sub);
+/**
+ * Sets, resets, or cancels the UAS subscription timeout.
+ * If there is an existing timer, it is cancelled before any
+ * other action. A timeout of 0 is ignored except that any
+ * existing timer is cancelled.
+ *
+ * @param sub The server subscription instance.
+ * @param seconds The new timeout.
+ */
+PJ_DEF(void) pjsip_evsub_uas_set_timeout(pjsip_evsub *sub,
+ pj_uint32_t seconds);
+
PJ_END_DECL
diff --git a/pjsip/include/pjsip-ua/sip_inv.h b/pjsip/include/pjsip-ua/sip_inv.h
index c969932..d62fd9e 100644
--- a/pjsip/include/pjsip-ua/sip_inv.h
+++ b/pjsip/include/pjsip-ua/sip_inv.h
@@ -1,4 +1,4 @@
-/* $Id: sip_inv.h 5435 2016-08-30 08:40:18Z riza $ */
+/* $Id: sip_inv.h 5641 2017-08-16 04:53:44Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -97,6 +97,17 @@ typedef enum pjsip_inv_state
} pjsip_inv_state;
/**
+ * Structure to hold parameters when calling the callback
+ * #on_rx_offer2().
+ */
+struct pjsip_inv_on_rx_offer_cb_param
+{
+ const pjmedia_sdp_session *offer; /** Remote offer. */
+ const pjsip_rx_data *rdata; /** The received request. */
+};
+
+
+/**
* This structure contains callbacks to be registered by application to
* receieve notifications from the framework about various events in
* the invite session.
@@ -154,11 +165,24 @@ typedef struct pjsip_inv_callback
* this SDP answer will be negotiated with the offer, and the result
* will be sent with the SIP message.
*
+ * Note: if callback #on_rx_offer2() is implemented, this callback will
+ * not be called.
+ *
* @param inv The invite session.
* @param offer Remote offer.
*/
void (*on_rx_offer)(pjsip_inv_session *inv,
- const pjmedia_sdp_session *offer);
+ const pjmedia_sdp_session *offer);
+
+ /**
+ * This callback is called when the invite session has received
+ * new offer from peer. Variant of #on_rx_offer() callback.
+ *
+ * @param inv The invite session.
+ * @param param The callback parameters.
+ */
+ void (*on_rx_offer2)(pjsip_inv_session *inv,
+ struct pjsip_inv_on_rx_offer_cb_param *param);
/**
* This callback is optional, and is called when the invite session has
diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
index f591b20..d67424c 100644
--- a/pjsip/include/pjsip/sip_config.h
+++ b/pjsip/include/pjsip/sip_config.h
@@ -1,4 +1,4 @@
-/* $Id: sip_config.h 5336 2016-06-07 10:07:57Z riza $ */
+/* $Id: sip_config.h 5557 2017-02-20 01:23:54Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -1242,6 +1242,18 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
/**
+ * Default delay for retrying session refresh request upon
+ * receiving transport error (503). Set it to -1 to end the session
+ * immediately instead.
+ *
+ * Default: 10 seconds
+ */
+#ifndef PJSIP_SESS_TIMER_RETRY_DELAY
+# define PJSIP_SESS_TIMER_RETRY_DELAY 10
+#endif
+
+
+/**
* Specify whether the client publication session should queue the
* PUBLISH request should there be another PUBLISH transaction still
* pending. If this is set to false, the client will return error
diff --git a/pjsip/include/pjsip/sip_multipart.h b/pjsip/include/pjsip/sip_multipart.h
index be8ae26..4540481 100644
--- a/pjsip/include/pjsip/sip_multipart.h
+++ b/pjsip/include/pjsip/sip_multipart.h
@@ -1,4 +1,4 @@
-/* $Id: sip_multipart.h 3553 2011-05-05 06:14:19Z nanang $ */
+/* $Id: sip_multipart.h 5569 2017-03-21 07:19:43Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -170,6 +170,21 @@ PJ_DECL(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool,
unsigned options);
/**
+ * Get the boundary string and the raw message body of the specified
+ * multipart message body. Note that raw message body will only be available
+ * if the multipart message body is generated by pjsip_multipart_parse().
+ *
+ * @param mp The multipart message body.
+ * @param boundary Optional parameter to receive the boundary string.
+ * @param raw_data Optional parameter to receive the raw message body.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_multipart_get_raw(pjsip_msg_body *mp,
+ pj_str_t *boundary,
+ pj_str_t *raw_data);
+
+/**
* @} PJSIP_MULTIPART
*/
diff --git a/pjsip/include/pjsip/sip_transaction.h b/pjsip/include/pjsip/sip_transaction.h
index 575298a..bb834b2 100644
--- a/pjsip/include/pjsip/sip_transaction.h
+++ b/pjsip/include/pjsip/sip_transaction.h
@@ -1,4 +1,4 @@
-/* $Id: sip_transaction.h 4420 2013-03-05 11:59:54Z bennylp $ */
+/* $Id: sip_transaction.h 5573 2017-03-29 02:40:48Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -179,6 +179,10 @@ PJ_DECL(unsigned) pjsip_tsx_layer_get_tsx_count(void);
* Find a transaction with the specified key. The transaction key normally
* is created by calling #pjsip_tsx_create_key() from an incoming message.
*
+ * IMPORTANT: To prevent deadlock, application should use
+ * #pjsip_tsx_layer_find_tsx2() instead which only adds a reference to
+ * the transaction instead of locking it.
+ *
* @param key The key string to find the transaction.
* @param lock If non-zero, transaction will be locked before the
* function returns, to make sure that it's not deleted
@@ -191,6 +195,21 @@ PJ_DECL(pjsip_transaction*) pjsip_tsx_layer_find_tsx( const pj_str_t *key,
pj_bool_t lock );
/**
+ * Find a transaction with the specified key. The transaction key normally
+ * is created by calling #pjsip_tsx_create_key() from an incoming message.
+ *
+ * @param key The key string to find the transaction.
+ * @param add_ref If non-zero, transaction's reference will be added
+ * by one before the function returns, to make sure that
+ * it's not deleted by other threads.
+ *
+ * @return The matching transaction instance, or NULL if transaction
+ * can not be found.
+ */
+PJ_DECL(pjsip_transaction*) pjsip_tsx_layer_find_tsx2( const pj_str_t *key,
+ pj_bool_t add_ref );
+
+/**
* Create, initialize, and register a new transaction as UAC from the
* specified transmit data (\c tdata). The transmit data must have a valid
* \c Request-Line and \c CSeq header.
diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h
index 78e3e1b..ad4300d 100644
--- a/pjsip/include/pjsip/sip_transport.h
+++ b/pjsip/include/pjsip/sip_transport.h
@@ -1,4 +1,4 @@
-/* $Id: sip_transport.h 5308 2016-05-19 06:55:16Z ming $ */
+/* $Id: sip_transport.h 5556 2017-02-20 01:16:58Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -903,6 +903,23 @@ PJ_DECL(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
PJ_DECL(pj_status_t) pjsip_transport_shutdown(pjsip_transport *tp);
/**
+ * Start shutdown procedure for this transport. If \a force is false,
+ * the API is the same as #pjsip_transport_shutdown(), while
+ * if \a force is true, existing transport users will immediately
+ * receive PJSIP_TP_STATE_DISCONNECTED notification and should not
+ * use the transport anymore. In either case, transport will
+ * only be destroyed after all objects release their references.
+ *
+ * @param tp The transport.
+ * @param force Force transport to immediately send
+ * disconnection state notification.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_transport_shutdown2(pjsip_transport *tp,
+ pj_bool_t force);
+
+/**
* Destroy a transport when there is no object currently uses the transport.
* This function is normally called internally by transport manager or the
* transport itself. Application should use #pjsip_transport_shutdown()
diff --git a/pjsip/include/pjsip/sip_transport_tcp.h b/pjsip/include/pjsip/sip_transport_tcp.h
index e793f02..a43c824 100644
--- a/pjsip/include/pjsip/sip_transport_tcp.h
+++ b/pjsip/include/pjsip/sip_transport_tcp.h
@@ -1,4 +1,4 @@
-/* $Id: sip_transport_tcp.h 4860 2014-06-19 05:07:12Z riza $ */
+/* $Id: sip_transport_tcp.h 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -225,6 +225,57 @@ PJ_DECL(pj_status_t) pjsip_tcp_transport_start3(
*/
PJ_DECL(pj_sock_t) pjsip_tcp_transport_get_socket(pjsip_transport *transport);
+/**
+ * Start the TCP listener, if the listener is not started yet. This is useful
+ * to start the listener manually, if listener was not started when
+ * PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER is set to 0.
+ *
+ * @param factory The SIP TCP transport factory.
+ *
+ * @param local The address where the listener should be bound to.
+ * Both IP interface address and port fields are optional.
+ * If IP interface address is not specified, socket
+ * will be bound to PJ_INADDR_ANY. If port is not
+ * specified, socket will be bound to any port
+ * selected by the operating system.
+ *
+ * @param a_name The published address for the listener.
+ * If this argument is NULL, then the bound address will
+ * be used as the published address.
+ *
+ * @return PJ_SUCCESS when the listener has been successfully
+ * started.
+ */
+PJ_DECL(pj_status_t) pjsip_tcp_transport_lis_start(pjsip_tpfactory *factory,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name);
+
+/**
+ * Restart the TCP listener. This will close the listener socket and recreate
+ * the socket based on the config used when starting the transport.
+ *
+ * @param factory The SIP TCP transport factory.
+ *
+ * @param local The address where the listener should be bound to.
+ * Both IP interface address and port fields are optional.
+ * If IP interface address is not specified, socket
+ * will be bound to PJ_INADDR_ANY. If port is not
+ * specified, socket will be bound to any port
+ * selected by the operating system.
+ *
+ * @param a_name The published address for the listener.
+ * If this argument is NULL, then the bound address will
+ * be used as the published address.
+ *
+ * @return PJ_SUCCESS when the listener has been successfully
+ * restarted.
+ *
+ */
+PJ_DECL(pj_status_t) pjsip_tcp_transport_restart(pjsip_tpfactory *factory,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name);
+
+
PJ_END_DECL
/**
diff --git a/pjsip/include/pjsip/sip_transport_tls.h b/pjsip/include/pjsip/sip_transport_tls.h
index 2a83cb8..ae4965f 100644
--- a/pjsip/include/pjsip/sip_transport_tls.h
+++ b/pjsip/include/pjsip/sip_transport_tls.h
@@ -1,4 +1,4 @@
-/* $Id: sip_transport_tls.h 5472 2016-10-27 07:58:01Z ming $ */
+/* $Id: sip_transport_tls.h 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -429,11 +429,62 @@ PJ_DECL(pj_status_t) pjsip_tls_transport_start(pjsip_endpoint *endpt,
* the appropriate error code.
*/
PJ_DECL(pj_status_t) pjsip_tls_transport_start2(pjsip_endpoint *endpt,
- const pjsip_tls_setting *opt,
- const pj_sockaddr *local,
- const pjsip_host_port *a_name,
- unsigned async_cnt,
- pjsip_tpfactory **p_factory);
+ const pjsip_tls_setting *opt,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name,
+ unsigned async_cnt,
+ pjsip_tpfactory **p_factory);
+
+/**
+ * Start the TLS listener, if the listener is not started yet. This is useful
+ * to start the listener manually, if listener was not started when
+ * PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER is set to 0.
+ *
+ * @param factory The SIP TLS transport factory.
+ *
+ * @param local The address where the listener should be bound to.
+ * Both IP interface address and port fields are optional.
+ * If IP interface address is not specified, socket
+ * will be bound to PJ_INADDR_ANY. If port is not
+ * specified, socket will be bound to any port
+ * selected by the operating system.
+ *
+ * @param a_name The published address for the listener.
+ * If this argument is NULL, then the bound address will
+ * be used as the published address.
+ *
+ * @return PJ_SUCCESS when the listener has been successfully
+ * started.
+ */
+PJ_DECL(pj_status_t) pjsip_tls_transport_lis_start(pjsip_tpfactory *factory,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name);
+
+
+/**
+ * Restart the TLS listener. This will close the listener socket and recreate
+ * the socket based on the config used when starting the transport.
+ *
+ * @param factory The SIP TLS transport factory.
+ *
+ * @param local The address where the listener should be bound to.
+ * Both IP interface address and port fields are optional.
+ * If IP interface address is not specified, socket
+ * will be bound to PJ_INADDR_ANY. If port is not
+ * specified, socket will be bound to any port
+ * selected by the operating system.
+ *
+ * @param a_name The published address for the listener.
+ * If this argument is NULL, then the bound address will
+ * be used as the published address.
+ *
+ * @return PJ_SUCCESS when the listener has been successfully
+ * restarted.
+ *
+ */
+PJ_DECL(pj_status_t) pjsip_tls_transport_restart(pjsip_tpfactory *factory,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name);
PJ_END_DECL
diff --git a/pjsip/include/pjsip/sip_transport_udp.h b/pjsip/include/pjsip/sip_transport_udp.h
index c952111..8305bc7 100644
--- a/pjsip/include/pjsip/sip_transport_udp.h
+++ b/pjsip/include/pjsip/sip_transport_udp.h
@@ -1,4 +1,4 @@
-/* $Id: sip_transport_udp.h 5284 2016-05-10 05:13:57Z nanang $ */
+/* $Id: sip_transport_udp.h 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -319,6 +319,51 @@ PJ_DECL(pj_status_t) pjsip_udp_transport_restart(pjsip_transport *transport,
const pj_sockaddr_in *local,
const pjsip_host_port *a_name);
+/**
+ * Restart the transport. Several operations are supported by this function:
+ * - if transport was made temporarily unavailable to SIP stack with
+ * pjsip_udp_transport_pause() and PJSIP_UDP_TRANSPORT_KEEP_SOCKET,
+ * application can make the transport available to the SIP stack
+ * again, by specifying PJSIP_UDP_TRANSPORT_KEEP_SOCKET flag here.
+ * - if application wants to replace the internal socket with a new
+ * socket, it must specify PJSIP_UDP_TRANSPORT_DESTROY_SOCKET when
+ * calling this function, so that the internal socket will be destroyed
+ * if it hasn't been closed. In this case, application has two choices
+ * on how to create the new socket: 1) to let the transport create
+ * the new socket, in this case the \a sock option should be set
+ * to \a PJ_INVALID_SOCKET and optionally the \a local parameter can be
+ * filled with the desired address and port where the new socket
+ * should be bound to, or 2) to specify its own socket to be used
+ * by this transport, by specifying a valid socket in \a sock argument
+ * and set the \a local argument to NULL. In both cases, application
+ * may specify the published address of the socket in \a a_name
+ * argument. This is another version of pjsip_udp_transport_restart()
+ * able to restart IPv6 transport.
+ *
+ * @param transport The UDP transport.
+ * @param option Restart option.
+ * @param sock Optional socket to be used by the transport.
+ * @param local The address where the socket should be bound to.
+ * If this argument is NULL, socket will be bound
+ * to any available port.
+ * @param a_name Optionally specify the published address for
+ * this transport. If the socket is not replaced
+ * (PJSIP_UDP_TRANSPORT_KEEP_SOCKET flag is
+ * specified), then if this argument is NULL, the
+ * previous value will be used. If the socket is
+ * replaced and this argument is NULL, the bound
+ * address will be used as the published address
+ * of the transport.
+ *
+ * @return PJ_SUCCESS if transport can be restarted, or
+ * the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_udp_transport_restart2(pjsip_transport *transport,
+ unsigned option,
+ pj_sock_t sock,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name);
+
PJ_END_DECL
diff --git a/pjsip/include/pjsip/sip_uri.h b/pjsip/include/pjsip/sip_uri.h
index 398085b..493593f 100644
--- a/pjsip/include/pjsip/sip_uri.h
+++ b/pjsip/include/pjsip/sip_uri.h
@@ -1,4 +1,4 @@
-/* $Id: sip_uri.h 4537 2013-06-19 06:47:43Z riza $ */
+/* $Id: sip_uri.h 5601 2017-06-08 04:57:59Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -294,7 +294,7 @@ PJ_INLINE(pj_status_t) pjsip_uri_cmp(pjsip_uri_context_e context,
* @param uri The URI to print.
* @param buf The buffer.
* @param size Size of the buffer.
- * @return Length printed.
+ * @return Length printed if successful, negative value if failed.
*/
PJ_INLINE(int) pjsip_uri_print(pjsip_uri_context_e context,
const void *uri,
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index ff89273..c077e4d 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -1,4 +1,4 @@
-/* $Id: pjsua.h 5493 2016-12-06 11:23:39Z ming $ */
+/* $Id: pjsua.h 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -619,6 +619,88 @@ typedef enum pjsua_contact_rewrite_method
/**
+ * This enumeration specifies the operation when handling IP change.
+ */
+typedef enum pjsua_ip_change_op {
+ /**
+ * Hasn't start ip change process.
+ */
+ PJSUA_IP_CHANGE_OP_NULL,
+
+ /**
+ * The restart listener process.
+ */
+ PJSUA_IP_CHANGE_OP_RESTART_LIS,
+
+ /**
+ * The shutdown transport process.
+ */
+ PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP,
+
+ /**
+ * The update contact process.
+ */
+ PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT,
+
+ /**
+ * The hanging up call process.
+ */
+ PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS,
+
+ /**
+ * The re-INVITE call process.
+ */
+ PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS
+
+} pjsua_ip_change_op;
+
+
+/**
+ * This will contain the information of the callback \a on_ip_change_progress.
+ */
+typedef union pjsua_ip_change_op_info {
+ /**
+ * The information from listener restart operation.
+ */
+ struct {
+ int transport_id;
+ } lis_restart;
+
+ /**
+ * The information from shutdown transport.
+ */
+ struct {
+ int acc_id;
+ } acc_shutdown_tp;
+
+ /**
+ * The information from updating contact.
+ */
+ struct {
+ pjsua_acc_id acc_id;
+ pj_bool_t is_register; /**< SIP Register if PJ_TRUE. */
+ int code; /**< SIP status code received. */
+ } acc_update_contact;
+
+ /**
+ * The information from hanging up call operation.
+ */
+ struct {
+ pjsua_acc_id acc_id;
+ pjsua_call_id call_id;
+ } acc_hangup_calls;
+
+ /**
+ * The information from re-Invite call operation.
+ */
+ struct {
+ pjsua_acc_id acc_id;
+ pjsua_call_id call_id;
+ } acc_reinvite_calls;
+} pjsua_ip_change_op_info;
+
+
+/**
* Call settings.
*/
typedef struct pjsua_call_setting
@@ -706,7 +788,8 @@ typedef struct pjsua_callback
* Normal application would need to implement this callback, e.g.
* to connect the call's media to sound device. When ICE is used,
* this callback will also be called to report ICE negotiation
- * failure.
+ * failure. When DTLS-SRTP is used, this callback will also be called
+ * to report DTLS negotiation failure.
*
* @param call_id The call index.
*/
@@ -1415,6 +1498,19 @@ typedef struct pjsua_callback
*/
pj_stun_resolve_cb on_stun_resolution_complete;
+ /**
+ * Calling #pjsua_handle_ip_change() may involve different operation. This
+ * callback is called to report the progress of each enabled operation.
+ *
+ * @param op The operation.
+ * @param status The status of operation.
+ * @param info The info from the operation
+ *
+ */
+ void (*on_ip_change_progress)(pjsua_ip_change_op op,
+ pj_status_t status,
+ const pjsua_ip_change_op_info *info);
+
} pjsua_callback;
@@ -1594,6 +1690,15 @@ typedef struct pjsua_config
pj_str_t stun_srv[8];
/**
+ * This specifies if the library should try to do an IPv6 resolution of
+ * the STUN servers if the IPv4 resolution fails. It can be useful
+ * in an IPv6-only environment, including on NAT64.
+ *
+ * Default: PJ_FALSE
+ */
+ pj_bool_t stun_try_ipv6;
+
+ /**
* This specifies if the library should ignore failure with the
* STUN servers. If this is set to PJ_FALSE, the library will refuse to
* start if it fails to resolve or contact any of the STUN servers.
@@ -2073,6 +2178,74 @@ struct pj_stun_resolve_result
/**
+ * This structure describe the parameter passed to #pjsua_handle_ip_change().
+ */
+typedef struct pjsua_ip_change_param
+{
+ /**
+ * If set to PJ_TRUE, this will restart the transport listener.
+ *
+ * Default : PJ_TRUE
+ */
+ pj_bool_t restart_listener;
+
+ /**
+ * If \a restart listener is set to PJ_TRUE, some delay might be needed
+ * for the listener to be restarted. Use this to set the delay.
+ *
+ * Default : PJSUA_TRANSPORT_RESTART_DELAY_TIME
+ */
+ unsigned restart_lis_delay;
+
+} pjsua_ip_change_param;
+
+
+/**
+ * This structure describe the account config specific to IP address change.
+ */
+typedef struct pjsua_ip_change_acc_cfg
+{
+ /**
+ * Shutdown the transport used for account registration. If this is set to
+ * PJ_TRUE, the transport will be shutdown altough it's used by multiple
+ * account. Shutdown transport will be followed by re-Registration if
+ * pjsua_acc_config.allow_contact_rewrite is enabled.
+ *
+ * Default: PJ_TRUE
+ */
+ pj_bool_t shutdown_tp;
+
+ /**
+ * Hangup active calls associated with the account. If this is set to
+ * PJ_TRUE, then the calls will be hang up.
+ *
+ * Default: PJ_FALSE
+ */
+ pj_bool_t hangup_calls;
+
+ /**
+ * Specify the call flags used in the re-INVITE when \a hangup_calls is set
+ * to PJ_FALSE. If this is set to 0, no re-INVITE will be sent. The
+ * re-INVITE will be sent after re-Registration is finished.
+ *
+ * Default: PJSUA_CALL_REINIT_MEDIA | PJSUA_CALL_UPDATE_CONTACT |
+ * PJSUA_CALL_UPDATE_VIA
+ */
+ unsigned reinvite_flags;
+
+} pjsua_ip_change_acc_cfg;
+
+
+/**
+ * Call this function to initialize \a pjsua_ip_change_param with default
+ * values.
+ *
+ * @param param The IP change param to be initialized.
+ */
+PJ_DECL(void) pjsua_ip_change_param_default(pjsua_ip_change_param *param);
+
+
+/**
* This is a utility function to detect NAT type in front of this
* endpoint. Once invoked successfully, this function will complete
* asynchronously and report the result in \a on_nat_detect() callback
@@ -2292,6 +2465,31 @@ PJ_DECL(void) pjsua_perror(const char *sender, const char *title,
*/
PJ_DECL(void) pjsua_dump(pj_bool_t detail);
+
+/**
+ * Inform the stack that IP address change event was detected.
+ * The stack will:
+ * 1. Restart the listener (this step is configurable via
+ * \a pjsua_ip_change_param.restart_listener).
+ * 2. Shutdown the transport used by account registration (this step is
+ * configurable via \a pjsua_acc_config.ip_change_cfg.shutdown_tp).
+ * 3. Update contact URI by sending re-Registration (this step is configurable
+ * via a\ pjsua_acc_config.allow_contact_rewrite and
+ * a\ pjsua_acc_config.contact_rewrite_method)
+ * 4. Hangup active calls (this step is configurable via
+ * a\ pjsua_acc_config.ip_change_cfg.hangup_calls) or
+ * continue the call by sending re-INVITE
+ * (configurable via \a pjsua_acc_config.ip_change_cfg.reinvite_flags).
+ *
+ * @param param The IP change parameter, have a look at
+ * #pjsua_ip_change_param.
+ *
+ * @return PJ_SUCCESS on success, other on error.
+ */
+PJ_DECL(pj_status_t) pjsua_handle_ip_change(
+ const pjsua_ip_change_param *param);
+
+
/**
* @}
*/
@@ -2567,6 +2765,22 @@ PJ_DECL(pj_status_t) pjsua_transport_set_enable(pjsua_transport_id id,
PJ_DECL(pj_status_t) pjsua_transport_close( pjsua_transport_id id,
pj_bool_t force );
+
+/**
+ * Start the listener of the transport. This is useful when listener is not
+ * automatically started when creating the transport.
+ *
+ * @param id Transport ID.
+ * @param cfg The new transport config used by the listener.
+ * Only port, public_addr and bound_addr are used at the
+ * moment.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_transport_lis_start( pjsua_transport_id id,
+ const pjsua_transport_config *cfg);
+
+
/**
* @}
*/
@@ -2909,6 +3123,23 @@ typedef enum pjsua_ipv6_use
} pjsua_ipv6_use;
/**
+ * Specify NAT64 options to be used in account config.
+ */
+typedef enum pjsua_nat64_opt
+{
+ /**
+ * NAT64 is not used.
+ */
+ PJSUA_NAT64_DISABLED,
+
+ /**
+ * NAT64 is enabled.
+ */
+ PJSUA_NAT64_ENABLED
+
+} pjsua_nat64_opt;
+
+/**
* This structure describes account configuration to be specified when
* adding a new account with #pjsua_acc_add(). Application MUST initialize
* this structure first by calling #pjsua_acc_config_default().
@@ -3346,6 +3577,13 @@ typedef struct pjsua_acc_config
pjsua_transport_config rtp_cfg;
/**
+ * Specify NAT64 options.
+ *
+ * Default: PJSUA_NAT64_DISABLED
+ */
+ pjsua_nat64_opt nat64_opt;
+
+ /**
* Specify whether IPv6 should be used on media.
*/
pjsua_ipv6_use ipv6_media_use;
@@ -3507,7 +3745,13 @@ typedef struct pjsua_acc_config
*
* Default: PJ_TRUE
*/
- pj_bool_t register_on_acc_add;
+ pj_bool_t register_on_acc_add;
+
+ /**
+ * Specify account configuration specific to IP address change used when
+ * calling #pjsua_handle_ip_change().
+ */
+ pjsua_ip_change_acc_cfg ip_change_cfg;
} pjsua_acc_config;
@@ -4231,10 +4475,10 @@ typedef struct pjsua_call_info
/** Internal */
struct {
- char local_info[128];
- char local_contact[128];
- char remote_info[128];
- char remote_contact[128];
+ char local_info[PJSIP_MAX_URL_SIZE];
+ char local_contact[PJSIP_MAX_URL_SIZE];
+ char remote_info[PJSIP_MAX_URL_SIZE];
+ char remote_contact[PJSIP_MAX_URL_SIZE];
char call_id[128];
char last_status_text[128];
} buf_;
@@ -5694,6 +5938,15 @@ PJ_DECL(pj_status_t) pjsua_im_typing(pjsua_acc_id acc_id,
/**
+ * Specify the delay needed when restarting the transport/listener.
+ * e.g: 10 msec on Linux or Android, and 0 on the other platforms.
+ */
+#ifndef PJSUA_TRANSPORT_RESTART_DELAY_TIME
+# define PJSUA_TRANSPORT_RESTART_DELAY_TIME 10
+#endif
+
+
+/**
* This structure describes media configuration, which will be specified
* when calling #pjsua_init(). Application MUST initialize this structure
* by calling #pjsua_media_config_default().
diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h
index ab4f076..3ba792e 100644
--- a/pjsip/include/pjsua-lib/pjsua_internal.h
+++ b/pjsip/include/pjsua-lib/pjsua_internal.h
@@ -1,4 +1,4 @@
-/* $Id: pjsua_internal.h 5442 2016-10-04 09:10:11Z ming $ */
+/* $Id: pjsua_internal.h 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -285,6 +285,7 @@ typedef struct pjsua_acc
pj_uint16_t next_rtp_port; /**< Next RTP port to be used. */
pjsip_transport_type_e tp_type; /**< Transport type (for local acc or
transport binding) */
+ pjsua_ip_change_op ip_change_op;/**< IP change process progress. */
} pjsua_acc;
@@ -303,6 +304,7 @@ typedef struct pjsua_transport_data
void *ptr;
} data;
+ pj_bool_t is_restarting;
} pjsua_transport_data;
@@ -374,6 +376,7 @@ typedef struct pjsua_stun_resolve
pj_status_t status; /**< Session status */
pj_sockaddr addr; /**< Result */
pj_stun_sock *stun_sock; /**< Testing STUN sock */
+ int af; /**< Address family */
pj_bool_t async_wait;/**< Async resolution
of STUN entry */
} pjsua_stun_resolve;
@@ -866,6 +869,16 @@ PJ_DECL(void) pjsua_vid_win_reset(pjsua_vid_win_id wid);
*/
void pjsua_call_schedule_reinvite_check(pjsua_call *call, unsigned delay_ms);
+/*
+ * Update contact per account on IP change process.
+ */
+pj_status_t pjsua_acc_update_contact_on_ip_change(pjsua_acc *acc);
+
+/*
+ * Call handling per account on IP change process.
+ */
+pj_status_t pjsua_acc_handle_call_on_ip_change(pjsua_acc *acc);
+
PJ_END_DECL
#endif /* __PJSUA_INTERNAL_H__ */
diff --git a/pjsip/include/pjsua2/account.hpp b/pjsip/include/pjsua2/account.hpp
index f4da4de..f0605a1 100644
--- a/pjsip/include/pjsua2/account.hpp
+++ b/pjsip/include/pjsua2/account.hpp
@@ -1,4 +1,4 @@
-/* $Id: account.hpp 5455 2016-10-07 07:42:22Z ming $ */
+/* $Id: account.hpp 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
*
@@ -469,6 +469,13 @@ struct AccountNatConfig : public PersistentObject
pjsua_stun_use mediaStunUse;
/**
+ * Specify NAT64 options.
+ *
+ * Default: PJSUA_NAT64_DISABLED
+ */
+ pjsua_nat64_opt nat64Opt;
+
+ /**
* Enable ICE for the media transport.
*
* Default: False
@@ -874,6 +881,56 @@ public:
};
/**
+ * Account config specific to IP address change.
+ */
+typedef struct AccountIpChangeConfig
+{
+ /**
+ * Shutdown the transport used for account registration. If this is set to
+ * PJ_TRUE, the transport will be shutdown altough it's used by multiple
+ * account. Shutdown transport will be followed by re-Registration if
+ * AccountConfig.natConfig.contactRewriteUse is enabled.
+ *
+ * Default: true
+ */
+ bool shutdownTp;
+
+ /**
+ * Hangup active calls associated with the acount. If this is set to true,
+ * then the calls will be hang up.
+ *
+ * Default: false
+ */
+ bool hangupCalls;
+
+ /**
+ * Specify the call flags used in the re-INVITE when \a hangupCalls is set
+ * to false. If this is set to 0, no re-INVITE will be sent. The
+ * re-INVITE will be sent after re-Registration is finished.
+ *
+ * Default: PJSUA_CALL_REINIT_MEDIA | PJSUA_CALL_UPDATE_CONTACT |
+ * PJSUA_CALL_UPDATE_VIA
+ */
+ unsigned reinviteFlags;
+
+public:
+ /**
+ * Read this object from a container node.
+ *
+ * @param node Container to read values from.
+ */
+ virtual void readObject(const ContainerNode &node) throw(Error);
+
+ /**
+ * Write this object to a container node.
+ *
+ * @param node Container to write values to.
+ */
+ virtual void writeObject(ContainerNode &node) const throw(Error);
+
+} AccountIpChangeConfig;
+
+/**
* Account configuration.
*/
struct AccountConfig : public PersistentObject
@@ -934,6 +991,11 @@ struct AccountConfig : public PersistentObject
*/
AccountVideoConfig videoConfig;
+ /**
+ * IP Change settings.
+ */
+ AccountIpChangeConfig ipChangeConfig;
+
public:
/**
* Default constructor will initialize with default values.
diff --git a/pjsip/include/pjsua2/call.hpp b/pjsip/include/pjsua2/call.hpp
index f347a0b..6f6fd42 100644
--- a/pjsip/include/pjsua2/call.hpp
+++ b/pjsip/include/pjsua2/call.hpp
@@ -1,4 +1,4 @@
-/* $Id: call.hpp 5417 2016-08-12 03:47:26Z ming $ */
+/* $Id: call.hpp 5645 2017-09-06 03:44:35Z riza $ */
/*
* Copyright (C) 2012-2013 Teluu Inc. (http://www.teluu.com)
*
@@ -601,9 +601,14 @@ struct StreamInfo
unsigned codecClockRate;
/**
- * Optional codec param.
+ * Optional audio codec param.
*/
- CodecParam codecParam;
+ CodecParam audCodecParam;
+
+ /**
+ * Optional video codec param.
+ */
+ VidCodecParam vidCodecParam;
public:
/**
diff --git a/pjsip/include/pjsua2/endpoint.hpp b/pjsip/include/pjsua2/endpoint.hpp
index d52cde3..822fe69 100644
--- a/pjsip/include/pjsua2/endpoint.hpp
+++ b/pjsip/include/pjsua2/endpoint.hpp
@@ -1,4 +1,4 @@
-/* $Id: endpoint.hpp 5522 2017-01-11 11:13:57Z ming $ */
+/* $Id: endpoint.hpp 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
*
@@ -319,6 +319,103 @@ struct OnSelectAccountParam
int accountIndex;
};
+/**
+ * Parameter of Endpoint::handleIpChange().
+ */
+struct IpChangeParam {
+ /**
+ * If set to PJ_TRUE, this will restart the transport listener.
+ *
+ * Default : PJ_TRUE
+ */
+ bool restartListener;
+
+ /**
+ * If \a restartListener is set to PJ_TRUE, some delay might be needed
+ * for the listener to be restarted. Use this to set the delay.
+ *
+ * Default : PJSUA_TRANSPORT_RESTART_DELAY_TIME
+ */
+ unsigned restartLisDelay;
+public:
+ /**
+ * Constructor.
+ */
+ IpChangeParam();
+
+ /**
+ * Export to pjsua_ip_change_param.
+ */
+ pjsua_ip_change_param toPj() const;
+
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjsua_ip_change_param ¶m);
+};
+
+/**
+ * Information of Update contact on IP change progress.
+ */
+struct RegProgressParam
+{
+ /**
+ * Indicate if this is a Register or Un-Register message.
+ */
+ bool isRegister;
+
+ /**
+ * SIP status code received.
+ */
+ int code;
+};
+
+/**
+ * Parameter of Endpoint::onIpChangeProgress().
+ */
+struct OnIpChangeProgressParam
+{
+ /**
+ * The IP change progress operation.
+ */
+ pjsua_ip_change_op op;
+
+ /**
+ * The operation progress status.
+ */
+ pj_status_t status;
+
+ /**
+ * Information of the transport id. This is only available when the
+ * operation is PJSUA_IP_CHANGE_OP_RESTART_LIS.
+ */
+ TransportId transportId;
+
+ /**
+ * Information of the account id. This is only available when the
+ * operation is:
+ * - PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP
+ * - PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT
+ * - PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS
+ * - PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS
+ */
+ int accId;
+
+ /**
+ * Information of the call id. This is only available when the operation is
+ * PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS or
+ * PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS
+ */
+ int callId;
+
+ /**
+ * Registration information. This is only available when the operation is
+ * PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT
+ */
+ RegProgressParam regInfo;
+};
+
+
//////////////////////////////////////////////////////////////////////////////
/**
* SIP User Agent related settings.
@@ -391,6 +488,15 @@ struct UaConfig : public PersistentObject
StringVector stunServer;
/**
+ * This specifies if the library should try to do an IPv6 resolution of
+ * the STUN servers if the IPv4 resolution fails. It can be useful
+ * in an IPv6-only environment, including on NAT64.
+ *
+ * Default: FALSE
+ */
+
+ bool stunTryIpv6;
+ /**
* This specifies if the library startup should ignore failure with the
* STUN servers. If this is set to PJ_FALSE, the library will refuse to
* start if it fails to resolve or contact any of the STUN servers.
@@ -1367,6 +1473,31 @@ public:
*/
void resetVideoCodecParam(const string &codec_id) throw(Error);
+ /*************************************************************************
+ * IP Change
+ */
+
+ /**
+ * Inform the stack that IP address change event was detected.
+ * The stack will:
+ * 1. Restart the listener (this step is configurable via
+ * \a IpChangeParam.restartListener).
+ * 2. Shutdown the transport used by account registration (this step is
+ * configurable via \a AccountConfig.ipChangeConfig.shutdownTp).
+ * 3. Update contact URI by sending re-Registration (this step is
+ * configurable via a\ AccountConfig.natConfig.contactRewriteUse and
+ * a\ AccountConfig.natConfig.contactRewriteMethod)
+ * 4. Hangup active calls (this step is configurable via
+ * a\ AccountConfig.ipChangeConfig.hangupCalls) or
+ * continue the call by sending re-INVITE
+ * (configurable via \a AccountConfig.ipChangeConfig.reinviteFlags).
+ *
+ * @param param The IP change parameter, have a look at #IpChangeParam.
+ *
+ * @return PJ_SUCCESS on success, other on error.
+ */
+ void handleIpChange(const IpChangeParam ¶m) throw(Error);
+
public:
/*
* Overrideables callbacks
@@ -1430,6 +1561,16 @@ public:
virtual void onSelectAccount(OnSelectAccountParam &prm)
{ PJ_UNUSED_ARG(prm); }
+ /**
+ * Calling #handleIpChange() may involve different operation. This
+ * callback is called to report the progress of each enabled operation.
+ *
+ * @param prm Callback parameters.
+ *
+ */
+ virtual void onIpChangeProgress(OnIpChangeProgressParam &prm)
+ { PJ_UNUSED_ARG(prm); }
+
private:
static Endpoint *instance_; // static instance
LogWriter *writer; // Custom writer, if any
@@ -1578,6 +1719,11 @@ private:
unsigned media_idx,
pjmedia_srtp_setting *srtp_opt);
+ static void
+ on_ip_change_progress(pjsua_ip_change_op op,
+ pj_status_t status,
+ const pjsua_ip_change_op_info *info);
+
private:
void clearCodecInfoList(CodecInfoVector &codec_list);
void updateCodecInfoList(pjsua_codec_info pj_codec[], unsigned count,
diff --git a/pjsip/include/pjsua2/media.hpp b/pjsip/include/pjsua2/media.hpp
index 42b1a21..3613adb 100644
--- a/pjsip/include/pjsua2/media.hpp
+++ b/pjsip/include/pjsua2/media.hpp
@@ -1,4 +1,4 @@
-/* $Id: media.hpp 5273 2016-04-04 01:44:10Z riza $ */
+/* $Id: media.hpp 5645 2017-09-06 03:44:35Z riza $ */
/*
* Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
*
@@ -108,7 +108,7 @@ struct MediaFormatVideo : public MediaFormat
};
/** Array of MediaFormat */
-typedef std::vector<MediaFormat*> MediaFormatVector;
+typedef std::vector<MediaFormat> MediaFormatVector;
/**
* This structure descibes information about a particular media port that
@@ -1954,11 +1954,6 @@ struct CodecInfo
typedef std::vector<CodecInfo*> CodecInfoVector;
/**
- * Codec parameters, corresponds to pjmedia_codec_param.
- */
-typedef void *CodecParam;
-
-/**
* Structure of codec specific parameters which contains name=value pairs.
* The codec specific parameters are to be used with SDP according to
* the standards (e.g: RFC 3555) in SDP 'a=fmtp' attribute.
@@ -1973,8 +1968,60 @@ typedef struct CodecFmtp
typedef std::vector<CodecFmtp> CodecFmtpVector;
/**
- * Detailed codec attributes used in configuring a codec and in querying
- * the capability of codec factories.
+ * Audio codec parameters info.
+ */
+struct CodecParamInfo
+{
+ unsigned clockRate; /**< Sampling rate in Hz */
+ unsigned channelCnt; /**< Channel count. */
+ unsigned avgBps; /**< Average bandwidth in bits/sec */
+ unsigned maxBps; /**< Maximum bandwidth in bits/sec */
+ unsigned maxRxFrameSize; /**< Maximum frame size */
+ unsigned frameLen; /**< Decoder frame ptime in msec. */
+ unsigned pcmBitsPerSample; /**< Bits/sample in the PCM side */
+ unsigned pt; /**< Payload type. */
+ pjmedia_format_id fmtId; /**< Source format, it's format of
+ encoder input and decoder
+ output. */
+};
+
+/**
+ * Audio codec parameters setting.
+ */
+struct CodecParamSetting
+{
+ unsigned frmPerPkt; /**< Number of frames per packet. */
+ bool vad; /**< Voice Activity Detector. */
+ bool cng; /**< Comfort Noise Generator. */
+ bool penh; /**< Perceptual Enhancement */
+ bool plc; /**< Packet loss concealment */
+ bool reserved; /**< Reserved, must be zero. */
+ CodecFmtpVector encFmtp; /**< Encoder's fmtp params. */
+ CodecFmtpVector decFmtp; /**< Decoder's fmtp params. */
+};
+
+/**
+ * Detailed codec attributes used in configuring an audio codec and in querying
+ * the capability of audio codec factories.
+ *
+ * Please note that codec parameter also contains SDP specific setting,
+ * #setting::decFmtp and #setting::encFmtp, which may need to be set
+ * appropriately based on the effective setting.
+ * See each codec documentation for more detail.
+ */
+struct CodecParam
+{
+ struct CodecParamInfo info;
+ struct CodecParamSetting setting;
+
+ void fromPj(const pjmedia_codec_param ¶m);
+
+ pjmedia_codec_param toPj() const;
+};
+
+/**
+ * Detailed codec attributes used in configuring a video codec and in querying
+ * the capability of video codec factories.
*
* Please note that codec parameter also contains SDP specific setting,
* #decFmtp and #encFmtp, which may need to be set appropriately based on
@@ -2002,14 +2049,6 @@ struct VidCodecParam
void fromPj(const pjmedia_vid_codec_param ¶m);
pjmedia_vid_codec_param toPj() const;
-
-private:
- void setCodecFmtp(const pjmedia_codec_fmtp &in_fmtp,
- CodecFmtpVector &out_fmtp);
-
- void getCodecFmtp(const CodecFmtpVector &in_fmtp,
- pjmedia_codec_fmtp &out_fmtp) const;
-
};
diff --git a/pjsip/src/pjsip-simple/evsub.c b/pjsip/src/pjsip-simple/evsub.c
index 0e775e2..55245c1 100644
--- a/pjsip/src/pjsip-simple/evsub.c
+++ b/pjsip/src/pjsip-simple/evsub.c
@@ -1,4 +1,4 @@
-/* $Id: evsub.c 5397 2016-07-26 02:58:44Z nanang $ */
+/* $Id: evsub.c 5558 2017-02-20 01:29:21Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -509,10 +509,9 @@ static void set_timer( pjsip_evsub *sub, int timer_id,
sub->timer.id = TIMER_TYPE_NONE;
}
- if (timer_id != TIMER_TYPE_NONE) {
+ if (timer_id != TIMER_TYPE_NONE && seconds > 0) {
pj_time_val timeout;
- PJ_ASSERT_ON_FAIL(seconds > 0, return);
PJ_ASSERT_ON_FAIL(timer_id>TIMER_TYPE_NONE && timer_id<TIMER_TYPE_MAX,
return);
@@ -530,6 +529,15 @@ static void set_timer( pjsip_evsub *sub, int timer_id,
/*
+ * Set event subscription UAS timout.
+ */
+PJ_DEF(void) pjsip_evsub_uas_set_timeout(pjsip_evsub *sub, pj_uint32_t seconds)
+{
+ set_timer(sub, TIMER_TYPE_UAS_TIMEOUT, (pj_int32_t)seconds);
+}
+
+
+/*
* Destructor.
*/
static void evsub_on_destroy(void *obj)
diff --git a/pjsip/src/pjsip-simple/evsub_msg.c b/pjsip/src/pjsip-simple/evsub_msg.c
index fc9f093..2718bd1 100644
--- a/pjsip/src/pjsip-simple/evsub_msg.c
+++ b/pjsip/src/pjsip-simple/evsub_msg.c
@@ -1,4 +1,4 @@
-/* $Id: evsub_msg.c 4537 2013-06-19 06:47:43Z riza $ */
+/* $Id: evsub_msg.c 5558 2017-02-20 01:29:21Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -179,7 +179,7 @@ static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr,
}
if (hdr->retry_after >= 0) {
pj_memcpy(p, ";retry-after=", 13);
- p += 9;
+ p += 13;
printed = pj_utoa(hdr->retry_after, p);
p += printed;
}
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index dd26632..1c74c9e 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -1,4 +1,4 @@
-/* $Id: sip_inv.c 5435 2016-08-30 08:40:18Z riza $ */
+/* $Id: sip_inv.c 5641 2017-08-16 04:53:44Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -1237,7 +1237,7 @@ PJ_DEF(pj_status_t) pjsip_inv_verify_request3(pjsip_rx_data *rdata,
if (i != allow->count) {
/* UPDATE is present in Allow */
- rem_option |= PJSIP_INV_SUPPORT_UPDATE;
+ *options |= PJSIP_INV_SUPPORT_UPDATE;
}
}
@@ -2103,10 +2103,14 @@ static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
}
/* Inform application about remote offer. */
- if (mod_inv.cb.on_rx_offer && inv->notify) {
-
- (*mod_inv.cb.on_rx_offer)(inv, sdp_info->sdp);
-
+ if (mod_inv.cb.on_rx_offer2 && inv->notify) {
+ struct pjsip_inv_on_rx_offer_cb_param param;
+
+ param.offer = sdp_info->sdp;
+ param.rdata = rdata;
+ (*mod_inv.cb.on_rx_offer2)(inv, ¶m);
+ } else if (mod_inv.cb.on_rx_offer && inv->notify) {
+ (*mod_inv.cb.on_rx_offer)(inv, sdp_info->sdp);
}
/* application must have supplied an answer at this point. */
@@ -2797,7 +2801,7 @@ PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv,
if (op == PJSIP_REDIRECT_ACCEPT_REPLACE) {
pjsip_to_hdr *to;
pjsip_dialog *dlg = inv->dlg;
- enum { TMP_LEN = 128 };
+ enum { TMP_LEN = PJSIP_MAX_URL_SIZE };
char tmp[TMP_LEN];
int len;
@@ -3275,7 +3279,7 @@ static void inv_respond_incoming_cancel(pjsip_inv_session *inv,
pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS,
pjsip_get_invite_method(), rdata);
- invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
+ invite_tsx = pjsip_tsx_layer_find_tsx2(&key, PJ_TRUE);
if (invite_tsx == NULL) {
@@ -3324,7 +3328,7 @@ static void inv_respond_incoming_cancel(pjsip_inv_session *inv,
}
if (invite_tsx)
- pj_grp_lock_release(invite_tsx->grp_lock);
+ pj_grp_lock_dec_ref(invite_tsx->grp_lock);
}
diff --git a/pjsip/src/pjsip-ua/sip_timer.c b/pjsip/src/pjsip-ua/sip_timer.c
index d26044d..d8b7a1e 100644
--- a/pjsip/src/pjsip-ua/sip_timer.c
+++ b/pjsip/src/pjsip-ua/sip_timer.c
@@ -1,4 +1,4 @@
-/* $Id: sip_timer.c 5488 2016-11-23 01:03:56Z ming $ */
+/* $Id: sip_timer.c 5576 2017-03-31 09:52:12Z riza $ */
/*
* Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -333,6 +333,8 @@ static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
pjsip_tx_data *tdata = NULL;
pj_status_t status;
pj_bool_t as_refresher;
+ int entry_id;
+ char obj_name[PJ_MAX_OBJ_NAME];
pj_assert(inv);
@@ -344,7 +346,10 @@ static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
/* Check our role */
as_refresher =
(inv->timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) ||
- (inv->timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS);
+ (inv->timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS);
+
+ entry_id = entry->id;
+ pj_ansi_strncpy(obj_name, inv->pool->obj_name, PJ_MAX_OBJ_NAME);
/* Do action based on role(refresher or refreshee).
* As refresher:
@@ -353,7 +358,7 @@ static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
* As refreshee:
* - end session if there is no refresh request received.
*/
- if (as_refresher && (entry->id != REFRESHER_EXPIRE_TIMER_ID)) {
+ if (as_refresher && (entry_id != REFRESHER_EXPIRE_TIMER_ID)) {
pj_time_val now;
/* As refresher, reshedule the refresh request on the following:
@@ -414,7 +419,7 @@ static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
}
pj_gettimeofday(&now);
- PJ_LOG(4, (inv->pool->obj_name,
+ PJ_LOG(4, (obj_name,
"Refreshing session after %ds (expiration period=%ds)",
(now.sec-inv->timer->last_refresh.sec),
inv->timer->setting.sess_expires));
@@ -432,7 +437,7 @@ static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
NULL, &tdata);
pj_gettimeofday(&now);
- PJ_LOG(3, (inv->pool->obj_name,
+ PJ_LOG(3, (obj_name,
"No session %s received after %ds "
"(expiration period=%ds), stopping session now!",
(as_refresher?"refresh response":"refresh"),
@@ -451,11 +456,16 @@ static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
status = pjsip_inv_send_msg(inv, tdata);
}
+ /*
+ * At this point, dialog might have already been destroyed,
+ * including its pool used by the invite session.
+ */
+
/* Print error message, if any */
if (status != PJ_SUCCESS) {
- PJ_PERROR(2, (inv->pool->obj_name, status,
+ PJ_PERROR(2, (obj_name, status,
"Error in %s session timer",
- ((as_refresher && entry->id != REFRESHER_EXPIRE_TIMER_ID)?
+ ((as_refresher && entry_id != REFRESHER_EXPIRE_TIMER_ID)?
"refreshing" : "terminating")));
}
}
@@ -970,20 +980,32 @@ PJ_DEF(pj_status_t) pjsip_timer_handle_refresh_error(
(pjsip_status_code)event->body.tsx_state.tsx->status_code;
PJ_LOG(3, (inv->pool->obj_name,
- "Receive error %d for refresh request %.*s/cseq=%d, "
- "stopping session now", st_code,
- event->body.tsx_state.tsx->method.name.slen,
+ "Receive error %d for refresh request %.*s/cseq=%d",
+ st_code, event->body.tsx_state.tsx->method.name.slen,
event->body.tsx_state.tsx->method.name.ptr,
event->body.tsx_state.tsx->cseq));
- status = pjsip_inv_end_session(inv,
+ if (st_code == 503 && PJSIP_SESS_TIMER_RETRY_DELAY >= 0) {
+ /* Retry the refresh after some delay */
+ pj_time_val delay = {PJSIP_SESS_TIMER_RETRY_DELAY, 0};
+
+ PJ_LOG(3, (inv->pool->obj_name, "Scheduling to retry refresh "
+ "request after %d second(s)", delay.sec));
+
+ inv->timer->timer.id = 1;
+ pjsip_endpt_schedule_timer(inv->dlg->endpt,
+ &inv->timer->timer, &delay);
+ } else {
+ PJ_LOG(3, (inv->pool->obj_name, "Ending session now"));
+
+ status = pjsip_inv_end_session(inv,
event->body.tsx_state.tsx->status_code,
pjsip_get_status_text(st_code),
&bye);
- if (status == PJ_SUCCESS && bye)
- status = pjsip_inv_send_msg(inv, bye);
-
+ if (status == PJ_SUCCESS && bye)
+ status = pjsip_inv_send_msg(inv, bye);
+ }
}
}
diff --git a/pjsip/src/pjsip/sip_auth_client.c b/pjsip/src/pjsip/sip_auth_client.c
index ab2d21c..3703339 100644
--- a/pjsip/src/pjsip/sip_auth_client.c
+++ b/pjsip/src/pjsip/sip_auth_client.c
@@ -1,4 +1,4 @@
-/* $Id: sip_auth_client.c 5373 2016-06-30 08:23:08Z ming $ */
+/* $Id: sip_auth_client.c 5575 2017-03-31 06:02:48Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -674,7 +674,6 @@ static pj_status_t auth_respond( pj_pool_t *req_pool,
uri_str.ptr = tmp;
uri_str.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, tmp,sizeof(tmp));
if (uri_str.slen < 1) {
- pj_assert(!"URL is too long!");
return PJSIP_EURITOOLONG;
}
@@ -695,7 +694,6 @@ static pj_status_t auth_respond( pj_pool_t *req_pool,
else if (hdr->type == PJSIP_H_PROXY_AUTHENTICATE)
hauth = pjsip_proxy_authorization_hdr_create(pool);
else {
- pj_assert(!"Invalid response header!");
return PJSIP_EINVALIDHDR;
}
diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c
index 5c86b83..6c5d43a 100644
--- a/pjsip/src/pjsip/sip_dialog.c
+++ b/pjsip/src/pjsip/sip_dialog.c
@@ -1,4 +1,4 @@
-/* $Id: sip_dialog.c 5456 2016-10-07 08:41:55Z ming $ */
+/* $Id: sip_dialog.c 5608 2017-06-20 04:12:09Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -169,23 +169,25 @@ PJ_DEF(pj_status_t) pjsip_dlg_create_uac( pjsip_user_agent *ua,
param = uri->header_param.next;
while (param != &uri->header_param) {
- pjsip_hdr *hdr;
- int c;
+ if (param->value.ptr) {
+ pjsip_hdr *hdr;
+ int c;
- c = param->value.ptr[param->value.slen];
- param->value.ptr[param->value.slen] = '\0';
+ c = param->value.ptr[param->value.slen];
+ param->value.ptr[param->value.slen] = '\0';
- hdr = (pjsip_hdr*)
- pjsip_parse_hdr(dlg->pool, ¶m->name, param->value.ptr,
- param->value.slen, NULL);
+ hdr = (pjsip_hdr*)
+ pjsip_parse_hdr(dlg->pool, ¶m->name, param->value.ptr,
+ param->value.slen, NULL);
- param->value.ptr[param->value.slen] = (char)c;
+ param->value.ptr[param->value.slen] = (char)c;
- if (hdr == NULL) {
- status = PJSIP_EINVALIDURI;
- goto on_error;
+ if (hdr == NULL) {
+ status = PJSIP_EINVALIDURI;
+ goto on_error;
+ }
+ pj_list_push_back(&dlg->inv_hdr, hdr);
}
- pj_list_push_back(&dlg->inv_hdr, hdr);
param = param->next;
}
@@ -324,7 +326,7 @@ pj_status_t create_uas_dialog( pjsip_user_agent *ua,
pjsip_rr_hdr *rr;
pjsip_transaction *tsx = NULL;
pj_str_t tmp;
- enum { TMP_LEN=128};
+ enum { TMP_LEN=PJSIP_MAX_URL_SIZE };
pj_ssize_t len;
pjsip_dialog *dlg;
diff --git a/pjsip/src/pjsip/sip_multipart.c b/pjsip/src/pjsip/sip_multipart.c
index 0952d0a..de8c544 100644
--- a/pjsip/src/pjsip/sip_multipart.c
+++ b/pjsip/src/pjsip/sip_multipart.c
@@ -1,4 +1,4 @@
-/* $Id: sip_multipart.c 5545 2017-01-24 05:59:05Z riza $ */
+/* $Id: sip_multipart.c 5594 2017-05-22 03:53:35Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -45,6 +45,7 @@ struct multipart_data
{
pj_str_t boundary;
pjsip_multipart_part part_head;
+ pj_str_t raw_data;
};
@@ -608,6 +609,12 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool,
body = pjsip_multipart_create(pool, ctype, &boundary);
+ /* Save full raw body */
+ {
+ struct multipart_data *mp = (struct multipart_data*)body->data;
+ pj_strset(&mp->raw_data, buf, len);
+ }
+
for (;;) {
char *start_body, *end_body;
pjsip_multipart_part *part;
@@ -646,13 +653,18 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool,
end_body = curptr;
- /* The newline preceeding the delimiter is conceptually part of
- * the delimiter, so trim it from the body.
+ /* Note that when body is empty, end_body will be equal
+ * to start_body.
*/
- if (*(end_body-1) == '\n')
- --end_body;
- if (*(end_body-1) == '\r')
- --end_body;
+ if (end_body > start_body) {
+ /* The newline preceeding the delimiter is conceptually part of
+ * the delimiter, so trim it from the body.
+ */
+ if (*(end_body-1) == '\n')
+ --end_body;
+ if (*(end_body-1) == '\r')
+ --end_body;
+ }
/* Now that we have determined the part's boundary, parse it
* to get the header and body part of the part.
@@ -667,3 +679,26 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool,
return body;
}
+
+PJ_DEF(pj_status_t) pjsip_multipart_get_raw( pjsip_msg_body *mp,
+ pj_str_t *boundary,
+ pj_str_t *raw_data)
+{
+ struct multipart_data *m_data;
+
+ /* Must specify mandatory params */
+ PJ_ASSERT_RETURN(mp, PJ_EINVAL);
+
+ /* mp must really point to an actual multipart msg body */
+ PJ_ASSERT_RETURN(mp->print_body==&multipart_print_body, PJ_EINVAL);
+
+ m_data = (struct multipart_data*)mp->data;
+
+ if (boundary)
+ *boundary = m_data->boundary;
+
+ if (raw_data)
+ *raw_data = m_data->raw_data;
+
+ return PJ_SUCCESS;
+}
diff --git a/pjsip/src/pjsip/sip_resolve.c b/pjsip/src/pjsip/sip_resolve.c
index 1b6ed79..05fcf39 100644
--- a/pjsip/src/pjsip/sip_resolve.c
+++ b/pjsip/src/pjsip/sip_resolve.c
@@ -1,4 +1,4 @@
-/* $Id: sip_resolve.c 5476 2016-10-31 01:27:34Z ming $ */
+/* $Id: sip_resolve.c 5635 2017-08-01 07:49:34Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -280,11 +280,11 @@ PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,
/* Generate a synthesized IPv6 address, if possible. */
unsigned int count = 1;
pj_addrinfo ai[1];
- pj_status_t status;
+ pj_status_t status2;
- status = pj_getaddrinfo(pj_AF_INET6(),
+ status2 = pj_getaddrinfo(pj_AF_INET6(),
&target->addr.host, &count, ai);
- if (status == PJ_SUCCESS && count > 0 &&
+ if (status2 == PJ_SUCCESS && count > 0 &&
ai[0].ai_addr.addr.sa_family == pj_AF_INET6())
{
pj_sockaddr_init(pj_AF_INET6(),
diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
index 30b7d40..37e9904 100644
--- a/pjsip/src/pjsip/sip_transaction.c
+++ b/pjsip/src/pjsip/sip_transaction.c
@@ -1,4 +1,4 @@
-/* $Id: sip_transaction.c 5244 2016-02-22 13:36:31Z nanang $ */
+/* $Id: sip_transaction.c 5613 2017-07-04 00:13:24Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -288,7 +288,8 @@ static pj_status_t create_tsx_key_2543( pj_pool_t *pool,
host = &rdata->msg_info.via->sent_by.host;
/* Calculate length required. */
- len_required = 9 + /* CSeq number */
+ len_required = method->name.slen + /* Method */
+ 9 + /* CSeq number */
rdata->msg_info.from->tag.slen + /* From tag. */
rdata->msg_info.cid->id.slen + /* Call-ID */
host->slen + /* Via host. */
@@ -641,8 +642,8 @@ PJ_DEF(unsigned) pjsip_tsx_layer_get_tsx_count(void)
/*
* Find a transaction.
*/
-PJ_DEF(pjsip_transaction*) pjsip_tsx_layer_find_tsx( const pj_str_t *key,
- pj_bool_t lock )
+static pjsip_transaction* find_tsx( const pj_str_t *key, pj_bool_t lock,
+ pj_bool_t add_ref )
{
pjsip_transaction *tsx;
pj_uint32_t hval = 0;
@@ -654,7 +655,7 @@ PJ_DEF(pjsip_transaction*) pjsip_tsx_layer_find_tsx( const pj_str_t *key,
/* Prevent the transaction to get deleted before we have chance to lock it.
*/
- if (tsx && lock)
+ if (tsx)
pj_grp_lock_add_ref(tsx->grp_lock);
pj_mutex_unlock(mod_tsx_layer.mutex);
@@ -666,15 +667,32 @@ PJ_DEF(pjsip_transaction*) pjsip_tsx_layer_find_tsx( const pj_str_t *key,
/* Simulate race condition! */
PJ_RACE_ME(5);
- if (tsx && lock) {
- pj_grp_lock_acquire(tsx->grp_lock);
- pj_grp_lock_dec_ref(tsx->grp_lock);
+ if (tsx) {
+ if (lock)
+ pj_grp_lock_acquire(tsx->grp_lock);
+
+ if (!add_ref)
+ pj_grp_lock_dec_ref(tsx->grp_lock);
}
return tsx;
}
+PJ_DEF(pjsip_transaction*) pjsip_tsx_layer_find_tsx( const pj_str_t *key,
+ pj_bool_t lock )
+{
+ return find_tsx(key, lock, PJ_FALSE);
+}
+
+
+PJ_DEF(pjsip_transaction*) pjsip_tsx_layer_find_tsx2( const pj_str_t *key,
+ pj_bool_t add_ref )
+{
+ return find_tsx(key, PJ_FALSE, add_ref);
+}
+
+
/* This module callback is called when module is being loaded by
* endpoint. It does nothing for this module.
*/
@@ -1230,7 +1248,29 @@ static void tsx_set_state( pjsip_transaction *tsx,
pjsip_event e;
PJSIP_EVENT_INIT_TSX_STATE(e, tsx, event_src_type, event_src,
prev_state);
+
+ /* For timer event, release lock to avoid deadlock.
+ * This should be safe because:
+ * 1. The tsx state just switches to TERMINATED or DESTROYED.
+ * 2. There should be no other processing taking place. All other
+ * events, such as the ones handled by tsx_on_state_terminated()
+ * should be ignored.
+ * 3. tsx_shutdown() hasn't been called.
+ * Refer to ticket #2001 (https://trac.pjsip.org/repos/ticket/2001).
+ */
+ if (event_src_type == PJSIP_EVENT_TIMER &&
+ (pj_timer_entry *)event_src == &tsx->timeout_timer)
+ {
+ pj_grp_lock_release(tsx->grp_lock);
+ }
+
(*tsx->tsx_user->on_tsx_state)(tsx, &e);
+
+ if (event_src_type == PJSIP_EVENT_TIMER &&
+ (pj_timer_entry *)event_src == &tsx->timeout_timer)
+ {
+ pj_grp_lock_acquire(tsx->grp_lock);
+ }
}
@@ -1808,8 +1848,12 @@ static void send_msg_callback( pjsip_send_state *send_state,
{
*cont = PJ_FALSE;
- /* Decrease pending send counter */
- pj_grp_lock_dec_ref(tsx->grp_lock);
+ /* Decrease pending send counter, but only if the transaction layer
+ * hasn't been shutdown.
+ */
+ if (mod_tsx_layer.mod.id >= 0)
+ pj_grp_lock_dec_ref(tsx->grp_lock);
+
return;
}
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
index f4e6bbe..9efa4ee 100644
--- a/pjsip/src/pjsip/sip_transport.c
+++ b/pjsip/src/pjsip/sip_transport.c
@@ -1,4 +1,4 @@
-/* $Id: sip_transport.c 5400 2016-07-28 03:17:04Z nanang $ */
+/* $Id: sip_transport.c 5564 2017-03-08 04:33:47Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -253,6 +253,7 @@ PJ_DEF(pj_status_t) pjsip_transport_register_type( unsigned tp_flag,
int *p_tp_type)
{
unsigned i;
+ pjsip_transport_type_e parent = 0;
PJ_ASSERT_RETURN(tp_flag && tp_name && def_port, PJ_EINVAL);
PJ_ASSERT_RETURN(pj_ansi_strlen(tp_name) <
@@ -260,6 +261,11 @@ PJ_DEF(pj_status_t) pjsip_transport_register_type( unsigned tp_flag,
PJ_ENAMETOOLONG);
for (i=1; i<PJ_ARRAY_SIZE(transport_names); ++i) {
+ if (tp_flag & PJSIP_TRANSPORT_IPV6 &&
+ pj_stricmp2(&transport_names[i].name, tp_name) == 0)
+ {
+ parent = transport_names[i].type;
+ }
if (transport_names[i].type == 0)
break;
}
@@ -267,14 +273,19 @@ PJ_DEF(pj_status_t) pjsip_transport_register_type( unsigned tp_flag,
if (i == PJ_ARRAY_SIZE(transport_names))
return PJ_ETOOMANY;
- transport_names[i].type = (pjsip_transport_type_e)i;
+ if (tp_flag & PJSIP_TRANSPORT_IPV6 && parent) {
+ transport_names[i].type = parent | PJSIP_TRANSPORT_IPV6;
+ } else {
+ transport_names[i].type = (pjsip_transport_type_e)i;
+ }
+
transport_names[i].port = (pj_uint16_t)def_port;
pj_ansi_strcpy(transport_names[i].name_buf, tp_name);
transport_names[i].name = pj_str(transport_names[i].name_buf);
transport_names[i].flag = tp_flag;
if (p_tp_type)
- *p_tp_type = i;
+ *p_tp_type = transport_names[i].type;
return PJ_SUCCESS;
}
@@ -422,7 +433,8 @@ PJ_DEF(pj_status_t) pjsip_tx_data_create( pjsip_tpmgr *mgr,
tdata = PJ_POOL_ZALLOC_T(pool, pjsip_tx_data);
tdata->pool = pool;
tdata->mgr = mgr;
- pj_memcpy(tdata->obj_name, pool->obj_name, PJ_MAX_OBJ_NAME);
+ pj_ansi_snprintf(tdata->obj_name, sizeof(tdata->obj_name), "tdta%p", tdata);
+ pj_memcpy(pool->obj_name, tdata->obj_name, sizeof(pool->obj_name));
status = pj_atomic_create(tdata->pool, 0, &tdata->ref_cnt);
if (status != PJ_SUCCESS) {
@@ -1163,11 +1175,22 @@ static pj_status_t destroy_transport( pjsip_tpmgr *mgr,
*/
PJ_DEF(pj_status_t) pjsip_transport_shutdown(pjsip_transport *tp)
{
+ return pjsip_transport_shutdown2(tp, PJ_FALSE);
+}
+
+
+/*
+ * Start shutdown procedure for this transport.
+ */
+PJ_DEF(pj_status_t) pjsip_transport_shutdown2(pjsip_transport *tp,
+ pj_bool_t force)
+{
pjsip_tpmgr *mgr;
pj_status_t status;
pjsip_tp_state_callback state_cb;
- TRACE_((THIS_FILE, "Transport %s shutting down", tp->obj_name));
+ PJ_LOG(4, (THIS_FILE, "Transport %s shutting down, force=%d",
+ tp->obj_name, force));
pj_lock_acquire(tp->lock);
@@ -1187,19 +1210,20 @@ PJ_DEF(pj_status_t) pjsip_transport_shutdown(pjsip_transport *tp)
if (tp->do_shutdown)
status = tp->do_shutdown(tp);
+ if (status == PJ_SUCCESS)
+ tp->is_shutdown = PJ_TRUE;
+
/* Notify application of transport shutdown */
state_cb = pjsip_tpmgr_get_state_cb(tp->tpmgr);
if (state_cb) {
pjsip_transport_state_info state_info;
pj_bzero(&state_info, sizeof(state_info));
- state_info.status = status;
- (*state_cb)(tp, PJSIP_TP_STATE_SHUTDOWN, &state_info);
+ state_info.status = PJ_ECANCELLED;
+ (*state_cb)(tp, (force? PJSIP_TP_STATE_DISCONNECTED:
+ PJSIP_TP_STATE_SHUTDOWN), &state_info);
}
- if (status == PJ_SUCCESS)
- tp->is_shutdown = PJ_TRUE;
-
/* If transport reference count is zero, start timer count-down */
if (pj_atomic_get(tp->ref_cnt) == 0) {
pjsip_transport_add_ref(tp);
diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c
index 704e936..e1a108f 100644
--- a/pjsip/src/pjsip/sip_transport_tcp.c
+++ b/pjsip/src/pjsip/sip_transport_tcp.c
@@ -1,4 +1,4 @@
-/* $Id: sip_transport_tcp.c 5534 2017-01-19 07:41:25Z nanang $ */
+/* $Id: sip_transport_tcp.c 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -61,6 +61,8 @@ struct tcp_listener
pj_qos_type qos_type;
pj_qos_params qos_params;
pj_sockopt_params sockopt_params;
+ pj_bool_t reuse_addr;
+ unsigned async_cnt;
/* Group lock to be used by TCP listener and ioqueue key */
pj_grp_lock_t *grp_lock;
@@ -241,140 +243,52 @@ PJ_DEF(void) pjsip_tcp_transport_cfg_default(pjsip_tcp_transport_cfg *cfg,
* The TCP listener/transport factory.
*/
-/*
- * This is the public API to create, initialize, register, and start the
- * TCP listener.
- */
-PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
- pjsip_endpoint *endpt,
- const pjsip_tcp_transport_cfg *cfg,
- pjsip_tpfactory **p_factory
- )
+static void update_bound_addr(struct tcp_listener *listener,
+ const pj_sockaddr *local)
{
- enum { INFO_LEN = 100 };
- char local_addr[PJ_INET6_ADDRSTRLEN+10];
- pj_pool_t *pool;
- pj_sock_t sock = PJ_INVALID_SOCKET;
- struct tcp_listener *listener;
- pj_activesock_cfg asock_cfg;
- pj_activesock_cb listener_cb;
- pj_sockaddr *listener_addr;
- int addr_len;
- pj_bool_t has_listener = PJ_FALSE;
- pj_status_t status;
+ pj_sockaddr *listener_addr = &listener->factory.local_addr;
+ int af = pjsip_transport_type_get_af(listener->factory.type);
- /* Sanity check */
- PJ_ASSERT_RETURN(endpt && cfg->async_cnt, PJ_EINVAL);
+ /* Bind address may be different than factory.local_addr because
+ * factory.local_addr will be resolved.
+ */
+ if (local) {
+ pj_sockaddr_cp(&listener->bound_addr, local);
+ }
+ else {
+ pj_sockaddr_init(af, &listener->bound_addr, NULL, 0);
+ }
+ pj_sockaddr_cp(listener_addr, &listener->bound_addr);
+}
- /* Verify that address given in a_name (if any) is valid */
- if (cfg->addr_name.host.slen) {
+static pj_status_t update_factory_addr(struct tcp_listener *listener,
+ const pjsip_host_port *addr_name)
+{
+ pj_status_t status = PJ_SUCCESS;
+ pj_sockaddr *listener_addr = &listener->factory.local_addr;
+
+ /* If published host/IP is specified, then use that address as the
+ * listener advertised address.
+ */
+ if (addr_name && addr_name->host.slen) {
pj_sockaddr tmp;
+ int af = pjsip_transport_type_get_af(listener->factory.type);
- status = pj_sockaddr_init(cfg->af, &tmp, &cfg->addr_name.host,
- (pj_uint16_t)cfg->addr_name.port);
+ /* Verify that address given in a_name (if any) is valid */
+ status = pj_sockaddr_init(af, &tmp, &addr_name->host,
+ (pj_uint16_t)addr_name->port);
if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
- (cfg->af==pj_AF_INET() &&
- tmp.ipv4.sin_addr.s_addr==PJ_INADDR_NONE))
+ (af == pj_AF_INET() && tmp.ipv4.sin_addr.s_addr == PJ_INADDR_NONE))
{
/* Invalid address */
return PJ_EINVAL;
}
- }
-
- pool = pjsip_endpt_create_pool(endpt, "tcptp", POOL_LIS_INIT,
- POOL_LIS_INC);
- PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
-
-
- listener = PJ_POOL_ZALLOC_T(pool, struct tcp_listener);
- listener->factory.pool = pool;
- listener->factory.type = cfg->af==pj_AF_INET() ? PJSIP_TRANSPORT_TCP :
- PJSIP_TRANSPORT_TCP6;
- listener->factory.type_name = (char*)
- pjsip_transport_get_type_name(listener->factory.type);
- listener->factory.flag =
- pjsip_transport_get_flag_from_type(listener->factory.type);
- listener->qos_type = cfg->qos_type;
- pj_memcpy(&listener->qos_params, &cfg->qos_params,
- sizeof(cfg->qos_params));
- pj_memcpy(&listener->sockopt_params, &cfg->sockopt_params,
- sizeof(cfg->sockopt_params));
-
- pj_ansi_strcpy(listener->factory.obj_name, "tcptp");
- if (listener->factory.type==PJSIP_TRANSPORT_TCP6)
- pj_ansi_strcat(listener->factory.obj_name, "6");
-
- status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name,
- &listener->factory.lock);
- if (status != PJ_SUCCESS)
- goto on_error;
-
-#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
- PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)
-
- /* Create socket */
- status = pj_sock_socket(cfg->af, pj_SOCK_STREAM(), 0, &sock);
- if (status != PJ_SUCCESS)
- goto on_error;
-
- /* Apply QoS, if specified */
- status = pj_sock_apply_qos2(sock, cfg->qos_type, &cfg->qos_params,
- 2, listener->factory.obj_name,
- "SIP TCP listener socket");
-
- /* Apply SO_REUSEADDR */
- if (cfg->reuse_addr) {
- int enabled = 1;
- status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(),
- &enabled, sizeof(enabled));
- if (status != PJ_SUCCESS) {
- PJ_PERROR(4,(listener->factory.obj_name, status,
- "Warning: error applying SO_REUSEADDR"));
- }
- }
- /* Apply socket options, if specified */
- if (cfg->sockopt_params.cnt)
- status = pj_sock_setsockopt_params(sock, &cfg->sockopt_params);
-
-#else
- PJ_UNUSED_ARG(addr_len);
-#endif
-
- /* Bind address may be different than factory.local_addr because
- * factory.local_addr will be resolved below.
- */
- pj_sockaddr_cp(&listener->bound_addr, &cfg->bind_addr);
-
- /* Bind socket */
- listener_addr = &listener->factory.local_addr;
- pj_sockaddr_cp(listener_addr, &cfg->bind_addr);
-
-#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
- PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)
-
- status = pj_sock_bind(sock, listener_addr,
- pj_sockaddr_get_len(listener_addr));
- if (status != PJ_SUCCESS)
- goto on_error;
-
- /* Retrieve the bound address */
- addr_len = pj_sockaddr_get_len(listener_addr);
- status = pj_sock_getsockname(sock, listener_addr, &addr_len);
- if (status != PJ_SUCCESS)
- goto on_error;
-
-#endif
-
- /* If published host/IP is specified, then use that address as the
- * listener advertised address.
- */
- if (cfg->addr_name.host.slen) {
/* Copy the address */
- listener->factory.addr_name = cfg->addr_name;
- pj_strdup(listener->factory.pool, &listener->factory.addr_name.host,
- &cfg->addr_name.host);
- listener->factory.addr_name.port = cfg->addr_name.port;
+ listener->factory.addr_name = *addr_name;
+ pj_strdup(listener->factory.pool, &listener->factory.addr_name.host,
+ &addr_name->host);
+ listener->factory.addr_name.port = addr_name->port;
} else {
/* No published address is given, use the bound address */
@@ -386,16 +300,16 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
pj_sockaddr hostip;
status = pj_gethostip(listener->bound_addr.addr.sa_family,
- &hostip);
+ &hostip);
if (status != PJ_SUCCESS)
- goto on_error;
+ return status;
pj_sockaddr_copy_addr(listener_addr, &hostip);
}
/* Save the address name */
- sockaddr_to_host_port(listener->factory.pool,
- &listener->factory.addr_name,
+ sockaddr_to_host_port(listener->factory.pool,
+ &listener->factory.addr_name,
listener_addr);
}
@@ -404,100 +318,129 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
}
- pj_ansi_snprintf(listener->factory.obj_name,
+ pj_ansi_snprintf(listener->factory.obj_name,
sizeof(listener->factory.obj_name),
- "tcptp:%d", listener->factory.addr_name.port);
+ "tcptp:%d", listener->factory.addr_name.port);
+ return status;
+}
+static void update_transport_info(struct tcp_listener *listener)
+{
+ enum { INFO_LEN = 100 };
+ char local_addr[PJ_INET6_ADDRSTRLEN + 10];
+ pj_sockaddr *listener_addr = &listener->factory.local_addr;
-#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
- PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)
+ /* Set transport info. */
+ if (listener->factory.info == NULL) {
+ listener->factory.info = (char*)pj_pool_alloc(listener->factory.pool,
+ INFO_LEN);
+ }
+ pj_sockaddr_print(listener_addr, local_addr, sizeof(local_addr), 3);
+ pj_ansi_snprintf(
+ listener->factory.info, INFO_LEN, "tcp %s [published as %.*s:%d]",
+ local_addr,
+ (int)listener->factory.addr_name.host.slen,
+ listener->factory.addr_name.host.ptr,
+ listener->factory.addr_name.port);
- /* Start listening to the address */
- status = pj_sock_listen(sock, PJSIP_TCP_TRANSPORT_BACKLOG);
- if (status != PJ_SUCCESS)
- goto on_error;
+ if (listener->asock) {
+ PJ_LOG(4, (listener->factory.obj_name,
+ "SIP TCP listener ready for incoming connections at %.*s:%d",
+ (int)listener->factory.addr_name.host.slen,
+ listener->factory.addr_name.host.ptr,
+ listener->factory.addr_name.port));
+ } else {
+ PJ_LOG(4, (listener->factory.obj_name, "SIP TCP is ready "
+ "(client only)"));
+ }
+}
+/*
+ * This is the public API to create, initialize, register, and start the
+ * TCP listener.
+ */
+PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
+ pjsip_endpoint *endpt,
+ const pjsip_tcp_transport_cfg *cfg,
+ pjsip_tpfactory **p_factory
+ )
+{
+ pj_pool_t *pool;
+ struct tcp_listener *listener;
+ pj_status_t status;
- /* Create active socket */
- pj_activesock_cfg_default(&asock_cfg);
- if (cfg->async_cnt > MAX_ASYNC_CNT)
- asock_cfg.async_cnt = MAX_ASYNC_CNT;
- else
- asock_cfg.async_cnt = cfg->async_cnt;
+ /* Sanity check */
+ PJ_ASSERT_RETURN(endpt && cfg->async_cnt, PJ_EINVAL);
-#endif
+ pool = pjsip_endpt_create_pool(endpt, "tcptp", POOL_LIS_INIT,
+ POOL_LIS_INC);
+ PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
+
+
+ listener = PJ_POOL_ZALLOC_T(pool, struct tcp_listener);
+ listener->factory.pool = pool;
+ listener->factory.type = cfg->af==pj_AF_INET() ? PJSIP_TRANSPORT_TCP :
+ PJSIP_TRANSPORT_TCP6;
+ listener->factory.type_name = (char*)
+ pjsip_transport_get_type_name(listener->factory.type);
+ listener->factory.flag =
+ pjsip_transport_get_flag_from_type(listener->factory.type);
+ listener->qos_type = cfg->qos_type;
+ listener->reuse_addr = cfg->reuse_addr;
+ listener->async_cnt = cfg->async_cnt;
+ pj_memcpy(&listener->qos_params, &cfg->qos_params,
+ sizeof(cfg->qos_params));
+ pj_memcpy(&listener->sockopt_params, &cfg->sockopt_params,
+ sizeof(cfg->sockopt_params));
+
+ pj_ansi_strcpy(listener->factory.obj_name, "tcptp");
+ if (listener->factory.type==PJSIP_TRANSPORT_TCP6)
+ pj_ansi_strcat(listener->factory.obj_name, "6");
+
+ status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name,
+ &listener->factory.lock);
+ if (status != PJ_SUCCESS)
+ goto on_error;
/* Create group lock */
status = pj_grp_lock_create(pool, NULL, &listener->grp_lock);
if (status != PJ_SUCCESS)
- return status;
+ goto on_error;
pj_grp_lock_add_ref(listener->grp_lock);
pj_grp_lock_add_handler(listener->grp_lock, pool, listener,
&lis_on_destroy);
- asock_cfg.grp_lock = listener->grp_lock;
-
- pj_bzero(&listener_cb, sizeof(listener_cb));
- listener_cb.on_accept_complete = &on_accept_complete;
-
-#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
- PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)
-
- status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), &asock_cfg,
- pjsip_endpt_get_ioqueue(endpt),
- &listener_cb, listener,
- &listener->asock);
-
-#endif
-
/* Register to transport manager */
listener->endpt = endpt;
listener->tpmgr = pjsip_endpt_get_tpmgr(endpt);
listener->factory.create_transport = lis_create_transport;
- listener->factory.destroy = lis_destroy;
- listener->is_registered = PJ_TRUE;
- status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
- &listener->factory);
- if (status != PJ_SUCCESS) {
- listener->is_registered = PJ_FALSE;
- goto on_error;
- }
+ listener->factory.destroy = lis_destroy;
#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
- PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)
+ PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)
+ /* Start listener. */
+ status = pjsip_tcp_transport_lis_start(&listener->factory, &cfg->bind_addr,
+ &cfg->addr_name);
+ if (status != PJ_SUCCESS)
+ goto on_error;
- /* Start pending accept() operations */
- status = pj_activesock_start_accept(listener->asock, pool);
+#else
+ update_bound_addr(listener, &cfg->bind_addr);
+ status = update_factory_addr(listener, &cfg->addr_name);
if (status != PJ_SUCCESS)
goto on_error;
-
- has_listener = PJ_TRUE;
+ /* Set transport info. */
+ update_transport_info(listener);
#endif
- /* Set transport info. */
- if (listener->factory.info == NULL) {
- listener->factory.info = (char*) pj_pool_alloc(listener->factory.pool,
- INFO_LEN);
- }
- pj_sockaddr_print(listener_addr, local_addr, sizeof(local_addr), 3);
- pj_ansi_snprintf(
- listener->factory.info, INFO_LEN, "tcp %s [published as %.*s:%d]",
- local_addr,
- (int)listener->factory.addr_name.host.slen,
- listener->factory.addr_name.host.ptr,
- listener->factory.addr_name.port);
-
- if (has_listener) {
- PJ_LOG(4,(listener->factory.obj_name,
- "SIP TCP listener ready for incoming connections at %.*s:%d",
- (int)listener->factory.addr_name.host.slen,
- listener->factory.addr_name.host.ptr,
- listener->factory.addr_name.port));
- } else {
- PJ_LOG(4,(listener->factory.obj_name, "SIP TCP is ready "
- "(client only)"));
+ listener->is_registered = PJ_TRUE;
+ status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
+ &listener->factory);
+ if (status != PJ_SUCCESS) {
+ listener->is_registered = PJ_FALSE;
+ goto on_error;
}
/* Return the pointer to user */
@@ -506,8 +449,6 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
return PJ_SUCCESS;
on_error:
- if (listener->asock==NULL && sock!=PJ_INVALID_SOCKET)
- pj_sock_close(sock);
lis_destroy(&listener->factory);
return status;
}
@@ -571,12 +512,9 @@ static void lis_on_destroy(void *arg)
}
}
-
-/* This callback is called by transport manager to destroy listener */
-static pj_status_t lis_destroy(pjsip_tpfactory *factory)
+/* This will close the listener. */
+static void lis_close(struct tcp_listener *listener)
{
- struct tcp_listener *listener = (struct tcp_listener *)factory;
-
if (listener->is_registered) {
pjsip_tpmgr_unregister_tpfactory(listener->tpmgr, &listener->factory);
listener->is_registered = PJ_FALSE;
@@ -586,6 +524,14 @@ static pj_status_t lis_destroy(pjsip_tpfactory *factory)
pj_activesock_close(listener->asock);
listener->asock = NULL;
}
+}
+
+/* This callback is called by transport manager to destroy listener */
+static pj_status_t lis_destroy(pjsip_tpfactory *factory)
+{
+ struct tcp_listener *listener = (struct tcp_listener *)factory;
+
+ lis_close(listener);
if (listener->grp_lock) {
pj_grp_lock_t *grp_lock = listener->grp_lock;
@@ -1637,5 +1583,135 @@ PJ_DEF(pj_sock_t) pjsip_tcp_transport_get_socket(pjsip_transport *transport)
}
+PJ_DEF(pj_status_t) pjsip_tcp_transport_lis_start(pjsip_tpfactory *factory,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name)
+{
+ pj_activesock_cfg asock_cfg;
+ pj_activesock_cb listener_cb;
+ pj_sock_t sock = PJ_INVALID_SOCKET;
+ int addr_len, af;
+ struct tcp_listener *listener = (struct tcp_listener *)factory;
+ pj_sockaddr *listener_addr = &factory->local_addr;
+ pj_status_t status = PJ_SUCCESS;
+
+ /* Nothing to be done, if listener already started. */
+ if (listener->asock)
+ return PJ_SUCCESS;
+
+ update_bound_addr(listener, local);
+
+ addr_len = pj_sockaddr_get_len(listener_addr);
+ af = pjsip_transport_type_get_af(listener->factory.type);
+
+ /* Create socket */
+ status = pj_sock_socket(af, pj_SOCK_STREAM(), 0, &sock);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Apply QoS, if specified */
+ status = pj_sock_apply_qos2(sock, listener->qos_type,
+ &listener->qos_params, 2,
+ listener->factory.obj_name,
+ "SIP TCP listener socket");
+
+ /* Apply SO_REUSEADDR */
+ if (listener->reuse_addr) {
+ int enabled = 1;
+ status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(),
+ &enabled, sizeof(enabled));
+ if (status != PJ_SUCCESS) {
+ PJ_LOG(1, ("TRACE", "fail set reuseaddr"));
+ PJ_PERROR(4, (listener->factory.obj_name, status,
+ "Warning: error applying SO_REUSEADDR"));
+ }
+ }
+
+ /* Apply socket options, if specified */
+ if (listener->sockopt_params.cnt)
+ status = pj_sock_setsockopt_params(sock, &listener->sockopt_params);
+
+ status = pj_sock_bind(sock, listener_addr, addr_len);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Retrieve the bound address */
+ status = pj_sock_getsockname(sock, &listener->factory.local_addr,
+ &addr_len);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ status = update_factory_addr(listener, a_name);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Start listening to the address */
+ status = pj_sock_listen(sock, PJSIP_TCP_TRANSPORT_BACKLOG);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+
+ /* Create active socket */
+ pj_activesock_cfg_default(&asock_cfg);
+ if (listener->async_cnt > MAX_ASYNC_CNT)
+ asock_cfg.async_cnt = MAX_ASYNC_CNT;
+ else
+ asock_cfg.async_cnt = listener->async_cnt;
+
+ asock_cfg.grp_lock = listener->grp_lock;
+ pj_bzero(&listener_cb, sizeof(listener_cb));
+ listener_cb.on_accept_complete = &on_accept_complete;
+
+ status = pj_activesock_create(listener->factory.pool, sock,
+ pj_SOCK_STREAM(), &asock_cfg,
+ pjsip_endpt_get_ioqueue(listener->endpt),
+ &listener_cb, listener,
+ &listener->asock);
+
+ /* Start pending accept() operations */
+ status = pj_activesock_start_accept(listener->asock,
+ listener->factory.pool);
+
+ update_transport_info(listener);
+
+ return status;
+
+on_error:
+ if (listener->asock == NULL && sock != PJ_INVALID_SOCKET)
+ pj_sock_close(sock);
+
+ return status;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_tcp_transport_restart(pjsip_tpfactory *factory,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name)
+{
+ pj_status_t status = PJ_SUCCESS;
+ struct tcp_listener *listener = (struct tcp_listener *)factory;
+
+ lis_close(listener);
+
+ status = pjsip_tcp_transport_lis_start(factory, local, a_name);
+ if (status != PJ_SUCCESS) {
+ tcp_perror(listener->factory.obj_name,
+ "Unable to start listener after closing it", status);
+
+ return status;
+ }
+
+ status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
+ &listener->factory);
+ if (status != PJ_SUCCESS) {
+ tcp_perror(listener->factory.obj_name,
+ "Unable to register the transport listener", status);
+ } else {
+ listener->is_registered = PJ_TRUE;
+ }
+
+ return status;
+}
+
#endif /* PJ_HAS_TCP */
diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c
index b798d05..624404d 100644
--- a/pjsip/src/pjsip/sip_transport_tls.c
+++ b/pjsip/src/pjsip/sip_transport_tls.c
@@ -1,4 +1,4 @@
-/* $Id: sip_transport_tls.c 5534 2017-01-19 07:41:25Z nanang $ */
+/* $Id: sip_transport_tls.c 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -57,7 +57,8 @@ struct tls_listener
pj_ssl_sock_t *ssock;
pj_sockaddr bound_addr;
pj_ssl_cert_t *cert;
- pjsip_tls_setting tls_setting;
+ pjsip_tls_setting tls_setting;
+ unsigned async_cnt;
/* Group lock to be used by TLS transport and ioqueue key */
pj_grp_lock_t *grp_lock;
@@ -282,64 +283,260 @@ static void tls_init_shutdown(struct tls_transport *tls, pj_status_t status)
* The TLS listener/transport factory.
*/
+
+static void set_ssock_param(pj_ssl_sock_param *ssock_param,
+ struct tls_listener *listener)
+{
+ int af, sip_ssl_method;
+ pj_uint32_t sip_ssl_proto;
+
+ /* Build SSL socket param */
+ af = pjsip_transport_type_get_af(listener->factory.type);
+ pj_ssl_sock_param_default(ssock_param);
+ ssock_param->sock_af = af;
+ ssock_param->cb.on_accept_complete = &on_accept_complete;
+ ssock_param->async_cnt = listener->async_cnt;
+ ssock_param->ioqueue = pjsip_endpt_get_ioqueue(listener->endpt);
+ ssock_param->timer_heap = pjsip_endpt_get_timer_heap(listener->endpt);
+ ssock_param->require_client_cert = listener->tls_setting.require_client_cert;
+ ssock_param->timeout = listener->tls_setting.timeout;
+ ssock_param->user_data = listener;
+ ssock_param->verify_peer = PJ_FALSE; /* avoid SSL socket closing the socket
+ * due to verification error */
+ if (ssock_param->send_buffer_size < PJSIP_MAX_PKT_LEN)
+ ssock_param->send_buffer_size = PJSIP_MAX_PKT_LEN;
+ if (ssock_param->read_buffer_size < PJSIP_MAX_PKT_LEN)
+ ssock_param->read_buffer_size = PJSIP_MAX_PKT_LEN;
+ ssock_param->ciphers_num = listener->tls_setting.ciphers_num;
+ ssock_param->ciphers = listener->tls_setting.ciphers;
+ ssock_param->curves_num = listener->tls_setting.curves_num;
+ ssock_param->curves = listener->tls_setting.curves;
+ ssock_param->sigalgs = listener->tls_setting.sigalgs;
+ ssock_param->entropy_type = listener->tls_setting.entropy_type;
+ ssock_param->entropy_path = listener->tls_setting.entropy_path;
+ ssock_param->reuse_addr = listener->tls_setting.reuse_addr;
+ ssock_param->qos_type = listener->tls_setting.qos_type;
+ ssock_param->qos_ignore_error = listener->tls_setting.qos_ignore_error;
+ pj_memcpy(&ssock_param->qos_params, &listener->tls_setting.qos_params,
+ sizeof(ssock_param->qos_params));
+
+ ssock_param->sockopt_ignore_error =
+ listener->tls_setting.sockopt_ignore_error;
+ /* Copy the sockopt */
+ pj_memcpy(&ssock_param->sockopt_params,
+ &listener->tls_setting.sockopt_params,
+ sizeof(listener->tls_setting.sockopt_params));
+
+ sip_ssl_method = listener->tls_setting.method;
+ sip_ssl_proto = listener->tls_setting.proto;
+ ssock_param->proto = ssl_get_proto(sip_ssl_method, sip_ssl_proto);
+}
+
+static void update_bound_addr(struct tls_listener *listener,
+ const pj_sockaddr *local)
+{
+ pj_sockaddr *listener_addr = &listener->factory.local_addr;
+ int af = pjsip_transport_type_get_af(listener->factory.type);
+
+ /* Bind address may be different than factory.local_addr because
+ * factory.local_addr will be resolved.
+ */
+ if (local) {
+ pj_sockaddr_cp(&listener->bound_addr, local);
+ } else {
+ pj_sockaddr_init(af, &listener->bound_addr, NULL, 0);
+ }
+ pj_sockaddr_cp(listener_addr, &listener->bound_addr);
+}
+
+static pj_status_t update_factory_addr(struct tls_listener *listener,
+ const pjsip_host_port *addr_name)
+{
+ pj_status_t status = PJ_SUCCESS;
+ pj_sockaddr *listener_addr = &listener->factory.local_addr;
+
+ if (addr_name && addr_name->host.slen) {
+ pj_sockaddr tmp;
+ int af = pjsip_transport_type_get_af(listener->factory.type);
+
+ status = pj_sockaddr_init(af, &tmp, &addr_name->host,
+ (pj_uint16_t)addr_name->port);
+ if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
+ (af == pj_AF_INET() && tmp.ipv4.sin_addr.s_addr == PJ_INADDR_NONE))
+ {
+ /* Invalid address */
+ return PJ_EINVAL;
+ }
+
+ /* Copy the address */
+ listener->factory.addr_name = *addr_name;
+ pj_strdup(listener->factory.pool, &listener->factory.addr_name.host,
+ &addr_name->host);
+ listener->factory.addr_name.port = addr_name->port;
+
+ }
+ else {
+ /* No published address is given, use the bound address */
+
+ /* If the address returns 0.0.0.0, use the default
+ * interface address as the transport's address.
+ */
+ if (!pj_sockaddr_has_addr(listener_addr)) {
+ pj_sockaddr hostip;
+
+ status = pj_gethostip(listener->bound_addr.addr.sa_family,
+ &hostip);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ pj_sockaddr_copy_addr(listener_addr, &hostip);
+ }
+
+ /* Save the address name */
+ sockaddr_to_host_port(listener->factory.pool,
+ &listener->factory.addr_name, listener_addr);
+ }
+
+ /* If port is zero, get the bound port */
+ if (listener->factory.addr_name.port == 0) {
+ listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
+ }
+
+ pj_ansi_snprintf(listener->factory.obj_name,
+ sizeof(listener->factory.obj_name),
+ "tlstp:%d", listener->factory.addr_name.port);
+ return status;
+}
+
+static void update_transport_info(struct tls_listener *listener)
+{
+ enum { INFO_LEN = 100 };
+ char local_addr[PJ_INET6_ADDRSTRLEN + 10];
+ pj_sockaddr *listener_addr = &listener->factory.local_addr;
+
+ if (listener->factory.info == NULL) {
+ listener->factory.info = (char*)pj_pool_alloc(listener->factory.pool,
+ INFO_LEN);
+ }
+ pj_sockaddr_print(listener_addr, local_addr, sizeof(local_addr), 3);
+ pj_ansi_snprintf(
+ listener->factory.info, INFO_LEN, "tls %s [published as %.*s:%d]",
+ local_addr,
+ (int)listener->factory.addr_name.host.slen,
+ listener->factory.addr_name.host.ptr,
+ listener->factory.addr_name.port);
+
+ if (listener->ssock) {
+ PJ_LOG(4, (listener->factory.obj_name,
+ "SIP TLS listener is ready for incoming connections "
+ "at %.*s:%d",
+ (int)listener->factory.addr_name.host.slen,
+ listener->factory.addr_name.host.ptr,
+ listener->factory.addr_name.port));
+ } else {
+ PJ_LOG(4, (listener->factory.obj_name, "SIP TLS is ready "
+ "(client only)"));
+ }
+}
+
+
/*
* This is the public API to create, initialize, register, and start the
* TLS listener.
*/
-PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
- const pjsip_tls_setting *opt,
- const pj_sockaddr_in *local_in,
- const pjsip_host_port *a_name,
- unsigned async_cnt,
- pjsip_tpfactory **p_factory)
+PJ_DEF(pj_status_t) pjsip_tls_transport_start(pjsip_endpoint *endpt,
+ const pjsip_tls_setting *opt,
+ const pj_sockaddr_in *local_in,
+ const pjsip_host_port *a_name,
+ unsigned async_cnt,
+ pjsip_tpfactory **p_factory)
{
pj_sockaddr local;
if (local_in)
pj_sockaddr_cp(&local, local_in);
- return pjsip_tls_transport_start2(endpt, opt, (local_in? &local : NULL),
- a_name, async_cnt, p_factory);
+ return pjsip_tls_transport_start2(endpt, opt, (local_in ? &local : NULL),
+ a_name, async_cnt, p_factory);
+}
+
+
+PJ_DEF(pj_status_t) pjsip_tls_transport_lis_start(pjsip_tpfactory *factory,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name)
+{
+ pj_status_t status = PJ_SUCCESS;
+ pj_ssl_sock_param ssock_param, newsock_param;
+ struct tls_listener *listener = (struct tls_listener *)factory;
+ pj_sockaddr *listener_addr = &listener->factory.local_addr;
+
+ if (listener->ssock)
+ return PJ_SUCCESS;
+
+ set_ssock_param(&ssock_param, listener);
+ update_bound_addr(listener, local);
+ ssock_param.grp_lock = listener->grp_lock;
+
+ /* Create SSL socket */
+ status = pj_ssl_sock_create(listener->factory.pool, &ssock_param,
+ &listener->ssock);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ if (listener->cert) {
+ status = pj_ssl_sock_set_certificate(listener->ssock,
+ listener->factory.pool, listener->cert);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ /* Start accepting incoming connections. Note that some TLS/SSL
+ * backends may not support for SSL socket server.
+ */
+ pj_memcpy(&newsock_param, &ssock_param, sizeof(newsock_param));
+ newsock_param.async_cnt = 1;
+ newsock_param.cb.on_data_read = &on_data_read;
+ newsock_param.cb.on_data_sent = &on_data_sent;
+ status = pj_ssl_sock_start_accept2(listener->ssock, listener->factory.pool,
+ (pj_sockaddr_t*)listener_addr,
+ pj_sockaddr_get_len((pj_sockaddr_t*)listener_addr),
+ &newsock_param);
+
+ if (status == PJ_SUCCESS || status == PJ_EPENDING) {
+ pj_ssl_sock_info info;
+
+ /* Retrieve the bound address */
+ status = pj_ssl_sock_get_info(listener->ssock, &info);
+ if (status == PJ_SUCCESS)
+ pj_sockaddr_cp(listener_addr, (pj_sockaddr_t*)&info.local_addr);
+
+ }
+ status = update_factory_addr(listener, a_name);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ update_transport_info(listener);
+
+ return status;
}
+
PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt,
const pjsip_tls_setting *opt,
const pj_sockaddr *local,
const pjsip_host_port *a_name,
unsigned async_cnt,
pjsip_tpfactory **p_factory)
-{
- enum { INFO_LEN = 100 };
- char local_addr[PJ_INET6_ADDRSTRLEN+10];
+{
pj_pool_t *pool;
- pj_bool_t is_ipv6;
- int af, sip_ssl_method;
- pj_uint32_t sip_ssl_proto;
- struct tls_listener *listener;
- pj_ssl_sock_param ssock_param, newsock_param;
- pj_sockaddr *listener_addr;
- pj_bool_t has_listener;
+ pj_bool_t is_ipv6;
+ struct tls_listener *listener;
pj_status_t status;
/* Sanity check */
PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL);
- is_ipv6 = (local && local->addr.sa_family == pj_AF_INET6());
- af = is_ipv6 ? pj_AF_INET6() : pj_AF_INET();
-
- /* Verify that address given in a_name (if any) is valid */
- if (a_name && a_name->host.slen) {
- pj_sockaddr tmp;
-
- status = pj_sockaddr_init(af, &tmp, &a_name->host,
- (pj_uint16_t)a_name->port);
- if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
- (!is_ipv6 && tmp.ipv4.sin_addr.s_addr == PJ_INADDR_NONE))
- {
- /* Invalid address */
- return PJ_EINVAL;
- }
- }
+ is_ipv6 = (local && local->addr.sa_family == pj_AF_INET6());
pool = pjsip_endpt_create_pool(endpt, "tlstp", POOL_LIS_INIT,
POOL_LIS_INC);
@@ -354,7 +551,8 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt,
listener->factory.type_name = (char*)
pjsip_transport_get_type_name(listener->factory.type);
listener->factory.flag =
- pjsip_transport_get_flag_from_type(listener->factory.type);
+ pjsip_transport_get_flag_from_type(listener->factory.type);
+ listener->endpt = endpt;
pj_ansi_strcpy(listener->factory.obj_name, "tlstp");
if (is_ipv6)
@@ -373,83 +571,18 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt,
if (async_cnt > MAX_ASYNC_CNT)
async_cnt = MAX_ASYNC_CNT;
- /* Build SSL socket param */
- pj_ssl_sock_param_default(&ssock_param);
- ssock_param.sock_af = af;
- ssock_param.cb.on_accept_complete = &on_accept_complete;
- ssock_param.async_cnt = async_cnt;
- ssock_param.ioqueue = pjsip_endpt_get_ioqueue(endpt);
- ssock_param.timer_heap = pjsip_endpt_get_timer_heap(endpt);
- ssock_param.require_client_cert = listener->tls_setting.require_client_cert;
- ssock_param.timeout = listener->tls_setting.timeout;
- ssock_param.user_data = listener;
- ssock_param.verify_peer = PJ_FALSE; /* avoid SSL socket closing the socket
- * due to verification error */
- if (ssock_param.send_buffer_size < PJSIP_MAX_PKT_LEN)
- ssock_param.send_buffer_size = PJSIP_MAX_PKT_LEN;
- if (ssock_param.read_buffer_size < PJSIP_MAX_PKT_LEN)
- ssock_param.read_buffer_size = PJSIP_MAX_PKT_LEN;
- ssock_param.ciphers_num = listener->tls_setting.ciphers_num;
- ssock_param.ciphers = listener->tls_setting.ciphers;
- ssock_param.curves_num = listener->tls_setting.curves_num;
- ssock_param.curves = listener->tls_setting.curves;
- ssock_param.sigalgs = listener->tls_setting.sigalgs;
- ssock_param.entropy_type = listener->tls_setting.entropy_type;
- ssock_param.entropy_path = listener->tls_setting.entropy_path;
- ssock_param.reuse_addr = listener->tls_setting.reuse_addr;
- ssock_param.qos_type = listener->tls_setting.qos_type;
- ssock_param.qos_ignore_error = listener->tls_setting.qos_ignore_error;
- pj_memcpy(&ssock_param.qos_params, &listener->tls_setting.qos_params,
- sizeof(ssock_param.qos_params));
-
- ssock_param.sockopt_ignore_error =
- listener->tls_setting.sockopt_ignore_error;
- /* Copy the sockopt */
- pj_memcpy(&ssock_param.sockopt_params,
- &listener->tls_setting.sockopt_params,
- sizeof(listener->tls_setting.sockopt_params));
-
- has_listener = PJ_FALSE;
-
- sip_ssl_method = listener->tls_setting.method;
- sip_ssl_proto = listener->tls_setting.proto;
- ssock_param.proto = ssl_get_proto(sip_ssl_method, sip_ssl_proto);
+ listener->async_cnt = async_cnt;
/* Create group lock */
status = pj_grp_lock_create(pool, NULL, &listener->grp_lock);
if (status != PJ_SUCCESS)
- return status;
+ goto on_error;
/* Setup group lock handler */
pj_grp_lock_add_ref(listener->grp_lock);
pj_grp_lock_add_handler(listener->grp_lock, pool, listener,
&lis_on_destroy);
-#if !(defined(PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER) && \
- PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER != 0)
-
- ssock_param.grp_lock = listener->grp_lock;
-
- /* Create SSL socket */
- status = pj_ssl_sock_create(pool, &ssock_param, &listener->ssock);
- if (status != PJ_SUCCESS)
- goto on_error;
-
-#endif
-
- /* Bind address may be different than factory.local_addr because
- * factory.local_addr will be resolved below.
- */
- listener_addr = &listener->factory.local_addr;
- if (local) {
- pj_sockaddr_cp((pj_sockaddr_t*)listener_addr,
- (const pj_sockaddr_t*)local);
- pj_sockaddr_cp(&listener->bound_addr, local);
- } else {
- pj_sockaddr_init(af, listener_addr, NULL, 0);
- pj_sockaddr_init(af, &listener->bound_addr, NULL, 0);
- }
-
/* Check if certificate/CA list for SSL socket is set */
if (listener->tls_setting.cert_file.slen ||
listener->tls_setting.ca_list_file.slen ||
@@ -464,90 +597,33 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt,
&listener->cert);
if (status != PJ_SUCCESS)
goto on_error;
- }
-
-#if !(defined(PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER) && \
- PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER != 0)
-
- if (listener->cert) {
- status = pj_ssl_sock_set_certificate(listener->ssock, pool,
- listener->cert);
- if (status != PJ_SUCCESS)
- goto on_error;
}
- /* Start accepting incoming connections. Note that some TLS/SSL backends
- * may not support for SSL socket server.
- */
- has_listener = PJ_FALSE;
-
- pj_memcpy(&newsock_param, &ssock_param, sizeof(newsock_param));
- newsock_param.async_cnt = 1;
- newsock_param.cb.on_data_read = &on_data_read;
- newsock_param.cb.on_data_sent = &on_data_sent;
- status = pj_ssl_sock_start_accept2(listener->ssock, pool,
- (pj_sockaddr_t*)listener_addr,
- pj_sockaddr_get_len((pj_sockaddr_t*)listener_addr),
- &newsock_param);
- if (status == PJ_SUCCESS || status == PJ_EPENDING) {
- pj_ssl_sock_info info;
- has_listener = PJ_TRUE;
+ /* Register to transport manager */
+ listener->endpt = endpt;
+ listener->tpmgr = pjsip_endpt_get_tpmgr(endpt);
+ listener->factory.create_transport2 = lis_create_transport;
+ listener->factory.destroy = lis_destroy;
- /* Retrieve the bound address */
- status = pj_ssl_sock_get_info(listener->ssock, &info);
- if (status == PJ_SUCCESS)
- pj_sockaddr_cp(listener_addr, (pj_sockaddr_t*)&info.local_addr);
- } else if (status != PJ_ENOTSUP) {
+#if !(defined(PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER) && \
+ PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER != 0)
+ /* Start listener. */
+ status = pjsip_tls_transport_lis_start(&listener->factory, local, a_name);
+ if (status != PJ_SUCCESS)
goto on_error;
- }
-
-#endif
-
+#else
+ update_bound_addr(listener, local);
/* If published host/IP is specified, then use that address as the
* listener advertised address.
*/
- if (a_name && a_name->host.slen) {
- /* Copy the address */
- listener->factory.addr_name = *a_name;
- pj_strdup(listener->factory.pool, &listener->factory.addr_name.host,
- &a_name->host);
- listener->factory.addr_name.port = a_name->port;
-
- } else {
- /* No published address is given, use the bound address */
-
- /* If the address returns 0.0.0.0, use the default
- * interface address as the transport's address.
- */
- if (!pj_sockaddr_has_addr(listener_addr)) {
- pj_sockaddr hostip;
-
- status = pj_gethostip(af, &hostip);
- if (status != PJ_SUCCESS)
- goto on_error;
-
- pj_sockaddr_copy_addr(listener_addr, &hostip);
- }
-
- /* Save the address name */
- sockaddr_to_host_port(listener->factory.pool,
- &listener->factory.addr_name, listener_addr);
- }
-
- /* If port is zero, get the bound port */
- if (listener->factory.addr_name.port == 0) {
- listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
- }
+ status = update_factory_addr(listener, a_name);
+ if (status != PJ_SUCCESS)
+ goto on_error;
- pj_ansi_snprintf(listener->factory.obj_name,
- sizeof(listener->factory.obj_name),
- "tlstp:%d", listener->factory.addr_name.port);
+ /* Set transport info. */
+ update_transport_info(listener);
+#endif
- /* Register to transport manager */
- listener->endpt = endpt;
- listener->tpmgr = pjsip_endpt_get_tpmgr(endpt);
- listener->factory.create_transport2 = lis_create_transport;
- listener->factory.destroy = lis_destroy;
listener->is_registered = PJ_TRUE;
status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
&listener->factory);
@@ -556,31 +632,6 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt,
goto on_error;
}
- /* Set transport info. */
- if (listener->factory.info == NULL) {
- listener->factory.info = (char*) pj_pool_alloc(listener->factory.pool,
- INFO_LEN);
- }
- pj_sockaddr_print(listener_addr, local_addr, sizeof(local_addr), 3);
- pj_ansi_snprintf(
- listener->factory.info, INFO_LEN, "tls %s [published as %.*s:%d]",
- local_addr,
- (int)listener->factory.addr_name.host.slen,
- listener->factory.addr_name.host.ptr,
- listener->factory.addr_name.port);
-
- if (has_listener) {
- PJ_LOG(4,(listener->factory.obj_name,
- "SIP TLS listener is ready for incoming connections "
- "at %.*s:%d",
- (int)listener->factory.addr_name.host.slen,
- listener->factory.addr_name.host.ptr,
- listener->factory.addr_name.port));
- } else {
- PJ_LOG(4,(listener->factory.obj_name, "SIP TLS is ready "
- "(client only)"));
- }
-
/* Return the pointer to user */
if (p_factory) *p_factory = &listener->factory;
@@ -609,11 +660,8 @@ static void lis_on_destroy(void *arg)
}
-/* This callback is called by transport manager to destroy listener */
-static pj_status_t lis_destroy(pjsip_tpfactory *factory)
+static void lis_close(struct tls_listener *listener)
{
- struct tls_listener *listener = (struct tls_listener *)factory;
-
if (listener->is_registered) {
pjsip_tpmgr_unregister_tpfactory(listener->tpmgr, &listener->factory);
listener->is_registered = PJ_FALSE;
@@ -623,6 +671,15 @@ static pj_status_t lis_destroy(pjsip_tpfactory *factory)
pj_ssl_sock_close(listener->ssock);
listener->ssock = NULL;
}
+}
+
+
+/* This callback is called by transport manager to destroy listener */
+static pj_status_t lis_destroy(pjsip_tpfactory *factory)
+{
+ struct tls_listener *listener = (struct tls_listener *)factory;
+
+ lis_close(listener);
if (listener->grp_lock) {
pj_grp_lock_t *grp_lock = listener->grp_lock;
@@ -637,6 +694,38 @@ static pj_status_t lis_destroy(pjsip_tpfactory *factory)
}
+PJ_DEF(pj_status_t) pjsip_tls_transport_restart(pjsip_tpfactory *factory,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name)
+{
+ pj_status_t status = PJ_SUCCESS;
+ struct tls_listener *listener = (struct tls_listener *)factory;
+
+ lis_close(listener);
+
+ status = pjsip_tls_transport_lis_start(factory, local, a_name);
+ if (status != PJ_SUCCESS) {
+ tls_perror(listener->factory.obj_name,
+ "Unable to start listener after closing it", status);
+
+ return status;
+ }
+
+ status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
+ &listener->factory);
+ if (status != PJ_SUCCESS) {
+ tls_perror(listener->factory.obj_name,
+ "Unable to register the transport listener", status);
+
+ listener->is_registered = PJ_FALSE;
+ } else {
+ listener->is_registered = PJ_TRUE;
+ }
+
+ return status;
+}
+
+
/***************************************************************************/
/*
* TLS Transport
diff --git a/pjsip/src/pjsip/sip_transport_udp.c b/pjsip/src/pjsip/sip_transport_udp.c
index 6148f4b..025d9d5 100644
--- a/pjsip/src/pjsip/sip_transport_udp.c
+++ b/pjsip/src/pjsip/sip_transport_udp.c
@@ -1,4 +1,4 @@
-/* $Id: sip_transport_udp.c 5519 2017-01-11 03:35:17Z nanang $ */
+/* $Id: sip_transport_udp.c 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -700,7 +700,7 @@ static pj_status_t transport_attach( pjsip_endpoint *endpt,
{
pj_pool_t *pool;
struct udp_transport *tp;
- const char *format, *ipv6_quoteb, *ipv6_quotee;
+ const char *format, *ipv6_quoteb = "", *ipv6_quotee = "";
unsigned i;
pj_status_t status;
@@ -709,12 +709,18 @@ static pj_status_t transport_attach( pjsip_endpoint *endpt,
/* Object name. */
if (type & PJSIP_TRANSPORT_IPV6) {
+ pj_in6_addr dummy6;
+
format = "udpv6%p";
- ipv6_quoteb = "[";
- ipv6_quotee = "]";
+ /* We don't need to add quote if the transport type is IPv6, but
+ * actually translated to IPv4.
+ */
+ if (pj_inet_pton(pj_AF_INET6(), &a_name->host, &dummy6)==PJ_SUCCESS) {
+ ipv6_quoteb = "[";
+ ipv6_quotee = "]";
+ }
} else {
format = "udp%p";
- ipv6_quoteb = ipv6_quotee = "";
}
/* Create pool. */
@@ -1074,11 +1080,22 @@ PJ_DEF(pj_status_t) pjsip_udp_transport_pause(pjsip_transport *transport,
* - if socket is not specified, create and replace.
*/
PJ_DEF(pj_status_t) pjsip_udp_transport_restart(pjsip_transport *transport,
- unsigned option,
+ unsigned option,
pj_sock_t sock,
const pj_sockaddr_in *local,
const pjsip_host_port *a_name)
{
+ return pjsip_udp_transport_restart2(transport, option, sock,
+ (pj_sockaddr*)local, a_name);
+}
+
+
+PJ_DEF(pj_status_t) pjsip_udp_transport_restart2(pjsip_transport *transport,
+ unsigned option,
+ pj_sock_t sock,
+ const pj_sockaddr *local,
+ const pjsip_host_port *a_name)
+{
struct udp_transport *tp;
pj_status_t status;
@@ -1092,7 +1109,7 @@ PJ_DEF(pj_status_t) pjsip_udp_transport_restart(pjsip_transport *transport,
* quit as soon as possible.
*/
tp->is_paused = PJ_TRUE;
-
+
if (option & PJSIP_UDP_TRANSPORT_DESTROY_SOCKET) {
char addr_buf[PJ_INET6_ADDRSTRLEN];
pjsip_host_port bound_name;
@@ -1115,8 +1132,8 @@ PJ_DEF(pj_status_t) pjsip_udp_transport_restart(pjsip_transport *transport,
/* Create the socket if it's not specified */
if (sock == PJ_INVALID_SOCKET) {
- status = create_socket(pj_AF_INET(), local,
- sizeof(pj_sockaddr_in), &sock);
+ status = create_socket(local->addr.sa_family, local,
+ pj_sockaddr_get_len(local), &sock);
if (status != PJ_SUCCESS)
return status;
}
@@ -1183,4 +1200,3 @@ PJ_DEF(pj_status_t) pjsip_udp_transport_restart(pjsip_transport *transport,
return PJ_SUCCESS;
}
-
diff --git a/pjsip/src/pjsip/sip_ua_layer.c b/pjsip/src/pjsip/sip_ua_layer.c
index 2dfa90a..83b5907 100644
--- a/pjsip/src/pjsip/sip_ua_layer.c
+++ b/pjsip/src/pjsip/sip_ua_layer.c
@@ -1,4 +1,4 @@
-/* $Id: sip_ua_layer.c 5456 2016-10-07 08:41:55Z ming $ */
+/* $Id: sip_ua_layer.c 5573 2017-03-29 02:40:48Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -551,12 +551,12 @@ static struct dlg_set *find_dlg_set_for_msg( pjsip_rx_data *rdata )
pjsip_get_invite_method(), rdata);
/* Lookup the INVITE transaction */
- tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
+ tsx = pjsip_tsx_layer_find_tsx2(&key, PJ_TRUE);
/* We should find the dialog attached to the INVITE transaction */
if (tsx) {
dlg = (pjsip_dialog*) tsx->mod_data[mod_ua.mod.id];
- pj_grp_lock_release(tsx->grp_lock);
+ pj_grp_lock_dec_ref(tsx->grp_lock);
/* Dlg may be NULL on some extreme condition
* (e.g. during debugging where initially there is a dialog)
diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c
index b4b5c11..484305a 100644
--- a/pjsip/src/pjsip/sip_util.c
+++ b/pjsip/src/pjsip/sip_util.c
@@ -1,4 +1,4 @@
-/* $Id: sip_util.c 5337 2016-06-08 02:49:56Z nanang $ */
+/* $Id: sip_util.c 5636 2017-08-02 02:51:59Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -1214,8 +1214,14 @@ static void stateless_send_transport_cb( void *token,
}
via->transport = pj_str(stateless_data->cur_transport->type_name);
+ /* For Cancel request, do not update the Via address with
+ * the new transport since it needs to match the original
+ * request.
+ */
if (tdata->via_addr.host.slen > 0 &&
- tdata->via_tp == (void *)stateless_data->cur_transport)
+ (!tdata->via_tp ||
+ tdata->via_tp == (void *)stateless_data->cur_transport ||
+ tdata->msg->line.req.method.id == PJSIP_CANCEL_METHOD))
{
via->sent_by = tdata->via_addr;
} else {
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index b55daa9..5263117 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_acc.c 5535 2017-01-19 10:31:38Z riza $ */
+/* $Id: pjsua_acc.c 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -32,6 +32,7 @@ enum
};
+static int get_ip_addr_ver(const pj_str_t *host);
static void schedule_reregistration(pjsua_acc *acc);
static void keep_alive_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te);
@@ -202,6 +203,20 @@ static pj_status_t initialize_acc(unsigned acc_id)
acc->user_part = sip_uri->user;
acc->srv_domain = sip_uri->host;
acc->srv_port = 0;
+
+ /* Escape user part (ticket #2010) */
+ if (acc->user_part.slen) {
+ const pjsip_parser_const_t *pconst;
+ char buf[PJSIP_MAX_URL_SIZE];
+ pj_str_t user_part;
+
+ pconst = pjsip_parser_const();
+ pj_strset(&user_part, buf, sizeof(buf));
+ pj_strncpy_escape(&user_part, &sip_uri->user, sizeof(buf),
+ &pconst->pjsip_USER_SPEC_LENIENT);
+ if (user_part.slen > acc->user_part.slen)
+ pj_strdup(acc->pool, &acc->user_part, &user_part);
+ }
}
acc->is_sips = PJSIP_URI_SCHEME_IS_SIPS(name_addr);
@@ -386,6 +401,8 @@ static pj_status_t initialize_acc(unsigned acc_id)
if (acc_cfg->transport_id != PJSUA_INVALID_ID)
acc->tp_type = pjsua_var.tpdata[acc_cfg->transport_id].type;
+ acc->ip_change_op = PJSUA_IP_CHANGE_OP_NULL;
+
return PJ_SUCCESS;
}
@@ -533,7 +550,7 @@ PJ_DEF(pj_status_t) pjsua_acc_add_local( pjsua_transport_id tid,
--cfg.priority;
/* Enclose IPv6 address in square brackets */
- if (t->type & PJSIP_TRANSPORT_IPV6) {
+ if (get_ip_addr_ver(&t->local_name.host) == 6) {
beginquote = "[";
endquote = "]";
} else {
@@ -672,6 +689,7 @@ PJ_DEF(pj_status_t) pjsua_acc_del(pjsua_acc_id acc_id)
pj_bzero(&acc->via_addr, sizeof(acc->via_addr));
acc->via_tp = NULL;
acc->next_rtp_port = 0;
+ acc->ip_change_op = PJSUA_IP_CHANGE_OP_NULL;
/* Remove from array */
for (i=0; i<pjsua_var.acc_cnt; ++i) {
@@ -1311,6 +1329,7 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id,
acc->cfg.rtp_cfg.bound_addr = b_addr;
}
+ acc->cfg.nat64_opt = cfg->nat64_opt;
acc->cfg.ipv6_media_use = cfg->ipv6_media_use;
/* STUN and Media customization */
@@ -1401,6 +1420,11 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id,
}
}
+ /* IP Change config */
+ acc->cfg.ip_change_cfg.shutdown_tp = cfg->ip_change_cfg.shutdown_tp;
+ acc->cfg.ip_change_cfg.hangup_calls = cfg->ip_change_cfg.hangup_calls;
+ acc->cfg.ip_change_cfg.reinvite_flags = cfg->ip_change_cfg.reinvite_flags;
+
on_return:
PJSUA_UNLOCK();
pj_log_pop_indent();
@@ -1682,9 +1706,12 @@ static pj_bool_t acc_check_nat_addr(pjsua_acc *acc,
if (status == PJ_SUCCESS) {
/* Compare the addresses as sockaddr according to the ticket above,
* but only if they have the same family (ipv4 vs ipv4, or
- * ipv6 vs ipv6)
+ * ipv6 vs ipv6).
+ * Checking for the same address family is currently disabled,
+ * since it can be useful in cases such as when on NAT64,
+ * in order to get the IPv4-mapped address from IPv6.
*/
- matched = (contact_addr.addr.sa_family != recv_addr.addr.sa_family) ||
+ matched = //(contact_addr.addr.sa_family != recv_addr.addr.sa_family)||
(uri->port == rport &&
pj_sockaddr_cmp(&contact_addr, &recv_addr)==0);
} else {
@@ -2180,6 +2207,15 @@ static void regc_tsx_cb(struct pjsip_regc_tsx_cb_param *param)
}
/*
+ * Timer callback to handle call on IP change process.
+ */
+static void handle_call_on_ip_change_cb(void *user_data)
+{
+ pjsua_acc *acc = (pjsua_acc*)user_data;
+ pjsua_acc_handle_call_on_ip_change(acc);
+}
+
+/*
* This callback is called by pjsip_regc when outgoing register
* request has completed.
*/
@@ -2246,7 +2282,8 @@ static void regc_cb(struct pjsip_regc_cbparam *param)
PJ_LOG(3,(THIS_FILE, "%s: unregistration success",
pjsua_var.acc[acc->index].cfg.id.ptr));
- } else {
+
+ } else {
/* Check and update SIP outbound status first, since the result
* will determine if we should update re-registration
*/
@@ -2286,8 +2323,8 @@ static void regc_cb(struct pjsip_regc_cbparam *param)
/* Subscribe to MWI, if it's enabled */
if (acc->cfg.mwi_enabled)
pjsua_start_mwi(acc->index, PJ_FALSE);
- }
+ }
} else {
PJ_LOG(4, (THIS_FILE, "SIP registration updated status=%d", param->code));
}
@@ -2330,6 +2367,51 @@ static void regc_cb(struct pjsip_regc_cbparam *param)
reg_info.renew = !param->is_unreg;
(*pjsua_var.ua_cfg.cb.on_reg_state2)(acc->index, ®_info);
}
+
+ if (acc->ip_change_op == PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT) {
+ if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
+ pjsua_ip_change_op_info ip_chg_info;
+ pjsip_regc_info rinfo;
+
+ pj_bzero(&ip_chg_info, sizeof(ip_chg_info));
+ pjsip_regc_get_info(param->regc, &rinfo);
+ ip_chg_info.acc_update_contact.acc_id = acc->index;
+ ip_chg_info.acc_update_contact.code = param->code;
+ ip_chg_info.acc_update_contact.is_register = !param->is_unreg;
+ (*pjsua_var.ua_cfg.cb.on_ip_change_progress)(acc->ip_change_op,
+ param->status,
+ &ip_chg_info);
+ }
+
+ if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {
+ if (param->expiration < 1) {
+ pj_status_t status;
+ /* Send re-register. */
+ PJ_LOG(3, (THIS_FILE, "%.*s: send registration triggered by IP"
+ " change", pjsua_var.acc[acc->index].cfg.id.slen,
+ pjsua_var.acc[acc->index].cfg.id.ptr));
+
+ status = pjsua_acc_set_registration(acc->index, PJ_TRUE);
+ if ((status != PJ_SUCCESS) &&
+ pjsua_var.ua_cfg.cb.on_ip_change_progress)
+ {
+ pjsua_ip_change_op_info ip_chg_info;
+
+ pj_bzero(&ip_chg_info, sizeof(ip_chg_info));
+ ip_chg_info.acc_update_contact.acc_id = acc->index;
+ ip_chg_info.acc_update_contact.is_register = PJ_TRUE;
+ (*pjsua_var.ua_cfg.cb.on_ip_change_progress)(
+ acc->ip_change_op,
+ status,
+ &ip_chg_info);
+ }
+ } else {
+ /* Avoid deadlock issue when sending BYE or Re-INVITE. */
+ pjsua_schedule_timer2(&handle_call_on_ip_change_cb,
+ (void*)acc, 0);
+ }
+ }
+ }
PJSUA_UNLOCK();
pj_log_pop_indent();
@@ -2656,7 +2738,7 @@ PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id,
//pjsip_regc_get_info(pjsua_var.acc[acc_id].regc, ®_info);
//pjsua_var.acc[acc_id].auto_rereg.reg_tp = reg_info.transport;
-
+
if (pjsua_var.ua_cfg.cb.on_reg_started) {
(*pjsua_var.ua_cfg.cb.on_reg_started)(acc_id, renew);
}
@@ -3100,6 +3182,7 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id,
pjsip_tpselector tp_sel;
pjsip_tpmgr *tpmgr;
pjsip_tpmgr_fla2_param tfla2_prm;
+ pj_bool_t update_addr = PJ_TRUE;
PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
acc = &pjsua_var.acc[acc_id];
@@ -3169,6 +3252,25 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id,
addr->host = tfla2_prm.ret_addr;
addr->port = tfla2_prm.ret_port;
+ /* If we are behind NAT64, use the Contact and Via address from
+ * the UDP6 transport, which should be obtained from STUN.
+ */
+ if (acc->cfg.nat64_opt != PJSUA_NAT64_DISABLED) {
+ pjsip_tpmgr_fla2_param tfla2_prm2 = tfla2_prm;
+
+ tfla2_prm2.tp_type = PJSIP_TRANSPORT_UDP6;
+ tfla2_prm2.tp_sel = NULL;
+ tfla2_prm2.local_if = (!pjsua_sip_acc_is_using_stun(acc_id));
+ status = pjsip_tpmgr_find_local_addr2(tpmgr, pool, &tfla2_prm2);
+ if (status == PJ_SUCCESS) {
+ update_addr = PJ_FALSE;
+ addr->host = tfla2_prm2.ret_addr;
+ pj_strdup(acc->pool, &acc->via_addr.host, &addr->host);
+ acc->via_addr.port = addr->port;
+ acc->via_tp = (pjsip_transport *)tfla2_prm.ret_tp;
+ }
+ }
+
/* For TCP/TLS, acc may request to specify source port */
if (acc->cfg.contact_use_src_port) {
pjsip_host_info dinfo;
@@ -3262,8 +3364,12 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id,
}
if (status == PJ_SUCCESS) {
- /* Got the local transport address */
- pj_strdup(pool, &addr->host, &tp->local_name.host);
+ /* Got the local transport address, don't update if
+ * we are on NAT64 and already obtained the address
+ * from STUN above.
+ */
+ if (update_addr)
+ pj_strdup(pool, &addr->host, &tp->local_name.host);
addr->port = tp->local_name.port;
}
@@ -3726,8 +3832,16 @@ void pjsua_acc_on_tp_state_changed(pjsip_transport *tp,
pjsip_regc_release_transport(pjsua_var.acc[i].regc);
- /* Schedule reregistration for this account */
- if (acc->cfg.reg_retry_interval) {
+ if (pjsua_var.acc[i].ip_change_op ==
+ PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP)
+ {
+ if (acc->cfg.allow_contact_rewrite) {
+ pjsua_acc_update_contact_on_ip_change(acc);
+ } else {
+ pjsua_acc_handle_call_on_ip_change(acc);
+ }
+ } else if (acc->cfg.reg_retry_interval) {
+ /* Schedule reregistration for this account */
schedule_reregistration(acc);
}
}
@@ -3736,3 +3850,115 @@ void pjsua_acc_on_tp_state_changed(pjsip_transport *tp,
PJSUA_UNLOCK();
pj_log_pop_indent();
}
+
+
+/*
+ * Internal function to update contact on ip change process.
+ */
+pj_status_t pjsua_acc_update_contact_on_ip_change(pjsua_acc *acc)
+{
+ pj_status_t status;
+ pj_bool_t need_unreg = ((acc->cfg.contact_rewrite_method &
+ PJSUA_CONTACT_REWRITE_UNREGISTER) != 0);
+
+ acc->ip_change_op = PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT;
+
+ PJ_LOG(3, (THIS_FILE, "%.*s: send %sregistration triggered "
+ "by IP change", acc->cfg.id.slen,
+ acc->cfg.id.ptr, (need_unreg ? "un-" : "")));
+
+ status = pjsua_acc_set_registration(acc->index, !need_unreg);
+
+ if ((status != PJ_SUCCESS) && (pjsua_var.ua_cfg.cb.on_ip_change_progress))
+ {
+ pjsua_ip_change_op_info info;
+
+ pj_bzero(&info, sizeof(info));
+ info.acc_update_contact.acc_id = acc->index;
+ info.acc_update_contact.is_register = !need_unreg;
+
+ pjsua_var.ua_cfg.cb.on_ip_change_progress(acc->ip_change_op,
+ status,
+ &info);
+ }
+ return status;
+}
+
+
+/*
+ * Internal function to handle call on ip change process.
+ */
+pj_status_t pjsua_acc_handle_call_on_ip_change(pjsua_acc *acc)
+{
+ pj_status_t status = PJ_SUCCESS;
+ unsigned i = 0;
+
+ if (acc->cfg.ip_change_cfg.hangup_calls ||
+ acc->cfg.ip_change_cfg.reinvite_flags)
+ {
+ for (i = 0; i < (int)pjsua_var.ua_cfg.max_calls; ++i) {
+ pjsua_call_info call_info;
+ pjsua_call_get_info(i, &call_info);
+
+ if (pjsua_var.calls[i].acc_id != acc->index)
+ {
+ continue;
+ }
+
+ if (acc->cfg.ip_change_cfg.hangup_calls) {
+ acc->ip_change_op = PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS;
+ PJ_LOG(3, (THIS_FILE, "call to %.*s: hangup "
+ "triggered by IP change",
+ call_info.remote_info.slen,
+ call_info.remote_info.ptr));
+
+ status = pjsua_call_hangup(i, PJSIP_SC_GONE, NULL, NULL);
+
+ if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
+ pjsua_ip_change_op_info info;
+
+ pj_bzero(&info, sizeof(info));
+ info.acc_hangup_calls.acc_id = acc->index;
+ info.acc_hangup_calls.call_id = call_info.id;
+
+ pjsua_var.ua_cfg.cb.on_ip_change_progress(
+ acc->ip_change_op,
+ status,
+ &info);
+ }
+ } else if ((acc->cfg.ip_change_cfg.reinvite_flags) &&
+ (call_info.state == PJSIP_INV_STATE_CONFIRMED))
+ {
+ acc->ip_change_op = PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS;
+
+ call_info.setting.flag |=
+ acc->cfg.ip_change_cfg.reinvite_flags;
+
+ PJ_LOG(3, (THIS_FILE, "call to %.*s: send "
+ "re-INVITE with flags 0x%x triggered "
+ "by IP change",
+ call_info.remote_info.slen,
+ call_info.remote_info.ptr,
+ acc->cfg.ip_change_cfg.reinvite_flags));
+
+ status = pjsua_call_reinvite(i, call_info.setting.flag, NULL);
+
+ if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
+ pjsua_ip_change_op_info info;
+
+ pj_bzero(&info, sizeof(info));
+ info.acc_reinvite_calls.acc_id = acc->index;
+ info.acc_reinvite_calls.call_id = call_info.id;
+
+ pjsua_var.ua_cfg.cb.on_ip_change_progress(
+ acc->ip_change_op,
+ status,
+ &info);
+ }
+
+ }
+ }
+ }
+ acc->ip_change_op = PJSUA_IP_CHANGE_OP_NULL;
+ return status;
+}
diff --git a/pjsip/src/pjsua-lib/pjsua_aud.c b/pjsip/src/pjsua-lib/pjsua_aud.c
index b84c550..8055a51 100644
--- a/pjsip/src/pjsua-lib/pjsua_aud.c
+++ b/pjsip/src/pjsua-lib/pjsua_aud.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_aud.c 5273 2016-04-04 01:44:10Z riza $ */
+/* $Id: pjsua_aud.c 5651 2017-09-19 10:21:42Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -512,7 +512,8 @@ void pjsua_aud_stop_stream(pjsua_call_media *call_med)
}
if ((call_med->dir & PJMEDIA_DIR_ENCODING) &&
- (pjmedia_stream_get_stat(strm, &stat) == PJ_SUCCESS))
+ (pjmedia_stream_get_stat(strm, &stat) == PJ_SUCCESS) &&
+ stat.tx.pkt)
{
/* Save RTP timestamp & sequence, so when media session is
* restarted, those values will be restored as the initial
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index d283f6d..2e50a1d 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_call.c 5535 2017-01-19 10:31:38Z riza $ */
+/* $Id: pjsua_call.c 5635 2017-08-01 07:49:34Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -130,6 +130,10 @@ static void reset_call(pjsua_call_id id)
pjsua_call *call = &pjsua_var.calls[id];
unsigned i;
+ if (call->incoming_data) {
+ pjsip_rx_data_free_cloned(call->incoming_data);
+ call->incoming_data = NULL;
+ }
pj_bzero(call, sizeof(*call));
call->index = id;
call->last_text.ptr = call->last_text_buf_;
@@ -1646,7 +1650,10 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
if (pjsua_var.ua_cfg.cb.on_incoming_call) {
pjsua_var.ua_cfg.cb.on_incoming_call(acc_id, call_id, rdata);
- /* onIncomingCall() may be simulated by onCreateMediaTransport()
+ /* Notes:
+ * - the call might be reset when it's rejected or hangup
+ * by application from the callback.
+ * - onIncomingCall() may be simulated by onCreateMediaTransport()
* when media init is done synchrounously (see #1916). And if app
* happens to answer/hangup the call from the callback, the
* answer/hangup should have been delayed (see #1923),
@@ -1820,6 +1827,8 @@ PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id,
dlg->local.contact->uri,
info->local_contact.ptr,
sizeof(info->buf_.local_contact));
+ if (info->local_contact.slen < 0)
+ info->local_contact.slen = 0;
/* remote info */
info->remote_info.ptr = info->buf_.remote_info;
@@ -2713,7 +2722,10 @@ PJ_DEF(pj_status_t) pjsua_call_update2(pjsua_call_id call_id,
if (status != PJ_SUCCESS)
goto on_return;
- if (pjsua_call_media_is_changing(call)) {
+ /* Don't check media changing if UPDATE is sent without SDP */
+ if (pjsua_call_media_is_changing(call) &&
+ (opt && opt->flag & PJSUA_CALL_NO_SDP_OFFER) == 0)
+ {
PJ_LOG(1,(THIS_FILE, "Unable to send UPDATE" ERR_MEDIA_CHANGING));
status = PJ_EINVALIDOP;
goto on_return;
@@ -2927,9 +2939,9 @@ PJ_DEF(pj_status_t) pjsua_call_xfer_replaces( pjsua_call_id call_id,
* URL escape it based off of the allowed characters for header values.
*/
pconst = pjsip_parser_const();
- call_id_len = pj_strncpy2_escape(call_id_dest_buf, &dest_dlg->call_id->id,
- PJ_ARRAY_SIZE(call_id_dest_buf),
- &pconst->pjsip_HDR_CHAR_SPEC);
+ call_id_len = (int)pj_strncpy2_escape(call_id_dest_buf, &dest_dlg->call_id->id,
+ PJ_ARRAY_SIZE(call_id_dest_buf),
+ &pconst->pjsip_HDR_CHAR_SPEC);
if (call_id_len < 0) {
status = PJSIP_EURITOOLONG;
goto on_error;
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 8d5bcf3..0464cc4 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_core.c 5449 2016-10-06 09:48:10Z ming $ */
+/* $Id: pjsua_core.c 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -305,6 +305,11 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
cfg->mwi_expires = PJSIP_MWI_DEFAULT_EXPIRES;
cfg->media_stun_use = PJSUA_STUN_RETRY_ON_FAILURE;
+ cfg->ip_change_cfg.shutdown_tp = PJ_TRUE;
+ cfg->ip_change_cfg.hangup_calls = PJ_FALSE;
+ cfg->ip_change_cfg.reinvite_flags = PJSUA_CALL_REINIT_MEDIA |
+ PJSUA_CALL_UPDATE_CONTACT |
+ PJSUA_CALL_UPDATE_VIA;
}
PJ_DEF(void) pjsua_buddy_config_default(pjsua_buddy_config *cfg)
@@ -1297,9 +1302,14 @@ static pj_bool_t test_stun_on_status(pj_stun_sock *stun_sock,
stun_resolve_add_ref(sess);
- ++sess->idx;
- if (sess->idx >= sess->count)
- sess->status = status;
+ if (pjsua_var.ua_cfg.stun_try_ipv6 && sess->af == pj_AF_INET()) {
+ sess->af = pj_AF_INET6();
+ } else {
+ ++sess->idx;
+ sess->af = pj_AF_INET();
+ if (sess->idx >= sess->count)
+ sess->status = status;
+ }
resolve_stun_entry(sess);
@@ -1339,7 +1349,10 @@ static void resolve_stun_entry(pjsua_stun_resolve *sess)
pj_status_t status = PJ_EUNKNOWN;
/* Loop while we have entry to try */
- for (; sess->idx < sess->count; ++sess->idx) {
+ for (; sess->idx < sess->count;
+ (pjsua_var.ua_cfg.stun_try_ipv6 && sess->af == pj_AF_INET())?
+ sess->af = pj_AF_INET6(): (++sess->idx, sess->af = pj_AF_INET()))
+ {
int af;
char target[64];
pj_str_t hostpart;
@@ -1358,14 +1371,6 @@ static void resolve_stun_entry(pjsua_stun_resolve *sess)
if (status != PJ_SUCCESS) {
PJ_LOG(2,(THIS_FILE, "Invalid STUN server entry %s", target));
continue;
- } else if (af != pj_AF_INET()) {
- /* Ignore IPv6 STUN server for now */
- status = PJ_EAFNOTSUP;
- PJ_LOG(3,(THIS_FILE, "Ignored STUN server entry %s, currently "
- "only IPv4 STUN server is supported (does "
- "IPv6 still need a mapped address?)",
- target));
- continue;
}
/* Use default port if not specified */
@@ -1374,15 +1379,16 @@ static void resolve_stun_entry(pjsua_stun_resolve *sess)
pj_assert(sess->stun_sock == NULL);
- PJ_LOG(4,(THIS_FILE, "Trying STUN server %s (%d of %d)..",
- target, sess->idx+1, sess->count));
+ PJ_LOG(4,(THIS_FILE, "Trying STUN server %s %s (%d of %d)..",
+ target, (sess->af == pj_AF_INET()? "IPv4": "IPv6"),
+ sess->idx+1, sess->count));
/* Use STUN_sock to test this entry */
pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
stun_sock_cb.on_status = &test_stun_on_status;
sess->async_wait = PJ_FALSE;
status = pj_stun_sock_create(&pjsua_var.stun_cfg, "stunresolve",
- pj_AF_INET(), &stun_sock_cb,
+ sess->af, &stun_sock_cb,
NULL, sess, &sess->stun_sock);
if (status != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
@@ -1488,6 +1494,7 @@ PJ_DEF(pj_status_t) pjsua_resolve_stun_servers( unsigned count,
sess->blocking = wait;
sess->waiter = pj_thread_this();
sess->status = PJ_EPENDING;
+ sess->af = pj_AF_INET();
sess->srv = (pj_str_t*) pj_pool_calloc(pool, count, sizeof(pj_str_t));
for (i=0; i<count; ++i) {
pj_strdup(pool, &sess->srv[i], &srv[i]);
@@ -2157,18 +2164,22 @@ static pj_status_t create_sip_udp_sock(int af,
if (pj_sockaddr_get_port(p_pub_addr) == 0)
pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);
- } else if (stun_srv.slen && af == pj_AF_INET()) {
+ } else if (stun_srv.slen &&
+ (af == pj_AF_INET() || pjsua_var.ua_cfg.stun_try_ipv6))
+ {
pjstun_setting stun_opt;
/*
* STUN is specified, resolve the address with STUN.
- * Currently, this is available for IPv4 address only.
+ * Currently, this is only to get IPv4 mapped address
+ * (does IPv6 still need a mapped address?).
*/
pj_bzero(&stun_opt, sizeof(stun_opt));
stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2;
+ stun_opt.af = pjsua_var.stun_srv.addr.sa_family;
stun_opt.srv1 = stun_opt.srv2 = stun_srv;
stun_opt.port1 = stun_opt.port2 =
- pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port);
+ pj_sockaddr_get_port(&pjsua_var.stun_srv);
status = pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
1, &sock, &p_pub_addr->ipv4);
if (status != PJ_SUCCESS) {
@@ -2361,7 +2372,7 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
/* Copy the sockopt */
pj_memcpy(&tcp_cfg.sockopt_params, &cfg->sockopt_params,
sizeof(tcp_cfg.sockopt_params));
-
+
/* Create the TCP transport */
status = pjsip_tcp_transport_start3(pjsua_var.endpt, &tcp_cfg, &tcp);
@@ -2419,8 +2430,7 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
if (cfg->public_addr.slen)
a_name.host = cfg->public_addr;
- status = pjsip_tls_transport_start2(pjsua_var.endpt,
- &cfg->tls_setting,
+ status = pjsip_tls_transport_start2(pjsua_var.endpt, &cfg->tls_setting,
&local_addr, &a_name, 1, &tls);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error creating SIP TLS listener",
@@ -2705,6 +2715,66 @@ PJ_DEF(pj_status_t) pjsua_transport_close( pjsua_transport_id id,
}
+PJ_DEF(pj_status_t) pjsua_transport_lis_start(pjsua_transport_id id,
+ const pjsua_transport_config *cfg)
+{
+ pj_status_t status = PJ_SUCCESS;
+ pjsip_transport_type_e tp_type;
+
+ /* Make sure id is in range. */
+ PJ_ASSERT_RETURN(id>=0 && id<(int)PJ_ARRAY_SIZE(pjsua_var.tpdata),
+ PJ_EINVAL);
+
+ /* Make sure that transport exists */
+ PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
+
+ tp_type = pjsua_var.tpdata[id].type & ~PJSIP_TRANSPORT_IPV6;
+
+ if ((tp_type == PJSIP_TRANSPORT_TLS) || (tp_type == PJSIP_TRANSPORT_TCP)) {
+ pj_sockaddr bind_addr;
+ pjsip_host_port addr_name;
+ pjsip_tpfactory *factory = pjsua_var.tpdata[id].data.factory;
+
+ int af = pjsip_transport_type_get_af(factory->type);
+
+ if (cfg->port)
+ pj_sockaddr_set_port(&bind_addr, (pj_uint16_t)cfg->port);
+
+ if (cfg->bound_addr.slen) {
+ status = pj_sockaddr_set_str_addr(af,
+ &bind_addr,
+ &cfg->bound_addr);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE,
+ "Unable to resolve transport bound address",
+ status);
+ return status;
+ }
+ }
+
+ /* Set published name */
+ if (cfg->public_addr.slen)
+ addr_name.host = cfg->public_addr;
+
+ if (tp_type == PJSIP_TRANSPORT_TCP) {
+ status = pjsip_tcp_transport_lis_start(factory, &bind_addr,
+ &addr_name);
+ }
+#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
+ else {
+ status = pjsip_tls_transport_lis_start(factory, &bind_addr,
+ &addr_name);
+ }
+#endif
+ } else if (tp_type == PJSIP_TRANSPORT_UDP) {
+ status = PJ_SUCCESS;
+ } else {
+ status = PJ_EINVAL;
+ }
+ return status;
+}
+
+
/*
* Add additional headers etc in msg_data specified by application
* when sending requests.
@@ -2859,6 +2929,14 @@ void pjsua_init_tpselector(pjsua_transport_id tp_id,
}
+PJ_DEF(void) pjsua_ip_change_param_default(pjsua_ip_change_param *param)
+{
+ pj_bzero(param, sizeof(*param));
+ param->restart_listener = PJ_TRUE;
+ param->restart_lis_delay = PJSUA_TRANSPORT_RESTART_DELAY_TIME;
+}
+
+
/* Callback upon NAT detection completion */
static void nat_detect_cb(void *user_data,
const pj_stun_nat_detect_result *res)
@@ -2894,14 +2972,14 @@ PJ_DEF(pj_status_t) pjsua_detect_nat_type()
}
/* Make sure we have STUN */
- if (pjsua_var.stun_srv.ipv4.sin_family == 0) {
+ if (pjsua_var.stun_srv.addr.sa_family == 0) {
pjsua_var.nat_status = PJNATH_ESTUNINSERVER;
return PJNATH_ESTUNINSERVER;
}
- status = pj_stun_detect_nat_type(&pjsua_var.stun_srv.ipv4,
- &pjsua_var.stun_cfg,
- NULL, &nat_detect_cb);
+ status = pj_stun_detect_nat_type2(&pjsua_var.stun_srv,
+ &pjsua_var.stun_cfg,
+ NULL, &nat_detect_cb);
if (status != PJ_SUCCESS) {
pjsua_var.nat_status = status;
@@ -3265,3 +3343,244 @@ PJ_DEF(void) pjsua_dump(pj_bool_t detail)
PJ_LOG(3,(THIS_FILE, "Dump complete"));
}
+
+/* Forward declaration. */
+static void restart_listener_cb(void *user_data);
+
+
+static pj_status_t handle_ip_change_on_acc()
+{
+ int i = 0;
+ pj_status_t status = PJ_SUCCESS;
+ pj_bool_t acc_done[PJSUA_MAX_ACC];
+
+ /* Reset ip_change_active flag. */
+ for (; i < (int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+ pjsua_var.acc[i].ip_change_op = PJSUA_IP_CHANGE_OP_NULL;
+ acc_done[i] = PJ_FALSE;
+ }
+
+ for (i = 0; i < (int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+ pj_bool_t shutdown_transport = PJ_FALSE;
+ pjsip_regc_info regc_info;
+ char acc_id[PJSUA_MAX_ACC * 4];
+ pjsua_acc *acc = &pjsua_var.acc[i];
+ pjsip_transport *transport = NULL;
+ pjsua_acc_id shut_acc_ids[PJSUA_MAX_ACC];
+ unsigned shut_acc_cnt = 0;
+
+ if (!acc->valid || (acc_done[i]))
+ continue;
+
+ if (acc->regc) {
+ pjsip_regc_get_info(acc->regc, ®c_info);
+ if ((regc_info.transport) &&
+ ((regc_info.transport->flag & PJSIP_TRANSPORT_DATAGRAM) == 0))
+ {
+ transport = regc_info.transport;
+ shutdown_transport = acc->cfg.ip_change_cfg.shutdown_tp;
+ shut_acc_ids[shut_acc_cnt++] = acc->index;
+ }
+ } else if (acc->reg_last_code != PJSIP_SC_BAD_GATEWAY &&
+ acc->reg_last_code != PJSIP_SC_REQUEST_TIMEOUT &&
+ acc->reg_last_code != PJSIP_SC_INTERNAL_SERVER_ERROR &&
+ acc->reg_last_code != PJSIP_SC_BAD_GATEWAY &&
+ acc->reg_last_code != PJSIP_SC_SERVICE_UNAVAILABLE &&
+ acc->reg_last_code != PJSIP_SC_SERVER_TIMEOUT &&
+ acc->reg_last_code != PJSIP_SC_TEMPORARILY_UNAVAILABLE)
+ {
+ continue;
+ }
+ pj_ansi_snprintf(acc_id, sizeof(acc_id), "#%d", i);
+
+ if (transport) {
+ unsigned j = i + 1;
+
+ /* Find other account that uses the same transport. */
+ for (; j < (int)PJ_ARRAY_SIZE(pjsua_var.acc); ++j) {
+ pjsip_regc_info tmp_regc_info;
+ pjsua_acc *next_acc = &pjsua_var.acc[j];
+
+ if (!next_acc->valid || !next_acc->regc ||
+ (next_acc->ip_change_op > PJSUA_IP_CHANGE_OP_NULL))
+ {
+ continue;
+ }
+
+ pjsip_regc_get_info(next_acc->regc, &tmp_regc_info);
+ if (transport == tmp_regc_info.transport) {
+ char tmp_buf[PJSUA_MAX_ACC * 4];
+
+ pj_ansi_strncpy(tmp_buf, acc_id, sizeof(acc_id));
+ pj_ansi_snprintf(acc_id, sizeof(acc_id), "%s #%d",
+ tmp_buf, j);
+ shut_acc_ids[shut_acc_cnt++] = j;
+ if (!shutdown_transport) {
+ shutdown_transport =
+ next_acc->cfg.ip_change_cfg.shutdown_tp;
+ }
+ }
+ }
+ }
+
+ if (shutdown_transport) {
+ unsigned j;
+ /* Shutdown the transport. */
+ PJ_LOG(3, (THIS_FILE, "Shutdown transport %s used by account %s "
+ "triggered by IP change", transport->obj_name, acc_id));
+
+ for (j = 0; j < shut_acc_cnt; ++j) {
+ pjsua_acc *tmp_acc = &pjsua_var.acc[shut_acc_ids[j]];
+ tmp_acc->ip_change_op = PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP;
+ acc_done[shut_acc_ids[j]] = PJ_TRUE;
+ }
+
+ status = pjsip_transport_shutdown2(transport, PJ_TRUE);
+
+ /* Report progress to each acc which uses the same transport. */
+ for (j = 0; j < shut_acc_cnt; ++j) {
+ pjsua_acc *tmp_acc = &pjsua_var.acc[shut_acc_ids[j]];
+
+ if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
+ pjsua_ip_change_op_info info;
+
+ pj_bzero(&info, sizeof(info));
+ info.acc_shutdown_tp.acc_id = tmp_acc->index;
+
+ pjsua_var.ua_cfg.cb.on_ip_change_progress(
+ tmp_acc->ip_change_op,
+ status,
+ &info);
+ }
+
+ }
+ } else {
+ acc_done[i] = PJ_TRUE;
+ if (acc->cfg.allow_contact_rewrite) {
+ status = pjsua_acc_update_contact_on_ip_change(acc);
+ } else {
+ status = pjsua_acc_handle_call_on_ip_change(acc);
+ }
+ }
+ }
+ return status;
+}
+
+
+static pj_status_t restart_listener(pjsua_transport_id id,
+ unsigned restart_lis_delay)
+{
+ pj_sockaddr bind_addr;
+ pjsua_transport_info tp_info;
+ pj_status_t status;
+
+ pjsua_transport_get_info(id, &tp_info);
+ pj_sockaddr_init(pjsip_transport_type_get_af(tp_info.type),
+ &bind_addr,
+ NULL,
+ pj_sockaddr_get_port(&tp_info.local_addr));
+
+ switch (tp_info.type) {
+ case PJSIP_TRANSPORT_UDP:
+ case PJSIP_TRANSPORT_UDP6:
+ status = pjsip_udp_transport_restart2(
+ pjsua_var.tpdata[id].data.tp,
+ PJSIP_UDP_TRANSPORT_DESTROY_SOCKET,
+ PJ_INVALID_SOCKET,
+ &bind_addr,
+ NULL);
+ break;
+
+#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
+ case PJSIP_TRANSPORT_TLS:
+ case PJSIP_TRANSPORT_TLS6:
+ status = pjsip_tls_transport_restart(
+ pjsua_var.tpdata[id].data.factory,
+ &bind_addr,
+ NULL);
+ break;
+#endif
+ case PJSIP_TRANSPORT_TCP:
+ case PJSIP_TRANSPORT_TCP6:
+ status = pjsip_tcp_transport_restart(
+ pjsua_var.tpdata[id].data.factory,
+ &bind_addr,
+ NULL);
+ break;
+
+ default:
+ status = PJ_EINVAL;
+ }
+ if (status != PJ_SUCCESS && (restart_lis_delay > 0)) {
+ /* Try restarting again, with delay. */
+ pjsua_schedule_timer2(&restart_listener_cb,
+ (void*)(pj_size_t)id,
+ restart_lis_delay);
+ } else {
+ int i = 0;
+ pj_bool_t all_done = PJ_TRUE;
+
+ pjsua_var.tpdata[id].is_restarting = PJ_FALSE;
+ if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
+ pjsua_ip_change_op_info info;
+
+ pj_bzero(&info, sizeof(info));
+ info.lis_restart.transport_id = id;
+ pjsua_var.ua_cfg.cb.on_ip_change_progress(
+ PJSUA_IP_CHANGE_OP_RESTART_LIS,
+ status,
+ &info);
+ }
+
+ /* Move forward if all listener has been restarted. */
+ for (; i < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) {
+ if (pjsua_var.tpdata[i].data.ptr != NULL &&
+ pjsua_var.tpdata[i].is_restarting)
+ {
+ all_done = PJ_FALSE;
+ break;
+ }
+ }
+ if (all_done)
+ status = handle_ip_change_on_acc();
+ }
+ return status;
+}
+
+
+static void restart_listener_cb(void *user_data)
+{
+ pjsua_transport_id transport_id = (pjsua_transport_id)(pj_size_t)user_data;
+ restart_listener(transport_id, 0);
+}
+
+
+PJ_DEF(pj_status_t) pjsua_handle_ip_change(const pjsua_ip_change_param *param)
+{
+ pj_status_t status = PJ_SUCCESS;
+ int i = 0;
+
+ PJ_ASSERT_RETURN(param, PJ_EINVAL);
+
+ PJ_LOG(3, (THIS_FILE, "Start handling IP address change"));
+
+ if (param->restart_listener) {
+ /* Restart listener/transport, handle_ip_change_on_acc() will
+ * be called after listener restart is completed successfully.
+ */
+ for (i = 0; i < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) {
+ if (pjsua_var.tpdata[i].data.ptr != NULL) {
+ pjsua_var.tpdata[i].is_restarting = PJ_TRUE;
+ }
+ }
+ for (i = 0; i < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) {
+ if (pjsua_var.tpdata[i].data.ptr != NULL) {
+ status = restart_listener(i, param->restart_lis_delay);
+ }
+ }
+ } else {
+ status = handle_ip_change_on_acc();
+ }
+
+ return status;
+}
diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
index c5943c5..130803a 100644
--- a/pjsip/src/pjsua-lib/pjsua_media.c
+++ b/pjsip/src/pjsua-lib/pjsua_media.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_media.c 5535 2017-01-19 10:31:38Z riza $ */
+/* $Id: pjsua_media.c 5637 2017-08-02 07:19:21Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -240,7 +240,7 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
RTP_RETRY = 100
};
int i;
- pj_bool_t use_ipv6;
+ pj_bool_t use_ipv6, use_nat64;
int af;
pj_sockaddr bound_addr;
pj_sockaddr mapped_addr[2];
@@ -250,10 +250,13 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
pj_sock_t sock[2];
use_ipv6 = (acc->cfg.ipv6_media_use != PJSUA_IPV6_DISABLED);
- af = use_ipv6 ? pj_AF_INET6() : pj_AF_INET();
+ use_nat64 = (acc->cfg.nat64_opt != PJSUA_NAT64_DISABLED);
+ af = (use_ipv6 || use_nat64) ? pj_AF_INET6() : pj_AF_INET();
/* Make sure STUN server resolution has completed */
- if (!use_ipv6 && pjsua_media_acc_is_using_stun(call_med->call->acc_id)) {
+ if ((!use_ipv6 || use_nat64) &&
+ pjsua_media_acc_is_using_stun(call_med->call->acc_id))
+ {
pj_bool_t retry_stun = (acc->cfg.media_stun_use &
PJSUA_STUN_RETRY_ON_FAILURE) ==
PJSUA_STUN_RETRY_ON_FAILURE;
@@ -353,11 +356,11 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
* If we're configured to use STUN, then find out the mapped address,
* and make sure that the mapped RTCP port is adjacent with the RTP.
*/
- if (!use_ipv6 &&
+ if ((!use_ipv6 || use_nat64) &&
pjsua_media_acc_is_using_stun(call_med->call->acc_id) &&
pjsua_var.stun_srv.addr.sa_family != 0)
{
- char ip_addr[32];
+ char ip_addr[PJ_INET6_ADDRSTRLEN];
pj_str_t stun_srv;
pj_sockaddr_in resolved_addr[2];
pjstun_setting stun_opt;
@@ -367,9 +370,10 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
pj_bzero(&stun_opt, sizeof(stun_opt));
stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2;
+ stun_opt.af = pjsua_var.stun_srv.addr.sa_family;
stun_opt.srv1 = stun_opt.srv2 = stun_srv;
stun_opt.port1 = stun_opt.port2 =
- pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port);
+ pj_sockaddr_get_port(&pjsua_var.stun_srv);
status=pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
2, sock, resolved_addr);
#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
@@ -432,9 +436,10 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
stun_srv.slen = 0;
}
+ stun_opt.af = pjsua_var.stun_srv.addr.sa_family;
stun_opt.srv1 = stun_opt.srv2 = stun_srv;
stun_opt.port1 = stun_opt.port2 =
- pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port);
+ pj_sockaddr_get_port(&pjsua_var.stun_srv);
status = pjstun_get_mapped_addr2(&pjsua_var.cp.factory,
&stun_opt, 2, sock,
resolved_addr);
@@ -823,10 +828,11 @@ static pj_status_t create_ice_media_transport(
char name[32];
unsigned comp_cnt;
pj_status_t status;
- pj_bool_t use_ipv6;
+ pj_bool_t use_ipv6, use_nat64;
acc_cfg = &pjsua_var.acc[call_med->call->acc_id].cfg;
use_ipv6 = (acc_cfg->ipv6_media_use != PJSUA_IPV6_DISABLED);
+ use_nat64 = (acc_cfg->nat64_opt != PJSUA_NAT64_DISABLED);
/* Make sure STUN server resolution has completed */
if (pjsua_media_acc_is_using_stun(call_med->call->acc_id)) {
@@ -852,6 +858,21 @@ static pj_status_t create_ice_media_transport(
ice_cfg.opt = acc_cfg->ice_cfg.ice_opt;
+ if (call_med->call->async_call.rem_sdp) {
+ /* Match the default address family according to the offer */
+ const pj_str_t ID_IP6 = { "IP6", 3};
+ const pjmedia_sdp_media *m;
+ const pjmedia_sdp_conn *c;
+
+ m = call_med->call->async_call.rem_sdp->media[call_med->idx];
+ c = m->conn? m->conn : call_med->call->async_call.rem_sdp->conn;
+
+ if (pj_stricmp(&c->addr_type, &ID_IP6) == 0)
+ ice_cfg.af = pj_AF_INET6();
+ } else if (use_ipv6 || use_nat64) {
+ ice_cfg.af = pj_AF_INET6();
+ }
+
/* If STUN transport is configured, initialize STUN transport settings */
if ((pj_sockaddr_has_addr(&pjsua_var.stun_srv) &&
pjsua_media_acc_is_using_stun(call_med->call->acc_id)) ||
@@ -859,7 +880,9 @@ static pj_status_t create_ice_media_transport(
{
ice_cfg.stun_tp_cnt = 1;
pj_ice_strans_stun_cfg_default(&ice_cfg.stun_tp[0]);
- if (use_ipv6 && PJ_ICE_MAX_STUN >= 2) {
+ if (use_nat64) {
+ ice_cfg.stun_tp[0].af = pj_AF_INET6();
+ } else if (use_ipv6 && PJ_ICE_MAX_STUN >= 2) {
ice_cfg.stun_tp_cnt = 2;
pj_ice_strans_stun_cfg_default(&ice_cfg.stun_tp[1]);
ice_cfg.stun_tp[1].af = pj_AF_INET6();
@@ -870,72 +893,72 @@ static pj_status_t create_ice_media_transport(
if (ice_cfg.stun_tp_cnt) {
unsigned i;
- /* Configure STUN server (currently only for IPv4) */
- if (pj_sockaddr_has_addr(&pjsua_var.stun_srv) &&
- pjsua_media_acc_is_using_stun(call_med->call->acc_id))
- {
- pj_sockaddr_print(&pjsua_var.stun_srv, stunip, sizeof(stunip), 0);
- ice_cfg.stun_tp[0].server = pj_str(stunip);
- ice_cfg.stun_tp[0].port =
- pj_sockaddr_get_port(&pjsua_var.stun_srv);
+ if (pj_sockaddr_has_addr(&pjsua_var.stun_srv)) {
+ pj_sockaddr_print(&pjsua_var.stun_srv, stunip,
+ sizeof(stunip), 0);
}
- /* Configure max host candidates */
- if (acc_cfg->ice_cfg.ice_max_host_cands >= 0) {
- for (i = 0; i < ice_cfg.stun_tp_cnt; ++i)
+ for (i = 0; i < ice_cfg.stun_tp_cnt; ++i) {
+ pj_str_t IN6_ADDR_ANY = {"0", 1};
+
+ /* Configure STUN server */
+ if (pj_sockaddr_has_addr(&pjsua_var.stun_srv) &&
+ pjsua_media_acc_is_using_stun(call_med->call->acc_id))
+ {
+ ice_cfg.stun_tp[i].server = pj_str(stunip);
+ ice_cfg.stun_tp[i].port = pj_sockaddr_get_port(
+ &pjsua_var.stun_srv);
+ }
+
+ /* Configure max host candidates */
+ if (acc_cfg->ice_cfg.ice_max_host_cands >= 0) {
ice_cfg.stun_tp[i].max_host_cands =
acc_cfg->ice_cfg.ice_max_host_cands;
- }
+ }
- /* Configure binding address */
- pj_sockaddr_init(ice_cfg.stun_tp[0].af,
- &ice_cfg.stun_tp[0].cfg.bound_addr,
- &cfg->bound_addr, (pj_uint16_t)cfg->port);
- ice_cfg.stun_tp[0].cfg.port_range = (pj_uint16_t)cfg->port_range;
- if (cfg->port != 0 && ice_cfg.stun_tp[0].cfg.port_range == 0) {
- ice_cfg.stun_tp[0].cfg.port_range =
+ /* Configure binding address */
+ pj_sockaddr_init(ice_cfg.stun_tp[i].af,
+ &ice_cfg.stun_tp[i].cfg.bound_addr,
+ (ice_cfg.stun_tp[i].af == pj_AF_INET()?
+ &cfg->bound_addr: &IN6_ADDR_ANY),
+ (pj_uint16_t)cfg->port);
+ ice_cfg.stun_tp[i].cfg.port_range = (pj_uint16_t)cfg->port_range;
+ if (cfg->port != 0 && ice_cfg.stun_tp[i].cfg.port_range == 0) {
+ ice_cfg.stun_tp[i].cfg.port_range =
(pj_uint16_t)(pjsua_var.ua_cfg.max_calls * 10);
- }
- if (use_ipv6 && ice_cfg.stun_tp_cnt > 1) {
- pj_str_t IN6_ADDR_ANY = {"0", 1};
- pj_sockaddr_init(pj_AF_INET6(),
- &ice_cfg.stun_tp[1].cfg.bound_addr,
- &IN6_ADDR_ANY, (pj_uint16_t)cfg->port);
- ice_cfg.stun_tp[1].cfg.port_range =
- ice_cfg.stun_tp[0].cfg.port_range;
- }
-
- /* Configure QoS setting */
- ice_cfg.stun_tp[0].cfg.qos_type = cfg->qos_type;
- pj_memcpy(&ice_cfg.stun_tp[0].cfg.qos_params, &cfg->qos_params,
- sizeof(cfg->qos_params));
- if (use_ipv6 && ice_cfg.stun_tp_cnt > 1) {
- ice_cfg.stun_tp[1].cfg.qos_type = cfg->qos_type;
- pj_memcpy(&ice_cfg.stun_tp[1].cfg.qos_params, &cfg->qos_params,
- sizeof(cfg->qos_params));
- }
+ }
- /* Configure max packet size */
- ice_cfg.stun_tp[0].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
- if (use_ipv6 && ice_cfg.stun_tp_cnt > 1)
- ice_cfg.stun_tp[1].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
+ /* Configure QoS setting */
+ ice_cfg.stun_tp[i].cfg.qos_type = cfg->qos_type;
+ pj_memcpy(&ice_cfg.stun_tp[i].cfg.qos_params, &cfg->qos_params,
+ sizeof(cfg->qos_params));
+ /* Configure max packet size */
+ ice_cfg.stun_tp[i].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
+ }
}
/* Configure TURN settings */
if (acc_cfg->turn_cfg.enable_turn) {
- ice_cfg.turn_tp_cnt = 1;
- pj_ice_strans_turn_cfg_default(&ice_cfg.turn_tp[0]);
- if (use_ipv6 && PJ_ICE_MAX_TURN >= 3) {
- ice_cfg.turn_tp_cnt = 3;
+ unsigned i, idx = 0;
+
+ if (use_ipv6 && !use_nat64 && PJ_ICE_MAX_TURN >= 3) {
+ ice_cfg.turn_tp_cnt = 3;
+ idx = 1;
+ } else {
+ ice_cfg.turn_tp_cnt = 1;
+ }
+
+ for (i = 0; i < ice_cfg.turn_tp_cnt; i++)
+ pj_ice_strans_turn_cfg_default(&ice_cfg.turn_tp[i]);
- pj_ice_strans_turn_cfg_default(&ice_cfg.turn_tp[1]);
- ice_cfg.turn_tp[1].af = pj_AF_INET6();
+ if (use_ipv6 || use_nat64) {
+ if (!use_nat64)
+ ice_cfg.turn_tp[idx++].af = pj_AF_INET6();
/* Additional candidate: IPv4 relay via IPv6 TURN server */
- pj_ice_strans_turn_cfg_default(&ice_cfg.turn_tp[2]);
- ice_cfg.turn_tp[2].af = pj_AF_INET6();
- ice_cfg.turn_tp[2].alloc_param.af = pj_AF_INET();
+ ice_cfg.turn_tp[idx].af = pj_AF_INET6();
+ ice_cfg.turn_tp[idx].alloc_param.af = pj_AF_INET();
}
/* Configure TURN server */
@@ -947,72 +970,38 @@ static pj_status_t create_ice_media_transport(
return PJ_EINVAL;
}
- /* Configure TURN connection settings and credential */
if (ice_cfg.turn_tp[0].port == 0)
ice_cfg.turn_tp[0].port = 3479;
- ice_cfg.turn_tp[0].conn_type = acc_cfg->turn_cfg.turn_conn_type;
- pj_memcpy(&ice_cfg.turn_tp[0].auth_cred,
- &acc_cfg->turn_cfg.turn_auth_cred,
- sizeof(ice_cfg.turn_tp[0].auth_cred));
-
- if (use_ipv6 && ice_cfg.turn_tp_cnt > 1) {
- ice_cfg.turn_tp[1].server = ice_cfg.turn_tp[0].server;
- ice_cfg.turn_tp[1].port = ice_cfg.turn_tp[0].port;
- ice_cfg.turn_tp[1].conn_type = ice_cfg.turn_tp[0].conn_type;
- pj_memcpy(&ice_cfg.turn_tp[1].auth_cred,
- &acc_cfg->turn_cfg.turn_auth_cred,
- sizeof(ice_cfg.turn_tp[1].auth_cred));
- ice_cfg.turn_tp[2].server = ice_cfg.turn_tp[0].server;
- ice_cfg.turn_tp[2].port = ice_cfg.turn_tp[0].port;
- ice_cfg.turn_tp[2].conn_type = ice_cfg.turn_tp[0].conn_type;
- pj_memcpy(&ice_cfg.turn_tp[2].auth_cred,
- &acc_cfg->turn_cfg.turn_auth_cred,
- sizeof(ice_cfg.turn_tp[2].auth_cred));
- }
+ for (i = 0; i < ice_cfg.turn_tp_cnt; i++) {
+ pj_str_t IN6_ADDR_ANY = {"0", 1};
- /* Configure QoS setting */
- ice_cfg.turn_tp[0].cfg.qos_type = cfg->qos_type;
- pj_memcpy(&ice_cfg.turn_tp[0].cfg.qos_params, &cfg->qos_params,
- sizeof(cfg->qos_params));
- if (use_ipv6 && ice_cfg.turn_tp_cnt > 1) {
- ice_cfg.turn_tp[1].cfg.qos_type = cfg->qos_type;
- pj_memcpy(&ice_cfg.turn_tp[1].cfg.qos_params, &cfg->qos_params,
- sizeof(cfg->qos_params));
+ /* Configure TURN connection settings and credential */
+ ice_cfg.turn_tp[i].server = ice_cfg.turn_tp[0].server;
+ ice_cfg.turn_tp[i].port = ice_cfg.turn_tp[0].port;
+ ice_cfg.turn_tp[i].conn_type = acc_cfg->turn_cfg.turn_conn_type;
+ pj_memcpy(&ice_cfg.turn_tp[i].auth_cred,
+ &acc_cfg->turn_cfg.turn_auth_cred,
+ sizeof(ice_cfg.turn_tp[i].auth_cred));
- ice_cfg.turn_tp[2].cfg.qos_type = cfg->qos_type;
- pj_memcpy(&ice_cfg.turn_tp[2].cfg.qos_params, &cfg->qos_params,
+ /* Configure QoS setting */
+ ice_cfg.turn_tp[i].cfg.qos_type = cfg->qos_type;
+ pj_memcpy(&ice_cfg.turn_tp[i].cfg.qos_params, &cfg->qos_params,
sizeof(cfg->qos_params));
- }
- /* Configure binding address */
- pj_sockaddr_init(ice_cfg.turn_tp[0].af, &ice_cfg.turn_tp[0].cfg.bound_addr,
- &cfg->bound_addr, (pj_uint16_t)cfg->port);
- ice_cfg.turn_tp[0].cfg.port_range = (pj_uint16_t)cfg->port_range;
- if (cfg->port != 0 && ice_cfg.turn_tp[0].cfg.port_range == 0)
- ice_cfg.turn_tp[0].cfg.port_range =
+ /* Configure binding address */
+ pj_sockaddr_init(ice_cfg.turn_tp[i].af,
+ &ice_cfg.turn_tp[i].cfg.bound_addr,
+ (ice_cfg.turn_tp[i].af == pj_AF_INET()?
+ &cfg->bound_addr: &IN6_ADDR_ANY),
+ (pj_uint16_t)cfg->port);
+ ice_cfg.turn_tp[i].cfg.port_range = (pj_uint16_t)cfg->port_range;
+ if (cfg->port != 0 && ice_cfg.turn_tp[i].cfg.port_range == 0)
+ ice_cfg.turn_tp[i].cfg.port_range =
(pj_uint16_t)(pjsua_var.ua_cfg.max_calls * 10);
- if (use_ipv6 && ice_cfg.turn_tp_cnt > 1) {
- pj_str_t IN6_ADDR_ANY = {"0", 1};
- pj_sockaddr_init(pj_AF_INET6(),
- &ice_cfg.turn_tp[1].cfg.bound_addr,
- &IN6_ADDR_ANY, (pj_uint16_t)cfg->port);
- ice_cfg.turn_tp[1].cfg.port_range =
- ice_cfg.turn_tp[0].cfg.port_range;
-
- pj_sockaddr_init(pj_AF_INET6(),
- &ice_cfg.turn_tp[2].cfg.bound_addr,
- &IN6_ADDR_ANY, (pj_uint16_t)cfg->port);
- ice_cfg.turn_tp[2].cfg.port_range =
- ice_cfg.turn_tp[0].cfg.port_range;
- }
-
- /* Configure max packet size */
- ice_cfg.turn_tp[0].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
- if (use_ipv6 && ice_cfg.turn_tp_cnt > 1) {
- ice_cfg.turn_tp[1].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
- ice_cfg.turn_tp[2].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
+ /* Configure max packet size */
+ ice_cfg.turn_tp[i].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
}
}
@@ -1259,6 +1248,7 @@ static void sort_media(const pjmedia_sdp_session *sdp,
for (i=0; i<sdp->media_count && count<PJSUA_MAX_CALL_MEDIA; ++i) {
const pjmedia_sdp_media *m = sdp->media[i];
const pjmedia_sdp_conn *c;
+ static const pj_str_t ID_RTP_SAVP = { "RTP/SAVP", 8 };
/* Skip different media */
if (pj_stricmp(&m->desc.media, type) != 0) {
@@ -1269,7 +1259,7 @@ static void sort_media(const pjmedia_sdp_session *sdp,
c = m->conn? m->conn : sdp->conn;
/* Supported transports */
- if (pj_stricmp2(&m->desc.transport, "RTP/SAVP")==0) {
+ if (pj_stristr(&m->desc.transport, &ID_RTP_SAVP)) {
switch (use_srtp) {
case PJMEDIA_SRTP_MANDATORY:
case PJMEDIA_SRTP_OPTIONAL:
@@ -1478,6 +1468,34 @@ void pjsua_set_media_tp_state(pjsua_call_media *call_med,
call_med->tp_st = tp_st;
}
+
+/* This callback is called when SRTP negotiation completes */
+static void on_srtp_nego_complete(pjmedia_transport *tp,
+ pj_status_t result)
+{
+ pjsua_call_media *call_med = (pjsua_call_media*)tp->user_data;
+ pjsua_call *call;
+
+ if (!call_med)
+ return;
+
+ call = call_med->call;
+ PJ_PERROR(4,(THIS_FILE, result,
+ "Call %d: Media %d: SRTP negotiation completes",
+ call->index, call_med->idx));
+
+ if (result != PJ_SUCCESS) {
+ call_med->state = PJSUA_CALL_MEDIA_ERROR;
+ call_med->dir = PJMEDIA_DIR_NONE;
+ if (call && pjsua_var.ua_cfg.cb.on_call_media_state) {
+ /* Defer the callback to a timer */
+ pjsua_schedule_timer2(&ice_failed_nego_cb,
+ (void*)(pj_ssize_t)call->index, 1);
+ }
+ }
+}
+
+
/* Callback to resume pjsua_call_media_init() after media transport
* creation is completed.
*/
@@ -1531,6 +1549,8 @@ static pj_status_t call_media_init_cb(pjsua_call_media *call_med,
/* Always create SRTP adapter */
pjmedia_srtp_setting_default(&srtp_opt);
srtp_opt.close_member_tp = PJ_TRUE;
+ srtp_opt.cb.on_srtp_nego_complete = &on_srtp_nego_complete;
+ srtp_opt.user_data = call_med;
/* If media session has been ever established, let's use remote's
* preference in SRTP usage policy, especially when it is stricter.
@@ -1985,7 +2005,9 @@ pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
*/
sort_media2(call->media_prov, call->med_prov_cnt,
PJMEDIA_TYPE_AUDIO, maudidx, &maudcnt, &mtotaudcnt);
- pj_assert(maudcnt > 0);
+
+ /* No need to assert if there's no media. */
+ //pj_assert(maudcnt > 0);
sort_media2(call->media_prov, call->med_prov_cnt,
PJMEDIA_TYPE_VIDEO, mvididx, &mvidcnt, &mtotvidcnt);
@@ -2347,13 +2369,16 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
/* Add connection line, if none */
if (m->conn == NULL && sdp->conn == NULL) {
pj_bool_t use_ipv6;
+ pj_bool_t use_nat64;
use_ipv6 = (pjsua_var.acc[call->acc_id].cfg.ipv6_media_use !=
PJSUA_IPV6_DISABLED);
+ use_nat64 = (pjsua_var.acc[call->acc_id].cfg.nat64_opt !=
+ PJSUA_NAT64_DISABLED);
m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
m->conn->net_type = pj_str("IN");
- if (use_ipv6) {
+ if (use_ipv6 && !use_nat64) {
m->conn->addr_type = pj_str("IP6");
m->conn->addr = pj_str("::1");
} else {
@@ -2534,11 +2559,17 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
static void stop_media_stream(pjsua_call *call, unsigned med_idx)
{
- pjsua_call_media *call_med = &call->media[med_idx];
-
- /* Check if stream does not exist */
- if (med_idx >= call->med_cnt)
- return;
+ pjsua_call_media *call_med;
+
+ if (pjsua_call_media_is_changing(call)) {
+ call_med = &call->media_prov[med_idx];
+ if (med_idx >= call->med_prov_cnt)
+ return;
+ } else {
+ call_med = &call->media[med_idx];
+ if (med_idx >= call->med_cnt)
+ return;
+ }
pj_log_push_indent();
@@ -3000,7 +3031,7 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
call_med->state = PJSUA_CALL_MEDIA_NONE;
call_med->dir = PJMEDIA_DIR_NONE;
- } else {
+ } else if (call_med->tp) {
pjmedia_transport_info tp_info;
pjmedia_srtp_info *srtp_info;
@@ -3158,7 +3189,7 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
call_med->state = PJSUA_CALL_MEDIA_NONE;
call_med->dir = PJMEDIA_DIR_NONE;
- } else {
+ } else if (call_med->tp) {
pjmedia_transport_info tp_info;
pjmedia_srtp_info *srtp_info;
diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c
index ddf6359..b8668c7 100644
--- a/pjsip/src/pjsua-lib/pjsua_pres.c
+++ b/pjsip/src/pjsua-lib/pjsua_pres.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_pres.c 5279 2016-04-20 01:45:47Z ming $ */
+/* $Id: pjsua_pres.c 5561 2017-03-02 01:56:32Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny at prijono.org>
@@ -1890,6 +1890,7 @@ static void subscribe_buddy_presence(pjsua_buddy_id buddy_id)
/* Set authentication preference */
pjsip_auth_clt_set_prefs(&buddy->dlg->auth_sess, &acc->cfg.auth_pref);
+ pjsip_evsub_add_header(buddy->sub, &acc->cfg.sub_hdr_list);
pjsip_evsub_set_mod_data(buddy->sub, pjsua_var.mod.id, buddy);
status = pjsip_pres_initiate(buddy->sub, -1, &tdata);
diff --git a/pjsip/src/pjsua-lib/pjsua_vid.c b/pjsip/src/pjsua-lib/pjsua_vid.c
index b3a131c..fc78ad5 100644
--- a/pjsip/src/pjsua-lib/pjsua_vid.c
+++ b/pjsip/src/pjsua-lib/pjsua_vid.c
@@ -1,4 +1,4 @@
-/* $Id: pjsua_vid.c 5410 2016-08-05 07:26:18Z riza $ */
+/* $Id: pjsua_vid.c 5660 2017-09-25 03:17:42Z riza $ */
/*
* Copyright (C) 2011-2011 Teluu Inc. (http://www.teluu.com)
*
@@ -75,6 +75,15 @@ pj_status_t pjsua_vid_subsys_init(void)
goto on_error;
}
+#if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_VID_TOOLBOX_CODEC
+ status = pjmedia_codec_vid_toolbox_init(NULL, &pjsua_var.cp.factory);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status,
+ "Error initializing Video Toolbox codec"));
+ goto on_error;
+ }
+#endif
+
#if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_OPENH264_CODEC
status = pjmedia_codec_openh264_vid_init(NULL, &pjsua_var.cp.factory);
if (status != PJ_SUCCESS) {
@@ -144,6 +153,10 @@ pj_status_t pjsua_vid_subsys_destroy(void)
pjmedia_codec_ffmpeg_vid_deinit();
#endif
+#if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_VID_TOOLBOX_CODEC
+ pjmedia_codec_vid_toolbox_deinit();
+#endif
+
#if defined(PJMEDIA_HAS_OPENH264_CODEC) && PJMEDIA_HAS_OPENH264_CODEC != 0
pjmedia_codec_openh264_vid_deinit();
#endif
@@ -1029,7 +1042,7 @@ pj_status_t pjsua_vid_channel_update(pjsua_call_media *call_med,
/* Setup encoding direction */
if (si->dir & PJMEDIA_DIR_ENCODING && !call->local_hold)
{
- pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id];
+ pjsua_acc *acc_enc = &pjsua_var.acc[call_med->call->acc_id];
pjsua_vid_win *w;
pjsua_vid_win_id wid;
pj_bool_t just_created = PJ_FALSE;
@@ -1057,10 +1070,8 @@ pj_status_t pjsua_vid_channel_update(pjsua_call_media *call_med,
&media_port->info.fmt,
call_med->strm.v.rdr_dev,
call_med->strm.v.cap_dev,
- //acc->cfg.vid_rend_dev,
- //acc->cfg.vid_cap_dev,
PJSUA_HIDE_WINDOW,
- acc->cfg.vid_wnd_flags,
+ acc_enc->cfg.vid_wnd_flags,
NULL,
&wid);
if (status != PJ_SUCCESS) {
@@ -1173,7 +1184,8 @@ void pjsua_vid_stop_stream(pjsua_call_media *call_med)
}
if ((call_med->dir & PJMEDIA_DIR_ENCODING) &&
- (pjmedia_vid_stream_get_stat(strm, &stat) == PJ_SUCCESS))
+ (pjmedia_vid_stream_get_stat(strm, &stat) == PJ_SUCCESS) &&
+ stat.tx.pkt)
{
/* Save RTP timestamp & sequence, so when media session is
* restarted, those values will be restored as the initial
diff --git a/pjsip/src/pjsua2/account.cpp b/pjsip/src/pjsua2/account.cpp
index cfa6559..02404c5 100644
--- a/pjsip/src/pjsua2/account.cpp
+++ b/pjsip/src/pjsua2/account.cpp
@@ -1,4 +1,4 @@
-/* $Id: account.cpp 5466 2016-10-21 07:40:47Z nanang $ */
+/* $Id: account.cpp 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
*
@@ -184,6 +184,7 @@ void AccountNatConfig::readObject(const ContainerNode &node) throw(Error)
NODE_READ_NUM_T ( this_node, pjsua_stun_use, sipStunUse);
NODE_READ_NUM_T ( this_node, pjsua_stun_use, mediaStunUse);
+ NODE_READ_NUM_T ( this_node, pjsua_nat64_opt, nat64Opt);
NODE_READ_BOOL ( this_node, iceEnabled);
NODE_READ_INT ( this_node, iceMaxHostCands);
NODE_READ_BOOL ( this_node, iceAggressiveNomination);
@@ -215,6 +216,7 @@ void AccountNatConfig::writeObject(ContainerNode &node) const throw(Error)
NODE_WRITE_NUM_T ( this_node, pjsua_stun_use, sipStunUse);
NODE_WRITE_NUM_T ( this_node, pjsua_stun_use, mediaStunUse);
+ NODE_WRITE_NUM_T ( this_node, pjsua_nat64_opt, nat64Opt);
NODE_WRITE_BOOL ( this_node, iceEnabled);
NODE_WRITE_INT ( this_node, iceMaxHostCands);
NODE_WRITE_BOOL ( this_node, iceAggressiveNomination);
@@ -297,6 +299,25 @@ void AccountVideoConfig::writeObject(ContainerNode &node) const throw(Error)
NODE_WRITE_UNSIGNED( this_node, startKeyframeCount);
NODE_WRITE_UNSIGNED( this_node, startKeyframeInterval);
}
+///////////////////////////////////////////////////////////////////////////////
+
+void AccountIpChangeConfig::readObject(const ContainerNode &node) throw(Error)
+{
+ ContainerNode this_node = node.readContainer("AccountIpChangeConfig");
+
+ NODE_READ_BOOL ( this_node, shutdownTp);
+ NODE_READ_BOOL ( this_node, hangupCalls);
+ NODE_READ_UNSIGNED( this_node, reinviteFlags);
+}
+
+void AccountIpChangeConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+ ContainerNode this_node = node.writeNewContainer("AccountIpChangeConfig");
+
+ NODE_WRITE_BOOL ( this_node, shutdownTp);
+ NODE_WRITE_BOOL ( this_node, hangupCalls);
+ NODE_WRITE_UNSIGNED( this_node, reinviteFlags);
+}
///////////////////////////////////////////////////////////////////////////////
@@ -391,6 +412,7 @@ void AccountConfig::toPj(pjsua_acc_config &ret) const
// AccountNatConfig
ret.sip_stun_use = natConfig.sipStunUse;
ret.media_stun_use = natConfig.mediaStunUse;
+ ret.nat64_opt = natConfig.nat64Opt;
ret.ice_cfg_use = PJSUA_ICE_CONFIG_USE_CUSTOM;
ret.ice_cfg.enable_ice = natConfig.iceEnabled;
ret.ice_cfg.ice_max_host_cands = natConfig.iceMaxHostCands;
@@ -442,6 +464,11 @@ void AccountConfig::toPj(pjsua_acc_config &ret) const
ret.vid_stream_rc_cfg.bandwidth = videoConfig.rateControlBandwidth;
ret.vid_stream_sk_cfg.count = videoConfig.startKeyframeCount;
ret.vid_stream_sk_cfg.interval = videoConfig.startKeyframeInterval;
+
+ // AccountIpChangeConfig
+ ret.ip_change_cfg.shutdown_tp = ipChangeConfig.shutdownTp;
+ ret.ip_change_cfg.hangup_calls = ipChangeConfig.hangupCalls;
+ ret.ip_change_cfg.reinvite_flags = ipChangeConfig.reinviteFlags;
}
/* Initialize from pjsip. */
@@ -534,6 +561,7 @@ void AccountConfig::fromPj(const pjsua_acc_config &prm,
// AccountNatConfig
natConfig.sipStunUse = prm.sip_stun_use;
natConfig.mediaStunUse = prm.media_stun_use;
+ natConfig.nat64Opt = prm.nat64_opt;
if (prm.ice_cfg_use == PJSUA_ICE_CONFIG_USE_CUSTOM) {
natConfig.iceEnabled = PJ2BOOL(prm.ice_cfg.enable_ice);
natConfig.iceMaxHostCands = prm.ice_cfg.ice_max_host_cands;
@@ -610,6 +638,11 @@ void AccountConfig::fromPj(const pjsua_acc_config &prm,
videoConfig.rateControlBandwidth = prm.vid_stream_rc_cfg.bandwidth;
videoConfig.startKeyframeCount = prm.vid_stream_sk_cfg.count;
videoConfig.startKeyframeInterval = prm.vid_stream_sk_cfg.interval;
+
+ // AccountIpChangeConfig
+ ipChangeConfig.shutdownTp = PJ2BOOL(prm.ip_change_cfg.shutdown_tp);
+ ipChangeConfig.hangupCalls = PJ2BOOL(prm.ip_change_cfg.hangup_calls);
+ ipChangeConfig.reinviteFlags = prm.ip_change_cfg.reinvite_flags;
}
void AccountConfig::readObject(const ContainerNode &node) throw(Error)
diff --git a/pjsip/src/pjsua2/call.cpp b/pjsip/src/pjsua2/call.cpp
index 5393490..81c1731 100644
--- a/pjsip/src/pjsua2/call.cpp
+++ b/pjsip/src/pjsua2/call.cpp
@@ -1,4 +1,4 @@
-/* $Id: call.cpp 5240 2016-02-04 09:31:01Z nanang $ */
+/* $Id: call.cpp 5645 2017-09-06 03:44:35Z riza $ */
/*
* Copyright (C) 2012-2013 Teluu Inc. (http://www.teluu.com)
*
@@ -296,7 +296,7 @@ void StreamInfo::fromPj(const pjsua_stream_info &info)
rxPt = info.info.aud.rx_pt;
codecName = pj2Str(info.info.aud.fmt.encoding_name);
codecClockRate = info.info.aud.fmt.clock_rate;
- codecParam = info.info.aud.param;
+ audCodecParam.fromPj(*info.info.aud.param);
} else if (type == PJMEDIA_TYPE_VIDEO) {
proto = info.info.vid.proto;
dir = info.info.vid.dir;
@@ -307,8 +307,8 @@ void StreamInfo::fromPj(const pjsua_stream_info &info)
txPt = info.info.vid.tx_pt;
rxPt = info.info.vid.rx_pt;
codecName = pj2Str(info.info.vid.codec_info.encoding_name);
- codecClockRate = info.info.vid.codec_info.clock_rate;
- codecParam = info.info.vid.codec_param;
+ codecClockRate = info.info.vid.codec_info.clock_rate;
+ vidCodecParam.fromPj(*info.info.vid.codec_param);
}
}
diff --git a/pjsip/src/pjsua2/endpoint.cpp b/pjsip/src/pjsua2/endpoint.cpp
index 690ce02..b796840 100644
--- a/pjsip/src/pjsua2/endpoint.cpp
+++ b/pjsip/src/pjsua2/endpoint.cpp
@@ -1,4 +1,4 @@
-/* $Id: endpoint.cpp 5522 2017-01-11 11:13:57Z ming $ */
+/* $Id: endpoint.cpp 5649 2017-09-15 05:32:08Z riza $ */
/*
* Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
*
@@ -84,6 +84,8 @@ void TlsInfo::fromPj(const pjsip_tls_state_info &info)
for (unsigned i = 0; i < verif_msg_cnt; ++i) {
verifyMsgs.push_back(verif_msgs[i]);
}
+#else
+ PJ_UNUSED_ARG(info);
#endif
}
@@ -120,7 +122,33 @@ void SslCertInfo::fromPj(const pj_ssl_cert_info &info)
}
///////////////////////////////////////////////////////////////////////////////
+IpChangeParam::IpChangeParam()
+{
+ pjsua_ip_change_param param;
+ pjsua_ip_change_param_default(¶m);
+ fromPj(param);
+}
+
+
+pjsua_ip_change_param IpChangeParam::toPj() const
+{
+ pjsua_ip_change_param param;
+ pjsua_ip_change_param_default(¶m);
+ param.restart_listener = restartListener;
+ param.restart_lis_delay = restartLisDelay;
+
+ return param;
+}
+
+
+void IpChangeParam::fromPj(const pjsua_ip_change_param ¶m)
+{
+ restartListener = PJ2BOOL(param.restart_listener);
+ restartLisDelay = param.restart_lis_delay;
+}
+
+///////////////////////////////////////////////////////////////////////////////
UaConfig::UaConfig()
: mainThreadOnly(false)
{
@@ -146,6 +174,7 @@ void UaConfig::fromPj(const pjsua_config &ua_cfg)
this->stunServer.push_back(pj2Str(ua_cfg.stun_srv[i]));
}
+ this->stunTryIpv6 = PJ2BOOL(ua_cfg.stun_try_ipv6);
this->stunIgnoreFailure = PJ2BOOL(ua_cfg.stun_ignore_failure);
this->natTypeInSdp = ua_cfg.nat_type_in_sdp;
this->mwiUnsolicitedEnabled = PJ2BOOL(ua_cfg.enable_unsolicited_mwi);
@@ -192,6 +221,7 @@ void UaConfig::readObject(const ContainerNode &node) throw(Error)
NODE_READ_STRINGV ( this_node, nameserver);
NODE_READ_STRING ( this_node, userAgent);
NODE_READ_STRINGV ( this_node, stunServer);
+ NODE_READ_BOOL ( this_node, stunTryIpv6);
NODE_READ_BOOL ( this_node, stunIgnoreFailure);
NODE_READ_INT ( this_node, natTypeInSdp);
NODE_READ_BOOL ( this_node, mwiUnsolicitedEnabled);
@@ -207,6 +237,7 @@ void UaConfig::writeObject(ContainerNode &node) const throw(Error)
NODE_WRITE_STRINGV ( this_node, nameserver);
NODE_WRITE_STRING ( this_node, userAgent);
NODE_WRITE_STRINGV ( this_node, stunServer);
+ NODE_WRITE_BOOL ( this_node, stunTryIpv6);
NODE_WRITE_BOOL ( this_node, stunIgnoreFailure);
NODE_WRITE_INT ( this_node, natTypeInSdp);
NODE_WRITE_BOOL ( this_node, mwiUnsolicitedEnabled);
@@ -1393,7 +1424,7 @@ void Endpoint::on_create_media_transport_srtp(pjsua_call_id call_id,
call->onCreateMediaTransportSrtp(prm);
srtp_opt->use = prm.srtpUse;
- srtp_opt->crypto_count = prm.cryptos.size();
+ srtp_opt->crypto_count = (unsigned)prm.cryptos.size();
for (unsigned i = 0; i < srtp_opt->crypto_count; i++) {
srtp_opt->crypto[i].key = str2Pj(prm.cryptos[i].key);
srtp_opt->crypto[i].name = str2Pj(prm.cryptos[i].name);
@@ -1401,6 +1432,43 @@ void Endpoint::on_create_media_transport_srtp(pjsua_call_id call_id,
}
}
+void Endpoint::on_ip_change_progress(pjsua_ip_change_op op,
+ pj_status_t status,
+ const pjsua_ip_change_op_info *info)
+{
+ Endpoint &ep = Endpoint::instance();
+ OnIpChangeProgressParam param;
+
+ param.op = op;
+ param.status = status;
+ switch (op) {
+ case PJSUA_IP_CHANGE_OP_RESTART_LIS:
+ param.transportId = info->lis_restart.transport_id;
+ break;
+ case PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP:
+ param.accId = info->acc_shutdown_tp.acc_id;
+ break;
+ case PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT:
+ param.accId = info->acc_update_contact.acc_id;
+ param.regInfo.code = info->acc_update_contact.code;
+ param.regInfo.isRegister =
+ PJ2BOOL(info->acc_update_contact.is_register);
+ break;
+ case PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS:
+ param.accId = info->acc_hangup_calls.acc_id;
+ param.callId = info->acc_hangup_calls.call_id;
+ break;
+ case PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS:
+ param.accId = info->acc_reinvite_calls.acc_id;
+ param.callId = info->acc_reinvite_calls.call_id;
+ break;
+ default:
+ param.accId = PJSUA_INVALID_ID;
+ break;
+ }
+ ep.onIpChangeProgress(param);
+}
+
///////////////////////////////////////////////////////////////////////////////
/*
* Endpoint library operations
@@ -1463,6 +1531,7 @@ void Endpoint::libInit(const EpConfig &prmEpConfig) throw(Error)
ua_cfg.cb.on_mwi_info = &Endpoint::on_mwi_info;
ua_cfg.cb.on_buddy_state = &Endpoint::on_buddy_state;
ua_cfg.cb.on_acc_find_for_incoming = &Endpoint::on_acc_find_for_incoming;
+ ua_cfg.cb.on_ip_change_progress = &Endpoint::on_ip_change_progress;
/* Call callbacks */
ua_cfg.cb.on_call_state = &Endpoint::on_call_state;
@@ -1877,21 +1946,23 @@ void Endpoint::codecSetPriority(const string &codec_id,
CodecParam Endpoint::codecGetParam(const string &codec_id) const throw(Error)
{
- pjmedia_codec_param *pj_param = NULL;
+ CodecParam param;
+ pjmedia_codec_param pj_param;
pj_str_t codec_str = str2Pj(codec_id);
- PJSUA2_CHECK_EXPR( pjsua_codec_get_param(&codec_str, pj_param) );
+ PJSUA2_CHECK_EXPR( pjsua_codec_get_param(&codec_str, &pj_param) );
- return pj_param;
+ param.fromPj(pj_param);
+ return param;
}
void Endpoint::codecSetParam(const string &codec_id,
const CodecParam param) throw(Error)
{
pj_str_t codec_str = str2Pj(codec_id);
- pjmedia_codec_param *pj_param = (pjmedia_codec_param*)param;
+ pjmedia_codec_param pj_param = param.toPj();
- PJSUA2_CHECK_EXPR( pjsua_codec_set_param(&codec_str, pj_param) );
+ PJSUA2_CHECK_EXPR( pjsua_codec_set_param(&codec_str, &pj_param) );
}
void Endpoint::clearCodecInfoList(CodecInfoVector &codec_list)
@@ -1981,3 +2052,9 @@ void Endpoint::resetVideoCodecParam(const string &codec_id) throw(Error)
PJ_UNUSED_ARG(codec_id);
#endif
}
+
+void Endpoint::handleIpChange(const IpChangeParam ¶m) throw(Error)
+{
+ pjsua_ip_change_param ip_change_param = param.toPj();
+ PJSUA2_CHECK_EXPR(pjsua_handle_ip_change(&ip_change_param));
+}
diff --git a/pjsip/src/pjsua2/media.cpp b/pjsip/src/pjsua2/media.cpp
index c3d89e5..9ac2f0b 100644
--- a/pjsip/src/pjsua2/media.cpp
+++ b/pjsip/src/pjsua2/media.cpp
@@ -1,4 +1,4 @@
-/* $Id: media.cpp 5273 2016-04-04 01:44:10Z riza $ */
+/* $Id: media.cpp 5654 2017-09-20 04:34:27Z riza $ */
/*
* Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
*
@@ -351,7 +351,7 @@ pj_uint32_t AudioMediaPlayer::getPos() const throw(Error)
{
pj_ssize_t pos = pjsua_player_get_pos(playerId);
if (pos < 0) {
- PJSUA2_RAISE_ERROR2(-pos, "AudioMediaPlayer::getPos()");
+ PJSUA2_RAISE_ERROR2((pj_status_t)-pos, "AudioMediaPlayer::getPos()");
}
return (pj_uint32_t)pos;
}
@@ -508,7 +508,7 @@ void ToneGenerator::play(const ToneDescVector &tones,
PJSUA2_RAISE_ERROR(PJ_EINVAL);
}
- status = pjmedia_tonegen_play(tonegen, tones.size(), &tones[0],
+ status = pjmedia_tonegen_play(tonegen, (unsigned)tones.size(), &tones[0],
loop? PJMEDIA_TONEGEN_LOOP : 0);
PJSUA2_CHECK_RAISE_ERROR2(status, "ToneGenerator::play()");
}
@@ -525,7 +525,7 @@ void ToneGenerator::playDigits(const ToneDigitVector &digits,
PJSUA2_RAISE_ERROR(PJ_EINVAL);
}
- status = pjmedia_tonegen_play_digits(tonegen, digits.size(), &digits[0],
+ status = pjmedia_tonegen_play_digits(tonegen, (unsigned)digits.size(), &digits[0],
loop? PJMEDIA_TONEGEN_LOOP : 0);
PJSUA2_CHECK_RAISE_ERROR2(status, "ToneGenerator::playDigits()");
}
@@ -571,7 +571,7 @@ void ToneGenerator::setDigitMap(const ToneDigitMapVector &digit_map)
PJSUA2_RAISE_ERROR(PJ_EINVALIDOP);
}
- digitMap.count = digit_map.size();
+ digitMap.count = (unsigned)digit_map.size();
if (digitMap.count > PJ_ARRAY_SIZE(digitMap.digits))
digitMap.count = PJ_ARRAY_SIZE(digitMap.digits);
@@ -598,20 +598,15 @@ void AudioDevInfo::fromPj(const pjmedia_aud_dev_info &dev_info)
routes = dev_info.routes;
for (unsigned i=0; i<dev_info.ext_fmt_cnt;++i) {
- MediaFormatAudio *format = new MediaFormatAudio;
-
- format->fromPj(dev_info.ext_fmt[i]);
- if (format->type == PJMEDIA_TYPE_AUDIO)
+ MediaFormatAudio format;
+ format.fromPj(dev_info.ext_fmt[i]);
+ if (format.type == PJMEDIA_TYPE_AUDIO)
extFmt.push_back(format);
}
}
AudioDevInfo::~AudioDevInfo()
{
- for(unsigned i=0;i<extFmt.size();++i) {
- delete extFmt[i];
- }
- extFmt.clear();
}
///////////////////////////////////////////////////////////////////////////////
@@ -1264,10 +1259,9 @@ void VideoDevInfo::fromPj(const pjmedia_vid_dev_info &dev_info)
caps = dev_info.caps;
for (unsigned i = 0; i<dev_info.fmt_cnt;++i) {
- MediaFormatVideo *format = new MediaFormatVideo;
-
- format->fromPj(dev_info.fmt[i]);
- if (format->type == PJMEDIA_TYPE_VIDEO)
+ MediaFormatVideo format;
+ format.fromPj(dev_info.fmt[i]);
+ if (format.type == PJMEDIA_TYPE_VIDEO)
fmt.push_back(format);
}
#else
@@ -1277,12 +1271,6 @@ void VideoDevInfo::fromPj(const pjmedia_vid_dev_info &dev_info)
VideoDevInfo::~VideoDevInfo()
{
-#if PJSUA_HAS_VIDEO
- for (unsigned i = 0;i<fmt.size();++i) {
- delete fmt[i];
- }
- fmt.clear();
-#endif
}
///////////////////////////////////////////////////////////////////////////////
@@ -1527,6 +1515,43 @@ VidDevManager::~VidDevManager()
}
///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Utility class for converting CodecFmtpVector to and from pjmedia_codec_fmtp.
+ */
+class CodecFmtpUtil
+{
+public:
+ static void fromPj(const pjmedia_codec_fmtp &in_fmtp,
+ CodecFmtpVector &out_fmtp)
+ {
+ unsigned i = 0;
+ for (; i<in_fmtp.cnt; ++i) {
+ CodecFmtp fmtp;
+ fmtp.name = pj2Str(in_fmtp.param[i].name);
+ fmtp.val = pj2Str(in_fmtp.param[i].val);
+
+ out_fmtp.push_back(fmtp);
+ }
+ }
+
+ static void toPj(const CodecFmtpVector &in_fmtp,
+ pjmedia_codec_fmtp &out_fmtp)
+ {
+ CodecFmtpVector::const_iterator i;
+ out_fmtp.cnt = 0;
+ for (i = in_fmtp.begin(); i != in_fmtp.end(); ++i) {
+ if (out_fmtp.cnt >= PJMEDIA_CODEC_MAX_FMTP_CNT) {
+ break;
+ }
+ out_fmtp.param[out_fmtp.cnt].name = str2Pj((*i).name);
+ out_fmtp.param[out_fmtp.cnt].val = str2Pj((*i).val);
+ ++out_fmtp.cnt;
+ }
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
void CodecInfo::fromPj(const pjsua_codec_info &codec_info)
{
codecId = pj2Str(codec_info.codec_id);
@@ -1534,6 +1559,59 @@ void CodecInfo::fromPj(const pjsua_codec_info &codec_info)
desc = pj2Str(codec_info.desc);
}
+///////////////////////////////////////////////////////////////////////////////
+void CodecParam::fromPj(const pjmedia_codec_param ¶m)
+{
+ /* info part. */
+ info.clockRate = param.info.clock_rate;
+ info.channelCnt = param.info.channel_cnt;
+ info.avgBps = param.info.avg_bps;
+ info.maxBps = param.info.max_bps;
+ info.maxRxFrameSize = param.info.max_rx_frame_size;
+ info.frameLen = param.info.frm_ptime;
+ info.pcmBitsPerSample = param.info.pcm_bits_per_sample;
+ info.pt = param.info.pt;
+ info.fmtId = param.info.fmt_id;
+
+ /* setting part. */
+ setting.frmPerPkt = param.setting.frm_per_pkt;
+ setting.vad = param.setting.vad;
+ setting.cng = param.setting.cng;
+ setting.penh = param.setting.penh;
+ setting.plc = param.setting.plc;
+ setting.reserved = param.setting.reserved;
+ CodecFmtpUtil::fromPj(param.setting.enc_fmtp, setting.encFmtp);
+ CodecFmtpUtil::fromPj(param.setting.dec_fmtp, setting.decFmtp);
+}
+
+pjmedia_codec_param CodecParam::toPj() const
+{
+ pjmedia_codec_param param;
+
+ /* info part. */
+ param.info.clock_rate = info.clockRate;
+ param.info.channel_cnt = info.channelCnt;
+ param.info.avg_bps = (pj_uint32_t)info.avgBps;
+ param.info.max_bps= (pj_uint32_t)info.maxBps;
+ param.info.max_rx_frame_size = info.maxRxFrameSize;
+ param.info.frm_ptime = (pj_uint16_t)info.frameLen;
+ param.info.pcm_bits_per_sample = (pj_uint8_t)info.pcmBitsPerSample;
+ param.info.pt = (pj_uint8_t)info.pt;
+ param.info.fmt_id = info.fmtId;
+
+ /* setting part. */
+ param.setting.frm_per_pkt = (pj_uint8_t)setting.frmPerPkt;
+ param.setting.vad = setting.vad;
+ param.setting.cng = setting.cng;
+ param.setting.penh = setting.penh;
+ param.setting.plc = setting.plc;
+ param.setting.reserved = setting.reserved;
+ CodecFmtpUtil::toPj(setting.encFmtp, param.setting.enc_fmtp);
+ CodecFmtpUtil::toPj(setting.decFmtp, param.setting.dec_fmtp);
+ return param;
+}
+
+///////////////////////////////////////////////////////////////////////////////
void VidCodecParam::fromPj(const pjmedia_vid_codec_param ¶m)
{
dir = param.dir;
@@ -1542,8 +1620,8 @@ void VidCodecParam::fromPj(const pjmedia_vid_codec_param ¶m)
encMtu = param.enc_mtu;
encFmt.fromPj(param.enc_fmt);
decFmt.fromPj(param.dec_fmt);
- setCodecFmtp(param.enc_fmtp, encFmtp);
- setCodecFmtp(param.dec_fmtp, decFmtp);
+ CodecFmtpUtil::fromPj(param.enc_fmtp, encFmtp);
+ CodecFmtpUtil::fromPj(param.dec_fmtp, decFmtp);
}
pjmedia_vid_codec_param VidCodecParam::toPj() const
@@ -1556,35 +1634,8 @@ pjmedia_vid_codec_param VidCodecParam::toPj() const
param.enc_mtu = encMtu;
param.enc_fmt = encFmt.toPj();
param.dec_fmt = decFmt.toPj();
- getCodecFmtp(encFmtp, param.enc_fmtp);
- getCodecFmtp(decFmtp, param.dec_fmtp);
+ CodecFmtpUtil::toPj(encFmtp, param.enc_fmtp);
+ CodecFmtpUtil::toPj(decFmtp, param.dec_fmtp);
return param;
}
-void VidCodecParam::setCodecFmtp(const pjmedia_codec_fmtp &in_fmtp,
- CodecFmtpVector &out_fmtp)
-{
- unsigned i = 0;
- for ( ; i<in_fmtp.cnt; ++i) {
- CodecFmtp fmtp;
- fmtp.name = pj2Str(in_fmtp.param[i].name);
- fmtp.val = pj2Str(in_fmtp.param[i].val);
-
- out_fmtp.push_back(fmtp);
- }
-}
-
-void VidCodecParam::getCodecFmtp(const CodecFmtpVector &in_fmtp,
- pjmedia_codec_fmtp &out_fmtp) const
-{
- CodecFmtpVector::const_iterator i;
- out_fmtp.cnt = 0;
- for (i=in_fmtp.begin(); i!=in_fmtp.end();++i) {
- if (out_fmtp.cnt >= PJMEDIA_CODEC_MAX_FMTP_CNT) {
- break;
- }
- out_fmtp.param[out_fmtp.cnt].name = str2Pj((*i).name);
- out_fmtp.param[out_fmtp.cnt].val = str2Pj((*i).val);
- ++out_fmtp.cnt;
- }
-}
diff --git a/pjsip/src/pjsua2/util.hpp b/pjsip/src/pjsua2/util.hpp
index cc99a0e..16ef002 100644
--- a/pjsip/src/pjsua2/util.hpp
+++ b/pjsip/src/pjsua2/util.hpp
@@ -1,4 +1,4 @@
-/* $Id: util.hpp 4704 2014-01-16 05:30:46Z ming $ */
+/* $Id: util.hpp 5601 2017-06-08 04:57:59Z nanang $ */
/*
* Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
*
@@ -36,7 +36,7 @@ inline pj_str_t str2Pj(const string &input_str)
inline string pj2Str(const pj_str_t &input_str)
{
- if (input_str.ptr)
+ if (input_str.ptr && input_str.slen>0)
return string(input_str.ptr, input_str.slen);
return string();
}
diff --git a/third_party/build/gsm/config.h b/third_party/build/gsm/config.h
index d01ab0f..cdb8dcc 100644
--- a/third_party/build/gsm/config.h
+++ b/third_party/build/gsm/config.h
@@ -10,6 +10,7 @@
#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 402
# pragma GCC diagnostic ignored "-Wpragmas"
# pragma GCC diagnostic ignored "-Wunused-const-variable"
+# pragma GCC diagnostic ignored "-Wshift-negative-value"
#endif
#include <string.h>
diff --git a/third_party/build/os-auto.mak.in b/third_party/build/os-auto.mak.in
index 3f83b81..22defec 100644
--- a/third_party/build/os-auto.mak.in
+++ b/third_party/build/os-auto.mak.in
@@ -11,7 +11,15 @@ ifneq (@ac_no_ilbc_codec@,1)
DIRS += ilbc
endif
-ifneq (@ac_no_speex_codec@,1)
+# Exclude Speex?
+EXCLUDE_SPEEX = 0
+ifeq (@ac_no_speex_codec@,1)
+ifneq (@ac_no_speex_aec@,)
+EXCLUDE_SPEEX = 1
+endif
+endif
+
+ifneq ($(EXCLUDE_SPEEX),1)
ifeq (@ac_external_speex@,1)
# External speex
else
@@ -31,22 +39,22 @@ else
endif
endif
-ifeq (@ac_external_srtp@,1)
+ifneq (@ac_external_srtp@,0)
# External SRTP
else
DIRS += srtp
ifeq (@ac_ssl_has_aes_gcm@,0)
CIPHERS_SRC = crypto/cipher/aes.o crypto/cipher/aes_icm.o \
- crypto/cipher/aes_cbc.o
+ # crypto/cipher/aes_cbc.o
HASHES_SRC = crypto/hash/sha1.o crypto/hash/hmac.o \
# crypto/hash/tmmhv2.o
-RNG_SRC = crypto/rng/rand_source.o crypto/rng/prng.o \
- crypto/rng/ctr_prng.o
+RNG_SRC = # crypto/rng/rand_source.o crypto/rng/prng.o \
+ # crypto/rng/ctr_prng.o
else
CIPHERS_SRC = crypto/cipher/aes_icm_ossl.o crypto/cipher/aes_gcm_ossl.o
HASHES_SRC = crypto/hash/hmac_ossl.o
-RNG_SRC = crypto/rng/rand_source_ossl.o
+RNG_SRC = # crypto/rng/rand_source_ossl.o
SRTP_OTHER_CFLAGS = -DOPENSSL
endif
diff --git a/third_party/build/speex/config.h b/third_party/build/speex/config.h
index 6c6545f..0f0f2d9 100644
--- a/third_party/build/speex/config.h
+++ b/third_party/build/speex/config.h
@@ -27,11 +27,13 @@
# pragma warning(disable: 4305) // truncation from 'const double ' to 'float '
# pragma warning(disable: 4018) // signed/unsigned mismatch
# pragma warning(disable: 4456) // declaration of '[var]' hides previous local declaration
+# pragma warning(disable: 4267) // conversion from 'size_t' to 'int', possible loss of data
//# pragma warning(disable: 4701) // local variable used without initialized
#endif
#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 402
# pragma GCC diagnostic ignored "-Wpragmas"
+# pragma GCC diagnostic ignored "-Wunknown-warning-option"
# pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif
diff --git a/third_party/build/srtp/libsrtp.vcproj b/third_party/build/srtp/libsrtp.vcproj
index 67fd15d..9964476 100644
--- a/third_party/build/srtp/libsrtp.vcproj
+++ b/third_party/build/srtp/libsrtp.vcproj
@@ -3137,10 +3137,6 @@
>
</File>
<File
- RelativePath="..\..\srtp\include\rtp.h"
- >
- </File>
- <File
RelativePath="..\..\srtp\include\srtp.h"
>
</File>
@@ -3162,14 +3158,224 @@
<File
RelativePath="..\..\srtp\crypto\cipher\aes.c"
>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
</File>
<File
- RelativePath="..\..\srtp\crypto\cipher\aes_cbc.c"
+ RelativePath="..\..\srtp\crypto\cipher\aes_gcm_ossl.c"
>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Static|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Static|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Dynamic|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Dynamic|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Dynamic|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Dynamic|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Static|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Static|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
</File>
<File
RelativePath="..\..\srtp\crypto\cipher\aes_icm.c"
>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\srtp\crypto\cipher\aes_icm_ossl.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Static|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Static|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Dynamic|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Dynamic|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Dynamic|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Dynamic|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Static|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Static|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
</File>
<File
RelativePath="..\..\srtp\crypto\cipher\cipher.c"
@@ -3190,6 +3396,113 @@
<File
RelativePath="..\..\srtp\crypto\hash\hmac.c"
>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\srtp\crypto\hash\hmac_ossl.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Static|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Static|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Dynamic|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Dynamic|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Dynamic|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug-Dynamic|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Static|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release-Static|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
</File>
<File
RelativePath="..\..\srtp\crypto\hash\null_auth.c"
@@ -3198,6 +3511,13 @@
<File
RelativePath="..\..\srtp\crypto\hash\sha1.c"
>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
</File>
</Filter>
<Filter
@@ -3224,10 +3544,6 @@
>
</File>
<File
- RelativePath="..\..\srtp\crypto\math\gf2_8.c"
- >
- </File>
- <File
RelativePath="..\..\srtp\crypto\math\stat.c"
>
</File>
@@ -3252,10 +3568,6 @@
>
</File>
<File
- RelativePath="..\..\srtp\crypto\include\aes_cbc.h"
- >
- </File>
- <File
RelativePath="..\..\srtp\crypto\include\aes_icm.h"
>
</File>
@@ -3272,26 +3584,14 @@
>
</File>
<File
- RelativePath="..\..\srtp\crypto\include\crypto.h"
- >
- </File>
- <File
RelativePath="..\..\srtp\crypto\include\crypto_kernel.h"
>
</File>
<File
- RelativePath="..\..\srtp\crypto\include\crypto_math.h"
- >
- </File>
- <File
RelativePath="..\..\srtp\crypto\include\crypto_types.h"
>
</File>
<File
- RelativePath="..\..\srtp\crypto\include\cryptoalg.h"
- >
- </File>
- <File
RelativePath="..\..\srtp\crypto\include\datatypes.h"
>
</File>
@@ -3300,10 +3600,6 @@
>
</File>
<File
- RelativePath="..\..\srtp\crypto\include\gf2_8.h"
- >
- </File>
- <File
RelativePath="..\..\srtp\crypto\include\hmac.h"
>
</File>
@@ -3312,10 +3608,6 @@
>
</File>
<File
- RelativePath="..\..\srtp\crypto\include\kernel_compat.h"
- >
- </File>
- <File
RelativePath="..\..\srtp\crypto\include\key.h"
>
</File>
@@ -3328,14 +3620,6 @@
>
</File>
<File
- RelativePath="..\..\srtp\crypto\include\prng.h"
- >
- </File>
- <File
- RelativePath="..\..\srtp\crypto\include\rand_source.h"
- >
- </File>
- <File
RelativePath="..\..\srtp\crypto\include\rdb.h"
>
</File>
@@ -3351,26 +3635,6 @@
RelativePath="..\..\srtp\crypto\include\stat.h"
>
</File>
- <File
- RelativePath="..\..\srtp\crypto\include\xfm.h"
- >
- </File>
- </Filter>
- <Filter
- Name="rng"
- >
- <File
- RelativePath="..\..\srtp\crypto\rng\ctr_prng.c"
- >
- </File>
- <File
- RelativePath="..\..\srtp\crypto\rng\prng.c"
- >
- </File>
- <File
- RelativePath="..\..\srtp\crypto\rng\rand_source.c"
- >
- </File>
</Filter>
</Filter>
</Files>
diff --git a/third_party/build/srtp/libsrtp.vcxproj b/third_party/build/srtp/libsrtp.vcxproj
index a19b2a9..adc1dab 100644
--- a/third_party/build/srtp/libsrtp.vcxproj
+++ b/third_party/build/srtp/libsrtp.vcxproj
@@ -493,7 +493,6 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\srtp\crypto\cipher\aes.c" />
- <ClCompile Include="..\..\srtp\crypto\cipher\aes_cbc.c" />
<ClCompile Include="..\..\srtp\crypto\cipher\aes_gcm_ossl.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-Static|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@@ -568,66 +567,33 @@
</ClCompile>
<ClCompile Include="..\..\srtp\crypto\kernel\key.c" />
<ClCompile Include="..\..\srtp\crypto\math\datatypes.c" />
- <ClCompile Include="..\..\srtp\crypto\math\gf2_8.c" />
<ClCompile Include="..\..\srtp\crypto\math\stat.c" />
<ClCompile Include="..\..\srtp\crypto\replay\rdb.c" />
<ClCompile Include="..\..\srtp\crypto\replay\rdbx.c" />
- <ClCompile Include="..\..\srtp\crypto\rng\ctr_prng.c" />
- <ClCompile Include="..\..\srtp\crypto\rng\prng.c" />
- <ClCompile Include="..\..\srtp\crypto\rng\rand_source.c" />
- <ClCompile Include="..\..\srtp\crypto\rng\rand_source_ossl.c">
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-Static|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-Dynamic|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-Static|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-Dynamic|Win32'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-Static|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-Dynamic|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-Static|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-Dynamic|x64'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-Static|ARM'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-Dynamic|ARM'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-Static|ARM'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release-Dynamic|ARM'">true</ExcludedFromBuild>
- </ClCompile>
<ClCompile Include="..\..\srtp\pjlib\srtp_err.c" />
<ClCompile Include="..\..\srtp\srtp\srtp.c" />
<ClCompile Include="..\..\srtp\srtp\ekt.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\srtp\crypto\include\aes.h" />
- <ClInclude Include="..\..\srtp\crypto\include\aes_cbc.h" />
<ClInclude Include="..\..\srtp\crypto\include\aes_icm.h" />
<ClInclude Include="..\..\srtp\crypto\include\alloc.h" />
<ClInclude Include="..\..\srtp\crypto\include\auth.h" />
<ClInclude Include="..\..\srtp\crypto\include\cipher.h" />
- <ClInclude Include="..\..\srtp\crypto\include\crypto.h" />
- <ClInclude Include="..\..\srtp\crypto\include\cryptoalg.h" />
<ClInclude Include="..\..\srtp\crypto\include\crypto_kernel.h" />
- <ClInclude Include="..\..\srtp\crypto\include\crypto_math.h" />
<ClInclude Include="..\..\srtp\crypto\include\crypto_types.h" />
<ClInclude Include="..\..\srtp\crypto\include\datatypes.h" />
<ClInclude Include="..\..\srtp\crypto\include\err.h" />
- <ClInclude Include="..\..\srtp\crypto\include\gf2_8.h" />
<ClInclude Include="..\..\srtp\crypto\include\hmac.h" />
<ClInclude Include="..\..\srtp\crypto\include\integers.h" />
- <ClInclude Include="..\..\srtp\crypto\include\kernel_compat.h" />
<ClInclude Include="..\..\srtp\crypto\include\key.h" />
<ClInclude Include="..\..\srtp\crypto\include\null_auth.h" />
<ClInclude Include="..\..\srtp\crypto\include\null_cipher.h" />
- <ClInclude Include="..\..\srtp\crypto\include\prng.h" />
- <ClInclude Include="..\..\srtp\crypto\include\rand_source.h" />
<ClInclude Include="..\..\srtp\crypto\include\rdb.h" />
<ClInclude Include="..\..\srtp\crypto\include\rdbx.h" />
<ClInclude Include="..\..\srtp\crypto\include\sha1.h" />
<ClInclude Include="..\..\srtp\crypto\include\stat.h" />
<ClInclude Include="..\..\srtp\include\ekt.h" />
- <ClInclude Include="..\..\srtp\include\rtp.h" />
<ClInclude Include="..\..\srtp\include\srtp.h" />
<ClInclude Include="..\..\srtp\include\ut_sim.h" />
<ClInclude Include="srtp_config.h" />
diff --git a/third_party/build/srtp/libsrtp.vcxproj.filters b/third_party/build/srtp/libsrtp.vcxproj.filters
index ad25a6d..6f0223a 100644
--- a/third_party/build/srtp/libsrtp.vcxproj.filters
+++ b/third_party/build/srtp/libsrtp.vcxproj.filters
@@ -30,9 +30,6 @@
<Filter Include="crypto\include">
<UniqueIdentifier>{b4cf0314-f1bd-44d6-ad75-187c4b03c5c3}</UniqueIdentifier>
</Filter>
- <Filter Include="crypto\rng">
- <UniqueIdentifier>{101639e1-fe64-435f-8428-4c647132ad40}</UniqueIdentifier>
- </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\srtp\srtp\srtp.c">
@@ -44,9 +41,6 @@
<ClCompile Include="..\..\srtp\crypto\cipher\aes.c">
<Filter>crypto\cipher</Filter>
</ClCompile>
- <ClCompile Include="..\..\srtp\crypto\cipher\aes_cbc.c">
- <Filter>crypto\cipher</Filter>
- </ClCompile>
<ClCompile Include="..\..\srtp\crypto\cipher\aes_icm.c">
<Filter>crypto\cipher</Filter>
</ClCompile>
@@ -80,9 +74,6 @@
<ClCompile Include="..\..\srtp\crypto\math\datatypes.c">
<Filter>crypto\math</Filter>
</ClCompile>
- <ClCompile Include="..\..\srtp\crypto\math\gf2_8.c">
- <Filter>crypto\math</Filter>
- </ClCompile>
<ClCompile Include="..\..\srtp\crypto\math\stat.c">
<Filter>crypto\math</Filter>
</ClCompile>
@@ -92,15 +83,6 @@
<ClCompile Include="..\..\srtp\crypto\replay\rdbx.c">
<Filter>crypto\replay</Filter>
</ClCompile>
- <ClCompile Include="..\..\srtp\crypto\rng\ctr_prng.c">
- <Filter>crypto\rng</Filter>
- </ClCompile>
- <ClCompile Include="..\..\srtp\crypto\rng\prng.c">
- <Filter>crypto\rng</Filter>
- </ClCompile>
- <ClCompile Include="..\..\srtp\crypto\rng\rand_source.c">
- <Filter>crypto\rng</Filter>
- </ClCompile>
<ClCompile Include="..\..\srtp\srtp\ekt.c">
<Filter>Source Files</Filter>
</ClCompile>
@@ -113,14 +95,8 @@
<ClCompile Include="..\..\srtp\crypto\hash\hmac_ossl.c">
<Filter>crypto\hash</Filter>
</ClCompile>
- <ClCompile Include="..\..\srtp\crypto\rng\rand_source_ossl.c">
- <Filter>crypto\rng</Filter>
- </ClCompile>
</ItemGroup>
<ItemGroup>
- <ClInclude Include="..\..\srtp\include\rtp.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="..\..\srtp\include\srtp.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -133,9 +109,6 @@
<ClInclude Include="..\..\srtp\crypto\include\aes.h">
<Filter>crypto\include</Filter>
</ClInclude>
- <ClInclude Include="..\..\srtp\crypto\include\aes_cbc.h">
- <Filter>crypto\include</Filter>
- </ClInclude>
<ClInclude Include="..\..\srtp\crypto\include\aes_icm.h">
<Filter>crypto\include</Filter>
</ClInclude>
@@ -148,39 +121,24 @@
<ClInclude Include="..\..\srtp\crypto\include\cipher.h">
<Filter>crypto\include</Filter>
</ClInclude>
- <ClInclude Include="..\..\srtp\crypto\include\crypto.h">
- <Filter>crypto\include</Filter>
- </ClInclude>
<ClInclude Include="..\..\srtp\crypto\include\crypto_kernel.h">
<Filter>crypto\include</Filter>
</ClInclude>
- <ClInclude Include="..\..\srtp\crypto\include\crypto_math.h">
- <Filter>crypto\include</Filter>
- </ClInclude>
<ClInclude Include="..\..\srtp\crypto\include\crypto_types.h">
<Filter>crypto\include</Filter>
</ClInclude>
- <ClInclude Include="..\..\srtp\crypto\include\cryptoalg.h">
- <Filter>crypto\include</Filter>
- </ClInclude>
<ClInclude Include="..\..\srtp\crypto\include\datatypes.h">
<Filter>crypto\include</Filter>
</ClInclude>
<ClInclude Include="..\..\srtp\crypto\include\err.h">
<Filter>crypto\include</Filter>
</ClInclude>
- <ClInclude Include="..\..\srtp\crypto\include\gf2_8.h">
- <Filter>crypto\include</Filter>
- </ClInclude>
<ClInclude Include="..\..\srtp\crypto\include\hmac.h">
<Filter>crypto\include</Filter>
</ClInclude>
<ClInclude Include="..\..\srtp\crypto\include\integers.h">
<Filter>crypto\include</Filter>
</ClInclude>
- <ClInclude Include="..\..\srtp\crypto\include\kernel_compat.h">
- <Filter>crypto\include</Filter>
- </ClInclude>
<ClInclude Include="..\..\srtp\crypto\include\key.h">
<Filter>crypto\include</Filter>
</ClInclude>
@@ -190,12 +148,6 @@
<ClInclude Include="..\..\srtp\crypto\include\null_cipher.h">
<Filter>crypto\include</Filter>
</ClInclude>
- <ClInclude Include="..\..\srtp\crypto\include\prng.h">
- <Filter>crypto\include</Filter>
- </ClInclude>
- <ClInclude Include="..\..\srtp\crypto\include\rand_source.h">
- <Filter>crypto\include</Filter>
- </ClInclude>
<ClInclude Include="..\..\srtp\crypto\include\rdb.h">
<Filter>crypto\include</Filter>
</ClInclude>
diff --git a/third_party/build/srtp/srtp_config.h b/third_party/build/srtp/srtp_config.h
index cc53f57..b9d1172 100644
--- a/third_party/build/srtp/srtp_config.h
+++ b/third_party/build/srtp/srtp_config.h
@@ -1,4 +1,4 @@
-/* $Id: srtp_config.h 5261 2016-03-15 03:57:39Z nanang $ */
+/* $Id: srtp_config.h 5635 2017-08-01 07:49:34Z nanang $ */
/*
* Copyright (C) 2003-2007 Benny Prijono <benny at prijono.org>
*
@@ -137,15 +137,16 @@
# define inline _inline
# endif
-//# pragma warning(disable:4311)
+# pragma warning(disable:4311) // 'type cast': pointer truncation from 'unsigned char *' to 'unsigned long'
//# pragma warning(disable:4761) // integral mismatch
-//# pragma warning(disable:4018) // signed/unsigned mismatch
+# pragma warning(disable:4018) // '<' : signed/unsigned mismatch
# pragma warning(disable:4244) // conversion from int64 to int
# pragma warning(disable:4100) // unreferenced formal parameter
# pragma warning(disable:4214) // bit field types other than int
# pragma warning(disable:4389) // '!=' : signed/unsigned mismatch
# pragma warning(disable:4701) // potentially uninitialized local variable used
# pragma warning(disable:4702) // unreachable code
+# pragma warning(disable:4703) // potentially uninitialized local pointer variable used
#endif
/* clock() */
@@ -225,10 +226,10 @@
/* #undef size_t */
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "libsrtp 1.5.4"
+#define PACKAGE_STRING "libsrtp 2.1.0"
/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.5.4"
+#define PACKAGE_VERSION "2.1.0"
#endif /* __SRTP_CONFIG_H__ */
diff --git a/third_party/build/yuv/Makefile b/third_party/build/yuv/Makefile
index d9c3501..276e952 100644
--- a/third_party/build/yuv/Makefile
+++ b/third_party/build/yuv/Makefile
@@ -48,14 +48,14 @@ export YUV_OBJS = \
rotate.o \
rotate_common.o \
rotate_gcc.o \
- rotate_mips.o \
+ rotate_dspr2.o \
rotate_neon64.o \
rotate_neon.o \
rotate_win.o \
row_any.o \
row_common.o \
row_gcc.o \
- row_mips.o \
+ row_dspr2.o \
row_neon64.o \
row_neon.o \
row_win.o \
@@ -64,7 +64,7 @@ export YUV_OBJS = \
scale.o \
scale_common.o \
scale_gcc.o \
- scale_mips.o \
+ scale_dspr2.o \
scale_neon64.o \
scale_neon.o \
scale_win.o \
diff --git a/third_party/build/yuv/Notes.txt b/third_party/build/yuv/Notes.txt
index 52a8db9..e3c389e 100644
--- a/third_party/build/yuv/Notes.txt
+++ b/third_party/build/yuv/Notes.txt
@@ -1,5 +1,7 @@
Notes:
-* Source code for libyuv from https://chromium.googlesource.com/libyuv/libyuv/ dated 23 June 2016.
+
+* Source code for libyuv from https://chromium.googlesource.com/libyuv/libyuv/ dated 27 July 2017.
+
* All code is compilable, except for compare_win.cc
- Use older version (https://chromium.googlesource.com/libyuv/libyuv/+/baf6a3c1bd385e7ffe6b7634560e71fb49e4f589%5E%21/)
Since there's a compiler error on:
@@ -15,7 +17,14 @@ Notes:
__declspec(naked)
--------------------------------------------------------------------------------------
-* Disable some compiler warning which apear alot:
- - warning C4100: unreferenced formal parameter
- - warning C4127: conditional expression is constant
- - warning C4244: '=' : conversion from 'uint32' to 'uint8', possible loss of data
\ No newline at end of file
+
+* Added these lines to file include/libyuv/basic_types.h:
+ --
+ #if _MSC_VER==1400
+ # include <stdint.h> // for uint8_t
+ #endif
+ ...
+ #if defined(_MSC_VER)
+ # pragma warning(disable:4996) // This function or variable may be unsafe.
+ #endif
+ --
diff --git a/version.mak b/version.mak
index a03d0ac..01e6531 100644
--- a/version.mak
+++ b/version.mak
@@ -1,6 +1,6 @@
# Don't change the "export PJ_VERSION_xxx" style, they are parsed by setup.py
export PJ_VERSION_MAJOR := 2
-export PJ_VERSION_MINOR := 6
+export PJ_VERSION_MINOR := 7
export PJ_VERSION_REV :=
export PJ_VERSION_SUFFIX :=
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/pjproject.git
More information about the Pkg-voip-commits
mailing list