Compare commits
225 Commits
Author | SHA1 | Date |
---|---|---|
Perry Ismangil | ef4f1a7962 | |
Nanang Izzuddin | e1a49e9707 | |
Nanang Izzuddin | 484ef33f2a | |
Sauw Ming | 180571ca9b | |
Nanang Izzuddin | 75d644cb9c | |
Riza Sulistyo | 1b28148b58 | |
Nanang Izzuddin | 6d74e9bf8d | |
Riza Sulistyo | 14c9f87ff0 | |
Riza Sulistyo | 61d29933fb | |
Riza Sulistyo | 82e6c63042 | |
Riza Sulistyo | b9e110ac0f | |
Riza Sulistyo | 7e15a033b3 | |
Riza Sulistyo | feb5c59039 | |
Riza Sulistyo | 59c958dcda | |
Sauw Ming | 9024184b74 | |
Riza Sulistyo | f6eb3e66ff | |
Riza Sulistyo | 23f62f41fc | |
Riza Sulistyo | c9a2760650 | |
Riza Sulistyo | 9d43c9c538 | |
Riza Sulistyo | fdfbdf0455 | |
Sauw Ming | 591a5caf79 | |
Sauw Ming | d6372ce634 | |
Sauw Ming | c7e64ef672 | |
Sauw Ming | a2dbe98b0b | |
Sauw Ming | 06cb5fc792 | |
Sauw Ming | b91c3f689a | |
Sauw Ming | 864e7129e3 | |
Sauw Ming | 86b1195389 | |
Sauw Ming | b3362da1d9 | |
Sauw Ming | 2b53792c09 | |
Nanang Izzuddin | fa6ed22257 | |
Nanang Izzuddin | 6f520daa20 | |
Nanang Izzuddin | ff878537a4 | |
Nanang Izzuddin | 6a25762e3e | |
Nanang Izzuddin | 89dc94199c | |
Nanang Izzuddin | 61c42a0769 | |
Nanang Izzuddin | 6daad56e29 | |
Nanang Izzuddin | 9fd914b0d9 | |
Nanang Izzuddin | 0c23c41c80 | |
Nanang Izzuddin | a235c608ac | |
Nanang Izzuddin | 72d68ae915 | |
Sauw Ming | dfd18708e1 | |
Nanang Izzuddin | b43138ce99 | |
Nanang Izzuddin | 79fb3506ce | |
Sauw Ming | b4873f8a1f | |
Sauw Ming | 3d0dc6bb4e | |
Nanang Izzuddin | 4a32d88622 | |
Sauw Ming | de259d5b1c | |
Nanang Izzuddin | 6080ac4ccc | |
Nanang Izzuddin | 7e1a8756fe | |
Nanang Izzuddin | 2bbf301b1b | |
Nanang Izzuddin | e9984d9969 | |
Nanang Izzuddin | 413f7802b2 | |
Nanang Izzuddin | 05bf6b88f5 | |
Benny Prijono | 76ae4d5383 | |
Nanang Izzuddin | 17672b71a5 | |
Nanang Izzuddin | f47f0bb63a | |
Nanang Izzuddin | a50f513484 | |
Nanang Izzuddin | 665ca37a5d | |
Nanang Izzuddin | ef6e6bdc49 | |
Benny Prijono | c6b4404efe | |
Benny Prijono | 7256578581 | |
Benny Prijono | 8cdfe3c9b2 | |
Benny Prijono | e9b50574aa | |
Nanang Izzuddin | ac0d2e22ae | |
Nanang Izzuddin | bfe43ff6cc | |
Benny Prijono | c0a2e0ae8d | |
Benny Prijono | 761d27ebf4 | |
Benny Prijono | 2c6c6f3fe5 | |
Benny Prijono | e539af61fc | |
Sauw Ming | 06271acf5a | |
Sauw Ming | ffe509ef22 | |
Sauw Ming | 0bef1aba2a | |
Nanang Izzuddin | 168308f986 | |
Benny Prijono | d7c9c30696 | |
Benny Prijono | c50297e31a | |
Nanang Izzuddin | ae93d09763 | |
Benny Prijono | 8e9c6e155b | |
Benny Prijono | 4d3be48784 | |
Nanang Izzuddin | 448f23a045 | |
Nanang Izzuddin | bf1be63d75 | |
Benny Prijono | 15d1719fbc | |
Benny Prijono | f1e64e5d43 | |
Benny Prijono | 1bfa740df3 | |
Nanang Izzuddin | 724fef1964 | |
Benny Prijono | 41a3ea908e | |
Nanang Izzuddin | 27d72771e5 | |
Nanang Izzuddin | bc983ad574 | |
Nanang Izzuddin | 3afc159959 | |
Benny Prijono | 1830ad187e | |
Nanang Izzuddin | d878b9269a | |
Sauw Ming | 71eb919763 | |
Nanang Izzuddin | 9810d54ea5 | |
Benny Prijono | b601e5a6a4 | |
Benny Prijono | a5b50d048a | |
Benny Prijono | 736059b495 | |
Benny Prijono | dbceba6cfa | |
Nanang Izzuddin | eefc7830ec | |
Benny Prijono | 318ccc316b | |
Benny Prijono | 22ae142460 | |
Benny Prijono | 71d74d51b1 | |
Nanang Izzuddin | 9fb9efdd2b | |
Nanang Izzuddin | 6b20937730 | |
Nanang Izzuddin | 9c9f099d5c | |
Nanang Izzuddin | 187b757b20 | |
Benny Prijono | a4126d1a94 | |
Benny Prijono | 59a994df3f | |
Benny Prijono | 28fdeea9e3 | |
Benny Prijono | fe82212205 | |
Benny Prijono | b3dc6fab7e | |
Nanang Izzuddin | 5429ca6f28 | |
Benny Prijono | 962d393ccd | |
Nanang Izzuddin | 06f998cb27 | |
Nanang Izzuddin | 470934aa27 | |
Nanang Izzuddin | 218b4618a5 | |
Nanang Izzuddin | efc8f666b5 | |
Nanang Izzuddin | a096d0c8c9 | |
Benny Prijono | 609c74fd35 | |
Benny Prijono | f0bd919a16 | |
Benny Prijono | 7432ad4d83 | |
Benny Prijono | 397441c03e | |
Benny Prijono | 67725b6260 | |
Benny Prijono | 62ee76adad | |
Benny Prijono | feb5acabc3 | |
Sauw Ming | 3eab787335 | |
Sauw Ming | 7f8dece6aa | |
Benny Prijono | ae0ec278ac | |
Benny Prijono | 0d3236cc3f | |
Benny Prijono | ae05b0e4fd | |
Benny Prijono | b00ed24a3e | |
Benny Prijono | 683d2a99b3 | |
Nanang Izzuddin | dd63449940 | |
Nanang Izzuddin | 7b3bf326b9 | |
Sauw Ming | b63b96cdda | |
Sauw Ming | 17fd38e141 | |
Benny Prijono | 6350a3e117 | |
Benny Prijono | ac28148a96 | |
Sauw Ming | 23fc90f71e | |
Sauw Ming | b42ec89256 | |
Benny Prijono | 262cb5fbef | |
Benny Prijono | 579935cffa | |
Benny Prijono | 0227c7a743 | |
Benny Prijono | e4e63d9e01 | |
Benny Prijono | dbf587f70e | |
Benny Prijono | f425fcb8f9 | |
Benny Prijono | 866c27ae73 | |
Benny Prijono | f69e2dac7b | |
Sauw Ming | cbdaa61cfc | |
Benny Prijono | 3e7d5b4daa | |
Sauw Ming | 5983428785 | |
Sauw Ming | e9d79557f6 | |
Sauw Ming | c658ab4d2f | |
Benny Prijono | bd81d171ea | |
Benny Prijono | 5c476dee84 | |
Benny Prijono | 0519f34aac | |
Nanang Izzuddin | 263ef2cdcc | |
Nanang Izzuddin | 4543316a5d | |
Nanang Izzuddin | 9f0f0fc58c | |
Benny Prijono | f5c62bdc8c | |
Benny Prijono | 5bf3e706e5 | |
Nanang Izzuddin | 34dd20dc54 | |
Benny Prijono | c8102910bf | |
Nanang Izzuddin | 76ce26e72e | |
Benny Prijono | 85e4c0e85e | |
Benny Prijono | ed138ae919 | |
Benny Prijono | 81d0acde01 | |
Benny Prijono | a3cd35091a | |
Benny Prijono | 6e475c1909 | |
Benny Prijono | 47244d8172 | |
Benny Prijono | 7e25d1b9ab | |
Benny Prijono | 2c9fa16c2d | |
Benny Prijono | 6108e28bd8 | |
Benny Prijono | b65fa69a07 | |
Benny Prijono | 1efdead3ce | |
Benny Prijono | 9fe479c531 | |
Benny Prijono | da58910013 | |
Nanang Izzuddin | 3ff64a70a4 | |
Benny Prijono | 8a0218aeea | |
Benny Prijono | 9b6228b080 | |
Benny Prijono | 3203c13e08 | |
Nanang Izzuddin | bc44d51965 | |
Benny Prijono | 0331a1bc11 | |
Benny Prijono | 8a160ef8eb | |
Benny Prijono | 17bf5ffa18 | |
Benny Prijono | fe8d972113 | |
Benny Prijono | ec520b8a55 | |
Benny Prijono | d7e0c75f64 | |
Sauw Ming | 39bf2fab53 | |
Sauw Ming | 855af302a6 | |
Benny Prijono | 233f308f3c | |
Perry Ismangil | b42cd1b681 | |
Perry Ismangil | d1289453fe | |
Sauw Ming | f6e1d07739 | |
Benny Prijono | 521b9f2fc0 | |
Benny Prijono | 8585cf8e69 | |
Nanang Izzuddin | e4875da904 | |
Benny Prijono | cc4410de58 | |
Benny Prijono | 6042a50a28 | |
Benny Prijono | 6d03afcc19 | |
Benny Prijono | 95cd3edd7b | |
Benny Prijono | 755deb6cfc | |
Nanang Izzuddin | 2da084fab9 | |
Benny Prijono | d87d3d1217 | |
Nanang Izzuddin | 9b138c6480 | |
Benny Prijono | 3a3bb957e5 | |
Nanang Izzuddin | d4726c1aee | |
Nanang Izzuddin | 59386d6386 | |
Nanang Izzuddin | c5ec3efcc9 | |
Nanang Izzuddin | 9c1737180a | |
Sauw Ming | 3ecaee38b3 | |
Benny Prijono | d90596de10 | |
Benny Prijono | 29063b1bad | |
Benny Prijono | 32040808f1 | |
Nanang Izzuddin | 63c0077c7b | |
Sauw Ming | faefe7cfb2 | |
Sauw Ming | 30024e3ec6 | |
Benny Prijono | e3f4038db2 | |
Nanang Izzuddin | 4995e24f62 | |
Nanang Izzuddin | f73b12a82f | |
Sauw Ming | b6bcfd5557 | |
Sauw Ming | e90d9c21ed | |
Benny Prijono | 39523ed980 | |
Benny Prijono | 416910f464 | |
Benny Prijono | 53fd6b4518 | |
Benny Prijono | 65f48a11ce |
4
Makefile
4
Makefile
|
@ -1,6 +1,7 @@
|
|||
include build.mak
|
||||
include build/host-$(HOST_NAME).mak
|
||||
-include user.mak
|
||||
include version.mak
|
||||
|
||||
DIRS = pjlib/build pjlib-util/build pjnath/build third_party/build pjmedia/build pjsip/build pjsip-apps/build $(EXTRA_DIRS)
|
||||
|
||||
|
@ -23,7 +24,7 @@ doc:
|
|||
exit 1; \
|
||||
fi
|
||||
for dir in $(DIRS); do \
|
||||
if $(MAKE) $(MAKE_FLAGS) -C $$dir/build $@; then \
|
||||
if $(MAKE) $(MAKE_FLAGS) -C $$dir $@; then \
|
||||
true; \
|
||||
else \
|
||||
exit 1; \
|
||||
|
@ -92,7 +93,6 @@ pjsua-test:
|
|||
cd tests/pjsua && python runall.py
|
||||
|
||||
prefix = $(ac_prefix)
|
||||
include version.mak
|
||||
|
||||
install:
|
||||
mkdir -p $(DESTDIR)$(prefix)/lib
|
||||
|
|
131
aconfigure
131
aconfigure
|
@ -596,10 +596,14 @@ ac_main_obj
|
|||
ac_host
|
||||
ac_linux_poll
|
||||
ac_cross_compile
|
||||
opencore_amrnb_present
|
||||
opencore_amrnb_h_present
|
||||
ac_no_opencore_amrnb
|
||||
libcrypto_present
|
||||
libssl_present
|
||||
openssl_h_present
|
||||
ac_no_ssl
|
||||
ac_resample_dll
|
||||
ac_no_ilbc_codec
|
||||
ac_no_speex_codec
|
||||
ac_no_g7221_codec
|
||||
|
@ -621,6 +625,7 @@ ac_os_objs
|
|||
EGREP
|
||||
GREP
|
||||
CPP
|
||||
ac_shlib_suffix
|
||||
ac_build_mak_vars
|
||||
ac_pjdir
|
||||
CC_CFLAGS
|
||||
|
@ -716,11 +721,13 @@ enable_g7221_codec
|
|||
enable_speex_codec
|
||||
enable_ilbc_codec
|
||||
enable_libsamplerate
|
||||
enable_resample_dll
|
||||
enable_ipp
|
||||
with_ipp
|
||||
with_ipp_samples
|
||||
with_ipp_arch
|
||||
enable_ssl
|
||||
enable_opencore_amrnb
|
||||
'
|
||||
ac_precious_vars='build_alias
|
||||
host_alias
|
||||
|
@ -1368,12 +1375,17 @@ Optional Features:
|
|||
--disable-ilbc-codec Exclude iLBC codec in the build
|
||||
--enable-libsamplerate Link with libsamplerate when available. Note that
|
||||
PJMEDIA_RESAMPLE_IMP must also be configured
|
||||
--enable-resample-dll Build libresample as shared library
|
||||
--enable-ipp Enable Intel IPP support. Specify the Intel IPP
|
||||
package and samples location using IPPROOT and
|
||||
IPPSAMPLES env var or with --with-ipp and
|
||||
--with-ipp-samples options
|
||||
--disable-ssl Exclude SSL support the build (default: autodetect)
|
||||
|
||||
--disable-opencore-amrnb
|
||||
Exclude OpenCORE AMR-NB support from the build
|
||||
(default: autodetect)
|
||||
|
||||
|
||||
Optional Packages:
|
||||
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
||||
|
@ -3439,7 +3451,7 @@ if test "$AR" = ""; then AR="${CROSS_COMPILE}ar rv"; fi
|
|||
|
||||
if test "$LD" = ""; then LD="$CC"; fi
|
||||
|
||||
if test "$LDOUT" = ""; then LDOUT="-o"; fi
|
||||
if test "$LDOUT" = ""; then LDOUT="-o "; fi
|
||||
|
||||
if test "$RANLIB" = ""; then RANLIB="${CROSS_COMPILE}ranlib"; fi
|
||||
|
||||
|
@ -3449,7 +3461,7 @@ if test "$LIBEXT" = ""; then LIBEXT='a'; fi
|
|||
|
||||
if test "$LIBEXT2" = ""; then LIBEXT2=""; fi
|
||||
|
||||
if test "$CC_OUT" = ""; then CC_OUT="-o"; fi
|
||||
if test "$CC_OUT" = ""; then CC_OUT="-o "; fi
|
||||
|
||||
if test "$CC_INC" = ""; then CC_INC="-I"; fi
|
||||
|
||||
|
@ -3480,6 +3492,19 @@ case $host in
|
|||
esac
|
||||
|
||||
|
||||
case $target in
|
||||
*mingw* | *cygw* | *win32* | *w32* )
|
||||
ac_shlib_suffix=dll
|
||||
;;
|
||||
*darwin*)
|
||||
ac_shlib_suffix=dylib
|
||||
;;
|
||||
*)
|
||||
ac_shlib_suffix=so
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
|
||||
$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
|
||||
if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then :
|
||||
|
@ -4574,6 +4599,12 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
|
|||
esac
|
||||
|
||||
|
||||
if test "x$ac_cv_c_bigendian" = "xyes"; then
|
||||
CFLAGS="$CFLAGS -DPJ_IS_BIG_ENDIAN=1 -DPJ_IS_LITTLE_ENDIAN=0"
|
||||
else
|
||||
CFLAGS="$CFLAGS -DPJ_IS_BIG_ENDIAN=0 -DPJ_IS_LITTLE_ENDIAN=1"
|
||||
fi
|
||||
|
||||
case $target in
|
||||
*mingw* | *cygw* | *win32* | *w32* )
|
||||
$as_echo "#define PJ_WIN32 1" >>confdefs.h
|
||||
|
@ -5834,6 +5865,20 @@ fi
|
|||
|
||||
|
||||
|
||||
# Check whether --enable-resample_dll was given.
|
||||
if test "${enable_resample_dll+set}" = set; then :
|
||||
enableval=$enable_resample_dll; if test "$enable_resample_dll" = "yes"; then
|
||||
ac_resample_dll=1
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Building libresample as shared library... yes" >&5
|
||||
$as_echo "Building libresample as shared library... yes" >&6; }
|
||||
fi
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Building libresample as shared library... no" >&5
|
||||
$as_echo "Building libresample as shared library... no" >&6; }
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-ipp was given.
|
||||
if test "${enable_ipp+set}" = set; then :
|
||||
enableval=$enable_ipp;
|
||||
|
@ -5982,9 +6027,8 @@ $as_echo "ok" >&6; }
|
|||
else
|
||||
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
|
||||
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
|
||||
{ as_fn_set_status run with --help for more info
|
||||
as_fn_error "Error: unable to recognize your IPP installation. Make sure the paths and ARCH suffix are set correctly
|
||||
See \`config.log' for more details." "$LINENO" 5; }; }
|
||||
as_fn_error "Error: unable to recognize your IPP installation. Make sure the paths and ARCH suffix are set correctly, run with --help for more info
|
||||
See \`config.log' for more details." "$LINENO" 5; }
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
|
@ -6259,6 +6303,83 @@ fi
|
|||
|
||||
|
||||
|
||||
# Check whether --enable-opencore_amrnb was given.
|
||||
if test "${enable_opencore_amrnb+set}" = set; then :
|
||||
enableval=$enable_opencore_amrnb;
|
||||
if test "$enable_opencore_amrnb" = "no"; then
|
||||
ac_no_opencore_amrnb=1
|
||||
$as_echo "#define PJMEDIA_HAS_OPENCORE_AMRNB_CODEC 0" >>confdefs.h
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if OpenCORE AMR-NB support is disabled... yes" >&5
|
||||
$as_echo "Checking if OpenCORE AMR-NB support is disabled... yes" >&6; }
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: checking for OpenCORE AMR-NB installations.." >&5
|
||||
$as_echo "checking for OpenCORE AMR-NB installations.." >&6; }
|
||||
|
||||
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "opencore-amrnb/interf_enc.h" "ac_cv_header_opencore_amrnb_interf_enc_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_opencore_amrnb_interf_enc_h" = x""yes; then :
|
||||
opencore_amrnb_h_present=1
|
||||
fi
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Encoder_Interface_init in -lopencore-amrnb" >&5
|
||||
$as_echo_n "checking for Encoder_Interface_init in -lopencore-amrnb... " >&6; }
|
||||
if test "${ac_cv_lib_opencore_amrnb_Encoder_Interface_init+set}" = set; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lopencore-amrnb $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char Encoder_Interface_init ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return Encoder_Interface_init ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_opencore_amrnb_Encoder_Interface_init=yes
|
||||
else
|
||||
ac_cv_lib_opencore_amrnb_Encoder_Interface_init=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_opencore_amrnb_Encoder_Interface_init" >&5
|
||||
$as_echo "$ac_cv_lib_opencore_amrnb_Encoder_Interface_init" >&6; }
|
||||
if test "x$ac_cv_lib_opencore_amrnb_Encoder_Interface_init" = x""yes; then :
|
||||
opencore_amrnb_present=1 && LIBS="$LIBS -lopencore-amrnb"
|
||||
fi
|
||||
|
||||
if test "x$opencore_amrnb_h_present" = "x1" -a "x$opencore_amrnb_present" = "x1"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenCORE AMR-NB library found, AMR-NB support enabled" >&5
|
||||
$as_echo "OpenCORE AMR-NB library found, AMR-NB support enabled" >&6; }
|
||||
$as_echo "#define PJMEDIA_HAS_OPENCORE_AMRNB_CODEC 1" >>confdefs.h
|
||||
|
||||
else
|
||||
ac_no_opencore_amrnb=1
|
||||
$as_echo "#define PJMEDIA_HAS_OPENCORE_AMRNB_CODEC 0" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if select() needs correct nfds" >&5
|
||||
|
|
|
@ -52,7 +52,7 @@ if test "$AR" = ""; then AR="${CROSS_COMPILE}ar rv"; fi
|
|||
AC_SUBST(AR)
|
||||
if test "$LD" = ""; then LD="$CC"; fi
|
||||
AC_SUBST(LD)
|
||||
if test "$LDOUT" = ""; then LDOUT="-o"; fi
|
||||
if test "$LDOUT" = ""; then LDOUT="-o "; fi
|
||||
AC_SUBST(LDOUT)
|
||||
if test "$RANLIB" = ""; then RANLIB="${CROSS_COMPILE}ranlib"; fi
|
||||
AC_SUBST(RANLIB)
|
||||
|
@ -62,7 +62,7 @@ if test "$LIBEXT" = ""; then LIBEXT='a'; fi
|
|||
AC_SUBST(LIBEXT)
|
||||
if test "$LIBEXT2" = ""; then LIBEXT2=""; fi
|
||||
AC_SUBST(LIBEXT2)
|
||||
if test "$CC_OUT" = ""; then CC_OUT="-o"; fi
|
||||
if test "$CC_OUT" = ""; then CC_OUT="-o "; fi
|
||||
AC_SUBST(CC_OUT)
|
||||
if test "$CC_INC" = ""; then CC_INC="-I"; fi
|
||||
AC_SUBST(CC_INC)
|
||||
|
@ -92,6 +92,19 @@ case $host in
|
|||
;;
|
||||
esac
|
||||
|
||||
AC_SUBST(ac_shlib_suffix)
|
||||
case $target in
|
||||
*mingw* | *cygw* | *win32* | *w32* )
|
||||
ac_shlib_suffix=dll
|
||||
;;
|
||||
*darwin*)
|
||||
ac_shlib_suffix=dylib
|
||||
;;
|
||||
*)
|
||||
ac_shlib_suffix=so
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_CHECK_LIB(pthread,pthread_create)
|
||||
AC_CHECK_LIB(wsock32,puts)
|
||||
AC_CHECK_LIB(ws2_32,puts)
|
||||
|
@ -127,6 +140,12 @@ dnl Endianness detection
|
|||
dnl
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
if test "x$ac_cv_c_bigendian" = "xyes"; then
|
||||
CFLAGS="$CFLAGS -DPJ_IS_BIG_ENDIAN=1 -DPJ_IS_LITTLE_ENDIAN=0"
|
||||
else
|
||||
CFLAGS="$CFLAGS -DPJ_IS_BIG_ENDIAN=0 -DPJ_IS_LITTLE_ENDIAN=1"
|
||||
fi
|
||||
|
||||
dnl
|
||||
dnl Legacy macros
|
||||
dnl
|
||||
|
@ -725,6 +744,17 @@ AC_ARG_ENABLE(libsamplerate,
|
|||
AC_MSG_RESULT([Skipping libsamplerate detection])
|
||||
)
|
||||
|
||||
dnl # Include libsamplerate
|
||||
AC_SUBST(ac_resample_dll)
|
||||
AC_ARG_ENABLE(resample_dll,
|
||||
AC_HELP_STRING([--enable-resample-dll],
|
||||
[Build libresample as shared library]),
|
||||
[if test "$enable_resample_dll" = "yes"; then
|
||||
[ac_resample_dll=1]
|
||||
AC_MSG_RESULT([Building libresample as shared library... yes])
|
||||
fi],
|
||||
AC_MSG_RESULT([Building libresample as shared library... no])
|
||||
)
|
||||
|
||||
dnl ########################################################
|
||||
dnl # Intel IPP support
|
||||
|
@ -848,7 +878,7 @@ if test "x$enable_ipp" != "xno"; then
|
|||
]],
|
||||
[ippStaticInit();])],
|
||||
[AC_MSG_RESULT(ok)],
|
||||
[AC_MSG_FAILURE(Error: unable to recognize your IPP installation. Make sure the paths and ARCH suffix are set correctly, run with --help for more info)])
|
||||
[AC_MSG_FAILURE([Error: unable to recognize your IPP installation. Make sure the paths and ARCH suffix are set correctly, run with --help for more info])])
|
||||
|
||||
CFLAGS="$SAVED_CFLAGS"
|
||||
LDFLAGS="$SAVED_LDFLAGS"
|
||||
|
@ -997,6 +1027,33 @@ AC_ARG_ENABLE(ssl,
|
|||
fi
|
||||
])
|
||||
|
||||
dnl # Include opencore-amrnb support
|
||||
AC_SUBST(ac_no_opencore_amrnb)
|
||||
AC_ARG_ENABLE(opencore_amrnb,
|
||||
AC_HELP_STRING([--disable-opencore-amrnb],
|
||||
[Exclude OpenCORE AMR-NB support from the build (default: autodetect)])
|
||||
,
|
||||
[
|
||||
if test "$enable_opencore_amrnb" = "no"; then
|
||||
[ac_no_opencore_amrnb=1]
|
||||
AC_DEFINE(PJMEDIA_HAS_OPENCORE_AMRNB_CODEC,0)
|
||||
AC_MSG_RESULT([Checking if OpenCORE AMR-NB support is disabled... yes])
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([checking for OpenCORE AMR-NB installations..])
|
||||
AC_SUBST(opencore_amrnb_h_present)
|
||||
AC_SUBST(opencore_amrnb_present)
|
||||
AC_CHECK_HEADER(opencore-amrnb/interf_enc.h,[opencore_amrnb_h_present=1])
|
||||
AC_CHECK_LIB(opencore-amrnb,Encoder_Interface_init,[opencore_amrnb_present=1 && LIBS="$LIBS -lopencore-amrnb"])
|
||||
if test "x$opencore_amrnb_h_present" = "x1" -a "x$opencore_amrnb_present" = "x1"; then
|
||||
AC_MSG_RESULT([OpenCORE AMR-NB library found, AMR-NB support enabled])
|
||||
AC_DEFINE(PJMEDIA_HAS_OPENCORE_AMRNB_CODEC,1)
|
||||
else
|
||||
[ac_no_opencore_amrnb=1]
|
||||
AC_DEFINE(PJMEDIA_HAS_OPENCORE_AMRNB_CODEC,0)
|
||||
fi
|
||||
])
|
||||
|
||||
dnl ##########################################
|
||||
dnl #
|
||||
|
|
20
build.mak.in
20
build.mak.in
|
@ -1,3 +1,7 @@
|
|||
export PJDIR := @ac_pjdir@
|
||||
include $(PJDIR)/version.mak
|
||||
export PJ_DIR := $(PJDIR)
|
||||
|
||||
# @configure_input@
|
||||
export MACHINE_NAME := auto
|
||||
export OS_NAME := auto
|
||||
|
@ -6,15 +10,25 @@ export CC_NAME := gcc
|
|||
export TARGET_NAME := @target@
|
||||
export CROSS_COMPILE := @ac_cross_compile@
|
||||
export LINUX_POLL := @ac_linux_poll@
|
||||
export SHLIB_SUFFIX := @ac_shlib_suffix@
|
||||
|
||||
export ac_prefix := @prefix@
|
||||
|
||||
LIB_SUFFIX = $(TARGET_NAME).a
|
||||
|
||||
# Determine which party libraries to use
|
||||
export APP_THIRD_PARTY_LIBS := -lresample-$(TARGET_NAME) -lmilenage-$(TARGET_NAME) -lsrtp-$(TARGET_NAME)
|
||||
export APP_THIRD_PARTY_LIBS := -lmilenage-$(TARGET_NAME) -lsrtp-$(TARGET_NAME)
|
||||
export APP_THIRD_PARTY_EXT :=
|
||||
export APP_THIRD_PARTY_LIB_FILES = $(PJ_DIR)/third_party/lib/libresample-$(LIB_SUFFIX) $(PJ_DIR)/third_party/lib/libmilenage-$(LIB_SUFFIX) $(PJ_DIR)/third_party/lib/libsrtp-$(LIB_SUFFIX)
|
||||
export APP_THIRD_PARTY_LIB_FILES := $(PJ_DIR)/third_party/lib/libmilenage-$(LIB_SUFFIX) $(PJ_DIR)/third_party/lib/libsrtp-$(LIB_SUFFIX)
|
||||
|
||||
ifeq (@ac_resample_dll@,1)
|
||||
export PJ_RESAMPLE_DLL := 1
|
||||
export APP_THIRD_PARTY_LIBS := -lresample $(APP_THIRD_PARTY_LIBS)
|
||||
export APP_THIRD_PARTY_LIB_FILES := $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFIX).$(PJ_VERSION_MAJOR) $(PJ_DIR)/third_party/lib/libresample.$(SHLIB_SUFFIX) $(APP_THIRD_PARTY_LIB_FILES)
|
||||
else
|
||||
export APP_THIRD_PARTY_LIBS := -lresample-$(TARGET_NAME) $(APP_THIRD_PARTY_LIBS)
|
||||
export APP_THIRD_PARTY_LIB_FILES := $(PJ_DIR)/third_party/lib/libresample-$(LIB_SUFFIX) $(APP_THIRD_PARTY_LIB_FILES)
|
||||
endif
|
||||
|
||||
ifneq (@ac_no_gsm_codec@,1)
|
||||
ifeq (@ac_external_gsm@,1)
|
||||
|
@ -59,7 +73,6 @@ endif
|
|||
@ac_build_mak_vars@
|
||||
|
||||
# CFLAGS, LDFLAGS, and LIBS to be used by applications
|
||||
export PJDIR := @ac_pjdir@
|
||||
export APP_CC := @CC@
|
||||
export APP_CXX := @CXX@
|
||||
export APP_CFLAGS := -DPJ_AUTOCONF=1\
|
||||
|
@ -104,7 +117,6 @@ export APP_LIB_FILES = $(PJ_DIR)/pjsip/lib/libpjsua-$(LIB_SUFFIX) \
|
|||
|
||||
# Here are the variabels to use if application is using the library
|
||||
# from within the source distribution
|
||||
export PJ_DIR := $(PJDIR)
|
||||
export PJ_CC := $(APP_CC)
|
||||
export PJ_CXX := $(APP_CXX)
|
||||
export PJ_CFLAGS := $(APP_CFLAGS)
|
||||
|
|
|
@ -10,6 +10,11 @@ endif
|
|||
#
|
||||
LIB = $($(APP)_LIB)
|
||||
|
||||
#
|
||||
# The full path of output lib file (e.g. ../lib/libapp.a).
|
||||
#
|
||||
SHLIB = $($(APP)_SHLIB)
|
||||
|
||||
#
|
||||
# The full path of output executable file (e.g. ../bin/app.exe).
|
||||
#
|
||||
|
@ -82,6 +87,11 @@ $(LIB): $(OBJDIRS) $(OBJS) $($(APP)_EXTRA_DEP)
|
|||
$(AR) $(LIB) $(OBJS)
|
||||
$(RANLIB) $(LIB)
|
||||
|
||||
$(SHLIB): $(OBJDIRS) $(OBJS) $($(APP)_EXTRA_DEP)
|
||||
if test ! -d $(LIBDIR); then $(subst @@,$(subst /,$(HOST_PSEP),$(LIBDIR)),$(HOST_MKDIR)); fi
|
||||
$(LD) $(LDOUT)$(subst /,$(HOST_PSEP),$(SHLIB)) \
|
||||
$(subst /,$(HOST_PSEP),$(OBJS)) $($(APP)_LDFLAGS)
|
||||
|
||||
$(EXE): $(OBJDIRS) $(OBJS) $($(APP)_EXTRA_DEP)
|
||||
if test ! -d $(BINDIR); then $(subst @@,$(subst /,$(HOST_PSEP),$(BINDIR)),$(HOST_MKDIR)); fi
|
||||
$(LD) $(LDOUT)$(subst /,$(HOST_PSEP),$(EXE)) \
|
||||
|
|
|
@ -25,7 +25,10 @@ fi
|
|||
|
||||
# Set the main iPhone developer directory, if not set
|
||||
if test "x${DEVPATH}" = "x"; then
|
||||
DEVPATH=/Developer/Platforms/iPhoneOS.platform/Developer
|
||||
DEVPATH=/Applications/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer
|
||||
if test ! -d $DEVPATH; then
|
||||
DEVPATH=/Developer/Platforms/iPhoneOS.platform/Developer
|
||||
fi
|
||||
echo "$F: DEVPATH is not specified, using ${DEVPATH}"
|
||||
fi
|
||||
|
||||
|
@ -71,20 +74,29 @@ fi
|
|||
# full path as it's not normally in user's PATH
|
||||
|
||||
if test "${CC}" = ""; then
|
||||
for archpath in `ls -d ${SDKPATH}/usr/lib/gcc/arm-apple-darwin*`; do
|
||||
archname=`basename ${archpath}`
|
||||
for gccver in `ls ${archpath}`; do
|
||||
gccpath="${DEVPATH}/usr/bin/${archname}-gcc-${gccver}"
|
||||
if test -e ${gccpath}; then
|
||||
export CC="${gccpath}"
|
||||
# break
|
||||
fi
|
||||
done
|
||||
if test ! "${CC}" = ""; then
|
||||
echo "$F: CC is not specified, choosing ${CC}"
|
||||
break
|
||||
# Try to use llvm-gcc if available
|
||||
gccpath="${DEVPATH}/usr/bin/llvm-gcc"
|
||||
if test -e ${gccpath}; then
|
||||
export CC="${gccpath}"
|
||||
|
||||
if test "${ARCH}" = ""; then
|
||||
export ARCH="-arch armv7"
|
||||
echo "$F: ARCH is not specified, choosing ${ARCH}"
|
||||
fi
|
||||
done
|
||||
else
|
||||
for archpath in `ls -d ${SDKPATH}/usr/lib/gcc/arm-apple-darwin*`; do
|
||||
archname=`basename ${archpath}`
|
||||
for gccver in `ls ${archpath}`; do
|
||||
gccpath="${DEVPATH}/usr/bin/${archname}-gcc-${gccver}"
|
||||
if test -e ${gccpath}; then
|
||||
export CC="${gccpath}"
|
||||
fi
|
||||
done
|
||||
done
|
||||
fi
|
||||
if test ! "${CC}" = ""; then
|
||||
echo "$F: CC is not specified, choosing ${CC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "${CC}" = ""; then
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
export UTIL_TEST_OBJS = main.o
|
||||
|
||||
include ../../build.mak
|
||||
include ../../version.mak
|
||||
include $(PJDIR)/build/common.mak
|
||||
|
||||
RULES_MAK := $(PJDIR)/build/rules.mak
|
||||
|
@ -55,10 +56,14 @@ TARGETS := pjlib-util pjlib-util-test
|
|||
all: $(TARGETS)
|
||||
|
||||
doc:
|
||||
cd .. && rm -rf docs/html docs/latex && doxygen docs/doxygen.cfg
|
||||
@if [ -n "$(WWWDIR)" ]; then \
|
||||
echo "Copying to $(WWWDIR)/pjlib-util/docs/html.." ; \
|
||||
cp -a ../docs/html/* $(WWWDIR)/pjlib-util/docs/html/ ; \
|
||||
cd .. && rm -rf docs/$(PJ_VERSION) && doxygen docs/doxygen.cfg
|
||||
@if [ -n "$(WWWDIR)" ] && ! [ -d "$(WWWDIR)/docs/$(PJ_VERSION)/pjlib-util/docs/html" ] ; then \
|
||||
echo "Creating docs/$(PJ_VERSION)/pjlib-util/docs/html" ; \
|
||||
mkdir -p $(WWWDIR)/docs/$(PJ_VERSION)/pjlib-util/docs/html ; \
|
||||
fi
|
||||
@if [ -n "$(WWWDIR)" ] && [ -d "$(WWWDIR)/docs/$(PJ_VERSION)/pjlib-util/docs/html" ] ; then \
|
||||
echo "Copying docs/$(PJ_VERSION) to $(WWWDIR)/docs/$(PJ_VERSION)/pjlib-util/docs/html.." ; \
|
||||
cp -v -a ../docs/$(PJ_VERSION)/html/* $(WWWDIR)/docs/$(PJ_VERSION)/pjlib-util/docs/html/ ; \
|
||||
fi
|
||||
|
||||
dep: depend
|
||||
|
@ -69,7 +74,7 @@ distclean: realclean
|
|||
pjlib-util:
|
||||
$(MAKE) -f $(RULES_MAK) APP=PJLIB_UTIL app=pjlib-util $(PJLIB_UTIL_LIB)
|
||||
|
||||
pjlib-util-test:
|
||||
pjlib-util-test: pjlib-util
|
||||
$(MAKE) -f $(RULES_MAK) APP=UTIL_TEST app=pjlib-util-test $(UTIL_TEST_EXE)
|
||||
|
||||
.PHONY: ../lib/pjlib-util.ko
|
||||
|
|
|
@ -23,14 +23,14 @@ PROJECT_NAME = "PJLIB-UTIL Reference"
|
|||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
PROJECT_NUMBER =
|
||||
PROJECT_NUMBER = $(PJ_VERSION)
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# base path where the generated documentation will be put.
|
||||
# If a relative path is entered, it will be relative to the location
|
||||
# where doxygen was started. If left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = docs
|
||||
OUTPUT_DIRECTORY = docs/$(PJ_VERSION)
|
||||
|
||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
|
@ -578,7 +578,7 @@ ENUM_VALUES_PER_LINE = 4
|
|||
# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
|
||||
# probably better off using the HTML help feature.
|
||||
|
||||
GENERATE_TREEVIEW = YES
|
||||
GENERATE_TREEVIEW = NO
|
||||
|
||||
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
|
||||
# used to set the initial width (in pixels) of the frame in which the tree
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
|
||||
<title>$title</title>
|
||||
<title>$title ($projectnumber)</title>
|
||||
<link href="/style/style.css" rel="stylesheet" type="text/css">
|
||||
</head><body>
|
||||
<!--#include virtual="/header.html" -->
|
||||
|
|
|
@ -188,6 +188,36 @@ typedef struct pj_http_req_param
|
|||
*/
|
||||
pj_http_auth_cred auth_cred;
|
||||
|
||||
/**
|
||||
* Optional source port range to use when binding the socket.
|
||||
* This can be used if the source port needs to be within a certain range
|
||||
* for instance due to strict firewall settings. The port used will be
|
||||
* randomized within the range.
|
||||
*
|
||||
* Note that if authentication is configured, the authentication response
|
||||
* will be a new transaction
|
||||
*
|
||||
* Default is 0 (The OS will select the source port automatically)
|
||||
*/
|
||||
pj_uint16_t source_port_range_start;
|
||||
|
||||
/**
|
||||
* Optional source port range to use when binding.
|
||||
* The size of the port restriction range
|
||||
*
|
||||
* Default is 0 (The OS will select the source port automatically))
|
||||
*/
|
||||
pj_uint16_t source_port_range_size;
|
||||
|
||||
/**
|
||||
* Max number of retries if binding to a port fails.
|
||||
* Note that this does not adress the scenario where a request times out
|
||||
* or errors. This needs to be taken care of by the on_complete callback.
|
||||
*
|
||||
* Default is 3
|
||||
*/
|
||||
pj_uint16_t max_retries;
|
||||
|
||||
} pj_http_req_param;
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,15 +26,17 @@
|
|||
#include <pj/pool.h>
|
||||
#include <pj/string.h>
|
||||
#include <pj/timer.h>
|
||||
#include <pj/rand.h>
|
||||
#include <pjlib-util/base64.h>
|
||||
#include <pjlib-util/errno.h>
|
||||
#include <pjlib-util/md5.h>
|
||||
#include <pjlib-util/scanner.h>
|
||||
#include <pjlib-util/string.h>
|
||||
|
||||
#define THIS_FILE "http_client.c"
|
||||
|
||||
#if 0
|
||||
/* Enable some tracing */
|
||||
#define THIS_FILE "http_client.c"
|
||||
#define TRACE_(arg) PJ_LOG(3,arg)
|
||||
#else
|
||||
#define TRACE_(arg)
|
||||
|
@ -764,6 +766,7 @@ PJ_DEF(void) pj_http_req_param_default(pj_http_req_param *param)
|
|||
pj_strset2(¶m->version, (char*)HTTP_1_0);
|
||||
param->timeout.msec = PJ_HTTP_DEFAULT_TIMEOUT;
|
||||
pj_time_val_normalize(¶m->timeout);
|
||||
param->max_retries = 3;
|
||||
}
|
||||
|
||||
/* Get the location of '@' character to indicate the end of
|
||||
|
@ -1004,11 +1007,13 @@ PJ_DEF(void*) pj_http_req_get_user_data(pj_http_req *http_req)
|
|||
return http_req->param.user_data;
|
||||
}
|
||||
|
||||
PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req)
|
||||
static pj_status_t start_http_req(pj_http_req *http_req,
|
||||
pj_bool_t notify_on_fail)
|
||||
{
|
||||
pj_sock_t sock = PJ_INVALID_SOCKET;
|
||||
pj_status_t status;
|
||||
pj_activesock_cb asock_cb;
|
||||
int retry = 0;
|
||||
|
||||
PJ_ASSERT_RETURN(http_req, PJ_EINVAL);
|
||||
/* Http request is not idle, a request was initiated before and
|
||||
|
@ -1031,7 +1036,7 @@ PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req)
|
|||
(http_req->param.addr_family==pj_AF_INET() &&
|
||||
http_req->addr.ipv4.sin_addr.s_addr==PJ_INADDR_NONE))
|
||||
{
|
||||
return status; // cannot resolve host name
|
||||
goto on_return;
|
||||
}
|
||||
http_req->resolved = PJ_TRUE;
|
||||
}
|
||||
|
@ -1045,6 +1050,32 @@ PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req)
|
|||
asock_cb.on_data_read = &http_on_data_read;
|
||||
asock_cb.on_data_sent = &http_on_data_sent;
|
||||
asock_cb.on_connect_complete = &http_on_connect;
|
||||
|
||||
do
|
||||
{
|
||||
pj_sockaddr_in bound_addr;
|
||||
pj_uint16_t port = 0;
|
||||
|
||||
/* If we are using port restriction.
|
||||
* Get a random port within the range
|
||||
*/
|
||||
if (http_req->param.source_port_range_start != 0) {
|
||||
port = (pj_uint16_t)
|
||||
(http_req->param.source_port_range_start +
|
||||
(pj_rand() % http_req->param.source_port_range_size));
|
||||
}
|
||||
|
||||
pj_sockaddr_in_init(&bound_addr, NULL, port);
|
||||
status = pj_sock_bind(sock, &bound_addr, sizeof(bound_addr));
|
||||
|
||||
} while (status != PJ_SUCCESS && (retry++ < http_req->param.max_retries));
|
||||
|
||||
if (status != PJ_SUCCESS) {
|
||||
PJ_PERROR(1,(THIS_FILE, status,
|
||||
"Unable to bind to the requested port"));
|
||||
pj_sock_close(sock);
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
// TODO: should we set whole data to 0 by default?
|
||||
// or add it in the param?
|
||||
|
@ -1052,8 +1083,7 @@ PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req)
|
|||
NULL, http_req->ioqueue,
|
||||
&asock_cb, http_req, &http_req->asock);
|
||||
if (status != PJ_SUCCESS) {
|
||||
if (sock != PJ_INVALID_SOCKET)
|
||||
pj_sock_close(sock);
|
||||
pj_sock_close(sock);
|
||||
goto on_return; // error creating activesock
|
||||
}
|
||||
|
||||
|
@ -1074,7 +1104,9 @@ PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req)
|
|||
pj_sockaddr_get_len(&http_req->addr));
|
||||
if (status == PJ_SUCCESS) {
|
||||
http_req->state = SENDING_REQUEST;
|
||||
return http_req_start_sending(http_req);
|
||||
status = http_req_start_sending(http_req);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_return;
|
||||
} else if (status != PJ_EPENDING) {
|
||||
goto on_return; // error connecting
|
||||
}
|
||||
|
@ -1082,10 +1114,21 @@ PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req)
|
|||
return PJ_SUCCESS;
|
||||
|
||||
on_return:
|
||||
http_req_end_request(http_req);
|
||||
http_req->error = status;
|
||||
if (notify_on_fail)
|
||||
pj_http_req_cancel(http_req, PJ_TRUE);
|
||||
else
|
||||
http_req_end_request(http_req);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Starts an asynchronous HTTP request to the URL specified. */
|
||||
PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req)
|
||||
{
|
||||
return start_http_req(http_req, PJ_FALSE);
|
||||
}
|
||||
|
||||
/* Respond to basic authentication challenge */
|
||||
static pj_status_t auth_respond_basic(pj_http_req *hreq)
|
||||
{
|
||||
|
@ -1345,7 +1388,7 @@ static pj_status_t auth_respond_digest(pj_http_req *hreq)
|
|||
*/
|
||||
const pj_str_t STR_MD5 = { "MD5", 3 };
|
||||
const pj_str_t qop = pj_str("auth");
|
||||
const pj_str_t nc = pj_str("1");
|
||||
const pj_str_t nc = pj_str("00000001");
|
||||
const pj_str_t cnonce = pj_str("b39971");
|
||||
|
||||
auth_create_digest_response(&digest_response, cred,
|
||||
|
@ -1433,7 +1476,7 @@ static void restart_req_with_auth(pj_http_req *hreq)
|
|||
|
||||
http_req_end_request(hreq);
|
||||
|
||||
status = pj_http_req_start(hreq);
|
||||
status = start_http_req(hreq, PJ_TRUE);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
|
|
|
@ -368,8 +368,20 @@ PJ_DEF(pj_status_t) pj_pcap_read_udp(pj_pcap_file *file,
|
|||
|
||||
*udp_payload_size = sz;
|
||||
|
||||
// Some layers may have trailer, e.g: link eth2.
|
||||
/* Check that we've read all the packets */
|
||||
PJ_ASSERT_RETURN(sz_read == rec_incl, PJ_EBUG);
|
||||
//PJ_ASSERT_RETURN(sz_read == rec_incl, PJ_EBUG);
|
||||
|
||||
/* Skip trailer */
|
||||
while (sz_read < rec_incl) {
|
||||
sz = rec_incl - sz_read;
|
||||
status = read_file(file, &tmp.eth, &sz);
|
||||
if (status != PJ_SUCCESS) {
|
||||
TRACE_((file->obj_name, "Error reading trailer: %d", status));
|
||||
return status;
|
||||
}
|
||||
sz_read += sz;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -180,7 +180,8 @@ struct pj_dns_resolver
|
|||
unsigned char udp_rx_pkt[UDPSZ];/**< UDP receive buffer. */
|
||||
unsigned char udp_tx_pkt[UDPSZ];/**< UDP receive buffer. */
|
||||
pj_ssize_t udp_len; /**< Length of received packet. */
|
||||
pj_ioqueue_op_key_t udp_op_key; /**< UDP read operation key. */
|
||||
pj_ioqueue_op_key_t udp_op_rx_key; /**< UDP read operation key. */
|
||||
pj_ioqueue_op_key_t udp_op_tx_key; /**< UDP write operation key. */
|
||||
pj_sockaddr_in udp_src_addr; /**< Source address of packet */
|
||||
int udp_addr_len; /**< Source address length. */
|
||||
|
||||
|
@ -223,6 +224,63 @@ static pj_status_t select_nameservers(pj_dns_resolver *resolver,
|
|||
unsigned servers[]);
|
||||
|
||||
|
||||
/* Close UDP socket */
|
||||
static void close_sock(pj_dns_resolver *resv)
|
||||
{
|
||||
/* Close existing socket */
|
||||
if (resv->udp_key != NULL) {
|
||||
pj_ioqueue_unregister(resv->udp_key);
|
||||
resv->udp_key = NULL;
|
||||
resv->udp_sock = PJ_INVALID_SOCKET;
|
||||
} else if (resv->udp_sock != PJ_INVALID_SOCKET) {
|
||||
pj_sock_close(resv->udp_sock);
|
||||
resv->udp_sock = PJ_INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Initialize UDP socket */
|
||||
static pj_status_t init_sock(pj_dns_resolver *resv)
|
||||
{
|
||||
pj_ioqueue_callback socket_cb;
|
||||
pj_status_t status;
|
||||
|
||||
/* Create the UDP socket */
|
||||
status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &resv->udp_sock);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Bind to any address/port */
|
||||
status = pj_sock_bind_in(resv->udp_sock, 0, 0);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Register to ioqueue */
|
||||
pj_bzero(&socket_cb, sizeof(socket_cb));
|
||||
socket_cb.on_read_complete = &on_read_complete;
|
||||
status = pj_ioqueue_register_sock(resv->pool, resv->ioqueue,
|
||||
resv->udp_sock, resv, &socket_cb,
|
||||
&resv->udp_key);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
pj_ioqueue_op_key_init(&resv->udp_op_rx_key, sizeof(resv->udp_op_rx_key));
|
||||
pj_ioqueue_op_key_init(&resv->udp_op_tx_key, sizeof(resv->udp_op_tx_key));
|
||||
|
||||
/* Start asynchronous read to the UDP socket */
|
||||
resv->udp_len = sizeof(resv->udp_rx_pkt);
|
||||
resv->udp_addr_len = sizeof(resv->udp_src_addr);
|
||||
status = pj_ioqueue_recvfrom(resv->udp_key, &resv->udp_op_rx_key,
|
||||
resv->udp_rx_pkt, &resv->udp_len,
|
||||
PJ_IOQUEUE_ALWAYS_ASYNC,
|
||||
&resv->udp_src_addr, &resv->udp_addr_len);
|
||||
if (status != PJ_EPENDING)
|
||||
return status;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize DNS settings with default values */
|
||||
PJ_DEF(void) pj_dns_settings_default(pj_dns_settings *s)
|
||||
{
|
||||
|
@ -247,7 +305,6 @@ PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf,
|
|||
{
|
||||
pj_pool_t *pool;
|
||||
pj_dns_resolver *resv;
|
||||
pj_ioqueue_callback socket_cb;
|
||||
pj_status_t status;
|
||||
|
||||
/* Sanity check */
|
||||
|
@ -302,37 +359,11 @@ PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf,
|
|||
resv->hquerybyres = pj_hash_create(pool, Q_HASH_TABLE_SIZE);
|
||||
pj_list_init(&resv->query_free_nodes);
|
||||
|
||||
/* Create the UDP socket */
|
||||
status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &resv->udp_sock);
|
||||
/* Initialize the UDP socket */
|
||||
status = init_sock(resv);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Bind to any address/port */
|
||||
status = pj_sock_bind_in(resv->udp_sock, 0, 0);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Register to ioqueue */
|
||||
pj_bzero(&socket_cb, sizeof(socket_cb));
|
||||
socket_cb.on_read_complete = &on_read_complete;
|
||||
status = pj_ioqueue_register_sock(pool, resv->ioqueue, resv->udp_sock,
|
||||
resv, &socket_cb, &resv->udp_key);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
pj_ioqueue_op_key_init(&resv->udp_op_key, sizeof(resv->udp_op_key));
|
||||
|
||||
/* Start asynchronous read to the UDP socket */
|
||||
resv->udp_len = sizeof(resv->udp_rx_pkt);
|
||||
resv->udp_addr_len = sizeof(resv->udp_src_addr);
|
||||
status = pj_ioqueue_recvfrom(resv->udp_key, &resv->udp_op_key,
|
||||
resv->udp_rx_pkt, &resv->udp_len,
|
||||
PJ_IOQUEUE_ALWAYS_ASYNC,
|
||||
&resv->udp_src_addr, &resv->udp_addr_len);
|
||||
if (status != PJ_EPENDING)
|
||||
goto on_error;
|
||||
|
||||
|
||||
/* Looks like everything is okay */
|
||||
*p_resolver = resv;
|
||||
return PJ_SUCCESS;
|
||||
|
@ -392,14 +423,7 @@ PJ_DEF(pj_status_t) pj_dns_resolver_destroy( pj_dns_resolver *resolver,
|
|||
resolver->timer = NULL;
|
||||
}
|
||||
|
||||
if (resolver->udp_key != NULL) {
|
||||
pj_ioqueue_unregister(resolver->udp_key);
|
||||
resolver->udp_key = NULL;
|
||||
resolver->udp_sock = PJ_INVALID_SOCKET;
|
||||
} else if (resolver->udp_sock != PJ_INVALID_SOCKET) {
|
||||
pj_sock_close(resolver->udp_sock);
|
||||
resolver->udp_sock = PJ_INVALID_SOCKET;
|
||||
}
|
||||
close_sock(resolver);
|
||||
|
||||
if (resolver->own_ioqueue && resolver->ioqueue) {
|
||||
pj_ioqueue_destroy(resolver->ioqueue);
|
||||
|
@ -561,15 +585,6 @@ static pj_status_t transmit_query(pj_dns_resolver *resolver,
|
|||
pj_time_val delay;
|
||||
pj_status_t status;
|
||||
|
||||
/* Create DNS query packet */
|
||||
pkt_size = sizeof(resolver->udp_tx_pkt);
|
||||
name = pj_str(q->key.name);
|
||||
status = pj_dns_make_query(resolver->udp_tx_pkt, &pkt_size,
|
||||
q->id, q->key.qtype, &name);
|
||||
if (status != PJ_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Select which nameserver(s) to send requests to. */
|
||||
server_cnt = PJ_ARRAY_SIZE(servers);
|
||||
status = select_nameservers(resolver, &server_cnt, servers);
|
||||
|
@ -595,6 +610,28 @@ static pj_status_t transmit_query(pj_dns_resolver *resolver,
|
|||
return status;
|
||||
}
|
||||
|
||||
/* Check if the socket is available for sending */
|
||||
if (pj_ioqueue_is_pending(resolver->udp_key, &resolver->udp_op_tx_key)) {
|
||||
++q->transmit_cnt;
|
||||
PJ_LOG(4,(resolver->name.ptr,
|
||||
"Socket busy in transmitting DNS %s query for %s%s",
|
||||
pj_dns_get_type_name(q->key.qtype),
|
||||
q->key.name,
|
||||
(q->transmit_cnt < resolver->settings.qretr_count?
|
||||
", will try again later":"")));
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Create DNS query packet */
|
||||
pkt_size = sizeof(resolver->udp_tx_pkt);
|
||||
name = pj_str(q->key.name);
|
||||
status = pj_dns_make_query(resolver->udp_tx_pkt, &pkt_size,
|
||||
q->id, q->key.qtype, &name);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_timer_heap_cancel(resolver->timer, &q->timer_entry);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Get current time. */
|
||||
pj_gettimeofday(&now);
|
||||
|
||||
|
@ -603,13 +640,16 @@ static pj_status_t transmit_query(pj_dns_resolver *resolver,
|
|||
pj_ssize_t sent = (pj_ssize_t) pkt_size;
|
||||
struct nameserver *ns = &resolver->ns[servers[i]];
|
||||
|
||||
pj_sock_sendto(resolver->udp_sock, resolver->udp_tx_pkt, &sent, 0,
|
||||
&resolver->ns[servers[i]].addr, sizeof(pj_sockaddr_in));
|
||||
status = pj_ioqueue_sendto(resolver->udp_key,
|
||||
&resolver->udp_op_tx_key,
|
||||
resolver->udp_tx_pkt, &sent, 0,
|
||||
&resolver->ns[servers[i]].addr,
|
||||
sizeof(pj_sockaddr_in));
|
||||
|
||||
PJ_LOG(4,(resolver->name.ptr,
|
||||
PJ_PERROR(4,(resolver->name.ptr, status,
|
||||
"%s %d bytes to NS %d (%s:%d): DNS %s query for %s",
|
||||
(q->transmit_cnt==0? "Transmitting":"Re-transmitting"),
|
||||
(int)sent, servers[i],
|
||||
(int)pkt_size, servers[i],
|
||||
pj_inet_ntoa(ns->addr.sin_addr),
|
||||
(int)pj_ntohs(ns->addr.sin_port),
|
||||
pj_dns_get_type_name(q->key.qtype),
|
||||
|
@ -1248,6 +1288,9 @@ static void on_timeout( pj_timer_heap_t *timer_heap,
|
|||
pj_hash_set(NULL, resolver->hquerybyid, &q->id, sizeof(q->id), 0, NULL);
|
||||
pj_hash_set(NULL, resolver->hquerybyres, &q->key, sizeof(q->key), 0, NULL);
|
||||
|
||||
/* Workaround for deadlock problem in #1565 (similar to #1108) */
|
||||
pj_mutex_unlock(resolver->mutex);
|
||||
|
||||
/* Call application callback, if any. */
|
||||
if (q->cb)
|
||||
(*q->cb)(q->user_data, PJ_ETIMEDOUT, NULL);
|
||||
|
@ -1260,6 +1303,9 @@ static void on_timeout( pj_timer_heap_t *timer_heap,
|
|||
cq = cq->next;
|
||||
}
|
||||
|
||||
/* Workaround for deadlock problem in #1565 (similar to #1108) */
|
||||
pj_mutex_lock(resolver->mutex);
|
||||
|
||||
/* Clear data */
|
||||
q->timer_entry.id = 0;
|
||||
q->user_data = NULL;
|
||||
|
|
|
@ -393,7 +393,6 @@ PJ_DEF(void) pj_scan_get_quotes(pj_scanner *scanner,
|
|||
}
|
||||
/* break from main loop if we have odd number of backslashes */
|
||||
if (((unsigned)(q-r) & 0x01) == 1) {
|
||||
++s;
|
||||
break;
|
||||
}
|
||||
++s;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
#include <pjlib-util/stun_simple.h>
|
||||
#include <pjlib-util/errno.h>
|
||||
#include <pj/compat/socket.h>
|
||||
#include <pj/log.h>
|
||||
#include <pj/os.h>
|
||||
#include <pj/pool.h>
|
||||
|
@ -44,7 +45,7 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr( pj_pool_factory *pf,
|
|||
{
|
||||
unsigned srv_cnt;
|
||||
pj_sockaddr_in srv_addr[2];
|
||||
int i, j, send_cnt = 0;
|
||||
int i, send_cnt = 0, nfds;
|
||||
pj_pool_t *pool;
|
||||
struct query_rec {
|
||||
struct {
|
||||
|
@ -113,6 +114,17 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr( pj_pool_factory *pf,
|
|||
|
||||
TRACE_((THIS_FILE, " Done initialization."));
|
||||
|
||||
#if defined(PJ_SELECT_NEEDS_NFDS) && PJ_SELECT_NEEDS_NFDS!=0
|
||||
nfds = -1;
|
||||
for (i=0; i<sock_cnt; ++i) {
|
||||
if (sock[i] > nfds) {
|
||||
nfds = sock[i];
|
||||
}
|
||||
}
|
||||
#else
|
||||
nfds = FD_SETSIZE-1;
|
||||
#endif
|
||||
|
||||
/* Main retransmission loop. */
|
||||
for (send_cnt=0; send_cnt<MAX_REQUEST; ++send_cnt) {
|
||||
pj_time_val next_tx, now;
|
||||
|
@ -123,6 +135,7 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr( pj_pool_factory *pf,
|
|||
|
||||
/* Send messages to servers that has not given us response. */
|
||||
for (i=0; i<sock_cnt && status==PJ_SUCCESS; ++i) {
|
||||
unsigned j;
|
||||
for (j=0; j<srv_cnt && status==PJ_SUCCESS; ++j) {
|
||||
pjstun_msg_hdr *msg_hdr = (pjstun_msg_hdr*) out_msg;
|
||||
pj_ssize_t sent_len;
|
||||
|
@ -169,7 +182,7 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr( pj_pool_factory *pf,
|
|||
PJ_FD_SET(sock[i], &r);
|
||||
}
|
||||
|
||||
select_rc = pj_sock_select(PJ_IOQUEUE_MAX_HANDLES, &r, NULL, NULL, &timeout);
|
||||
select_rc = pj_sock_select(nfds+1, &r, NULL, NULL, &timeout);
|
||||
TRACE_((THIS_FILE, " select() rc=%d", select_rc));
|
||||
if (select_rc < 1)
|
||||
continue;
|
||||
|
|
|
@ -100,13 +100,13 @@ static pj_xml_node *xml_parse_node( pj_pool_t *pool, pj_scanner *scanner)
|
|||
pj_scan_get_char(scanner);
|
||||
|
||||
/* Get node name. */
|
||||
pj_scan_get_until_chr( scanner, " />\t", &node->name);
|
||||
pj_scan_get_until_chr( scanner, " />\t\r\n", &node->name);
|
||||
|
||||
/* Get attributes. */
|
||||
while (*scanner->curptr != '>' && *scanner->curptr != '/') {
|
||||
pj_xml_attr *attr = alloc_attr(pool);
|
||||
|
||||
pj_scan_get_until_chr( scanner, "=> \t", &attr->name);
|
||||
pj_scan_get_until_chr( scanner, "=> \t\r\n", &attr->name);
|
||||
if (*scanner->curptr == '=') {
|
||||
pj_scan_get_char( scanner );
|
||||
pj_scan_get_quotes(scanner, "\"'", "\"'", 2, &attr->value);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
include ../../build.mak
|
||||
include ../../version.mak
|
||||
include $(PJDIR)/build/common.mak
|
||||
|
||||
RULES_MAK := $(PJDIR)/build/rules.mak
|
||||
|
@ -57,12 +58,15 @@ export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT
|
|||
all: $(TARGETS)
|
||||
|
||||
doc:
|
||||
cd .. && rm -rf docs/html docs/latex && doxygen docs/doxygen.cfg
|
||||
@if [ -n "$(WWWDIR)" ]; then \
|
||||
echo "Copying to $(WWWDIR)/pjlib/docs/html.." ; \
|
||||
cp -a ../docs/html/* $(WWWDIR)/pjlib/docs/html/ ; \
|
||||
cd .. && rm -rf docs/$(PJ_VERSION) && doxygen docs/doxygen.cfg
|
||||
@if [ -n "$(WWWDIR)" ] && ! [ -d "$(WWWDIR)/docs/$(PJ_VERSION)/pjlib/docs/html" ] ; then \
|
||||
echo "Creating docs/$(PJ_VERSION)/pjlib/docs/html" ; \
|
||||
mkdir -p $(WWWDIR)/docs/$(PJ_VERSION)/pjlib/docs/html ; \
|
||||
fi
|
||||
@if [ -n "$(WWWDIR)" ] && [ -d "$(WWWDIR)/docs/$(PJ_VERSION)/pjlib/docs/html" ] ; then \
|
||||
echo "Copying docs/$(PJ_VERSION) to $(WWWDIR)/docs/$(PJ_VERSION)/pjlib/docs/html.." ; \
|
||||
cp -v -a ../docs/$(PJ_VERSION)/html/* $(WWWDIR)/docs/$(PJ_VERSION)/pjlib/docs/html/ ; \
|
||||
fi
|
||||
|
||||
print:
|
||||
$(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib print_lib
|
||||
$(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test print_bin
|
||||
|
@ -83,7 +87,7 @@ pjlib: ../include/pj/config_site.h
|
|||
../include/pj/config_site.h:
|
||||
touch ../include/pj/config_site.h
|
||||
|
||||
pjlib-test:
|
||||
pjlib-test: pjlib
|
||||
$(MAKE) -f $(RULES_MAK) APP=TEST app=pjlib-test $(TEST_EXE)
|
||||
|
||||
.PHONY: ../lib/pjlib.ko
|
||||
|
|
|
@ -23,14 +23,14 @@ PROJECT_NAME = "PJLIB Reference"
|
|||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
PROJECT_NUMBER =
|
||||
PROJECT_NUMBER = $(PJ_VERSION)
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# base path where the generated documentation will be put.
|
||||
# If a relative path is entered, it will be relative to the location
|
||||
# where doxygen was started. If left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = docs
|
||||
OUTPUT_DIRECTORY = docs/$(PJ_VERSION)
|
||||
|
||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
|
@ -578,7 +578,7 @@ ENUM_VALUES_PER_LINE = 4
|
|||
# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
|
||||
# probably better off using the HTML help feature.
|
||||
|
||||
GENERATE_TREEVIEW = YES
|
||||
GENERATE_TREEVIEW = NO
|
||||
|
||||
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
|
||||
# used to set the initial width (in pixels) of the frame in which the tree
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
|
||||
<title>$title</title>
|
||||
<title>$title ($projectnumber)</title>
|
||||
<link href="/style/style.css" rel="stylesheet" type="text/css">
|
||||
</head><body>
|
||||
<!--#include virtual="/header.html" -->
|
||||
|
|
|
@ -177,6 +177,8 @@
|
|||
# include "Availability.h"
|
||||
/* Use CFHost API for pj_getaddrinfo() (see ticket #1246) */
|
||||
# define PJ_GETADDRINFO_USE_CFHOST 1
|
||||
/* Disable local host resolution in pj_gethostip() (see ticket #1342) */
|
||||
# define PJ_GETHOSTIP_DISABLE_LOCAL_RESOLUTION 1
|
||||
# ifdef __IPHONE_4_0
|
||||
/* Is multitasking support available? (see ticket #1107) */
|
||||
# define PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT 1
|
||||
|
|
|
@ -108,6 +108,11 @@
|
|||
# define NULL 0
|
||||
#endif
|
||||
|
||||
/* Endianness */
|
||||
#ifndef PJ_IS_LITTLE_ENDIAN
|
||||
# define PJ_IS_LITTLE_ENDIAN 1
|
||||
# define PJ_IS_BIG_ENDIAN 0
|
||||
#endif
|
||||
|
||||
/* Doesn't seem to allow more than this */
|
||||
#define PJ_IOQUEUE_MAX_HANDLES 8
|
||||
|
|
|
@ -98,6 +98,12 @@
|
|||
*/
|
||||
#define PJ_SELECT_NEEDS_NFDS 0
|
||||
|
||||
/* Endianness */
|
||||
#ifndef PJ_IS_LITTLE_ENDIAN
|
||||
# define PJ_IS_LITTLE_ENDIAN 1
|
||||
# define PJ_IS_BIG_ENDIAN 0
|
||||
#endif
|
||||
|
||||
/* Default threading is enabled, unless it's overridden. */
|
||||
#ifndef PJ_HAS_THREADS
|
||||
# define PJ_HAS_THREADS (1)
|
||||
|
|
|
@ -165,7 +165,7 @@
|
|||
#elif defined(PJ_M_IA64) || defined(__ia64__) || defined(_IA64) || \
|
||||
defined(__IA64__) || defined( _M_IA64)
|
||||
/*
|
||||
* Intel IA64 processor, little endian
|
||||
* Intel IA64 processor, default to little endian
|
||||
*/
|
||||
# undef PJ_M_IA64
|
||||
# define PJ_M_IA64 1
|
||||
|
@ -203,15 +203,14 @@
|
|||
#elif defined(PJ_M_MIPS) || defined(__mips__) || defined(__mips) || \
|
||||
defined(__MIPS__) || defined(MIPS) || defined(_MIPS_)
|
||||
/*
|
||||
* MIPS, default to little endian
|
||||
* MIPS, bi-endian, so raise error if endianness is not configured
|
||||
*/
|
||||
# undef PJ_M_MIPS
|
||||
# define PJ_M_MIPS 1
|
||||
# define PJ_M_NAME "mips"
|
||||
# define PJ_HAS_PENTIUM 0
|
||||
# if !defined(PJ_IS_LITTLE_ENDIAN) && !defined(PJ_IS_BIG_ENDIAN)
|
||||
# define PJ_IS_LITTLE_ENDIAN 1
|
||||
# define PJ_IS_BIG_ENDIAN 0
|
||||
# if !PJ_IS_LITTLE_ENDIAN && !PJ_IS_BIG_ENDIAN
|
||||
# error Endianness must be declared for this processor
|
||||
# endif
|
||||
|
||||
|
||||
|
@ -229,29 +228,29 @@
|
|||
#elif defined (PJ_M_ARMV4) || defined(ARM) || defined(_ARM_) || \
|
||||
defined(ARMV4) || defined(__arm__)
|
||||
/*
|
||||
* ARM, default to little endian
|
||||
* ARM, bi-endian, so raise error if endianness is not configured
|
||||
*/
|
||||
# undef PJ_M_ARMV4
|
||||
# define PJ_M_ARMV4 1
|
||||
# define PJ_M_NAME "armv4"
|
||||
# define PJ_HAS_PENTIUM 0
|
||||
# if !defined(PJ_IS_LITTLE_ENDIAN) && !defined(PJ_IS_BIG_ENDIAN)
|
||||
# define PJ_IS_LITTLE_ENDIAN 1
|
||||
# define PJ_IS_BIG_ENDIAN 0
|
||||
# if !PJ_IS_LITTLE_ENDIAN && !PJ_IS_BIG_ENDIAN
|
||||
# error Endianness must be declared for this processor
|
||||
# endif
|
||||
|
||||
#elif defined (PJ_M_POWERPC) || defined(__powerpc) || defined(__powerpc__) || \
|
||||
defined(__POWERPC__) || defined(__ppc__) || defined(_M_PPC) || \
|
||||
defined(_ARCH_PPC)
|
||||
/*
|
||||
* PowerPC, big endian
|
||||
* PowerPC, bi-endian, so raise error if endianness is not configured
|
||||
*/
|
||||
# undef PJ_M_POWERPC
|
||||
# define PJ_M_POWERPC 1
|
||||
# define PJ_M_NAME "powerpc"
|
||||
# define PJ_HAS_PENTIUM 0
|
||||
# define PJ_IS_LITTLE_ENDIAN 0
|
||||
# define PJ_IS_BIG_ENDIAN 1
|
||||
# if !PJ_IS_LITTLE_ENDIAN && !PJ_IS_BIG_ENDIAN
|
||||
# error Endianness must be declared for this processor
|
||||
# endif
|
||||
|
||||
#elif defined (PJ_M_NIOS2) || defined(__nios2) || defined(__nios2__) || \
|
||||
defined(__NIOS2__) || defined(__M_NIOS2) || defined(_ARCH_NIOS2)
|
||||
|
@ -1123,13 +1122,13 @@ PJ_BEGIN_DECL
|
|||
#define PJ_VERSION_NUM_MAJOR 1
|
||||
|
||||
/** PJLIB version minor number. */
|
||||
#define PJ_VERSION_NUM_MINOR 10
|
||||
#define PJ_VERSION_NUM_MINOR 16
|
||||
|
||||
/** PJLIB version revision number. */
|
||||
#define PJ_VERSION_NUM_REV 0
|
||||
|
||||
/**
|
||||
* Extra suffix for the version (e.g. "-trunk"), or empty for
|
||||
* Extra suffix for the version (e.g. "-svn"), or empty for
|
||||
* web release version.
|
||||
*/
|
||||
#define PJ_VERSION_NUM_EXTRA "-svn"
|
||||
|
|
|
@ -82,6 +82,17 @@ PJ_DECL(unsigned) pj_GUID_STRING_LENGTH(void);
|
|||
*/
|
||||
PJ_DECL(pj_str_t*) pj_generate_unique_string(pj_str_t *str);
|
||||
|
||||
/**
|
||||
* Create a globally unique string in lowercase, which length is
|
||||
* PJ_GUID_STRING_LENGTH characters. Caller is responsible for preallocating
|
||||
* the storage used in the string.
|
||||
*
|
||||
* @param str The string to store the result.
|
||||
*
|
||||
* @return The string.
|
||||
*/
|
||||
PJ_DECL(pj_str_t*) pj_generate_unique_string_lower(pj_str_t *str);
|
||||
|
||||
/**
|
||||
* Generate a unique string.
|
||||
*
|
||||
|
@ -90,6 +101,14 @@ PJ_DECL(pj_str_t*) pj_generate_unique_string(pj_str_t *str);
|
|||
*/
|
||||
PJ_DECL(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str);
|
||||
|
||||
/**
|
||||
* Generate a unique string in lowercase.
|
||||
*
|
||||
* @param pool Pool to allocate memory from.
|
||||
* @param str The string.
|
||||
*/
|
||||
PJ_DECL(void) pj_create_unique_string_lower(pj_pool_t *pool, pj_str_t *str);
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
|
|
@ -75,8 +75,8 @@ PJ_DECL(pj_uint32_t) pj_hash_calc(pj_uint32_t hval,
|
|||
* string is stored in \c result.
|
||||
*
|
||||
* @param hval The initial hash value, normally zero.
|
||||
* @param result Buffer to store the result, which must be enough to hold
|
||||
* the string.
|
||||
* @param result Optional. Buffer to store the result, which must be enough
|
||||
* to hold the string.
|
||||
* @param key The input key to be converted and calculated.
|
||||
*
|
||||
* @return The hash value.
|
||||
|
@ -115,6 +115,17 @@ PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht,
|
|||
pj_uint32_t *hval );
|
||||
|
||||
|
||||
/**
|
||||
* Variant of #pj_hash_get() with the key being converted to lowercase when
|
||||
* calculating the hash value.
|
||||
*
|
||||
* @see pj_hash_get()
|
||||
*/
|
||||
PJ_DECL(void *) pj_hash_get_lower( pj_hash_table_t *ht,
|
||||
const void *key, unsigned keylen,
|
||||
pj_uint32_t *hval );
|
||||
|
||||
|
||||
/**
|
||||
* Associate/disassociate a value with the specified key. If value is not
|
||||
* NULL and entry already exists, the entry's value will be overwritten.
|
||||
|
@ -125,8 +136,8 @@ PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht,
|
|||
* @param pool the pool to allocate the new entry if a new entry has to be
|
||||
* created.
|
||||
* @param ht the hash table.
|
||||
* @param key the key, which MUST point to buffer that remains valid
|
||||
* for the duration of the entry.
|
||||
* @param key the key. If pool is not specified, the key MUST point to
|
||||
* buffer that remains valid for the duration of the entry.
|
||||
* @param keylen the length of the key, or PJ_HASH_KEY_STRING to use the
|
||||
* string length of the key.
|
||||
* @param hval if the value is not zero, then the hash table will use
|
||||
|
@ -141,6 +152,17 @@ PJ_DECL(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
|
|||
void *value );
|
||||
|
||||
|
||||
/**
|
||||
* Variant of #pj_hash_set() with the key being converted to lowercase when
|
||||
* calculating the hash value.
|
||||
*
|
||||
* @see pj_hash_set()
|
||||
*/
|
||||
PJ_DECL(void) pj_hash_set_lower( pj_pool_t *pool, pj_hash_table_t *ht,
|
||||
const void *key, unsigned keylen,
|
||||
pj_uint32_t hval, void *value );
|
||||
|
||||
|
||||
/**
|
||||
* Associate/disassociate a value with the specified key. This function works
|
||||
* like #pj_hash_set(), except that it doesn't use pool (hence the np -- no
|
||||
|
@ -164,6 +186,18 @@ PJ_DECL(void) pj_hash_set_np(pj_hash_table_t *ht,
|
|||
pj_uint32_t hval, pj_hash_entry_buf entry_buf,
|
||||
void *value);
|
||||
|
||||
/**
|
||||
* Variant of #pj_hash_set_np() with the key being converted to lowercase
|
||||
* when calculating the hash value.
|
||||
*
|
||||
* @see pj_hash_set_np()
|
||||
*/
|
||||
PJ_DECL(void) pj_hash_set_np_lower(pj_hash_table_t *ht,
|
||||
const void *key, unsigned keylen,
|
||||
pj_uint32_t hval,
|
||||
pj_hash_entry_buf entry_buf,
|
||||
void *value);
|
||||
|
||||
/**
|
||||
* Get the total number of entries in the hash table.
|
||||
*
|
||||
|
|
|
@ -509,7 +509,7 @@ PJ_INLINE(void*) pj_pool_zalloc(pj_pool_t *pool, pj_size_t size)
|
|||
* Internal functions
|
||||
*/
|
||||
PJ_IDECL(void*) pj_pool_alloc_from_block(pj_pool_block *block, pj_size_t size);
|
||||
PJ_DECL(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size);
|
||||
PJ_DECL(void*) pj_pool_allocate_find(pj_pool_t *pool, pj_size_t size);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ PJ_IDEF(void*) pj_pool_alloc_from_block( pj_pool_block *block, pj_size_t size )
|
|||
if (size & (PJ_POOL_ALIGNMENT-1)) {
|
||||
size = (size + PJ_POOL_ALIGNMENT) & ~(PJ_POOL_ALIGNMENT-1);
|
||||
}
|
||||
if ((unsigned)(block->end - block->cur) >= size) {
|
||||
if ((pj_size_t)(block->end - block->cur) >= size) {
|
||||
void *ptr = block->cur;
|
||||
block->cur += size;
|
||||
return ptr;
|
||||
|
|
|
@ -493,6 +493,13 @@ typedef struct pj_in_addr
|
|||
*/
|
||||
#define PJ_INET6_ADDRSTRLEN 46
|
||||
|
||||
/**
|
||||
* The size of sin_zero field in pj_sockaddr_in structure. Most OSes
|
||||
* use 8, but others such as the BSD TCP/IP stack in eCos uses 24.
|
||||
*/
|
||||
#ifndef PJ_SOCKADDR_IN_SIN_ZERO_LEN
|
||||
# define PJ_SOCKADDR_IN_SIN_ZERO_LEN 8
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This structure describes Internet socket address.
|
||||
|
@ -512,7 +519,7 @@ struct pj_sockaddr_in
|
|||
#endif
|
||||
pj_uint16_t sin_port; /**< Transport layer port number. */
|
||||
pj_in_addr sin_addr; /**< IP address. */
|
||||
char sin_zero[8]; /**< Padding. */
|
||||
char sin_zero[PJ_SOCKADDR_IN_SIN_ZERO_LEN]; /**< Padding.*/
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -331,16 +331,38 @@ PJ_DECL(pj_status_t) pj_ssl_cipher_get_availables(pj_ssl_cipher ciphers[],
|
|||
unsigned *cipher_num);
|
||||
|
||||
|
||||
/**
|
||||
* Check if the specified cipher is supported by SSL/TLS backend.
|
||||
*
|
||||
* @param cipher The cipher.
|
||||
*
|
||||
* @return PJ_TRUE when supported.
|
||||
*/
|
||||
PJ_DECL(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher);
|
||||
|
||||
|
||||
/**
|
||||
* Get cipher name string.
|
||||
*
|
||||
* @param cipher The cipher.
|
||||
*
|
||||
* @return The cipher name or NULL if cipher is not recognized.
|
||||
* @return The cipher name or NULL if cipher is not recognized/
|
||||
* supported.
|
||||
*/
|
||||
PJ_DECL(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher);
|
||||
|
||||
|
||||
/**
|
||||
* Get cipher ID from cipher name string.
|
||||
*
|
||||
* @param cipher_name The cipher name string.
|
||||
*
|
||||
* @return The cipher ID or PJ_TLS_UNKNOWN_CIPHER if the cipher
|
||||
* name string is not recognized/supported.
|
||||
*/
|
||||
PJ_DECL(pj_ssl_cipher) pj_ssl_cipher_id(const char *cipher_name);
|
||||
|
||||
|
||||
/**
|
||||
* This structure contains the callbacks to be called by the secure socket.
|
||||
*/
|
||||
|
@ -520,6 +542,11 @@ typedef struct pj_ssl_sock_info
|
|||
*/
|
||||
pj_uint32_t verify_status;
|
||||
|
||||
/**
|
||||
* Last native error returned by the backend.
|
||||
*/
|
||||
unsigned long last_native_err;
|
||||
|
||||
} pj_ssl_sock_info;
|
||||
|
||||
|
||||
|
|
|
@ -290,6 +290,9 @@ typedef int pj_exception_id_t;
|
|||
* in random string generation, and to initialize operating system dependent
|
||||
* functionality (such as WSAStartup() in Windows).
|
||||
*
|
||||
* Apart from calling pj_init(), application typically should also initialize
|
||||
* the random seed by calling pj_srand().
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pj_init(void);
|
||||
|
|
|
@ -17,11 +17,32 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <pj/ctype.h>
|
||||
#include <pj/guid.h>
|
||||
#include <pj/pool.h>
|
||||
|
||||
PJ_DEF(pj_str_t*) pj_generate_unique_string_lower(pj_str_t *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
pj_generate_unique_string(str);
|
||||
for (i = 0; i < str->slen; i++)
|
||||
str->ptr[i] = (char)pj_tolower(str->ptr[i]);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
PJ_DEF(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str)
|
||||
{
|
||||
str->ptr = (char*)pj_pool_alloc(pool, PJ_GUID_STRING_LENGTH);
|
||||
pj_generate_unique_string(str);
|
||||
}
|
||||
|
||||
PJ_DEF(void) pj_create_unique_string_lower(pj_pool_t *pool, pj_str_t *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
pj_create_unique_string(pool, str);
|
||||
for (i = 0; i < str->slen; i++)
|
||||
str->ptr[i] = (char)pj_tolower(str->ptr[i]);
|
||||
}
|
||||
|
|
|
@ -79,16 +79,21 @@ PJ_DEF(pj_uint32_t) pj_hash_calc_tolower( pj_uint32_t hval,
|
|||
#if defined(PJ_HASH_USE_OWN_TOLOWER) && PJ_HASH_USE_OWN_TOLOWER != 0
|
||||
for (i=0; i<key->slen; ++i) {
|
||||
pj_uint8_t c = key->ptr[i];
|
||||
char lower;
|
||||
if (c & 64)
|
||||
result[i] = (char)(c | 32);
|
||||
lower = (char)(c | 32);
|
||||
else
|
||||
result[i] = (char)c;
|
||||
hval = hval * PJ_HASH_MULTIPLIER + result[i];
|
||||
lower = (char)c;
|
||||
if (result)
|
||||
result[i] = lower;
|
||||
hval = hval * PJ_HASH_MULTIPLIER + lower;
|
||||
}
|
||||
#else
|
||||
for (i=0; i<key->slen; ++i) {
|
||||
result[i] = (char)pj_tolower(key->ptr[i]);
|
||||
hval = hval * PJ_HASH_MULTIPLIER + result[i];
|
||||
char lower = (char)pj_tolower(key->ptr[i]);
|
||||
if (result)
|
||||
result[i] = lower;
|
||||
hval = hval * PJ_HASH_MULTIPLIER + lower;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -128,7 +133,7 @@ PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size)
|
|||
static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht,
|
||||
const void *key, unsigned keylen,
|
||||
void *val, pj_uint32_t *hval,
|
||||
void *entry_buf)
|
||||
void *entry_buf, pj_bool_t lower)
|
||||
{
|
||||
pj_uint32_t hash;
|
||||
pj_hash_entry **p_entry, *entry;
|
||||
|
@ -146,14 +151,20 @@ static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht,
|
|||
if (keylen==PJ_HASH_KEY_STRING) {
|
||||
const pj_uint8_t *p = (const pj_uint8_t*)key;
|
||||
for ( ; *p; ++p ) {
|
||||
hash = hash * PJ_HASH_MULTIPLIER + *p;
|
||||
if (lower)
|
||||
hash = hash * PJ_HASH_MULTIPLIER + pj_tolower(*p);
|
||||
else
|
||||
hash = hash * PJ_HASH_MULTIPLIER + *p;
|
||||
}
|
||||
keylen = p - (const unsigned char*)key;
|
||||
} else {
|
||||
const pj_uint8_t *p = (const pj_uint8_t*)key,
|
||||
*end = p + keylen;
|
||||
for ( ; p!=end; ++p) {
|
||||
hash = hash * PJ_HASH_MULTIPLIER + *p;
|
||||
if (lower)
|
||||
hash = hash * PJ_HASH_MULTIPLIER + pj_tolower(*p);
|
||||
else
|
||||
hash = hash * PJ_HASH_MULTIPLIER + *p;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,9 +179,11 @@ static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht,
|
|||
p_entry = &entry->next, entry = *p_entry)
|
||||
{
|
||||
if (entry->hash==hash && entry->keylen==keylen &&
|
||||
pj_memcmp(entry->key, key, keylen)==0)
|
||||
((lower && pj_ansi_strnicmp((const char*)entry->key,
|
||||
(const char*)key, keylen)==0) ||
|
||||
(!lower && pj_memcmp(entry->key, key, keylen)==0)))
|
||||
{
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,17 +227,27 @@ PJ_DEF(void *) pj_hash_get( pj_hash_table_t *ht,
|
|||
pj_uint32_t *hval)
|
||||
{
|
||||
pj_hash_entry *entry;
|
||||
entry = *find_entry( NULL, ht, key, keylen, NULL, hval, NULL);
|
||||
entry = *find_entry( NULL, ht, key, keylen, NULL, hval, NULL, PJ_FALSE);
|
||||
return entry ? entry->value : NULL;
|
||||
}
|
||||
|
||||
PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
|
||||
const void *key, unsigned keylen, pj_uint32_t hval,
|
||||
void *value )
|
||||
PJ_DEF(void *) pj_hash_get_lower( pj_hash_table_t *ht,
|
||||
const void *key, unsigned keylen,
|
||||
pj_uint32_t *hval)
|
||||
{
|
||||
pj_hash_entry *entry;
|
||||
entry = *find_entry( NULL, ht, key, keylen, NULL, hval, NULL, PJ_TRUE);
|
||||
return entry ? entry->value : NULL;
|
||||
}
|
||||
|
||||
static void hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
|
||||
const void *key, unsigned keylen, pj_uint32_t hval,
|
||||
void *value, void *entry_buf, pj_bool_t lower )
|
||||
{
|
||||
pj_hash_entry **p_entry;
|
||||
|
||||
p_entry = find_entry( pool, ht, key, keylen, value, &hval, NULL);
|
||||
p_entry = find_entry( pool, ht, key, keylen, value, &hval, entry_buf,
|
||||
lower);
|
||||
if (*p_entry) {
|
||||
if (value == NULL) {
|
||||
/* delete entry */
|
||||
|
@ -241,29 +264,35 @@ PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
|
|||
}
|
||||
}
|
||||
|
||||
PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
|
||||
const void *key, unsigned keylen, pj_uint32_t hval,
|
||||
void *value )
|
||||
{
|
||||
hash_set(pool, ht, key, keylen, hval, value, NULL, PJ_FALSE);
|
||||
}
|
||||
|
||||
PJ_DEF(void) pj_hash_set_lower( pj_pool_t *pool, pj_hash_table_t *ht,
|
||||
const void *key, unsigned keylen,
|
||||
pj_uint32_t hval, void *value )
|
||||
{
|
||||
hash_set(pool, ht, key, keylen, hval, value, NULL, PJ_TRUE);
|
||||
}
|
||||
|
||||
PJ_DEF(void) pj_hash_set_np( pj_hash_table_t *ht,
|
||||
const void *key, unsigned keylen,
|
||||
pj_uint32_t hval, pj_hash_entry_buf entry_buf,
|
||||
void *value)
|
||||
{
|
||||
pj_hash_entry **p_entry;
|
||||
hash_set(NULL, ht, key, keylen, hval, value, (void *)entry_buf, PJ_FALSE);
|
||||
}
|
||||
|
||||
p_entry = find_entry( NULL, ht, key, keylen, value, &hval,
|
||||
(void*)entry_buf );
|
||||
if (*p_entry) {
|
||||
if (value == NULL) {
|
||||
/* delete entry */
|
||||
PJ_LOG(6, ("hashtbl", "%p: p_entry %p deleted", ht, *p_entry));
|
||||
*p_entry = (*p_entry)->next;
|
||||
--ht->count;
|
||||
|
||||
} else {
|
||||
/* overwrite */
|
||||
(*p_entry)->value = value;
|
||||
PJ_LOG(6, ("hashtbl", "%p: p_entry %p value set to %p", ht,
|
||||
*p_entry, value));
|
||||
}
|
||||
}
|
||||
PJ_DEF(void) pj_hash_set_np_lower( pj_hash_table_t *ht,
|
||||
const void *key, unsigned keylen,
|
||||
pj_uint32_t hval,
|
||||
pj_hash_entry_buf entry_buf,
|
||||
void *value)
|
||||
{
|
||||
hash_set(NULL, ht, key, keylen, hval, value, (void *)entry_buf, PJ_TRUE);
|
||||
}
|
||||
|
||||
PJ_DEF(unsigned) pj_hash_count( pj_hash_table_t *ht )
|
||||
|
|
|
@ -283,7 +283,7 @@ void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h)
|
|||
/* Socket is writable. */
|
||||
struct write_operation *write_op;
|
||||
pj_ssize_t sent;
|
||||
pj_status_t send_rc;
|
||||
pj_status_t send_rc = PJ_SUCCESS;
|
||||
|
||||
/* Get the first in the queue. */
|
||||
write_op = h->write_list.next;
|
||||
|
@ -312,8 +312,8 @@ void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h)
|
|||
*/
|
||||
//write_op->op = 0;
|
||||
} else if (write_op->op == PJ_IOQUEUE_OP_SEND_TO) {
|
||||
int retry;
|
||||
for (retry=0; retry<2; ++retry) {
|
||||
int retry = 2;
|
||||
while (--retry >= 0) {
|
||||
send_rc = pj_sock_sendto(h->fd,
|
||||
write_op->buf+write_op->written,
|
||||
&sent, write_op->flags,
|
||||
|
@ -945,7 +945,11 @@ PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
|
|||
PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
|
||||
PJ_CHECK_STACK();
|
||||
|
||||
#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
|
||||
PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
|
||||
retry_on_restart:
|
||||
#endif
|
||||
|
||||
/* Check if key is closing. */
|
||||
if (IS_CLOSING(key))
|
||||
return PJ_ECANCELLED;
|
||||
|
|
|
@ -340,6 +340,7 @@ CPjSocket *CIoqueueCallback::HandleAcceptCompletion()
|
|||
//
|
||||
void CIoqueueCallback::RunL()
|
||||
{
|
||||
pj_ioqueue_t *ioq = ioqueue_;
|
||||
Type cur_type = type_;
|
||||
|
||||
type_ = TYPE_NONE;
|
||||
|
@ -399,7 +400,7 @@ void CIoqueueCallback::RunL()
|
|||
}
|
||||
}
|
||||
|
||||
ioqueue_->eventCount++;
|
||||
ioq->eventCount++;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -165,9 +165,6 @@ static pj_status_t if_enum_by_af(int af,
|
|||
return PJ_RETURN_OS_ERROR(oserr);
|
||||
}
|
||||
|
||||
/* Done with socket */
|
||||
pj_sock_close(sock);
|
||||
|
||||
/* Interface interfaces */
|
||||
ifr = (struct ifreq*) ifc.ifc_req;
|
||||
count = ifc.ifc_len / sizeof(struct ifreq);
|
||||
|
@ -177,6 +174,7 @@ static pj_status_t if_enum_by_af(int af,
|
|||
*p_cnt = 0;
|
||||
for (i=0; i<count; ++i) {
|
||||
struct ifreq *itf = &ifr[i];
|
||||
struct ifreq iff = *itf;
|
||||
struct sockaddr *ad = &itf->ifr_addr;
|
||||
|
||||
TRACE_((THIS_FILE, " checking interface %s", itf->ifr_name));
|
||||
|
@ -188,13 +186,19 @@ static pj_status_t if_enum_by_af(int af,
|
|||
continue;
|
||||
}
|
||||
|
||||
if ((itf->ifr_flags & IFF_UP)==0) {
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &iff) != 0) {
|
||||
TRACE_((THIS_FILE, " ioctl(SIOCGIFFLAGS) failed: %s",
|
||||
get_os_errmsg()));
|
||||
continue; /* Failed to get flags, continue */
|
||||
}
|
||||
|
||||
if ((iff.ifr_flags & IFF_UP)==0) {
|
||||
TRACE_((THIS_FILE, " interface is down"));
|
||||
continue; /* Skip when interface is down */
|
||||
}
|
||||
|
||||
#if PJ_IP_HELPER_IGNORE_LOOPBACK_IF
|
||||
if (itf->ifr_flags & IFF_LOOPBACK) {
|
||||
if (iff.ifr_flags & IFF_LOOPBACK) {
|
||||
TRACE_((THIS_FILE, " loopback interface"));
|
||||
continue; /* Skip loopback interface */
|
||||
}
|
||||
|
@ -220,10 +224,14 @@ static pj_status_t if_enum_by_af(int af,
|
|||
(*p_cnt)++;
|
||||
}
|
||||
|
||||
/* Done with socket */
|
||||
pj_sock_close(sock);
|
||||
|
||||
TRACE_((THIS_FILE, "done, found %d address(es)", *p_cnt));
|
||||
return (*p_cnt != 0) ? PJ_SUCCESS : PJ_ENOTFOUND;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(PJ_HAS_NET_IF_H) && PJ_HAS_NET_IF_H != 0
|
||||
/* Note: this does not work with IPv6 */
|
||||
static pj_status_t if_enum_by_af(int af, unsigned *p_cnt, pj_sockaddr ifs[])
|
||||
|
|
|
@ -75,6 +75,9 @@ struct pj_sem_t
|
|||
int max;
|
||||
};
|
||||
|
||||
/* Flag and reference counter for PJLIB instance */
|
||||
static int initialized;
|
||||
|
||||
/* Flags to indicate which TLS variables have been used */
|
||||
static int tls_vars[PJ_MAX_TLS];
|
||||
|
||||
|
@ -83,8 +86,6 @@ static unsigned atexit_count;
|
|||
static void (*atexit_func[32])(void);
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CPjTimeoutTimer implementation
|
||||
|
@ -335,6 +336,12 @@ PJ_DEF(pj_status_t) pj_init(void)
|
|||
char stack_ptr;
|
||||
pj_status_t status;
|
||||
|
||||
/* Check if PJLIB have been initialized */
|
||||
if (initialized) {
|
||||
++initialized;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
pj_ansi_strcpy(main_thread.obj_name, "pjthread");
|
||||
|
||||
// Init main thread
|
||||
|
@ -368,6 +375,10 @@ PJ_DEF(pj_status_t) pj_init(void)
|
|||
stack_ptr = '\0';
|
||||
#endif
|
||||
|
||||
/* Flag PJLIB as initialized */
|
||||
++initialized;
|
||||
pj_assert(initialized == 1);
|
||||
|
||||
PJ_LOG(5,(THIS_FILE, "PJLIB initialized."));
|
||||
return PJ_SUCCESS;
|
||||
|
||||
|
@ -390,6 +401,11 @@ PJ_DEF(pj_status_t) pj_atexit(pj_exit_callback func)
|
|||
|
||||
PJ_DEF(void) pj_shutdown(void)
|
||||
{
|
||||
/* Only perform shutdown operation when 'initialized' reaches zero */
|
||||
pj_assert(initialized > 0);
|
||||
if (--initialized != 0)
|
||||
return;
|
||||
|
||||
/* Call atexit() functions */
|
||||
while (atexit_count > 0) {
|
||||
(*atexit_func[atexit_count-1])();
|
||||
|
|
|
@ -102,6 +102,11 @@ struct pj_event_t
|
|||
#endif /* PJ_HAS_EVENT_OBJ */
|
||||
|
||||
|
||||
/*
|
||||
* Flag and reference counter for PJLIB instance.
|
||||
*/
|
||||
static int initialized;
|
||||
|
||||
#if PJ_HAS_THREADS
|
||||
static pj_thread_t main_thread;
|
||||
static long thread_tls_id;
|
||||
|
@ -127,6 +132,12 @@ PJ_DEF(pj_status_t) pj_init(void)
|
|||
pj_str_t guid;
|
||||
pj_status_t rc;
|
||||
|
||||
/* Check if PJLIB have been initialized */
|
||||
if (initialized) {
|
||||
++initialized;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
#if PJ_HAS_THREADS
|
||||
/* Init this thread's TLS. */
|
||||
if ((rc=pj_thread_init()) != 0) {
|
||||
|
@ -167,6 +178,10 @@ PJ_DEF(pj_status_t) pj_init(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Flag PJLIB as initialized */
|
||||
++initialized;
|
||||
pj_assert(initialized == 1);
|
||||
|
||||
PJ_LOG(4,(THIS_FILE, "pjlib %s for POSIX initialized",
|
||||
PJ_VERSION));
|
||||
|
||||
|
@ -192,6 +207,11 @@ PJ_DEF(void) pj_shutdown()
|
|||
{
|
||||
int i;
|
||||
|
||||
/* Only perform shutdown operation when 'initialized' reaches zero */
|
||||
pj_assert(initialized > 0);
|
||||
if (--initialized != 0)
|
||||
return;
|
||||
|
||||
/* Call atexit() functions */
|
||||
for (i=atexit_count-1; i>=0; --i) {
|
||||
(*atexit_func[i])();
|
||||
|
|
|
@ -116,6 +116,11 @@ struct pj_atomic_t
|
|||
long value;
|
||||
};
|
||||
|
||||
/*
|
||||
* Flag and reference counter for PJLIB instance.
|
||||
*/
|
||||
static int initialized;
|
||||
|
||||
/*
|
||||
* Static global variables.
|
||||
*/
|
||||
|
@ -142,6 +147,12 @@ PJ_DEF(pj_status_t) pj_init(void)
|
|||
pj_str_t guid;
|
||||
pj_status_t rc;
|
||||
|
||||
/* Check if PJLIB have been initialized */
|
||||
if (initialized) {
|
||||
++initialized;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Init Winsock.. */
|
||||
if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
|
||||
return PJ_RETURN_OS_ERROR(WSAGetLastError());
|
||||
|
@ -187,6 +198,10 @@ PJ_DEF(pj_status_t) pj_init(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Flag PJLIB as initialized */
|
||||
++initialized;
|
||||
pj_assert(initialized == 1);
|
||||
|
||||
PJ_LOG(4,(THIS_FILE, "pjlib %s for win32 initialized",
|
||||
PJ_VERSION));
|
||||
|
||||
|
@ -213,6 +228,11 @@ PJ_DEF(void) pj_shutdown()
|
|||
{
|
||||
int i;
|
||||
|
||||
/* Only perform shutdown operation when 'initialized' reaches zero */
|
||||
pj_assert(initialized > 0);
|
||||
if (--initialized != 0)
|
||||
return;
|
||||
|
||||
/* Display stack usage */
|
||||
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
|
||||
{
|
||||
|
@ -559,6 +579,9 @@ PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
|
|||
PJ_CHECK_STACK();
|
||||
PJ_ASSERT_RETURN(p, PJ_EINVAL);
|
||||
|
||||
if (p == pj_thread_this())
|
||||
return PJ_ECANCELLED;
|
||||
|
||||
PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
|
||||
|
||||
rc = WaitForSingleObject(rec->hthread, INFINITE);
|
||||
|
|
|
@ -242,6 +242,9 @@ PJ_DEF(const pj_sys_info*) pj_get_sys_info(void)
|
|||
} else {
|
||||
si.os_name = pj_str("Unknown");
|
||||
}
|
||||
|
||||
/* Avoid compile warning on Symbian. */
|
||||
goto get_sdk_info;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
|
|||
* If no space is available in all the blocks, a new block might be created
|
||||
* (depending on whether the pool is allowed to resize).
|
||||
*/
|
||||
PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
|
||||
PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, pj_size_t size)
|
||||
{
|
||||
pj_pool_block *block = pool->block_list.next;
|
||||
void *p;
|
||||
|
@ -121,7 +121,7 @@ PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
|
|||
if (pool->increment_size <
|
||||
size + sizeof(pj_pool_block) + PJ_POOL_ALIGNMENT)
|
||||
{
|
||||
unsigned count;
|
||||
pj_size_t count;
|
||||
count = (size + pool->increment_size + sizeof(pj_pool_block) +
|
||||
PJ_POOL_ALIGNMENT) /
|
||||
pool->increment_size;
|
||||
|
|
|
@ -178,7 +178,11 @@ static pj_pool_t* cpool_create_pool(pj_pool_factory *pf,
|
|||
pj_pool_init_int(pool, name, increment_sz, callback);
|
||||
|
||||
/* Update pool manager's free capacity. */
|
||||
cp->capacity -= pj_pool_get_capacity(pool);
|
||||
if (cp->capacity > pj_pool_get_capacity(pool)) {
|
||||
cp->capacity -= pj_pool_get_capacity(pool);
|
||||
} else {
|
||||
cp->capacity = 0;
|
||||
}
|
||||
|
||||
PJ_LOG(6, (pool->obj_name, "pool reused, size=%u", pool->capacity));
|
||||
}
|
||||
|
@ -199,7 +203,7 @@ static pj_pool_t* cpool_create_pool(pj_pool_factory *pf,
|
|||
static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
|
||||
{
|
||||
pj_caching_pool *cp = (pj_caching_pool*)pf;
|
||||
unsigned pool_capacity;
|
||||
pj_size_t pool_capacity;
|
||||
unsigned i;
|
||||
|
||||
PJ_CHECK_STACK();
|
||||
|
|
|
@ -718,7 +718,6 @@ PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
|
|||
{
|
||||
PJ_CHECK_STACK();
|
||||
PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
|
||||
|
||||
*len = recvfrom(sock, (char*)buf, *len, flags,
|
||||
(struct sockaddr*)from, (socklen_t*)fromlen);
|
||||
|
@ -726,7 +725,9 @@ PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
|
|||
if (*len < 0)
|
||||
return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
|
||||
else {
|
||||
PJ_SOCKADDR_RESET_LEN(from);
|
||||
if (from) {
|
||||
PJ_SOCKADDR_RESET_LEN(from);
|
||||
}
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -784,6 +784,8 @@ PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr)
|
|||
addr->addr.sa_family = (pj_uint16_t)af;
|
||||
PJ_SOCKADDR_RESET_LEN(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);
|
||||
|
@ -797,7 +799,10 @@ PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr)
|
|||
TRACE_((THIS_FILE, "hostname IP is %s",
|
||||
pj_sockaddr_print(&ai.ai_addr, strip, sizeof(strip), 0)));
|
||||
}
|
||||
|
||||
#else
|
||||
PJ_UNUSED_ARG(ai);
|
||||
PJ_UNUSED_ARG(count);
|
||||
#endif
|
||||
|
||||
/* Get default interface (interface for default route) */
|
||||
if (cand_cnt < PJ_ARRAY_SIZE(cand_addr)) {
|
||||
|
|
|
@ -21,89 +21,6 @@
|
|||
#include <pj/errno.h>
|
||||
#include <pj/string.h>
|
||||
|
||||
/* Cipher name structure */
|
||||
typedef struct cipher_name_t {
|
||||
pj_ssl_cipher cipher;
|
||||
const char *name;
|
||||
} cipher_name_t;
|
||||
|
||||
/* Cipher name constants */
|
||||
static cipher_name_t cipher_names[] =
|
||||
{
|
||||
{PJ_TLS_NULL_WITH_NULL_NULL, "NULL"},
|
||||
|
||||
/* TLS/SSLv3 */
|
||||
{PJ_TLS_RSA_WITH_NULL_MD5, "TLS_RSA_WITH_NULL_MD5"},
|
||||
{PJ_TLS_RSA_WITH_NULL_SHA, "TLS_RSA_WITH_NULL_SHA"},
|
||||
{PJ_TLS_RSA_WITH_NULL_SHA256, "TLS_RSA_WITH_NULL_SHA256"},
|
||||
{PJ_TLS_RSA_WITH_RC4_128_MD5, "TLS_RSA_WITH_RC4_128_MD5"},
|
||||
{PJ_TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA"},
|
||||
{PJ_TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
|
||||
{PJ_TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"},
|
||||
{PJ_TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA"},
|
||||
{PJ_TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256"},
|
||||
{PJ_TLS_RSA_WITH_AES_256_CBC_SHA256, "TLS_RSA_WITH_AES_256_CBC_SHA256"},
|
||||
{PJ_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"},
|
||||
{PJ_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"},
|
||||
{PJ_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"},
|
||||
{PJ_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"},
|
||||
{PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"},
|
||||
{PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"},
|
||||
{PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"},
|
||||
{PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"},
|
||||
{PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"},
|
||||
{PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"},
|
||||
{PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"},
|
||||
{PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
|
||||
{PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA256, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"},
|
||||
{PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA256, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"},
|
||||
{PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"},
|
||||
{PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"},
|
||||
{PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA256, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"},
|
||||
{PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA256, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"},
|
||||
{PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"},
|
||||
{PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
|
||||
{PJ_TLS_DH_anon_WITH_RC4_128_MD5, "TLS_DH_anon_WITH_RC4_128_MD5"},
|
||||
{PJ_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"},
|
||||
{PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA, "TLS_DH_anon_WITH_AES_128_CBC_SHA"},
|
||||
{PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA, "TLS_DH_anon_WITH_AES_256_CBC_SHA"},
|
||||
{PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA256, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"},
|
||||
{PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA256, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"},
|
||||
|
||||
/* TLS (deprecated) */
|
||||
{PJ_TLS_RSA_EXPORT_WITH_RC4_40_MD5, "TLS_RSA_EXPORT_WITH_RC4_40_MD5"},
|
||||
{PJ_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"},
|
||||
{PJ_TLS_RSA_WITH_IDEA_CBC_SHA, "TLS_RSA_WITH_IDEA_CBC_SHA"},
|
||||
{PJ_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"},
|
||||
{PJ_TLS_RSA_WITH_DES_CBC_SHA, "TLS_RSA_WITH_DES_CBC_SHA"},
|
||||
{PJ_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"},
|
||||
{PJ_TLS_DH_DSS_WITH_DES_CBC_SHA, "TLS_DH_DSS_WITH_DES_CBC_SHA"},
|
||||
{PJ_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"},
|
||||
{PJ_TLS_DH_RSA_WITH_DES_CBC_SHA, "TLS_DH_RSA_WITH_DES_CBC_SHA"},
|
||||
{PJ_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"},
|
||||
{PJ_TLS_DHE_DSS_WITH_DES_CBC_SHA, "TLS_DHE_DSS_WITH_DES_CBC_SHA"},
|
||||
{PJ_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"},
|
||||
{PJ_TLS_DHE_RSA_WITH_DES_CBC_SHA, "TLS_DHE_RSA_WITH_DES_CBC_SHA"},
|
||||
{PJ_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"},
|
||||
{PJ_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"},
|
||||
{PJ_TLS_DH_anon_WITH_DES_CBC_SHA, "TLS_DH_anon_WITH_DES_CBC_SHA"},
|
||||
|
||||
/* SSLv3 */
|
||||
{PJ_SSL_FORTEZZA_KEA_WITH_NULL_SHA, "SSL_FORTEZZA_KEA_WITH_NULL_SHA"},
|
||||
{PJ_SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA,"SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"},
|
||||
{PJ_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA"},
|
||||
|
||||
/* SSLv2 */
|
||||
{PJ_SSL_CK_RC4_128_WITH_MD5, "SSL_CK_RC4_128_WITH_MD5"},
|
||||
{PJ_SSL_CK_RC4_128_EXPORT40_WITH_MD5, "SSL_CK_RC4_128_EXPORT40_WITH_MD5"},
|
||||
{PJ_SSL_CK_RC2_128_CBC_WITH_MD5, "SSL_CK_RC2_128_CBC_WITH_MD5"},
|
||||
{PJ_SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, "SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5"},
|
||||
{PJ_SSL_CK_IDEA_128_CBC_WITH_MD5, "SSL_CK_IDEA_128_CBC_WITH_MD5"},
|
||||
{PJ_SSL_CK_DES_64_CBC_WITH_MD5, "SSL_CK_DES_64_CBC_WITH_MD5"},
|
||||
{PJ_SSL_CK_DES_192_EDE3_CBC_WITH_MD5, "SSL_CK_DES_192_EDE3_CBC_WITH_MD5"}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Initialize the SSL socket configuration with the default values.
|
||||
*/
|
||||
|
@ -129,23 +46,6 @@ PJ_DEF(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param)
|
|||
}
|
||||
|
||||
|
||||
/* Get cipher name string */
|
||||
PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
|
||||
{
|
||||
unsigned i, n;
|
||||
|
||||
n = PJ_ARRAY_SIZE(cipher_names);
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (cipher == cipher_names[i].cipher)
|
||||
return cipher_names[i].name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PJ_DEF(pj_status_t) pj_ssl_cert_get_verify_status_strings(
|
||||
pj_uint32_t verify_status,
|
||||
const char *error_strings[],
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
/* Workaround for ticket #985 */
|
||||
#define DELAYED_CLOSE_TIMEOUT 200
|
||||
|
||||
/* Maximum ciphers */
|
||||
#define MAX_CIPHERS 100
|
||||
|
||||
/*
|
||||
* Include OpenSSL headers
|
||||
*/
|
||||
|
@ -102,9 +105,10 @@ typedef struct read_data_t
|
|||
ssock->param.read_buffer_size)
|
||||
|
||||
/*
|
||||
* Structure of SSL socket write buffer.
|
||||
* Structure of SSL socket write data.
|
||||
*/
|
||||
typedef struct write_data_t {
|
||||
PJ_DECL_LIST_MEMBER(struct write_data_t);
|
||||
pj_ioqueue_op_key_t key;
|
||||
pj_size_t record_len;
|
||||
pj_ioqueue_op_key_t *app_key;
|
||||
|
@ -118,23 +122,14 @@ typedef struct write_data_t {
|
|||
} write_data_t;
|
||||
|
||||
/*
|
||||
* Structure of SSL socket write state.
|
||||
* Structure of SSL socket write buffer (circular buffer).
|
||||
*/
|
||||
typedef struct write_state_t {
|
||||
typedef struct send_buf_t {
|
||||
char *buf;
|
||||
pj_size_t max_len;
|
||||
char *start;
|
||||
pj_size_t len;
|
||||
write_data_t *last_data;
|
||||
} write_state_t;
|
||||
|
||||
/*
|
||||
* Structure of write data pending.
|
||||
*/
|
||||
typedef struct write_pending_t {
|
||||
PJ_DECL_LIST_MEMBER(struct write_pending_t);
|
||||
write_data_t data;
|
||||
} write_pending_t;
|
||||
} send_buf_t;
|
||||
|
||||
/*
|
||||
* Secure socket structure definition.
|
||||
|
@ -155,6 +150,8 @@ struct pj_ssl_sock_t
|
|||
pj_timer_entry timer;
|
||||
pj_status_t verify_status;
|
||||
|
||||
unsigned long last_err;
|
||||
|
||||
pj_sock_t sock;
|
||||
pj_activesock_t *asock;
|
||||
|
||||
|
@ -168,10 +165,12 @@ struct pj_ssl_sock_t
|
|||
void **asock_rbuf;
|
||||
read_data_t *ssock_rbuf;
|
||||
|
||||
write_state_t write_state;
|
||||
write_pending_t write_pending;
|
||||
write_pending_t write_pending_empty;
|
||||
pj_lock_t *write_mutex; /* protect write BIO and write_state */
|
||||
write_data_t write_pending;/* list of pending write to OpenSSL */
|
||||
write_data_t write_pending_empty; /* cache for write_pending */
|
||||
pj_bool_t flushing_write_pend; /* flag of flushing is ongoing*/
|
||||
send_buf_t send_buf;
|
||||
write_data_t send_pending; /* list of pending write to network */
|
||||
pj_lock_t *write_mutex; /* protect write BIO and send_buf */
|
||||
|
||||
SSL_CTX *ossl_ctx;
|
||||
SSL *ossl_ssl;
|
||||
|
@ -192,6 +191,8 @@ struct pj_ssl_cert_t
|
|||
};
|
||||
|
||||
|
||||
static write_data_t* alloc_send_data(pj_ssl_sock_t *ssock, pj_size_t len);
|
||||
static void free_send_data(pj_ssl_sock_t *ssock, write_data_t *wdata);
|
||||
static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock);
|
||||
|
||||
/*
|
||||
|
@ -209,17 +210,38 @@ static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock);
|
|||
|
||||
#define PJ_SSL_ERRNO_SPACE_SIZE PJ_ERRNO_SPACE_SIZE
|
||||
|
||||
#define STATUS_FROM_SSL_ERR(err, status) { \
|
||||
status = ERR_GET_LIB(err)*300 + ERR_GET_REASON(err);\
|
||||
pj_assert(status < PJ_SSL_ERRNO_SPACE_SIZE);\
|
||||
if (status) status += PJ_SSL_ERRNO_START;\
|
||||
/* 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)
|
||||
{
|
||||
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;
|
||||
ssock->last_err = err;
|
||||
return status;
|
||||
}
|
||||
|
||||
#define GET_SSL_STATUS(status) { \
|
||||
unsigned long e = ERR_get_error();\
|
||||
STATUS_FROM_SSL_ERR(e, status);\
|
||||
static pj_status_t GET_SSL_STATUS(pj_ssl_sock_t *ssock)
|
||||
{
|
||||
return STATUS_FROM_SSL_ERR(ssock, ERR_get_error());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get error string of OpenSSL.
|
||||
*/
|
||||
|
@ -232,8 +254,8 @@ static pj_str_t ssl_strerror(pj_status_t status,
|
|||
if (ssl_err) {
|
||||
unsigned long l, r;
|
||||
ssl_err -= PJ_SSL_ERRNO_START;
|
||||
l = ssl_err/300;
|
||||
r = ssl_err%300;
|
||||
l = ssl_err / MAX_OSSL_ERR_REASON;
|
||||
r = ssl_err % MAX_OSSL_ERR_REASON;
|
||||
ssl_err = ERR_PACK(l, 0, r);
|
||||
}
|
||||
|
||||
|
@ -241,12 +263,7 @@ static pj_str_t ssl_strerror(pj_status_t status,
|
|||
|
||||
{
|
||||
const char *tmp = NULL;
|
||||
|
||||
if (ssl_err >= 300)
|
||||
tmp = ERR_reason_error_string(ssl_err);
|
||||
else
|
||||
tmp = X509_verify_cert_error_string(ssl_err);
|
||||
|
||||
tmp = ERR_reason_error_string(ssl_err);
|
||||
if (tmp) {
|
||||
pj_ansi_strncpy(buf, tmp, bufsize);
|
||||
errstr = pj_str(buf);
|
||||
|
@ -269,8 +286,11 @@ static pj_str_t ssl_strerror(pj_status_t status,
|
|||
static int openssl_init_count;
|
||||
|
||||
/* OpenSSL available ciphers */
|
||||
static pj_ssl_cipher openssl_ciphers[100];
|
||||
static unsigned openssl_cipher_num;
|
||||
static struct openssl_ciphers_t {
|
||||
pj_ssl_cipher id;
|
||||
const char *name;
|
||||
} openssl_ciphers[MAX_CIPHERS];
|
||||
|
||||
/* OpenSSL application data index */
|
||||
static int sslsock_idx;
|
||||
|
@ -310,8 +330,10 @@ static pj_status_t init_openssl(void)
|
|||
meth = (SSL_METHOD*)TLSv1_server_method();
|
||||
if (!meth)
|
||||
meth = (SSL_METHOD*)SSLv3_server_method();
|
||||
#ifndef OPENSSL_NO_SSL2
|
||||
if (!meth)
|
||||
meth = (SSL_METHOD*)SSLv2_server_method();
|
||||
#endif
|
||||
pj_assert(meth);
|
||||
|
||||
ctx=SSL_CTX_new(meth);
|
||||
|
@ -327,9 +349,9 @@ static pj_status_t init_openssl(void)
|
|||
for (i = 0; i < n; ++i) {
|
||||
SSL_CIPHER *c;
|
||||
c = sk_SSL_CIPHER_value(sk_cipher,i);
|
||||
openssl_ciphers[i] = (pj_ssl_cipher)
|
||||
(pj_uint32_t)c->id & 0x00FFFFFF;
|
||||
//printf("%3u: %08x=%s\n", i+1, c->id, SSL_CIPHER_get_name(c));
|
||||
openssl_ciphers[i].id = (pj_ssl_cipher)
|
||||
(pj_uint32_t)c->id & 0x00FFFFFF;
|
||||
openssl_ciphers[i].name = SSL_CIPHER_get_name(c);
|
||||
}
|
||||
|
||||
SSL_free(ssl);
|
||||
|
@ -488,9 +510,11 @@ static pj_status_t create_ssl(pj_ssl_sock_t *ssock)
|
|||
case PJ_SSL_SOCK_PROTO_TLS1:
|
||||
ssl_method = (SSL_METHOD*)TLSv1_method();
|
||||
break;
|
||||
#ifndef OPENSSL_NO_SSL2
|
||||
case PJ_SSL_SOCK_PROTO_SSL2:
|
||||
ssl_method = (SSL_METHOD*)SSLv2_method();
|
||||
break;
|
||||
#endif
|
||||
case PJ_SSL_SOCK_PROTO_SSL3:
|
||||
ssl_method = (SSL_METHOD*)SSLv3_method();
|
||||
break;
|
||||
|
@ -507,8 +531,7 @@ static pj_status_t create_ssl(pj_ssl_sock_t *ssock)
|
|||
/* Create SSL context */
|
||||
ctx = SSL_CTX_new(ssl_method);
|
||||
if (ctx == NULL) {
|
||||
GET_SSL_STATUS(status);
|
||||
return status;
|
||||
return GET_SSL_STATUS(ssock);
|
||||
}
|
||||
|
||||
/* Apply credentials */
|
||||
|
@ -519,7 +542,7 @@ static pj_status_t create_ssl(pj_ssl_sock_t *ssock)
|
|||
rc = SSL_CTX_load_verify_locations(ctx, cert->CA_file.ptr, NULL);
|
||||
|
||||
if (rc != 1) {
|
||||
GET_SSL_STATUS(status);
|
||||
status = GET_SSL_STATUS(ssock);
|
||||
PJ_LOG(1,(ssock->pool->obj_name, "Error loading CA list file "
|
||||
"'%s'", cert->CA_file.ptr));
|
||||
SSL_CTX_free(ctx);
|
||||
|
@ -541,7 +564,7 @@ static pj_status_t create_ssl(pj_ssl_sock_t *ssock)
|
|||
rc = SSL_CTX_use_certificate_chain_file(ctx, cert->cert_file.ptr);
|
||||
|
||||
if(rc != 1) {
|
||||
GET_SSL_STATUS(status);
|
||||
status = GET_SSL_STATUS(ssock);
|
||||
PJ_LOG(1,(ssock->pool->obj_name, "Error loading certificate "
|
||||
"chain file '%s'", cert->cert_file.ptr));
|
||||
SSL_CTX_free(ctx);
|
||||
|
@ -557,7 +580,7 @@ static pj_status_t create_ssl(pj_ssl_sock_t *ssock)
|
|||
SSL_FILETYPE_PEM);
|
||||
|
||||
if(rc != 1) {
|
||||
GET_SSL_STATUS(status);
|
||||
status = GET_SSL_STATUS(ssock);
|
||||
PJ_LOG(1,(ssock->pool->obj_name, "Error adding private key "
|
||||
"from '%s'", cert->privkey_file.ptr));
|
||||
SSL_CTX_free(ctx);
|
||||
|
@ -570,8 +593,7 @@ static pj_status_t create_ssl(pj_ssl_sock_t *ssock)
|
|||
ssock->ossl_ctx = ctx;
|
||||
ssock->ossl_ssl = SSL_new(ssock->ossl_ctx);
|
||||
if (ssock->ossl_ssl == NULL) {
|
||||
GET_SSL_STATUS(status);
|
||||
return status;
|
||||
return GET_SSL_STATUS(ssock);
|
||||
}
|
||||
|
||||
/* Set SSL sock as application data of SSL instance */
|
||||
|
@ -703,9 +725,7 @@ static pj_status_t set_cipher_list(pj_ssl_sock_t *ssock)
|
|||
/* Finally, set chosen cipher list */
|
||||
ret = SSL_set_cipher_list(ssock->ossl_ssl, buf);
|
||||
if (ret < 1) {
|
||||
pj_status_t status;
|
||||
GET_SSL_STATUS(status);
|
||||
return status;
|
||||
return GET_SSL_STATUS(ssock);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
@ -1010,6 +1030,13 @@ static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
|
|||
* reconnect in the callback.
|
||||
*/
|
||||
if (status != PJ_SUCCESS) {
|
||||
/* Server disconnected us, possibly due to SSL nego failure */
|
||||
if (status == PJ_EEOF) {
|
||||
unsigned long err;
|
||||
err = ERR_get_error();
|
||||
if (err != SSL_ERROR_NONE)
|
||||
status = STATUS_FROM_SSL_ERR(ssock, err);
|
||||
}
|
||||
reset_ssl_sock_state(ssock);
|
||||
}
|
||||
if (ssock->param.cb.on_connect_complete) {
|
||||
|
@ -1023,6 +1050,179 @@ static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
|
|||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
static write_data_t* alloc_send_data(pj_ssl_sock_t *ssock, pj_size_t len)
|
||||
{
|
||||
send_buf_t *send_buf = &ssock->send_buf;
|
||||
pj_size_t avail_len, skipped_len = 0;
|
||||
char *reg1, *reg2;
|
||||
pj_size_t reg1_len, reg2_len;
|
||||
write_data_t *p;
|
||||
|
||||
/* Check buffer availability */
|
||||
avail_len = send_buf->max_len - send_buf->len;
|
||||
if (avail_len < len)
|
||||
return NULL;
|
||||
|
||||
/* If buffer empty, reset start pointer and return it */
|
||||
if (send_buf->len == 0) {
|
||||
send_buf->start = send_buf->buf;
|
||||
send_buf->len = len;
|
||||
p = (write_data_t*)send_buf->start;
|
||||
goto init_send_data;
|
||||
}
|
||||
|
||||
/* Free space may be wrapped/splitted into two regions, so let's
|
||||
* analyze them if any region can hold the write data.
|
||||
*/
|
||||
reg1 = send_buf->start + send_buf->len;
|
||||
if (reg1 >= send_buf->buf + send_buf->max_len)
|
||||
reg1 -= send_buf->max_len;
|
||||
reg1_len = send_buf->max_len - send_buf->len;
|
||||
if (reg1 + reg1_len > send_buf->buf + send_buf->max_len) {
|
||||
reg1_len = send_buf->buf + send_buf->max_len - reg1;
|
||||
reg2 = send_buf->buf;
|
||||
reg2_len = send_buf->start - send_buf->buf;
|
||||
} else {
|
||||
reg2 = NULL;
|
||||
reg2_len = 0;
|
||||
}
|
||||
|
||||
/* More buffer availability check, note that the write data must be in
|
||||
* a contigue buffer.
|
||||
*/
|
||||
avail_len = PJ_MAX(reg1_len, reg2_len);
|
||||
if (avail_len < len)
|
||||
return NULL;
|
||||
|
||||
/* Get the data slot */
|
||||
if (reg1_len >= len) {
|
||||
p = (write_data_t*)reg1;
|
||||
} else {
|
||||
p = (write_data_t*)reg2;
|
||||
skipped_len = reg1_len;
|
||||
}
|
||||
|
||||
/* Update buffer length */
|
||||
send_buf->len += len + skipped_len;
|
||||
|
||||
init_send_data:
|
||||
/* Init the new send data */
|
||||
pj_bzero(p, sizeof(*p));
|
||||
pj_list_init(p);
|
||||
pj_list_push_back(&ssock->send_pending, p);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void free_send_data(pj_ssl_sock_t *ssock, write_data_t *wdata)
|
||||
{
|
||||
send_buf_t *buf = &ssock->send_buf;
|
||||
write_data_t *spl = &ssock->send_pending;
|
||||
|
||||
pj_assert(!pj_list_empty(&ssock->send_pending));
|
||||
|
||||
/* Free slot from the buffer */
|
||||
if (spl->next == wdata && spl->prev == wdata) {
|
||||
/* This is the only data, reset the buffer */
|
||||
buf->start = buf->buf;
|
||||
buf->len = 0;
|
||||
} else if (spl->next == wdata) {
|
||||
/* This is the first data, shift start pointer of the buffer and
|
||||
* adjust the buffer length.
|
||||
*/
|
||||
buf->start = (char*)wdata->next;
|
||||
if (wdata->next > wdata) {
|
||||
buf->len -= ((char*)wdata->next - buf->start);
|
||||
} else {
|
||||
/* Overlapped */
|
||||
unsigned right_len, left_len;
|
||||
right_len = buf->buf + buf->max_len - (char*)wdata;
|
||||
left_len = (char*)wdata->next - buf->buf;
|
||||
buf->len -= (right_len + left_len);
|
||||
}
|
||||
} else if (spl->prev == wdata) {
|
||||
/* This is the last data, just adjust the buffer length */
|
||||
if (wdata->prev < wdata) {
|
||||
unsigned jump_len;
|
||||
jump_len = (char*)wdata -
|
||||
((char*)wdata->prev + wdata->prev->record_len);
|
||||
buf->len -= (wdata->record_len + jump_len);
|
||||
} else {
|
||||
/* Overlapped */
|
||||
unsigned right_len, left_len;
|
||||
right_len = buf->buf + buf->max_len -
|
||||
((char*)wdata->prev + wdata->prev->record_len);
|
||||
left_len = (char*)wdata + wdata->record_len - buf->buf;
|
||||
buf->len -= (right_len + left_len);
|
||||
}
|
||||
}
|
||||
/* For data in the middle buffer, just do nothing on the buffer. The slot
|
||||
* will be freed later when freeing the first/last data.
|
||||
*/
|
||||
|
||||
/* Remove the data from send pending list */
|
||||
pj_list_erase(wdata);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Just for testing send buffer alloc/free */
|
||||
#include <pj/rand.h>
|
||||
pj_status_t pj_ssl_sock_ossl_test_send_buf(pj_pool_t *pool)
|
||||
{
|
||||
enum { MAX_CHUNK_NUM = 20 };
|
||||
unsigned chunk_size, chunk_cnt, i;
|
||||
write_data_t *wdata[MAX_CHUNK_NUM] = {0};
|
||||
pj_time_val now;
|
||||
pj_ssl_sock_t *ssock = NULL;
|
||||
pj_ssl_sock_param param;
|
||||
pj_status_t status;
|
||||
|
||||
pj_gettimeofday(&now);
|
||||
pj_srand((unsigned)now.sec);
|
||||
|
||||
pj_ssl_sock_param_default(¶m);
|
||||
status = pj_ssl_sock_create(pool, ¶m, &ssock);
|
||||
if (status != PJ_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (ssock->send_buf.max_len == 0) {
|
||||
ssock->send_buf.buf = (char*)
|
||||
pj_pool_alloc(ssock->pool,
|
||||
ssock->param.send_buffer_size);
|
||||
ssock->send_buf.max_len = ssock->param.send_buffer_size;
|
||||
ssock->send_buf.start = ssock->send_buf.buf;
|
||||
ssock->send_buf.len = 0;
|
||||
}
|
||||
|
||||
chunk_size = ssock->param.send_buffer_size / MAX_CHUNK_NUM / 2;
|
||||
chunk_cnt = 0;
|
||||
for (i = 0; i < MAX_CHUNK_NUM; i++) {
|
||||
wdata[i] = alloc_send_data(ssock, pj_rand() % chunk_size + 321);
|
||||
if (wdata[i])
|
||||
chunk_cnt++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
while (chunk_cnt) {
|
||||
i = pj_rand() % MAX_CHUNK_NUM;
|
||||
if (wdata[i]) {
|
||||
free_send_data(ssock, wdata[i]);
|
||||
wdata[i] = NULL;
|
||||
chunk_cnt--;
|
||||
}
|
||||
}
|
||||
|
||||
if (ssock->send_buf.len != 0)
|
||||
status = PJ_EBUG;
|
||||
|
||||
pj_ssl_sock_close(ssock);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Flush write BIO to network socket. Note that any access to write BIO
|
||||
* MUST be serialized, so mutex protection must cover any call to OpenSSL
|
||||
* API (that possibly generate data for write BIO) along with the call to
|
||||
|
@ -1036,76 +1236,39 @@ static pj_status_t flush_write_bio(pj_ssl_sock_t *ssock,
|
|||
{
|
||||
char *data;
|
||||
pj_ssize_t len;
|
||||
|
||||
write_state_t *write_st = &ssock->write_state;
|
||||
write_data_t *wdata;
|
||||
pj_size_t avail_len, needed_len, skipped_len = 0;
|
||||
pj_size_t needed_len;
|
||||
pj_status_t status;
|
||||
|
||||
pj_lock_acquire(ssock->write_mutex);
|
||||
|
||||
/* Check if there is data in write BIO, flush it if any */
|
||||
if (!BIO_pending(ssock->ossl_wbio))
|
||||
if (!BIO_pending(ssock->ossl_wbio)) {
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Get data and its length */
|
||||
len = BIO_get_mem_data(ssock->ossl_wbio, &data);
|
||||
if (len == 0)
|
||||
if (len == 0) {
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Calculate buffer size needed, and align it to 8 */
|
||||
needed_len = len + sizeof(write_data_t);
|
||||
needed_len = ((needed_len + 7) >> 3) << 3;
|
||||
|
||||
/* Check buffer availability */
|
||||
avail_len = write_st->max_len - write_st->len;
|
||||
if (avail_len < needed_len)
|
||||
/* Allocate buffer for send data */
|
||||
wdata = alloc_send_data(ssock, needed_len);
|
||||
if (wdata == NULL) {
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
return PJ_ENOMEM;
|
||||
|
||||
/* More buffer availability check, note that the write data must be in
|
||||
* a contigue buffer.
|
||||
*/
|
||||
if (write_st->len == 0) {
|
||||
|
||||
write_st->start = write_st->buf;
|
||||
wdata = (write_data_t*)write_st->start;
|
||||
|
||||
} else {
|
||||
|
||||
char *reg1, *reg2;
|
||||
pj_size_t reg1_len, reg2_len;
|
||||
|
||||
/* Unused slots may be wrapped/splitted into two regions, so let's
|
||||
* analyze them if any region can hold the write data.
|
||||
*/
|
||||
reg1 = write_st->start + write_st->len;
|
||||
if (reg1 >= write_st->buf + write_st->max_len)
|
||||
reg1 -= write_st->max_len;
|
||||
reg1_len = write_st->max_len - write_st->len;
|
||||
if (reg1 + reg1_len > write_st->buf + write_st->max_len) {
|
||||
reg1_len = write_st->buf + write_st->max_len - reg1;
|
||||
reg2 = write_st->buf;
|
||||
reg2_len = write_st->start - write_st->buf;
|
||||
} else {
|
||||
reg2 = NULL;
|
||||
reg2_len = 0;
|
||||
}
|
||||
avail_len = PJ_MAX(reg1_len, reg2_len);
|
||||
if (avail_len < needed_len)
|
||||
return PJ_ENOMEM;
|
||||
|
||||
/* Get write data pointer and update buffer length */
|
||||
if (reg1_len >= needed_len) {
|
||||
wdata = (write_data_t*)reg1;
|
||||
} else {
|
||||
wdata = (write_data_t*)reg2;
|
||||
/* Unused slot in region 1 is skipped as current write data
|
||||
* doesn't fit it.
|
||||
*/
|
||||
skipped_len = reg1_len;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the data and set its properties into the buffer */
|
||||
pj_bzero(wdata, sizeof(write_data_t));
|
||||
/* Copy the data and set its properties into the send data */
|
||||
pj_ioqueue_op_key_init(&wdata->key, sizeof(pj_ioqueue_op_key_t));
|
||||
wdata->key.user_data = wdata;
|
||||
wdata->app_key = send_key;
|
||||
wdata->record_len = needed_len;
|
||||
wdata->data_len = len;
|
||||
|
@ -1113,6 +1276,12 @@ static pj_status_t flush_write_bio(pj_ssl_sock_t *ssock,
|
|||
wdata->flags = flags;
|
||||
pj_memcpy(&wdata->data, data, len);
|
||||
|
||||
/* Reset write BIO */
|
||||
BIO_reset(ssock->ossl_wbio);
|
||||
|
||||
/* Ticket #1573: Don't hold mutex while calling PJLIB socket send(). */
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
|
||||
/* Send it */
|
||||
if (ssock->param.sock_type == pj_SOCK_STREAM()) {
|
||||
status = pj_activesock_send(ssock->asock, &wdata->key,
|
||||
|
@ -1126,24 +1295,13 @@ static pj_status_t flush_write_bio(pj_ssl_sock_t *ssock,
|
|||
ssock->addr_len);
|
||||
}
|
||||
|
||||
/* Oh no, EWOULDBLOCK! */
|
||||
if (status == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) {
|
||||
/* Just return PJ_SUCCESS here, the pending data will be sent in next
|
||||
* call of this function since the data is still stored in write BIO.
|
||||
if (status != PJ_EPENDING) {
|
||||
/* When the sending is not pending, remove the wdata from send
|
||||
* pending list.
|
||||
*/
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Reset write BIO after flushed */
|
||||
BIO_reset(ssock->ossl_wbio);
|
||||
|
||||
if (status == PJ_EPENDING) {
|
||||
/* Update write state */
|
||||
pj_assert(skipped_len==0 || write_st->last_data);
|
||||
write_st->len += needed_len + skipped_len;
|
||||
if (write_st->last_data)
|
||||
write_st->last_data->record_len += skipped_len;
|
||||
write_st->last_data = wdata;
|
||||
pj_lock_acquire(ssock->write_mutex);
|
||||
free_send_data(ssock, wdata);
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
}
|
||||
|
||||
return status;
|
||||
|
@ -1182,31 +1340,28 @@ static pj_status_t do_handshake(pj_ssl_sock_t *ssock)
|
|||
pj_status_t status;
|
||||
int err;
|
||||
|
||||
pj_lock_acquire(ssock->write_mutex);
|
||||
|
||||
/* Perform SSL handshake */
|
||||
pj_lock_acquire(ssock->write_mutex);
|
||||
err = SSL_do_handshake(ssock->ossl_ssl);
|
||||
if (err < 0) {
|
||||
err = SSL_get_error(ssock->ossl_ssl, err);
|
||||
if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ)
|
||||
{
|
||||
/* Handshake fails */
|
||||
GET_SSL_STATUS(status);
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
|
||||
/* SSL_do_handshake() may put some pending data into SSL write BIO,
|
||||
* flush it if any.
|
||||
*/
|
||||
status = flush_write_bio(ssock, &ssock->handshake_op_key, 0, 0);
|
||||
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
if (err < 0) {
|
||||
err = SSL_get_error(ssock->ossl_ssl, err);
|
||||
if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ)
|
||||
{
|
||||
/* Handshake fails */
|
||||
status = STATUS_FROM_SSL_ERR(ssock, err);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if handshake has been completed */
|
||||
if (SSL_is_init_finished(ssock->ossl_ssl)) {
|
||||
|
@ -1239,7 +1394,7 @@ static pj_bool_t asock_on_data_read (pj_activesock_t *asock,
|
|||
/* Consume the whole data */
|
||||
nwritten = BIO_write(ssock->ossl_rbio, data, size);
|
||||
if (nwritten < size) {
|
||||
GET_SSL_STATUS(status);
|
||||
status = GET_SSL_STATUS(ssock);
|
||||
goto on_error;
|
||||
}
|
||||
}
|
||||
|
@ -1313,7 +1468,7 @@ 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 */
|
||||
GET_SSL_STATUS(status);
|
||||
status = STATUS_FROM_SSL_ERR(ssock, err);
|
||||
reset_ssl_sock_state(ssock);
|
||||
goto on_error;
|
||||
}
|
||||
|
@ -1325,9 +1480,15 @@ static pj_bool_t asock_on_data_read (pj_activesock_t *asock,
|
|||
/* Update certificates */
|
||||
update_certs_info(ssock);
|
||||
|
||||
pj_lock_acquire(ssock->write_mutex);
|
||||
// Ticket #1573: Don't hold mutex while calling
|
||||
// PJLIB socket send().
|
||||
//pj_lock_acquire(ssock->write_mutex);
|
||||
status = flush_delayed_send(ssock);
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
//pj_lock_release(ssock->write_mutex);
|
||||
|
||||
/* If flushing is ongoing, treat it as success */
|
||||
if (status == PJ_EBUSY)
|
||||
status = PJ_SUCCESS;
|
||||
|
||||
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
|
||||
PJ_PERROR(1,(ssock->pool->obj_name, status,
|
||||
|
@ -1387,11 +1548,14 @@ static pj_bool_t asock_on_data_sent (pj_activesock_t *asock,
|
|||
|
||||
} else if (send_key != &ssock->handshake_op_key) {
|
||||
/* Some data has been sent, notify application */
|
||||
write_data_t *wdata = (write_data_t*)send_key;
|
||||
write_data_t *wdata = (write_data_t*)send_key->user_data;
|
||||
if (ssock->param.cb.on_data_sent) {
|
||||
pj_bool_t ret;
|
||||
pj_ssize_t sent_len;
|
||||
|
||||
sent_len = (sent > 0)? wdata->plain_data_len : sent;
|
||||
ret = (*ssock->param.cb.on_data_sent)(ssock, wdata->app_key,
|
||||
wdata->plain_data_len);
|
||||
sent_len);
|
||||
if (!ret) {
|
||||
/* We've been destroyed */
|
||||
return PJ_FALSE;
|
||||
|
@ -1400,12 +1564,7 @@ static pj_bool_t asock_on_data_sent (pj_activesock_t *asock,
|
|||
|
||||
/* Update write buffer state */
|
||||
pj_lock_acquire(ssock->write_mutex);
|
||||
ssock->write_state.start += wdata->record_len;
|
||||
ssock->write_state.len -= wdata->record_len;
|
||||
if (ssock->write_state.last_data == wdata) {
|
||||
pj_assert(ssock->write_state.len == 0);
|
||||
ssock->write_state.last_data = NULL;
|
||||
}
|
||||
free_send_data(ssock, wdata);
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
|
||||
} else {
|
||||
|
@ -1516,13 +1675,13 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock,
|
|||
goto on_return;
|
||||
|
||||
/* Prepare write/send state */
|
||||
pj_assert(ssock->write_state.max_len == 0);
|
||||
ssock->write_state.buf = (char*)
|
||||
pj_pool_alloc(ssock->pool,
|
||||
ssock->param.send_buffer_size);
|
||||
ssock->write_state.max_len = ssock->param.send_buffer_size;
|
||||
ssock->write_state.start = ssock->write_state.buf;
|
||||
ssock->write_state.len = 0;
|
||||
pj_assert(ssock->send_buf.max_len == 0);
|
||||
ssock->send_buf.buf = (char*)
|
||||
pj_pool_alloc(ssock->pool,
|
||||
ssock->param.send_buffer_size);
|
||||
ssock->send_buf.max_len = ssock->param.send_buffer_size;
|
||||
ssock->send_buf.start = ssock->send_buf.buf;
|
||||
ssock->send_buf.len = 0;
|
||||
|
||||
/* Start handshake timer */
|
||||
if (ssock->param.timer_heap && (ssock->param.timeout.sec != 0 ||
|
||||
|
@ -1595,13 +1754,13 @@ static pj_bool_t asock_on_connect_complete (pj_activesock_t *asock,
|
|||
goto on_return;
|
||||
|
||||
/* Prepare write/send state */
|
||||
pj_assert(ssock->write_state.max_len == 0);
|
||||
ssock->write_state.buf = (char*)
|
||||
pj_assert(ssock->send_buf.max_len == 0);
|
||||
ssock->send_buf.buf = (char*)
|
||||
pj_pool_alloc(ssock->pool,
|
||||
ssock->param.send_buffer_size);
|
||||
ssock->write_state.max_len = ssock->param.send_buffer_size;
|
||||
ssock->write_state.start = ssock->write_state.buf;
|
||||
ssock->write_state.len = 0;
|
||||
ssock->send_buf.max_len = ssock->param.send_buffer_size;
|
||||
ssock->send_buf.start = ssock->send_buf.buf;
|
||||
ssock->send_buf.len = 0;
|
||||
|
||||
#ifdef SSL_set_tlsext_host_name
|
||||
/* Set server name to connect */
|
||||
|
@ -1701,18 +1860,57 @@ PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables(pj_ssl_cipher ciphers[],
|
|||
shutdown_openssl();
|
||||
}
|
||||
|
||||
if (openssl_cipher_num == 0)
|
||||
if (openssl_cipher_num == 0) {
|
||||
*cipher_num = 0;
|
||||
return PJ_ENOTFOUND;
|
||||
}
|
||||
|
||||
*cipher_num = PJ_MIN(*cipher_num, openssl_cipher_num);
|
||||
|
||||
for (i = 0; i < *cipher_num; ++i)
|
||||
ciphers[i] = openssl_ciphers[i];
|
||||
ciphers[i] = openssl_ciphers[i].id;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Get cipher name string */
|
||||
PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (openssl_cipher_num == 0) {
|
||||
init_openssl();
|
||||
shutdown_openssl();
|
||||
}
|
||||
|
||||
for (i = 0; i < openssl_cipher_num; ++i) {
|
||||
if (cipher == openssl_ciphers[i].id)
|
||||
return openssl_ciphers[i].name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check if the specified cipher is supported by SSL/TLS backend. */
|
||||
PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (openssl_cipher_num == 0) {
|
||||
init_openssl();
|
||||
shutdown_openssl();
|
||||
}
|
||||
|
||||
for (i = 0; i < openssl_cipher_num; ++i) {
|
||||
if (cipher == openssl_ciphers[i].id)
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
return PJ_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create SSL socket instance.
|
||||
*/
|
||||
|
@ -1735,7 +1933,10 @@ PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool,
|
|||
ssock->ssl_state = SSL_STATE_NULL;
|
||||
pj_list_init(&ssock->write_pending);
|
||||
pj_list_init(&ssock->write_pending_empty);
|
||||
pj_list_init(&ssock->send_pending);
|
||||
pj_timer_entry_init(&ssock->timer, 0, ssock, &on_timer);
|
||||
pj_ioqueue_op_key_init(&ssock->handshake_op_key,
|
||||
sizeof(pj_ioqueue_op_key_t));
|
||||
|
||||
/* Create secure socket mutex */
|
||||
status = pj_lock_create_recursive_mutex(pool, pool->obj_name,
|
||||
|
@ -1856,6 +2057,9 @@ PJ_DEF(pj_status_t) pj_ssl_sock_get_info (pj_ssl_sock_t *ssock,
|
|||
info->verify_status = ssock->verify_status;
|
||||
}
|
||||
|
||||
/* Last known OpenSSL error code */
|
||||
info->last_native_err = ssock->last_err;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1965,10 +2169,7 @@ PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom2 (pj_ssl_sock_t *ssock,
|
|||
return PJ_ENOTSUP;
|
||||
}
|
||||
|
||||
/* Write plain data to SSL and flush write BIO. Note that accessing
|
||||
* write BIO must be serialized, so a call to this function must be
|
||||
* protected by write mutex of SSL socket.
|
||||
*/
|
||||
/* Write plain data to SSL and flush write BIO. */
|
||||
static pj_status_t ssl_write(pj_ssl_sock_t *ssock,
|
||||
pj_ioqueue_op_key_t *send_key,
|
||||
const void *data,
|
||||
|
@ -1983,7 +2184,9 @@ static pj_status_t ssl_write(pj_ssl_sock_t *ssock,
|
|||
* negotitation may be on progress, so sending data should be delayed
|
||||
* until re-negotiation is completed.
|
||||
*/
|
||||
pj_lock_acquire(ssock->write_mutex);
|
||||
nwritten = SSL_write(ssock->ossl_ssl, data, size);
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
|
||||
if (nwritten == size) {
|
||||
/* All data written, flush write BIO to network socket */
|
||||
|
@ -2002,7 +2205,7 @@ static pj_status_t ssl_write(pj_ssl_sock_t *ssock,
|
|||
status = PJ_EBUSY;
|
||||
} else {
|
||||
/* Some problem occured */
|
||||
GET_SSL_STATUS(status);
|
||||
status = STATUS_FROM_SSL_ERR(ssock, err);
|
||||
}
|
||||
} else {
|
||||
/* nwritten < *size, shouldn't happen, unless write BIO cannot hold
|
||||
|
@ -2014,56 +2217,81 @@ static pj_status_t ssl_write(pj_ssl_sock_t *ssock,
|
|||
return status;
|
||||
}
|
||||
|
||||
/* Flush delayed data sending in the write pending list. Note that accessing
|
||||
* write pending list must be serialized, so a call to this function must be
|
||||
* protected by write mutex of SSL socket.
|
||||
*/
|
||||
/* Flush delayed data sending in the write pending list. */
|
||||
static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock)
|
||||
{
|
||||
/* Check for another ongoing flush */
|
||||
if (ssock->flushing_write_pend)
|
||||
return PJ_EBUSY;
|
||||
|
||||
pj_lock_acquire(ssock->write_mutex);
|
||||
|
||||
/* Again, check for another ongoing flush */
|
||||
if (ssock->flushing_write_pend) {
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
return PJ_EBUSY;
|
||||
}
|
||||
|
||||
/* Set ongoing flush flag */
|
||||
ssock->flushing_write_pend = PJ_TRUE;
|
||||
|
||||
while (!pj_list_empty(&ssock->write_pending)) {
|
||||
write_pending_t *wp;
|
||||
write_data_t *wp;
|
||||
pj_status_t status;
|
||||
|
||||
wp = ssock->write_pending.next;
|
||||
|
||||
status = ssl_write(ssock, &wp->data.key, wp->data.data.ptr,
|
||||
wp->data.plain_data_len, wp->data.flags);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
/* Ticket #1573: Don't hold mutex while calling socket send. */
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
|
||||
status = ssl_write(ssock, &wp->key, wp->data.ptr,
|
||||
wp->plain_data_len, wp->flags);
|
||||
if (status != PJ_SUCCESS) {
|
||||
/* Reset ongoing flush flag first. */
|
||||
ssock->flushing_write_pend = PJ_FALSE;
|
||||
return status;
|
||||
}
|
||||
|
||||
pj_lock_acquire(ssock->write_mutex);
|
||||
pj_list_erase(wp);
|
||||
pj_list_push_back(&ssock->write_pending_empty, wp);
|
||||
}
|
||||
|
||||
/* Reset ongoing flush flag */
|
||||
ssock->flushing_write_pend = PJ_FALSE;
|
||||
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Sending is delayed, push back the sending data into pending list. Note that
|
||||
* accessing write pending list must be serialized, so a call to this function
|
||||
* must be protected by write mutex of SSL socket.
|
||||
*/
|
||||
/* Sending is delayed, push back the sending data into pending list. */
|
||||
static pj_status_t delay_send (pj_ssl_sock_t *ssock,
|
||||
pj_ioqueue_op_key_t *send_key,
|
||||
const void *data,
|
||||
pj_ssize_t size,
|
||||
unsigned flags)
|
||||
{
|
||||
write_pending_t *wp;
|
||||
write_data_t *wp;
|
||||
|
||||
pj_lock_acquire(ssock->write_mutex);
|
||||
|
||||
/* Init write pending instance */
|
||||
if (!pj_list_empty(&ssock->write_pending_empty)) {
|
||||
wp = ssock->write_pending_empty.next;
|
||||
pj_list_erase(wp);
|
||||
} else {
|
||||
wp = PJ_POOL_ZALLOC_T(ssock->pool, write_pending_t);
|
||||
wp = PJ_POOL_ZALLOC_T(ssock->pool, write_data_t);
|
||||
}
|
||||
|
||||
wp->data.app_key = send_key;
|
||||
wp->data.plain_data_len = size;
|
||||
wp->data.data.ptr = data;
|
||||
wp->data.flags = flags;
|
||||
wp->app_key = send_key;
|
||||
wp->plain_data_len = size;
|
||||
wp->data.ptr = data;
|
||||
wp->flags = flags;
|
||||
|
||||
pj_list_push_back(&ssock->write_pending, wp);
|
||||
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
|
||||
/* Must return PJ_EPENDING */
|
||||
return PJ_EPENDING;
|
||||
|
@ -2083,14 +2311,15 @@ PJ_DEF(pj_status_t) pj_ssl_sock_send (pj_ssl_sock_t *ssock,
|
|||
PJ_ASSERT_RETURN(ssock && data && size && (*size>0), PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(ssock->ssl_state==SSL_STATE_ESTABLISHED, PJ_EINVALIDOP);
|
||||
|
||||
pj_lock_acquire(ssock->write_mutex);
|
||||
// Ticket #1573: Don't hold mutex while calling PJLIB socket send().
|
||||
//pj_lock_acquire(ssock->write_mutex);
|
||||
|
||||
/* Flush delayed send first. Sending data might be delayed when
|
||||
* re-negotiation is on-progress.
|
||||
*/
|
||||
status = flush_delayed_send(ssock);
|
||||
if (status == PJ_EBUSY) {
|
||||
/* Re-negotiation is on progress, delay sending */
|
||||
/* Re-negotiation or flushing is on progress, delay sending */
|
||||
status = delay_send(ssock, send_key, data, *size, flags);
|
||||
goto on_return;
|
||||
} else if (status != PJ_SUCCESS) {
|
||||
|
@ -2105,7 +2334,7 @@ PJ_DEF(pj_status_t) pj_ssl_sock_send (pj_ssl_sock_t *ssock,
|
|||
}
|
||||
|
||||
on_return:
|
||||
pj_lock_release(ssock->write_mutex);
|
||||
//pj_lock_release(ssock->write_mutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -2329,7 +2558,7 @@ PJ_DEF(pj_status_t) pj_ssl_sock_renegotiate(pj_ssl_sock_t *ssock)
|
|||
|
||||
ret = SSL_renegotiate(ssock->ossl_ssl);
|
||||
if (ret <= 0) {
|
||||
GET_SSL_STATUS(status);
|
||||
status = GET_SSL_STATUS(ssock);
|
||||
} else {
|
||||
status = do_handshake(ssock);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,104 @@
|
|||
|
||||
#define THIS_FILE "ssl_sock_symbian.cpp"
|
||||
|
||||
|
||||
/* Cipher name structure */
|
||||
typedef struct cipher_name_t {
|
||||
pj_ssl_cipher cipher;
|
||||
const char *name;
|
||||
} cipher_name_t;
|
||||
|
||||
/* Cipher name constants */
|
||||
static cipher_name_t cipher_names[] =
|
||||
{
|
||||
{PJ_TLS_NULL_WITH_NULL_NULL, "NULL"},
|
||||
|
||||
/* TLS/SSLv3 */
|
||||
{PJ_TLS_RSA_WITH_NULL_MD5, "TLS_RSA_WITH_NULL_MD5"},
|
||||
{PJ_TLS_RSA_WITH_NULL_SHA, "TLS_RSA_WITH_NULL_SHA"},
|
||||
{PJ_TLS_RSA_WITH_NULL_SHA256, "TLS_RSA_WITH_NULL_SHA256"},
|
||||
{PJ_TLS_RSA_WITH_RC4_128_MD5, "TLS_RSA_WITH_RC4_128_MD5"},
|
||||
{PJ_TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA"},
|
||||
{PJ_TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
|
||||
{PJ_TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"},
|
||||
{PJ_TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA"},
|
||||
{PJ_TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256"},
|
||||
{PJ_TLS_RSA_WITH_AES_256_CBC_SHA256, "TLS_RSA_WITH_AES_256_CBC_SHA256"},
|
||||
{PJ_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"},
|
||||
{PJ_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"},
|
||||
{PJ_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"},
|
||||
{PJ_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"},
|
||||
{PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"},
|
||||
{PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"},
|
||||
{PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"},
|
||||
{PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"},
|
||||
{PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"},
|
||||
{PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"},
|
||||
{PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"},
|
||||
{PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
|
||||
{PJ_TLS_DH_DSS_WITH_AES_128_CBC_SHA256, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"},
|
||||
{PJ_TLS_DH_RSA_WITH_AES_128_CBC_SHA256, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"},
|
||||
{PJ_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"},
|
||||
{PJ_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"},
|
||||
{PJ_TLS_DH_DSS_WITH_AES_256_CBC_SHA256, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"},
|
||||
{PJ_TLS_DH_RSA_WITH_AES_256_CBC_SHA256, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"},
|
||||
{PJ_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"},
|
||||
{PJ_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
|
||||
{PJ_TLS_DH_anon_WITH_RC4_128_MD5, "TLS_DH_anon_WITH_RC4_128_MD5"},
|
||||
{PJ_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"},
|
||||
{PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA, "TLS_DH_anon_WITH_AES_128_CBC_SHA"},
|
||||
{PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA, "TLS_DH_anon_WITH_AES_256_CBC_SHA"},
|
||||
{PJ_TLS_DH_anon_WITH_AES_128_CBC_SHA256, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"},
|
||||
{PJ_TLS_DH_anon_WITH_AES_256_CBC_SHA256, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"},
|
||||
|
||||
/* TLS (deprecated) */
|
||||
{PJ_TLS_RSA_EXPORT_WITH_RC4_40_MD5, "TLS_RSA_EXPORT_WITH_RC4_40_MD5"},
|
||||
{PJ_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"},
|
||||
{PJ_TLS_RSA_WITH_IDEA_CBC_SHA, "TLS_RSA_WITH_IDEA_CBC_SHA"},
|
||||
{PJ_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"},
|
||||
{PJ_TLS_RSA_WITH_DES_CBC_SHA, "TLS_RSA_WITH_DES_CBC_SHA"},
|
||||
{PJ_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"},
|
||||
{PJ_TLS_DH_DSS_WITH_DES_CBC_SHA, "TLS_DH_DSS_WITH_DES_CBC_SHA"},
|
||||
{PJ_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"},
|
||||
{PJ_TLS_DH_RSA_WITH_DES_CBC_SHA, "TLS_DH_RSA_WITH_DES_CBC_SHA"},
|
||||
{PJ_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"},
|
||||
{PJ_TLS_DHE_DSS_WITH_DES_CBC_SHA, "TLS_DHE_DSS_WITH_DES_CBC_SHA"},
|
||||
{PJ_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"},
|
||||
{PJ_TLS_DHE_RSA_WITH_DES_CBC_SHA, "TLS_DHE_RSA_WITH_DES_CBC_SHA"},
|
||||
{PJ_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"},
|
||||
{PJ_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"},
|
||||
{PJ_TLS_DH_anon_WITH_DES_CBC_SHA, "TLS_DH_anon_WITH_DES_CBC_SHA"},
|
||||
|
||||
/* SSLv3 */
|
||||
{PJ_SSL_FORTEZZA_KEA_WITH_NULL_SHA, "SSL_FORTEZZA_KEA_WITH_NULL_SHA"},
|
||||
{PJ_SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA,"SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"},
|
||||
{PJ_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA"},
|
||||
|
||||
/* SSLv2 */
|
||||
{PJ_SSL_CK_RC4_128_WITH_MD5, "SSL_CK_RC4_128_WITH_MD5"},
|
||||
{PJ_SSL_CK_RC4_128_EXPORT40_WITH_MD5, "SSL_CK_RC4_128_EXPORT40_WITH_MD5"},
|
||||
{PJ_SSL_CK_RC2_128_CBC_WITH_MD5, "SSL_CK_RC2_128_CBC_WITH_MD5"},
|
||||
{PJ_SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5, "SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5"},
|
||||
{PJ_SSL_CK_IDEA_128_CBC_WITH_MD5, "SSL_CK_IDEA_128_CBC_WITH_MD5"},
|
||||
{PJ_SSL_CK_DES_64_CBC_WITH_MD5, "SSL_CK_DES_64_CBC_WITH_MD5"},
|
||||
{PJ_SSL_CK_DES_192_EDE3_CBC_WITH_MD5, "SSL_CK_DES_192_EDE3_CBC_WITH_MD5"}
|
||||
};
|
||||
|
||||
|
||||
/* Get cipher name string */
|
||||
static const char* get_cipher_name(pj_ssl_cipher cipher)
|
||||
{
|
||||
unsigned i, n;
|
||||
|
||||
n = PJ_ARRAY_SIZE(cipher_names);
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (cipher == cipher_names[i].cipher)
|
||||
return cipher_names[i].name;
|
||||
}
|
||||
|
||||
return "CIPHER_UNKNOWN";
|
||||
}
|
||||
|
||||
typedef void (*CPjSSLSocket_cb)(int err, void *key);
|
||||
|
||||
class CPjSSLSocketReader : public CActive
|
||||
|
@ -115,7 +213,8 @@ public:
|
|||
|
||||
int Connect(CPjSSLSocket_cb cb, void *key, const TInetAddr &local_addr,
|
||||
const TInetAddr &rem_addr,
|
||||
const TDesC8 &servername = TPtrC8(NULL,0));
|
||||
const TDesC8 &servername = TPtrC8(NULL,0),
|
||||
const TDesC8 &ciphers = TPtrC8(NULL,0));
|
||||
int Send(CPjSSLSocket_cb cb, void *key, const TDesC8 &aDesc, TUint flags);
|
||||
int SendSync(const TDesC8 &aDesc, TUint flags);
|
||||
|
||||
|
@ -146,6 +245,7 @@ private:
|
|||
TBuf<32> ssl_proto_;
|
||||
TInetAddr rem_addr_;
|
||||
TPtrC8 servername_;
|
||||
TPtrC8 ciphers_;
|
||||
TInetAddr local_addr_;
|
||||
TSockXfrLength sent_len_;
|
||||
|
||||
|
@ -186,7 +286,8 @@ private:
|
|||
int CPjSSLSocket::Connect(CPjSSLSocket_cb cb, void *key,
|
||||
const TInetAddr &local_addr,
|
||||
const TInetAddr &rem_addr,
|
||||
const TDesC8 &servername)
|
||||
const TDesC8 &servername,
|
||||
const TDesC8 &ciphers)
|
||||
{
|
||||
pj_status_t status;
|
||||
|
||||
|
@ -213,7 +314,11 @@ int CPjSSLSocket::Connect(CPjSSLSocket_cb cb, void *key,
|
|||
cb_ = cb;
|
||||
key_ = key;
|
||||
rem_addr_ = rem_addr;
|
||||
|
||||
/* Note: the following members only keep the pointer, not the data */
|
||||
servername_.Set(servername);
|
||||
ciphers_.Set(ciphers);
|
||||
|
||||
rSock.Connect(rem_addr_, iStatus);
|
||||
SetActive();
|
||||
state_ = SSL_STATE_CONNECTING;
|
||||
|
@ -318,6 +423,8 @@ void CPjSSLSocket::RunL()
|
|||
if (servername_.Length() > 0)
|
||||
securesock_->SetOpt(KSoSSLDomainName, KSolInetSSL,
|
||||
servername_);
|
||||
if (ciphers_.Length() > 0)
|
||||
securesock_->SetAvailableCipherSuites(ciphers_);
|
||||
|
||||
// FlushSessionCache() seems to also fire signals to all
|
||||
// completed AOs (something like CActiveScheduler::RunIfReady())
|
||||
|
@ -441,9 +548,8 @@ struct pj_ssl_sock_t
|
|||
|
||||
pj_ssl_sock_proto proto;
|
||||
pj_time_val timeout;
|
||||
unsigned ciphers_num;
|
||||
pj_ssl_cipher *ciphers;
|
||||
pj_str_t servername;
|
||||
pj_str_t ciphers;
|
||||
pj_ssl_cert_info remote_cert_info;
|
||||
};
|
||||
|
||||
|
@ -579,15 +685,20 @@ static void update_certs_info(pj_ssl_sock_t *ssock)
|
|||
}
|
||||
|
||||
|
||||
/* Available ciphers */
|
||||
static unsigned ciphers_num_ = 0;
|
||||
static struct ciphers_t
|
||||
{
|
||||
pj_ssl_cipher id;
|
||||
const char *name;
|
||||
} ciphers_[64];
|
||||
|
||||
/*
|
||||
* Get cipher list supported by SSL/TLS backend.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables (pj_ssl_cipher ciphers[],
|
||||
unsigned *cipher_num)
|
||||
{
|
||||
/* Available ciphers */
|
||||
static pj_ssl_cipher ciphers_[64];
|
||||
static unsigned ciphers_num_ = 0;
|
||||
unsigned i;
|
||||
|
||||
PJ_ASSERT_RETURN(ciphers && cipher_num, PJ_EINVAL);
|
||||
|
@ -605,25 +716,69 @@ PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables (pj_ssl_cipher ciphers[],
|
|||
ciphers_num_ = ciphers_buf.Length() / 2;
|
||||
if (ciphers_num_ > PJ_ARRAY_SIZE(ciphers_))
|
||||
ciphers_num_ = PJ_ARRAY_SIZE(ciphers_);
|
||||
for (i = 0; i < ciphers_num_; ++i)
|
||||
ciphers_[i] = (pj_ssl_cipher)(ciphers_buf[i*2]*10 +
|
||||
ciphers_buf[i*2+1]);
|
||||
for (i = 0; i < ciphers_num_; ++i) {
|
||||
ciphers_[i].id = (pj_ssl_cipher)(ciphers_buf[i*2]*10 +
|
||||
ciphers_buf[i*2+1]);
|
||||
ciphers_[i].name = get_cipher_name(ciphers_[i].id);
|
||||
}
|
||||
}
|
||||
|
||||
delete secure_sock;
|
||||
}
|
||||
|
||||
if (ciphers_num_ == 0) {
|
||||
*cipher_num = 0;
|
||||
return PJ_ENOTFOUND;
|
||||
}
|
||||
|
||||
*cipher_num = PJ_MIN(*cipher_num, ciphers_num_);
|
||||
for (i = 0; i < *cipher_num; ++i)
|
||||
ciphers[i] = ciphers_[i];
|
||||
ciphers[i] = ciphers_[i].id;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Get cipher name string */
|
||||
PJ_DEF(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (ciphers_num_ == 0) {
|
||||
pj_ssl_cipher c[1];
|
||||
i = 0;
|
||||
pj_ssl_cipher_get_availables(c, &i);
|
||||
}
|
||||
|
||||
for (i = 0; i < ciphers_num_; ++i) {
|
||||
if (cipher == ciphers_[i].id)
|
||||
return ciphers_[i].name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Check if the specified cipher is supported by SSL/TLS backend. */
|
||||
PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (ciphers_num_ == 0) {
|
||||
pj_ssl_cipher c[1];
|
||||
i = 0;
|
||||
pj_ssl_cipher_get_availables(c, &i);
|
||||
}
|
||||
|
||||
for (i = 0; i < ciphers_num_; ++i) {
|
||||
if (cipher == ciphers_[i].id)
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
return PJ_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create SSL socket instance.
|
||||
*/
|
||||
|
@ -652,14 +807,15 @@ PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool,
|
|||
ssock->cb = param->cb;
|
||||
ssock->user_data = param->user_data;
|
||||
ssock->timeout = param->timeout;
|
||||
ssock->ciphers_num = param->ciphers_num;
|
||||
if (param->ciphers_num > 0) {
|
||||
unsigned i;
|
||||
ssock->ciphers = (pj_ssl_cipher*)
|
||||
pj_pool_calloc(pool, param->ciphers_num,
|
||||
sizeof(pj_ssl_cipher));
|
||||
for (i = 0; i < param->ciphers_num; ++i)
|
||||
ssock->ciphers[i] = param->ciphers[i];
|
||||
/* Cipher list in Symbian is represented as array of two-octets. */
|
||||
ssock->ciphers.slen = param->ciphers_num*2;
|
||||
ssock->ciphers.ptr = (char*)pj_pool_alloc(pool, ssock->ciphers.slen);
|
||||
pj_uint8_t *c = (pj_uint8_t*)ssock->ciphers.ptr;
|
||||
for (unsigned i = 0; i < param->ciphers_num; ++i) {
|
||||
*c++ = (pj_uint8_t)(param->ciphers[i] & 0xFF00) >> 8;
|
||||
*c++ = (pj_uint8_t)(param->ciphers[i] & 0xFF);
|
||||
}
|
||||
}
|
||||
pj_strdup_with_null(pool, &ssock->servername, ¶m->server_name);
|
||||
|
||||
|
@ -1246,9 +1402,13 @@ PJ_DEF(pj_status_t) pj_ssl_sock_start_connect (pj_ssl_sock_t *ssock,
|
|||
TPtrC8 servername_((TUint8*)ssock->servername.ptr,
|
||||
ssock->servername.slen);
|
||||
|
||||
/* Convert cipher list to Symbian descriptor */
|
||||
TPtrC8 ciphers_((TUint8*)ssock->ciphers.ptr,
|
||||
ssock->ciphers.slen);
|
||||
|
||||
/* Try to connect */
|
||||
status = sock->Connect(&connect_cb, ssock, localaddr_, remaddr_,
|
||||
servername_);
|
||||
servername_, ciphers_);
|
||||
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
|
||||
delete sock;
|
||||
return status;
|
||||
|
|
|
@ -497,15 +497,16 @@ PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht,
|
|||
|
||||
PJ_ASSERT_RETURN(ht, 0);
|
||||
|
||||
lock_timer_heap(ht);
|
||||
if (!ht->cur_size && next_delay) {
|
||||
next_delay->sec = next_delay->msec = PJ_MAXINT32;
|
||||
unlock_timer_heap(ht);
|
||||
return 0;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
pj_gettickcount(&now);
|
||||
|
||||
lock_timer_heap(ht);
|
||||
while ( ht->cur_size &&
|
||||
PJ_TIME_VAL_LTE(ht->heap[0]->_timer_value, now) &&
|
||||
count < ht->max_entries_per_poll )
|
||||
|
|
|
@ -213,6 +213,7 @@ static int udp_ping_pong_test(void)
|
|||
for (i=0; i<10 && last_rx1 == srv1->rx_cnt && last_rx2 == srv2->rx_cnt; ++i) {
|
||||
pj_time_val delay = {0, 10};
|
||||
#ifdef PJ_SYMBIAN
|
||||
PJ_UNUSED_ARG(delay);
|
||||
pj_symbianos_poll(-1, 100);
|
||||
#else
|
||||
pj_ioqueue_poll(ioqueue, &delay);
|
||||
|
|
|
@ -363,7 +363,7 @@ static int compliance_test_0(pj_bool_t allow_concur)
|
|||
|
||||
#ifdef PJ_SYMBIAN
|
||||
callback_call_count = 0;
|
||||
pj_symbianos_poll(-1, 1000);
|
||||
pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
|
||||
status = callback_call_count;
|
||||
#else
|
||||
status = pj_ioqueue_poll(ioque, &timeout);
|
||||
|
@ -412,7 +412,7 @@ static int compliance_test_0(pj_bool_t allow_concur)
|
|||
if (pending_op == 0) {
|
||||
pj_time_val timeout = {1, 0};
|
||||
#ifdef PJ_SYMBIAN
|
||||
status = pj_symbianos_poll(-1, 1000);
|
||||
status = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
|
||||
#else
|
||||
status = pj_ioqueue_poll(ioque, &timeout);
|
||||
#endif
|
||||
|
@ -542,7 +542,7 @@ static int compliance_test_1(pj_bool_t allow_concur)
|
|||
|
||||
#ifdef PJ_SYMBIAN
|
||||
callback_call_count = 0;
|
||||
pj_symbianos_poll(-1, 1000);
|
||||
pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
|
||||
status = callback_call_count;
|
||||
#else
|
||||
status = pj_ioqueue_poll(ioque, &timeout);
|
||||
|
@ -576,7 +576,7 @@ static int compliance_test_1(pj_bool_t allow_concur)
|
|||
if (pending_op == 0) {
|
||||
pj_time_val timeout = {1, 0};
|
||||
#ifdef PJ_SYMBIAN
|
||||
status = pj_symbianos_poll(-1, 1000);
|
||||
status = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
|
||||
#else
|
||||
status = pj_ioqueue_poll(ioque, &timeout);
|
||||
#endif
|
||||
|
@ -771,7 +771,7 @@ static int compliance_test_2(pj_bool_t allow_concur)
|
|||
pj_time_val timeout = {1, 0};
|
||||
|
||||
#ifdef PJ_SYMBIAN
|
||||
status = pj_symbianos_poll(-1, 1000);
|
||||
status = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
|
||||
#else
|
||||
status = pj_ioqueue_poll(ioque, &timeout);
|
||||
#endif
|
||||
|
@ -797,7 +797,7 @@ static int compliance_test_2(pj_bool_t allow_concur)
|
|||
if (pending_op == 0) {
|
||||
pj_time_val timeout = {1, 0};
|
||||
#ifdef PJ_SYMBIAN
|
||||
status = pj_symbianos_poll(-1, 1000);
|
||||
status = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
|
||||
#else
|
||||
status = pj_ioqueue_poll(ioque, &timeout);
|
||||
#endif
|
||||
|
|
|
@ -267,7 +267,7 @@ static int compliance_test(pj_bool_t allow_concur)
|
|||
|
||||
TRACE_("poll...");
|
||||
#ifdef PJ_SYMBIAN
|
||||
rc = pj_symbianos_poll(-1, 5000);
|
||||
rc = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
|
||||
#else
|
||||
rc = pj_ioqueue_poll(ioque, &timeout);
|
||||
#endif
|
||||
|
@ -783,7 +783,7 @@ static int bench_test(pj_bool_t allow_concur, int bufsize,
|
|||
do {
|
||||
pj_time_val timeout = { 1, 0 };
|
||||
#ifdef PJ_SYMBIAN
|
||||
rc = pj_symbianos_poll(-1, 1000);
|
||||
rc = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout));
|
||||
#else
|
||||
rc = pj_ioqueue_poll(ioque, &timeout);
|
||||
#endif
|
||||
|
@ -812,6 +812,7 @@ static int bench_test(pj_bool_t allow_concur, int bufsize,
|
|||
do {
|
||||
pj_time_val timeout = { 0, 10 };
|
||||
#ifdef PJ_SYMBIAN
|
||||
PJ_UNUSED_ARG(timeout);
|
||||
rc = pj_symbianos_poll(-1, 100);
|
||||
#else
|
||||
rc = pj_ioqueue_poll(ioque, &timeout);
|
||||
|
|
|
@ -22,11 +22,81 @@
|
|||
#include <pj/os.h>
|
||||
|
||||
#if INCLUDE_OS_TEST
|
||||
static int endianness_test32(void)
|
||||
{
|
||||
union t
|
||||
{
|
||||
pj_uint32_t u32;
|
||||
pj_uint16_t u16[2];
|
||||
pj_uint8_t u8[4];
|
||||
} t;
|
||||
|
||||
PJ_LOG(3,("", " Testing endianness.."));
|
||||
|
||||
t.u32 = 0x11223344;
|
||||
|
||||
#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN
|
||||
PJ_LOG(3,("", " Library is set to little endian"));
|
||||
|
||||
# if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN
|
||||
# error Error: Both PJ_IS_LITTLE_ENDIAN and PJ_IS_BIG_ENDIAN are set!
|
||||
# endif
|
||||
|
||||
if ((t.u16[0] & 0xFFFF) != 0x3344 ||
|
||||
(t.u16[1] & 0xFFFF) != 0x1122)
|
||||
{
|
||||
PJ_LOG(3,("", " Error: wrong 16bit values 0x%x and 0x%x",
|
||||
(t.u16[0] & 0xFFFF), (t.u16[1] & 0xFFFF)));
|
||||
return 10;
|
||||
}
|
||||
|
||||
if ((t.u8[0] & 0xFF) != 0x44 ||
|
||||
(t.u8[1] & 0xFF) != 0x33 ||
|
||||
(t.u8[2] & 0xFF) != 0x22 ||
|
||||
(t.u8[3] & 0xFF) != 0x11)
|
||||
{
|
||||
PJ_LOG(3,("", " Error: wrong 8bit values"));
|
||||
return 12;
|
||||
}
|
||||
|
||||
#elif defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN
|
||||
PJ_LOG(3,("", " Library is set to big endian"));
|
||||
|
||||
if ((t.u16[0] & 0xFFFF) != 0x1122 ||
|
||||
(t.u16[1] & 0xFFFF) != 0x3344)
|
||||
{
|
||||
PJ_LOG(3,("", " Error: wrong 16bit values 0x%x and 0x%x",
|
||||
(t.u16[0] & 0xFFFF), (t.u16[1] & 0xFFFF)));
|
||||
return 20;
|
||||
}
|
||||
|
||||
if ((t.u8[0] & 0xFF) != 0x11 ||
|
||||
(t.u8[1] & 0xFF) != 0x22 ||
|
||||
(t.u8[2] & 0xFF) != 0x33 ||
|
||||
(t.u8[3] & 0xFF) != 0x44)
|
||||
{
|
||||
PJ_LOG(3,("", " Error: wrong 8bit values"));
|
||||
return 22;
|
||||
}
|
||||
|
||||
# if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN
|
||||
# error Error: Both PJ_IS_LITTLE_ENDIAN and PJ_IS_BIG_ENDIAN are set!
|
||||
# endif
|
||||
|
||||
|
||||
#else
|
||||
# error Error: Endianness is not set properly!
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int os_test(void)
|
||||
{
|
||||
const pj_sys_info *si;
|
||||
int rc = 0;
|
||||
|
||||
PJ_LOG(3,("", " Sys info:"));
|
||||
si = pj_get_sys_info();
|
||||
PJ_LOG(3,("", " machine: %s", si->machine.ptr));
|
||||
PJ_LOG(3,("", " os_name: %s", si->os_name.ptr));
|
||||
|
@ -35,6 +105,8 @@ int os_test(void)
|
|||
PJ_LOG(3,("", " sdk_ver: 0x%x", si->sdk_ver));
|
||||
PJ_LOG(3,("", " info: %s", si->info.ptr));
|
||||
|
||||
rc = endianness_test32();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -510,7 +510,7 @@ static int send_recv_test(int sock_type,
|
|||
}
|
||||
if (srclen != addrlen)
|
||||
return -151;
|
||||
if (pj_memcmp(&addr, srcaddr, srclen) != 0) {
|
||||
if (pj_sockaddr_cmp(&addr, srcaddr) != 0) {
|
||||
char srcaddr_str[32], addr_str[32];
|
||||
strcpy(srcaddr_str, pj_inet_ntoa(srcaddr->sin_addr));
|
||||
strcpy(addr_str, pj_inet_ntoa(addr.sin_addr));
|
||||
|
|
|
@ -1329,11 +1329,34 @@ on_return:
|
|||
return status;
|
||||
}
|
||||
|
||||
#if 0 && (!defined(PJ_SYMBIAN) || PJ_SYMBIAN==0)
|
||||
pj_status_t pj_ssl_sock_ossl_test_send_buf(pj_pool_t *pool);
|
||||
static int ossl_test_send_buf()
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
pj_status_t status;
|
||||
|
||||
pool = pj_pool_create(mem, "send_buf", 256, 256, NULL);
|
||||
status = pj_ssl_sock_ossl_test_send_buf(pool);
|
||||
pj_pool_release(pool);
|
||||
return status;
|
||||
}
|
||||
#else
|
||||
static int ossl_test_send_buf()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ssl_sock_test(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
PJ_LOG(3,("", "..test ossl send buf"));
|
||||
ret = ossl_test_send_buf();
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
PJ_LOG(3,("", "..get cipher list test"));
|
||||
ret = get_cipher_list();
|
||||
if (ret != 0)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
static pj_ioqueue_key_t *key;
|
||||
static pj_atomic_t *total_bytes;
|
||||
static pj_bool_t thread_quit_flag;
|
||||
|
||||
struct op_key
|
||||
{
|
||||
|
@ -145,12 +146,12 @@ static int worker_thread(void *arg)
|
|||
on_read_complete(key, &read_op.op_key_, length);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
while (!thread_quit_flag) {
|
||||
pj_time_val timeout;
|
||||
timeout.sec = 0; timeout.msec = 10;
|
||||
rc = pj_ioqueue_poll(ioqueue, &timeout);
|
||||
}
|
||||
PJ_UNREACHED(return 0;)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udp_echo_srv_ioqueue(void)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <pjlib.h>
|
||||
|
||||
static pj_atomic_t *total_bytes;
|
||||
static pj_bool_t thread_quit_flag = 0;
|
||||
|
||||
static int worker_thread(void *arg)
|
||||
{
|
||||
|
@ -28,7 +29,7 @@ static int worker_thread(void *arg)
|
|||
char buf[512];
|
||||
pj_status_t last_recv_err = PJ_SUCCESS, last_write_err = PJ_SUCCESS;
|
||||
|
||||
for (;;) {
|
||||
while (!thread_quit_flag) {
|
||||
pj_ssize_t len;
|
||||
pj_status_t rc;
|
||||
pj_sockaddr_in addr;
|
||||
|
@ -56,7 +57,7 @@ static int worker_thread(void *arg)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
PJ_UNREACHED(return 0;)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
#
|
||||
# 3. Success conditions, started with '!', followed by condition name
|
||||
# and its maximum tolerable value, in frames unit. Recognized condition
|
||||
# names are: burst, discard, lost, empty, delay. These conditions will
|
||||
# be verified with jitter buffer statistics after all session test data
|
||||
# are executed.
|
||||
# names are: burst, discard, lost, empty, delay, delay_min. These
|
||||
# conditions will be verified with jitter buffer statistics after all
|
||||
# session test data are executed.
|
||||
# Example:
|
||||
# !delay 10 <- maximum average delay of jbuf is 10 frames
|
||||
# !delay 10 <- average delay of jbuf is 10 frames
|
||||
#
|
||||
# 4. Session test data, containing sequence of jitter buffer events,
|
||||
# an event is represented by a character as follow:
|
||||
|
@ -295,7 +295,7 @@ PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG
|
|||
!discard 50 <- frames discarded for delay adaptation
|
||||
!lost 50 <- ticket #1188, normal frame after discarded frame is flagged 'lost' to align signal
|
||||
!empty 0
|
||||
!delay 25 <- average delay, JB is able to adapt the delay
|
||||
!delay_min 2 <- minimum delay, JB is able to adapt the delay
|
||||
PPPPPPPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPPPP PPPPPPPPPP
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
|
@ -311,13 +311,30 @@ PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
|||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
.
|
||||
|
||||
= Fixed mode prefetch 5, with two empty events
|
||||
%fixed 5
|
||||
!burst 1
|
||||
!discard 0
|
||||
!lost 0
|
||||
!discard 4 <- the burst level is about 1, but prefetching will cause delay by 5 frames prefetching, delay adjustment may take place later on
|
||||
!lost 4 <- progressive discard drops frames as if they were lost
|
||||
!empty 10
|
||||
!delay 5
|
||||
G
|
||||
|
@ -329,8 +346,8 @@ PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
|||
= Fixed mode prefetch 5, with random burst
|
||||
%fixed 5
|
||||
!burst 3
|
||||
!discard 0
|
||||
!lost 0
|
||||
!discard 4 <- (see above test scenario)
|
||||
!lost 4 <- (see above test scenario)
|
||||
!empty 5
|
||||
!delay 5
|
||||
PGPGPPGGPPPPGGPGGGPG PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPPPGGPGGGPG
|
||||
|
@ -349,7 +366,7 @@ PGGGGPPPGPPGPPPGGPGG PGPGPPGGPPGGPPPGGGPG PGGGGPPPGPPGPPPGGPGG
|
|||
!discard 50 <- frames discarded for delay adaptation
|
||||
!lost 50 <- ticket #1188, normal frame after discarded frame is flagged 'lost' to align signal
|
||||
!empty 0
|
||||
!delay 20 <- average delay, twice of minimal prefetch
|
||||
!delay_min 20 <- minimum delay, twice of minimal prefetch
|
||||
PPPPPPPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPPPP PPPPPPPPPP
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
||||
|
@ -369,7 +386,7 @@ PGPGPGPGPGPGPGPGPGPG PGPGPGPGPGPGPGPGPGPG PGPGPGPGPG
|
|||
|
||||
= Large PUT burst at beginning, then normal with burst level 10 and periodic burst spikes
|
||||
%adaptive 0 0 40
|
||||
!burst 10
|
||||
!burst 12
|
||||
!discard 300 <- not so relevant for long period session with many delay adjustments needed (i.e: for first burst and periodic spikes)
|
||||
!lost 300 <- ticket #1188, normal frame after discarded frame is flagged 'lost' to align signal
|
||||
!empty 60 <- delay adjustment effect, as there is actually no drift
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
include ../../build.mak
|
||||
include ../../version.mak
|
||||
|
||||
THIRD_PARTY:=$(PJDIR)/third_party
|
||||
|
||||
|
@ -122,11 +123,14 @@ TARGETS := pjmedia pjmedia-audiodev pjmedia-codec pjsdp pjmedia-test
|
|||
all: $(TARGETS)
|
||||
|
||||
doc:
|
||||
cd .. && rm -rf docs/html docs/latex && doxygen docs/doxygen.cfg
|
||||
@if [ -n "$(WWWDIR)" ]; then \
|
||||
echo "Copying to $(WWWDIR)/pjmedia/docs/html.." ; \
|
||||
rm -rf $(WWWDIR)/pjmedia/docs/html/* ; \
|
||||
cp -a ../docs/html/* $(WWWDIR)/pjmedia/docs/html/ ; \
|
||||
cd .. && rm -rf docs/$(PJ_VERSION) && doxygen docs/doxygen.cfg
|
||||
@if [ -n "$(WWWDIR)" ] && ! [ -d "$(WWWDIR)/docs/$(PJ_VERSION)/pjmedia/docs/html" ] ; then \
|
||||
echo "Creating docs/$(PJ_VERSION)/pjmedia/docs/html" ; \
|
||||
mkdir -p $(WWWDIR)/docs/$(PJ_VERSION)/pjmedia/docs/html ; \
|
||||
fi
|
||||
@if [ -n "$(WWWDIR)" ] && [ -d "$(WWWDIR)/docs/$(PJ_VERSION)/pjmedia/docs/html" ] ; then \
|
||||
echo "Copying docs/$(PJ_VERSION) to $(WWWDIR)/docs/$(PJ_VERSION)/pjmedia/docs/html.." ; \
|
||||
cp -v -a ../docs/$(PJ_VERSION)/html/* $(WWWDIR)/docs/$(PJ_VERSION)/pjmedia/docs/html/ ; \
|
||||
fi
|
||||
|
||||
dep: depend
|
||||
|
@ -146,7 +150,9 @@ pjmedia-audiodev:
|
|||
pjsdp:
|
||||
$(MAKE) -f $(RULES_MAK) APP=PJSDP app=pjsdp $(PJSDP_LIB)
|
||||
|
||||
pjmedia-test: $(PJMEDIA_LIB)
|
||||
$(PJMEDIA_LIB): pjmedia
|
||||
|
||||
pjmedia-test: $(PJMEDIA_LIB) pjmedia
|
||||
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_TEST app=pjmedia-test $(PJMEDIA_TEST_EXE)
|
||||
|
||||
.PHONY: ../lib/pjmedia.ko
|
||||
|
|
|
@ -29,6 +29,7 @@ AC_NO_SPEEX_CODEC=@ac_no_speex_codec@
|
|||
AC_NO_ILBC_CODEC=@ac_no_ilbc_codec@
|
||||
AC_NO_G722_CODEC=@ac_no_g722_codec@
|
||||
AC_NO_G7221_CODEC=@ac_no_g7221_codec@
|
||||
AC_NO_OPENCORE_AMRNB=@ac_no_opencore_amrnb@
|
||||
|
||||
export CODEC_OBJS=
|
||||
|
||||
|
@ -81,6 +82,12 @@ export CODEC_OBJS += g7221.o
|
|||
export G7221_CFLAGS += -I$(THIRD_PARTY)
|
||||
endif
|
||||
|
||||
ifeq ($(AC_NO_OPENCORE_AMRNB),1)
|
||||
export CFLAGS += -DPJMEDIA_HAS_OPENCORE_AMRNB_CODEC=0
|
||||
else
|
||||
export CODEC_OBJS += opencore_amrnb.o
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# PortAudio
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,14 +23,14 @@ PROJECT_NAME = "PJMEDIA Reference"
|
|||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
PROJECT_NUMBER =
|
||||
PROJECT_NUMBER = $(PJ_VERSION)
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# base path where the generated documentation will be put.
|
||||
# If a relative path is entered, it will be relative to the location
|
||||
# where doxygen was started. If left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = docs
|
||||
OUTPUT_DIRECTORY = docs/$(PJ_VERSION)
|
||||
|
||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
|
||||
<title>$title</title>
|
||||
<title>$title ($projectnumber)</title>
|
||||
<link href="/style/style.css" rel="stylesheet" type="text/css">
|
||||
</head><body>
|
||||
<!--#include virtual="/header.html" -->
|
||||
|
|
|
@ -144,6 +144,21 @@ PJ_BEGIN_DECL
|
|||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* This setting controls whether the Symbian audio with built-in multimedia
|
||||
* framework backend should be started synchronously. Note that synchronous
|
||||
* start will block the application/UI, e.g: about 40ms for each direction
|
||||
* on N95. While asynchronous start may cause invalid value (always zero)
|
||||
* returned in input/output volume query, if the query is performed when
|
||||
* the internal start procedure is not completely finished.
|
||||
*
|
||||
* Default: 1 (yes)
|
||||
*/
|
||||
#ifndef PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START
|
||||
# define PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START 1
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* This setting controls whether the Audio Device API should support
|
||||
* device implementation that is based on the old sound device API
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <pjmedia-codec/g7221.h>
|
||||
#include <pjmedia-codec/ipp_codecs.h>
|
||||
#include <pjmedia-codec/passthrough.h>
|
||||
#include <pjmedia-codec/opencore_amrnb.h>
|
||||
|
||||
|
||||
#endif /* __PJMEDIA_CODEC_PJMEDIA_CODEC_H__ */
|
||||
|
|
|
@ -567,7 +567,7 @@ const pj_int16_t* const pjmedia_codec_amrwb_ordermaps[9] =
|
|||
* Constant of AMR-NB frame lengths in bytes.
|
||||
*/
|
||||
const pj_uint8_t pjmedia_codec_amrnb_framelen[16] =
|
||||
{12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 5};
|
||||
{12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0};
|
||||
/**
|
||||
* Constant of AMR-NB frame lengths in bits.
|
||||
*/
|
||||
|
@ -583,7 +583,7 @@ const pj_uint16_t pjmedia_codec_amrnb_bitrates[8] =
|
|||
* Constant of AMR-WB frame lengths in bytes.
|
||||
*/
|
||||
const pj_uint8_t pjmedia_codec_amrwb_framelen[16] =
|
||||
{17, 23, 32, 37, 40, 46, 50, 58, 60, 5, 0, 0, 0, 0, 0, 5};
|
||||
{17, 23, 32, 37, 40, 46, 50, 58, 60, 5, 0, 0, 0, 0, 0, 0};
|
||||
/**
|
||||
* Constant of AMR-WB frame lengths in bits.
|
||||
*/
|
||||
|
@ -606,6 +606,7 @@ typedef struct pjmedia_codec_amr_bit_info {
|
|||
pj_int8_t mode; /**< AMR mode. */
|
||||
pj_uint8_t start_bit; /**< Frame start bit. */
|
||||
pj_uint8_t good_quality:1; /**< Flag if frame is good/degraded. */
|
||||
pj_uint8_t STI:1; /**< STI mode (first/update). */
|
||||
} pjmedia_codec_amr_bit_info;
|
||||
#pragma pack()
|
||||
|
||||
|
@ -1020,9 +1021,7 @@ PJ_INLINE (pj_status_t) pjmedia_codec_amr_pack(
|
|||
} else if (info->frame_type == SID_FT) {
|
||||
|
||||
/* SID */
|
||||
pj_uint8_t STI = 0;
|
||||
|
||||
amr_bits[35] = (pj_uint8_t)(STI & 1);
|
||||
amr_bits[35] |= info->STI;
|
||||
|
||||
if (setting->amr_nb) {
|
||||
amr_bits[36] = (pj_uint8_t)((info->mode >> 2) & 1);
|
||||
|
@ -1163,6 +1162,7 @@ PJ_INLINE(pj_status_t) pjmedia_codec_amr_parse(
|
|||
info->mode = (pj_int8_t)((FT < SID_FT)? FT : -1);
|
||||
info->good_quality = (pj_uint8_t)(Q == 1);
|
||||
info->start_bit = 0;
|
||||
info->STI = 0;
|
||||
frames[cnt].timestamp = ts_;
|
||||
frames[cnt].type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
|
||||
|
@ -1186,6 +1186,13 @@ PJ_INLINE(pj_status_t) pjmedia_codec_amr_parse(
|
|||
frames[cnt].buf = r;
|
||||
info->start_bit = r_bitptr;
|
||||
|
||||
if (FT == SID_FT) {
|
||||
unsigned sti_bitptr;
|
||||
sti_bitptr = r_bitptr + 35;
|
||||
info->STI = (pj_uint8_t)
|
||||
(r[sti_bitptr >> 3] >> (7 - (sti_bitptr % 8))) & 1;
|
||||
}
|
||||
|
||||
if (setting->octet_aligned) {
|
||||
r += framelen_tbl[FT];
|
||||
frames[cnt].size = framelen_tbl[FT];
|
||||
|
|
|
@ -312,6 +312,39 @@
|
|||
# define PJMEDIA_HAS_G7221_CODEC 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Enable OpenCORE AMR-NB codec.
|
||||
* See https://trac.pjsip.org/repos/ticket/1388 for some info.
|
||||
*
|
||||
* Default: 0
|
||||
*/
|
||||
#ifndef PJMEDIA_HAS_OPENCORE_AMRNB_CODEC
|
||||
# define PJMEDIA_HAS_OPENCORE_AMRNB_CODEC 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Link with libopencore-amrXX via pragma comment on Visual Studio.
|
||||
* This option only makes sense if PJMEDIA_HAS_OPENCORE_AMRNB_CODEC
|
||||
* is enabled.
|
||||
*
|
||||
* Default: 1
|
||||
*/
|
||||
#ifndef PJMEDIA_AUTO_LINK_OPENCORE_AMR_LIBS
|
||||
# define PJMEDIA_AUTO_LINK_OPENCORE_AMR_LIBS 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Link with libopencore-amrXX.a that has been produced with gcc.
|
||||
* This option only makes sense if PJMEDIA_HAS_OPENCORE_AMRNB_CODEC
|
||||
* and PJMEDIA_AUTO_LINK_OPENCORE_AMR_LIBS are enabled.
|
||||
*
|
||||
* Default: 1
|
||||
*/
|
||||
#ifndef PJMEDIA_OPENCORE_AMR_BUILT_WITH_GCC
|
||||
# define PJMEDIA_OPENCORE_AMR_BUILT_WITH_GCC 1
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Default G.722.1 codec encoder and decoder level adjustment.
|
||||
* If the value is non-zero, then PCM input samples to the encoder will
|
||||
|
|
|
@ -69,6 +69,11 @@
|
|||
#undef PJMEDIA_HAS_G7221_CODEC
|
||||
#endif
|
||||
|
||||
/* OpenCORE AMR-NB codec */
|
||||
#ifndef PJMEDIA_HAS_OPENCORE_AMRNB_CODEC
|
||||
#undef PJMEDIA_HAS_OPENCORE_AMRNB_CODEC
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __PJMEDIA_CODEC_CONFIG_AUTO_H_ */
|
||||
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
|
||||
* Copyright (C) 2011 Dan Arrhenius <dan@keystream.se>
|
||||
*
|
||||
* 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_OPENCORE_AMRNB_H__
|
||||
#define __PJMEDIA_CODEC_OPENCORE_AMRNB_H__
|
||||
|
||||
#include <pjmedia-codec/types.h>
|
||||
|
||||
/**
|
||||
* @defgroup PJMED_OC_AMRNB OpenCORE AMR-NB Codec
|
||||
* @ingroup PJMEDIA_CODEC_CODECS
|
||||
* @brief AMRCodec wrapper for OpenCORE AMR-NB codec
|
||||
* @{
|
||||
*/
|
||||
|
||||
PJ_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Settings. Use #pjmedia_codec_opencore_amrnb_set_config() to
|
||||
* activate.
|
||||
*/
|
||||
typedef struct pjmedia_codec_amrnb_config
|
||||
{
|
||||
/**
|
||||
* Control whether to use octent align.
|
||||
*/
|
||||
pj_bool_t octet_align;
|
||||
|
||||
/**
|
||||
* Set the bitrate.
|
||||
*/
|
||||
unsigned bitrate;
|
||||
|
||||
} pjmedia_codec_amrnb_config;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize and register AMR-NB codec factory to pjmedia endpoint.
|
||||
*
|
||||
* @param endpt The pjmedia endpoint.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_codec_opencore_amrnb_init(pjmedia_endpt* endpt);
|
||||
|
||||
/**
|
||||
* Unregister AMR-NB codec factory from pjmedia endpoint and deinitialize
|
||||
* the OpenCORE codec library.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_codec_opencore_amrnb_deinit(void);
|
||||
|
||||
|
||||
/**
|
||||
* Set AMR-NB parameters.
|
||||
*
|
||||
* @param cfg The settings;
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_codec_opencore_amrnb_set_config(
|
||||
const pjmedia_codec_amrnb_config* cfg);
|
||||
|
||||
PJ_END_DECL
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* __PJMEDIA_CODEC_OPENCORE_AMRNB_H__ */
|
||||
|
|
@ -309,6 +309,18 @@ typedef struct pjmedia_codec_param
|
|||
} pjmedia_codec_param;
|
||||
|
||||
|
||||
/**
|
||||
* Duplicate codec parameter.
|
||||
*
|
||||
* @param pool The pool.
|
||||
* @param src The codec parameter to be duplicated.
|
||||
*
|
||||
* @return Duplicated codec parameter.
|
||||
*/
|
||||
PJ_DECL(pjmedia_codec_param*) pjmedia_codec_param_clone(
|
||||
pj_pool_t *pool,
|
||||
const pjmedia_codec_param *src);
|
||||
|
||||
|
||||
/*
|
||||
* Forward declaration for pjmedia_codec.
|
||||
|
|
|
@ -387,7 +387,7 @@
|
|||
|
||||
|
||||
/**
|
||||
* Number of packets received from different source IP address from the
|
||||
* Number of RTP packets received from different source IP address from the
|
||||
* remote address required to make the stream switch transmission
|
||||
* to the source address.
|
||||
*/
|
||||
|
@ -396,6 +396,16 @@
|
|||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Number of RTCP packets received from different source IP address from the
|
||||
* remote address required to make the stream switch RTCP transmission
|
||||
* to the source address.
|
||||
*/
|
||||
#ifndef PJMEDIA_RTCP_NAT_PROBATION_CNT
|
||||
# define PJMEDIA_RTCP_NAT_PROBATION_CNT 3
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Specify whether RTCP should be advertised in SDP. This setting would
|
||||
* affect whether RTCP candidate will be added in SDP when ICE is used.
|
||||
|
@ -443,6 +453,19 @@
|
|||
# define PJMEDIA_RTCP_STAT_HAS_RAW_JITTER 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Specify the factor with wich RTCP RTT statistics should be normalized
|
||||
* if exceptionally high. For e.g. mobile networks with potentially large
|
||||
* fluctuations, this might be unwanted.
|
||||
*
|
||||
* Use (0) to disable this feature.
|
||||
*
|
||||
* Default: 3.
|
||||
*/
|
||||
#ifndef PJMEDIA_RTCP_NORMALIZE_FACTOR
|
||||
# define PJMEDIA_RTCP_NORMALIZE_FACTOR 3
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Specify whether RTCP statistics includes IP Delay Variation statistics.
|
||||
|
@ -466,7 +489,7 @@
|
|||
* if it is enabled on run-time on per stream basis. See
|
||||
* PJMEDIA_STREAM_ENABLE_XR setting for more info.
|
||||
*
|
||||
* Default: 1 (yes).
|
||||
* Default: 0 (no).
|
||||
*/
|
||||
#ifndef PJMEDIA_HAS_RTCP_XR
|
||||
# define PJMEDIA_HAS_RTCP_XR 0
|
||||
|
@ -484,6 +507,19 @@
|
|||
# define PJMEDIA_STREAM_ENABLE_XR 0
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Specify the buffer length for storing any received RTCP SDES text
|
||||
* in a stream session. Usually RTCP contains only the mandatory SDES
|
||||
* field, i.e: CNAME.
|
||||
*
|
||||
* Default: 64 bytes.
|
||||
*/
|
||||
#ifndef PJMEDIA_RTCP_RX_SDES_BUF_LEN
|
||||
# define PJMEDIA_RTCP_RX_SDES_BUF_LEN 64
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Specify how long (in miliseconds) the stream should suspend the
|
||||
* silence detector/voice activity detector (VAD) during the initial
|
||||
|
@ -876,7 +912,64 @@
|
|||
* Default: 5 seconds
|
||||
*/
|
||||
#ifndef PJMEDIA_STREAM_KA_INTERVAL
|
||||
# define PJMEDIA_STREAM_KA_INTERVAL 5
|
||||
# define PJMEDIA_STREAM_KA_INTERVAL 5
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Minimum gap between two consecutive discards in jitter buffer,
|
||||
* in milliseconds.
|
||||
*
|
||||
* Default: 200 ms
|
||||
*/
|
||||
#ifndef PJMEDIA_JBUF_DISC_MIN_GAP
|
||||
# define PJMEDIA_JBUF_DISC_MIN_GAP 200
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Minimum burst level reference used for calculating discard duration
|
||||
* in jitter buffer progressive discard algorithm, in frames.
|
||||
*
|
||||
* Default: 1 frame
|
||||
*/
|
||||
#ifndef PJMEDIA_JBUF_PRO_DISC_MIN_BURST
|
||||
# define PJMEDIA_JBUF_PRO_DISC_MIN_BURST 1
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Maximum burst level reference used for calculating discard duration
|
||||
* in jitter buffer progressive discard algorithm, in frames.
|
||||
*
|
||||
* Default: 200 frames
|
||||
*/
|
||||
#ifndef PJMEDIA_JBUF_PRO_DISC_MAX_BURST
|
||||
# define PJMEDIA_JBUF_PRO_DISC_MAX_BURST 100
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Duration for progressive discard algotithm in jitter buffer to discard
|
||||
* an excessive frame when burst is equal to or lower than
|
||||
* PJMEDIA_JBUF_PRO_DISC_MIN_BURST, in milliseconds.
|
||||
*
|
||||
* Default: 2000 ms
|
||||
*/
|
||||
#ifndef PJMEDIA_JBUF_PRO_DISC_T1
|
||||
# define PJMEDIA_JBUF_PRO_DISC_T1 2000
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Duration for progressive discard algotithm in jitter buffer to discard
|
||||
* an excessive frame when burst is equal to or greater than
|
||||
* PJMEDIA_JBUF_PRO_DISC_MAX_BURST, in milliseconds.
|
||||
*
|
||||
* Default: 10000 ms
|
||||
*/
|
||||
#ifndef PJMEDIA_JBUF_PRO_DISC_T2
|
||||
# define PJMEDIA_JBUF_PRO_DISC_T2 10000
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -63,6 +63,19 @@ PJ_BEGIN_DECL
|
|||
/** Opaque declaration for delay buffer. */
|
||||
typedef struct pjmedia_delay_buf pjmedia_delay_buf;
|
||||
|
||||
/**
|
||||
* Delay buffer options.
|
||||
*/
|
||||
typedef enum pjmedia_delay_buf_flag
|
||||
{
|
||||
/**
|
||||
* Use simple FIFO mechanism for the delay buffer, i.e.
|
||||
* without WSOLA for expanding and shrinking audio samples.
|
||||
*/
|
||||
PJMEDIA_DELAY_BUF_SIMPLE_FIFO = 1
|
||||
|
||||
} pjmedia_delay_buf_flag;
|
||||
|
||||
/**
|
||||
* Create the delay buffer. Once the delay buffer is created, it will
|
||||
* enter learning state unless the delay argument is specified, which
|
||||
|
@ -79,7 +92,12 @@ typedef struct pjmedia_delay_buf pjmedia_delay_buf;
|
|||
* in ms, if this value is negative or less than
|
||||
* one frame time, default maximum delay used is
|
||||
* 400 ms.
|
||||
* @param options Option flags, must be zero for now.
|
||||
* @param options Options. If PJMEDIA_DELAY_BUF_SIMPLE_FIFO is
|
||||
* specified, then a simple FIFO mechanism
|
||||
* will be used instead of the adaptive
|
||||
* implementation (which uses WSOLA to expand
|
||||
* or shrink audio samples).
|
||||
* See #pjmedia_delay_buf_flag for other options.
|
||||
* @param p_b Pointer to receive the delay buffer instance.
|
||||
*
|
||||
* @return PJ_SUCCESS if the delay buffer has been
|
||||
|
|
|
@ -88,7 +88,20 @@ typedef enum pjmedia_echo_flag
|
|||
* for the echo canceller, but application will guarantee that echo
|
||||
* canceller will not be called by different threads at the same time.
|
||||
*/
|
||||
PJMEDIA_ECHO_NO_LOCK = 16
|
||||
PJMEDIA_ECHO_NO_LOCK = 16,
|
||||
|
||||
/**
|
||||
* If PJMEDIA_ECHO_USE_SIMPLE_FIFO flag is specified, the delay buffer
|
||||
* created for the echo canceller will use simple FIFO mechanism, i.e.
|
||||
* without using WSOLA to expand and shrink audio samples.
|
||||
*/
|
||||
PJMEDIA_ECHO_USE_SIMPLE_FIFO = 32,
|
||||
|
||||
/**
|
||||
* If PJMEDIA_ECHO_USE_SW_ECHO flag is specified, software echo canceller
|
||||
* will be used instead of device EC.
|
||||
*/
|
||||
PJMEDIA_ECHO_USE_SW_ECHO = 64
|
||||
|
||||
} pjmedia_echo_flag;
|
||||
|
||||
|
|
|
@ -59,6 +59,12 @@ typedef enum pjmedia_endpt_flag
|
|||
} pjmedia_endpt_flag;
|
||||
|
||||
|
||||
/**
|
||||
* Type of callback to register to pjmedia_endpt_atexit().
|
||||
*/
|
||||
typedef void (*pjmedia_endpt_exit_callback)(pjmedia_endpt *endpt);
|
||||
|
||||
|
||||
/**
|
||||
* Create an instance of media endpoint.
|
||||
*
|
||||
|
@ -204,6 +210,23 @@ PJ_DECL(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
|
|||
PJ_DECL(pj_status_t) pjmedia_endpt_dump(pjmedia_endpt *endpt);
|
||||
|
||||
|
||||
/**
|
||||
* Register cleanup function to be called by media endpoint when
|
||||
* #pjmedia_endpt_destroy() is called. Note that application should not
|
||||
* use or access any endpoint resource (such as pool, ioqueue) from within
|
||||
* the callback as such resource may have been released when the callback
|
||||
* function is invoked.
|
||||
*
|
||||
* @param endpt The media endpoint.
|
||||
* @param func The function to be registered.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_endpt_atexit(pjmedia_endpt *endpt,
|
||||
pjmedia_endpt_exit_callback func);
|
||||
|
||||
|
||||
|
||||
PJ_END_DECL
|
||||
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ PJ_BEGIN_DECL
|
|||
/**
|
||||
* Types of frame returned by the jitter buffer.
|
||||
*/
|
||||
enum pjmedia_jb_frame_type
|
||||
typedef enum pjmedia_jb_frame_type
|
||||
{
|
||||
PJMEDIA_JB_MISSING_FRAME = 0, /**< No frame because it's missing */
|
||||
PJMEDIA_JB_NORMAL_FRAME = 1, /**< Normal frame is being returned */
|
||||
|
@ -56,19 +56,47 @@ enum pjmedia_jb_frame_type
|
|||
because JB is bufferring. */
|
||||
PJMEDIA_JB_ZERO_EMPTY_FRAME = 3 /**< Zero frame is being returned
|
||||
because JB is empty. */
|
||||
};
|
||||
} pjmedia_jb_frame_type;
|
||||
|
||||
|
||||
/**
|
||||
* @see pjmedia_jb_frame_type.
|
||||
* Enumeration of jitter buffer discard algorithm. The jitter buffer
|
||||
* continuously calculates the jitter level to get the optimum latency at
|
||||
* any time and in order to adjust the latency, the jitter buffer may need
|
||||
* to discard some frames.
|
||||
*/
|
||||
typedef enum pjmedia_jb_frame_type pjmedia_jb_frame_type;
|
||||
typedef enum pjmedia_jb_discard_algo
|
||||
{
|
||||
/**
|
||||
* Jitter buffer should not discard any frame, except when the jitter
|
||||
* buffer is full and a new frame arrives, one frame will be discarded
|
||||
* to make space for the new frame.
|
||||
*/
|
||||
PJMEDIA_JB_DISCARD_NONE = 0,
|
||||
|
||||
/**
|
||||
* Only discard one frame in at least 200ms when the latency is considered
|
||||
* much higher than it should be. When the jitter buffer is full and a new
|
||||
* frame arrives, one frame will be discarded to make space for the new
|
||||
* frame.
|
||||
*/
|
||||
PJMEDIA_JB_DISCARD_STATIC,
|
||||
|
||||
/**
|
||||
* The discard rate is dynamically calculated based on actual parameters
|
||||
* such as jitter level and latency. When the jitter buffer is full and
|
||||
* a new frame arrives, one frame will be discarded to make space for the
|
||||
* new frame.
|
||||
*/
|
||||
PJMEDIA_JB_DISCARD_PROGRESSIVE
|
||||
|
||||
} pjmedia_jb_discard_algo;
|
||||
|
||||
|
||||
/**
|
||||
* This structure describes jitter buffer state.
|
||||
*/
|
||||
struct pjmedia_jb_state
|
||||
typedef struct pjmedia_jb_state
|
||||
{
|
||||
/* Setting */
|
||||
unsigned frame_size; /**< Individual frame size, in bytes. */
|
||||
|
@ -89,13 +117,7 @@ struct pjmedia_jb_state
|
|||
unsigned lost; /**< Number of lost frames. */
|
||||
unsigned discard; /**< Number of discarded frames. */
|
||||
unsigned empty; /**< Number of empty on GET events. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @see pjmedia_jb_state
|
||||
*/
|
||||
typedef struct pjmedia_jb_state pjmedia_jb_state;
|
||||
} pjmedia_jb_state;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -113,7 +135,9 @@ typedef struct pjmedia_jbuf pjmedia_jbuf;
|
|||
/**
|
||||
* Create an adaptive jitter buffer according to the specification. If
|
||||
* application wants to have a fixed jitter buffer, it may call
|
||||
* #pjmedia_jbuf_set_fixed() after the jitter buffer is created.
|
||||
* #pjmedia_jbuf_set_fixed() after the jitter buffer is created. Also
|
||||
* if application wants to alter the discard algorithm, which the default
|
||||
* PJMEDIA_JB_DISCARD_PROGRESSIVE, it may call #pjmedia_jbuf_set_discard().
|
||||
*
|
||||
* This function may allocate large chunk of memory to keep the frames in
|
||||
* the buffer.
|
||||
|
@ -179,6 +203,19 @@ PJ_DECL(pj_status_t) pjmedia_jbuf_set_adaptive( pjmedia_jbuf *jb,
|
|||
unsigned max_prefetch);
|
||||
|
||||
|
||||
/**
|
||||
* Set the jitter buffer discard algorithm. The default discard algorithm,
|
||||
* set in jitter buffer creation, is PJMEDIA_JB_DISCARD_PROGRESSIVE.
|
||||
*
|
||||
* @param jb The jitter buffer.
|
||||
* @param algo The discard algorithm to be used.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_jbuf_set_discard(pjmedia_jbuf *jb,
|
||||
pjmedia_jb_discard_algo algo);
|
||||
|
||||
|
||||
/**
|
||||
* Destroy jitter buffer instance.
|
||||
*
|
||||
|
|
|
@ -54,29 +54,26 @@ PJ_BEGIN_DECL
|
|||
* #pjmedia_stream_get_stat() function.
|
||||
*/
|
||||
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/**
|
||||
* RTCP sender report.
|
||||
*/
|
||||
struct pjmedia_rtcp_sr
|
||||
typedef struct pjmedia_rtcp_sr
|
||||
{
|
||||
pj_uint32_t ntp_sec; /**< NTP time, seconds part. */
|
||||
pj_uint32_t ntp_frac; /**< NTP time, fractions part. */
|
||||
pj_uint32_t rtp_ts; /**< RTP timestamp. */
|
||||
pj_uint32_t sender_pcount; /**< Sender packet cound. */
|
||||
pj_uint32_t sender_bcount; /**< Sender octet/bytes count. */
|
||||
};
|
||||
} pjmedia_rtcp_sr;
|
||||
|
||||
/**
|
||||
* @see pjmedia_rtcp_sr
|
||||
*/
|
||||
typedef struct pjmedia_rtcp_sr pjmedia_rtcp_sr;
|
||||
|
||||
/**
|
||||
* RTCP receiver report.
|
||||
*/
|
||||
struct pjmedia_rtcp_rr
|
||||
typedef struct pjmedia_rtcp_rr
|
||||
{
|
||||
pj_uint32_t ssrc; /**< SSRC identification. */
|
||||
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
|
||||
|
@ -94,18 +91,13 @@ struct pjmedia_rtcp_rr
|
|||
pj_uint32_t jitter; /**< Jitter. */
|
||||
pj_uint32_t lsr; /**< Last SR. */
|
||||
pj_uint32_t dlsr; /**< Delay since last SR. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @see pjmedia_rtcp_rr
|
||||
*/
|
||||
typedef struct pjmedia_rtcp_rr pjmedia_rtcp_rr;
|
||||
} pjmedia_rtcp_rr;
|
||||
|
||||
|
||||
/**
|
||||
* RTCP common header.
|
||||
*/
|
||||
struct pjmedia_rtcp_common
|
||||
typedef struct pjmedia_rtcp_common
|
||||
{
|
||||
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
|
||||
unsigned version:2; /**< packet type */
|
||||
|
@ -120,12 +112,8 @@ struct pjmedia_rtcp_common
|
|||
#endif
|
||||
unsigned length:16; /**< packet length */
|
||||
pj_uint32_t ssrc; /**< SSRC identification */
|
||||
};
|
||||
} pjmedia_rtcp_common;
|
||||
|
||||
/**
|
||||
* @see pjmedia_rtcp_common
|
||||
*/
|
||||
typedef struct pjmedia_rtcp_common pjmedia_rtcp_common;
|
||||
|
||||
/**
|
||||
* This structure declares default RTCP packet (SR) that is sent by pjmedia.
|
||||
|
@ -152,26 +140,35 @@ typedef struct pjmedia_rtcp_rr_pkt
|
|||
#pragma pack()
|
||||
|
||||
|
||||
/**
|
||||
* RTCP SDES structure.
|
||||
*/
|
||||
typedef struct pjmedia_rtcp_sdes
|
||||
{
|
||||
pj_str_t cname; /**< RTCP SDES type CNAME. */
|
||||
pj_str_t name; /**< RTCP SDES type NAME. */
|
||||
pj_str_t email; /**< RTCP SDES type EMAIL. */
|
||||
pj_str_t phone; /**< RTCP SDES type PHONE. */
|
||||
pj_str_t loc; /**< RTCP SDES type LOC. */
|
||||
pj_str_t tool; /**< RTCP SDES type TOOL. */
|
||||
pj_str_t note; /**< RTCP SDES type NOTE. */
|
||||
} pjmedia_rtcp_sdes;
|
||||
|
||||
|
||||
/**
|
||||
* NTP time representation.
|
||||
*/
|
||||
struct pjmedia_rtcp_ntp_rec
|
||||
typedef struct pjmedia_rtcp_ntp_rec
|
||||
{
|
||||
pj_uint32_t hi; /**< High order 32-bit part. */
|
||||
pj_uint32_t lo; /**< Lo order 32-bit part. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @see pjmedia_rtcp_ntp_rec
|
||||
*/
|
||||
typedef struct pjmedia_rtcp_ntp_rec pjmedia_rtcp_ntp_rec;
|
||||
|
||||
} pjmedia_rtcp_ntp_rec;
|
||||
|
||||
|
||||
/**
|
||||
* Unidirectional RTP stream statistics.
|
||||
*/
|
||||
struct pjmedia_rtcp_stream_stat
|
||||
typedef struct pjmedia_rtcp_stream_stat
|
||||
{
|
||||
pj_time_val update; /**< Time of last update. */
|
||||
unsigned update_cnt; /**< Number of updates (to calculate avg) */
|
||||
|
@ -190,20 +187,14 @@ struct pjmedia_rtcp_stream_stat
|
|||
} loss_type; /**< Types of loss detected. */
|
||||
|
||||
pj_math_stat jitter; /**< Jitter statistics (in usec) */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @see pjmedia_rtcp_stream_stat
|
||||
*/
|
||||
typedef struct pjmedia_rtcp_stream_stat pjmedia_rtcp_stream_stat;
|
||||
|
||||
} pjmedia_rtcp_stream_stat;
|
||||
|
||||
|
||||
/**
|
||||
* Bidirectional RTP stream statistics.
|
||||
*/
|
||||
struct pjmedia_rtcp_stat
|
||||
typedef struct pjmedia_rtcp_stat
|
||||
{
|
||||
pj_time_val start; /**< Time when session was created */
|
||||
|
||||
|
@ -226,20 +217,19 @@ struct pjmedia_rtcp_stat
|
|||
receiving direction
|
||||
(in usec). */
|
||||
#endif
|
||||
};
|
||||
|
||||
pjmedia_rtcp_sdes peer_sdes; /**< Peer SDES. */
|
||||
char peer_sdes_buf_[PJMEDIA_RTCP_RX_SDES_BUF_LEN];
|
||||
/**< Peer SDES buffer. */
|
||||
|
||||
/**
|
||||
* @see pjmedia_rtcp_stat
|
||||
*/
|
||||
typedef struct pjmedia_rtcp_stat pjmedia_rtcp_stat;
|
||||
} pjmedia_rtcp_stat;
|
||||
|
||||
|
||||
/**
|
||||
* RTCP session is used to monitor the RTP session of one endpoint. There
|
||||
* should only be one RTCP session for a bidirectional RTP streams.
|
||||
*/
|
||||
struct pjmedia_rtcp_session
|
||||
typedef struct pjmedia_rtcp_session
|
||||
{
|
||||
char *name; /**< Name identification. */
|
||||
pjmedia_rtcp_sr_pkt rtcp_sr_pkt;/**< Cached RTCP SR packet. */
|
||||
|
@ -278,12 +268,7 @@ struct pjmedia_rtcp_session
|
|||
*/
|
||||
pjmedia_rtcp_xr_session xr_session;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @see pjmedia_rtcp_session
|
||||
*/
|
||||
typedef struct pjmedia_rtcp_session pjmedia_rtcp_session;
|
||||
} pjmedia_rtcp_session;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -438,6 +423,46 @@ PJ_DECL(void) pjmedia_rtcp_build_rtcp( pjmedia_rtcp_session *session,
|
|||
void **rtcp_pkt, int *len);
|
||||
|
||||
|
||||
/**
|
||||
* Build an RTCP SDES (source description) packet. This packet can be
|
||||
* appended to other RTCP packets, e.g: RTCP RR/SR, to compose a compound
|
||||
* RTCP packet.
|
||||
*
|
||||
* @param session The RTCP session.
|
||||
* @param buf The buffer to receive RTCP SDES packet.
|
||||
* @param length On input, it will contain the buffer length.
|
||||
* On output, it will contain the generated RTCP SDES
|
||||
* packet length.
|
||||
* @param sdes The source description, see #pjmedia_rtcp_sdes.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_rtcp_build_rtcp_sdes(
|
||||
pjmedia_rtcp_session *session,
|
||||
void *buf,
|
||||
pj_size_t *length,
|
||||
const pjmedia_rtcp_sdes *sdes);
|
||||
|
||||
/**
|
||||
* Build an RTCP BYE packet. This packet can be appended to other RTCP
|
||||
* packets, e.g: RTCP RR/SR, to compose a compound RTCP packet.
|
||||
*
|
||||
* @param session The RTCP session.
|
||||
* @param buf The buffer to receive RTCP BYE packet.
|
||||
* @param length On input, it will contain the buffer length.
|
||||
* On output, it will contain the generated RTCP BYE
|
||||
* packet length.
|
||||
* @param reason Optional, the BYE reason.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_rtcp_build_rtcp_bye(
|
||||
pjmedia_rtcp_session *session,
|
||||
void *buf,
|
||||
pj_size_t *length,
|
||||
const pj_str_t *reason);
|
||||
|
||||
|
||||
/**
|
||||
* Call this function if RTCP XR needs to be enabled/disabled in the
|
||||
* RTCP session.
|
||||
|
|
|
@ -200,6 +200,17 @@ typedef struct pjmedia_rtcp_xr_rb_voip_mtc
|
|||
jitter buffer */
|
||||
} pjmedia_rtcp_xr_rb_voip_mtc;
|
||||
|
||||
|
||||
/**
|
||||
* Constant of RTCP-XR content size.
|
||||
*/
|
||||
#define PJMEDIA_RTCP_XR_BUF_SIZE \
|
||||
sizeof(pjmedia_rtcp_xr_rb_rr_time) + \
|
||||
sizeof(pjmedia_rtcp_xr_rb_dlrr) + \
|
||||
sizeof(pjmedia_rtcp_xr_rb_stats) + \
|
||||
sizeof(pjmedia_rtcp_xr_rb_voip_mtc)
|
||||
|
||||
|
||||
/**
|
||||
* This structure declares RTCP XR (Extended Report) packet.
|
||||
*/
|
||||
|
@ -221,7 +232,8 @@ typedef struct pjmedia_rtcp_xr_pkt
|
|||
pj_uint32_t ssrc; /**< SSRC identification */
|
||||
} common;
|
||||
|
||||
pj_int8_t buf[PJMEDIA_MAX_MTU];/**< Content buffer */
|
||||
pj_int8_t buf[PJMEDIA_RTCP_XR_BUF_SIZE];
|
||||
/**< Content buffer */
|
||||
} pjmedia_rtcp_xr_pkt;
|
||||
|
||||
#pragma pack()
|
||||
|
|
|
@ -231,6 +231,26 @@ PJ_DECL(pj_status_t) pjmedia_session_resume_stream(pjmedia_session *session,
|
|||
unsigned index,
|
||||
pjmedia_dir dir);
|
||||
|
||||
/**
|
||||
* Send RTCP SDES for the session.
|
||||
*
|
||||
* @param session The media session.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pjmedia_session_send_rtcp_sdes( const pjmedia_session *session );
|
||||
|
||||
/**
|
||||
* Send RTCP BYE for the session.
|
||||
*
|
||||
* @param session The media session.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pjmedia_session_send_rtcp_bye( const pjmedia_session *session );
|
||||
|
||||
/**
|
||||
* Enumerate media streams in the session.
|
||||
*
|
||||
|
|
|
@ -75,6 +75,8 @@ enum pjmedia_snd_port_option
|
|||
|
||||
/**
|
||||
* This structure specifies the parameters to create the sound port.
|
||||
* Use pjmedia_snd_port_param_default() to initialize this structure with
|
||||
* default values (mostly zeroes)
|
||||
*/
|
||||
typedef struct pjmedia_snd_port_param
|
||||
{
|
||||
|
@ -87,8 +89,21 @@ typedef struct pjmedia_snd_port_param
|
|||
* Sound port creation options.
|
||||
*/
|
||||
unsigned options;
|
||||
|
||||
/**
|
||||
* Echo cancellation options/flags.
|
||||
*/
|
||||
unsigned ec_options;
|
||||
|
||||
} pjmedia_snd_port_param;
|
||||
|
||||
/**
|
||||
* Initialize pjmedia_snd_port_param with default values.
|
||||
*
|
||||
* @param prm The parameter.
|
||||
*/
|
||||
PJ_DECL(void) pjmedia_snd_port_param_default(pjmedia_snd_port_param *prm);
|
||||
|
||||
/**
|
||||
* This opaque type describes sound device port connection.
|
||||
* Sound device port is not a media port, but it is used to connect media
|
||||
|
|
|
@ -133,6 +133,9 @@ struct pjmedia_stream_info
|
|||
(see #PJMEDIA_STREAM_ENABLE_KA)
|
||||
is enabled? */
|
||||
#endif
|
||||
pj_bool_t rtcp_sdes_bye_disabled;
|
||||
/**< Disable automatic sending of RTCP
|
||||
SDES and BYE. */
|
||||
};
|
||||
|
||||
|
||||
|
@ -371,6 +374,26 @@ pjmedia_stream_set_dtmf_callback(pjmedia_stream *stream,
|
|||
int digit),
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Send RTCP SDES for the media stream.
|
||||
*
|
||||
* @param stream The media stream.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pjmedia_stream_send_rtcp_sdes( pjmedia_stream *stream );
|
||||
|
||||
/**
|
||||
* Send RTCP BYE for the media stream.
|
||||
*
|
||||
* @param stream The media stream.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pjmedia_stream_send_rtcp_bye( pjmedia_stream *stream );
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -533,7 +533,7 @@ PJ_INLINE(void) pjmedia_transport_info_init(pjmedia_transport_info *info)
|
|||
* for example to fill in the "c=" and "m=" line of local SDP.
|
||||
*
|
||||
* @param tp The transport.
|
||||
* @param info Media socket info to be initialized.
|
||||
* @param info Media transport info to be initialized.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
|
@ -547,6 +547,29 @@ PJ_INLINE(pj_status_t) pjmedia_transport_get_info(pjmedia_transport *tp,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility API to get transport type specific info from the specified media
|
||||
* transport info.
|
||||
*
|
||||
* @param info Media transport info.
|
||||
* @param type Media transport type.
|
||||
*
|
||||
* @return Pointer to media transport specific info, or NULL if
|
||||
* specific info for the transport type is not found.
|
||||
*/
|
||||
PJ_INLINE(void*) pjmedia_transport_info_get_spc_info(
|
||||
pjmedia_transport_info *info,
|
||||
pjmedia_transport_type type)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < info->specific_info_cnt; ++i) {
|
||||
if (info->spc_info[i].type == type)
|
||||
return (void*)info->spc_info[i].buffer;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attach callbacks to be called on receipt of incoming RTP/RTCP packets.
|
||||
* This is just a simple wrapper which calls <tt>attach()</tt> member of
|
||||
|
|
|
@ -49,15 +49,18 @@ PJ_BEGIN_DECL
|
|||
* @param endpt The media endpoint.
|
||||
* @param name Optional name to identify this media transport
|
||||
* for logging purposes.
|
||||
* @param transport The underlying media transport to send and receive
|
||||
* RTP/RTCP packets.
|
||||
* @param base_tp The base/underlying media transport to send and
|
||||
* receive RTP/RTCP packets.
|
||||
* @param del_base Specify whether the base transport should also be
|
||||
* destroyed when destroy() is called upon us.
|
||||
* @param p_tp Pointer to receive the media transport instance.
|
||||
*
|
||||
* @return PJ_SUCCESS on success, or the appropriate error code.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_tp_adapter_create( pjmedia_endpt *endpt,
|
||||
const char *name,
|
||||
pjmedia_transport *transport,
|
||||
pjmedia_transport *base_tp,
|
||||
pj_bool_t del_base,
|
||||
pjmedia_transport **p_tp);
|
||||
|
||||
PJ_END_DECL
|
||||
|
|
|
@ -200,8 +200,12 @@ typedef struct pjmedia_srtp_info
|
|||
* will also invoke this function. This function will also register SRTP
|
||||
* library deinitialization to #pj_atexit(), so the deinitialization
|
||||
* of SRTP library will be performed automatically by PJLIB destructor.
|
||||
*
|
||||
* @param endpt The media endpoint instance.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjmedia_srtp_init_lib(void);
|
||||
PJ_DECL(pj_status_t) pjmedia_srtp_init_lib(pjmedia_endpt *endpt);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -232,7 +232,7 @@ static pj_status_t add_dev (struct alsa_factory *af, const char *dev_name)
|
|||
pj_bzero(adi, sizeof(*adi));
|
||||
|
||||
/* Set device name */
|
||||
strcpy(adi->name, dev_name);
|
||||
strncpy(adi->name, dev_name, sizeof(adi->name));
|
||||
|
||||
/* Check the number of playback channels */
|
||||
adi->output_count = (pb_result>=0) ? 1 : 0;
|
||||
|
@ -547,6 +547,7 @@ static pj_status_t open_playback (struct alsa_stream* stream,
|
|||
int result;
|
||||
unsigned int rate;
|
||||
snd_pcm_uframes_t tmp_buf_size;
|
||||
snd_pcm_uframes_t tmp_period_size;
|
||||
|
||||
if (param->play_id < 0 || param->play_id >= stream->af->dev_cnt)
|
||||
return PJMEDIA_EAUD_INVDEV;
|
||||
|
@ -613,10 +614,11 @@ static pj_status_t open_playback (struct alsa_stream* stream,
|
|||
param->channel_count;
|
||||
TRACE_((THIS_FILE, "open_playback: set period size: %d",
|
||||
stream->pb_frames));
|
||||
tmp_period_size = stream->pb_frames;
|
||||
snd_pcm_hw_params_set_period_size_near (stream->pb_pcm, params,
|
||||
&stream->pb_frames, NULL);
|
||||
&tmp_period_size, NULL);
|
||||
TRACE_((THIS_FILE, "open_playback: period size set to: %d",
|
||||
stream->pb_frames));
|
||||
tmp_period_size));
|
||||
|
||||
/* Set the sound device buffer size and latency */
|
||||
if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY)
|
||||
|
@ -663,6 +665,7 @@ static pj_status_t open_capture (struct alsa_stream* stream,
|
|||
int result;
|
||||
unsigned int rate;
|
||||
snd_pcm_uframes_t tmp_buf_size;
|
||||
snd_pcm_uframes_t tmp_period_size;
|
||||
|
||||
if (param->rec_id < 0 || param->rec_id >= stream->af->dev_cnt)
|
||||
return PJMEDIA_EAUD_INVDEV;
|
||||
|
@ -729,10 +732,11 @@ static pj_status_t open_capture (struct alsa_stream* stream,
|
|||
param->channel_count;
|
||||
TRACE_((THIS_FILE, "open_capture: set period size: %d",
|
||||
stream->ca_frames));
|
||||
tmp_period_size = stream->ca_frames;
|
||||
snd_pcm_hw_params_set_period_size_near (stream->ca_pcm, params,
|
||||
&stream->ca_frames, NULL);
|
||||
&tmp_period_size, NULL);
|
||||
TRACE_((THIS_FILE, "open_capture: period size set to: %d",
|
||||
stream->ca_frames));
|
||||
tmp_period_size));
|
||||
|
||||
/* Set the sound device buffer size and latency */
|
||||
if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY)
|
||||
|
|
|
@ -145,7 +145,7 @@ PJ_DEF(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
|
|||
break;
|
||||
}
|
||||
|
||||
if (i==32) {
|
||||
if (i==PJ_ARRAY_SIZE(cap_infos)) {
|
||||
*p_desc = "??";
|
||||
return "??";
|
||||
}
|
||||
|
@ -488,11 +488,13 @@ PJ_DEF(pj_status_t) pjmedia_aud_subsys_shutdown(void)
|
|||
}
|
||||
--aud_subsys.init_count;
|
||||
|
||||
for (i=0; i<aud_subsys.drv_cnt; ++i) {
|
||||
deinit_driver(i);
|
||||
}
|
||||
if (aud_subsys.init_count == 0) {
|
||||
for (i=0; i<aud_subsys.drv_cnt; ++i) {
|
||||
deinit_driver(i);
|
||||
}
|
||||
|
||||
aud_subsys.pf = NULL;
|
||||
aud_subsys.pf = NULL;
|
||||
}
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -1111,7 +1111,17 @@ static void interruptionListener(void *inClientData, UInt32 inInterruption)
|
|||
{
|
||||
struct stream_list *it, *itBegin;
|
||||
pj_status_t status;
|
||||
|
||||
pj_thread_desc thread_desc;
|
||||
pj_thread_t *thread;
|
||||
|
||||
/* Register the thread with PJLIB, this is must for any external threads
|
||||
* which need to use the PJLIB framework.
|
||||
*/
|
||||
if (!pj_thread_is_registered()) {
|
||||
pj_bzero(thread_desc, sizeof(pj_thread_desc));
|
||||
status = pj_thread_register("intListener", thread_desc, &thread);
|
||||
}
|
||||
|
||||
PJ_LOG(3, (THIS_FILE, "Session interrupted! --- %s ---",
|
||||
inInterruption == kAudioSessionBeginInterruption ?
|
||||
"Begin Interruption" : "End Interruption"));
|
||||
|
@ -1954,6 +1964,11 @@ static pj_status_t ca_stream_set_cap(pjmedia_aud_stream *s,
|
|||
strm->cf->io_comp = io_comp;
|
||||
strm->param.ec_enabled = *(pj_bool_t*)pval;
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, "Using %s audio unit",
|
||||
(desc.componentSubType ==
|
||||
kAudioUnitSubType_RemoteIO? "RemoteIO":
|
||||
"VoiceProcessingIO")));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1086,7 +1086,7 @@ static void PlayCb(TAPSCommBuffer &buf, void *user_data)
|
|||
buf.iBuffer.Append((TUint8*)sf->data, len);
|
||||
} else {
|
||||
enum {NO_DATA_FT = 15 };
|
||||
pj_uint8_t amr_header = 4 || (NO_DATA_FT << 3);
|
||||
pj_uint8_t amr_header = 4 | (NO_DATA_FT << 3);
|
||||
|
||||
buf.iBuffer.Append(amr_header);
|
||||
}
|
||||
|
@ -1095,7 +1095,7 @@ static void PlayCb(TAPSCommBuffer &buf, void *user_data)
|
|||
|
||||
} else { /* PJMEDIA_FRAME_TYPE_NONE */
|
||||
enum {NO_DATA_FT = 15 };
|
||||
pj_uint8_t amr_header = 4 || (NO_DATA_FT << 3);
|
||||
pj_uint8_t amr_header = 4 | (NO_DATA_FT << 3);
|
||||
|
||||
buf.iBuffer.Append(amr_header);
|
||||
|
||||
|
|
|
@ -239,6 +239,7 @@ private:
|
|||
TPtr8 iFramePtr_;
|
||||
TInt lastError_;
|
||||
pj_uint32_t timeStamp_;
|
||||
CActiveSchedulerWait startAsw_;
|
||||
|
||||
// cache variable
|
||||
// to avoid calculating frame length repeatedly
|
||||
|
@ -363,6 +364,13 @@ pj_status_t CPjAudioInputEngine::StartRecord()
|
|||
lastError_ = KRequestPending;
|
||||
iInputStream_->Open(&iStreamSettings);
|
||||
|
||||
#if defined(PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START) && \
|
||||
PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START != 0
|
||||
|
||||
startAsw_.Start();
|
||||
|
||||
#endif
|
||||
|
||||
// Success
|
||||
PJ_LOG(4,(THIS_FILE, "Sound capture started."));
|
||||
return PJ_SUCCESS;
|
||||
|
@ -386,6 +394,10 @@ void CPjAudioInputEngine::Stop()
|
|||
iInputStream_ = NULL;
|
||||
}
|
||||
|
||||
if (startAsw_.IsStarted()) {
|
||||
startAsw_.AsyncStop();
|
||||
}
|
||||
|
||||
state_ = STATE_INACTIVE;
|
||||
}
|
||||
|
||||
|
@ -399,12 +411,25 @@ TPtr8 & CPjAudioInputEngine::GetFrame()
|
|||
|
||||
void CPjAudioInputEngine::MaiscOpenComplete(TInt aError)
|
||||
{
|
||||
if (startAsw_.IsStarted()) {
|
||||
startAsw_.AsyncStop();
|
||||
}
|
||||
|
||||
lastError_ = aError;
|
||||
if (aError != KErrNone) {
|
||||
snd_perror("Error in MaiscOpenComplete()", aError);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Apply input volume setting if specified */
|
||||
if (parentStrm_->param.flags &
|
||||
PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING)
|
||||
{
|
||||
stream_set_cap(&parentStrm_->base,
|
||||
PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING,
|
||||
&parentStrm_->param.input_vol);
|
||||
}
|
||||
|
||||
// set stream priority to normal and time sensitive
|
||||
iInputStream_->SetPriority(EPriorityNormal,
|
||||
EMdaPriorityPreferenceTime);
|
||||
|
@ -414,7 +439,12 @@ void CPjAudioInputEngine::MaiscOpenComplete(TInt aError)
|
|||
TRAPD(err2, iInputStream_->ReadL(frm));
|
||||
if (err2) {
|
||||
PJ_LOG(4,(THIS_FILE, "Exception in iInputStream_->ReadL()"));
|
||||
lastError_ = err2;
|
||||
return;
|
||||
}
|
||||
|
||||
// input stream opened succesfully, set status to Active
|
||||
state_ = STATE_ACTIVE;
|
||||
}
|
||||
|
||||
void CPjAudioInputEngine::MaiscBufferCopied(TInt aError,
|
||||
|
@ -547,6 +577,7 @@ private:
|
|||
TPtrC8 frame_;
|
||||
TInt lastError_;
|
||||
unsigned timestamp_;
|
||||
CActiveSchedulerWait startAsw_;
|
||||
|
||||
CPjAudioOutputEngine(struct mda_stream *parent_strm,
|
||||
pjmedia_aud_play_cb play_cb,
|
||||
|
@ -638,6 +669,13 @@ pj_status_t CPjAudioOutputEngine::StartPlay()
|
|||
// Open stream.
|
||||
lastError_ = KRequestPending;
|
||||
iOutputStream_->Open(&iStreamSettings);
|
||||
|
||||
#if defined(PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START) && \
|
||||
PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START != 0
|
||||
|
||||
startAsw_.Start();
|
||||
|
||||
#endif
|
||||
|
||||
// Success
|
||||
PJ_LOG(4,(THIS_FILE, "Sound playback started"));
|
||||
|
@ -662,17 +700,22 @@ void CPjAudioOutputEngine::Stop()
|
|||
iOutputStream_ = NULL;
|
||||
}
|
||||
|
||||
if (startAsw_.IsStarted()) {
|
||||
startAsw_.AsyncStop();
|
||||
}
|
||||
|
||||
state_ = STATE_INACTIVE;
|
||||
}
|
||||
|
||||
void CPjAudioOutputEngine::MaoscOpenComplete(TInt aError)
|
||||
{
|
||||
if (startAsw_.IsStarted()) {
|
||||
startAsw_.AsyncStop();
|
||||
}
|
||||
|
||||
lastError_ = aError;
|
||||
|
||||
if (aError==KErrNone) {
|
||||
// output stream opened succesfully, set status to Active
|
||||
state_ = STATE_ACTIVE;
|
||||
|
||||
// set stream properties, 16bit 8KHz mono
|
||||
TMdaAudioDataSettings iSettings;
|
||||
iSettings.iChannels =
|
||||
|
@ -683,8 +726,17 @@ void CPjAudioOutputEngine::MaoscOpenComplete(TInt aError)
|
|||
iOutputStream_->SetAudioPropertiesL(iSettings.iSampleRate,
|
||||
iSettings.iChannels);
|
||||
|
||||
// set volume to 1/2th of stream max volume
|
||||
iOutputStream_->SetVolume(iOutputStream_->MaxVolume()/2);
|
||||
/* Apply output volume setting if specified */
|
||||
if (parentStrm_->param.flags &
|
||||
PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING)
|
||||
{
|
||||
stream_set_cap(&parentStrm_->base,
|
||||
PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
|
||||
&parentStrm_->param.output_vol);
|
||||
} else {
|
||||
// set volume to 1/2th of stream max volume
|
||||
iOutputStream_->SetVolume(iOutputStream_->MaxVolume()/2);
|
||||
}
|
||||
|
||||
// set stream priority to normal and time sensitive
|
||||
iOutputStream_->SetPriority(EPriorityNormal,
|
||||
|
@ -718,6 +770,9 @@ void CPjAudioOutputEngine::MaoscOpenComplete(TInt aError)
|
|||
// until whole data buffer is written.
|
||||
frame_.Set(frameBuf_, frameBufSize_);
|
||||
iOutputStream_->WriteL(frame_);
|
||||
|
||||
// output stream opened succesfully, set status to Active
|
||||
state_ = STATE_ACTIVE;
|
||||
} else {
|
||||
snd_perror("Error in MaoscOpenComplete()", aError);
|
||||
}
|
||||
|
@ -881,7 +936,8 @@ static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
|
|||
param->channel_count = 1;
|
||||
param->samples_per_frame = af->dev_info.default_samples_per_sec * 20 / 1000;
|
||||
param->bits_per_sample = BITS_PER_SAMPLE;
|
||||
param->flags = af->dev_info.caps;
|
||||
// Don't set the flags without specifying the flags value.
|
||||
//param->flags = af->dev_info.caps;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
@ -956,6 +1012,20 @@ static pj_status_t stream_get_param(pjmedia_aud_stream *s,
|
|||
|
||||
pj_memcpy(pi, &strm->param, sizeof(*pi));
|
||||
|
||||
/* Update the output volume setting */
|
||||
if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
|
||||
&pi->output_vol) == PJ_SUCCESS)
|
||||
{
|
||||
pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
|
||||
}
|
||||
|
||||
/* Update the input volume setting */
|
||||
if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING,
|
||||
&pi->input_vol) == PJ_SUCCESS)
|
||||
{
|
||||
pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1034,7 +1104,7 @@ static pj_status_t stream_set_cap(pjmedia_aud_stream *s,
|
|||
}
|
||||
break;
|
||||
case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
|
||||
if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
|
||||
if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
|
||||
PJ_ASSERT_RETURN(strm->out_engine, PJ_EINVAL);
|
||||
|
||||
TInt max_vol = strm->out_engine->GetMaxVolume();
|
||||
|
|
|
@ -1130,7 +1130,7 @@ static void PlayCb(CVoIPDataBuffer *buf, void *user_data)
|
|||
buffer.Append((TUint8*)sf->data, len);
|
||||
} else {
|
||||
enum {NO_DATA_FT = 15 };
|
||||
pj_uint8_t amr_header = 4 || (NO_DATA_FT << 3);
|
||||
pj_uint8_t amr_header = 4 | (NO_DATA_FT << 3);
|
||||
|
||||
buffer.Append(amr_header);
|
||||
}
|
||||
|
@ -1139,7 +1139,7 @@ static void PlayCb(CVoIPDataBuffer *buf, void *user_data)
|
|||
|
||||
} else { /* PJMEDIA_FRAME_TYPE_NONE */
|
||||
enum {NO_DATA_FT = 15 };
|
||||
pj_uint8_t amr_header = 4 || (NO_DATA_FT << 3);
|
||||
pj_uint8_t amr_header = 4 | (NO_DATA_FT << 3);
|
||||
|
||||
buffer.Append(amr_header);
|
||||
|
||||
|
@ -1746,12 +1746,6 @@ static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
|
|||
return PJ_RETURN_OS_ERROR(err);
|
||||
}
|
||||
|
||||
/* Apply output volume setting if specified */
|
||||
if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
|
||||
stream_set_cap(&strm->base, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
|
||||
¶m->output_vol);
|
||||
}
|
||||
|
||||
/* Done */
|
||||
strm->base.op = &stream_op;
|
||||
*p_aud_strm = &strm->base;
|
||||
|
@ -1945,10 +1939,21 @@ static pj_status_t stream_start(pjmedia_aud_stream *strm)
|
|||
} while (!stream->engine->IsStarted() &&
|
||||
(now.MicroSecondsFrom(start) < VAS_WAIT_START * 1000));
|
||||
|
||||
if (stream->engine->IsStarted())
|
||||
if (stream->engine->IsStarted()) {
|
||||
|
||||
/* Apply output volume setting if specified */
|
||||
if (stream->param.flags &
|
||||
PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING)
|
||||
{
|
||||
stream_set_cap(strm,
|
||||
PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
|
||||
&stream->param.output_vol);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
else
|
||||
} else {
|
||||
return PJ_ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return PJ_EINVALIDOP;
|
||||
|
|
|
@ -748,15 +748,14 @@ static pj_status_t codec_encode( pjmedia_codec *codec,
|
|||
struct pjmedia_frame *output)
|
||||
{
|
||||
codec_private_t *codec_data = (codec_private_t*) codec->codec_data;
|
||||
const Word16 *pcm_input;
|
||||
Word16 mlt_coefs[MAX_SAMPLES_PER_FRAME];
|
||||
Word16 mag_shift;
|
||||
unsigned nsamples, processed;
|
||||
|
||||
/* Check frame in & out size */
|
||||
PJ_ASSERT_RETURN((pj_uint16_t)input->size ==
|
||||
(codec_data->samples_per_frame<<1),
|
||||
PJMEDIA_CODEC_EPCMTOOSHORT);
|
||||
PJ_ASSERT_RETURN(output_buf_len >= codec_data->frame_size,
|
||||
nsamples = input->size >> 1;
|
||||
PJ_ASSERT_RETURN(nsamples % codec_data->samples_per_frame == 0,
|
||||
PJMEDIA_CODEC_EPCMFRMINLEN);
|
||||
PJ_ASSERT_RETURN(output_buf_len >= codec_data->frame_size * nsamples /
|
||||
codec_data->samples_per_frame,
|
||||
PJMEDIA_CODEC_EFRMTOOSHORT);
|
||||
|
||||
/* Apply silence detection if VAD is enabled */
|
||||
|
@ -788,41 +787,52 @@ static pj_status_t codec_encode( pjmedia_codec *codec,
|
|||
}
|
||||
}
|
||||
|
||||
/* Encoder adjust the input signal level */
|
||||
if (codec_data->pcm_shift) {
|
||||
unsigned i;
|
||||
pcm_input = (const Word16*)input->buf;
|
||||
for (i=0; i<codec_data->samples_per_frame; ++i) {
|
||||
codec_data->enc_frame[i] =
|
||||
(pj_int16_t)(pcm_input[i] >> codec_data->pcm_shift);
|
||||
processed = 0;
|
||||
output->size = 0;
|
||||
while (processed < nsamples) {
|
||||
Word16 mlt_coefs[MAX_SAMPLES_PER_FRAME];
|
||||
Word16 mag_shift;
|
||||
const Word16 *pcm_input;
|
||||
pj_int8_t *out_bits;
|
||||
|
||||
pcm_input = (const Word16*)input->buf + processed;
|
||||
out_bits = (pj_int8_t*)output->buf + output->size;
|
||||
|
||||
/* Encoder adjust the input signal level */
|
||||
if (codec_data->pcm_shift) {
|
||||
unsigned i;
|
||||
for (i=0; i<codec_data->samples_per_frame; ++i) {
|
||||
codec_data->enc_frame[i] =
|
||||
(Word16)(pcm_input[i] >> codec_data->pcm_shift);
|
||||
}
|
||||
pcm_input = codec_data->enc_frame;
|
||||
}
|
||||
pcm_input = codec_data->enc_frame;
|
||||
} else {
|
||||
pcm_input = (const Word16*)input->buf;
|
||||
|
||||
/* Convert input samples to rmlt coefs */
|
||||
mag_shift = samples_to_rmlt_coefs(pcm_input,
|
||||
codec_data->enc_old_frame,
|
||||
mlt_coefs,
|
||||
codec_data->samples_per_frame);
|
||||
|
||||
/* Encode the mlt coefs. Note that encoder output stream is
|
||||
* 16 bit array, so we need to take care about endianness.
|
||||
*/
|
||||
encoder(codec_data->frame_size_bits,
|
||||
codec_data->number_of_regions,
|
||||
mlt_coefs,
|
||||
mag_shift,
|
||||
(Word16*)out_bits);
|
||||
|
||||
/* Encoder output are in native host byte order, while ITU says
|
||||
* it must be in network byte order (MSB first).
|
||||
*/
|
||||
swap_bytes((pj_uint16_t*)out_bits, codec_data->frame_size/2);
|
||||
|
||||
processed += codec_data->samples_per_frame;
|
||||
output->size += codec_data->frame_size;
|
||||
}
|
||||
|
||||
/* Convert input samples to rmlt coefs */
|
||||
mag_shift = samples_to_rmlt_coefs(pcm_input,
|
||||
codec_data->enc_old_frame,
|
||||
mlt_coefs,
|
||||
codec_data->samples_per_frame);
|
||||
|
||||
/* Encode the mlt coefs. Note that encoder output stream is 16 bit array,
|
||||
* so we need to take care about endianness.
|
||||
*/
|
||||
encoder(codec_data->frame_size_bits,
|
||||
codec_data->number_of_regions,
|
||||
mlt_coefs,
|
||||
mag_shift,
|
||||
output->buf);
|
||||
|
||||
/* Encoder output are in native host byte order, while ITU says
|
||||
* it must be in network byte order (MSB first).
|
||||
*/
|
||||
swap_bytes((pj_uint16_t*)output->buf, codec_data->frame_size/2);
|
||||
|
||||
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
output->size = codec_data->frame_size;
|
||||
output->timestamp = input->timestamp;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#define THIS_FILE "ipp_codecs.c"
|
||||
|
||||
|
||||
/* Prototypes for IPP codecs factory */
|
||||
static pj_status_t ipp_test_alloc( pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *id );
|
||||
|
@ -237,9 +238,8 @@ static struct ipp_codec {
|
|||
ipp_codec[] =
|
||||
{
|
||||
# if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
|
||||
/* AMR-NB SID seems to produce noise, so let's just disable its VAD. */
|
||||
{1, "AMR", PJMEDIA_RTP_PT_AMR, &USC_GSMAMR_Fxns, 8000, 1, 160,
|
||||
7400, 12200, 2, 0, 1,
|
||||
7400, 12200, 2, 1, 1,
|
||||
&predecode_amr, &parse_amr, &pack_amr,
|
||||
{1, {{{"octet-align", 11}, {"1", 1}}} }
|
||||
},
|
||||
|
@ -247,7 +247,7 @@ ipp_codec[] =
|
|||
|
||||
# if PJMEDIA_HAS_INTEL_IPP_CODEC_AMRWB
|
||||
{1, "AMR-WB", PJMEDIA_RTP_PT_AMRWB, &USC_AMRWB_Fxns, 16000, 1, 320,
|
||||
15850, 23850, 1, 1, 1,
|
||||
15850, 23850, 2, 1, 1,
|
||||
&predecode_amr, &parse_amr, &pack_amr,
|
||||
{1, {{{"octet-align", 11}, {"1", 1}}} }
|
||||
},
|
||||
|
@ -437,7 +437,7 @@ static pj_status_t parse_g723(ipp_private_t *codec_data, void *pkt,
|
|||
#endif /* PJMEDIA_HAS_INTEL_IPP_CODEC_G723_1 */
|
||||
|
||||
|
||||
#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR
|
||||
#if PJMEDIA_HAS_INTEL_IPP_CODEC_AMR || PJMEDIA_HAS_INTEL_IPP_CODEC_AMRWB
|
||||
|
||||
#include <pjmedia-codec/amr_helper.h>
|
||||
|
||||
|
@ -487,9 +487,7 @@ static void predecode_amr( ipp_private_t *codec_data,
|
|||
} else if (frame.size == 5) {
|
||||
/* SID */
|
||||
if (info->good_quality) {
|
||||
pj_bool_t STI;
|
||||
STI = (((pj_uint8_t*)frame.buf)[35 >> 3] & 0x10) != 0;
|
||||
usc_frame->frametype = STI? 2 : 1;
|
||||
usc_frame->frametype = info->STI? 2 : 1;
|
||||
} else {
|
||||
usc_frame->frametype = setting->amr_nb ? 6 : 7;
|
||||
}
|
||||
|
@ -511,8 +509,11 @@ static pj_status_t pack_amr(ipp_private_t *codec_data, void *pkt,
|
|||
pj_uint8_t *r; /* Read cursor */
|
||||
pj_uint8_t SID_FT;
|
||||
pjmedia_codec_amr_pack_setting *setting;
|
||||
const pj_uint8_t *framelen_tbl;
|
||||
|
||||
setting = &((amr_settings_t*)codec_data->codec_setting)->enc_setting;
|
||||
framelen_tbl = setting->amr_nb? pjmedia_codec_amrnb_framelen:
|
||||
pjmedia_codec_amrwb_framelen;
|
||||
|
||||
SID_FT = (pj_uint8_t)(setting->amr_nb? 8 : 9);
|
||||
|
||||
|
@ -533,11 +534,11 @@ static pj_status_t pack_amr(ipp_private_t *codec_data, void *pkt,
|
|||
info->frame_type = (pj_uint8_t)(info_ & 0x0F);
|
||||
info->good_quality = (pj_uint8_t)((info_ & 0x80) == 0);
|
||||
info->mode = (pj_int8_t) ((info_ >> 8) & 0x0F);
|
||||
info->STI = (pj_uint8_t)((info_ >> 5) & 1);
|
||||
|
||||
frames[nframes].buf = r + 2;
|
||||
frames[nframes].size = info->frame_type <= SID_FT ?
|
||||
pjmedia_codec_amrnb_framelen[info->frame_type] :
|
||||
0;
|
||||
framelen_tbl[info->frame_type] : 0;
|
||||
|
||||
r += frames[nframes].size + 2;
|
||||
|
||||
|
@ -1418,6 +1419,7 @@ static pj_status_t ipp_codec_encode( pjmedia_codec *codec,
|
|||
|
||||
/* Two octets for AMR frame info, 0=LSB:
|
||||
* bit 0-3 : frame type
|
||||
* bit 5 : STI flag
|
||||
* bit 6 : last frame flag
|
||||
* bit 7 : quality flag
|
||||
* bit 8-11 : mode
|
||||
|
@ -1441,6 +1443,9 @@ static pj_status_t ipp_codec_encode( pjmedia_codec *codec,
|
|||
/* Quality */
|
||||
if (out.frametype == 6 || out.frametype == 7)
|
||||
*info |= 0x80;
|
||||
/* STI */
|
||||
if (out.frametype != 1)
|
||||
*info |= 0x20;
|
||||
} else {
|
||||
/* Untransmited */
|
||||
*info = 15;
|
||||
|
|
|
@ -0,0 +1,820 @@
|
|||
/* $Id */
|
||||
/*
|
||||
* Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
|
||||
* Copyright (C) 2011 Dan Arrhenius <dan@keystream.se>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* AMR-NB codec implementation with OpenCORE AMRNB library
|
||||
*/
|
||||
#include <pjmedia-codec/g722.h>
|
||||
#include <pjmedia/codec.h>
|
||||
#include <pjmedia/errno.h>
|
||||
#include <pjmedia/endpoint.h>
|
||||
#include <pjmedia/plc.h>
|
||||
#include <pjmedia/port.h>
|
||||
#include <pjmedia/silencedet.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/log.h>
|
||||
#include <pj/pool.h>
|
||||
#include <pj/string.h>
|
||||
#include <pj/os.h>
|
||||
#include <pj/math.h>
|
||||
|
||||
#if defined(PJMEDIA_HAS_OPENCORE_AMRNB_CODEC) && \
|
||||
(PJMEDIA_HAS_OPENCORE_AMRNB_CODEC != 0)
|
||||
|
||||
#include <opencore-amrnb/interf_enc.h>
|
||||
#include <opencore-amrnb/interf_dec.h>
|
||||
#include <pjmedia-codec/amr_helper.h>
|
||||
#include <pjmedia-codec/opencore_amrnb.h>
|
||||
|
||||
#define THIS_FILE "opencore_amrnb.c"
|
||||
|
||||
/* Tracing */
|
||||
#define PJ_TRACE 0
|
||||
|
||||
#if PJ_TRACE
|
||||
# define TRACE_(expr) PJ_LOG(4,expr)
|
||||
#else
|
||||
# define TRACE_(expr)
|
||||
#endif
|
||||
|
||||
/* Use PJMEDIA PLC */
|
||||
#define USE_PJMEDIA_PLC 1
|
||||
|
||||
|
||||
|
||||
/* Prototypes for AMR-NB factory */
|
||||
static pj_status_t amr_test_alloc(pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *id );
|
||||
static pj_status_t amr_default_attr(pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *id,
|
||||
pjmedia_codec_param *attr );
|
||||
static pj_status_t amr_enum_codecs(pjmedia_codec_factory *factory,
|
||||
unsigned *count,
|
||||
pjmedia_codec_info codecs[]);
|
||||
static pj_status_t amr_alloc_codec(pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *id,
|
||||
pjmedia_codec **p_codec);
|
||||
static pj_status_t amr_dealloc_codec(pjmedia_codec_factory *factory,
|
||||
pjmedia_codec *codec );
|
||||
|
||||
/* Prototypes for AMR-NB implementation. */
|
||||
static pj_status_t amr_codec_init(pjmedia_codec *codec,
|
||||
pj_pool_t *pool );
|
||||
static pj_status_t amr_codec_open(pjmedia_codec *codec,
|
||||
pjmedia_codec_param *attr );
|
||||
static pj_status_t amr_codec_close(pjmedia_codec *codec );
|
||||
static pj_status_t amr_codec_modify(pjmedia_codec *codec,
|
||||
const pjmedia_codec_param *attr );
|
||||
static pj_status_t amr_codec_parse(pjmedia_codec *codec,
|
||||
void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_timestamp *ts,
|
||||
unsigned *frame_cnt,
|
||||
pjmedia_frame frames[]);
|
||||
static pj_status_t amr_codec_encode(pjmedia_codec *codec,
|
||||
const struct pjmedia_frame *input,
|
||||
unsigned output_buf_len,
|
||||
struct pjmedia_frame *output);
|
||||
static pj_status_t amr_codec_decode(pjmedia_codec *codec,
|
||||
const struct pjmedia_frame *input,
|
||||
unsigned output_buf_len,
|
||||
struct pjmedia_frame *output);
|
||||
static pj_status_t amr_codec_recover(pjmedia_codec *codec,
|
||||
unsigned output_buf_len,
|
||||
struct pjmedia_frame *output);
|
||||
|
||||
|
||||
|
||||
/* Definition for AMR-NB codec operations. */
|
||||
static pjmedia_codec_op amr_op =
|
||||
{
|
||||
&amr_codec_init,
|
||||
&amr_codec_open,
|
||||
&amr_codec_close,
|
||||
&amr_codec_modify,
|
||||
&amr_codec_parse,
|
||||
&amr_codec_encode,
|
||||
&amr_codec_decode,
|
||||
&amr_codec_recover
|
||||
};
|
||||
|
||||
/* Definition for AMR-NB codec factory operations. */
|
||||
static pjmedia_codec_factory_op amr_factory_op =
|
||||
{
|
||||
&amr_test_alloc,
|
||||
&amr_default_attr,
|
||||
&amr_enum_codecs,
|
||||
&amr_alloc_codec,
|
||||
&amr_dealloc_codec
|
||||
};
|
||||
|
||||
|
||||
/* AMR-NB factory */
|
||||
static struct amr_codec_factory
|
||||
{
|
||||
pjmedia_codec_factory base;
|
||||
pjmedia_endpt *endpt;
|
||||
pj_pool_t *pool;
|
||||
} amr_codec_factory;
|
||||
|
||||
|
||||
/* AMR-NB codec private data. */
|
||||
struct amr_data
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
void *encoder;
|
||||
void *decoder;
|
||||
pj_bool_t plc_enabled;
|
||||
pj_bool_t vad_enabled;
|
||||
int enc_mode;
|
||||
pjmedia_codec_amr_pack_setting enc_setting;
|
||||
pjmedia_codec_amr_pack_setting dec_setting;
|
||||
#if USE_PJMEDIA_PLC
|
||||
pjmedia_plc *plc;
|
||||
#endif
|
||||
pj_timestamp last_tx;
|
||||
};
|
||||
|
||||
static pjmedia_codec_amrnb_config def_config =
|
||||
{
|
||||
PJ_FALSE, /* octet align */
|
||||
5900 /* bitrate */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Initialize and register AMR-NB codec factory to pjmedia endpoint.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_init( pjmedia_endpt *endpt )
|
||||
{
|
||||
pjmedia_codec_mgr *codec_mgr;
|
||||
pj_status_t status;
|
||||
|
||||
if (amr_codec_factory.pool != NULL)
|
||||
return PJ_SUCCESS;
|
||||
|
||||
/* Create AMR-NB codec factory. */
|
||||
amr_codec_factory.base.op = &amr_factory_op;
|
||||
amr_codec_factory.base.factory_data = NULL;
|
||||
amr_codec_factory.endpt = endpt;
|
||||
|
||||
amr_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "amrnb", 1000,
|
||||
1000);
|
||||
if (!amr_codec_factory.pool)
|
||||
return PJ_ENOMEM;
|
||||
|
||||
/* 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,
|
||||
&amr_codec_factory.base);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Done. */
|
||||
return PJ_SUCCESS;
|
||||
|
||||
on_error:
|
||||
pj_pool_release(amr_codec_factory.pool);
|
||||
amr_codec_factory.pool = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unregister AMR-NB codec factory from pjmedia endpoint and deinitialize
|
||||
* the AMR-NB codec library.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_deinit(void)
|
||||
{
|
||||
pjmedia_codec_mgr *codec_mgr;
|
||||
pj_status_t status;
|
||||
|
||||
if (amr_codec_factory.pool == NULL)
|
||||
return PJ_SUCCESS;
|
||||
|
||||
/* Get the codec manager. */
|
||||
codec_mgr = pjmedia_endpt_get_codec_mgr(amr_codec_factory.endpt);
|
||||
if (!codec_mgr) {
|
||||
pj_pool_release(amr_codec_factory.pool);
|
||||
amr_codec_factory.pool = NULL;
|
||||
return PJ_EINVALIDOP;
|
||||
}
|
||||
|
||||
/* Unregister AMR-NB codec factory. */
|
||||
status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
|
||||
&amr_codec_factory.base);
|
||||
|
||||
/* Destroy pool. */
|
||||
pj_pool_release(amr_codec_factory.pool);
|
||||
amr_codec_factory.pool = NULL;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_set_config(
|
||||
const pjmedia_codec_amrnb_config *config)
|
||||
{
|
||||
unsigned nbitrates;
|
||||
|
||||
|
||||
def_config = *config;
|
||||
|
||||
/* Normalize bitrate. */
|
||||
nbitrates = PJ_ARRAY_SIZE(pjmedia_codec_amrnb_bitrates);
|
||||
if (def_config.bitrate < pjmedia_codec_amrnb_bitrates[0])
|
||||
def_config.bitrate = pjmedia_codec_amrnb_bitrates[0];
|
||||
else if (def_config.bitrate > pjmedia_codec_amrnb_bitrates[nbitrates-1])
|
||||
def_config.bitrate = pjmedia_codec_amrnb_bitrates[nbitrates-1];
|
||||
else
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < nbitrates; ++i) {
|
||||
if (def_config.bitrate <= pjmedia_codec_amrnb_bitrates[i])
|
||||
break;
|
||||
}
|
||||
def_config.bitrate = pjmedia_codec_amrnb_bitrates[i];
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if factory can allocate the specified codec.
|
||||
*/
|
||||
static pj_status_t amr_test_alloc( pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *info )
|
||||
{
|
||||
PJ_UNUSED_ARG(factory);
|
||||
|
||||
/* Check payload type. */
|
||||
if (info->pt != PJMEDIA_RTP_PT_AMR)
|
||||
return PJMEDIA_CODEC_EUNSUP;
|
||||
|
||||
/* Ignore the rest, since it's static payload type. */
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate default attribute.
|
||||
*/
|
||||
static pj_status_t amr_default_attr( pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *id,
|
||||
pjmedia_codec_param *attr )
|
||||
{
|
||||
PJ_UNUSED_ARG(factory);
|
||||
PJ_UNUSED_ARG(id);
|
||||
|
||||
pj_bzero(attr, sizeof(pjmedia_codec_param));
|
||||
attr->info.clock_rate = 8000;
|
||||
attr->info.channel_cnt = 1;
|
||||
attr->info.avg_bps = def_config.bitrate;
|
||||
attr->info.max_bps = pjmedia_codec_amrnb_bitrates[7];
|
||||
attr->info.pcm_bits_per_sample = 16;
|
||||
attr->info.frm_ptime = 20;
|
||||
attr->info.pt = PJMEDIA_RTP_PT_AMR;
|
||||
|
||||
attr->setting.frm_per_pkt = 2;
|
||||
attr->setting.vad = 1;
|
||||
attr->setting.plc = 1;
|
||||
|
||||
if (def_config.octet_align) {
|
||||
attr->setting.dec_fmtp.cnt = 1;
|
||||
attr->setting.dec_fmtp.param[0].name = pj_str("octet-align");
|
||||
attr->setting.dec_fmtp.param[0].val = pj_str("1");
|
||||
}
|
||||
|
||||
/* Default all other flag bits disabled. */
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Enum codecs supported by this factory (i.e. only AMR-NB!).
|
||||
*/
|
||||
static pj_status_t amr_enum_codecs( pjmedia_codec_factory *factory,
|
||||
unsigned *count,
|
||||
pjmedia_codec_info codecs[])
|
||||
{
|
||||
PJ_UNUSED_ARG(factory);
|
||||
PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
|
||||
|
||||
pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
|
||||
codecs[0].encoding_name = pj_str("AMR");
|
||||
codecs[0].pt = PJMEDIA_RTP_PT_AMR;
|
||||
codecs[0].type = PJMEDIA_TYPE_AUDIO;
|
||||
codecs[0].clock_rate = 8000;
|
||||
codecs[0].channel_cnt = 1;
|
||||
|
||||
*count = 1;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate a new AMR-NB codec instance.
|
||||
*/
|
||||
static pj_status_t amr_alloc_codec( pjmedia_codec_factory *factory,
|
||||
const pjmedia_codec_info *id,
|
||||
pjmedia_codec **p_codec)
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
pjmedia_codec *codec;
|
||||
struct amr_data *amr_data;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(factory == &amr_codec_factory.base, PJ_EINVAL);
|
||||
|
||||
pool = pjmedia_endpt_create_pool(amr_codec_factory.endpt, "amrnb-inst",
|
||||
512, 512);
|
||||
|
||||
codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
|
||||
PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
|
||||
codec->op = &amr_op;
|
||||
codec->factory = factory;
|
||||
|
||||
amr_data = PJ_POOL_ZALLOC_T(pool, struct amr_data);
|
||||
codec->codec_data = amr_data;
|
||||
amr_data->pool = pool;
|
||||
|
||||
#if USE_PJMEDIA_PLC
|
||||
/* Create PLC */
|
||||
status = pjmedia_plc_create(pool, 8000, 160, 0, &amr_data->plc);
|
||||
if (status != PJ_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
#else
|
||||
PJ_UNUSED_ARG(status);
|
||||
#endif
|
||||
*p_codec = codec;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free codec.
|
||||
*/
|
||||
static pj_status_t amr_dealloc_codec( pjmedia_codec_factory *factory,
|
||||
pjmedia_codec *codec )
|
||||
{
|
||||
struct amr_data *amr_data;
|
||||
|
||||
PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(factory == &amr_codec_factory.base, PJ_EINVAL);
|
||||
|
||||
amr_data = (struct amr_data*) codec->codec_data;
|
||||
|
||||
/* Close codec, if it's not closed. */
|
||||
amr_codec_close(codec);
|
||||
|
||||
pj_pool_release(amr_data->pool);
|
||||
amr_data = NULL;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Init codec.
|
||||
*/
|
||||
static pj_status_t amr_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 amr_codec_open( pjmedia_codec *codec,
|
||||
pjmedia_codec_param *attr )
|
||||
{
|
||||
struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
|
||||
pjmedia_codec_amr_pack_setting *setting;
|
||||
unsigned i;
|
||||
pj_uint8_t octet_align = 0;
|
||||
pj_int8_t enc_mode;
|
||||
const pj_str_t STR_FMTP_OCTET_ALIGN = {"octet-align", 11};
|
||||
|
||||
PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(amr_data != NULL, PJ_EINVALIDOP);
|
||||
|
||||
enc_mode = pjmedia_codec_amr_get_mode(attr->info.avg_bps);
|
||||
pj_assert(enc_mode >= 0 && enc_mode <= 7);
|
||||
|
||||
/* Check octet-align */
|
||||
for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
|
||||
if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name,
|
||||
&STR_FMTP_OCTET_ALIGN) == 0)
|
||||
{
|
||||
octet_align = (pj_uint8_t)
|
||||
(pj_strtoul(&attr->setting.dec_fmtp.param[i].val));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check mode-set */
|
||||
for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
|
||||
const pj_str_t STR_FMTP_MODE_SET = {"mode-set", 8};
|
||||
|
||||
if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name,
|
||||
&STR_FMTP_MODE_SET) == 0)
|
||||
{
|
||||
const char *p;
|
||||
pj_size_t l;
|
||||
pj_int8_t diff = 99;
|
||||
|
||||
/* Encoding mode is chosen based on local default mode setting:
|
||||
* - if local default mode is included in the mode-set, use it
|
||||
* - otherwise, find the closest mode to local default mode;
|
||||
* if there are two closest modes, prefer to use the higher
|
||||
* one, e.g: local default mode is 4, the mode-set param
|
||||
* contains '2,3,5,6', then 5 will be chosen.
|
||||
*/
|
||||
p = pj_strbuf(&attr->setting.enc_fmtp.param[i].val);
|
||||
l = pj_strlen(&attr->setting.enc_fmtp.param[i].val);
|
||||
while (l--) {
|
||||
if (*p>='0' && *p<='7') {
|
||||
pj_int8_t tmp = *p - '0' - enc_mode;
|
||||
|
||||
if (PJ_ABS(diff) > PJ_ABS(tmp) ||
|
||||
(PJ_ABS(diff) == PJ_ABS(tmp) && tmp > diff))
|
||||
{
|
||||
diff = tmp;
|
||||
if (diff == 0) break;
|
||||
}
|
||||
}
|
||||
++p;
|
||||
}
|
||||
PJ_ASSERT_RETURN(diff != 99, PJMEDIA_CODEC_EFAILED);
|
||||
|
||||
enc_mode = enc_mode + diff;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
amr_data->vad_enabled = (attr->setting.vad != 0);
|
||||
amr_data->plc_enabled = (attr->setting.plc != 0);
|
||||
amr_data->enc_mode = enc_mode;
|
||||
|
||||
amr_data->encoder = Encoder_Interface_init(amr_data->vad_enabled);
|
||||
if (amr_data->encoder == NULL) {
|
||||
TRACE_((THIS_FILE, "Encoder_Interface_init() failed"));
|
||||
amr_codec_close(codec);
|
||||
return PJMEDIA_CODEC_EFAILED;
|
||||
}
|
||||
setting = &amr_data->enc_setting;
|
||||
pj_bzero(setting, sizeof(pjmedia_codec_amr_pack_setting));
|
||||
setting->amr_nb = 1;
|
||||
setting->reorder = 0;
|
||||
setting->octet_aligned = octet_align;
|
||||
setting->cmr = 15;
|
||||
|
||||
amr_data->decoder = Decoder_Interface_init();
|
||||
if (amr_data->decoder == NULL) {
|
||||
TRACE_((THIS_FILE, "Decoder_Interface_init() failed"));
|
||||
amr_codec_close(codec);
|
||||
return PJMEDIA_CODEC_EFAILED;
|
||||
}
|
||||
setting = &amr_data->dec_setting;
|
||||
pj_bzero(setting, sizeof(pjmedia_codec_amr_pack_setting));
|
||||
setting->amr_nb = 1;
|
||||
setting->reorder = 0;
|
||||
setting->octet_aligned = octet_align;
|
||||
|
||||
TRACE_((THIS_FILE, "AMR-NB codec allocated: vad=%d, plc=%d, bitrate=%d",
|
||||
amr_data->vad_enabled, amr_data->plc_enabled,
|
||||
pjmedia_codec_amrnb_bitrates[amr_data->enc_mode]));
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Close codec.
|
||||
*/
|
||||
static pj_status_t amr_codec_close( pjmedia_codec *codec )
|
||||
{
|
||||
struct amr_data *amr_data;
|
||||
|
||||
PJ_ASSERT_RETURN(codec, PJ_EINVAL);
|
||||
|
||||
amr_data = (struct amr_data*) codec->codec_data;
|
||||
PJ_ASSERT_RETURN(amr_data != NULL, PJ_EINVALIDOP);
|
||||
|
||||
if (amr_data->encoder) {
|
||||
Encoder_Interface_exit(amr_data->encoder);
|
||||
amr_data->encoder = NULL;
|
||||
}
|
||||
|
||||
if (amr_data->decoder) {
|
||||
Decoder_Interface_exit(amr_data->decoder);
|
||||
amr_data->decoder = NULL;
|
||||
}
|
||||
|
||||
TRACE_((THIS_FILE, "AMR-NB codec closed"));
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Modify codec settings.
|
||||
*/
|
||||
static pj_status_t amr_codec_modify( pjmedia_codec *codec,
|
||||
const pjmedia_codec_param *attr )
|
||||
{
|
||||
struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
|
||||
pj_bool_t prev_vad_state;
|
||||
|
||||
pj_assert(amr_data != NULL);
|
||||
pj_assert(amr_data->encoder != NULL && amr_data->decoder != NULL);
|
||||
|
||||
prev_vad_state = amr_data->vad_enabled;
|
||||
amr_data->vad_enabled = (attr->setting.vad != 0);
|
||||
amr_data->plc_enabled = (attr->setting.plc != 0);
|
||||
|
||||
if (prev_vad_state != amr_data->vad_enabled) {
|
||||
/* Reinit AMR encoder to update VAD setting */
|
||||
TRACE_((THIS_FILE, "Reiniting AMR encoder to update VAD setting."));
|
||||
Encoder_Interface_exit(amr_data->encoder);
|
||||
amr_data->encoder = Encoder_Interface_init(amr_data->vad_enabled);
|
||||
if (amr_data->encoder == NULL) {
|
||||
TRACE_((THIS_FILE, "Encoder_Interface_init() failed"));
|
||||
amr_codec_close(codec);
|
||||
return PJMEDIA_CODEC_EFAILED;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_((THIS_FILE, "AMR-NB codec modified: vad=%d, plc=%d",
|
||||
amr_data->vad_enabled, amr_data->plc_enabled));
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get frames in the packet.
|
||||
*/
|
||||
static pj_status_t amr_codec_parse( pjmedia_codec *codec,
|
||||
void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_timestamp *ts,
|
||||
unsigned *frame_cnt,
|
||||
pjmedia_frame frames[])
|
||||
{
|
||||
struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
|
||||
pj_uint8_t cmr;
|
||||
pj_status_t status;
|
||||
|
||||
status = pjmedia_codec_amr_parse(pkt, pkt_size, ts, &amr_data->dec_setting,
|
||||
frames, frame_cnt, &cmr);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Check for Change Mode Request. */
|
||||
if (cmr <= 7 && amr_data->enc_mode != cmr) {
|
||||
amr_data->enc_mode = cmr;
|
||||
TRACE_((THIS_FILE, "AMR-NB encoder switched mode to %d (%dbps)",
|
||||
amr_data->enc_mode,
|
||||
pjmedia_codec_amrnb_bitrates[amr_data->enc_mode]));
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Encode frame.
|
||||
*/
|
||||
static pj_status_t amr_codec_encode( pjmedia_codec *codec,
|
||||
const struct pjmedia_frame *input,
|
||||
unsigned output_buf_len,
|
||||
struct pjmedia_frame *output)
|
||||
{
|
||||
struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
|
||||
unsigned char *bitstream;
|
||||
pj_int16_t *speech;
|
||||
unsigned nsamples, samples_per_frame;
|
||||
enum {MAX_FRAMES_PER_PACKET = 16};
|
||||
pjmedia_frame frames[MAX_FRAMES_PER_PACKET];
|
||||
pj_uint8_t *p;
|
||||
unsigned i, out_size = 0, nframes = 0;
|
||||
pj_size_t payload_len;
|
||||
unsigned dtx_cnt, sid_cnt;
|
||||
pj_status_t status;
|
||||
int size;
|
||||
|
||||
pj_assert(amr_data != NULL);
|
||||
PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
|
||||
|
||||
nsamples = input->size >> 1;
|
||||
samples_per_frame = 160;
|
||||
PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0,
|
||||
PJMEDIA_CODEC_EPCMFRMINLEN);
|
||||
|
||||
nframes = nsamples / samples_per_frame;
|
||||
PJ_ASSERT_RETURN(nframes <= MAX_FRAMES_PER_PACKET,
|
||||
PJMEDIA_CODEC_EFRMTOOSHORT);
|
||||
|
||||
/* Encode the frames */
|
||||
speech = (pj_int16_t*)input->buf;
|
||||
bitstream = (unsigned char*)output->buf;
|
||||
while (nsamples >= samples_per_frame) {
|
||||
size = Encoder_Interface_Encode (amr_data->encoder, amr_data->enc_mode,
|
||||
speech, bitstream, 0);
|
||||
if (size == 0) {
|
||||
output->size = 0;
|
||||
output->buf = NULL;
|
||||
output->type = PJMEDIA_FRAME_TYPE_NONE;
|
||||
TRACE_((THIS_FILE, "AMR-NB encode() failed"));
|
||||
return PJMEDIA_CODEC_EFAILED;
|
||||
}
|
||||
nsamples -= 160;
|
||||
speech += samples_per_frame;
|
||||
bitstream += size;
|
||||
out_size += size;
|
||||
TRACE_((THIS_FILE, "AMR-NB encode(): mode=%d, size=%d",
|
||||
amr_data->enc_mode, out_size));
|
||||
}
|
||||
|
||||
/* Pack payload */
|
||||
p = (pj_uint8_t*)output->buf + output_buf_len - out_size;
|
||||
pj_memmove(p, output->buf, out_size);
|
||||
dtx_cnt = sid_cnt = 0;
|
||||
for (i = 0; i < nframes; ++i) {
|
||||
pjmedia_codec_amr_bit_info *info = (pjmedia_codec_amr_bit_info*)
|
||||
&frames[i].bit_info;
|
||||
info->frame_type = (pj_uint8_t)((*p >> 3) & 0x0F);
|
||||
info->good_quality = (pj_uint8_t)((*p >> 2) & 0x01);
|
||||
info->mode = (pj_int8_t)amr_data->enc_mode;
|
||||
info->start_bit = 0;
|
||||
frames[i].buf = p + 1;
|
||||
frames[i].size = (info->frame_type <= 8)?
|
||||
pjmedia_codec_amrnb_framelen[info->frame_type] : 0;
|
||||
p += frames[i].size + 1;
|
||||
|
||||
/* Count the number of SID and DTX frames */
|
||||
if (info->frame_type == 15) /* DTX*/
|
||||
++dtx_cnt;
|
||||
else if (info->frame_type == 8) /* SID */
|
||||
++sid_cnt;
|
||||
}
|
||||
|
||||
/* VA generates DTX frames as DTX+SID frames switching quickly and it
|
||||
* seems that the SID frames occur too often (assuming the purpose is
|
||||
* only for keeping NAT alive?). So let's modify the behavior a bit.
|
||||
* Only an SID frame will be sent every PJMEDIA_CODEC_MAX_SILENCE_PERIOD
|
||||
* milliseconds.
|
||||
*/
|
||||
if (sid_cnt + dtx_cnt == nframes) {
|
||||
pj_int32_t dtx_duration;
|
||||
|
||||
dtx_duration = pj_timestamp_diff32(&amr_data->last_tx,
|
||||
&input->timestamp);
|
||||
if (PJMEDIA_CODEC_MAX_SILENCE_PERIOD == -1 ||
|
||||
dtx_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD*8000/1000)
|
||||
{
|
||||
output->size = 0;
|
||||
output->type = PJMEDIA_FRAME_TYPE_NONE;
|
||||
output->timestamp = input->timestamp;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
payload_len = output_buf_len;
|
||||
|
||||
status = pjmedia_codec_amr_pack(frames, nframes, &amr_data->enc_setting,
|
||||
output->buf, &payload_len);
|
||||
if (status != PJ_SUCCESS) {
|
||||
output->size = 0;
|
||||
output->buf = NULL;
|
||||
output->type = PJMEDIA_FRAME_TYPE_NONE;
|
||||
TRACE_((THIS_FILE, "Failed to pack AMR payload, status=%d", status));
|
||||
return status;
|
||||
}
|
||||
|
||||
output->size = payload_len;
|
||||
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
output->timestamp = input->timestamp;
|
||||
|
||||
amr_data->last_tx = input->timestamp;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Decode frame.
|
||||
*/
|
||||
static pj_status_t amr_codec_decode( pjmedia_codec *codec,
|
||||
const struct pjmedia_frame *input,
|
||||
unsigned output_buf_len,
|
||||
struct pjmedia_frame *output)
|
||||
{
|
||||
struct amr_data *amr_data = (struct amr_data*) codec->codec_data;
|
||||
pjmedia_frame input_;
|
||||
pjmedia_codec_amr_bit_info *info;
|
||||
/* VA AMR-NB decoding buffer: AMR-NB max frame size + 1 byte header. */
|
||||
unsigned char bitstream[32];
|
||||
|
||||
pj_assert(amr_data != NULL);
|
||||
PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
|
||||
|
||||
if (output_buf_len < 320)
|
||||
return PJMEDIA_CODEC_EPCMTOOSHORT;
|
||||
|
||||
input_.buf = &bitstream[1];
|
||||
input_.size = 31; /* AMR-NB max frame size */
|
||||
pjmedia_codec_amr_predecode(input, &amr_data->dec_setting, &input_);
|
||||
info = (pjmedia_codec_amr_bit_info*)&input_.bit_info;
|
||||
|
||||
/* VA AMRNB decoder requires frame info in the first byte. */
|
||||
bitstream[0] = (info->frame_type << 3) | (info->good_quality << 2);
|
||||
|
||||
TRACE_((THIS_FILE, "AMR-NB decode(): mode=%d, ft=%d, size=%d",
|
||||
info->mode, info->frame_type, input_.size));
|
||||
|
||||
/* Decode */
|
||||
Decoder_Interface_Decode(amr_data->decoder, bitstream,
|
||||
(pj_int16_t*)output->buf, 0);
|
||||
|
||||
output->size = 320;
|
||||
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
output->timestamp = input->timestamp;
|
||||
|
||||
#if USE_PJMEDIA_PLC
|
||||
if (amr_data->plc_enabled)
|
||||
pjmedia_plc_save(amr_data->plc, (pj_int16_t*)output->buf);
|
||||
#endif
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Recover lost frame.
|
||||
*/
|
||||
#if USE_PJMEDIA_PLC
|
||||
/*
|
||||
* Recover lost frame.
|
||||
*/
|
||||
static pj_status_t amr_codec_recover( pjmedia_codec *codec,
|
||||
unsigned output_buf_len,
|
||||
struct pjmedia_frame *output)
|
||||
{
|
||||
struct amr_data *amr_data = codec->codec_data;
|
||||
|
||||
TRACE_((THIS_FILE, "amr_codec_recover"));
|
||||
|
||||
PJ_ASSERT_RETURN(amr_data->plc_enabled, PJ_EINVALIDOP);
|
||||
|
||||
PJ_ASSERT_RETURN(output_buf_len >= 320, PJMEDIA_CODEC_EPCMTOOSHORT);
|
||||
|
||||
pjmedia_plc_generate(amr_data->plc, (pj_int16_t*)output->buf);
|
||||
|
||||
output->size = 320;
|
||||
output->type = PJMEDIA_FRAME_TYPE_AUDIO;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && PJMEDIA_AUTO_LINK_OPENCORE_AMR_LIBS
|
||||
# if PJMEDIA_OPENCORE_AMR_BUILT_WITH_GCC
|
||||
# pragma comment( lib, "libopencore-amrnb.a")
|
||||
# else
|
||||
# error Unsupported OpenCORE AMR library, fix here
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -259,13 +259,16 @@ static pj_status_t pack_amr ( codec_private_t *codec_data,
|
|||
pj_bzero(info, sizeof(*info));
|
||||
|
||||
if (len == 0) {
|
||||
info->frame_type = (pj_uint8_t)(enc_setting->amr_nb? 14 : 15);
|
||||
/* DTX */
|
||||
info->frame_type = 15;
|
||||
} else {
|
||||
info->frame_type = pjmedia_codec_amr_get_mode2(enc_setting->amr_nb,
|
||||
len);
|
||||
}
|
||||
info->good_quality = 1;
|
||||
info->mode = setting->enc_mode;
|
||||
if (info->frame_type == SID_FT)
|
||||
info->STI = (sf->data[4] >> 4) & 1;
|
||||
|
||||
frames[i].buf = sf->data;
|
||||
frames[i].size = len;
|
||||
|
|
|
@ -128,6 +128,12 @@ PJ_DEF(pj_uint8_t) pjmedia_linear2alaw(
|
|||
} else {
|
||||
mask = 0x55; /* sign bit = 0 */
|
||||
pcm_val = -pcm_val - 8;
|
||||
|
||||
/* https://trac.pjsip.org/repos/ticket/1301
|
||||
* Thank you K Johnson - Zetron - 27 May 2011
|
||||
*/
|
||||
if (pcm_val < 0)
|
||||
pcm_val = 0;
|
||||
}
|
||||
|
||||
/* Convert the scaled magnitude to segment number. */
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
struct pjmedia_clock
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
pj_timestamp freq;
|
||||
pj_timestamp interval;
|
||||
pj_timestamp next_tick;
|
||||
|
@ -70,8 +71,8 @@ PJ_DEF(pj_status_t) pjmedia_clock_create( pj_pool_t *pool,
|
|||
PJ_EINVAL);
|
||||
|
||||
clock = PJ_POOL_ALLOC_T(pool, pjmedia_clock);
|
||||
clock->pool = pj_pool_create(pool->factory, "clock%p", 512, 512, NULL);
|
||||
|
||||
|
||||
status = pj_get_timestamp_freq(&clock->freq);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
@ -94,16 +95,6 @@ PJ_DEF(pj_status_t) pjmedia_clock_create( pj_pool_t *pool,
|
|||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
if ((clock->options & PJMEDIA_CLOCK_NO_ASYNC) == 0) {
|
||||
status = pj_thread_create(pool, "clock", &clock_thread, clock,
|
||||
0, 0, &clock->thread);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_lock_destroy(clock->lock);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*p_clock = clock;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
@ -127,12 +118,20 @@ PJ_DEF(pj_status_t) pjmedia_clock_start(pjmedia_clock *clock)
|
|||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
pj_lock_acquire(clock->lock);
|
||||
clock->next_tick.u64 = now.u64 + clock->interval.u64;
|
||||
clock->running = PJ_TRUE;
|
||||
pj_lock_release(clock->lock);
|
||||
clock->quitting = PJ_FALSE;
|
||||
|
||||
return status;
|
||||
if ((clock->options & PJMEDIA_CLOCK_NO_ASYNC) == 0 && !clock->thread) {
|
||||
status = pj_thread_create(clock->pool, "clock", &clock_thread, clock,
|
||||
0, 0, &clock->thread);
|
||||
if (status != PJ_SUCCESS) {
|
||||
clock->running = PJ_FALSE;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -144,6 +143,17 @@ PJ_DEF(pj_status_t) pjmedia_clock_stop(pjmedia_clock *clock)
|
|||
PJ_ASSERT_RETURN(clock != NULL, PJ_EINVAL);
|
||||
|
||||
clock->running = PJ_FALSE;
|
||||
clock->quitting = PJ_TRUE;
|
||||
|
||||
if (clock->thread) {
|
||||
if (pj_thread_join(clock->thread) == PJ_SUCCESS) {
|
||||
pj_thread_destroy(clock->thread);
|
||||
clock->thread = NULL;
|
||||
pj_pool_reset(clock->pool);
|
||||
} else {
|
||||
clock->quitting = PJ_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
@ -254,6 +264,10 @@ static int clock_thread(void *arg)
|
|||
if (clock->cb)
|
||||
(*clock->cb)(&clock->timestamp, clock->user_data);
|
||||
|
||||
/* Best effort way to detect if we've been destroyed in the callback */
|
||||
if (clock->quitting)
|
||||
break;
|
||||
|
||||
/* Increment timestamp */
|
||||
clock->timestamp.u64 += clock->timestamp_inc;
|
||||
|
||||
|
@ -288,6 +302,11 @@ PJ_DEF(pj_status_t) pjmedia_clock_destroy(pjmedia_clock *clock)
|
|||
clock->lock = NULL;
|
||||
}
|
||||
|
||||
if (clock->pool) {
|
||||
pj_pool_t *pool = clock->pool;
|
||||
clock->pool = NULL;
|
||||
pj_pool_release(pool);
|
||||
}
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,39 @@ struct pjmedia_codec_default_param
|
|||
static void sort_codecs(pjmedia_codec_mgr *mgr);
|
||||
|
||||
|
||||
/*
|
||||
* Duplicate codec parameter.
|
||||
*/
|
||||
PJ_DEF(pjmedia_codec_param*) pjmedia_codec_param_clone(
|
||||
pj_pool_t *pool,
|
||||
const pjmedia_codec_param *src)
|
||||
{
|
||||
pjmedia_codec_param *p;
|
||||
unsigned i;
|
||||
|
||||
PJ_ASSERT_RETURN(pool && src, NULL);
|
||||
|
||||
p = PJ_POOL_ZALLOC_T(pool, pjmedia_codec_param);
|
||||
|
||||
/* Update codec param */
|
||||
pj_memcpy(p, src, sizeof(pjmedia_codec_param));
|
||||
for (i = 0; i < src->setting.dec_fmtp.cnt; ++i) {
|
||||
pj_strdup(pool, &p->setting.dec_fmtp.param[i].name,
|
||||
&src->setting.dec_fmtp.param[i].name);
|
||||
pj_strdup(pool, &p->setting.dec_fmtp.param[i].val,
|
||||
&src->setting.dec_fmtp.param[i].val);
|
||||
}
|
||||
for (i = 0; i < src->setting.enc_fmtp.cnt; ++i) {
|
||||
pj_strdup(pool, &p->setting.enc_fmtp.param[i].name,
|
||||
&src->setting.enc_fmtp.param[i].name);
|
||||
pj_strdup(pool, &p->setting.enc_fmtp.param[i].val,
|
||||
&src->setting.enc_fmtp.param[i].val);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize codec manager.
|
||||
*/
|
||||
|
|
|
@ -540,7 +540,7 @@ PJ_DEF(pj_status_t) pjmedia_conf_connect_port( pjmedia_conf *conf,
|
|||
/* Channel count must match. */
|
||||
if (src_port->info->channel_count != dst_port->info->channel_count) {
|
||||
pj_mutex_unlock(conf->mutex);
|
||||
return PJMEDIA_ENCCLOCKRATE;
|
||||
return PJMEDIA_ENCCHANNEL;
|
||||
}
|
||||
|
||||
/* Source and sink ptime must be equal or a multiplication factor. */
|
||||
|
@ -1073,11 +1073,14 @@ static pj_status_t write_frame(struct conf_port *cport_dst,
|
|||
while (f_start < f_end) {
|
||||
unsigned nsamples_to_copy, nsamples_req;
|
||||
|
||||
/* Copy frame to listener's TX buffer. */
|
||||
/* Copy frame to listener's TX buffer.
|
||||
* Note that if the destination is port 0, just copy the whole
|
||||
* available samples.
|
||||
*/
|
||||
nsamples_to_copy = f_end - f_start;
|
||||
nsamples_req = cport_dst->info->samples_per_frame -
|
||||
(frm_dst->size>>1);
|
||||
if (nsamples_to_copy > nsamples_req)
|
||||
if (cport_dst->slot && nsamples_to_copy > nsamples_req)
|
||||
nsamples_to_copy = nsamples_req;
|
||||
|
||||
/* Adjust TX level. */
|
||||
|
@ -1110,16 +1113,19 @@ static pj_status_t write_frame(struct conf_port *cport_dst,
|
|||
|
||||
/* Check if it's time to deliver the TX buffer to listener,
|
||||
* i.e: samples count in TX buffer equal to listener's
|
||||
* samples per frame.
|
||||
* samples per frame. Note that for destination port 0 this
|
||||
* function will just populate all samples in the TX buffer.
|
||||
*/
|
||||
if ((frm_dst->size >> 1) == cport_dst->info->samples_per_frame)
|
||||
if (cport_dst->slot == 0) {
|
||||
/* Update TX timestamp. */
|
||||
pj_add_timestamp32(&cport_dst->ts_tx, nsamples_to_copy);
|
||||
} else if ((frm_dst->size >> 1) ==
|
||||
cport_dst->info->samples_per_frame)
|
||||
{
|
||||
if (cport_dst->slot) {
|
||||
pjmedia_port_put_frame(cport_dst->port, frm_dst);
|
||||
pjmedia_port_put_frame(cport_dst->port, frm_dst);
|
||||
|
||||
/* Reset TX buffer. */
|
||||
frm_dst->size = 0;
|
||||
}
|
||||
/* Reset TX buffer. */
|
||||
frm_dst->size = 0;
|
||||
|
||||
/* Update TX timestamp. */
|
||||
pj_add_timestamp32(&cport_dst->ts_tx,
|
||||
|
|
|
@ -1800,13 +1800,16 @@ static pj_status_t get_frame(pjmedia_port *this_port,
|
|||
for (i=0, ci=0; i<conf->max_ports && ci < conf->port_cnt; ++i) {
|
||||
struct conf_port *conf_port = conf->ports[i];
|
||||
|
||||
/* Skip empty slot. */
|
||||
/* Skip empty port. */
|
||||
if (!conf_port)
|
||||
continue;
|
||||
|
||||
/* Var "ci" is to count how many ports have been visited so far. */
|
||||
++ci;
|
||||
|
||||
/* Reset buffer & auto adjustment level for mixed signal */
|
||||
/* Reset buffer (only necessary if the port has transmitter) and
|
||||
* reset auto adjustment level for mixed signal.
|
||||
*/
|
||||
conf_port->mix_adj = NORMAL_LEVEL;
|
||||
if (conf_port->transmitter_cnt) {
|
||||
pj_bzero(conf_port->mix_buf,
|
||||
|
@ -1817,7 +1820,7 @@ static pj_status_t get_frame(pjmedia_port *this_port,
|
|||
/* Get frames from all ports, and "mix" the signal
|
||||
* to mix_buf of all listeners of the port.
|
||||
*/
|
||||
for (i=0, ci=0; i<conf->max_ports && ci<conf->port_cnt; ++i) {
|
||||
for (i=0, ci=0; i < conf->max_ports && ci < conf->port_cnt; ++i) {
|
||||
struct conf_port *conf_port = conf->ports[i];
|
||||
pj_int32_t level = 0;
|
||||
|
||||
|
@ -1945,23 +1948,33 @@ static pj_status_t get_frame(pjmedia_port *this_port,
|
|||
|
||||
mix_buf = listener->mix_buf;
|
||||
|
||||
/* Mixing signals,
|
||||
* and calculate appropriate level adjustment if there is
|
||||
* any overflowed level in the mixed signal.
|
||||
*/
|
||||
for (k=0; k<conf->samples_per_frame; ++k) {
|
||||
mix_buf[k] += p_in[k];
|
||||
/* Check if normalization adjustment needed. */
|
||||
if (IS_OVERFLOW(mix_buf[k])) {
|
||||
/* NORMAL_LEVEL * MAX_LEVEL / mix_buf[k]; */
|
||||
int tmp_adj = (MAX_LEVEL<<7) / mix_buf[k];
|
||||
if (tmp_adj<0) tmp_adj = -tmp_adj;
|
||||
if (listener->transmitter_cnt > 1) {
|
||||
/* Mixing signals,
|
||||
* and calculate appropriate level adjustment if there is
|
||||
* any overflowed level in the mixed signal.
|
||||
*/
|
||||
for (k=0; k < conf->samples_per_frame; ++k) {
|
||||
mix_buf[k] += p_in[k];
|
||||
/* Check if normalization adjustment needed. */
|
||||
if (IS_OVERFLOW(mix_buf[k])) {
|
||||
/* NORMAL_LEVEL * MAX_LEVEL / mix_buf[k]; */
|
||||
int tmp_adj = (MAX_LEVEL<<7) / mix_buf[k];
|
||||
if (tmp_adj<0) tmp_adj = -tmp_adj;
|
||||
|
||||
if (tmp_adj<listener->mix_adj)
|
||||
listener->mix_adj = tmp_adj;
|
||||
if (tmp_adj<listener->mix_adj)
|
||||
listener->mix_adj = tmp_adj;
|
||||
|
||||
} /* if any overflow in the mixed signals */
|
||||
} /* loop mixing signals */
|
||||
} /* if any overflow in the mixed signals */
|
||||
} /* loop mixing signals */
|
||||
} else {
|
||||
/* Only 1 transmitter:
|
||||
* just copy the samples to the mix buffer
|
||||
* no mixing and level adjustment needed
|
||||
*/
|
||||
for (k=0; k<conf->samples_per_frame; ++k) {
|
||||
mix_buf[k] = p_in[k];
|
||||
}
|
||||
}
|
||||
} /* loop the listeners of conf port */
|
||||
} /* loop of all conf ports */
|
||||
|
||||
|
|
|
@ -99,9 +99,6 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool,
|
|||
|
||||
PJ_ASSERT_RETURN(pool && samples_per_frame && clock_rate && channel_count &&
|
||||
p_b, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(options==0, PJ_EINVAL);
|
||||
|
||||
PJ_UNUSED_ARG(options);
|
||||
|
||||
if (!name) {
|
||||
name = "delaybuf";
|
||||
|
@ -126,11 +123,16 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool,
|
|||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Create WSOLA */
|
||||
status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 1,
|
||||
PJMEDIA_WSOLA_NO_FADING, &b->wsola);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
if (!(options & PJMEDIA_DELAY_BUF_SIMPLE_FIFO)) {
|
||||
/* Create WSOLA */
|
||||
status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 1,
|
||||
PJMEDIA_WSOLA_NO_FADING, &b->wsola);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
PJ_LOG(5, (b->obj_name, "Using delay buffer with WSOLA."));
|
||||
} else {
|
||||
PJ_LOG(5, (b->obj_name, "Using simple FIFO delay buffer."));
|
||||
}
|
||||
|
||||
/* Finally, create mutex */
|
||||
status = pj_lock_create_recursive_mutex(pool, b->obj_name,
|
||||
|
@ -147,15 +149,17 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool,
|
|||
|
||||
PJ_DEF(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b)
|
||||
{
|
||||
pj_status_t status;
|
||||
pj_status_t status = PJ_SUCCESS;
|
||||
|
||||
PJ_ASSERT_RETURN(b, PJ_EINVAL);
|
||||
|
||||
pj_lock_acquire(b->lock);
|
||||
|
||||
status = pjmedia_wsola_destroy(b->wsola);
|
||||
if (status == PJ_SUCCESS)
|
||||
b->wsola = NULL;
|
||||
if (b->wsola) {
|
||||
status = pjmedia_wsola_destroy(b->wsola);
|
||||
if (status == PJ_SUCCESS)
|
||||
b->wsola = NULL;
|
||||
}
|
||||
|
||||
pj_lock_release(b->lock);
|
||||
|
||||
|
@ -264,12 +268,14 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b,
|
|||
|
||||
pj_lock_acquire(b->lock);
|
||||
|
||||
update(b, OP_PUT);
|
||||
if (b->wsola) {
|
||||
update(b, OP_PUT);
|
||||
|
||||
status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_lock_release(b->lock);
|
||||
return status;
|
||||
status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_lock_release(b->lock);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Overflow checking */
|
||||
|
@ -277,13 +283,15 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b,
|
|||
b->max_cnt)
|
||||
{
|
||||
unsigned erase_cnt;
|
||||
|
||||
/* shrink one frame or just the diff? */
|
||||
//erase_cnt = b->samples_per_frame;
|
||||
erase_cnt = pjmedia_circ_buf_get_len(b->circ_buf) +
|
||||
b->samples_per_frame - b->max_cnt;
|
||||
|
||||
shrink_buffer(b, erase_cnt);
|
||||
if (b->wsola) {
|
||||
/* shrink one frame or just the diff? */
|
||||
//erase_cnt = b->samples_per_frame;
|
||||
erase_cnt = pjmedia_circ_buf_get_len(b->circ_buf) +
|
||||
b->samples_per_frame - b->max_cnt;
|
||||
|
||||
shrink_buffer(b, erase_cnt);
|
||||
}
|
||||
|
||||
/* Check if shrinking failed or erased count is less than requested,
|
||||
* delaybuf needs to drop eldest samples, this is bad since the voice
|
||||
|
@ -297,9 +305,9 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b,
|
|||
|
||||
pjmedia_circ_buf_adv_read_ptr(b->circ_buf, erase_cnt);
|
||||
|
||||
PJ_LOG(4,(b->obj_name,"Shrinking failed or insufficient, dropping"
|
||||
" %d eldest samples, buf_cnt=%d", erase_cnt,
|
||||
pjmedia_circ_buf_get_len(b->circ_buf)));
|
||||
PJ_LOG(4,(b->obj_name,"%sDropping %d eldest samples, buf_cnt=%d",
|
||||
(b->wsola? "Shrinking failed or insufficient. ": ""),
|
||||
erase_cnt, pjmedia_circ_buf_get_len(b->circ_buf)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,13 +320,14 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b,
|
|||
PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b,
|
||||
pj_int16_t frame[])
|
||||
{
|
||||
pj_status_t status;
|
||||
pj_status_t status = PJ_SUCCESS;
|
||||
|
||||
PJ_ASSERT_RETURN(b && frame, PJ_EINVAL);
|
||||
|
||||
pj_lock_acquire(b->lock);
|
||||
|
||||
update(b, OP_GET);
|
||||
if (b->wsola)
|
||||
update(b, OP_GET);
|
||||
|
||||
/* Starvation checking */
|
||||
if (pjmedia_circ_buf_get_len(b->circ_buf) < b->samples_per_frame) {
|
||||
|
@ -326,24 +335,29 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b,
|
|||
PJ_LOG(4,(b->obj_name,"Underflow, buf_cnt=%d, will generate 1 frame",
|
||||
pjmedia_circ_buf_get_len(b->circ_buf)));
|
||||
|
||||
status = pjmedia_wsola_generate(b->wsola, frame);
|
||||
if (b->wsola) {
|
||||
status = pjmedia_wsola_generate(b->wsola, frame);
|
||||
|
||||
if (status == PJ_SUCCESS) {
|
||||
TRACE__((b->obj_name,"Successfully generate 1 frame"));
|
||||
if (pjmedia_circ_buf_get_len(b->circ_buf) == 0) {
|
||||
pj_lock_release(b->lock);
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
if (status == PJ_SUCCESS) {
|
||||
TRACE__((b->obj_name,"Successfully generate 1 frame"));
|
||||
if (pjmedia_circ_buf_get_len(b->circ_buf) == 0) {
|
||||
pj_lock_release(b->lock);
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Put generated frame into buffer */
|
||||
pjmedia_circ_buf_write(b->circ_buf, frame, b->samples_per_frame);
|
||||
/* Put generated frame into buffer */
|
||||
pjmedia_circ_buf_write(b->circ_buf, frame,
|
||||
b->samples_per_frame);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!b->wsola || status != PJ_SUCCESS) {
|
||||
unsigned buf_len = pjmedia_circ_buf_get_len(b->circ_buf);
|
||||
|
||||
/* Give all what delay buffer has, then pad with zeroes */
|
||||
PJ_LOG(4,(b->obj_name,"Error generating frame, status=%d",
|
||||
status));
|
||||
if (b->wsola)
|
||||
PJ_LOG(4,(b->obj_name,"Error generating frame, status=%d",
|
||||
status));
|
||||
|
||||
pjmedia_circ_buf_read(b->circ_buf, frame, buf_len);
|
||||
pjmedia_zero_samples(&frame[buf_len],
|
||||
|
@ -378,7 +392,8 @@ PJ_DEF(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b)
|
|||
pjmedia_circ_buf_reset(b->circ_buf);
|
||||
|
||||
/* Reset WSOLA */
|
||||
pjmedia_wsola_reset(b->wsola, 0);
|
||||
if (b->wsola)
|
||||
pjmedia_wsola_reset(b->wsola, 0);
|
||||
|
||||
pj_lock_release(b->lock);
|
||||
|
||||
|
|
|
@ -144,6 +144,7 @@ PJ_DEF(pj_status_t) pjmedia_echo_create2(pj_pool_t *pool,
|
|||
pjmedia_echo_state **p_echo )
|
||||
{
|
||||
unsigned ptime, lat_cnt;
|
||||
unsigned delay_buf_opt = 0;
|
||||
pjmedia_echo_state *ec;
|
||||
pj_status_t status;
|
||||
|
||||
|
@ -211,10 +212,12 @@ PJ_DEF(pj_status_t) pjmedia_echo_create2(pj_pool_t *pool,
|
|||
}
|
||||
|
||||
/* Create delay buffer to compensate drifts */
|
||||
if (options & PJMEDIA_ECHO_USE_SIMPLE_FIFO)
|
||||
delay_buf_opt |= PJMEDIA_DELAY_BUF_SIMPLE_FIFO;
|
||||
status = pjmedia_delay_buf_create(ec->pool, ec->obj_name, clock_rate,
|
||||
samples_per_frame, channel_count,
|
||||
(PJMEDIA_SOUND_BUFFER_COUNT+1) * ptime,
|
||||
0, &ec->delay_buf);
|
||||
delay_buf_opt, &ec->delay_buf);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_pool_release(pool);
|
||||
return status;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <pjmedia-audiodev/audiodev.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/ioqueue.h>
|
||||
#include <pj/lock.h>
|
||||
#include <pj/log.h>
|
||||
#include <pj/os.h>
|
||||
#include <pj/pool.h>
|
||||
|
@ -56,6 +57,14 @@ static int PJ_THREAD_FUNC worker_proc(void*);
|
|||
#define MAX_THREADS 16
|
||||
|
||||
|
||||
/* List of media endpoint exit callback. */
|
||||
typedef struct exit_cb
|
||||
{
|
||||
PJ_DECL_LIST_MEMBER (struct exit_cb);
|
||||
pjmedia_endpt_exit_callback func;
|
||||
} exit_cb;
|
||||
|
||||
|
||||
/** Concrete declaration of media endpoint. */
|
||||
struct pjmedia_endpt
|
||||
{
|
||||
|
@ -85,6 +94,9 @@ struct pjmedia_endpt
|
|||
|
||||
/** Is telephone-event enable */
|
||||
pj_bool_t has_telephone_event;
|
||||
|
||||
/** List of exit callback. */
|
||||
exit_cb exit_cb_list;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -128,6 +140,9 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create(pj_pool_factory *pf,
|
|||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Initialize exit callback list. */
|
||||
pj_list_init(&endpt->exit_cb_list);
|
||||
|
||||
/* Create ioqueue if none is specified. */
|
||||
if (endpt->ioqueue == NULL) {
|
||||
|
||||
|
@ -188,6 +203,7 @@ PJ_DEF(pjmedia_codec_mgr*) pjmedia_endpt_get_codec_mgr(pjmedia_endpt *endpt)
|
|||
*/
|
||||
PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt)
|
||||
{
|
||||
exit_cb *ecb;
|
||||
unsigned i;
|
||||
|
||||
PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
|
||||
|
@ -213,6 +229,14 @@ PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt)
|
|||
|
||||
pjmedia_codec_mgr_destroy(&endpt->codec_mgr);
|
||||
pjmedia_aud_subsys_shutdown();
|
||||
|
||||
/* Call all registered exit callbacks */
|
||||
ecb = endpt->exit_cb_list.next;
|
||||
while (ecb != &endpt->exit_cb_list) {
|
||||
(*ecb->func)(endpt);
|
||||
ecb = ecb->next;
|
||||
}
|
||||
|
||||
pj_pool_release (endpt->pool);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
@ -450,7 +474,7 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
|
|||
rtpmap.param.slen = 1;
|
||||
|
||||
} else {
|
||||
rtpmap.param.ptr = NULL;
|
||||
rtpmap.param.ptr = "";
|
||||
rtpmap.param.slen = 0;
|
||||
}
|
||||
|
||||
|
@ -628,3 +652,23 @@ PJ_DEF(pj_status_t) pjmedia_endpt_dump(pjmedia_endpt *endpt)
|
|||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
PJ_DEF(pj_status_t) pjmedia_endpt_atexit( pjmedia_endpt *endpt,
|
||||
pjmedia_endpt_exit_callback func)
|
||||
{
|
||||
exit_cb *new_cb;
|
||||
|
||||
PJ_ASSERT_RETURN(endpt && func, PJ_EINVAL);
|
||||
|
||||
if (endpt->quit_flag)
|
||||
return PJ_EINVALIDOP;
|
||||
|
||||
new_cb = PJ_POOL_ZALLOC_T(endpt->pool, exit_cb);
|
||||
new_cb->func = func;
|
||||
|
||||
pj_enter_critical_section();
|
||||
pj_list_push_back(&endpt->exit_cb_list, new_cb);
|
||||
pj_leave_critical_section();
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -330,7 +330,8 @@ static pj_status_t g711_alloc_codec( pjmedia_codec_factory *factory,
|
|||
|
||||
#if !PLC_DISABLED
|
||||
/* Create PLC, always with 10ms ptime */
|
||||
status = pjmedia_plc_create(g711_factory.pool, 8000, 80,
|
||||
status = pjmedia_plc_create(g711_factory.pool, 8000,
|
||||
SAMPLES_PER_FRAME,
|
||||
0, &codec_priv->plc);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_mutex_unlock(g711_factory.mutex);
|
||||
|
@ -340,7 +341,7 @@ static pj_status_t g711_alloc_codec( pjmedia_codec_factory *factory,
|
|||
|
||||
/* Create VAD */
|
||||
status = pjmedia_silence_det_create(g711_factory.pool,
|
||||
8000, 80,
|
||||
8000, SAMPLES_PER_FRAME,
|
||||
&codec_priv->vad);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_mutex_unlock(g711_factory.mutex);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue