Re #1900: More merged from trunk (r5512 mistakenly contains merged changes in third-party dir only).

git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/uwp@5513 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
Nanang Izzuddin 2016-12-28 03:40:07 +00:00
commit c551b147fc
301 changed files with 20176 additions and 10480 deletions

View File

@ -447,9 +447,11 @@ Using Default Settings
...
Notes:
The default settings build the libraries in "release" mode, with
default CFLAGS set to "-O2 -DNDEBUG". To change the default CFLAGS,
we can use the usual "./configure CFLAGS='-g'" construct.
The default settings build the libraries in "debug" mode
(active assert()), with default CFLAGS set to "-O2". To change
the default CFLAGS, we can use the usual "./configure CFLAGS='-g'"
construct. To build in "release" mode, and deactivate assert(),
we can use "./configure CFLAGS='-DNDEBUG'".
Features Customization
@ -463,6 +465,7 @@ Using Default Settings
$ ./configure --help
...
Optional Features:
--enable-epoll Use epoll on Linux instead of select
--disable-floating-point Disable floating point where possible
--disable-sound Exclude sound (i.e. use null sound)
--disable-small-filter Exclude small filter in resampling

1012
aconfigure

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
AC_INIT(pjproject,2.x)
AC_INIT([pjproject],[2.x])
host_orig="$host"
@ -19,7 +19,6 @@ AC_CONFIG_FILES([build.mak
pjmedia/build/os-auto.mak
pjsip/build/os-auto.mak
third_party/build/os-auto.mak
third_party/build/portaudio/os-auto.mak
])
@ -39,7 +38,7 @@ dnl # Configure tools
dnl #
AC_PROG_CC
AC_PROG_CXX
AC_LANG_C
AC_LANG([C])
AC_PROG_RANLIB
AC_CHECK_TOOLS([AR], [ar gar], :)
@ -181,7 +180,7 @@ esac
dnl # --disable-floating-point option
AC_ARG_ENABLE(floating-point,
AC_HELP_STRING([--disable-floating-point],
AS_HELP_STRING([--disable-floating-point],
[Disable floating point where possible]),
[if test "$enable_floating_point" = "no"; then
AC_DEFINE(PJ_HAS_FLOATING_POINT,0)
@ -266,6 +265,9 @@ AC_CHECK_HEADER(net/if.h,[AC_DEFINE(PJ_HAS_NET_IF_H,1)],[],
# include <sys/socket.h>
#endif
])
AC_CHECK_FUNC(localtime_r,[AC_DEFINE(PJ_HAS_LOCALTIME_R,1)])
AC_MSG_RESULT([Setting PJ_OS_NAME to $target])
AC_DEFINE_UNQUOTED(PJ_OS_NAME,["$target"])
@ -344,6 +346,15 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
AC_MSG_RESULT(yes)],
AC_MSG_RESULT(no))
dnl # Determine if IPV6_V6ONLY is available
AC_MSG_CHECKING([if IPV6_V6ONLY is available])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>
#include <netinet/in.h>]],
[int opt = IPV6_V6ONLY;])],
[AC_DEFINE(PJ_SOCK_HAS_IPV6_V6ONLY,1)
AC_MSG_RESULT(yes)],
AC_MSG_RESULT(no))
dnl # Determine if SO_ERROR is available
AC_MSG_CHECKING([if SO_ERROR is available])
case $target in
@ -410,22 +421,26 @@ dnl ######################
dnl # ioqueue selection
dnl #
AC_SUBST(ac_os_objs)
AC_SUBST(ac_linux_poll)
AC_MSG_CHECKING([ioqueue backend])
AC_ARG_ENABLE(epoll,
AC_HELP_STRING([--enable-epoll],
AS_HELP_STRING([--enable-epoll],
[Use /dev/epoll ioqueue on Linux (experimental)]),
[
ac_os_objs=ioqueue_epoll.o
AC_MSG_RESULT([/dev/epoll])
AC_DEFINE(PJ_HAS_LINUX_EPOLL,1)
ac_linux_poll=epoll
],
[
ac_os_objs=ioqueue_select.o
AC_MSG_RESULT([select()])
AC_MSG_RESULT([select()])
ac_linux_poll=select
])
AC_SUBST(ac_shared_libraries)
AC_ARG_ENABLE(shared,
AC_HELP_STRING([--enable-shared],
AS_HELP_STRING([--enable-shared],
[Build shared libraries]),
[if test "$enable_shared" = "yes"; then
[ac_shared_libraries=1]
@ -450,18 +465,33 @@ case $target in
ac_os_objs="$ac_os_objs os_info_iphone.o"
;;
esac
# QoS
case $target in
*darwin*)
;;
*)
ac_os_objs="$ac_os_objs sock_qos_bsd.o"
;;
esac
# UUID
if test "$ac_has_uuid_lib" = "1" -a "$ac_has_uuid_h" = "1"; then
ac_os_objs="$ac_os_objs guid_uuid.o"
else
ac_os_objs="$ac_os_objs guid_simple.o"
fi
case $target in
*android*)
ac_os_objs="$ac_os_objs guid_android.o"
;;
*)
if test "$ac_has_uuid_lib" = "1" -a "$ac_has_uuid_h" = "1"; then
ac_os_objs="$ac_os_objs guid_uuid.o"
else
ac_os_objs="$ac_os_objs guid_simple.o"
fi
;;
esac
;;
esac
case $target in
*darwin*)
ac_os_objs="$ac_os_objs os_core_darwin.o"
ac_os_objs="$ac_os_objs sock_qos_darwin.o os_core_darwin.o"
;;
esac
@ -473,7 +503,7 @@ dnl #
dnl # Use external Speex installation
AC_SUBST(ac_external_speex,0)
AC_ARG_WITH(external-speex,
AC_HELP_STRING([--with-external-speex],
AS_HELP_STRING([--with-external-speex],
[Use external Speex development files, not the one in "third_party" directory. When this option is set, make sure that Speex is accessible to use (hint: use CFLAGS and LDFLAGS env var to set the include/lib paths)]),
[
if test "x$with_external_speex" != "xno"; then
@ -495,7 +525,7 @@ AC_ARG_WITH(external-speex,
dnl # Use external GSM codec library installation
AC_SUBST(ac_external_gsm,0)
AC_ARG_WITH(external-gsm,
AC_HELP_STRING([--with-external-gsm],
AS_HELP_STRING([--with-external-gsm],
[Use external GSM codec library, not the one in "third_party" directory. When this option is set, make sure that the GSM include/lib files are accessible to use (hint: use CFLAGS and LDFLAGS env var to set the include/lib paths)]),
[
if test "x$with_external_gsm" != "xno"; then
@ -531,7 +561,7 @@ AC_ARG_WITH(external-gsm,
dnl # Use external SRTP installation
AC_SUBST(ac_external_srtp,0)
AC_ARG_WITH(external-srtp,
AC_HELP_STRING([--with-external-srtp],
AS_HELP_STRING([--with-external-srtp],
[Use external SRTP development files, not the one in "third_party" directory. When this option is set, make sure that SRTP is accessible to use (hint: use CFLAGS and LDFLAGS env var to set the include/lib paths)]),
[
if test "x$with_external_srtp" != "xno"; then
@ -558,10 +588,53 @@ if test "x$ac_external_srtp" = "x1"; then
fi
fi
dnl # Use external libyuv installation
AC_SUBST(ac_external_yuv,0)
AC_ARG_WITH(external-yuv,
AS_HELP_STRING([--with-external-yuv],
[Use external libyuv development files, not the one in "third_party" directory. When this option is set, make sure that libyuv is accessible to use (hint: use CFLAGS and LDFLAGS env var to set the include/lib paths)]),
[
if test "x$with_external_yuv" != "xno"; then
# Test libyuv installation
AC_MSG_CHECKING([if external libyuv devkit is installed])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <libyuv.h>]],
[RGB24ToI420(0,0,0,0,0,0,0,0,0,0);])],
[AC_MSG_RESULT(yes!!)
ac_external_yuv="1"
],
[AC_MSG_ERROR([Unable to use external libyuv. If libyuv development files are not available in the default locations, use CFLAGS and LDFLAGS env var to set the include/lib paths])])
fi
]
)
dnl # Use external webrtc installation
AC_SUBST(ac_external_webrtc,0)
AC_ARG_WITH(external-webrtc,
AS_HELP_STRING([--with-external-webrtc],
[Use external webrtc development files, not the one in "third_party" directory. When this option is set, make sure that webrtc is accessible to use (hint: use CFLAGS and LDFLAGS env var to set the include/lib paths)]),
[
if test "x$with_external_webrtc" != "xno"; then
# Test webrtc installation
AC_MSG_CHECKING([if external webrtc devkit is installed])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <webrtc/modules/audio_processing/aec/aec_core.h>
#include <webrtc/modules/audio_processing/aec/include/echo_cancellation.h>
]],
[WebRtcAec_Create();])],
[AC_MSG_RESULT(yes!!)
ac_external_webrtc="1"
],
[AC_MSG_ERROR([Unable to use external webrtc. If webrtc development files are not available in the default locations, use CFLAGS and LDFLAGS env var to set the include/lib paths])])
fi
]
)
dnl # Resample implementation
AC_SUBST(ac_pjmedia_resample,libresample)
AC_ARG_ENABLE(resample,
AC_HELP_STRING([--disable-resample],
AS_HELP_STRING([--disable-resample],
[Disable resampling implementations]),
[if test "$enable_resample" = "no"; then
[ac_pjmedia_resample=none]
@ -572,7 +645,7 @@ AC_ARG_ENABLE(resample,
dnl # Sound device backend selection
AC_SUBST(ac_pjmedia_snd)
AC_ARG_ENABLE(sound,
AC_HELP_STRING([--disable-sound],
AS_HELP_STRING([--disable-sound],
[Exclude sound (i.e. use null sound)]),
[if test "$enable_sound" = "no"; then
[ac_pjmedia_snd=null]
@ -583,7 +656,7 @@ AC_ARG_ENABLE(sound,
dnl # Use external PortAudio installation
AC_SUBST(ac_external_pa,0)
AC_ARG_WITH(external-pa,
AC_HELP_STRING([--with-external-pa],
AS_HELP_STRING([--with-external-pa],
[Use external PortAudio development files, not the one in "third_party" directory. When this option is set, make sure that PortAudio is accessible to use (hint: use CFLAGS and LDFLAGS env var to set the include/lib paths)]),
[
if test "x$with_external_pa" != "xno"; then
@ -651,19 +724,17 @@ else
;;
*)
dnl # Check if ALSA is available
ac_pjmedia_snd=pa_unix
ac_pjmedia_snd=alsa
AC_SUBST(ac_pa_use_alsa,1)
AC_CHECK_HEADER(alsa/version.h,
[AC_SUBST(ac_pa_use_alsa,1)
AC_SUBST(ac_pjmedia_snd,alsa)
LIBS="$LIBS -lasound"
],
[AC_SUBST(ac_pa_use_alsa,0)])
[LIBS="$LIBS -lasound"],
[ac_pa_use_alsa=0])
AC_MSG_RESULT([Checking sound device backend... unix])
dnl # Check if OSS is disabled
AC_SUBST(ac_pa_use_oss,1)
AC_ARG_ENABLE(oss,
AC_HELP_STRING([--disable-oss],
AS_HELP_STRING([--disable-oss],
[Disable OSS audio (default: not disabled)]),
[
if test "$enable_oss" = "no"; then
@ -677,9 +748,16 @@ fi
AC_SUBST(ac_pjmedia_video)
# Disable video on mingw
case $target in
*mingw*)
enable_video="no"
;;
esac
dnl # --disable-video option
AC_ARG_ENABLE(video,
AC_HELP_STRING([--disable-video],
AS_HELP_STRING([--disable-video],
[Disable video feature]),
[if test "$enable_video" = "no"; then
#AC_DEFINE(PJMEDIA_HAS_VIDEO,0)
@ -725,43 +803,58 @@ else
fi
ac_android_cflags="$ac_android_cflags -DPJMEDIA_VIDEO_DEV_HAS_ANDROID=1"
;;
*-apple-darwin_ios*)
ac_pjmedia_video=iphone_os
AC_SUBST(ac_pjmedia_video_has_ios)
AC_SUBST(ac_ios_cflags)
*darwin*)
ac_pjmedia_video=darwin_os
AC_SUBST(ac_pjmedia_video_has_darwin)
AC_SUBST(ac_pjmedia_video_has_ios_opengl)
AC_SUBST(ac_darwin_cflags)
SAVED_LIBS="$LIBS"
LIBS="-framework AVFoundation -framework CoreGraphics -framework QuartzCore -framework CoreVideo -framework CoreMedia"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [])],[ac_pjmedia_video_has_ios=yes],[ac_pjmedia_video_has_ios=no])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [])],
[ac_pjmedia_video_has_darwin=yes],
[ac_pjmedia_video_has_darwin=no])
LIBS="-framework OpenGLES"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [])],
[ac_pjmedia_video_has_ios_opengl=yes],
[ac_pjmedia_video_has_ios_opengl=no])
LIBS="$SAVED_LIBS"
if test "$ac_pjmedia_video_has_ios" = "yes"; then
ac_ios_cflags="-DPJMEDIA_VIDEO_DEV_HAS_IOS=1 -DPJMEDIA_VIDEO_DEV_HAS_IOS_OPENGL=1"
LIBS="$LIBS -framework OpenGLES -framework AVFoundation -framework CoreGraphics -framework QuartzCore -framework CoreVideo -framework CoreMedia"
if test "$ac_pjmedia_video_has_darwin" = "yes"; then
ac_darwin_cflags="-DPJMEDIA_VIDEO_DEV_HAS_DARWIN=1"
LIBS="$LIBS -framework AVFoundation -framework CoreGraphics -framework QuartzCore -framework CoreVideo -framework CoreMedia"
AC_MSG_RESULT([Checking if AVFoundation framework is available... yes])
else
AC_MSG_RESULT([Checking if AVFoundation framework is available... no])
fi
;;
*darwin*)
ac_pjmedia_video=mac_os
AC_SUBST(ac_pjmedia_video_has_qt)
AC_SUBST(ac_qt_cflags)
SAVED_LIBS="$LIBS"
LIBS="-framework QTKit"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [])],[ac_pjmedia_video_has_qt=yes],[ac_pjmedia_video_has_qt=no])
LIBS="$SAVED_LIBS"
if test "$ac_pjmedia_video_has_qt" = "yes"; then
ac_qt_cflags="-DPJMEDIA_VIDEO_DEV_HAS_QT=1"
LIBS="$LIBS -framework QTKit -framework QuartzCore -framework OpenGL"
AC_MSG_RESULT([Checking if QTKit framework is available... yes])
if test "$ac_pjmedia_video_has_ios_opengl" = "yes"; then
ac_darwin_cflags+=" -DPJMEDIA_VIDEO_DEV_HAS_IOS_OPENGL=1"
LIBS="$LIBS -framework OpenGLES"
AC_MSG_RESULT([Checking if OpenGLES framework is available... yes])
else
AC_MSG_RESULT([Checking if QTKit framework is available... no])
AC_MSG_RESULT([Checking if OpenGLES framework is available... no])
fi
;;
if false; then
# QTKit is deprecated, see ticket #1931.
ac_pjmedia_video=mac_os
AC_SUBST(ac_pjmedia_video_has_qt)
AC_SUBST(ac_qt_cflags)
SAVED_LIBS="$LIBS"
LIBS="-framework QTKit"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [])],[ac_pjmedia_video_has_qt=yes],[ac_pjmedia_video_has_qt=no])
LIBS="$SAVED_LIBS"
if test "$ac_pjmedia_video_has_qt" = "yes"; then
ac_qt_cflags="-DPJMEDIA_VIDEO_DEV_HAS_QT=1"
LIBS="$LIBS -framework QTKit -framework QuartzCore -framework OpenGL"
AC_MSG_RESULT([Checking if QTKit framework is available... yes])
else
AC_MSG_RESULT([Checking if QTKit framework is available... no])
fi
fi
;;
esac
fi
AC_ARG_ENABLE(ext_sound,
AC_HELP_STRING([--enable-ext-sound],
AS_HELP_STRING([--enable-ext-sound],
[PJMEDIA will not provide any sound device backend]),
[if test "$enable_ext_sound" = "yes"; then
[ac_pjmedia_snd=external]
@ -772,7 +865,7 @@ AC_ARG_ENABLE(ext_sound,
dnl # Include resampling small filter
AC_SUBST(ac_no_small_filter)
AC_ARG_ENABLE(small-filter,
AC_HELP_STRING([--disable-small-filter],
AS_HELP_STRING([--disable-small-filter],
[Exclude small filter in resampling]),
[if test "$enable_small_filter" = "no"; then
[ac_no_small_filter='-DPJMEDIA_HAS_SMALL_FILTER=0']
@ -783,7 +876,7 @@ AC_ARG_ENABLE(small-filter,
dnl # Include resampling large filter
AC_SUBST(ac_no_large_filter)
AC_ARG_ENABLE(large-filter,
AC_HELP_STRING([--disable-large-filter],
AS_HELP_STRING([--disable-large-filter],
[Exclude large filter in resampling]),
[if test "$enable_large_filter" = "no"; then
[ac_no_large_filter='-DPJMEDIA_HAS_LARGE_FILTER=0']
@ -794,7 +887,7 @@ AC_ARG_ENABLE(large-filter,
dnl # Include Speex AEC
AC_SUBST(ac_no_speex_aec)
AC_ARG_ENABLE(speex-aec,
AC_HELP_STRING([--disable-speex-aec],
AS_HELP_STRING([--disable-speex-aec],
[Exclude Speex Acoustic Echo Canceller/AEC]),
[if test "$enable_speex_aec" = "no"; then
[ac_no_speex_aec='-DPJMEDIA_HAS_SPEEX_AEC=0']
@ -805,7 +898,7 @@ AC_ARG_ENABLE(speex-aec,
dnl # Include G711 codec
AC_SUBST(ac_no_g711_codec)
AC_ARG_ENABLE(g711-codec,
AC_HELP_STRING([--disable-g711-codec],
AS_HELP_STRING([--disable-g711-codec],
[Exclude G.711 codecs from the build]),
[if test "$enable_g711_codec" = "no"; then
[ac_no_g711_codec=1]
@ -818,7 +911,7 @@ AC_ARG_ENABLE(g711-codec,
dnl # Include L16 codec
AC_SUBST(ac_no_l16_codec)
AC_ARG_ENABLE(l16-codec,
AC_HELP_STRING([--disable-l16-codec],
AS_HELP_STRING([--disable-l16-codec],
[Exclude Linear/L16 codec family from the build]),
[if test "$enable_l16_codec" = "no"; then
[ac_no_l16_codec=1]
@ -831,7 +924,7 @@ AC_ARG_ENABLE(l16-codec,
dnl # Include GSM codec
AC_SUBST(ac_no_gsm_codec)
AC_ARG_ENABLE(gsm-codec,
AC_HELP_STRING([--disable-gsm-codec],
AS_HELP_STRING([--disable-gsm-codec],
[Exclude GSM codec in the build]),
[if test "$enable_gsm_codec" = "no"; then
[ac_no_gsm_codec=1]
@ -843,7 +936,7 @@ AC_ARG_ENABLE(gsm-codec,
dnl # Include G.722 codec
AC_SUBST(ac_no_g722_codec)
AC_ARG_ENABLE(g722-codec,
AC_HELP_STRING([--disable-g722-codec],
AS_HELP_STRING([--disable-g722-codec],
[Exclude G.722 codec in the build]),
[if test "$enable_g722_codec" = "no"; then
[ac_no_g722_codec=1]
@ -855,7 +948,7 @@ AC_ARG_ENABLE(g722-codec,
dnl # Include G722.1 codec
AC_SUBST(ac_no_g7221_codec)
AC_ARG_ENABLE(g7221-codec,
AC_HELP_STRING([--disable-g7221-codec],
AS_HELP_STRING([--disable-g7221-codec],
[Exclude G.7221 codec in the build]),
[if test "$enable_g7221_codec" = "no"; then
[ac_no_g7221_codec=1]
@ -867,7 +960,7 @@ AC_ARG_ENABLE(g7221-codec,
dnl # Include Speex codec
AC_SUBST(ac_no_speex_codec)
AC_ARG_ENABLE(speex-codec,
AC_HELP_STRING([--disable-speex-codec],
AS_HELP_STRING([--disable-speex-codec],
[Exclude Speex codecs in the build]),
[if test "$enable_speex_codec" = "no"; then
[ac_no_speex_codec=1]
@ -879,7 +972,7 @@ AC_ARG_ENABLE(speex-codec,
dnl # Include iLBC codec
AC_SUBST(ac_no_ilbc_codec)
AC_ARG_ENABLE(ilbc-codec,
AC_HELP_STRING([--disable-ilbc-codec],
AS_HELP_STRING([--disable-ilbc-codec],
[Exclude iLBC codec in the build]),
[if test "$enable_ilbc_codec" = "no"; then
[ac_no_ilbc_codec=1]
@ -890,7 +983,7 @@ AC_ARG_ENABLE(ilbc-codec,
dnl # Include libsamplerate
AC_ARG_ENABLE(libsamplerate,
AC_HELP_STRING([--enable-libsamplerate],
AS_HELP_STRING([--enable-libsamplerate],
[Link with libsamplerate when available.]),
[
if test "$enable_libsamplerate" = "yes"; then
@ -904,7 +997,7 @@ AC_ARG_ENABLE(libsamplerate,
AC_SUBST(ac_resample_dll)
AC_ARG_ENABLE(resample_dll,
AC_HELP_STRING([--enable-resample-dll],
AS_HELP_STRING([--enable-resample-dll],
[Build libresample as shared library]),
[if test "$enable_resample_dll" = "yes"; then
[ac_resample_dll=1]
@ -915,7 +1008,7 @@ AC_ARG_ENABLE(resample_dll,
dnl # SDL alt prefix
AC_ARG_WITH(sdl,
AC_HELP_STRING([--with-sdl=DIR],
AS_HELP_STRING([--with-sdl=DIR],
[Specify alternate libSDL prefix]),
[],
[with_sdl=no]
@ -928,7 +1021,7 @@ fi
dnl # SDL
AC_ARG_ENABLE(sdl,
AC_HELP_STRING([--disable-sdl],
AS_HELP_STRING([--disable-sdl],
[Disable SDL (default: not disabled)]),
[
if test "$enable_sdl" = "no"; then
@ -960,7 +1053,7 @@ AC_ARG_ENABLE(sdl,
AC_ARG_WITH(ffmpeg,
AC_HELP_STRING([--with-ffmpeg=DIR],
AS_HELP_STRING([--with-ffmpeg=DIR],
[Specify alternate FFMPEG prefix]),
[],
[with_ffmpeg=no]
@ -973,7 +1066,7 @@ fi
dnl # FFMPEG stuffs
AC_ARG_ENABLE(ffmpeg,
AC_HELP_STRING([--disable-ffmpeg],
AS_HELP_STRING([--disable-ffmpeg],
[Disable ffmpeg (default: not disabled)]),
[
AC_SUBST(ac_has_ffmpeg,0)
@ -999,9 +1092,9 @@ AC_ARG_ENABLE(ffmpeg,
if test "$PKG_CONFIG" != "none"; then
AC_MSG_CHECKING([ffmpeg packages])
av_pkg=""
if $PKG_CONFIG --exists libdevice; then
if $PKG_CONFIG --exists libavdevice; then
ac_ffmpeg_cflags="$ac_ffmpeg_cflags -DPJMEDIA_HAS_LIBAVDEVICE=1"
av_pkg="$av_pkg libdevice"
av_pkg="$av_pkg libavdevice"
fi
if $PKG_CONFIG --exists libavformat; then
ac_ffmpeg_cflags="$ac_ffmpeg_cflags -DPJMEDIA_HAS_LIBAVFORMAT=1"
@ -1019,10 +1112,6 @@ AC_ARG_ENABLE(ffmpeg,
ac_ffmpeg_cflags="$ac_ffmpeg_cflags -DPJMEDIA_HAS_LIBAVUTIL=1"
av_pkg="$av_pkg libavutil"
fi
if $PKG_CONFIG --exists libavcore; then
ac_ffmpeg_cflags="$ac_ffmpeg_cflags -DPJMEDIA_HAS_LIBAVCORE=1"
av_pkg="$av_pkg libavcore"
fi
if test "x$av_pkg" == "x"; then
AC_MSG_RESULT([none detected (check the prefix)! **])
@ -1089,6 +1178,12 @@ AC_ARG_ENABLE(ffmpeg,
fi
AC_CHECK_TYPES(enum AVPixelFormat,
[],
[ac_ffmpeg_cflags="$ac_ffmpeg_cflags -DPJMEDIA_USE_OLD_FFMPEG=1"],
[[#include <libavformat/avformat.h>]]
)
LIBS="$LIBS $ac_ffmpeg_ldflags"
export PKG_CONFIG_PATH=$SAVED_PKG_CONFIG_PATH
]
@ -1096,7 +1191,7 @@ AC_ARG_ENABLE(ffmpeg,
dnl # Video for Linux 2
AC_ARG_ENABLE(v4l2,
AC_HELP_STRING([--disable-v4l2],
AS_HELP_STRING([--disable-v4l2],
[Disable Video4Linux2 (default: not disabled)]),
[
if test "$enable_v4l2" = "no"; then
@ -1117,7 +1212,7 @@ AC_ARG_ENABLE(v4l2,
dnl # OpenH264 alt prefix
AC_ARG_WITH(openh264,
AC_HELP_STRING([--with-openh264=DIR],
AS_HELP_STRING([--with-openh264=DIR],
[Specify alternate OpenH264 prefix]),
[],
[with_openh264=no]
@ -1132,7 +1227,7 @@ dnl # OpenH264
AC_SUBST(ac_openh264_cflags)
AC_SUBST(ac_openh264_ldflags)
AC_ARG_ENABLE(openh264,
AC_HELP_STRING([--disable-openh264],
AS_HELP_STRING([--disable-openh264],
[Disable OpenH264 (default: not disabled)]),
[
if test "$enable_openh264" = "no"; then
@ -1180,185 +1275,33 @@ AC_ARG_ENABLE(openh264,
])
dnl # libyuv alt prefix
AC_ARG_WITH(libyuv,
AC_HELP_STRING([--with-libyuv=DIR],
[Specify alternate libyuv prefix]),
[],
[with_libyuv=no]
)
dnl # Do not use default libyuv installation if we are cross-compiling
if test "x$ac_cross_compile" != "x" -a "x$with_libyuv" = "xno"; then
enable_libyuv=no
fi
dnl # Include libyuv
AC_SUBST(ac_libyuv_cflags)
AC_SUBST(ac_libyuv_ldflags)
AC_ARG_ENABLE(libyuv,
AC_HELP_STRING([--disable-libyuv],
[Exclude libyuv in the build]),
[if test "$enable_libyuv" = "no"; then
AC_MSG_RESULT([Checking if libyuv is disabled...yes])
fi],
[
if test "x$with_libyuv" != "xno" -a "x$with_libyuv" != "x"; then
LIBYUV_PREFIX=$with_libyuv
LIBYUV_CFLAGS="-I$LIBYUV_PREFIX/include"
case $target in
*-apple-darwin_ios*)
LIBYUV_LDFLAGS="-L$LIBYUV_PREFIX/out_ios/Release-iphoneos"
case $ARCH in
*arm*)
LIBYUV_LIBS="-lyuv_neon"
;;
*)
;;
esac
;;
*mingw* | *cygw* | *win32* | *w32* | *darwin* | *linux* | *android*)
LIBYUV_LDFLAGS="-L$LIBYUV_PREFIX/out/Release"
;;
*)
LIBYUV_CFLAGS=""
LIBYUV_LDFLAGS=""
;;
esac
AC_MSG_RESULT([Using libyuv prefix... $with_libyuv])
else
LIBYUV_CFLAGS=""
LIBYUV_LDFLAGS=""
fi
LIBYUV_LIBS="$LIBYUV_LIBS -lyuv"
SAVED_LIBS="$LIBS"
SAVED_LDFLAGS="$LDFLAGS"
SAVED_CFLAGS="$CFLAGS"
LIBS="$LIBYUV_LIBS $LIBS"
LDFLAGS="$LIBYUV_LDFLAGS $LDFLAGS"
CFLAGS="$LIBYUV_CFLAGS $CFLAGS"
AC_CHECK_LIB(yuv,
I420Scale,
[ ac_libyuv_cflags="-DPJMEDIA_HAS_LIBYUV=1 $LIBYUV_CFLAGS"
ac_libyuv_ldflags="$LIBYUV_LDFLAGS $LIBYUV_LIBS"
],
[ LIBS="$SAVED_LIBS"
LDFLAGS="$SAVED_LDFLAGS"
CFLAGS="$SAVED_CFLAGS"
],
[]
)
])
dnl # WebRtc alt prefix
AC_ARG_WITH(webrtc,
AC_HELP_STRING([--with-webrtc=DIR],
[Specify alternate WebRtc prefix]),
[],
[with_webrtc=no]
)
dnl # Do not use default webrtc installation if we are cross-compiling
if test "x$ac_cross_compile" != "x" -a "x$with_webrtc" = "xno"; then
enable_webrtc=no
fi
dnl # WebRtc
AC_SUBST(ac_webrtc_cflags)
AC_SUBST(ac_webrtc_ldflags)
AC_ARG_ENABLE(webrtc,
AC_HELP_STRING([--disable-webrtc],
[Exclude webrtc in the build]),
[if test "$enable_webrtc" = "no"; then
AC_MSG_RESULT([Checking if webrtc is disabled...yes])
fi],
[
if test "x$with_webrtc" != "xno" -a "x$with_webrtc" != "x"; then
WEBRTC_PREFIX=$with_webrtc
WEBRTC_CFLAGS="-I$WEBRTC_PREFIX/src"
case $target in
*-apple-darwin_ios*)
case $ARCH in
*arm*)
WEBRTC_CFLAGS="-DPJMEDIA_WEBRTC_AEC_USE_MOBILE=1 $WEBRTC_CFLAGS"
WEBRTC_LDFLAGS="-L$WEBRTC_PREFIX/src/out_ios/Release-iphoneos"
WEBRTC_LIBS="-laudio_processing_neon -lcommon_audio_neon"
;;
*)
;;
esac
;;
*mingw* | *cygw* | *win32* | *w32* | *darwin* | *linux* | *android*)
WEBRTC_LDFLAGS="-L$WEBRTC_PREFIX/src/out/Release"
WEBRTC_LIBS="-laudio_processing_sse2"
;;
*)
;;
esac
AC_MSG_RESULT([Using webrtc prefix... $with_webrtc])
else
WEBRTC_CFLAGS=""
WEBRTC_LDFLAGS=""
fi
WEBRTC_LIBS="$WEBRTC_LIBS -laudio_processing -lcommon_audio -lsystem_wrappers"
SAVED_LIBS="$LIBS"
SAVED_LDFLAGS="$LDFLAGS"
SAVED_CFLAGS="$CFLAGS"
LIBS="$WEBRTC_LIBS $LIBS"
LDFLAGS="$WEBRTC_LDFLAGS $LDFLAGS"
CFLAGS="$WEBRTC_CFLAGS $CFLAGS"
AC_CHECK_LIB(audio_processing,
WebRtcAec_Process,
[ ac_webrtc_cflags="-DPJMEDIA_HAS_WEBRTC_AEC=1 $WEBRTC_CFLAGS"
ac_webrtc_ldflags="$WEBRTC_LDFLAGS $WEBRTC_LIBS"
],
[ LIBS="$SAVED_LIBS"
LDFLAGS="$SAVED_LDFLAGS"
CFLAGS="$SAVED_CFLAGS"
],
[]
)
])
dnl ########################################################
dnl # Intel IPP support
dnl #
AC_ARG_ENABLE(ipp,
AC_HELP_STRING([--enable-ipp],
AS_HELP_STRING([--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]),
[],
[enable_ipp=no]
)
AC_ARG_WITH(ipp,
AC_HELP_STRING([--with-ipp=DIR],
AS_HELP_STRING([--with-ipp=DIR],
[Specify the Intel IPP location]),
[],
[with_ipp=no]
)
AC_ARG_WITH(ipp-samples,
AC_HELP_STRING([--with-ipp-samples=DIR],
AS_HELP_STRING([--with-ipp-samples=DIR],
[Specify the Intel IPP samples location]),
[],
[with_ipp_samples=no]
)
AC_ARG_WITH(ipp-arch,
AC_HELP_STRING([--with-ipp-arch=ARCH],
AS_HELP_STRING([--with-ipp-arch=ARCH],
[Specify the Intel IPP ARCH suffix, e.g. "64" or "em64t. Default is blank for IA32"]),
[],
[with_ipp_arch=no]
@ -1576,7 +1519,7 @@ dnl #
dnl # SSL alt prefix
AC_ARG_WITH(ssl,
AC_HELP_STRING([--with-ssl=DIR],
AS_HELP_STRING([--with-ssl=DIR],
[Specify alternate libssl prefix]),
[],
[with_ssl=no]
@ -1589,8 +1532,11 @@ fi
dnl # Include SSL support
AC_SUBST(ac_no_ssl)
AC_SUBST(ac_ssl_has_aes_gcm,0)
AC_SUBST(ac_ssl_has_ec,0)
AC_SUBST(ac_ssl_has_sigalg,0)
AC_ARG_ENABLE(ssl,
AC_HELP_STRING([--disable-ssl],
AS_HELP_STRING([--disable-ssl],
[Exclude SSL support the build (default: autodetect)])
,
[
@ -1614,6 +1560,53 @@ AC_ARG_ENABLE(ssl,
AC_CHECK_LIB(ssl,SSL_library_init,[libssl_present=1 && LIBS="-lssl $LIBS"])
if test "x$openssl_h_present" = "x1" -a "x$libssl_present" = "x1" -a "x$libcrypto_present" = "x1"; then
AC_MSG_RESULT([OpenSSL library found, SSL support enabled])
# Check if SRTP should be compiled with OpenSSL
# support, to enable cryptos such as AES GCM
AC_CHECK_LIB(crypto,EVP_aes_128_gcm,[ac_ssl_has_aes_gcm=1])
if test "x$ac_ssl_has_aes_gcm" = "x1"; then
AC_MSG_RESULT([OpenSSL has AES GCM support, SRTP will use OpenSSL])
else
AC_MSG_RESULT([OpenSSL AES GCM support not found, SRTP will only support AES CM cryptos])
fi
# Check if OpenSSL supports setting curve algorithm
# and has elliptic curve
AC_MSG_CHECKING([OpenSSL setting curve functions])
AC_SUBST(set_curve_present,0)
AC_SUBST(ec_curve_present,0)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <openssl/ssl.h>
]],
[ SSL_set1_curves(NULL, NULL, 0);]
)],
[ set_curve_present=1
AC_MSG_RESULT(ok)
],
[
AC_MSG_RESULT(no)
])
AC_CHECK_LIB(ssl,EC_curve_nid2nist,[ec_curve_present=1])
if test "x$set_curve_present" = "x1" -a "x$ec_curve_present" = "x1"; then
[ac_ssl_has_ec=1]
AC_MSG_RESULT([OpenSSL has elliptic curve support])
else
AC_MSG_RESULT([OpenSSL elliptic curve algorithm unsupported])
fi
AC_MSG_CHECKING([OpenSSL setting sigalg])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <openssl/ssl.h>
]],
[SSL_set1_sigalgs_list(NULL, NULL);]
)],
[ ac_ssl_has_sigalg=1
AC_MSG_RESULT(ok)
],
[
AC_MSG_RESULT(no)
])
# PJSIP_HAS_TLS_TRANSPORT setting follows PJ_HAS_SSL_SOCK
#AC_DEFINE(PJSIP_HAS_TLS_TRANSPORT, 1)
AC_DEFINE(PJ_HAS_SSL_SOCK, 1)
@ -1624,15 +1617,15 @@ AC_ARG_ENABLE(ssl,
dnl # Obsolete option --with-opencore-amrnb
AC_ARG_WITH(opencore-amrnb,
AC_HELP_STRING([--with-opencore-amrnb=DIR],
AS_HELP_STRING([--with-opencore-amrnb=DIR],
[This option is obsolete and replaced by --with-opencore-amr=DIR]),
[AC_MSG_ERROR(This option is obsolete and replaced by --with-opencore-amr=DIR)],
[]
[true;]
)
dnl # opencore-amr alt prefix
AC_ARG_WITH(opencore-amr,
AC_HELP_STRING([--with-opencore-amr=DIR],
AS_HELP_STRING([--with-opencore-amr=DIR],
[Specify alternate libopencore-amr prefix]),
[],
[with_opencore_amr=no]
@ -1645,7 +1638,7 @@ fi
dnl # vo-amrwbenc alt prefix
AC_ARG_WITH(opencore-amrwbenc,
AC_HELP_STRING([--with-opencore-amrwbenc=DIR],
AS_HELP_STRING([--with-opencore-amrwbenc=DIR],
[Specify alternate libvo-amrwbenc prefix]),
[],
[with_opencore_amrwbenc=no]
@ -1661,7 +1654,7 @@ dnl # Include opencore-amr support
AC_SUBST(ac_no_opencore_amrnb)
AC_SUBST(ac_no_opencore_amrwb)
AC_ARG_ENABLE(opencore_amr,
AC_HELP_STRING([--disable-opencore-amr],
AS_HELP_STRING([--disable-opencore-amr],
[Exclude OpenCORE AMR support from the build (default: autodetect)])
,
[
@ -1716,7 +1709,7 @@ AC_ARG_ENABLE(opencore_amr,
dnl # SILK prefix
AC_ARG_WITH(silk,
AC_HELP_STRING([--with-silk=DIR],
AS_HELP_STRING([--with-silk=DIR],
[Specify alternate SILK prefix]),
[],
[with_silk=no]
@ -1730,7 +1723,7 @@ fi
dnl # Include SILK support
AC_SUBST(ac_no_silk)
AC_ARG_ENABLE(silk,
AC_HELP_STRING([--disable-silk],
AS_HELP_STRING([--disable-silk],
[Exclude SILK support from the build (default: autodetect)])
,
[
@ -1761,6 +1754,130 @@ AC_ARG_ENABLE(silk,
fi
])
dnl # Do not use default OPUS installation if we are cross-compiling
if test "x$ac_cross_compile" != "x" -a "x$with_opus" = "xno"; then
enable_opus=no
fi
dnl # OPUS prefix
AC_ARG_WITH(opus,
AS_HELP_STRING([--with-opus=DIR],
[Specify alternate OPUS prefix]),
[],
[with_opus=no]
)
dnl # Include OPUS support
AC_SUBST(ac_no_opus)
AC_ARG_ENABLE(opus,
AS_HELP_STRING([--disable-opus],
[Exclude OPUS support from the build (default: autodetect)])
,
[
if test "$enable_opus" = "no"; then
[ac_no_opus=1]
AC_DEFINE(PJMEDIA_HAS_OPUS_CODEC,0)
AC_MSG_RESULT([Checking if OPUS support is disabled... yes])
fi
],
[
AC_MSG_RESULT([checking for OPUS installations..])
if test "x$with_opus" != "xno" -a "x$with_opus" != "x"; then
CFLAGS="$CFLAGS -I$with_opus/include"
CPPFLAGS="$CPPFLAGS -I$with_opus/include"
LDFLAGS="$LDFLAGS -L$with_opus/lib"
AC_MSG_RESULT([Using OPUS prefix... $with_opus])
fi
AC_SUBST(opus_h_present)
AC_SUBST(opus_present)
AC_CHECK_HEADER(opus/opus.h,[opus_h_present=1])
AC_CHECK_LIB(opus,opus_repacketizer_get_size,[opus_present=1 && LIBS="-lopus $LIBS"])
if test "x$opus_h_present" = "x1" -a "x$opus_present" = "x1"; then
AC_MSG_RESULT([OPUS library found, OPUS support enabled])
AC_DEFINE(PJMEDIA_HAS_OPUS_CODEC,1)
else
[ac_no_opus=1]
AC_MSG_RESULT([OPUS library not found, OPUS support disabled])
AC_DEFINE(PJMEDIA_HAS_OPUS_CODEC,0)
fi
])
dnl # Include libyuv
AC_SUBST(ac_no_yuv)
AC_ARG_ENABLE(libyuv,
AS_HELP_STRING([--disable-libyuv],
[Exclude libyuv in the build]),
[if test "$enable_libyuv" = "no"; then
[ac_no_yuv=1]
AC_DEFINE(PJMEDIA_HAS_LIBYUV,0)
AC_MSG_RESULT([Checking if libyuv is disabled...yes])
fi],
AC_MSG_RESULT([Checking if libyuv is disabled...no]))
dnl # Include webrtc
AC_SUBST(ac_no_webrtc)
AC_SUBST(ac_webrtc_instset)
AC_SUBST(ac_webrtc_cflags)
AC_SUBST(ac_webrtc_ldflags)
AC_ARG_ENABLE(libwebrtc,
AS_HELP_STRING([--disable-libwebrtc],
[Exclude libwebrtc in the build]),
[if test "$enable_libwebrtc" = "no"; then
[ac_no_webrtc=1]
AC_DEFINE(PJMEDIA_HAS_LIBWEBRTC,0)
AC_MSG_RESULT([Checking if libwebrtc is disabled...yes])
fi],
[
AC_MSG_RESULT([Checking if libwebrtc is disabled...no])
case $target in
*-apple-darwin_ios*)
case $target in
arm64*)
ac_webrtc_instset=neon
ac_webrtc_cflags="-DWEBRTC_ARCH_ARM64"
;;
*arm*)
ac_webrtc_instset=neon
;;
*)
ac_webrtc_instset=sse2
;;
esac
;;
*android*)
case $TARGET_ABI in
armeabi-v7a)
ac_webrtc_instset=neon
ac_webrtc_cflags="-mfloat-abi=softfp -mfpu=neon"
;;
armeabi)
ac_webrtc_instset=neon
ac_webrtc_cflags="-mthumb -mfloat-abi=softfp -mfpu=neon -march=armv7"
;;
arm64*)
ac_webrtc_instset=neon
ac_webrtc_cflags="-DWEBRTC_ARCH_ARM64"
;;
mips64*)
ac_webrtc_instset=generic
;;
mips*)
ac_webrtc_instset=mips
;;
*)
ac_webrtc_instset=sse2
;;
esac
;;
*mingw* | *cygw* | *win32* | *w32* | *darwin* | *linux*)
ac_webrtc_instset=sse2
;;
*)
;;
esac
])
dnl ##########################################
dnl #
@ -1831,7 +1948,6 @@ esac
AC_SUBST(target)
AC_SUBST(ac_linux_poll,select)
AC_SUBST(ac_host,unix)
AC_SUBST(ac_main_obj)
case $target in
@ -1845,7 +1961,7 @@ esac
AC_SUBST(CC)
ac_build_mak_vars=`echo $ac_build_mak_vars | sed 's/\\\\n/\n/g'`
AC_OUTPUT()
AC_OUTPUT
AC_MSG_RESULT([

View File

@ -121,6 +121,35 @@ endif
endif
endif
ifneq (@ac_no_yuv@,1)
ifeq (@ac_external_yuv@,1)
APP_THIRD_PARTY_EXT += -lyuv
else
APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libyuv-$(LIB_SUFFIX)
ifeq ($(PJ_SHARED_LIBRARIES),)
APP_THIRD_PARTY_LIBS += -lyuv-$(TARGET_NAME)
else
APP_THIRD_PARTY_LIBS += -lyuv
APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libyuv.$(SHLIB_SUFFIX).$(PJ_VERSION_MAJOR) $(PJ_DIR)/third_party/lib/libyuv.$(SHLIB_SUFFIX)
endif
endif
endif
ifneq (@ac_no_webrtc@,1)
ifeq (@ac_external_webrtc@,1)
APP_THIRD_PARTY_EXT += -lwebrtc
else
APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libwebrtc-$(LIB_SUFFIX)
ifeq ($(PJ_SHARED_LIBRARIES),)
APP_THIRD_PARTY_LIBS += -lwebrtc-$(TARGET_NAME)
else
APP_THIRD_PARTY_LIBS += -lwebrtc
APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libwebrtc.$(SHLIB_SUFFIX).$(PJ_VERSION_MAJOR) $(PJ_DIR)/third_party/lib/libwebrtc.$(SHLIB_SUFFIX)
endif
endif
endif
# Additional flags
@ac_build_mak_vars@
@ -147,23 +176,21 @@ OPENH264_LDFLAGS = @ac_openh264_ldflags@
# QT
AC_PJMEDIA_VIDEO_HAS_QT = @ac_pjmedia_video_has_qt@
QT_CFLAGS = @ac_qt_cflags@
# QT_CFLAGS = @ac_qt_cflags@
# iOS
IOS_CFLAGS = @ac_ios_cflags@
# Darwin (Mac and iOS)
AC_PJMEDIA_VIDEO_HAS_DARWIN = @ac_pjmedia_video_has_darwin@
AC_PJMEDIA_VIDEO_HAS_IOS_OPENGL = @ac_pjmedia_video_has_ios_opengl@
DARWIN_CFLAGS = @ac_darwin_cflags@
# Android
ANDROID_CFLAGS = @ac_android_cflags@
# libyuv
LIBYUV_CFLAGS = @ac_libyuv_cflags@
LIBYUV_LDFLAGS = @ac_libyuv_ldflags@
# PJMEDIA features exclusion
PJ_VIDEO_CFLAGS += $(SDL_CFLAGS) $(FFMPEG_CFLAGS) $(V4L2_CFLAGS) $(QT_CFLAGS) \
$(OPENH264_CFLAGS) $(IOS_CFLAGS) $(LIBYUV_CFLAGS)
$(OPENH264_CFLAGS) $(DARWIN_CFLAGS)
PJ_VIDEO_LDFLAGS += $(SDL_LDFLAGS) $(FFMPEG_LDFLAGS) $(V4L2_LDFLAGS) \
$(OPENH264_LDFLAGS) $(LIBYUV_LDFLAGS)
$(OPENH264_LDFLAGS)
# CFLAGS, LDFLAGS, and LIBS to be used by applications
export APP_CC := @CC@

View File

@ -51,7 +51,7 @@ OBJDIRS := $(sort $(dir $(OBJS)))
#
# FULL_SRCS is ../src/app/file1.c ../src/app/file1.S
#
FULL_SRCS = $(foreach file, $($(APP)_OBJS), $(SRCDIR)/$(basename $(file)).m $(SRCDIR)/$(basename $(file)).c $(SRCDIR)/$(basename $(file)).cpp $(SRCDIR)/$(basename $(file)).S)
FULL_SRCS = $(foreach file, $($(APP)_OBJS), $(SRCDIR)/$(basename $(file)).m $(SRCDIR)/$(basename $(file)).c $(SRCDIR)/$(basename $(file)).cpp $(SRCDIR)/$(basename $(file)).cc $(SRCDIR)/$(basename $(file)).S)
#
# When generating dependency (gcc -MM), ideally we use only either
@ -174,6 +174,11 @@ $(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.cpp
$(CC_OUT)$(subst /,$(HOST_PSEP),$@) \
$(subst /,$(HOST_PSEP),$<)
$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.cc
$(CXX) $($(APP)_CXXFLAGS) \
$(CC_OUT)$(subst /,$(HOST_PSEP),$@) \
$(subst /,$(HOST_PSEP),$<)
$(OBJDIRS):
$(subst @@,$(subst /,$(HOST_PSEP),$@),$(HOST_MKDIR))

View File

@ -61,8 +61,14 @@ if test "$1" = "--use-ndk-cflags"; then
if test "x${IGNORE_CFLAGS}" = "x"; then
IGNORE_CFLAGS="\-M\|\-f*stack\|\-f*alias"
fi
if test -f ${ANDROID_NDK_ROOT}/build/ndk-build; then
NDK_BUILD=${ANDROID_NDK_ROOT}/build/ndk-build
else
NDK_BUILD=${ANDROID_NDK_ROOT}/ndk-build
fi
NDK_OUT=`${ANDROID_NDK_ROOT}/ndk-build -n -C ${ANDROID_NDK_ROOT}/samples/hello-jni NDK_TOOLCHAIN_VERSION=4.8 APP_PLATFORM=${APP_PLATFORM} APP_ABI=${TARGET_ABI}`
NDK_OUT=`${NDK_BUILD} -n -C pjsip-apps/src/samples/android_sample APP_PLATFORM=${APP_PLATFORM} APP_ABI=${TARGET_ABI}`
if test ! "${NDK_OUT}"; then
echo "$F error: failed to run ndk-build, check ANDROID_NDK_ROOT env var"
exit 1
@ -72,7 +78,7 @@ if test "$1" = "--use-ndk-cflags"; then
if test "x${NDK_CXX}" != "x" -a "$i" = "-o"; then break; fi
# Parse NDK CXXFLAGS
if test "x${NDK_CXX}" != "x" -a "x`echo $i|grep 'hello-jni'`" = "x"; then
if test "x${NDK_CXX}" != "x" -a "x`echo $i|grep 'dummy'`" = "x"; then
if test "x`echo $i|grep '\-\-sysroot='`" != "x"; then
ANDROID_SYSROOT=`echo $i|sed 's/--sysroot=//'`;
fi
@ -80,7 +86,7 @@ if test "$1" = "--use-ndk-cflags"; then
fi
# Parse NDK CFLAGS
if test "x${NDK_CC}" != "x" -a "x`echo $i|grep 'hello-jni'`" = "x" -a "${ADD_CFLAGS}" = "1"; then
if test "x${NDK_CC}" != "x" -a "x`echo $i|grep 'dummy'`" = "x" -a "${ADD_CFLAGS}" = "1"; then
if test "$i" = "-c"; then ADD_CFLAGS="0"; else
if test "x`echo $i|grep ${IGNORE_CFLAGS}`" = "x"; then
NDK_CFLAGS="${NDK_CFLAGS} $i"
@ -107,15 +113,16 @@ if test "$1" = "--use-ndk-cflags"; then
# Make sure target host string has 'linux-android' in it
if test "x`echo ${TARGET_HOST} | grep 'linux-android'`" = "x"; then
#TARGET_HOST=`echo ${TARGET_HOST} | sed -e 's/\(.*\)\-\([0-9\.]*\)/\1-linux-android-\2/'`
TARGET_HOST+=-linux-android
TARGET_HOST="${TARGET_HOST}-linux-android"
fi
export TARGET_ABI="${TARGET_ABI}"
export CC="${NDK_CC}"
export CXX="${NDK_CXX}"
export AR=`echo ${NDK_CXX}|sed 's/-g++/-ar/'`;
export RANLIB=`echo ${NDK_CXX}|sed 's/-g++/-ranlib/'`;
export LDFLAGS="${LDFLAGS} -nostdlib -L${ANDROID_SYSROOT}${USR_LIB}"
export LDFLAGS="${LDFLAGS} --sysroot=${ANDROID_SYSROOT}"
export LIBS="${LIBS} -lc -lgcc -ldl"
export CFLAGS="${NDK_CFLAGS} ${CFLAGS}"
export CPPFLAGS="${CFLAGS} -fexceptions -frtti"
@ -143,14 +150,15 @@ else
exit 1
fi
export TARGET_ABI="${TARGET_ABI}"
export CC="${ANDROID_TC}/bin/${TARGET_HOST}-gcc"
export CXX="${ANDROID_TC}/bin/${TARGET_HOST}-g++"
export AR="${ANDROID_TC}/bin/${TARGET_HOST}-ar"
export RANLIB="${ANDROID_TC}/bin/${TARGET_HOST}-ranlib"
export LDFLAGS="${LDFLAGS} -nostdlib -L${ANDROID_SYSROOT}${USR_LIB}"
export LDFLAGS="${LDFLAGS} --sysroot=${ANDROID_SYSROOT}"
export LIBS="${LIBS} -lc -lgcc"
export CFLAGS="${CFLAGS} -I${ANDROID_SYSROOT}/usr/include"
export CFLAGS="${CFLAGS} --sysroot=${ANDROID_SYSROOT}"
export CPPFLAGS="${CFLAGS} -fexceptions -frtti"
export CXXFLAGS="${CXXFLAGS} -shared --sysroot=${ANDROID_SYSROOT} -fexceptions -frtti"
@ -167,12 +175,12 @@ fi
# gnustl
STDCPP_TC_VER=`ls -d ${ANDROID_NDK_ROOT}/sources/cxx-stl/gnu-libstdc++/[0-9]* | sort -gr | head -1`
STDCPP_CFLAGS="-I${STDCPP_TC_VER}/include -I${STDCPP_TC_VER}/libs/${TARGET_ABI}/include"
STDCPP_LIBS="${ANDROID_SYSROOT}${USR_LIB}/crtbegin_so.o -lgnustl_static"
STDCPP_LIBS="-lgnustl_static"
STDCPP_LDFLAGS="-L${STDCPP_TC_VER}/libs/${TARGET_ABI}/"
# stlport
#STDCPP_CFLAGS="-I${ANDROID_NDK_ROOT}/sources/cxx-stl/stlport/stlport"
#STDCPP_LIBS="${ANDROID_SYSROOT}${USR_LIB}/crtbegin_so.o -lstlport_static -ldl"
#STDCPP_LIBS="-lstlport_static -ldl"
#STDCPP_LDFLAGS="-L${ANDROID_NDK_ROOT}/sources/cxx-stl/stlport/libs/${TARGET_ABI}"
export CFLAGS="${CFLAGS} ${STDCPP_CFLAGS}"
@ -191,6 +199,7 @@ if test "1" = "1"; then
echo " AR = ${AR}"
echo " RANLIB = ${RANLIB}"
echo " TARGET_HOST = ${TARGET_HOST}"
echo " TARGET_ABI = ${TARGET_ABI}"
fi
./configure --host=${TARGET_HOST} $*

View File

@ -18,7 +18,10 @@ if test "$*" = "--help" -o "$*" = "-h"; then
echo " to use. By default, the compiler is deduced from the"
echo " SDK."
echo " ARCH Optional flags to specify target architecture, e.g."
echo " ARCH='-arch armv6'. Default is armv7."
echo " ARCH=\"-arch armv6\". Default is armv7."
echo " MIN_IOS Optional flags to specify minimum supported iOS"
echo " versions, e.g. MIN_IOS=\"-miphoneos-version-min=10.0\". "
echo " Default is 7.0."
echo ""
exit 0
fi
@ -115,6 +118,13 @@ if test "${ARCH}" = ""; then
fi
export ARCH_VAL=`echo ${ARCH} | sed 's/\-arch //' | sed -e 's/^[ \t]*//;s/[ \t]*$//' `
if test "${MIN_IOS}" = ""; then
MIN_IOS="7.0"
echo "$F: MIN_IOS is not specified, choosing ${MIN_IOS}"
CFLAGS="${CFLAGS} -miphoneos-version-min=${MIN_IOS}"
LDFLAGS="${LDFLAGS} -miphoneos-version-min=${MIN_IOS}"
fi
# Set CXX if not set
if test "${CXX}" = ""; then
export CXX=`echo ${CC} | sed 's/gcc/g++/'`

View File

@ -94,7 +94,7 @@ typedef struct pj_cli_telnet_cfg
/**
* Specify a password to be asked to the end user to access the
* application.
* application. Currently this is not implemented yet.
*
* Default: empty (no password)
*/
@ -102,6 +102,7 @@ typedef struct pj_cli_telnet_cfg
/**
* Specify text message to be displayed to newly connected users.
* Currently this is not implemented yet.
*
* Default: empty
*/

View File

@ -426,6 +426,22 @@ PJ_DECL(void) pj_dns_init_a_rr(pj_dns_parsed_rr *rec,
unsigned ttl,
const pj_in_addr *ip_addr);
/**
* Initialize DNS record as DNS AAAA record.
*
* @param rec The DNS resource record to be initialized as DNS
* AAAA record.
* @param res_name Resource name.
* @param dnsclass DNS class.
* @param ttl Resource TTL value.
* @param ip_addr Host address.
*/
PJ_DECL(void) pj_dns_init_aaaa_rr(pj_dns_parsed_rr *rec,
const pj_str_t *res_name,
unsigned dnsclass,
unsigned ttl,
const pj_in6_addr *ip_addr);
/**
* Dump DNS packet to standard log.
*

View File

@ -225,6 +225,47 @@ typedef struct pj_dns_a_record
} pj_dns_a_record;
/**
* This structure represents DNS address record, i.e: DNS A and DNS AAAA
* records, as the result of parsing DNS response packet using
* #pj_dns_parse_addr_response().
*/
typedef struct pj_dns_addr_record
{
/** The target name being queried. */
pj_str_t name;
/** If target name corresponds to a CNAME entry, the alias contains
* the value of the CNAME entry, otherwise it will be empty.
*/
pj_str_t alias;
/** Number of IP addresses. */
unsigned addr_count;
/** IP addresses of the host found in the response */
struct {
/** IP address family */
int af;
/** IP address */
union {
/** IPv4 address */
pj_in_addr v4;
/** IPv6 address */
pj_in6_addr v6;
} ip;
} addr[PJ_DNS_MAX_IP_IN_A_REC];
/** Internal buffer for hostname and alias. */
char buf_[128];
} pj_dns_addr_record;
/**
* Set default values to the DNS settings.
*
@ -407,6 +448,21 @@ PJ_DECL(pj_status_t) pj_dns_parse_a_response(const pj_dns_parsed_packet *pkt,
pj_dns_a_record *rec);
/**
* A utility function to parse a DNS response containing AAAA records into
* DNS AAAA record.
*
* @param pkt The DNS response packet.
* @param rec The structure to be initialized with the parsed
* DNS AAAA record from the packet.
*
* @return PJ_SUCCESS if response can be parsed successfully.
*/
PJ_DECL(pj_status_t) pj_dns_parse_addr_response(
const pj_dns_parsed_packet *pkt,
pj_dns_addr_record *rec);
/**
* Put the specified DNS packet into DNS cache. This function is mainly used
* for testing the resolver, however it can also be used to inject entries

View File

@ -84,27 +84,34 @@ typedef enum pj_dns_srv_option
* Specify if the resolver should fallback with DNS A
* resolution when the SRV resolution fails. This option may
* be specified together with PJ_DNS_SRV_FALLBACK_AAAA to
* make the resolver fallback to AAAA if SRV resolution fails,
* and then to DNS A resolution if the AAAA resolution fails.
* make the resolver fallback to both DNS A and DNS AAAA
* resolutions if SRV resolution fails.
*/
PJ_DNS_SRV_FALLBACK_A = 1,
/**
* Specify if the resolver should fallback with DNS AAAA
* resolution when the SRV resolution fails. This option may
* be specified together with PJ_DNS_SRV_FALLBACK_A to
* make the resolver fallback to AAAA if SRV resolution fails,
* and then to DNS A resolution if the AAAA resolution fails.
* be specified together with PJ_DNS_SRV_FALLBACK_AAAA to
* make the resolver fallback to both DNS A and DNS AAAA
* resolutions if SRV resolution fails.
*/
PJ_DNS_SRV_FALLBACK_AAAA = 2,
/**
* Specify if the resolver should try to resolve with DNS AAAA
* resolution first of each targets in the DNS SRV record. If
* this option is not specified, the SRV resolver will query
* the DNS A record for the target instead.
* resolution of each targets in the DNS SRV record. If this
* option is not specified, the SRV resolver will query the
* DNS A record for the target instead.
*/
PJ_DNS_SRV_RESOLVE_AAAA = 4
PJ_DNS_SRV_RESOLVE_AAAA = 4,
/**
* Specify if the resolver should try to resolve with DNS AAAA
* resolution only (i.e: without DNS A resolution) for each targets
* in the DNS SRV record.
*/
PJ_DNS_SRV_RESOLVE_AAAA_ONLY = 8
} pj_dns_srv_option;
@ -131,7 +138,7 @@ typedef struct pj_dns_srv_record
pj_uint16_t port;
/** The host address. */
pj_dns_a_record server;
pj_dns_addr_record server;
} entry[PJ_DNS_SRV_MAX_ADDR];

View File

@ -191,6 +191,20 @@ static int print_rr(pj_uint8_t *pkt, int size, pj_uint8_t *pos,
p += 6;
size -= 6;
} else if (rr->type == PJ_DNS_TYPE_AAAA) {
if (size < 18)
return -1;
/* RDLEN is 16 */
write16(p, 16);
/* Address */
pj_memcpy(p+2, &rr->rdata.aaaa.ip_addr, 16);
p += 18;
size -= 18;
} else if (rr->type == PJ_DNS_TYPE_CNAME ||
rr->type == PJ_DNS_TYPE_NS ||
rr->type == PJ_DNS_TYPE_PTR) {
@ -330,7 +344,7 @@ static int server_thread(void *p)
while (!thread_quit) {
pj_fd_set_t rset;
pj_time_val timeout = {0, 500};
pj_sockaddr_in src_addr;
pj_sockaddr src_addr;
pj_dns_parsed_packet *req;
char pkt[1024];
pj_ssize_t pkt_len;
@ -405,16 +419,21 @@ static int poll_worker_thread(void *p)
static void destroy(void);
static int init(void)
static int init(pj_bool_t use_ipv6)
{
pj_status_t status;
pj_str_t nameservers[2];
pj_uint16_t ports[2];
int i;
nameservers[0] = pj_str("127.0.0.1");
if (use_ipv6) {
nameservers[0] = pj_str("::1");
nameservers[1] = pj_str("::1");
} else {
nameservers[0] = pj_str("127.0.0.1");
nameservers[1] = pj_str("127.0.0.1");
}
ports[0] = 5553;
nameservers[1] = pj_str("127.0.0.1");
ports[1] = 5554;
g_server[0].port = ports[0];
@ -425,16 +444,20 @@ static int init(void)
status = pj_sem_create(pool, NULL, 0, 2, &sem);
pj_assert(status == PJ_SUCCESS);
for (i=0; i<2; ++i) {
pj_sockaddr_in addr;
thread_quit = PJ_FALSE;
status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &g_server[i].sock);
for (i=0; i<2; ++i) {
pj_sockaddr addr;
status = pj_sock_socket((use_ipv6? pj_AF_INET6() : pj_AF_INET()),
pj_SOCK_DGRAM(), 0, &g_server[i].sock);
if (status != PJ_SUCCESS)
return -10;
pj_sockaddr_in_init(&addr, NULL, (pj_uint16_t)g_server[i].port);
pj_sockaddr_init((use_ipv6? pj_AF_INET6() : pj_AF_INET()),
&addr, NULL, (pj_uint16_t)g_server[i].port);
status = pj_sock_bind(g_server[i].sock, &addr, sizeof(addr));
status = pj_sock_bind(g_server[i].sock, &addr, pj_sockaddr_get_len(&addr));
if (status != PJ_SUCCESS)
return -20;
@ -692,6 +715,215 @@ static int a_parser_test(void)
}
////////////////////////////////////////////////////////////////////////////
/* DNS A/AAAA parser tests */
static int addr_parser_test(void)
{
pj_dns_parsed_packet pkt;
pj_dns_addr_record rec;
pj_status_t rc;
PJ_LOG(3,(THIS_FILE, " DNS A/AAAA record parser tests"));
pkt.q = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_query);
pkt.ans = (pj_dns_parsed_rr*)
pj_pool_calloc(pool, 32, sizeof(pj_dns_parsed_rr));
/* Simple answer with direct A record, but with addition of
* a CNAME and another A to confuse the parser.
*/
PJ_LOG(3,(THIS_FILE, " A RR with duplicate CNAME/A"));
pkt.hdr.flags = 0;
pkt.hdr.qdcount = 1;
pkt.q[0].type = PJ_DNS_TYPE_A;
pkt.q[0].dnsclass = 1;
pkt.q[0].name = pj_str("ahost");
pkt.hdr.anscount = 4;
/* This is the RR corresponding to the query */
pkt.ans[0].name = pj_str("ahost");
pkt.ans[0].type = PJ_DNS_TYPE_A;
pkt.ans[0].dnsclass = 1;
pkt.ans[0].ttl = 1;
pkt.ans[0].rdata.a.ip_addr.s_addr = 0x01020304;
/* CNAME to confuse the parser */
pkt.ans[1].name = pj_str("ahost");
pkt.ans[1].type = PJ_DNS_TYPE_CNAME;
pkt.ans[1].dnsclass = 1;
pkt.ans[1].ttl = 1;
pkt.ans[1].rdata.cname.name = pj_str("bhost");
/* DNS A RR to confuse the parser */
pkt.ans[2].name = pj_str("bhost");
pkt.ans[2].type = PJ_DNS_TYPE_A;
pkt.ans[2].dnsclass = 1;
pkt.ans[2].ttl = 1;
pkt.ans[2].rdata.a.ip_addr.s_addr = 0x0203;
/* Additional RR corresponding to the query, DNS AAAA RR */
pkt.ans[3].name = pj_str("ahost");
pkt.ans[3].type = PJ_DNS_TYPE_AAAA;
pkt.ans[3].dnsclass = 1;
pkt.ans[3].ttl = 1;
pkt.ans[3].rdata.aaaa.ip_addr.u6_addr32[0] = 0x01020304;
rc = pj_dns_parse_addr_response(&pkt, &rec);
pj_assert(rc == PJ_SUCCESS);
pj_assert(pj_strcmp2(&rec.name, "ahost")==0);
pj_assert(rec.alias.slen == 0);
pj_assert(rec.addr_count == 2);
pj_assert(rec.addr[0].af==pj_AF_INET() && rec.addr[0].ip.v4.s_addr == 0x01020304);
pj_assert(rec.addr[1].af==pj_AF_INET6() && rec.addr[1].ip.v6.u6_addr32[0] == 0x01020304);
/* Answer with the target corresponds to a CNAME entry, but not
* as the first record, and with additions of some CNAME and A
* entries to confuse the parser.
*/
PJ_LOG(3,(THIS_FILE, " CNAME RR with duplicate CNAME/A"));
pkt.hdr.flags = 0;
pkt.hdr.qdcount = 1;
pkt.q[0].type = PJ_DNS_TYPE_A;
pkt.q[0].dnsclass = 1;
pkt.q[0].name = pj_str("ahost");
pkt.hdr.anscount = 4;
/* This is the DNS A record for the alias */
pkt.ans[0].name = pj_str("ahostalias");
pkt.ans[0].type = PJ_DNS_TYPE_A;
pkt.ans[0].dnsclass = 1;
pkt.ans[0].ttl = 1;
pkt.ans[0].rdata.a.ip_addr.s_addr = 0x02020202;
/* CNAME entry corresponding to the query */
pkt.ans[1].name = pj_str("ahost");
pkt.ans[1].type = PJ_DNS_TYPE_CNAME;
pkt.ans[1].dnsclass = 1;
pkt.ans[1].ttl = 1;
pkt.ans[1].rdata.cname.name = pj_str("ahostalias");
/* Another CNAME to confuse the parser */
pkt.ans[2].name = pj_str("ahost");
pkt.ans[2].type = PJ_DNS_TYPE_CNAME;
pkt.ans[2].dnsclass = 1;
pkt.ans[2].ttl = 1;
pkt.ans[2].rdata.cname.name = pj_str("ahostalias2");
/* Another DNS A to confuse the parser */
pkt.ans[3].name = pj_str("ahostalias2");
pkt.ans[3].type = PJ_DNS_TYPE_A;
pkt.ans[3].dnsclass = 1;
pkt.ans[3].ttl = 1;
pkt.ans[3].rdata.a.ip_addr.s_addr = 0x03030303;
rc = pj_dns_parse_addr_response(&pkt, &rec);
pj_assert(rc == PJ_SUCCESS);
pj_assert(pj_strcmp2(&rec.name, "ahost")==0);
pj_assert(pj_strcmp2(&rec.alias, "ahostalias")==0);
pj_assert(rec.addr_count == 1);
pj_assert(rec.addr[0].ip.v4.s_addr == 0x02020202);
/*
* No query section.
*/
PJ_LOG(3,(THIS_FILE, " No query section"));
pkt.hdr.qdcount = 0;
pkt.hdr.anscount = 0;
rc = pj_dns_parse_addr_response(&pkt, &rec);
pj_assert(rc == PJLIB_UTIL_EDNSINANSWER);
/*
* No answer section.
*/
PJ_LOG(3,(THIS_FILE, " No answer section"));
pkt.hdr.flags = 0;
pkt.hdr.qdcount = 1;
pkt.q[0].type = PJ_DNS_TYPE_A;
pkt.q[0].dnsclass = 1;
pkt.q[0].name = pj_str("ahost");
pkt.hdr.anscount = 0;
rc = pj_dns_parse_addr_response(&pkt, &rec);
pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC);
/*
* Answer doesn't match query.
*/
PJ_LOG(3,(THIS_FILE, " Answer doesn't match query"));
pkt.hdr.flags = 0;
pkt.hdr.qdcount = 1;
pkt.q[0].type = PJ_DNS_TYPE_A;
pkt.q[0].dnsclass = 1;
pkt.q[0].name = pj_str("ahost");
pkt.hdr.anscount = 1;
/* An answer that doesn't match the query */
pkt.ans[0].name = pj_str("ahostalias");
pkt.ans[0].type = PJ_DNS_TYPE_A;
pkt.ans[0].dnsclass = 1;
pkt.ans[0].ttl = 1;
pkt.ans[0].rdata.a.ip_addr.s_addr = 0x02020202;
rc = pj_dns_parse_addr_response(&pkt, &rec);
pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC);
/*
* DNS CNAME that doesn't have corresponding DNS A.
*/
PJ_LOG(3,(THIS_FILE, " CNAME with no matching DNS A RR (1)"));
pkt.hdr.flags = 0;
pkt.hdr.qdcount = 1;
pkt.q[0].type = PJ_DNS_TYPE_A;
pkt.q[0].dnsclass = 1;
pkt.q[0].name = pj_str("ahost");
pkt.hdr.anscount = 1;
/* The CNAME */
pkt.ans[0].name = pj_str("ahost");
pkt.ans[0].type = PJ_DNS_TYPE_CNAME;
pkt.ans[0].dnsclass = 1;
pkt.ans[0].ttl = 1;
pkt.ans[0].rdata.cname.name = pj_str("ahostalias");
rc = pj_dns_parse_addr_response(&pkt, &rec);
pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC);
/*
* DNS CNAME that doesn't have corresponding DNS A.
*/
PJ_LOG(3,(THIS_FILE, " CNAME with no matching DNS A RR (2)"));
pkt.hdr.flags = 0;
pkt.hdr.qdcount = 1;
pkt.q[0].type = PJ_DNS_TYPE_A;
pkt.q[0].dnsclass = 1;
pkt.q[0].name = pj_str("ahost");
pkt.hdr.anscount = 2;
/* The CNAME */
pkt.ans[0].name = pj_str("ahost");
pkt.ans[0].type = PJ_DNS_TYPE_CNAME;
pkt.ans[0].dnsclass = 1;
pkt.ans[0].ttl = 1;
pkt.ans[0].rdata.cname.name = pj_str("ahostalias");
/* DNS A record, but the name doesn't match */
pkt.ans[1].name = pj_str("ahost");
pkt.ans[1].type = PJ_DNS_TYPE_A;
pkt.ans[1].dnsclass = 1;
pkt.ans[1].ttl = 1;
pkt.ans[1].rdata.a.ip_addr.s_addr = 0x01020304;
rc = pj_dns_parse_addr_response(&pkt, &rec);
pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC);
return 0;
}
////////////////////////////////////////////////////////////////////////////
/* Simple DNS test */
#define IP_ADDR0 0x00010203
@ -1005,6 +1237,27 @@ static void action1_1(const pj_dns_parsed_packet *pkt,
res->ans[1].ttl = 1;
res->ans[1].name = pj_str(alias);
res->ans[1].rdata.a.ip_addr.s_addr = IP_ADDR1;
} else if (pkt->q[0].type == PJ_DNS_TYPE_AAAA) {
char *alias = "sipalias.somedomain.com";
pj_assert(pj_strcmp2(&res->q[0].name, target)==0);
res->hdr.anscount = 2;
res->ans[0].type = PJ_DNS_TYPE_CNAME;
res->ans[0].dnsclass = 1;
res->ans[0].ttl = 1000; /* resolver should select minimum TTL */
res->ans[0].name = res->q[0].name;
res->ans[0].rdata.cname.name = pj_str(alias);
res->ans[1].type = PJ_DNS_TYPE_AAAA;
res->ans[1].dnsclass = 1;
res->ans[1].ttl = 1;
res->ans[1].name = pj_str(alias);
res->ans[1].rdata.aaaa.ip_addr.u6_addr32[0] = IP_ADDR1;
res->ans[1].rdata.aaaa.ip_addr.u6_addr32[1] = IP_ADDR1;
res->ans[1].rdata.aaaa.ip_addr.u6_addr32[2] = IP_ADDR1;
res->ans[1].rdata.aaaa.ip_addr.u6_addr32[3] = IP_ADDR1;
}
*p_res = res;
@ -1026,12 +1279,16 @@ static void srv_cb_1(void *user_data,
return);
PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.alias, "sipalias.somedomain.com")==0,
return);
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr[0].s_addr == IP_ADDR1, return);
/* IPv4 only */
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr_count == 1, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr[0].ip.v4.s_addr == IP_ADDR1, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].port == PORT1, return);
}
static void srv_cb_1b(void *user_data,
pj_status_t status,
const pj_dns_srv_record *rec)
@ -1045,6 +1302,61 @@ static void srv_cb_1b(void *user_data,
PJ_ASSERT_ON_FAIL(rec->count == 0, return);
}
static void srv_cb_1c(void *user_data,
pj_status_t status,
const pj_dns_srv_record *rec)
{
PJ_UNUSED_ARG(user_data);
pj_sem_post(sem);
PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return);
PJ_ASSERT_ON_FAIL(rec->count == 1, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].priority == 1, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].weight == 2, return);
PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.name, "sip.somedomain.com")==0,
return);
PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.alias, "sipalias.somedomain.com")==0,
return);
PJ_ASSERT_ON_FAIL(rec->entry[0].port == PORT1, return);
/* IPv4 and IPv6 */
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr_count == 2, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr[0].af == pj_AF_INET() &&
rec->entry[0].server.addr[0].ip.v4.s_addr == IP_ADDR1, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr[1].af == pj_AF_INET6() &&
rec->entry[0].server.addr[1].ip.v6.u6_addr32[0] == IP_ADDR1, return);
}
static void srv_cb_1d(void *user_data,
pj_status_t status,
const pj_dns_srv_record *rec)
{
PJ_UNUSED_ARG(user_data);
pj_sem_post(sem);
PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return);
PJ_ASSERT_ON_FAIL(rec->count == 1, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].priority == 1, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].weight == 2, return);
PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.name, "sip.somedomain.com")==0,
return);
PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.alias, "sipalias.somedomain.com")==0,
return);
PJ_ASSERT_ON_FAIL(rec->entry[0].port == PORT1, return);
/* IPv6 only */
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr_count == 1, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr[0].af == pj_AF_INET6() &&
rec->entry[0].server.addr[0].ip.v6.u6_addr32[0] == IP_ADDR1, return);
}
static int srv_resolver_test(void)
{
pj_status_t status;
@ -1078,6 +1390,48 @@ static int srv_resolver_test(void)
pj_thread_sleep(1000 +
((set.qretr_count + 2) * set.qretr_delay));
/* DNS SRV option PJ_DNS_SRV_RESOLVE_AAAA */
PJ_LOG(3,(THIS_FILE, " srv_resolve(): option PJ_DNS_SRV_RESOLVE_AAAA"));
g_server[0].action = ACTION_CB;
g_server[0].action_cb = &action1_1;
g_server[1].action = ACTION_CB;
g_server[1].action_cb = &action1_1;
g_server[0].pkt_count = 0;
g_server[1].pkt_count = 0;
status = pj_dns_srv_resolve(&domain, &res_name, 5061, pool, resolver,
PJ_DNS_SRV_RESOLVE_AAAA,
NULL, &srv_cb_1c, NULL);
pj_assert(status == PJ_SUCCESS);
pj_sem_wait(sem);
pj_thread_sleep(1000);
/* DNS SRV option PJ_DNS_SRV_RESOLVE_AAAA_ONLY */
PJ_LOG(3,(THIS_FILE, " srv_resolve(): option PJ_DNS_SRV_RESOLVE_AAAA_ONLY"));
g_server[0].action = ACTION_CB;
g_server[0].action_cb = &action1_1;
g_server[1].action = ACTION_CB;
g_server[1].action_cb = &action1_1;
g_server[0].pkt_count = 0;
g_server[1].pkt_count = 0;
status = pj_dns_srv_resolve(&domain, &res_name, 5061, pool, resolver,
PJ_DNS_SRV_RESOLVE_AAAA_ONLY,
NULL, &srv_cb_1d, NULL);
pj_assert(status == PJ_SUCCESS);
pj_sem_wait(sem);
pj_thread_sleep(1000);
/* Successful scenario */
PJ_LOG(3,(THIS_FILE, " srv_resolve(): parallel queries"));
g_server[0].pkt_count = 0;
@ -1102,7 +1456,6 @@ static int srv_resolver_test(void)
/* Since TTL is one, subsequent queries should fail */
PJ_LOG(3,(THIS_FILE, " srv_resolve(): cache expires scenario"));
pj_thread_sleep(1000);
g_server[0].action = PJ_DNS_RCODE_NXDOMAIN;
@ -1114,6 +1467,7 @@ static int srv_resolver_test(void)
pj_sem_wait(sem);
return 0;
}
@ -1171,6 +1525,27 @@ static void action2_1(const pj_dns_parsed_packet *pkt,
res->ans[1].name = pj_str(alias);
res->ans[1].ttl = 1;
res->ans[1].rdata.a.ip_addr.s_addr = IP_ADDR2;
} else if (pkt->q[0].type == PJ_DNS_TYPE_AAAA) {
char *alias = "sipalias01." TARGET;
pj_assert(pj_strcmp2(&res->q[0].name, TARGET)==0);
res->hdr.anscount = 2;
res->ans[0].type = PJ_DNS_TYPE_CNAME;
res->ans[0].dnsclass = 1;
res->ans[0].name = res->q[0].name;
res->ans[0].ttl = 1;
res->ans[0].rdata.cname.name = pj_str(alias);
res->ans[1].type = PJ_DNS_TYPE_AAAA;
res->ans[1].dnsclass = 1;
res->ans[1].ttl = 1;
res->ans[1].name = pj_str(alias);
res->ans[1].rdata.aaaa.ip_addr.u6_addr32[0] = IP_ADDR2;
res->ans[1].rdata.aaaa.ip_addr.u6_addr32[1] = IP_ADDR2;
res->ans[1].rdata.aaaa.ip_addr.u6_addr32[2] = IP_ADDR2;
res->ans[1].rdata.aaaa.ip_addr.u6_addr32[3] = IP_ADDR2;
}
*p_res = res;
@ -1192,8 +1567,62 @@ static void srv_cb_2(void *user_data,
return);
PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.alias, "sipalias01." TARGET)==0,
return);
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr[0].s_addr == IP_ADDR2, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].port == PORT2, return);
/* IPv4 only */
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr_count == 1, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr[0].af == pj_AF_INET() &&
rec->entry[0].server.addr[0].ip.v4.s_addr == IP_ADDR2, return);
}
static void srv_cb_2a(void *user_data,
pj_status_t status,
const pj_dns_srv_record *rec)
{
PJ_UNUSED_ARG(user_data);
pj_sem_post(sem);
PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return);
PJ_ASSERT_ON_FAIL(rec->count == 1, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].priority == 0, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].weight == 0, return);
PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.name, TARGET)==0,
return);
PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.alias, "sipalias01." TARGET)==0,
return);
PJ_ASSERT_ON_FAIL(rec->entry[0].port == PORT2, return);
/* IPv4 and IPv6 */
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr_count == 2, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr[0].af == pj_AF_INET() &&
rec->entry[0].server.addr[0].ip.v4.s_addr == IP_ADDR2, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr[1].af == pj_AF_INET6() &&
rec->entry[0].server.addr[1].ip.v6.u6_addr32[0] == IP_ADDR2, return);
}
static void srv_cb_2b(void *user_data,
pj_status_t status,
const pj_dns_srv_record *rec)
{
PJ_UNUSED_ARG(user_data);
pj_sem_post(sem);
PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return);
PJ_ASSERT_ON_FAIL(rec->count == 1, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].priority == 0, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].weight == 0, return);
PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.name, TARGET)==0,
return);
PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.alias, "sipalias01." TARGET)==0,
return);
PJ_ASSERT_ON_FAIL(rec->entry[0].port == PORT2, return);
/* IPv6 only */
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr_count == 1, return);
PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr[0].af == pj_AF_INET6() &&
rec->entry[0].server.addr[0].ip.v6.u6_addr32[0] == IP_ADDR2, return);
}
static int srv_resolver_fallback_test(void)
@ -1202,6 +1631,7 @@ static int srv_resolver_fallback_test(void)
pj_str_t domain = pj_str(TARGET);
pj_str_t res_name = pj_str("_sip._udp.");
/* Fallback test */
PJ_LOG(3,(THIS_FILE, " srv_resolve(): fallback test"));
g_server[0].action = ACTION_CB;
@ -1235,6 +1665,51 @@ static int srv_resolver_fallback_test(void)
pj_assert(g_server[0].pkt_count == 0);
pj_assert(g_server[1].pkt_count == 0);
/* Clear cache */
pj_thread_sleep(1000);
/* Fallback with PJ_DNS_SRV_FALLBACK_A and PJ_DNS_SRV_FALLBACK_AAAA */
PJ_LOG(3,(THIS_FILE, " srv_resolve(): fallback to DNS A and AAAA"));
g_server[0].action = ACTION_CB;
g_server[0].action_cb = &action2_1;
g_server[1].action = ACTION_CB;
g_server[1].action_cb = &action2_1;
status = pj_dns_srv_resolve(&domain, &res_name, PORT2, pool, resolver,
PJ_DNS_SRV_FALLBACK_A | PJ_DNS_SRV_FALLBACK_AAAA,
NULL, &srv_cb_2a, NULL);
if (status != PJ_SUCCESS) {
app_perror(" srv_resolve error", status);
pj_assert(status == PJ_SUCCESS);
}
pj_sem_wait(sem);
/* Clear cache */
pj_thread_sleep(1000);
/* Fallback with PJ_DNS_SRV_FALLBACK_AAAA only */
PJ_LOG(3,(THIS_FILE, " srv_resolve(): fallback to DNS AAAA only"));
g_server[0].action = ACTION_CB;
g_server[0].action_cb = &action2_1;
g_server[1].action = ACTION_CB;
g_server[1].action_cb = &action2_1;
status = pj_dns_srv_resolve(&domain, &res_name, PORT2, pool, resolver,
PJ_DNS_SRV_FALLBACK_AAAA,
NULL, &srv_cb_2b, NULL);
if (status != PJ_SUCCESS) {
app_perror(" srv_resolve error", status);
pj_assert(status == PJ_SUCCESS);
}
pj_sem_wait(sem);
/* Clear cache */
pj_thread_sleep(1000);
return 0;
}
@ -1333,7 +1808,7 @@ static void srv_cb_3(void *user_data,
pj_assert(rec->entry[i].server.addr_count == PJ_DNS_MAX_IP_IN_A_REC);
for (j=0; j<PJ_DNS_MAX_IP_IN_A_REC; ++j) {
pj_assert(rec->entry[i].server.addr[j].s_addr == IP_ADDR3+j);
pj_assert(rec->entry[i].server.addr[j].ip.v4.s_addr == IP_ADDR3+j);
}
}
@ -1374,7 +1849,7 @@ int resolver_test(void)
{
int rc;
rc = init();
rc = init(PJ_FALSE);
if (rc != 0)
goto on_error;
@ -1382,6 +1857,10 @@ int resolver_test(void)
if (rc != 0)
goto on_error;
rc = addr_parser_test();
if (rc != 0)
goto on_error;
rc = simple_test();
if (rc != 0)
goto on_error;
@ -1395,6 +1874,31 @@ int resolver_test(void)
srv_resolver_many_test();
destroy();
#if PJ_HAS_IPV6
/* Similar tests using IPv6 socket and without parser tests */
PJ_LOG(3,(THIS_FILE, "Re-run DNS resolution tests using IPv6 socket"));
rc = init(PJ_TRUE);
if (rc != 0)
goto on_error;
rc = simple_test();
if (rc != 0)
goto on_error;
rc = dns_test();
if (rc != 0)
goto on_error;
srv_resolver_test();
srv_resolver_fallback_test();
srv_resolver_many_test();
destroy();
#endif
return 0;
on_error:
@ -1402,4 +1906,3 @@ on_error:
return rc;
}

View File

@ -1373,7 +1373,7 @@ static void telnet_fe_write_log(pj_cli_front_end *fe, int level,
cli_telnet_sess *tsess = (cli_telnet_sess *)sess;
sess = sess->next;
if (tsess->base.log_level > level) {
if (tsess->base.log_level >= level) {
pj_str_t s;
pj_strset(&s, (char *)data, len);
@ -1928,7 +1928,8 @@ PJ_DEF(pj_status_t) pj_cli_telnet_get_info(pj_cli_front_end *fe,
if (status != PJ_SUCCESS)
return status;
pj_strcpy2(&info->ip_address, pj_inet_ntoa(hostip.ipv4.sin_addr));
pj_sockaddr_print(&hostip, info->buf_, sizeof(info->buf_), 0);
pj_strset2(&info->ip_address, info->buf_);
info->port = tfe->cfg.port;

View File

@ -749,3 +749,18 @@ PJ_DEF(void) pj_dns_init_a_rr( pj_dns_parsed_rr *rec,
rec->rdata.a.ip_addr = *ip_addr;
}
PJ_DEF(void) pj_dns_init_aaaa_rr(pj_dns_parsed_rr *rec,
const pj_str_t *res_name,
unsigned dnsclass,
unsigned ttl,
const pj_in6_addr *ip_addr)
{
pj_bzero(rec, sizeof(*rec));
rec->name = *res_name;
rec->type = PJ_DNS_TYPE_AAAA;
rec->dnsclass = (pj_uint16_t) dnsclass;
rec->ttl = ttl;
rec->rdata.aaaa.ip_addr = *ip_addr;
}

View File

@ -90,6 +90,7 @@ static void dump_answer(unsigned index, const pj_dns_parsed_rr *rr)
const pj_str_t root_name = { "<Root>", 6 };
const pj_str_t *name = &rr->name;
char ttl_words[32];
char addr[PJ_INET6_ADDRSTRLEN];
if (name->slen == 0)
name = &root_name;
@ -117,9 +118,9 @@ static void dump_answer(unsigned index, const pj_dns_parsed_rr *rr)
rr->rdata.cname.name.ptr));
} else if (rr->type == PJ_DNS_TYPE_A) {
PJ_LOG(3,(THIS_FILE, " IP address: %s",
pj_inet_ntoa(rr->rdata.a.ip_addr)));
pj_inet_ntop2(pj_AF_INET(), &rr->rdata.a.ip_addr,
addr, sizeof(addr))));
} else if (rr->type == PJ_DNS_TYPE_AAAA) {
char addr[PJ_INET6_ADDRSTRLEN];
PJ_LOG(3,(THIS_FILE, " IPv6 address: %s",
pj_inet_ntop2(pj_AF_INET6(), &rr->rdata.aaaa.ip_addr,
addr, sizeof(addr))));
@ -170,7 +171,7 @@ PJ_DEF(void) pj_dns_dump_packet(const pj_dns_parsed_packet *res)
}
/* Dump NS sections */
if (res->hdr.anscount) {
if (res->hdr.nscount) {
PJ_LOG(3,(THIS_FILE, " NS Authority RR:"));
for (i=0; i<res->hdr.nscount; ++i) {

View File

@ -311,6 +311,20 @@ static int print_rr(pj_uint8_t *pkt, int size, pj_uint8_t *pos,
p += 6;
size -= 6;
} else if (rr->type == PJ_DNS_TYPE_AAAA) {
if (size < 18)
return -1;
/* RDLEN is 16 */
write16(p, 16);
/* Address */
pj_memcpy(p+2, &rr->rdata.aaaa.ip_addr, 16);
p += 18;
size -= 18;
} else if (rr->type == PJ_DNS_TYPE_CNAME ||
rr->type == PJ_DNS_TYPE_NS ||
rr->type == PJ_DNS_TYPE_PTR) {

View File

@ -229,9 +229,11 @@ PJ_DEF(pj_status_t) pj_pcap_read_udp(pj_pcap_file *file,
unsigned rec_incl;
pj_ssize_t sz;
pj_size_t sz_read = 0;
char addr[PJ_INET_ADDRSTRLEN];
pj_status_t status;
TRACE_((file->obj_name, "Reading packet.."));
pj_bzero(&addr, sizeof(addr));
/* Read PCAP packet header */
sz = sizeof(tmp.rec);
@ -282,7 +284,8 @@ PJ_DEF(pj_status_t) pj_pcap_read_udp(pj_pcap_file *file,
/* Skip if IP source mismatch */
if (file->filter.ip_src && tmp.ip.ip_src != file->filter.ip_src) {
TRACE_((file->obj_name, "IP source %s mismatch, skipping",
pj_inet_ntoa(*(pj_in_addr*)&tmp.ip.ip_src)));
pj_inet_ntop2(pj_AF_INET(), (pj_in_addr*)&tmp.ip.ip_src,
addr, sizeof(addr))));
SKIP_PKT();
continue;
}
@ -290,7 +293,8 @@ PJ_DEF(pj_status_t) pj_pcap_read_udp(pj_pcap_file *file,
/* Skip if IP destination mismatch */
if (file->filter.ip_dst && tmp.ip.ip_dst != file->filter.ip_dst) {
TRACE_((file->obj_name, "IP detination %s mismatch, skipping",
pj_inet_ntoa(*(pj_in_addr*)&tmp.ip.ip_dst)));
pj_inet_ntop2(pj_AF_INET(), (pj_in_addr*)&tmp.ip.ip_dst,
addr, sizeof(addr))));
SKIP_PKT();
continue;
}

View File

@ -19,6 +19,7 @@
*/
#include <pjlib-util/resolver.h>
#include <pjlib-util/errno.h>
#include <pj/compat/socket.h>
#include <pj/assert.h>
#include <pj/ctype.h>
#include <pj/except.h>
@ -79,7 +80,7 @@ static const char *state_names[3] =
*/
struct nameserver
{
pj_sockaddr_in addr; /**< Server address. */
pj_sockaddr addr; /**< Server address. */
enum ns_state state; /**< Nameserver state. */
pj_time_val state_expiry; /**< Time set next state. */
@ -179,13 +180,24 @@ struct pj_dns_resolver
pj_sock_t udp_sock; /**< UDP socket. */
pj_ioqueue_key_t *udp_key; /**< UDP socket ioqueue key. */
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. */
unsigned char udp_tx_pkt[UDPSZ];/**< UDP transmit buffer. */
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 */
pj_sockaddr udp_src_addr; /**< Source address of packet */
int udp_addr_len; /**< Source address length. */
#if PJ_HAS_IPV6
/* IPv6 socket */
pj_sock_t udp6_sock; /**< UDP socket. */
pj_ioqueue_key_t *udp6_key; /**< UDP socket ioqueue key. */
unsigned char udp6_rx_pkt[UDPSZ];/**< UDP receive buffer. */
//unsigned char udp6_tx_pkt[UDPSZ];/**< UDP transmit buffer. */
pj_ioqueue_op_key_t udp6_op_rx_key;/**< UDP read operation key. */
pj_ioqueue_op_key_t udp6_op_tx_key;/**< UDP write operation key. */
pj_sockaddr udp6_src_addr; /**< Source address of packet */
int udp6_addr_len; /**< Source address length. */
#endif
/* Settings */
pj_dns_settings settings; /**< Resolver settings. */
@ -237,6 +249,17 @@ static void close_sock(pj_dns_resolver *resv)
pj_sock_close(resv->udp_sock);
resv->udp_sock = PJ_INVALID_SOCKET;
}
#if PJ_HAS_IPV6
if (resv->udp6_key != NULL) {
pj_ioqueue_unregister(resv->udp6_key);
resv->udp6_key = NULL;
resv->udp6_sock = PJ_INVALID_SOCKET;
} else if (resv->udp6_sock != PJ_INVALID_SOCKET) {
pj_sock_close(resv->udp6_sock);
resv->udp6_sock = PJ_INVALID_SOCKET;
}
#endif
}
@ -244,6 +267,8 @@ static void close_sock(pj_dns_resolver *resv)
static pj_status_t init_sock(pj_dns_resolver *resv)
{
pj_ioqueue_callback socket_cb;
pj_sockaddr bound_addr;
pj_ssize_t rx_pkt_size;
pj_status_t status;
/* Create the UDP socket */
@ -269,15 +294,67 @@ static pj_status_t init_sock(pj_dns_resolver *resv)
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);
rx_pkt_size = 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,
resv->udp_rx_pkt, &rx_pkt_size,
PJ_IOQUEUE_ALWAYS_ASYNC,
&resv->udp_src_addr, &resv->udp_addr_len);
if (status != PJ_EPENDING)
return status;
#if PJ_HAS_IPV6
/* Also setup IPv6 socket */
/* Create the UDP socket */
status = pj_sock_socket(pj_AF_INET6(), pj_SOCK_DGRAM(), 0,
&resv->udp6_sock);
if (status != PJ_SUCCESS) {
/* Skip IPv6 socket on system without IPv6 (see ticket #1953) */
if (status == PJ_STATUS_FROM_OS(OSERR_EAFNOSUPPORT)) {
PJ_LOG(3,(resv->name.ptr,
"System does not support IPv6, resolver will "
"ignore any IPv6 nameservers"));
return PJ_SUCCESS;
}
return status;
}
/* Bind to any address/port */
pj_sockaddr_init(pj_AF_INET6(), &bound_addr, NULL, 0);
status = pj_sock_bind(resv->udp6_sock, &bound_addr,
pj_sockaddr_get_len(&bound_addr));
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->udp6_sock, resv, &socket_cb,
&resv->udp6_key);
if (status != PJ_SUCCESS)
return status;
pj_ioqueue_op_key_init(&resv->udp6_op_rx_key,
sizeof(resv->udp6_op_rx_key));
pj_ioqueue_op_key_init(&resv->udp6_op_tx_key,
sizeof(resv->udp6_op_tx_key));
/* Start asynchronous read to the UDP socket */
rx_pkt_size = sizeof(resv->udp6_rx_pkt);
resv->udp6_addr_len = sizeof(resv->udp6_src_addr);
status = pj_ioqueue_recvfrom(resv->udp6_key, &resv->udp6_op_rx_key,
resv->udp6_rx_pkt, &rx_pkt_size,
PJ_IOQUEUE_ALWAYS_ASYNC,
&resv->udp6_src_addr, &resv->udp6_addr_len);
if (status != PJ_EPENDING)
return status;
#else
PJ_UNUSED_ARG(bound_addr);
#endif
return PJ_SUCCESS;
}
@ -474,8 +551,11 @@ PJ_DEF(pj_status_t) pj_dns_resolver_set_ns( pj_dns_resolver *resolver,
for (i=0; i<count; ++i) {
struct nameserver *ns = &resolver->ns[i];
status = pj_sockaddr_in_init(&ns->addr, &servers[i],
(pj_uint16_t)(ports ? ports[i] : PORT));
status = pj_sockaddr_init(pj_AF_INET(), &ns->addr, &servers[i],
(pj_uint16_t)(ports ? ports[i] : PORT));
if (status != PJ_SUCCESS)
status = pj_sockaddr_init(pj_AF_INET6(), &ns->addr, &servers[i],
(pj_uint16_t)(ports ? ports[i] : PORT));
if (status != PJ_SUCCESS) {
pj_mutex_unlock(resolver->mutex);
return PJLIB_UTIL_EDNSINNSADDR;
@ -579,7 +659,7 @@ static pj_status_t transmit_query(pj_dns_resolver *resolver,
pj_dns_async_query *q)
{
unsigned pkt_size;
unsigned i, server_cnt;
unsigned i, server_cnt, send_cnt;
unsigned servers[PJ_DNS_RESOLVER_MAX_NS];
pj_time_val now;
pj_str_t name;
@ -612,7 +692,14 @@ static pj_status_t transmit_query(pj_dns_resolver *resolver,
}
/* Check if the socket is available for sending */
if (pj_ioqueue_is_pending(resolver->udp_key, &resolver->udp_op_tx_key)) {
if (pj_ioqueue_is_pending(resolver->udp_key, &resolver->udp_op_tx_key)
#if PJ_HAS_IPV6
|| (resolver->udp6_key &&
pj_ioqueue_is_pending(resolver->udp6_key,
&resolver->udp6_op_tx_key))
#endif
)
{
++q->transmit_cnt;
PJ_LOG(4,(resolver->name.ptr,
"Socket busy in transmitting DNS %s query for %s%s",
@ -637,22 +724,42 @@ static pj_status_t transmit_query(pj_dns_resolver *resolver,
pj_gettimeofday(&now);
/* Send the packet to name servers */
send_cnt = 0;
for (i=0; i<server_cnt; ++i) {
char addr[PJ_INET6_ADDRSTRLEN];
pj_ssize_t sent = (pj_ssize_t) pkt_size;
struct nameserver *ns = &resolver->ns[servers[i]];
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));
if (ns->addr.addr.sa_family == pj_AF_INET()) {
status = pj_ioqueue_sendto(resolver->udp_key,
&resolver->udp_op_tx_key,
resolver->udp_tx_pkt, &sent, 0,
&ns->addr,
pj_sockaddr_get_len(&ns->addr));
if (status == PJ_SUCCESS || status == PJ_EPENDING)
send_cnt++;
}
#if PJ_HAS_IPV6
else if (resolver->udp6_key) {
status = pj_ioqueue_sendto(resolver->udp6_key,
&resolver->udp6_op_tx_key,
resolver->udp_tx_pkt, &sent, 0,
&ns->addr,
pj_sockaddr_get_len(&ns->addr));
if (status == PJ_SUCCESS || status == PJ_EPENDING)
send_cnt++;
}
#endif
else {
continue;
}
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)pkt_size, servers[i],
pj_inet_ntoa(ns->addr.sin_addr),
(int)pj_ntohs(ns->addr.sin_port),
pj_sockaddr_print(&ns->addr, addr, sizeof(addr), 2),
pj_sockaddr_get_port(&ns->addr),
pj_dns_get_type_name(q->key.qtype),
q->key.name));
@ -662,6 +769,9 @@ static pj_status_t transmit_query(pj_dns_resolver *resolver,
}
}
if (send_cnt == 0)
return PJLIB_UTIL_EDNSNOWORKINGNS;
++q->transmit_cnt;
return PJ_SUCCESS;
@ -746,7 +856,7 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver,
pj_time_val now;
struct res_key key;
struct cached_res *cache;
pj_dns_async_query *q;
pj_dns_async_query *q, *p_q = NULL;
pj_uint32_t hval;
pj_status_t status = PJ_SUCCESS;
@ -760,9 +870,6 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver,
/* Check type */
PJ_ASSERT_RETURN(type > 0 && type < 0xFFFF, PJ_EINVAL);
if (p_query)
*p_query = NULL;
/* Build resource key for looking up hash tables */
init_res_key(&key, type, name);
@ -822,7 +929,13 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver,
/* Must return PJ_SUCCESS */
status = PJ_SUCCESS;
goto on_return;
/*
* We cannot write to *p_query after calling cb because what
* p_query points to may have been freed by cb.
* Refer to ticket #1974.
*/
pj_mutex_unlock(resolver->mutex);
return status;
}
/* At this point, we have a cached entry, but this entry has expired.
@ -854,6 +967,7 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver,
/* Done. This child query will be notified once the "parent"
* query completes.
*/
p_q = nq;
status = PJ_SUCCESS;
goto on_return;
}
@ -881,10 +995,12 @@ PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver,
pj_hash_set_np(resolver->hquerybyres, &q->key, sizeof(q->key),
0, q->hbufkey, q);
if (p_query)
*p_query = q;
p_q = q;
on_return:
if (p_query)
*p_query = p_q;
pj_mutex_unlock(resolver->mutex);
return status;
}
@ -1026,6 +1142,132 @@ PJ_DEF(pj_status_t) pj_dns_parse_a_response(const pj_dns_parsed_packet *pkt,
}
/*
* DNS response containing A and/or AAAA packet.
*/
PJ_DEF(pj_status_t) pj_dns_parse_addr_response(
const pj_dns_parsed_packet *pkt,
pj_dns_addr_record *rec)
{
enum { MAX_SEARCH = 20 };
pj_str_t hostname, alias = {NULL, 0}, *resname;
pj_size_t bufstart = 0;
pj_size_t bufleft;
unsigned i, ansidx, cnt=0;
PJ_ASSERT_RETURN(pkt && rec, PJ_EINVAL);
/* Init the record */
pj_bzero(rec, sizeof(*rec));
bufleft = sizeof(rec->buf_);
/* Return error if there's error in the packet. */
if (PJ_DNS_GET_RCODE(pkt->hdr.flags))
return PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_GET_RCODE(pkt->hdr.flags));
/* Return error if there's no query section */
if (pkt->hdr.qdcount == 0)
return PJLIB_UTIL_EDNSINANSWER;
/* Return error if there's no answer */
if (pkt->hdr.anscount == 0)
return PJLIB_UTIL_EDNSNOANSWERREC;
/* Get the hostname from the query. */
hostname = pkt->q[0].name;
/* Copy hostname to the record */
if (hostname.slen > (int)bufleft) {
return PJ_ENAMETOOLONG;
}
pj_memcpy(&rec->buf_[bufstart], hostname.ptr, hostname.slen);
rec->name.ptr = &rec->buf_[bufstart];
rec->name.slen = hostname.slen;
bufstart += hostname.slen;
bufleft -= hostname.slen;
/* Find the first RR which name matches the hostname. */
for (ansidx=0; ansidx < pkt->hdr.anscount; ++ansidx) {
if (pj_stricmp(&pkt->ans[ansidx].name, &hostname)==0)
break;
}
if (ansidx == pkt->hdr.anscount)
return PJLIB_UTIL_EDNSNOANSWERREC;
resname = &hostname;
/* Keep following CNAME records. */
while (pkt->ans[ansidx].type == PJ_DNS_TYPE_CNAME &&
cnt++ < MAX_SEARCH)
{
resname = &pkt->ans[ansidx].rdata.cname.name;
if (!alias.slen)
alias = *resname;
for (i=0; i < pkt->hdr.anscount; ++i) {
if (pj_stricmp(resname, &pkt->ans[i].name)==0)
break;
}
if (i==pkt->hdr.anscount)
return PJLIB_UTIL_EDNSNOANSWERREC;
ansidx = i;
}
if (cnt >= MAX_SEARCH)
return PJLIB_UTIL_EDNSINANSWER;
if (pkt->ans[ansidx].type != PJ_DNS_TYPE_A &&
pkt->ans[ansidx].type != PJ_DNS_TYPE_AAAA)
{
return PJLIB_UTIL_EDNSINANSWER;
}
/* Copy alias to the record, if present. */
if (alias.slen) {
if (alias.slen > (int)bufleft)
return PJ_ENAMETOOLONG;
pj_memcpy(&rec->buf_[bufstart], alias.ptr, alias.slen);
rec->alias.ptr = &rec->buf_[bufstart];
rec->alias.slen = alias.slen;
bufstart += alias.slen;
bufleft -= alias.slen;
}
/* Get the IP addresses. */
cnt = 0;
for (i=0; i < pkt->hdr.anscount && cnt < PJ_DNS_MAX_IP_IN_A_REC ; ++i) {
if ((pkt->ans[i].type == PJ_DNS_TYPE_A ||
pkt->ans[i].type == PJ_DNS_TYPE_AAAA) &&
pj_stricmp(&pkt->ans[i].name, resname)==0)
{
if (pkt->ans[i].type == PJ_DNS_TYPE_A) {
rec->addr[cnt].af = pj_AF_INET();
rec->addr[cnt].ip.v4 = pkt->ans[i].rdata.a.ip_addr;
} else {
rec->addr[cnt].af = pj_AF_INET6();
rec->addr[cnt].ip.v6 = pkt->ans[i].rdata.aaaa.ip_addr;
}
++cnt;
}
}
rec->addr_count = cnt;
if (cnt == 0)
return PJLIB_UTIL_EDNSNOANSWERREC;
return PJ_SUCCESS;
}
/* Set nameserver state */
static void set_nameserver_state(pj_dns_resolver *resolver,
unsigned index,
@ -1034,6 +1276,7 @@ static void set_nameserver_state(pj_dns_resolver *resolver,
{
struct nameserver *ns = &resolver->ns[index];
enum ns_state old_state = ns->state;
char addr[PJ_INET6_ADDRSTRLEN];
ns->state = state;
ns->state_expiry = *now;
@ -1047,8 +1290,8 @@ static void set_nameserver_state(pj_dns_resolver *resolver,
ns->state_expiry.sec += resolver->settings.bad_ns_ttl;
PJ_LOG(5, (resolver->name.ptr, "Nameserver %s:%d state changed %s --> %s",
pj_inet_ntoa(ns->addr.sin_addr),
(int)pj_ntohs(ns->addr.sin_port),
pj_sockaddr_print(&ns->addr, addr, sizeof(addr), 2),
pj_sockaddr_get_port(&ns->addr),
state_names[old_state], state_names[state]));
}
@ -1127,7 +1370,7 @@ static pj_status_t select_nameservers(pj_dns_resolver *resolver,
/* Update name server status */
static void report_nameserver_status(pj_dns_resolver *resolver,
const pj_sockaddr_in *ns_addr,
const pj_sockaddr *ns_addr,
const pj_dns_parsed_packet *pkt)
{
unsigned i;
@ -1147,7 +1390,12 @@ static void report_nameserver_status(pj_dns_resolver *resolver,
q_id = (pj_uint32_t)-1;
}
if (!pkt || rcode == PJ_DNS_RCODE_SERVFAIL ||
/* Some nameserver is reported to respond with PJ_DNS_RCODE_SERVFAIL for
* missing AAAA record, and the standard doesn't seem to specify that
* SERVFAIL should prevent the server to be contacted again for other
* queries. So let's not mark nameserver as bad for SERVFAIL response.
*/
if (!pkt || /* rcode == PJ_DNS_RCODE_SERVFAIL || */
rcode == PJ_DNS_RCODE_REFUSED ||
rcode == PJ_DNS_RCODE_NOTAUTH)
{
@ -1164,10 +1412,7 @@ static void report_nameserver_status(pj_dns_resolver *resolver,
for (i=0; i<resolver->ns_count; ++i) {
struct nameserver *ns = &resolver->ns[i];
if (ns->addr.sin_addr.s_addr == ns_addr->sin_addr.s_addr &&
ns->addr.sin_port == ns_addr->sin_port &&
ns->addr.sin_family == ns_addr->sin_family)
{
if (pj_sockaddr_cmp(&ns->addr, ns_addr) == 0) {
if (q_id == ns->q_id) {
/* Calculate response time */
pj_time_val rt = now;
@ -1232,10 +1477,12 @@ static void update_res_cache(pj_dns_resolver *resolver,
if (ttl > resolver->settings.cache_max_ttl)
ttl = resolver->settings.cache_max_ttl;
/* Get a cache response entry */
cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key,
sizeof(*key), &hval);
/* If TTL is zero, clear the same entry in the hash table */
if (ttl == 0) {
cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key,
sizeof(*key), &hval);
/* Remove the entry before releasing its pool (see ticket #1710) */
pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL);
@ -1245,24 +1492,23 @@ static void update_res_cache(pj_dns_resolver *resolver,
return;
}
/* Get a cache response entry */
cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key,
sizeof(*key), &hval);
if (cache == NULL) {
cache = alloc_entry(resolver);
} else if (cache->ref_cnt > 1) {
/* When cache entry is being used by callback (to app), just decrement
* ref_cnt so it will be freed after the callback returns and allocate
* new entry.
*/
cache->ref_cnt--;
cache = alloc_entry(resolver);
} else {
/* Remove the entry before resetting its pool (see ticket #1710) */
pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL);
/* Reset cache to avoid bloated cache pool */
reset_entry(&cache);
if (cache->ref_cnt > 1) {
/* When cache entry is being used by callback (to app),
* just decrement ref_cnt so it will be freed after
* the callback returns and allocate new entry.
*/
cache->ref_cnt--;
cache = alloc_entry(resolver);
} else {
/* Reset cache to avoid bloated cache pool */
reset_entry(&cache);
}
}
/* Duplicate the packet.
@ -1390,11 +1636,33 @@ static void on_read_complete(pj_ioqueue_key_t *key,
pj_pool_t *pool = NULL;
pj_dns_parsed_packet *dns_pkt;
pj_dns_async_query *q;
char addr[PJ_INET6_ADDRSTRLEN];
pj_sockaddr *src_addr;
int *src_addr_len;
unsigned char *rx_pkt;
pj_ssize_t rx_pkt_size;
pj_status_t status;
PJ_USE_EXCEPTION;
resolver = (pj_dns_resolver *) pj_ioqueue_get_user_data(key);
pj_assert(resolver);
#if PJ_HAS_IPV6
if (key == resolver->udp6_key) {
src_addr = &resolver->udp6_src_addr;
src_addr_len = &resolver->udp6_addr_len;
rx_pkt = resolver->udp6_rx_pkt;
rx_pkt_size = sizeof(resolver->udp6_rx_pkt);
} else
#endif
{
src_addr = &resolver->udp_src_addr;
src_addr_len = &resolver->udp_addr_len;
rx_pkt = resolver->udp_rx_pkt;
rx_pkt_size = sizeof(resolver->udp_rx_pkt);
}
pj_mutex_lock(resolver->mutex);
@ -1404,11 +1672,7 @@ static void on_read_complete(pj_ioqueue_key_t *key,
status = (pj_status_t)-bytes_read;
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(4,(resolver->name.ptr,
"DNS resolver read error from %s:%d: %s",
pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
pj_ntohs(resolver->udp_src_addr.sin_port),
errmsg));
PJ_LOG(4,(resolver->name.ptr, "DNS resolver read error: %s", errmsg));
goto read_next_packet;
}
@ -1416,8 +1680,8 @@ static void on_read_complete(pj_ioqueue_key_t *key,
PJ_LOG(5,(resolver->name.ptr,
"Received %d bytes DNS response from %s:%d",
(int)bytes_read,
pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
pj_ntohs(resolver->udp_src_addr.sin_port)));
pj_sockaddr_print(src_addr, addr, sizeof(addr), 2),
pj_sockaddr_get_port(src_addr)));
/* Check for zero packet */
@ -1432,7 +1696,7 @@ static void on_read_complete(pj_ioqueue_key_t *key,
status = -1;
dns_pkt = NULL;
PJ_TRY {
status = pj_dns_parse_packet(pool, resolver->udp_rx_pkt,
status = pj_dns_parse_packet(pool, rx_pkt,
(unsigned)bytes_read, &dns_pkt);
}
PJ_CATCH_ANY {
@ -1441,7 +1705,7 @@ static void on_read_complete(pj_ioqueue_key_t *key,
PJ_END;
/* Update nameserver status */
report_nameserver_status(resolver, &resolver->udp_src_addr, dns_pkt);
report_nameserver_status(resolver, src_addr, dns_pkt);
/* Handle parse error */
if (status != PJ_SUCCESS) {
@ -1450,8 +1714,8 @@ static void on_read_complete(pj_ioqueue_key_t *key,
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(3,(resolver->name.ptr,
"Error parsing DNS response from %s:%d: %s",
pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
pj_ntohs(resolver->udp_src_addr.sin_port),
pj_sockaddr_print(src_addr, addr, sizeof(addr), 2),
pj_sockaddr_get_port(src_addr),
errmsg));
goto read_next_packet;
}
@ -1463,8 +1727,8 @@ static void on_read_complete(pj_ioqueue_key_t *key,
if (!q) {
PJ_LOG(5,(resolver->name.ptr,
"DNS response from %s:%d id=%d discarded",
pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
pj_ntohs(resolver->udp_src_addr.sin_port),
pj_sockaddr_print(src_addr, addr, sizeof(addr), 2),
pj_sockaddr_get_port(src_addr),
(unsigned)dns_pkt->hdr.id));
goto read_next_packet;
}
@ -1527,13 +1791,11 @@ read_next_packet:
/* needed just in case PJ_HAS_POOL_ALT_API is set */
pj_pool_release(pool);
}
bytes_read = sizeof(resolver->udp_rx_pkt);
resolver->udp_addr_len = sizeof(resolver->udp_src_addr);
status = pj_ioqueue_recvfrom(resolver->udp_key, op_key,
resolver->udp_rx_pkt,
&bytes_read, PJ_IOQUEUE_ALWAYS_ASYNC,
&resolver->udp_src_addr,
&resolver->udp_addr_len);
status = pj_ioqueue_recvfrom(key, op_key, rx_pkt, &rx_pkt_size,
PJ_IOQUEUE_ALWAYS_ASYNC,
src_addr, src_addr_len);
if (status != PJ_EPENDING) {
char errmsg[PJ_ERR_MSG_SIZE];
@ -1633,12 +1895,14 @@ PJ_DEF(void) pj_dns_resolver_dump(pj_dns_resolver *resolver,
PJ_LOG(3,(resolver->name.ptr, " Name servers:"));
for (i=0; i<resolver->ns_count; ++i) {
char addr[PJ_INET6_ADDRSTRLEN];
struct nameserver *ns = &resolver->ns[i];
PJ_LOG(3,(resolver->name.ptr,
" NS %d: %s:%d (state=%s until %ds, rtt=%d ms)",
i, pj_inet_ntoa(ns->addr.sin_addr),
pj_ntohs(ns->addr.sin_port),
i,
pj_sockaddr_print(&ns->addr, addr, sizeof(addr), 2),
pj_sockaddr_get_port(&ns->addr),
state_names[ns->state],
ns->state_expiry.sec - now.sec,
PJ_TIME_VAL_MSEC(ns->rt_delay)));

View File

@ -37,22 +37,26 @@ struct common
pj_dns_type type; /**< Type of this structure.*/
};
#pragma pack(1)
struct srv_target
{
struct common common;
struct common common_aaaa;
pj_dns_srv_async_query *parent;
pj_str_t target_name;
pj_dns_async_query *q_a;
pj_dns_async_query *q_aaaa;
char target_buf[PJ_MAX_HOSTNAME];
pj_str_t cname;
char cname_buf[PJ_MAX_HOSTNAME];
unsigned port;
pj_uint16_t port;
unsigned priority;
unsigned weight;
unsigned sum;
unsigned addr_cnt;
pj_in_addr addr[ADDR_MAX_COUNT];
pj_sockaddr addr[ADDR_MAX_COUNT];/**< Address family and IP.*/
};
#pragma pack()
struct pj_dns_srv_async_query
{
@ -135,6 +139,10 @@ PJ_DEF(pj_status_t) pj_dns_srv_resolve( const pj_str_t *domain_name,
query_job->domain_part.slen = target_name.slen - len;
query_job->def_port = (pj_uint16_t)def_port;
/* Normalize query job option PJ_DNS_SRV_RESOLVE_AAAA_ONLY */
if (query_job->option & PJ_DNS_SRV_RESOLVE_AAAA_ONLY)
query_job->option |= PJ_DNS_SRV_RESOLVE_AAAA;
/* Start the asynchronous query_job */
query_job->dns_state = PJ_DNS_TYPE_SRV;
@ -178,6 +186,14 @@ PJ_DEF(pj_status_t) pj_dns_srv_cancel_query(pj_dns_srv_async_query *query,
srv->q_a = NULL;
has_pending = PJ_TRUE;
}
if (srv->q_aaaa) {
/* Check if it is a dummy query. */
if (srv->q_aaaa != (pj_dns_async_query*)0x1) {
pj_dns_resolver_cancel_query(srv->q_aaaa, PJ_FALSE);
has_pending = PJ_TRUE;
}
srv->q_aaaa = NULL;
}
}
if (has_pending && notify && query->cb) {
@ -314,29 +330,56 @@ static void build_server_entries(pj_dns_srv_async_query *query_job,
query_job->srv[i].target_name.ptr = query_job->srv[i].target_buf;
}
/* Check for Additional Info section if A records are available, and
* fill in the IP address (so that we won't need to resolve the A
/* Check for Additional Info section if A/AAAA records are available, and
* fill in the IP address (so that we won't need to resolve the A/AAAA
* record with another DNS query_job).
*/
for (i=0; i<response->hdr.arcount; ++i) {
pj_dns_parsed_rr *rr = &response->arr[i];
unsigned j;
if (rr->type != PJ_DNS_TYPE_A)
/* Skip non-A/AAAA record */
if (rr->type != PJ_DNS_TYPE_A && rr->type != PJ_DNS_TYPE_AAAA)
continue;
/* Yippeaiyee!! There is an "A" record!
/* Also skip if:
* - it is A record and app only want AAAA record, or
* - it is AAAA record and app does not want AAAA record
*/
if ((rr->type == PJ_DNS_TYPE_A &&
(query_job->option & PJ_DNS_SRV_RESOLVE_AAAA_ONLY)!=0) ||
(rr->type == PJ_DNS_TYPE_AAAA &&
(query_job->option & PJ_DNS_SRV_RESOLVE_AAAA)==0))
{
continue;
}
/* Yippeaiyee!! There is an "A/AAAA" record!
* Update the IP address of the corresponding SRV record.
*/
for (j=0; j<query_job->srv_cnt; ++j) {
if (pj_stricmp(&rr->name, &query_job->srv[j].target_name)==0 &&
query_job->srv[j].addr_cnt < ADDR_MAX_COUNT)
{
if (pj_stricmp(&rr->name, &query_job->srv[j].target_name)==0
&& query_job->srv[j].addr_cnt < ADDR_MAX_COUNT)
{
unsigned cnt = query_job->srv[j].addr_cnt;
query_job->srv[j].addr[cnt].s_addr = rr->rdata.a.ip_addr.s_addr;
if (rr->type == PJ_DNS_TYPE_A) {
pj_sockaddr_init(pj_AF_INET(),
&query_job->srv[j].addr[cnt], NULL,
query_job->srv[j].port);
query_job->srv[j].addr[cnt].ipv4.sin_addr =
rr->rdata.a.ip_addr;
} else {
pj_sockaddr_init(pj_AF_INET6(),
&query_job->srv[j].addr[cnt], NULL,
query_job->srv[j].port);
query_job->srv[j].addr[cnt].ipv6.sin6_addr =
rr->rdata.aaaa.ip_addr;
}
/* Only increment host_resolved once per SRV record */
if (query_job->srv[j].addr_cnt == 0)
++query_job->host_resolved;
++query_job->srv[j].addr_cnt;
break;
}
@ -354,6 +397,7 @@ static void build_server_entries(pj_dns_srv_async_query *query_job,
rr->name.ptr));
}
*/
}
/* Rescan again the name specified in the SRV record to see if IP
@ -362,14 +406,32 @@ static void build_server_entries(pj_dns_srv_async_query *query_job,
*/
for (i=0; i<query_job->srv_cnt; ++i) {
pj_in_addr addr;
pj_in6_addr addr6;
if (query_job->srv[i].addr_cnt != 0) {
/* IP address already resolved */
continue;
}
if (pj_inet_aton(&query_job->srv[i].target_name, &addr) != 0) {
query_job->srv[i].addr[query_job->srv[i].addr_cnt++] = addr;
if ((query_job->option & PJ_DNS_SRV_RESOLVE_AAAA_ONLY)==0 &&
pj_inet_pton(pj_AF_INET(), &query_job->srv[i].target_name,
&addr) == PJ_SUCCESS)
{
unsigned cnt = query_job->srv[i].addr_cnt;
pj_sockaddr_init(pj_AF_INET(), &query_job->srv[i].addr[cnt],
NULL, query_job->srv[i].port);
query_job->srv[i].addr[cnt].ipv4.sin_addr = addr;
++query_job->srv[i].addr_cnt;
++query_job->host_resolved;
} else if ((query_job->option & PJ_DNS_SRV_RESOLVE_AAAA)!=0 &&
pj_inet_pton(pj_AF_INET6(), &query_job->srv[i].target_name,
&addr6) == PJ_SUCCESS)
{
unsigned cnt = query_job->srv[i].addr_cnt;
pj_sockaddr_init(pj_AF_INET6(), &query_job->srv[i].addr[cnt],
NULL, query_job->srv[i].port);
query_job->srv[i].addr[cnt].ipv6.sin6_addr = addr6;
++query_job->srv[i].addr_cnt;
++query_job->host_resolved;
}
}
@ -385,12 +447,13 @@ static void build_server_entries(pj_dns_srv_async_query *query_job,
(query_job->srv_cnt ? ':' : ' ')));
for (i=0; i<query_job->srv_cnt; ++i) {
const char *addr;
char addr[PJ_INET6_ADDRSTRLEN];
if (query_job->srv[i].addr_cnt != 0)
addr = pj_inet_ntoa(query_job->srv[i].addr[0]);
else
addr = "-";
if (query_job->srv[i].addr_cnt != 0) {
pj_sockaddr_print(&query_job->srv[i].addr[0],
addr, sizeof(addr), 2);
} else
pj_ansi_strcpy(addr, "-");
PJ_LOG(5,(query_job->objname,
" %d: SRV %d %d %d %.*s (%s)",
@ -404,13 +467,16 @@ static void build_server_entries(pj_dns_srv_async_query *query_job,
}
/* Start DNS A record queries for all SRV records in the query_job structure */
/* Start DNS A and/or AAAA record queries for all SRV records in
* the query_job structure.
*/
static pj_status_t resolve_hostnames(pj_dns_srv_async_query *query_job)
{
unsigned i, err_cnt = 0;
pj_status_t err=PJ_SUCCESS, status;
query_job->dns_state = PJ_DNS_TYPE_A;
for (i=0; i<query_job->srv_cnt; ++i) {
struct srv_target *srv = &query_job->srv[i];
@ -420,18 +486,47 @@ static pj_status_t resolve_hostnames(pj_dns_srv_async_query *query_job)
srv->target_name.ptr));
srv->common.type = PJ_DNS_TYPE_A;
srv->common_aaaa.type = PJ_DNS_TYPE_AAAA;
srv->parent = query_job;
srv->q_a = NULL;
srv->q_aaaa = NULL;
status = PJ_SUCCESS;
/* Start DNA A record query */
if ((query_job->option & PJ_DNS_SRV_RESOLVE_AAAA_ONLY) == 0)
{
if ((query_job->option & PJ_DNS_SRV_RESOLVE_AAAA) != 0) {
/* If there will be DNS AAAA query too, let's setup
* a dummy one here, otherwise app callback may be called
* immediately (before DNS AAAA query is sent) when
* DNS A record is available in the cache.
*/
srv->q_aaaa = (pj_dns_async_query*)0x1;
}
status = pj_dns_resolver_start_query(query_job->resolver,
&srv->target_name,
PJ_DNS_TYPE_A, 0,
&dns_callback,
&srv->common, &srv->q_a);
}
/* Start DNA AAAA record query */
if (status == PJ_SUCCESS &&
(query_job->option & PJ_DNS_SRV_RESOLVE_AAAA) != 0)
{
status = pj_dns_resolver_start_query(query_job->resolver,
&srv->target_name,
PJ_DNS_TYPE_AAAA, 0,
&dns_callback,
&srv->common_aaaa, &srv->q_aaaa);
}
/* See also #1809: dns_callback() will be invoked synchronously when response
* is available in the cache, and var 'query_job->host_resolved' will get
* incremented within the dns_callback(), which will cause this function
* returning false error, so don't use that variable for counting errors.
*/
status = pj_dns_resolver_start_query(query_job->resolver,
&srv->target_name,
PJ_DNS_TYPE_A, 0,
&dns_callback,
srv, &srv->q_a);
if (status != PJ_SUCCESS) {
query_job->host_resolved++;
err_cnt++;
@ -461,6 +556,9 @@ static void dns_callback(void *user_data,
} else if (common->type == PJ_DNS_TYPE_A) {
srv = (struct srv_target*) common;
query_job = srv->parent;
} else if (common->type == PJ_DNS_TYPE_AAAA) {
srv = (struct srv_target*)((pj_int8_t*)common-sizeof(struct common));
query_job = srv->parent;
} else {
pj_assert(!"Unexpected user data!");
return;
@ -471,6 +569,7 @@ static void dns_callback(void *user_data,
/* We are getting SRV response */
/* Clear the outstanding job */
query_job->q_srv = NULL;
if (status == PJ_SUCCESS && pkt->hdr.anscount != 0) {
@ -504,13 +603,15 @@ static void dns_callback(void *user_data,
* an A record and resolve with DNS A resolution.
*/
if (query_job->srv_cnt == 0) {
unsigned new_option = 0;
/* Looks like we aren't getting any SRV responses.
* Resolve the original target as A record by creating a
* single "dummy" srv record and start the hostname resolution.
*/
PJ_LOG(4, (query_job->objname,
"DNS SRV resolution failed for %.*s, trying "
"resolving A record for %.*s",
"resolving A/AAAA record for %.*s",
(int)query_job->full_name.slen,
query_job->full_name.ptr,
(int)query_job->domain_part.slen,
@ -523,11 +624,20 @@ static void dns_callback(void *user_data,
query_job->srv[i].priority = 0;
query_job->srv[i].weight = 0;
query_job->srv[i].port = query_job->def_port;
}
/* Update query_job resolution option based on fallback option */
if (query_job->option & PJ_DNS_SRV_FALLBACK_AAAA)
new_option |= (PJ_DNS_SRV_RESOLVE_AAAA |
PJ_DNS_SRV_RESOLVE_AAAA_ONLY);
if (query_job->option & PJ_DNS_SRV_FALLBACK_A)
new_option &= (~PJ_DNS_SRV_RESOLVE_AAAA_ONLY);
query_job->option = new_option;
}
/* Resolve server hostnames (DNS A record) for hosts which don't have
* A record yet.
/* Resolve server hostnames (DNS A/AAAA record) for hosts which
* don't have A/AAAA record yet.
*/
if (query_job->host_resolved != query_job->srv_cnt) {
status = resolve_hostnames(query_job);
@ -541,51 +651,83 @@ static void dns_callback(void *user_data,
}
} else if (query_job->dns_state == PJ_DNS_TYPE_A) {
pj_bool_t is_type_a, srv_completed;
/* Clear the outstanding job */
srv->q_a = NULL;
/* Clear outstanding job */
if (common->type == PJ_DNS_TYPE_A) {
srv_completed = (srv->q_aaaa == NULL);
srv->q_a = NULL;
} else if (common->type == PJ_DNS_TYPE_AAAA) {
srv_completed = (srv->q_a == NULL);
srv->q_aaaa = NULL;
} else {
pj_assert(!"Unexpected job type");
query_job->last_error = status = PJ_EINVALIDOP;
goto on_error;
}
is_type_a = (common->type == PJ_DNS_TYPE_A);
/* Check that we really have answer */
if (status==PJ_SUCCESS && pkt->hdr.anscount != 0) {
pj_dns_a_record rec;
char addr[PJ_INET6_ADDRSTRLEN];
pj_dns_addr_record rec;
/* Parse response */
status = pj_dns_parse_a_response(pkt, &rec);
status = pj_dns_parse_addr_response(pkt, &rec);
if (status != PJ_SUCCESS)
goto on_error;
pj_assert(rec.addr_count != 0);
/* Update CNAME alias, if present. */
if (rec.alias.slen) {
if (srv->cname.slen==0 && rec.alias.slen) {
pj_assert(rec.alias.slen <= (int)sizeof(srv->cname_buf));
srv->cname.ptr = srv->cname_buf;
pj_strcpy(&srv->cname, &rec.alias);
} else {
srv->cname.slen = 0;
//} else {
//srv->cname.slen = 0;
}
/* Update IP address of the corresponding hostname or CNAME */
if (srv->addr_cnt < ADDR_MAX_COUNT) {
srv->addr[srv->addr_cnt++].s_addr = rec.addr[0].s_addr;
PJ_LOG(5,(query_job->objname,
"DNS A for %.*s: %s",
(int)srv->target_name.slen,
srv->target_name.ptr,
pj_inet_ntoa(rec.addr[0])));
}
/* Check for multiple IP addresses */
for (i=1; i<rec.addr_count && srv->addr_cnt < ADDR_MAX_COUNT; ++i)
for (i=0; i<rec.addr_count && srv->addr_cnt<ADDR_MAX_COUNT; ++i)
{
srv->addr[srv->addr_cnt++].s_addr = rec.addr[i].s_addr;
pj_bool_t added = PJ_FALSE;
PJ_LOG(5,(query_job->objname,
"Additional DNS A for %.*s: %s",
(int)srv->target_name.slen,
srv->target_name.ptr,
pj_inet_ntoa(rec.addr[i])));
if (is_type_a && rec.addr[i].af == pj_AF_INET()) {
pj_sockaddr_init(pj_AF_INET(), &srv->addr[srv->addr_cnt],
NULL, srv->port);
srv->addr[srv->addr_cnt].ipv4.sin_addr =
rec.addr[i].ip.v4;
added = PJ_TRUE;
} else if (!is_type_a && rec.addr[i].af == pj_AF_INET6()) {
pj_sockaddr_init(pj_AF_INET6(), &srv->addr[srv->addr_cnt],
NULL, srv->port);
srv->addr[srv->addr_cnt].ipv6.sin6_addr =
rec.addr[i].ip.v6;
added = PJ_TRUE;
} else {
/* Mismatched address family, e.g: getting IPv6 address in
* DNS A query resolution.
*/
PJ_LOG(4,(query_job->objname,
"Bad address family in DNS %s query for %.*s",
(is_type_a? "A" : "AAAA"),
(int)srv->target_name.slen,
srv->target_name.ptr));
}
if (added) {
PJ_LOG(5,(query_job->objname,
"DNS %s for %.*s: %s",
(is_type_a? "A" : "AAAA"),
(int)srv->target_name.slen,
srv->target_name.ptr,
pj_sockaddr_print(&srv->addr[srv->addr_cnt],
addr, sizeof(addr), 2)));
++srv->addr_cnt;
}
}
} else if (status != PJ_SUCCESS) {
@ -596,11 +738,17 @@ static void dns_callback(void *user_data,
/* Log error */
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(4,(query_job->objname, "DNS A record resolution failed: %s",
PJ_LOG(4,(query_job->objname,
"DNS %s record resolution failed: %s",
(is_type_a? "A" : "AAAA"),
errmsg));
}
++query_job->host_resolved;
/* Increment host resolved count when both DNS A and AAAA record
* queries for this server are completed.
*/
if (srv_completed)
++query_job->host_resolved;
} else {
pj_assert(!"Unexpected state!");
@ -617,6 +765,7 @@ static void dns_callback(void *user_data,
for (i=0; i<query_job->srv_cnt; ++i) {
unsigned j;
struct srv_target *srv2 = &query_job->srv[i];
pj_dns_addr_record *s = &srv_rec.entry[srv_rec.count].server;
srv_rec.entry[srv_rec.count].priority = srv2->priority;
srv_rec.entry[srv_rec.count].weight = srv2->weight;
@ -628,10 +777,13 @@ static void dns_callback(void *user_data,
pj_assert(srv2->addr_cnt <= PJ_DNS_MAX_IP_IN_A_REC);
for (j=0; j<srv2->addr_cnt; ++j) {
srv_rec.entry[srv_rec.count].server.addr[j].s_addr =
srv2->addr[j].s_addr;
++srv_rec.entry[srv_rec.count].server.addr_count;
for (j=0; j<srv2->addr_cnt; ++j) {
s->addr[j].af = srv2->addr[j].addr.sa_family;
if (s->addr[j].af == pj_AF_INET())
s->addr[j].ip.v4 = srv2->addr[j].ipv4.sin_addr;
else
s->addr[j].ip.v6 = srv2->addr[j].ipv6.sin6_addr;
++s->addr_count;
}
if (srv2->addr_cnt > 0) {
@ -674,6 +826,10 @@ on_error:
query_job->domain_part.ptr,
status,
pj_strerror(status,errmsg,sizeof(errmsg)).ptr));
/* Cancel any pending query */
pj_dns_srv_cancel_query(query_job, PJ_FALSE);
(*query_job->cb)(query_job->token, status, NULL);
return;
}

View File

@ -33,7 +33,6 @@ static int stun_timer[] = {500, 500, 500, 500 };
#define STUN_MAGIC 0x2112A442
#define THIS_FILE "stun_client.c"
#define LOG_ADDR(addr) pj_inet_ntoa(addr.sin_addr), pj_ntohs(addr.sin_port)
#define TRACE_(x) PJ_LOG(6,x)

View File

@ -34,7 +34,7 @@ export PJLIB_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
activesock.o array.o config.o ctype.o errno.o except.o fifobuf.o \
guid.o hash.o ip_helper_generic.o list.o lock.o log.o os_time_common.o \
os_info.o pool.o pool_buf.o pool_caching.o pool_dbg.o rand.o \
rbtree.o sock_common.o sock_qos_common.o sock_qos_bsd.o \
rbtree.o sock_common.o sock_qos_common.o \
ssl_sock_common.o ssl_sock_ossl.o ssl_sock_dump.o \
string.o timer.o types.o
export PJLIB_CFLAGS += $(_CFLAGS)

View File

@ -33,4 +33,10 @@ export TEST_OBJS += @ac_main_obj@
export TARGETS = $(PJLIB_LIB) $(PJLIB_SONAME)
export TARGETS_EXE = $(TEST_EXE)
ifeq (@ac_ssl_has_ec@,1)
export PJLIB_CFLAGS += -DPJ_SSL_SOCK_OSSL_HAS_EC=1
endif
ifeq (@ac_ssl_has_sigalg@,1)
export PJLIB_CFLAGS += -DPJ_SSL_SOCK_OSSL_HAS_SIGALG=1
endif

View File

@ -18,6 +18,8 @@ export PJLIB_OBJS += ioqueue_select.o
export PJLIB_OBJS += file_access_unistd.o file_io_ansi.o
export PJLIB_OBJS += sock_qos_darwin.o
#
# TEST_OBJS are operating system specific object files to be included in
# the test application.

View File

@ -21,6 +21,8 @@ export PJLIB_OBJS += compat/sigjmp.o compat/setjmp_i386.o \
export PJLIB_OBJS += ioqueue_epoll.o
#export PJLIB_OBJS += ioqueue_select.o
export PJLIB_OBJS += sock_qos_bsd.o
#
# TEST_OBJS are operating system specific object files to be included in
# the test application.

View File

@ -20,6 +20,8 @@ else
export PJLIB_OBJS += ioqueue_select.o
endif
export PJLIB_OBJS += sock_qos_bsd.o
#
# TEST_OBJS are operating system specific object files to be included in
# the test application.

View File

@ -18,6 +18,7 @@ export PJLIB_OBJS += addr_resolv_sock.o guid_simple.o \
export PJLIB_OBJS += ioqueue_select.o
export PJLIB_OBJS += file_access_unistd.o file_io_ansi.o
export PJLIB_OBJS += sock_qos_bsd.o
#
# TEST_OBJS are operating system specific object files to be included in

View File

@ -17,6 +17,8 @@ export PJLIB_OBJS += addr_resolv_sock.o file_access_unistd.o \
export PJLIB_OBJS += ioqueue_select.o
#export PJLIB_OBJS += ioqueue_epoll.o
export PJLIB_OBJS += sock_qos_bsd.o
#
# TEST_OBJS are operating system specific object files to be included in
# the test application.

View File

@ -19,6 +19,8 @@ export PJLIB_OBJS += ioqueue_select.o
export PJLIB_OBJS += file_io_win32.o file_access_win32.o
#export PJLIB_OBJS += file_io_ansi.o
export PJLIB_OBJS += sock_qos_bsd.o
#
# TEST_OBJS are operating system specific object files to be included in
# the test application.

View File

@ -83,6 +83,7 @@
#undef PJ_HAS_WINSOCK2_H
#undef PJ_HAS_WS2TCPIP_H
#undef PJ_SOCK_HAS_IPV6_V6ONLY
#undef PJ_SOCK_HAS_INET_ATON
#undef PJ_SOCK_HAS_INET_PTON
#undef PJ_SOCK_HAS_INET_NTOP
@ -128,6 +129,9 @@
*/
#undef PJ_SELECT_NEEDS_NFDS
/* Was Linux epoll support enabled */
#undef PJ_HAS_LINUX_EPOLL
/* Is errno a good way to retrieve OS errors?
*/
#undef PJ_HAS_ERRNO_VAR
@ -162,6 +166,9 @@
# define PJ_OS_HAS_CHECK_STACK 0
#endif
/* Is localtime_r() available? */
#undef PJ_HAS_LOCALTIME_R
/* Unicode? */
#undef PJ_NATIVE_STRING_IS_UNICODE
@ -172,13 +179,18 @@
#undef PJ_ATOMIC_VALUE_TYPE
#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
/* Disable local host resolution in pj_gethostip() (see ticket #1342) */
# define PJ_GETHOSTIP_DISABLE_LOCAL_RESOLUTION 1
/* Use pj_getaddrinfo() (instead of pj_inet_pton()) in
* pj_sockaddr_set_str_addr()
*/
# define PJ_SOCKADDR_USE_GETADDRINFO 1
# include "TargetConditionals.h"
# if TARGET_OS_IPHONE
# 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

View File

@ -55,6 +55,8 @@
#define PJ_HAS_WINSOCK_H 0
#define PJ_HAS_WINSOCK2_H 0
#define PJ_HAS_LOCALTIME_R 1
/* Is errno a good way to retrieve OS errors?
*/
#define PJ_HAS_ERRNO_VAR 1

View File

@ -55,6 +55,8 @@
#define PJ_HAS_WINSOCK_H 0
#define PJ_HAS_WINSOCK2_H 0
#define PJ_HAS_LOCALTIME_R 1
#define PJ_SOCK_HAS_INET_ATON 1
/* Set 1 if native sockaddr_in has sin_len member.

View File

@ -64,7 +64,7 @@
# define s_addr S_un.S_addr
# endif
# if !defined(IPPROTO_IPV6)
# if !defined(IPPROTO_IPV6) && (_WIN32_WINNT == 0x0500)
/* Need to download and install IPv6Kit for this platform.
* Please see the comments above about Visual Studio 6.
*/
@ -158,16 +158,22 @@
# define OSERR_EINPROGRESS WSAEINPROGRESS
# define OSERR_ECONNRESET WSAECONNRESET
# define OSERR_ENOTCONN WSAENOTCONN
# define OSERR_EAFNOSUPPORT WSAEAFNOSUPPORT
# define OSERR_ENOPROTOOPT WSAENOPROTOOPT
#elif defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
# define OSERR_EWOULDBLOCK -1
# define OSERR_EINPROGRESS -1
# define OSERR_ECONNRESET -1
# define OSERR_ENOTCONN -1
# define OSERR_EAFNOSUPPORT -1
# define OSERR_ENOPROTOOPT -1
#else
# define OSERR_EWOULDBLOCK EWOULDBLOCK
# define OSERR_EINPROGRESS EINPROGRESS
# define OSERR_ECONNRESET ECONNRESET
# define OSERR_ENOTCONN ENOTCONN
# define OSERR_EAFNOSUPPORT EAFNOSUPPORT
# define OSERR_ENOPROTOOPT ENOPROTOOPT
#endif

View File

@ -872,6 +872,9 @@
/** QoS backend for Symbian */
#define PJ_QOS_SYMBIAN 4
/** QoS backend for Darwin */
#define PJ_QOS_DARWIN 5
/**
* Force the use of some QoS backend API for some platforms.
*/
@ -917,6 +920,16 @@
#endif
/**
* Define the maximum number of curves supported by the secure socket.
*
* Default: 32
*/
#ifndef PJ_SSL_SOCK_MAX_CURVES
# define PJ_SSL_SOCK_MAX_CURVES 32
#endif
/**
* Disable WSAECONNRESET error for UDP sockets on Win32 platforms. See
* https://trac.pjsip.org/repos/ticket/1197.
@ -1247,7 +1260,7 @@ PJ_BEGIN_DECL
#define PJ_VERSION_NUM_MAJOR 2
/** PJLIB version minor number. */
#define PJ_VERSION_NUM_MINOR 4
#define PJ_VERSION_NUM_MINOR 5
/** PJLIB version revision number. */
#define PJ_VERSION_NUM_REV 5

View File

@ -436,6 +436,8 @@
#define PJMEDIA_HAS_SPEEX_AEC 0
#undef PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
#define PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO 0
#undef PJMEDIA_AUDIO_DEV_HAS_ALSA
#define PJMEDIA_AUDIO_DEV_HAS_ALSA 0
#endif
@ -475,7 +477,6 @@
# define PJ_DEBUG 0
# define PJSIP_SAFE_MODULE 0
# define PJ_HAS_STRICMP_ALNUM 0
# define PJ_HASH_USE_OWN_TOLOWER 1
# define PJSIP_UNESCAPE_IN_PLACE 1
# if defined(PJ_WIN32) || defined(PJ_WIN64)

View File

@ -105,8 +105,9 @@ enum pj_log_decoration
* @hideinitializer
*/
#define PJ_LOG(level,arg) do { \
if (level <= pj_log_get_level()) \
if (level <= pj_log_get_level()) { \
pj_log_wrapper_##level(arg); \
} \
} while (0)
/**

View File

@ -276,6 +276,19 @@ extern const pj_uint16_t PJ_IPTOS_MINCOST;
#endif
/** IPV6_TCLASS optname in setsockopt(). @see pj_IPV6_TCLASS() */
extern const pj_uint16_t PJ_IPV6_TCLASS;
#if defined(PJ_DLL)
/** Get #PJ_IPV6_TCLASS constant */
PJ_DECL(int) pj_IPV6_TCLASS(void);
#else
/** Get #PJ_IPV6_TCLASS constant */
# define pj_IPV6_TCLASS() PJ_IPV6_TCLASS
#endif
/**
* Values to be specified as \c optname when calling #pj_sock_setsockopt()
* or #pj_sock_getsockopt().

View File

@ -121,10 +121,11 @@ PJ_BEGIN_DECL
typedef enum pj_qos_type
{
PJ_QOS_TYPE_BEST_EFFORT,
PJ_QOS_TYPE_BACKGROUND,
PJ_QOS_TYPE_BACKGROUND,
PJ_QOS_TYPE_VIDEO,
PJ_QOS_TYPE_VOICE,
PJ_QOS_TYPE_CONTROL
PJ_QOS_TYPE_CONTROL,
PJ_QOS_TYPE_SIGNALLING
} pj_qos_type;
\endcode
@ -141,6 +142,7 @@ PJ_BEGIN_DECL
VIDEO 0x28 VI (Video) 5
VOICE 0x30 VO (Voice) 6
CONTROL 0x38 VO (Voice) 7
SIGNALLING 0x28 VI (Video) 5
=================================================================
\endcode
@ -235,10 +237,11 @@ typedef enum pj_qos_type
PJ_QOS_TYPE_BEST_EFFORT, /**< Best effort traffic (default value).
Any QoS function calls with specifying
this value are effectively no-op */
PJ_QOS_TYPE_BACKGROUND, /**< Background traffic. */
PJ_QOS_TYPE_BACKGROUND, /**< Background traffic. */
PJ_QOS_TYPE_VIDEO, /**< Video traffic. */
PJ_QOS_TYPE_VOICE, /**< Voice traffic. */
PJ_QOS_TYPE_CONTROL /**< Control traffic. */
PJ_QOS_TYPE_CONTROL, /**< Control traffic. */
PJ_QOS_TYPE_SIGNALLING /**< Signalling traffic. */
} pj_qos_type;
/**

View File

@ -181,6 +181,9 @@ typedef struct pj_ssl_cert_info {
} subj_alt_name; /**< Subject alternative
name extension */
pj_str_t raw; /**< Raw certificate in PEM format, only
available for remote certificate. */
} pj_ssl_cert_info;
@ -398,6 +401,99 @@ PJ_DECL(const char*) pj_ssl_cipher_name(pj_ssl_cipher cipher);
*/
PJ_DECL(pj_ssl_cipher) pj_ssl_cipher_id(const char *cipher_name);
/**
* Elliptic curves enumeration.
*/
typedef enum pj_ssl_curve
{
PJ_TLS_UNKNOWN_CURVE = 0,
PJ_TLS_CURVE_SECT163K1 = 1,
PJ_TLS_CURVE_SECT163R1 = 2,
PJ_TLS_CURVE_SECT163R2 = 3,
PJ_TLS_CURVE_SECT193R1 = 4,
PJ_TLS_CURVE_SECT193R2 = 5,
PJ_TLS_CURVE_SECT233K1 = 6,
PJ_TLS_CURVE_SECT233R1 = 7,
PJ_TLS_CURVE_SECT239K1 = 8,
PJ_TLS_CURVE_SECT283K1 = 9,
PJ_TLS_CURVE_SECT283R1 = 10,
PJ_TLS_CURVE_SECT409K1 = 11,
PJ_TLS_CURVE_SECT409R1 = 12,
PJ_TLS_CURVE_SECT571K1 = 13,
PJ_TLS_CURVE_SECT571R1 = 14,
PJ_TLS_CURVE_SECP160K1 = 15,
PJ_TLS_CURVE_SECP160R1 = 16,
PJ_TLS_CURVE_SECP160R2 = 17,
PJ_TLS_CURVE_SECP192K1 = 18,
PJ_TLS_CURVE_SECP192R1 = 19,
PJ_TLS_CURVE_SECP224K1 = 20,
PJ_TLS_CURVE_SECP224R1 = 21,
PJ_TLS_CURVE_SECP256K1 = 22,
PJ_TLS_CURVE_SECP256R1 = 23,
PJ_TLS_CURVE_SECP384R1 = 24,
PJ_TLS_CURVE_SECP521R1 = 25,
PJ_TLS_CURVE_BRAINPOOLP256R1 = 26,
PJ_TLS_CURVE_BRAINPOOLP384R1 = 27,
PJ_TLS_CURVE_BRAINPOOLP512R1 = 28,
PJ_TLS_CURVE_ARBITRARY_EXPLICIT_PRIME_CURVES = 0XFF01,
PJ_TLS_CURVE_ARBITRARY_EXPLICIT_CHAR2_CURVES = 0XFF02
} pj_ssl_curve;
/**
* Get curve list supported by SSL/TLS backend.
*
* @param curves The curves buffer to receive curve list.
* @param curves_num Maximum number of curves to be received.
*
* @return PJ_SUCCESS when successful.
*/
PJ_DECL(pj_status_t) pj_ssl_curve_get_availables(pj_ssl_curve curves[],
unsigned *curve_num);
/**
* Check if the specified curve is supported by SSL/TLS backend.
*
* @param curve The curve.
*
* @return PJ_TRUE when supported.
*/
PJ_DECL(pj_bool_t) pj_ssl_curve_is_supported(pj_ssl_curve curve);
/**
* Get curve name string.
*
* @param curve The curve.
*
* @return The curve name or NULL if curve is not recognized/
* supported.
*/
PJ_DECL(const char*) pj_ssl_curve_name(pj_ssl_curve curve);
/**
* Get curve ID from curve name string. Note that on different backends
* (e.g. OpenSSL or Symbian implementation), curve names may not be
* equivalent for the same curve ID.
*
* @param curve_name The curve name string.
*
* @return The curve ID or PJ_TLS_UNKNOWN_CURVE if the curve
* name string is not recognized/supported.
*/
PJ_DECL(pj_ssl_curve) pj_ssl_curve_id(const char *curve_name);
/*
* Entropy enumeration
*/
typedef enum pj_ssl_entropy
{
PJ_SSL_ENTROPY_NONE = 0,
PJ_SSL_ENTROPY_EGD = 1,
PJ_SSL_ENTROPY_RANDOM = 2,
PJ_SSL_ENTROPY_URANDOM = 3,
PJ_SSL_ENTROPY_FILE = 4,
PJ_SSL_ENTROPY_UNKNOWN = 0x0F
} pj_ssl_entropy_t;
/**
* This structure contains the callbacks to be called by the secure socket.
@ -766,6 +862,51 @@ typedef struct pj_ssl_sock_param
*/
pj_ssl_cipher *ciphers;
/**
* Number of curves contained in the specified curve preference.
* If this is set to zero, then default curve list of the backend
* will be used.
*
* Default: 0 (zero).
*/
unsigned curves_num;
/**
* Curves and order preference. The #pj_ssl_curve_get_availables()
* can be used to check the available curves supported by backend.
*/
pj_ssl_curve *curves;
/**
* The supported signature algorithms. Set the sigalgs string
* using this form:
* "<DIGEST>+<ALGORITHM>:<DIGEST>+<ALGORITHM>"
* Digests are: "RSA", "DSA" or "ECDSA"
* Algorithms are: "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512"
* Example: "ECDSA+SHA256:RSA+SHA256"
*/
pj_str_t sigalgs;
/**
* Reseed random number generator.
* For type #PJ_SSL_ENTROPY_FILE, parameter \a entropy_path
* must be set to a file.
* For type #PJ_SSL_ENTROPY_EGD, parameter \a entropy_path
* must be set to a socket.
*
* Default value is PJ_SSL_ENTROPY_NONE.
*/
pj_ssl_entropy_t entropy_type;
/**
* When using a file/socket for entropy #PJ_SSL_ENTROPY_EGD or
* #PJ_SSL_ENTROPY_FILE, \a entropy_path must contain the path
* to entropy socket/file.
*
* Default value is an empty string.
*/
pj_str_t entropy_path;
/**
* Security negotiation timeout. If this is set to zero (both sec and
* msec), the negotiation doesn't have a timeout.
@ -863,6 +1004,18 @@ typedef struct pj_ssl_sock_param
PJ_DECL(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param);
/**
* Duplicate pj_ssl_sock_param.
*
* @param pool Pool to allocate memory.
* @param dst Destination parameter.
* @param src Source parameter.
*/
PJ_DECL(void) pj_ssl_sock_param_copy(pj_pool_t *pool,
pj_ssl_sock_param *dst,
const pj_ssl_sock_param *src);
/**
* Create secure socket instance.
*
@ -1114,6 +1267,30 @@ PJ_DECL(pj_status_t) pj_ssl_sock_start_accept(pj_ssl_sock_t *ssock,
int addr_len);
/**
* Same as #pj_ssl_sock_start_accept(), but application can provide
* a secure socket parameter, which will be used to create a new secure
* socket reported in \a on_accept_complete() callback when there is
* an incoming connection.
*
* @param ssock The secure socket.
* @param pool Pool used to allocate some internal data for the
* operation.
* @param localaddr Local address to bind on.
* @param addr_len Length of buffer containing local address.
* @param newsock_param Secure socket parameter for new accepted sockets.
*
* @return PJ_SUCCESS if the operation has been successful,
* or the appropriate error code on failure.
*/
PJ_DECL(pj_status_t)
pj_ssl_sock_start_accept2(pj_ssl_sock_t *ssock,
pj_pool_t *pool,
const pj_sockaddr_t *local_addr,
int addr_len,
const pj_ssl_sock_param *newsock_param);
/**
* Starts asynchronous socket connect() operation and SSL/TLS handshaking
* for this socket. Once the connection is done (either successfully or not),

View File

@ -469,6 +469,8 @@ PJ_IDECL(void) pj_strcat2(pj_str_t *dst, const char *src);
*/
PJ_INLINE(char*) pj_strchr( const pj_str_t *str, int chr)
{
if (str->slen == 0)
return NULL;
return (char*) memchr((char*)str->ptr, chr, str->slen);
}

View File

@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/assert.h>
#include <pj/pool.h>
PJ_IDEF(pj_str_t) pj_str(char *str)
@ -117,8 +118,10 @@ PJ_IDEF(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src)
PJ_IDEF(pj_str_t*) pj_strncpy( pj_str_t *dst, const pj_str_t *src,
pj_ssize_t max)
{
pj_assert(max >= 0);
if (max > src->slen) max = src->slen;
pj_memcpy(dst->ptr, src->ptr, max);
if (max > 0)
pj_memcpy(dst->ptr, src->ptr, max);
dst->slen = max;
return dst;
}
@ -126,6 +129,8 @@ PJ_IDEF(pj_str_t*) pj_strncpy( pj_str_t *dst, const pj_str_t *src,
PJ_IDEF(pj_str_t*) pj_strncpy_with_null( pj_str_t *dst, const pj_str_t *src,
pj_ssize_t max)
{
pj_assert(max > 0);
if (max <= src->slen)
max = max-1;
else

View File

@ -82,6 +82,8 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6 ||
af==PJ_AF_UNSPEC, PJ_EINVAL);
#if PJ_WIN32_WINCE
/* Check if nodename is IP address */
pj_bzero(&ai[0], sizeof(ai[0]));
if ((af==PJ_AF_INET || af==PJ_AF_UNSPEC) &&
@ -109,6 +111,10 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
return PJ_SUCCESS;
}
#else /* PJ_WIN32_WINCE */
PJ_UNUSED_ARG(has_addr);
#endif
/* Copy node name to null terminated string. */
if (nodename->slen >= PJ_MAX_HOSTNAME)
return PJ_ENAMETOOLONG;
@ -145,10 +151,10 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
/* Store address */
addr_size = sizeof(*addr);
if (af == PJ_AF_INET6) {
if (addr->sa_family == PJ_AF_INET6) {
addr_size = addr->sa_len;
}
PJ_ASSERT_ON_FAIL(addr_size <= sizeof(pj_sockaddr), continue);
PJ_ASSERT_ON_FAIL(addr_size <= sizeof(pj_sockaddr), continue);
pj_memcpy(&ai[i].ai_addr, addr, addr_size);
PJ_SOCKADDR_RESET_LEN(&ai[i].ai_addr);
@ -157,6 +163,9 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
}
*count = i;
if (*count == 0)
status = PJ_ERESOLVE;
} else {
status = PJ_ERESOLVE;
}
@ -205,7 +214,7 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
freeaddrinfo(orig_res);
/* Done */
return PJ_SUCCESS;
return (*count > 0? PJ_SUCCESS : PJ_ERESOLVE);
#endif
#else /* PJ_SOCK_HAS_GETADDRINFO */
@ -213,6 +222,8 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
PJ_ASSERT_RETURN(count && *count, PJ_EINVAL);
#if PJ_WIN32_WINCE
/* Check if nodename is IP address */
pj_bzero(&ai[0], sizeof(ai[0]));
if ((af==PJ_AF_INET || af==PJ_AF_UNSPEC) &&
@ -241,6 +252,10 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
return PJ_SUCCESS;
}
#else /* PJ_WIN32_WINCE */
PJ_UNUSED_ARG(has_addr);
#endif
if (af == PJ_AF_INET || af == PJ_AF_UNSPEC) {
pj_hostent he;
unsigned i, max_count;
@ -273,7 +288,7 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename,
(*count)++;
}
return PJ_SUCCESS;
return (*count > 0? PJ_SUCCESS : PJ_ERESOLVE);
} else {
/* IPv6 is not supported */

View File

@ -50,7 +50,7 @@ PJ_DEF(const char*) pj_get_version(void)
PJ_DEF(void) pj_dump_config(void)
{
PJ_LOG(3, (id, "PJLIB (c)2008-2009 Teluu Inc."));
PJ_LOG(3, (id, "PJLIB (c)2008-2016 Teluu Inc."));
PJ_LOG(3, (id, "Dumping configurations:"));
PJ_LOG(3, (id, " PJ_VERSION : %s", PJ_VERSION));
PJ_LOG(3, (id, " PJ_M_NAME : %s", PJ_M_NAME));
@ -85,5 +85,6 @@ PJ_DEF(void) pj_dump_config(void)
PJ_LOG(3, (id, " PJ_TIMESTAMP_USE_RDTSC: : %d", PJ_TIMESTAMP_USE_RDTSC));
PJ_LOG(3, (id, " PJ_OS_HAS_CHECK_STACK : %d", PJ_OS_HAS_CHECK_STACK));
PJ_LOG(3, (id, " PJ_HAS_HIGH_RES_TIMER : %d", PJ_HAS_HIGH_RES_TIMER));
PJ_LOG(3, (id, " PJ_HAS_IPV6 : %d", PJ_HAS_IPV6));
}

117
pjlib/src/pj/guid_android.c Normal file
View File

@ -0,0 +1,117 @@
/* $Id$ */
/*
* Copyright (C) 2015-2016 Teluu Inc. (http://www.teluu.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This original code was kindly contributed by Johan Lantz.
*/
#include <pj/guid.h>
#include <pj/log.h>
#include <pj/string.h>
#include <jni.h>
extern JavaVM *pj_jni_jvm;
static pj_bool_t attach_jvm(JNIEnv **jni_env)
{
if ((*pj_jni_jvm)->GetEnv(pj_jni_jvm, (void **)jni_env,
JNI_VERSION_1_4) < 0)
{
if ((*pj_jni_jvm)->AttachCurrentThread(pj_jni_jvm, jni_env, NULL) < 0)
{
jni_env = NULL;
return PJ_FALSE;
}
return PJ_TRUE;
}
return PJ_FALSE;
}
#define detach_jvm(attached) \
if (attached) \
(*pj_jni_jvm)->DetachCurrentThread(pj_jni_jvm);
PJ_DEF_DATA(const unsigned) PJ_GUID_STRING_LENGTH=36;
PJ_DEF(unsigned) pj_GUID_STRING_LENGTH()
{
return PJ_GUID_STRING_LENGTH;
}
PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)
{
jclass uuid_class;
jmethodID get_uuid_method;
jmethodID to_string_method;
JNIEnv *jni_env = 0;
jobject javaUuid;
jstring uuid_string;
const char *native_string;
pj_str_t native_str;
pj_bool_t attached = attach_jvm(&jni_env);
if (!jni_env)
goto on_error;
uuid_class = (jclass)(*jni_env)->NewGlobalRef(jni_env,
(*jni_env)->FindClass(jni_env, "java/util/UUID"));
if (uuid_class == 0)
goto on_error;
get_uuid_method = (*jni_env)->GetStaticMethodID(jni_env, uuid_class,
"randomUUID",
"()Ljava/util/UUID;");
if (get_uuid_method == 0)
goto on_error;
javaUuid = (*jni_env)->CallStaticObjectMethod(jni_env, uuid_class,
get_uuid_method);
if (javaUuid == 0)
goto on_error;
to_string_method = (*jni_env)->GetMethodID(jni_env, uuid_class,
"toString",
"()Ljava/lang/String;");
if (to_string_method == 0)
goto on_error;
uuid_string = (*jni_env)->CallObjectMethod(jni_env, javaUuid,
to_string_method);
if (uuid_string == 0)
goto on_error;
native_string = (*jni_env)->GetStringUTFChars(jni_env, uuid_string,
JNI_FALSE);
if (native_string == 0)
goto on_error;
native_str.ptr = (char *)native_string;
native_str.slen = pj_ansi_strlen(native_string);
pj_strncpy(str, &native_str, PJ_GUID_STRING_LENGTH);
(*jni_env)->ReleaseStringUTFChars(jni_env, uuid_string, native_string);
detach_jvm(attached);
return str;
on_error:
PJ_LOG(2, ("guid_android.c", ("Error generating UUID")));
detach_jvm(attached);
return NULL;
}

View File

@ -76,26 +76,12 @@ PJ_DEF(pj_uint32_t) pj_hash_calc_tolower( pj_uint32_t hval,
{
long i;
#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)
lower = (char)(c | 32);
else
lower = (char)c;
if (result)
result[i] = lower;
hval = hval * PJ_HASH_MULTIPLIER + lower;
}
#else
for (i=0; i<key->slen; ++i) {
char lower = (char)pj_tolower(key->ptr[i]);
if (result)
result[i] = lower;
hval = hval * PJ_HASH_MULTIPLIER + lower;
}
#endif
return hval;
}

View File

@ -1125,7 +1125,7 @@ static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type)
if (type == PJ_MUTEX_SIMPLE) {
#if (defined(PJ_LINUX) && PJ_LINUX!=0) || \
defined(PJ_HAS_PTHREAD_MUTEXATTR_SETTYPE)
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP);
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
#elif (defined(PJ_RTEMS) && PJ_RTEMS!=0) || \
defined(PJ_PTHREAD_MUTEXATTR_T_HAS_RECURSIVE)
/* Nothing to do, default is simple */
@ -1135,7 +1135,7 @@ static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type)
} else {
#if (defined(PJ_LINUX) && PJ_LINUX!=0) || \
defined(PJ_HAS_PTHREAD_MUTEXATTR_SETTYPE)
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#elif (defined(PJ_RTEMS) && PJ_RTEMS!=0) || \
defined(PJ_PTHREAD_MUTEXATTR_T_HAS_RECURSIVE)
// Phil Torre <ptorre@zetron.com>:

View File

@ -28,19 +28,24 @@
PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)
{
struct tm *local_time;
struct tm local_time;
PJ_CHECK_STACK();
local_time = localtime((time_t*)&tv->sec);
#if defined(PJ_HAS_LOCALTIME_R) && PJ_HAS_LOCALTIME_R != 0
localtime_r((time_t*)&tv->sec, &local_time);
#else
/* localtime() is NOT thread-safe. */
local_time = *localtime((time_t*)&tv->sec);
#endif
pt->year = local_time->tm_year+1900;
pt->mon = local_time->tm_mon;
pt->day = local_time->tm_mday;
pt->hour = local_time->tm_hour;
pt->min = local_time->tm_min;
pt->sec = local_time->tm_sec;
pt->wday = local_time->tm_wday;
pt->year = local_time.tm_year+1900;
pt->mon = local_time.tm_mon;
pt->day = local_time.tm_mday;
pt->hour = local_time.tm_hour;
pt->min = local_time.tm_min;
pt->sec = local_time.tm_sec;
pt->wday = local_time.tm_wday;
pt->msec = tv->msec;
return PJ_SUCCESS;

View File

@ -160,6 +160,68 @@ PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
return PJ_SUCCESS;
}
#elif defined(__ANDROID__)
#include <errno.h>
#include <linux/android_alarm.h>
#include <fcntl.h>
#include <time.h>
#define NSEC_PER_SEC 1000000000
static int s_alarm_fd = -1;
void close_alarm_fd()
{
if (s_alarm_fd != -1)
close(s_alarm_fd);
s_alarm_fd = -1;
}
PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
{
struct timespec tp;
int err = -1;
if (s_alarm_fd == -1) {
int fd = open("/dev/alarm", O_RDONLY);
if (fd >= 0) {
s_alarm_fd = fd;
pj_atexit(&close_alarm_fd);
}
}
if (s_alarm_fd != -1) {
err = ioctl(s_alarm_fd,
ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &tp);
}
if (err != 0) {
/* Fallback to CLOCK_MONOTONIC if /dev/alarm is not found, or
* getting ANDROID_ALARM_ELAPSED_REALTIME fails.
*/
err = clock_gettime(CLOCK_MONOTONIC, &tp);
}
if (err != 0) {
return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
}
ts->u64 = tp.tv_sec;
ts->u64 *= NSEC_PER_SEC;
ts->u64 += tp.tv_nsec;
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
{
freq->u32.hi = 0;
freq->u32.lo = NSEC_PER_SEC;
return PJ_SUCCESS;
}
#elif defined(USE_POSIX_TIMERS) && USE_POSIX_TIMERS != 0
#include <sys/time.h>
#include <time.h>

View File

@ -131,6 +131,14 @@ const pj_uint16_t PJ_IPTOS_MINCOST = 0x02;
#endif
/* IPV6_TCLASS */
#ifdef IPV6_TCLASS
const pj_uint16_t PJ_IPV6_TCLASS = IPV6_TCLASS;
#else
const pj_uint16_t PJ_IPV6_TCLASS = 0xFFFF;
#endif
/* optname values. */
const pj_uint16_t PJ_SO_TYPE = SO_TYPE;
const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF;
@ -539,6 +547,12 @@ PJ_DEF(pj_status_t) pj_sock_socket(int af,
pj_sock_setsockopt(*sock, pj_SOL_SOCKET(), pj_SO_NOSIGPIPE(),
&val, sizeof(val));
}
#if defined(PJ_SOCK_HAS_IPV6_V6ONLY) && PJ_SOCK_HAS_IPV6_V6ONLY != 0
if (af == PJ_AF_INET6) {
pj_sock_setsockopt(*sock, PJ_SOL_IPV6, IPV6_V6ONLY,
&val, sizeof(val));
}
#endif
#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0
if (type == pj_SOCK_DGRAM()) {

View File

@ -172,8 +172,12 @@ PJ_DEF(pj_status_t) pj_sockaddr_set_str_addr(int af,
PJ_SOCKADDR_RESET_LEN(addr);
if (str_addr && str_addr->slen) {
#if defined(PJ_SOCKADDR_USE_GETADDRINFO) && PJ_SOCKADDR_USE_GETADDRINFO!=0
if (1) {
#else
status = pj_inet_pton(PJ_AF_INET6, str_addr, &addr->ipv6.sin6_addr);
if (status != PJ_SUCCESS) {
#endif
pj_addrinfo ai;
unsigned count = 1;
@ -181,6 +185,7 @@ PJ_DEF(pj_status_t) pj_sockaddr_set_str_addr(int af,
if (status==PJ_SUCCESS) {
pj_memcpy(&addr->ipv6.sin6_addr, &ai.ai_addr.ipv6.sin6_addr,
sizeof(addr->ipv6.sin6_addr));
addr->ipv6.sin6_scope_id = ai.ai_addr.ipv6.sin6_scope_id;
}
}
} else {
@ -1244,6 +1249,11 @@ PJ_DEF(int) pj_IPTOS_MINCOST(void)
return PJ_IPTOS_MINCOST;
}
PJ_DEF(int) pj_IPV6_TCLASS(void)
{
return PJ_IPV6_TCLASS;
}
PJ_DEF(pj_uint16_t) pj_SO_TYPE(void)
{
return PJ_SO_TYPE;

View File

@ -22,7 +22,7 @@
#include <pj/string.h>
/* This is the implementation of QoS with BSD socket's setsockopt(),
* using IP_TOS and SO_PRIORITY
* using IP_TOS/IPV6_TCLASS and SO_PRIORITY
*/
#if !defined(PJ_QOS_IMPLEMENTATION) || PJ_QOS_IMPLEMENTATION==PJ_QOS_BSD
@ -41,10 +41,30 @@ PJ_DEF(pj_status_t) pj_sock_set_qos_params(pj_sock_t sock,
/* Set TOS/DSCP */
if (param->flags & PJ_QOS_PARAM_HAS_DSCP) {
/* We need to know if the socket is IPv4 or IPv6 */
pj_sockaddr sa;
int salen = sizeof(salen);
/* Value is dscp_val << 2 */
int val = (param->dscp_val << 2);
status = pj_sock_setsockopt(sock, pj_SOL_IP(), pj_IP_TOS(),
&val, sizeof(val));
status = pj_sock_getsockname(sock, &sa, &salen);
if (status != PJ_SUCCESS)
return status;
if (sa.addr.sa_family == pj_AF_INET()) {
/* In IPv4, the DS field goes in the TOS field */
status = pj_sock_setsockopt(sock, pj_SOL_IP(), pj_IP_TOS(),
&val, sizeof(val));
} else if (sa.addr.sa_family == pj_AF_INET6()) {
/* In IPv6, the DS field goes in the Traffic Class field */
status = pj_sock_setsockopt(sock, pj_SOL_IPV6(),
pj_IPV6_TCLASS(),
&val, sizeof(val));
} else {
status = PJ_EINVAL;
}
if (status != PJ_SUCCESS) {
param->flags &= ~(PJ_QOS_PARAM_HAS_DSCP);
last_err = status;
@ -84,17 +104,33 @@ PJ_DEF(pj_status_t) pj_sock_get_qos_params(pj_sock_t sock,
{
pj_status_t last_err = PJ_ENOTSUP;
int val, optlen;
pj_sockaddr sa;
int salen = sizeof(salen);
pj_status_t status;
pj_bzero(p_param, sizeof(*p_param));
/* Get DSCP/TOS value */
optlen = sizeof(val);
status = pj_sock_getsockopt(sock, pj_SOL_IP(), pj_IP_TOS(),
&val, &optlen);
status = pj_sock_getsockname(sock, &sa, &salen);
if (status == PJ_SUCCESS) {
p_param->flags |= PJ_QOS_PARAM_HAS_DSCP;
p_param->dscp_val = (pj_uint8_t)(val >> 2);
optlen = sizeof(val);
if (sa.addr.sa_family == pj_AF_INET()) {
status = pj_sock_getsockopt(sock, pj_SOL_IP(), pj_IP_TOS(),
&val, &optlen);
} else if (sa.addr.sa_family == pj_AF_INET6()) {
status = pj_sock_getsockopt(sock, pj_SOL_IPV6(),
pj_IPV6_TCLASS(),
&val, &optlen);
} else {
status = PJ_EINVAL;
}
if (status == PJ_SUCCESS) {
p_param->flags |= PJ_QOS_PARAM_HAS_DSCP;
p_param->dscp_val = (pj_uint8_t)(val >> 2);
} else {
last_err = status;
}
} else {
last_err = status;
}

View File

@ -31,10 +31,11 @@ static const pj_qos_params qos_map[] =
{
/* flags dscp prio wmm_prio */
{ALL_FLAGS, 0x00, 0, PJ_QOS_WMM_PRIO_BULK_EFFORT}, /* BE */
{ALL_FLAGS, 0x08, 2, PJ_QOS_WMM_PRIO_BULK}, /* BK */
{ALL_FLAGS, 0x08, 2, PJ_QOS_WMM_PRIO_BULK}, /* BK */
{ALL_FLAGS, 0x28, 5, PJ_QOS_WMM_PRIO_VIDEO}, /* VI */
{ALL_FLAGS, 0x30, 6, PJ_QOS_WMM_PRIO_VOICE}, /* VO */
{ALL_FLAGS, 0x38, 7, PJ_QOS_WMM_PRIO_VOICE} /* CO */
{ALL_FLAGS, 0x38, 7, PJ_QOS_WMM_PRIO_VOICE}, /* CO */
{ALL_FLAGS, 0x28, 5, PJ_QOS_WMM_PRIO_VIDEO} /* SIG */
};

View File

@ -0,0 +1,427 @@
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/sock_qos.h>
#include <pj/assert.h>
#include <pj/errno.h>
#include <pj/string.h>
#include <pj/compat/socket.h>
/* This is the implementation of QoS with BSD socket's setsockopt(),
* using Darwin-specific SO_NET_SERVICE_TYPE if available, and IP_TOS/
* IPV6_TCLASS as fallback.
*/
#if !defined(PJ_QOS_IMPLEMENTATION) || PJ_QOS_IMPLEMENTATION==PJ_QOS_IOS
#include <sys/socket.h>
#ifdef SO_NET_SERVICE_TYPE
static pj_status_t sock_set_net_service_type(pj_sock_t sock, int val)
{
pj_status_t status;
status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), SO_NET_SERVICE_TYPE,
&val, sizeof(val));
if (status == PJ_STATUS_FROM_OS(OSERR_ENOPROTOOPT))
status = PJ_ENOTSUP;
return status;
}
#endif
static pj_status_t sock_set_net_service_type_type(pj_sock_t sock,
pj_qos_type type)
{
#ifdef SO_NET_SERVICE_TYPE
int val = NET_SERVICE_TYPE_BE;
switch (type) {
case PJ_QOS_TYPE_BEST_EFFORT:
val = NET_SERVICE_TYPE_BE;
break;
case PJ_QOS_TYPE_BACKGROUND:
val = NET_SERVICE_TYPE_BK;
break;
case PJ_QOS_TYPE_SIGNALLING:
val = NET_SERVICE_TYPE_SIG;
break;
case PJ_QOS_TYPE_VIDEO:
val = NET_SERVICE_TYPE_VI;
break;
case PJ_QOS_TYPE_VOICE:
case PJ_QOS_TYPE_CONTROL:
default:
val = NET_SERVICE_TYPE_VO;
break;
}
return sock_set_net_service_type(sock, val);
#else
return PJ_ENOTSUP;
#endif
}
static pj_status_t sock_set_net_service_type_params(pj_sock_t sock,
pj_qos_params *param)
{
#ifdef SO_NET_SERVICE_TYPE
pj_status_t status;
int val = -1;
PJ_ASSERT_RETURN(param, PJ_EINVAL);
/*
* Sources:
* - IETF draft-szigeti-tsvwg-ieee-802-11e-01
* - iOS 10 SDK, sys/socket.h
*/
if (val == -1 && param->flags & PJ_QOS_PARAM_HAS_DSCP) {
if (param->dscp_val == 0) /* DF */
val = NET_SERVICE_TYPE_BE;
else if (param->dscp_val < 0x10) /* CS1, AF11, AF12, AF13 */
val = NET_SERVICE_TYPE_BK;
else if (param->dscp_val == 0x10) /* CS2 */
val = NET_SERVICE_TYPE_OAM;
else if (param->dscp_val < 0x18) /* AF21, AF22, AF23 */
val = NET_SERVICE_TYPE_RD;
else if (param->dscp_val < 0x20) /* CS3, AF31, AF32, AF33 */
val = NET_SERVICE_TYPE_AV;
else if (param->dscp_val == 0x20) /* CS4 */
val = NET_SERVICE_TYPE_RD;
else if (param->dscp_val < 0x28) /* AF41, AF42, AF43 */
val = NET_SERVICE_TYPE_VI;
else if (param->dscp_val == 0x28) /* CS5 */
val = NET_SERVICE_TYPE_SIG;
else
val = NET_SERVICE_TYPE_VO; /* VOICE-ADMIT, EF, CS6, etc. */
}
if (val == -1 && param->flags & PJ_QOS_PARAM_HAS_WMM) {
switch (param->wmm_prio) {
case PJ_QOS_WMM_PRIO_BULK_EFFORT:
val = NET_SERVICE_TYPE_BE;
break;
case PJ_QOS_WMM_PRIO_BULK:
val = NET_SERVICE_TYPE_BK;
break;
case PJ_QOS_WMM_PRIO_VIDEO:
val = NET_SERVICE_TYPE_VI;
break;
case PJ_QOS_WMM_PRIO_VOICE:
val = NET_SERVICE_TYPE_VO;
break;
}
}
if (val == -1) {
pj_qos_type type;
status = pj_qos_get_type(param, &type);
if (status == PJ_SUCCESS)
return sock_set_net_service_type_type(sock, type);
val = NET_SERVICE_TYPE_BE;
}
return sock_set_net_service_type(sock, val);
#else
return PJ_ENOTSUP;
#endif
}
static pj_status_t sock_set_ip_ds(pj_sock_t sock, pj_qos_params *param)
{
pj_status_t status = PJ_SUCCESS;
PJ_ASSERT_RETURN(param, PJ_EINVAL);
if (param->flags & PJ_QOS_PARAM_HAS_DSCP) {
/* We need to know if the socket is IPv4 or IPv6 */
pj_sockaddr sa;
int salen = sizeof(salen);
/* Value is dscp_val << 2 */
int val = (param->dscp_val << 2);
status = pj_sock_getsockname(sock, &sa, &salen);
if (status != PJ_SUCCESS)
return status;
if (sa.addr.sa_family == pj_AF_INET()) {
/* In IPv4, the DS field goes in the TOS field */
status = pj_sock_setsockopt(sock, pj_SOL_IP(), pj_IP_TOS(),
&val, sizeof(val));
} else if (sa.addr.sa_family == pj_AF_INET6()) {
/* In IPv6, the DS field goes in the Traffic Class field */
status = pj_sock_setsockopt(sock, pj_SOL_IPV6(),
pj_IPV6_TCLASS(),
&val, sizeof(val));
} else
status = PJ_EINVAL;
if (status != PJ_SUCCESS) {
param->flags &= ~(PJ_QOS_PARAM_HAS_DSCP);
}
}
return status;
}
PJ_DEF(pj_status_t) pj_sock_set_qos_params(pj_sock_t sock,
pj_qos_params *param)
{
pj_status_t status;
PJ_ASSERT_RETURN(param, PJ_EINVAL);
/* No op? */
if (!param->flags)
return PJ_SUCCESS;
/* Clear prio field since we don't support it */
param->flags &= ~(PJ_QOS_PARAM_HAS_SO_PRIO);
/* Try SO_NET_SERVICE_TYPE */
status = sock_set_net_service_type_params(sock, param);
if (status == PJ_SUCCESS)
return status;
if (status != PJ_ENOTSUP) {
/* SO_NET_SERVICE_TYPE sets both DSCP and WMM */
param->flags &= ~(PJ_QOS_PARAM_HAS_DSCP);
param->flags &= ~(PJ_QOS_PARAM_HAS_WMM);
return status;
}
/* Fall back to IP_TOS/IPV6_TCLASS */
return sock_set_ip_ds(sock, param);
}
PJ_DEF(pj_status_t) pj_sock_set_qos_type(pj_sock_t sock,
pj_qos_type type)
{
pj_status_t status;
pj_qos_params param;
/* Try SO_NET_SERVICE_TYPE */
status = sock_set_net_service_type_type(sock, type);
if (status == PJ_SUCCESS || status != PJ_ENOTSUP)
return status;
/* Fall back to IP_TOS/IPV6_TCLASS */
status = pj_qos_get_params(type, &param);
if (status != PJ_SUCCESS)
return status;
return sock_set_ip_ds(sock, &param);
}
#ifdef SO_NET_SERVICE_TYPE
static pj_status_t sock_get_net_service_type(pj_sock_t sock, int *p_val)
{
pj_status_t status;
int optlen = sizeof(*p_val);
PJ_ASSERT_RETURN(p_val, PJ_EINVAL);
status = pj_sock_getsockopt(sock, pj_SOL_SOCKET(), SO_NET_SERVICE_TYPE,
p_val, &optlen);
if (status == PJ_STATUS_FROM_OS(OSERR_ENOPROTOOPT))
status = PJ_ENOTSUP;
return status;
}
#endif
static pj_status_t sock_get_net_service_type_type(pj_sock_t sock,
pj_qos_type *p_type)
{
#ifdef SO_NET_SERVICE_TYPE
pj_status_t status;
int val;
PJ_ASSERT_RETURN(p_type, PJ_EINVAL);
status = sock_get_net_service_type(sock, &val);
if (status == PJ_SUCCESS) {
switch (val) {
default:
case NET_SERVICE_TYPE_BE:
*p_type = PJ_QOS_TYPE_BEST_EFFORT;
break;
case NET_SERVICE_TYPE_BK:
*p_type = PJ_QOS_TYPE_BACKGROUND;
break;
case NET_SERVICE_TYPE_SIG:
*p_type = PJ_QOS_TYPE_SIGNALLING;
break;
case NET_SERVICE_TYPE_VI:
case NET_SERVICE_TYPE_RV:
case NET_SERVICE_TYPE_AV:
case NET_SERVICE_TYPE_OAM:
case NET_SERVICE_TYPE_RD:
*p_type = PJ_QOS_TYPE_VIDEO;
break;
case NET_SERVICE_TYPE_VO:
*p_type = PJ_QOS_TYPE_VOICE;
break;
}
}
return status;
#else
return PJ_ENOTSUP;
#endif
}
static pj_status_t sock_get_net_service_type_params(pj_sock_t sock,
pj_qos_params *p_param)
{
#ifdef SO_NET_SERVICE_TYPE
pj_status_t status;
int val;
PJ_ASSERT_RETURN(p_param, PJ_EINVAL);
status = sock_get_net_service_type(sock, &val);
if (status == PJ_SUCCESS) {
pj_bzero(p_param, sizeof(*p_param));
/* Note: these are just educated guesses, chosen for symmetry with
* sock_set_net_service_type_params: we can't know the actual values
* chosen by the OS, or even if DSCP/WMM are used at all.
*
* The source for mapping DSCP to WMM is:
* - IETF draft-szigeti-tsvwg-ieee-802-11e-01
*/
switch (val) {
default:
case NET_SERVICE_TYPE_BE:
p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM;
p_param->dscp_val = 0; /* DF */
p_param->wmm_prio = PJ_QOS_WMM_PRIO_BULK_EFFORT; /* AC_BE */
break;
case NET_SERVICE_TYPE_BK:
p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM;
p_param->dscp_val = 0x08; /* CS1 */
p_param->wmm_prio = PJ_QOS_WMM_PRIO_BULK; /* AC_BK */
break;
case NET_SERVICE_TYPE_SIG:
p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM;
p_param->dscp_val = 0x28; /* CS5 */
p_param->wmm_prio = PJ_QOS_WMM_PRIO_VIDEO; /* AC_VI */
break;
case NET_SERVICE_TYPE_VI:
p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM;
p_param->dscp_val = 0x22; /* AF41 */
p_param->wmm_prio = PJ_QOS_WMM_PRIO_VIDEO; /* AC_VI */
break;
case NET_SERVICE_TYPE_VO:
p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM;
p_param->dscp_val = 0x30; /* CS6 */
p_param->wmm_prio = PJ_QOS_WMM_PRIO_VOICE; /* AC_VO */
break;
case NET_SERVICE_TYPE_RV:
p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM;
p_param->dscp_val = 0x22; /* AF41 */
p_param->wmm_prio = PJ_QOS_WMM_PRIO_VIDEO; /* AC_VI */
break;
case NET_SERVICE_TYPE_AV:
p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM;
p_param->dscp_val = 0x18; /* CS3 */
p_param->wmm_prio = PJ_QOS_WMM_PRIO_VIDEO; /* AC_VI */
break;
case NET_SERVICE_TYPE_OAM:
p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM;
p_param->dscp_val = 0x10; /* CS2 */
p_param->wmm_prio = PJ_QOS_WMM_PRIO_BULK_EFFORT; /* AC_BE */
break;
case NET_SERVICE_TYPE_RD:
p_param->flags = PJ_QOS_PARAM_HAS_DSCP | PJ_QOS_PARAM_HAS_WMM;
p_param->dscp_val = 0x20; /* CS4 */
p_param->wmm_prio = PJ_QOS_WMM_PRIO_VIDEO; /* AC_VI */
break;
}
}
return status;
#else
return PJ_ENOTSUP;
#endif
}
PJ_DEF(pj_status_t) pj_sock_get_qos_params(pj_sock_t sock,
pj_qos_params *p_param)
{
pj_status_t status;
int val, optlen;
pj_sockaddr sa;
int salen = sizeof(salen);
PJ_ASSERT_RETURN(p_param, PJ_EINVAL);
pj_bzero(p_param, sizeof(*p_param));
/* Try SO_NET_SERVICE_TYPE */
status = sock_get_net_service_type_params(sock, p_param);
if (status != PJ_ENOTSUP)
return status;
/* Fall back to IP_TOS/IPV6_TCLASS */
status = pj_sock_getsockname(sock, &sa, &salen);
if (status != PJ_SUCCESS)
return status;
optlen = sizeof(val);
if (sa.addr.sa_family == pj_AF_INET()) {
status = pj_sock_getsockopt(sock, pj_SOL_IP(), pj_IP_TOS(),
&val, &optlen);
} else if (sa.addr.sa_family == pj_AF_INET6()) {
status = pj_sock_getsockopt(sock, pj_SOL_IPV6(), pj_IPV6_TCLASS(),
&val, &optlen);
} else
status = PJ_EINVAL;
if (status == PJ_SUCCESS) {
p_param->flags |= PJ_QOS_PARAM_HAS_DSCP;
p_param->dscp_val = (pj_uint8_t)(val >> 2);
}
return status;
}
PJ_DEF(pj_status_t) pj_sock_get_qos_type(pj_sock_t sock,
pj_qos_type *p_type)
{
pj_qos_params param;
pj_status_t status;
PJ_ASSERT_RETURN(p_type, PJ_EINVAL);
status = sock_get_net_service_type_type(sock, p_type);
if (status != PJ_ENOTSUP)
return status;
status = pj_sock_get_qos_params(sock, &param);
if (status != PJ_SUCCESS)
return status;
return pj_qos_get_type(&param, p_type);
}
#endif /* PJ_QOS_IMPLEMENTATION */

View File

@ -19,6 +19,7 @@
#include <pj/ssl_sock.h>
#include <pj/assert.h>
#include <pj/errno.h>
#include <pj/pool.h>
#include <pj/string.h>
/*
@ -48,6 +49,49 @@ PJ_DEF(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param)
}
/*
* Duplicate SSL socket parameter.
*/
PJ_DEF(void) pj_ssl_sock_param_copy( pj_pool_t *pool,
pj_ssl_sock_param *dst,
const pj_ssl_sock_param *src)
{
/* Init secure socket param */
pj_memcpy(dst, src, sizeof(*dst));
if (src->ciphers_num > 0) {
unsigned i;
dst->ciphers = (pj_ssl_cipher*)
pj_pool_calloc(pool, src->ciphers_num,
sizeof(pj_ssl_cipher));
for (i = 0; i < src->ciphers_num; ++i)
dst->ciphers[i] = src->ciphers[i];
}
if (src->curves_num > 0) {
unsigned i;
dst->curves = (pj_ssl_curve *)pj_pool_calloc(pool, src->curves_num,
sizeof(pj_ssl_curve));
for (i = 0; i < src->curves_num; ++i)
dst->curves[i] = src->curves[i];
}
if (src->server_name.slen) {
/* Server name must be null-terminated */
pj_strdup_with_null(pool, &dst->server_name, &src->server_name);
}
if (src->sigalgs.slen) {
/* Sigalgs name must be null-terminated */
pj_strdup_with_null(pool, &dst->sigalgs, &src->sigalgs);
}
if (src->entropy_path.slen) {
/* Path name must be null-terminated */
pj_strdup_with_null(pool, &dst->entropy_path, &src->entropy_path);
}
}
PJ_DEF(pj_status_t) pj_ssl_cert_get_verify_status_strings(
pj_uint32_t verify_status,
const char *error_strings[],

View File

@ -37,8 +37,10 @@
#define THIS_FILE "ssl_sock_ossl.c"
/* Workaround for ticket #985 */
#define DELAYED_CLOSE_TIMEOUT 200
/* Workaround for ticket #985 and #1930 */
#ifndef PJ_SSL_SOCK_DELAYED_CLOSE_TIMEOUT
# define PJ_SSL_SOCK_DELAYED_CLOSE_TIMEOUT 500
#endif
/*
* Include OpenSSL headers
@ -47,7 +49,13 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/x509v3.h>
#include <openssl/rand.h>
#include <openssl/engine.h>
#if defined(PJ_SSL_SOCK_OSSL_HAS_EC) && PJ_SSL_SOCK_OSSL_HAS_EC==1
extern int tls1_ec_nid2curve_id(int nid);
extern int tls1_ec_curve_id2nid(int curve_id);
#endif
#ifdef _MSC_VER
# pragma comment( lib, "libeay32")
@ -141,6 +149,7 @@ struct pj_ssl_sock_t
pj_pool_t *pool;
pj_ssl_sock_t *parent;
pj_ssl_sock_param param;
pj_ssl_sock_param newsock_param;
pj_ssl_cert_t *cert;
pj_ssl_cert_info local_cert_info;
@ -296,6 +305,13 @@ static struct openssl_ciphers_t {
const char *name;
} openssl_ciphers[PJ_SSL_SOCK_MAX_CIPHERS];
/* OpenSSL available curves */
static unsigned openssl_curves_num;
static struct openssl_curves_t {
pj_ssl_curve id;
const char *name;
} openssl_curves[PJ_SSL_SOCK_MAX_CURVES];
/* OpenSSL application data index */
static int sslsock_idx;
@ -325,12 +341,14 @@ static pj_status_t init_openssl(void)
#endif
/* Init available ciphers */
if (openssl_cipher_num == 0) {
if (openssl_cipher_num == 0 || openssl_curves_num == 0) {
SSL_METHOD *meth = NULL;
SSL_CTX *ctx;
SSL *ssl;
STACK_OF(SSL_CIPHER) *sk_cipher;
unsigned i, n;
int nid;
const char *cname;
meth = (SSL_METHOD*)SSLv23_server_method();
if (!meth)
@ -349,6 +367,7 @@ static pj_status_t init_openssl(void)
SSL_CTX_set_cipher_list(ctx, "ALL:COMPLEMENTOFALL");
ssl = SSL_new(ctx);
sk_cipher = SSL_get_ciphers(ssl);
n = sk_SSL_CIPHER_num(sk_cipher);
@ -362,17 +381,44 @@ static pj_status_t init_openssl(void)
(pj_uint32_t)c->id & 0x00FFFFFF;
openssl_ciphers[i].name = SSL_CIPHER_get_name(c);
}
openssl_cipher_num = n;
ssl->session = SSL_SESSION_new();
#if defined(PJ_SSL_SOCK_OSSL_HAS_EC) && PJ_SSL_SOCK_OSSL_HAS_EC==1
openssl_curves_num = SSL_get_shared_curve(ssl,-1);
if (openssl_curves_num > PJ_ARRAY_SIZE(openssl_curves))
openssl_curves_num = PJ_ARRAY_SIZE(openssl_curves);
for (i = 0; i < openssl_curves_num; i++) {
nid = SSL_get_shared_curve(ssl, i);
if (nid & TLSEXT_nid_unknown) {
cname = "curve unknown";
nid &= 0xFFFF;
} else {
cname = EC_curve_nid2nist(nid);
if (!cname)
cname = OBJ_nid2sn(nid);
}
openssl_curves[i].id = tls1_ec_nid2curve_id(nid);
openssl_curves[i].name = cname;
}
#else
PJ_UNUSED_ARG(nid);
PJ_UNUSED_ARG(cname);
openssl_curves_num = 0;
#endif
SSL_free(ssl);
SSL_CTX_free(ctx);
openssl_cipher_num = n;
}
/* Create OpenSSL application data index for SSL socket */
sslsock_idx = SSL_get_ex_new_index(0, "SSL socket", NULL, NULL, NULL);
return PJ_SUCCESS;
return status;
}
@ -495,7 +541,12 @@ static int verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
/* Setting SSL sock cipher list */
static pj_status_t set_cipher_list(pj_ssl_sock_t *ssock);
/* Setting SSL sock curves list */
static pj_status_t set_curves_list(pj_ssl_sock_t *ssock);
/* Setting sigalgs list */
static pj_status_t set_sigalgs(pj_ssl_sock_t *ssock);
/* Setting entropy for rng */
static void set_entropy(pj_ssl_sock_t *ssock);
/* Create and initialize new SSL context and instance */
static pj_status_t create_ssl(pj_ssl_sock_t *ssock)
@ -520,6 +571,8 @@ static pj_status_t create_ssl(pj_ssl_sock_t *ssock)
/* Make sure OpenSSL library has been initialized */
init_openssl();
set_entropy(ssock);
if (ssock->param.proto == PJ_SSL_SOCK_PROTO_DEFAULT)
ssock->param.proto = PJ_SSL_SOCK_PROTO_SSL23;
@ -772,6 +825,16 @@ static pj_status_t create_ssl(pj_ssl_sock_t *ssock)
if (status != PJ_SUCCESS)
return status;
/* Set curve list */
status = set_curves_list(ssock);
if (status != PJ_SUCCESS)
return status;
/* Set sigalg list */
status = set_sigalgs(ssock);
if (status != PJ_SUCCESS)
return status;
/* Setup SSL BIOs */
ssock->ossl_rbio = BIO_new(BIO_s_mem());
ssock->ossl_wbio = BIO_new(BIO_s_mem());
@ -806,22 +869,46 @@ static void destroy_ssl(pj_ssl_sock_t *ssock)
}
/* Close sockets */
static void close_sockets(pj_ssl_sock_t *ssock)
{
pj_activesock_t *asock;
pj_sock_t sock;
/* This can happen when pj_ssl_sock_create() fails. */
if (!ssock->write_mutex)
return;
pj_lock_acquire(ssock->write_mutex);
asock = ssock->asock;
if (asock) {
// Don't set ssock->asock to NULL, as it may trigger assertion in
// send operation. This should be safe as active socket will simply
// return PJ_EINVALIDOP on any operation if it is already closed.
//ssock->asock = NULL;
ssock->sock = PJ_INVALID_SOCKET;
}
sock = ssock->sock;
if (sock != PJ_INVALID_SOCKET)
ssock->sock = PJ_INVALID_SOCKET;
pj_lock_release(ssock->write_mutex);
if (asock)
pj_activesock_close(asock);
if (sock != PJ_INVALID_SOCKET)
pj_sock_close(sock);
}
/* Reset SSL socket state */
static void reset_ssl_sock_state(pj_ssl_sock_t *ssock)
{
pj_lock_acquire(ssock->write_mutex);
ssock->ssl_state = SSL_STATE_NULL;
pj_lock_release(ssock->write_mutex);
destroy_ssl(ssock);
if (ssock->asock) {
pj_activesock_close(ssock->asock);
ssock->asock = NULL;
ssock->sock = PJ_INVALID_SOCKET;
}
if (ssock->sock != PJ_INVALID_SOCKET) {
pj_sock_close(ssock->sock);
ssock->sock = PJ_INVALID_SOCKET;
}
close_sockets(ssock);
/* Upon error, OpenSSL may leave any error description in the thread
* error queue, which sometime may cause next call to SSL API returning
@ -836,7 +923,9 @@ static void reset_ssl_sock_state(pj_ssl_sock_t *ssock)
/* Generate cipher list with user preference order in OpenSSL format */
static pj_status_t set_cipher_list(pj_ssl_sock_t *ssock)
{
char buf[1024];
pj_pool_t *tmp_pool = NULL;
char *buf = NULL;
enum { BUF_SIZE = 8192 };
pj_str_t cipher_list;
STACK_OF(SSL_CIPHER) *sk_cipher;
unsigned i;
@ -851,6 +940,14 @@ static pj_status_t set_cipher_list(pj_ssl_sock_t *ssock)
return PJ_SUCCESS;
}
/* Create temporary pool. */
tmp_pool = pj_pool_create(ssock->pool->factory, "ciphpool", BUF_SIZE,
BUF_SIZE/2 , NULL);
if (!tmp_pool)
return PJ_ENOMEM;
buf = (char *)pj_pool_zalloc(tmp_pool, BUF_SIZE);
pj_strset(&cipher_list, buf, 0);
/* Set SSL with ALL available ciphers */
@ -871,7 +968,7 @@ static pj_status_t set_cipher_list(pj_ssl_sock_t *ssock)
/* Check buffer size */
if (cipher_list.slen + pj_ansi_strlen(c_name) + 2 >
sizeof(buf))
BUF_SIZE)
{
pj_assert(!"Insufficient temporary buffer for cipher");
return PJ_ETOOMANY;
@ -894,12 +991,101 @@ 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_pool_release(tmp_pool);
return GET_SSL_STATUS(ssock);
}
pj_pool_release(tmp_pool);
return PJ_SUCCESS;
}
static pj_status_t set_curves_list(pj_ssl_sock_t *ssock)
{
#if defined(PJ_SSL_SOCK_OSSL_HAS_EC) && PJ_SSL_SOCK_OSSL_HAS_EC==1
int ret;
int curves[PJ_SSL_SOCK_MAX_CURVES];
int cnt;
if (ssock->param.curves_num == 0)
return PJ_SUCCESS;
for (cnt = 0; cnt < ssock->param.curves_num; cnt++) {
curves[cnt] = tls1_ec_curve_id2nid(ssock->param.curves[cnt]);
}
if( ssock->ossl_ssl->server ) {
ret = SSL_set1_curves(ssock->ossl_ssl, curves,
ssock->param.curves_num);
if (ret < 1)
return GET_SSL_STATUS(ssock);
} else {
ret = SSL_CTX_set1_curves(ssock->ossl_ctx, curves,
ssock->param.curves_num);
if (ret < 1)
return GET_SSL_STATUS(ssock);
}
#else
PJ_UNUSED_ARG(ssock);
#endif
return PJ_SUCCESS;
}
static pj_status_t set_sigalgs(pj_ssl_sock_t *ssock)
{
#if defined(PJ_SSL_SOCK_OSSL_HAS_SIGALG) && PJ_SSL_SOCK_OSSL_HAS_SIGALG==1
int ret;
if (ssock->param.sigalgs.ptr && ssock->param.sigalgs.slen) {
if (ssock->is_server) {
ret = SSL_set1_client_sigalgs_list(ssock->ossl_ssl,
ssock->param.sigalgs.ptr);
} else {
ret = SSL_set1_sigalgs_list(ssock->ossl_ssl,
ssock->param.sigalgs.ptr);
}
if (ret < 1)
return GET_SSL_STATUS(ssock);
}
#else
PJ_UNUSED_ARG(ssock);
#endif
return PJ_SUCCESS;
}
static void set_entropy(pj_ssl_sock_t *ssock)
{
int ret;
switch (ssock->param.entropy_type) {
#ifndef OPENSSL_NO_EGD
case PJ_SSL_ENTROPY_EGD:
ret = RAND_egd(ssock->param.entropy_path.ptr);
break;
#endif
case PJ_SSL_ENTROPY_RANDOM:
ret = RAND_load_file("/dev/random",255);
break;
case PJ_SSL_ENTROPY_URANDOM:
ret = RAND_load_file("/dev/urandom",255);
break;
case PJ_SSL_ENTROPY_FILE:
ret = RAND_load_file(ssock->param.entropy_path.ptr,255);
break;
case PJ_SSL_ENTROPY_NONE:
default:
return;
break;
}
if (ret < 0) {
PJ_LOG(3, (ssock->pool->obj_name, "SSL failed to reseed with "
"entropy type %d",
ssock->param.entropy_type));
}
}
/* Parse OpenSSL ASN1_TIME to pj_time_val and GMT info */
static pj_bool_t parse_ossl_asn1_time(pj_time_val *tv, pj_bool_t *gmt,
@ -964,7 +1150,7 @@ static void get_cn_from_gen_name(const pj_str_t *gen_name, pj_str_t *cn)
pj_str_t CN_sign = {"/CN=", 4};
char *p, *q;
pj_bzero(cn, sizeof(cn));
pj_bzero(cn, sizeof(pj_str_t));
p = pj_strstr(gen_name, &CN_sign);
if (!p)
@ -982,12 +1168,13 @@ static void get_cn_from_gen_name(const pj_str_t *gen_name, pj_str_t *cn)
* hal already populated, this function will check if the contents need
* to be updated by inspecting the issuer and the serial number.
*/
static void get_cert_info(pj_pool_t *pool, pj_ssl_cert_info *ci, X509 *x)
static void get_cert_info(pj_pool_t *pool, pj_ssl_cert_info *ci, X509 *x,
pj_bool_t get_pem)
{
pj_bool_t update_needed;
char buf[512];
pj_uint8_t serial_no[64] = {0}; /* should be >= sizeof(ci->serial_no) */
pj_uint8_t *p;
pj_uint8_t *q;
unsigned len;
GENERAL_NAMES *names = NULL;
@ -997,11 +1184,11 @@ static void get_cert_info(pj_pool_t *pool, pj_ssl_cert_info *ci, X509 *x)
X509_NAME_oneline(X509_get_issuer_name(x), buf, sizeof(buf));
/* Get serial no */
p = (pj_uint8_t*) M_ASN1_STRING_data(X509_get_serialNumber(x));
q = (pj_uint8_t*) M_ASN1_STRING_data(X509_get_serialNumber(x));
len = M_ASN1_STRING_length(X509_get_serialNumber(x));
if (len > sizeof(ci->serial_no))
len = sizeof(ci->serial_no);
pj_memcpy(serial_no + sizeof(ci->serial_no) - len, p, len);
pj_memcpy(serial_no + sizeof(ci->serial_no) - len, q, len);
/* Check if the contents need to be updated. */
update_needed = pj_strcmp2(&ci->issuer.info, buf) ||
@ -1095,6 +1282,24 @@ static void get_cert_info(pj_pool_t *pool, pj_ssl_cert_info *ci, X509 *x)
}
}
}
if (get_pem) {
/* Update raw Certificate info in PEM format. */
BIO *bio;
BUF_MEM *ptr;
bio = BIO_new(BIO_s_mem());
if (!PEM_write_bio_X509(bio, x)) {
PJ_LOG(3,(THIS_FILE, "Error retrieving raw certificate info"));
ci->raw.ptr = NULL;
ci->raw.slen = 0;
} else {
BIO_write(bio, "\0", 1);
BIO_get_mem_ptr(bio, &ptr);
pj_strdup2(pool, &ci->raw, ptr->data);
}
BIO_free(bio);
}
}
@ -1110,7 +1315,7 @@ static void update_certs_info(pj_ssl_sock_t *ssock)
/* Active local certificate */
x = SSL_get_certificate(ssock->ossl_ssl);
if (x) {
get_cert_info(ssock->pool, &ssock->local_cert_info, x);
get_cert_info(ssock->pool, &ssock->local_cert_info, x, PJ_FALSE);
/* Don't free local's X509! */
} else {
pj_bzero(&ssock->local_cert_info, sizeof(pj_ssl_cert_info));
@ -1119,7 +1324,7 @@ static void update_certs_info(pj_ssl_sock_t *ssock)
/* Active remote certificate */
x = SSL_get_peer_certificate(ssock->ossl_ssl);
if (x) {
get_cert_info(ssock->pool, &ssock->remote_cert_info, x);
get_cert_info(ssock->pool, &ssock->remote_cert_info, x, PJ_TRUE);
/* Free peer's X509 */
X509_free(x);
} else {
@ -1160,26 +1365,42 @@ static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
pj_sockaddr_print(&ssock->rem_addr, buf, sizeof(buf), 3),
errmsg));
/* Workaround for ticket #985 */
#if (defined(PJ_WIN32) && PJ_WIN32!=0) || (defined(PJ_WIN64) && PJ_WIN64!=0)
/* Originally, this is a workaround for ticket #985. However,
* a race condition may occur in multiple worker threads
* environment when we are destroying SSL objects while other
* threads are still accessing them.
* Please see ticket #1930 for more info.
*/
#if 1 //(defined(PJ_WIN32) && PJ_WIN32!=0)||(defined(PJ_WIN64) && PJ_WIN64!=0)
if (ssock->param.timer_heap) {
pj_time_val interval = {0, DELAYED_CLOSE_TIMEOUT};
pj_time_val interval = {0, PJ_SSL_SOCK_DELAYED_CLOSE_TIMEOUT};
reset_ssl_sock_state(ssock);
ssock->ssl_state = SSL_STATE_NULL;
close_sockets(ssock);
if (ssock->timer.id != TIMER_NONE) {
pj_timer_heap_cancel(ssock->param.timer_heap,
&ssock->timer);
}
ssock->timer.id = TIMER_CLOSE;
pj_time_val_normalize(&interval);
if (pj_timer_heap_schedule(ssock->param.timer_heap,
&ssock->timer, &interval) != 0)
{
PJ_LOG(3,(ssock->pool->obj_name, "Failed to schedule "
"a delayed close. Race condition may occur."));
ssock->timer.id = TIMER_NONE;
pj_ssl_sock_close(ssock);
}
} else
#endif /* PJ_WIN32 */
} else {
pj_ssl_sock_close(ssock);
}
#else
{
pj_ssl_sock_close(ssock);
}
#endif
return PJ_FALSE;
}
/* Notify application the newly accepted SSL socket */
@ -1541,6 +1762,21 @@ static pj_status_t do_handshake(pj_ssl_sock_t *ssock)
return PJ_EPENDING;
}
static void ssl_on_destroy(void *arg)
{
pj_pool_t *pool = NULL;
pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)arg;
destroy_ssl(ssock);
pj_lock_destroy(ssock->write_mutex);
pool = ssock->pool;
ssock->pool = NULL;
if (pool)
pj_pool_release(pool);
}
/*
*******************************************************************
@ -1757,11 +1993,9 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock,
unsigned i;
pj_status_t status;
PJ_UNUSED_ARG(src_addr_len);
/* Create new SSL socket instance */
status = pj_ssl_sock_create(ssock_parent->pool, &ssock_parent->param,
&ssock);
status = pj_ssl_sock_create(ssock_parent->pool,
&ssock_parent->newsock_param, &ssock);
if (status != PJ_SUCCESS)
goto on_return;
@ -1837,12 +2071,10 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock,
if (status != PJ_SUCCESS)
goto on_return;
/* Temporarily add ref the group lock until active socket creation,
* to make sure that group lock is destroyed if the active socket
* creation fails.
*/
pj_grp_lock_add_ref(glock);
asock_cfg.grp_lock = ssock->param.grp_lock = glock;
pj_grp_lock_add_handler(ssock->param.grp_lock, ssock->pool, ssock,
ssl_on_destroy);
}
pj_bzero(&asock_cb, sizeof(asock_cb));
@ -1858,11 +2090,6 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock,
ssock,
&ssock->asock);
/* This will destroy the group lock if active socket creation fails */
if (asock_cfg.grp_lock) {
pj_grp_lock_dec_ref(asock_cfg.grp_lock);
}
if (status != PJ_SUCCESS)
goto on_return;
@ -1892,8 +2119,10 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock,
status = pj_timer_heap_schedule(ssock->param.timer_heap,
&ssock->timer,
&ssock->param.timeout);
if (status != PJ_SUCCESS)
if (status != PJ_SUCCESS) {
ssock->timer.id = TIMER_NONE;
status = PJ_SUCCESS;
}
}
/* Start SSL handshake */
@ -1902,8 +2131,9 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock,
status = do_handshake(ssock);
on_return:
if (ssock && status != PJ_EPENDING)
if (ssock && status != PJ_EPENDING) {
on_handshake_complete(ssock, status);
}
/* Must return PJ_TRUE whatever happened, as active socket must
* continue listening.
@ -2044,7 +2274,7 @@ PJ_DEF(pj_status_t) pj_ssl_cert_load_from_files2(pj_pool_t *pool,
/* Set SSL socket credentials. */
PJ_DECL(pj_status_t) pj_ssl_sock_set_certificate(
PJ_DEF(pj_status_t) pj_ssl_sock_set_certificate(
pj_ssl_sock_t *ssock,
pj_pool_t *pool,
const pj_ssl_cert_t *cert)
@ -2054,7 +2284,7 @@ PJ_DECL(pj_status_t) pj_ssl_sock_set_certificate(
PJ_ASSERT_RETURN(ssock && pool && cert, PJ_EINVAL);
cert_ = PJ_POOL_ZALLOC_T(pool, pj_ssl_cert_t);
pj_memcpy(cert_, cert, sizeof(cert));
pj_memcpy(cert_, cert, sizeof(pj_ssl_cert_t));
pj_strdup_with_null(pool, &cert_->CA_file, &cert->CA_file);
pj_strdup_with_null(pool, &cert_->CA_path, &cert->CA_path);
pj_strdup_with_null(pool, &cert_->cert_file, &cert->cert_file);
@ -2148,6 +2378,85 @@ PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
return PJ_FALSE;
}
/* Get available curves. */
PJ_DEF(pj_status_t) pj_ssl_curve_get_availables(pj_ssl_curve curves[],
unsigned *curve_num)
{
unsigned i;
PJ_ASSERT_RETURN(curves && curve_num, PJ_EINVAL);
if (openssl_curves_num == 0) {
init_openssl();
shutdown_openssl();
}
if (openssl_curves_num == 0) {
*curve_num = 0;
return PJ_ENOTFOUND;
}
*curve_num = PJ_MIN(*curve_num, openssl_curves_num);
for (i = 0; i < *curve_num; ++i)
curves[i] = openssl_curves[i].id;
return PJ_SUCCESS;
}
/* Get curve name string. */
PJ_DEF(const char*) pj_ssl_curve_name(pj_ssl_curve curve)
{
unsigned i;
if (openssl_curves_num == 0) {
init_openssl();
shutdown_openssl();
}
for (i = 0; i < openssl_curves_num; ++i) {
if (curve == openssl_curves[i].id)
return openssl_curves[i].name;
}
return NULL;
}
/* Get curve ID from curve name string. */
PJ_DEF(pj_ssl_curve) pj_ssl_curve_id(const char *curve_name)
{
unsigned i;
if (openssl_curves_num == 0) {
init_openssl();
shutdown_openssl();
}
for (i = 0; i < openssl_curves_num; ++i) {
if (!pj_ansi_stricmp(openssl_curves[i].name, curve_name))
return openssl_curves[i].id;
}
return PJ_TLS_UNKNOWN_CURVE;
}
/* Check if the specified curve is supported by SSL/TLS backend. */
PJ_DEF(pj_bool_t) pj_ssl_curve_is_supported(pj_ssl_curve curve)
{
unsigned i;
if (openssl_curves_num == 0) {
init_openssl();
shutdown_openssl();
}
for (i = 0; i < openssl_curves_num; ++i) {
if (curve == openssl_curves[i].id)
return PJ_TRUE;
}
return PJ_FALSE;
}
/*
* Create SSL socket instance.
@ -2179,24 +2488,27 @@ PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool,
/* Create secure socket mutex */
status = pj_lock_create_recursive_mutex(pool, pool->obj_name,
&ssock->write_mutex);
if (status != PJ_SUCCESS)
if (status != PJ_SUCCESS) {
pj_pool_release(pool);
return status;
/* Init secure socket param */
ssock->param = *param;
ssock->param.read_buffer_size = ((ssock->param.read_buffer_size+7)>>3)<<3;
if (param->ciphers_num > 0) {
unsigned i;
ssock->param.ciphers = (pj_ssl_cipher*)
pj_pool_calloc(pool, param->ciphers_num,
sizeof(pj_ssl_cipher));
for (i = 0; i < param->ciphers_num; ++i)
ssock->param.ciphers[i] = param->ciphers[i];
}
/* Server name must be null-terminated */
pj_strdup_with_null(pool, &ssock->param.server_name,
&param->server_name);
/* Init secure socket param */
pj_ssl_sock_param_copy(pool, &ssock->param, param);
if (ssock->param.grp_lock) {
pj_grp_lock_add_ref(ssock->param.grp_lock);
pj_grp_lock_add_handler(ssock->param.grp_lock, pool, ssock,
ssl_on_destroy);
}
ssock->param.read_buffer_size = ((ssock->param.read_buffer_size+7)>>3)<<3;
if (!ssock->param.timer_heap) {
PJ_LOG(3,(ssock->pool->obj_name, "Warning: timer heap is not "
"available. It is recommended to supply one to avoid "
"a race condition if more than one worker threads "
"are used."));
}
/* Finally */
*p_ssock = ssock;
@ -2211,8 +2523,6 @@ PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool,
*/
PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock)
{
pj_pool_t *pool;
PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
if (!ssock->pool)
@ -2224,12 +2534,11 @@ PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock)
}
reset_ssl_sock_state(ssock);
pj_lock_destroy(ssock->write_mutex);
pool = ssock->pool;
ssock->pool = NULL;
if (pool)
pj_pool_release(pool);
if (ssock->param.grp_lock) {
pj_grp_lock_dec_ref(ssock->param.grp_lock);
} else {
ssl_on_destroy(ssock);
}
return PJ_SUCCESS;
}
@ -2616,6 +2925,22 @@ PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock,
pj_pool_t *pool,
const pj_sockaddr_t *localaddr,
int addr_len)
{
return pj_ssl_sock_start_accept2(ssock, pool, localaddr, addr_len,
&ssock->param);
}
/**
* Same as #pj_ssl_sock_start_accept(), but application provides parameter
* for new accepted secure sockets.
*/
PJ_DEF(pj_status_t)
pj_ssl_sock_start_accept2(pj_ssl_sock_t *ssock,
pj_pool_t *pool,
const pj_sockaddr_t *localaddr,
int addr_len,
const pj_ssl_sock_param *newsock_param)
{
pj_activesock_cb asock_cb;
pj_activesock_cfg asock_cfg;
@ -2623,6 +2948,14 @@ PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock,
PJ_ASSERT_RETURN(ssock && pool && localaddr && addr_len, PJ_EINVAL);
/* Verify new socket parameters */
if (newsock_param->grp_lock != ssock->param.grp_lock ||
newsock_param->sock_af != ssock->param.sock_af ||
newsock_param->sock_type != ssock->param.sock_type)
{
return PJ_EINVAL;
}
/* Create socket */
status = pj_sock_socket(ssock->param.sock_af, ssock->param.sock_type, 0,
&ssock->sock);
@ -2691,6 +3024,8 @@ PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock,
goto on_error;
/* Start accepting */
pj_ssl_sock_param_copy(pool, &ssock->newsock_param, newsock_param);
ssock->newsock_param.grp_lock = NULL;
status = pj_activesock_start_accept(ssock->asock, pool);
if (status != PJ_SUCCESS)
goto on_error;
@ -2715,7 +3050,7 @@ on_error:
/**
* Starts asynchronous socket connect() operation.
*/
PJ_DECL(pj_status_t) pj_ssl_sock_start_connect(pj_ssl_sock_t *ssock,
PJ_DEF(pj_status_t) pj_ssl_sock_start_connect( pj_ssl_sock_t *ssock,
pj_pool_t *pool,
const pj_sockaddr_t *localaddr,
const pj_sockaddr_t *remaddr,
@ -2791,8 +3126,10 @@ PJ_DECL(pj_status_t) pj_ssl_sock_start_connect(pj_ssl_sock_t *ssock,
status = pj_timer_heap_schedule(ssock->param.timer_heap,
&ssock->timer,
&ssock->param.timeout);
if (status != PJ_SUCCESS)
if (status != PJ_SUCCESS) {
ssock->timer.id = TIMER_NONE;
status = PJ_SUCCESS;
}
}
status = pj_activesock_start_connect(ssock->asock, pool, remaddr,

View File

@ -57,6 +57,7 @@ static int echo_client_thread(void *arg)
pj_sock_t sock;
char send_buf[BUF_SIZE];
char recv_buf[BUF_SIZE];
char addr[PJ_INET_ADDRSTRLEN];
pj_sockaddr_in addr;
pj_str_t s;
pj_status_t rc;
@ -87,7 +88,8 @@ static int echo_client_thread(void *arg)
}
PJ_LOG(3,("", "...socket connected to %s:%d",
pj_inet_ntoa(addr.sin_addr),
pj_inet_ntop2(pj_AF_INET(), &addr.sin_addr,
addr, sizeof(addr)),
pj_ntohs(addr.sin_port)));
pj_memset(send_buf, 'A', BUF_SIZE);

View File

@ -106,7 +106,9 @@ int errno_test(void)
/*
* Unix errors
*/
# if defined(EINVAL) && !defined(PJ_SYMBIAN) && !defined(PJ_WIN32)
# if defined(EINVAL) && !defined(PJ_SYMBIAN) && !defined(PJ_WIN32) \
&& !defined(PJ_WIN64)
rc = PJ_STATUS_FROM_OS(EINVAL);
pj_set_os_error(rc);

View File

@ -424,8 +424,8 @@ static int purity_test(void)
cnt = PJ_ARRAY_SIZE(ai);
rc = pj_getaddrinfo(pj_AF_UNSPEC(), &str_ip, &cnt, ai);
if (rc == PJ_SUCCESS) {
pj_assert(cnt == 1);
CHECK_SA_ZERO_LEN(&ai[0].ai_addr, -70);
while (cnt--)
CHECK_SA_ZERO_LEN(&ai[cnt].ai_addr, -70);
}
}
#endif
@ -759,6 +759,8 @@ static int gethostbyname_test(void)
pj_hostent he;
pj_status_t status;
PJ_LOG(3,("test", "...gethostbyname_test()"));
/* Testing pj_gethostbyname() with invalid host */
host = pj_str("an-invalid-host-name");
status = pj_gethostbyname(&host, &he);

View File

@ -1318,9 +1318,11 @@ on_return:
if (ssock_serv)
pj_ssl_sock_close(ssock_serv);
for (i = 0; i < clients; ++i) {
if (ssock_cli[i] && !state_cli[i].err && !state_cli[i].done)
pj_ssl_sock_close(ssock_cli[i]);
if (ssock_cli && state_cli) {
for (i = 0; i < clients; ++i) {
if (ssock_cli[i] && !state_cli[i].err && !state_cli[i].done)
pj_ssl_sock_close(ssock_cli[i]);
}
}
if (ioqueue)
pj_ioqueue_destroy(ioqueue);
@ -1376,9 +1378,9 @@ int ssl_sock_test(void)
* which require SSL server, for now.
*/
PJ_LOG(3,("", "..echo test w/ TLSv1 and PJ_TLS_RSA_WITH_DES_CBC_SHA cipher"));
PJ_LOG(3,("", "..echo test w/ TLSv1 and PJ_TLS_RSA_WITH_AES_256_CBC_SHA cipher"));
ret = echo_test(PJ_SSL_SOCK_PROTO_TLS1, PJ_SSL_SOCK_PROTO_TLS1,
PJ_TLS_RSA_WITH_DES_CBC_SHA, PJ_TLS_RSA_WITH_DES_CBC_SHA,
PJ_TLS_RSA_WITH_AES_256_CBC_SHA, PJ_TLS_RSA_WITH_AES_256_CBC_SHA,
PJ_FALSE, PJ_FALSE);
if (ret != 0)
return ret;

View File

@ -75,13 +75,11 @@ export PJMEDIA_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
types.o vid_codec.o vid_codec_util.o \
vid_port.o vid_stream.o vid_stream_info.o vid_tee.o \
wav_player.o wav_playlist.o wav_writer.o wave.o \
wsola.o
wsola.o audiodev.o videodev.o
export PJMEDIA_CFLAGS += $(_CFLAGS)
export PJMEDIA_CXXFLAGS += $(_CXXFLAGS)
export PJMEDIA_LDFLAGS += $(PJMEDIA_VIDEODEV_LDLIB) \
$(PJMEDIA_AUDIODEV_LDLIB) \
$(PJLIB_LDLIB) \
export PJMEDIA_LDFLAGS += $(PJLIB_LDLIB) \
$(PJLIB_UTIL_LDLIB) \
$(PJNATH_LDLIB) \
$(_LDFLAGS)
@ -97,7 +95,8 @@ export PJMEDIA_AUDIODEV_OBJS += audiodev.o audiotest.o errno.o \
android_jni_dev.o opensl_dev.o
export PJMEDIA_AUDIODEV_CFLAGS += $(_CFLAGS)
export PJMEDIA_AUDIODEV_CXXFLAGS += $(_CXXFLAGS)
export PJMEDIA_AUDIODEV_LDFLAGS += $(PJLIB_LDLIB) \
export PJMEDIA_AUDIODEV_LDFLAGS += $(PJMEDIA_LDLIB) \
$(PJLIB_LDLIB) \
$(_LDFLAGS)
@ -105,12 +104,13 @@ export PJMEDIA_AUDIODEV_LDFLAGS += $(PJLIB_LDLIB) \
# Defines for building PJMEDIA-VIDEODEV library
#
export PJMEDIA_VIDEODEV_SRCDIR = ../src/pjmedia-videodev
export PJMEDIA_VIDEODEV_OBJS += errno.o videodev.o avi_dev.o ffmpeg_dev.o \
export PJMEDIA_VIDEODEV_OBJS += videodev.o errno.o avi_dev.o ffmpeg_dev.o \
colorbar_dev.o v4l2_dev.o opengl_dev.o \
util.o
export PJMEDIA_VIDEODEV_CFLAGS += $(_CFLAGS)
export PJMEDIA_VIDEODEV_CXXFLAGS += $(_CXXFLAGS)
export PJMEDIA_VIDEODEV_LDFLAGS += $(PJLIB_LDLIB) \
export PJMEDIA_VIDEODEV_LDFLAGS += $(PJMEDIA_LDLIB) \
$(PJLIB_LDLIB) \
$(_LDFLAGS)
@ -138,7 +138,7 @@ export PJMEDIA_CODEC_SRCDIR = ../src/pjmedia-codec
export PJMEDIA_CODEC_OBJS += audio_codecs.o ffmpeg_vid_codecs.o openh264.o \
h263_packetizer.o h264_packetizer.o \
$(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
ipp_codecs.o silk.o $(CODEC_OBJS) \
ipp_codecs.o silk.o opus.o $(CODEC_OBJS) \
g7221_sdp_match.o amr_sdp_match.o
export PJMEDIA_CODEC_CFLAGS += $(_CFLAGS) $(GSM_CFLAGS) $(SPEEX_CFLAGS) \
$(ILBC_CFLAGS) $(IPP_CFLAGS) $(G7221_CFLAGS)
@ -160,8 +160,8 @@ export PJMEDIA_TEST_CFLAGS += $(_CFLAGS)
export PJMEDIA_TEST_CXXFLAGS += $(_CXXFLAGS)
export PJMEDIA_TEST_LDFLAGS += $(PJMEDIA_CODEC_LDLIB) \
$(PJMEDIA_VIDEODEV_LDLIB) \
$(PJMEDIA_LDLIB) \
$(PJMEDIA_AUDIODEV_LDLIB) \
$(PJMEDIA_LDLIB) \
$(PJLIB_LDLIB) \
$(PJLIB_UTIL_LDLIB) \
$(PJNATH_LDLIB) \
@ -211,7 +211,7 @@ distclean: realclean
pjmedia: $(PJMEDIA_LIB)
$(PJMEDIA_SONAME): $(PJMEDIA_LIB)
$(PJMEDIA_LIB) $(PJMEDIA_SONAME): $(PJMEDIA_AUDIODEV_LIB) $(PJMEDIA_AUDIODEV_SONAME) $(PJMEDIA_VIDEODEV_LIB) $(PJMEDIA_VIDEODEV_SONAME)
$(PJMEDIA_LIB) $(PJMEDIA_SONAME):
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA app=pjmedia $(subst /,$(HOST_PSEP),$(LIBDIR)/$@)
pjmedia-codec: $(PJMEDIA_CODEC_LIB)
@ -221,12 +221,12 @@ $(PJMEDIA_CODEC_LIB) $(PJMEDIA_CODEC_SONAME): $(PJMEDIA_LIB) $(PJMEDIA_SONAME)
pjmedia-videodev: $(PJMEDIA_VIDEODEV_LIB)
$(PJMEDIA_VIDEODEV_SONAME): $(PJMEDIA_VIDEODEV_LIB)
$(PJMEDIA_VIDEODEV_LIB) $(PJMEDIA_VIDEODEV_SONAME):
$(PJMEDIA_VIDEODEV_LIB) $(PJMEDIA_VIDEODEV_SONAME): $(PJMEDIA_LIB) $(PJMEDIA_SONAME)
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_VIDEODEV app=pjmedia-videodev $(subst /,$(HOST_PSEP),$(LIBDIR)/$@)
pjmedia-audiodev: $(PJMEDIA_AUDIODEV_LIB)
$(PJMEDIA_AUDIODEV_SONAME): $(PJMEDIA_AUDIODEV_LIB)
$(PJMEDIA_AUDIODEV_LIB) $(PJMEDIA_AUDIODEV_SONAME):
$(PJMEDIA_AUDIODEV_LIB) $(PJMEDIA_AUDIODEV_SONAME): $(PJMEDIA_LIB) $(PJMEDIA_SONAME)
$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_AUDIODEV app=pjmedia-audiodev $(subst /,$(HOST_PSEP),$(LIBDIR)/$@)
pjsdp: $(PJSDP_LIB)

View File

@ -2,8 +2,7 @@
# Define the desired video device backend
# Valid values are:
# - mac_os
# - iphone_os
# - darwin_os
# - android_os
AC_PJMEDIA_VIDEO = @ac_pjmedia_video@
@ -21,34 +20,26 @@ V4L2_LDFLAGS = @ac_v4l2_ldflags@
# QT
AC_PJMEDIA_VIDEO_HAS_QT = @ac_pjmedia_video_has_qt@
QT_CFLAGS = @ac_qt_cflags@
# QT_CFLAGS = @ac_qt_cflags@
# iOS
IOS_CFLAGS = @ac_ios_cflags@
# Darwin (Mac and iOS)
DARWIN_CFLAGS = @ac_darwin_cflags@
# Android
ANDROID_CFLAGS = @ac_android_cflags@
# libyuv
LIBYUV_CFLAGS = @ac_libyuv_cflags@
LIBYUV_LDFLAGS = @ac_libyuv_ldflags@
# openh264
OPENH264_CFLAGS = @ac_openh264_cflags@
OPENH264_LDFLAGS = @ac_openh264_ldflags@
# WebRtc
WEBRTC_CFLAGS = @ac_webrtc_cflags@
WEBRTC_LDFLAGS = @ac_webrtc_ldflags@
# PJMEDIA features exclusion
export CFLAGS += @ac_no_small_filter@ @ac_no_large_filter@ @ac_no_speex_aec@ \
$(SDL_CFLAGS) $(FFMPEG_CFLAGS) $(V4L2_CFLAGS) $(QT_CFLAGS) \
$(IOS_CFLAGS) $(ANDROID_CFLAGS) $(LIBYUV_CFLAGS) \
$(OPENH264_CFLAGS) $(WEBRTC_CFLAGS)
$(DARWIN_CFLAGS) $(ANDROID_CFLAGS) \
$(OPENH264_CFLAGS)
export LDFLAGS += $(SDL_LDFLAGS) $(FFMPEG_LDFLAGS) $(V4L2_LDFLAGS) \
$(LIBYUV_LDFLAGS) $(OPENH264_LDFLAGS) $(WEBRTC_LDFLAGS)
$(OPENH264_LDFLAGS)
# Define the desired sound device backend
# Valid values are:
@ -191,18 +182,40 @@ endif
#
# PortAudio
#
ifneq ($(findstring pa,$(AC_PJMEDIA_SND)),)
ifeq (@ac_external_pa@,1)
# External PA
export CFLAGS += -DPJMEDIA_AUDIO_DEV_HAS_PORTAUDIO=1
endif
#
# libyuv
#
ifeq (@ac_no_yuv@,1)
export CFLAGS += -DPJMEDIA_HAS_LIBYUV=0
else
# Our PA in third_party
export CFLAGS += -I$(THIRD_PARTY)/build/portaudio \
-I$(THIRD_PARTY)/portaudio/include \
-DPJMEDIA_AUDIO_DEV_HAS_PORTAUDIO=1
export CFLAGS += -DPJMEDIA_HAS_LIBYUV=1
ifeq (@ac_external_yuv@,0)
export CFLAGS += -I$(THIRD_PARTY)/yuv/include
endif
endif
#
# libwebrtc
#
ifeq (@ac_no_webrtc@,1)
export CFLAGS += -DPJMEDIA_HAS_WEBRTC_AEC=0
else
export CFLAGS += -DPJMEDIA_HAS_WEBRTC_AEC=1
ifneq ($(findstring arm,$(@ac_webrtc_instset@)),)
export CFLAGS += -DPJMEDIA_WEBRTC_AEC_USE_MOBILE=1
endif
ifeq (@ac_external_webrtc@,0)
export CFLAGS += -I$(THIRD_PARTY)/webrtc/src
endif
endif
#
# MacOSX specific
#
@ -255,10 +268,17 @@ export PJMEDIA_VIDEODEV_OBJS += qt_dev.o
endif
#
# iOS video device
# Darwin video device
#
ifeq ($(AC_PJMEDIA_VIDEO),iphone_os)
export PJMEDIA_VIDEODEV_OBJS += ios_dev.o ios_opengl_dev.o
ifeq ($(AC_PJMEDIA_VIDEO_HAS_DARWIN),yes)
export PJMEDIA_VIDEODEV_OBJS += darwin_dev.o
endif
#
# iOS OpenGL video device
#
ifeq ($(AC_PJMEDIA_VIDEO_HAS_IOS_OPENGL),yes)
export PJMEDIA_VIDEODEV_OBJS += ios_opengl_dev.o
endif
#
@ -272,7 +292,7 @@ endif
# Determine whether we should compile the obj-c version of a particular
# source code
#
ifneq (,$(filter $(AC_PJMEDIA_VIDEO),mac_os iphone_os))
ifneq (,$(filter $(AC_PJMEDIA_VIDEO),darwin_os))
# Mac and iPhone OS specific, use obj-c
export PJMEDIA_VIDEODEV_OBJS += sdl_dev_m.o
else

File diff suppressed because it is too large Load Diff

View File

@ -306,7 +306,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderOutputFile />
</ClCompile>
@ -324,14 +324,14 @@
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderOutputFile />
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderOutputFile />
</ClCompile>
@ -349,7 +349,7 @@
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderOutputFile />
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
@ -357,7 +357,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Static|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderOutputFile />
</ClCompile>
@ -375,7 +375,7 @@
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderOutputFile />
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
@ -383,7 +383,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-Dynamic|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderOutputFile />
</ClCompile>
@ -401,14 +401,14 @@
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderOutputFile />
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-Dynamic|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderOutputFile />
</ClCompile>
@ -426,7 +426,7 @@
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderOutputFile />
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
@ -434,7 +434,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-Static|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderOutputFile />
</ClCompile>
@ -452,7 +452,7 @@
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../include;../../pjlib/include;../../pjlib-util/include;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../../third_party/yuv/include;../../third_party/webrtc/src;../..;$(DXSDK_DIR)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderOutputFile />
</ClCompile>
@ -460,6 +460,7 @@
<ItemGroup>
<ClCompile Include="..\src\pjmedia\alaw_ulaw.c" />
<ClCompile Include="..\src\pjmedia\alaw_ulaw_table.c" />
<ClCompile Include="..\src\pjmedia\audiodev.c" />
<ClCompile Include="..\src\pjmedia\avi_player.c" />
<ClCompile Include="..\src\pjmedia\bidirectional.c" />
<ClCompile Include="..\src\pjmedia\clock_thread.c" />
@ -474,6 +475,7 @@
<ClCompile Include="..\src\pjmedia\echo_port.c" />
<ClCompile Include="..\src\pjmedia\echo_speex.c" />
<ClCompile Include="..\src\pjmedia\echo_suppress.c" />
<ClCompile Include="..\src\pjmedia\echo_webrtc.c" />
<ClCompile Include="..\src\pjmedia\endpoint.c" />
<ClCompile Include="..\src\pjmedia\errno.c" />
<ClCompile Include="..\src\pjmedia\event.c" />
@ -512,6 +514,7 @@
<ClCompile Include="..\src\pjmedia\transport_srtp.c" />
<ClCompile Include="..\src\pjmedia\transport_udp.c" />
<ClCompile Include="..\src\pjmedia\types.c" />
<ClCompile Include="..\src\pjmedia\videodev.c" />
<ClCompile Include="..\src\pjmedia\vid_codec.c" />
<ClCompile Include="..\src\pjmedia\vid_codec_util.c" />
<ClCompile Include="..\src\pjmedia\vid_port.c" />
@ -527,6 +530,7 @@
<ItemGroup>
<ClInclude Include="..\include\pjmedia.h" />
<ClInclude Include="..\include\pjmedia\alaw_ulaw.h" />
<ClInclude Include="..\include\pjmedia\audiodev.h" />
<ClInclude Include="..\include\pjmedia\avi.h" />
<ClInclude Include="..\include\pjmedia\avi_stream.h" />
<ClInclude Include="..\include\pjmedia\bidirectional.h" />
@ -574,6 +578,7 @@
<ClInclude Include="..\include\pjmedia\transport_srtp.h" />
<ClInclude Include="..\include\pjmedia\transport_udp.h" />
<ClInclude Include="..\include\pjmedia\types.h" />
<ClInclude Include="..\include\pjmedia\videodev.h" />
<ClInclude Include="..\include\pjmedia\vid_codec.h" />
<ClInclude Include="..\include\pjmedia\vid_codec_util.h" />
<ClInclude Include="..\include\pjmedia\vid_port.h" />

View File

@ -206,6 +206,15 @@
<ClCompile Include="..\src\pjmedia\wsola.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\pjmedia\audiodev.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\pjmedia\videodev.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\pjmedia\echo_webrtc.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\pjmedia\alaw_ulaw.h">
@ -382,5 +391,11 @@
<ClInclude Include="..\include\pjmedia\wsola.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\pjmedia\audiodev.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\pjmedia\videodev.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@ -524,6 +524,7 @@
<ClCompile Include="..\src\pjmedia-codec\l16.c" />
<ClCompile Include="..\src\pjmedia-codec\opencore_amr.c" />
<ClCompile Include="..\src\pjmedia-codec\openh264.cpp" />
<ClCompile Include="..\src\pjmedia-codec\opus.c" />
<ClCompile Include="..\src\pjmedia-codec\passthrough.c" />
<ClCompile Include="..\src\pjmedia-codec\silk.c" />
<ClCompile Include="..\src\pjmedia-codec\speex_codec.c" />
@ -545,6 +546,7 @@
<ClInclude Include="..\include\pjmedia-codec\ipp_codecs.h" />
<ClInclude Include="..\include\pjmedia-codec\l16.h" />
<ClInclude Include="..\include\pjmedia-codec\opencore_amr.h" />
<ClInclude Include="..\include\pjmedia-codec\opus.h" />
<ClInclude Include="..\include\pjmedia-codec\passthrough.h" />
<ClInclude Include="..\include\pjmedia-codec\silk.h" />
<ClInclude Include="..\include\pjmedia-codec\speex.h" />

View File

@ -71,6 +71,9 @@
<ClCompile Include="..\src\pjmedia-codec\g722\g722_enc.c">
<Filter>Source Files\g722 Files</Filter>
</ClCompile>
<ClCompile Include="..\src\pjmedia-codec\opus.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\pjmedia-codec\g722\g722_dec.h">
@ -139,5 +142,8 @@
<ClInclude Include="..\include\pjmedia-codec\types.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\pjmedia-codec\opus.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -22,478 +22,21 @@
/**
* @file audiodev.h
* @brief Audio device API.
* @brief Audio subsystem API.
*/
#include <pjmedia-audiodev/config.h>
#include <pjmedia-audiodev/errno.h>
#include <pjmedia/format.h>
#include <pjmedia/frame.h>
#include <pjmedia/types.h>
#include <pj/pool.h>
#include <pjmedia/audiodev.h>
PJ_BEGIN_DECL
/**
* @defgroup s2_audio_device_reference Audio Device API Reference
* @ingroup audio_device_api
* @defgroup s2_audio_device_reference Audio Subsystem API Reference
* @ingroup audio_subsystem_api
* @brief API Reference
* @{
*/
/**
* Type for device index.
*/
typedef pj_int32_t pjmedia_aud_dev_index;
/**
* Device index constants.
*/
enum
{
/**
* Constant to denote default capture device
*/
PJMEDIA_AUD_DEFAULT_CAPTURE_DEV = -1,
/**
* Constant to denote default playback device
*/
PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV = -2,
/**
* Constant to denote invalid device index.
*/
PJMEDIA_AUD_INVALID_DEV = -3
};
/**
* This enumeration identifies various audio device capabilities. These audio
* capabilities indicates what features are supported by the underlying
* audio device implementation.
*
* Applications get these capabilities in the #pjmedia_aud_dev_info structure.
*
* Application can also set the specific features/capabilities when opening
* the audio stream by setting the \a flags member of #pjmedia_aud_param
* structure.
*
* Once audio stream is running, application can also retrieve or set some
* specific audio capability, by using #pjmedia_aud_stream_get_cap() and
* #pjmedia_aud_stream_set_cap() and specifying the desired capability. The
* value of the capability is specified as pointer, and application needs to
* supply the pointer with the correct value, according to the documentation
* of each of the capability.
*/
typedef enum pjmedia_aud_dev_cap
{
/**
* Support for audio formats other than PCM. The value of this capability
* is represented by #pjmedia_format structure.
*/
PJMEDIA_AUD_DEV_CAP_EXT_FORMAT = 1,
/**
* Support for audio input latency control or query. The value of this
* capability is an unsigned integer containing milliseconds value of
* the latency.
*/
PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY = 2,
/**
* Support for audio output latency control or query. The value of this
* capability is an unsigned integer containing milliseconds value of
* the latency.
*/
PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY = 4,
/**
* Support for setting/retrieving the audio input device volume level.
* The value of this capability is an unsigned integer representing
* the input audio volume setting in percent.
*/
PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING = 8,
/**
* Support for setting/retrieving the audio output device volume level.
* The value of this capability is an unsigned integer representing
* the output audio volume setting in percent.
*/
PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING = 16,
/**
* Support for monitoring the current audio input signal volume.
* The value of this capability is an unsigned integer representing
* the audio volume in percent.
*/
PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER = 32,
/**
* Support for monitoring the current audio output signal volume.
* The value of this capability is an unsigned integer representing
* the audio volume in percent.
*/
PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER = 64,
/**
* Support for audio input routing. The value of this capability is an
* integer containing #pjmedia_aud_dev_route enumeration.
*/
PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE = 128,
/**
* Support for audio output routing (e.g. loudspeaker vs earpiece). The
* value of this capability is an integer containing #pjmedia_aud_dev_route
* enumeration.
*/
PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE = 256,
/**
* The audio device has echo cancellation feature. The value of this
* capability is a pj_bool_t containing boolean PJ_TRUE or PJ_FALSE.
*/
PJMEDIA_AUD_DEV_CAP_EC = 512,
/**
* The audio device supports setting echo cancellation fail length. The
* value of this capability is an unsigned integer representing the
* echo tail in milliseconds.
*/
PJMEDIA_AUD_DEV_CAP_EC_TAIL = 1024,
/**
* The audio device has voice activity detection feature. The value
* of this capability is a pj_bool_t containing boolean PJ_TRUE or
* PJ_FALSE.
*/
PJMEDIA_AUD_DEV_CAP_VAD = 2048,
/**
* The audio device has comfort noise generation feature. The value
* of this capability is a pj_bool_t containing boolean PJ_TRUE or
* PJ_FALSE.
*/
PJMEDIA_AUD_DEV_CAP_CNG = 4096,
/**
* The audio device has packet loss concealment feature. The value
* of this capability is a pj_bool_t containing boolean PJ_TRUE or
* PJ_FALSE.
*/
PJMEDIA_AUD_DEV_CAP_PLC = 8192,
/**
* End of capability
*/
PJMEDIA_AUD_DEV_CAP_MAX = 16384
} pjmedia_aud_dev_cap;
/**
* This enumeration describes audio routing setting.
*/
typedef enum pjmedia_aud_dev_route
{
/**
* Default route, it is the default audio route of the audio framework
* backend, as in opening audio device without specifying any route
* setting or with specifying neutral route setting.
*/
PJMEDIA_AUD_DEV_ROUTE_DEFAULT = 0,
/** Route to loudspeaker */
PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER = 1,
/** Route to earpiece */
PJMEDIA_AUD_DEV_ROUTE_EARPIECE = 2,
/** Route to paired Bluetooth device */
PJMEDIA_AUD_DEV_ROUTE_BLUETOOTH = 4
} pjmedia_aud_dev_route;
/**
* Device information structure returned by #pjmedia_aud_dev_get_info().
*/
typedef struct pjmedia_aud_dev_info
{
/**
* The device name
*/
char name[PJMEDIA_AUD_DEV_INFO_NAME_LEN];
/**
* Maximum number of input channels supported by this device. If the
* value is zero, the device does not support input operation (i.e.
* it is a playback only device).
*/
unsigned input_count;
/**
* Maximum number of output channels supported by this device. If the
* value is zero, the device does not support output operation (i.e.
* it is an input only device).
*/
unsigned output_count;
/**
* Default sampling rate.
*/
unsigned default_samples_per_sec;
/**
* The underlying driver name
*/
char driver[32];
/**
* Device capabilities, as bitmask combination of #pjmedia_aud_dev_cap.
*/
unsigned caps;
/**
* Supported audio device routes, as bitmask combination of
* #pjmedia_aud_dev_route. The value may be zero if the device
* does not support audio routing.
*/
unsigned routes;
/**
* Number of audio formats supported by this device. The value may be
* zero if the device does not support non-PCM format.
*/
unsigned ext_fmt_cnt;
/**
* Array of supported extended audio formats
*/
pjmedia_format ext_fmt[8];
} pjmedia_aud_dev_info;
/**
* This callback is called by player stream when it needs additional data
* to be played by the device. Application must fill in the whole of output
* buffer with audio samples.
*
* The frame argument contains the following values:
* - timestamp Playback timestamp, in samples.
* - buf Buffer to be filled out by application.
* - size The size requested in bytes, which will be equal to
* the size of one whole packet.
*
* @param user_data User data associated with the stream.
* @param frame Audio frame, which buffer is to be filled in by
* the application.
*
* @return Returning non-PJ_SUCCESS will cause the audio stream
* to stop
*/
typedef pj_status_t (*pjmedia_aud_play_cb)(void *user_data,
pjmedia_frame *frame);
/**
* This callback is called by recorder stream when it has captured the whole
* packet worth of audio samples.
*
* @param user_data User data associated with the stream.
* @param frame Captured frame.
*
* @return Returning non-PJ_SUCCESS will cause the audio stream
* to stop
*/
typedef pj_status_t (*pjmedia_aud_rec_cb)(void *user_data,
pjmedia_frame *frame);
/**
* This structure specifies the parameters to open the audio stream.
*/
typedef struct pjmedia_aud_param
{
/**
* The audio direction. This setting is mandatory.
*/
pjmedia_dir dir;
/**
* The audio recorder device ID. This setting is mandatory if the audio
* direction includes input/capture direction.
*/
pjmedia_aud_dev_index rec_id;
/**
* The audio playback device ID. This setting is mandatory if the audio
* direction includes output/playback direction.
*/
pjmedia_aud_dev_index play_id;
/**
* Clock rate/sampling rate. This setting is mandatory.
*/
unsigned clock_rate;
/**
* Number of channels. This setting is mandatory.
*/
unsigned channel_count;
/**
* Number of samples per frame. This setting is mandatory.
*/
unsigned samples_per_frame;
/**
* Number of bits per sample. This setting is mandatory.
*/
unsigned bits_per_sample;
/**
* This flags specifies which of the optional settings are valid in this
* structure. The flags is bitmask combination of pjmedia_aud_dev_cap.
*/
unsigned flags;
/**
* Set the audio format. This setting is optional, and will only be used
* if PJMEDIA_AUD_DEV_CAP_EXT_FORMAT is set in the flags.
*/
pjmedia_format ext_fmt;
/**
* Input latency, in milliseconds. This setting is optional, and will
* only be used if PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY is set in the flags.
*/
unsigned input_latency_ms;
/**
* Input latency, in milliseconds. This setting is optional, and will
* only be used if PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY is set in the flags.
*/
unsigned output_latency_ms;
/**
* Input volume setting, in percent. This setting is optional, and will
* only be used if PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING is set in
* the flags.
*/
unsigned input_vol;
/**
* Output volume setting, in percent. This setting is optional, and will
* only be used if PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING is set in
* the flags.
*/
unsigned output_vol;
/**
* Set the audio input route. This setting is optional, and will only be
* used if PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE is set in the flags.
*/
pjmedia_aud_dev_route input_route;
/**
* Set the audio output route. This setting is optional, and will only be
* used if PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE is set in the flags.
*/
pjmedia_aud_dev_route output_route;
/**
* Enable/disable echo canceller, if the device supports it. This setting
* is optional, and will only be used if PJMEDIA_AUD_DEV_CAP_EC is set in
* the flags.
*/
pj_bool_t ec_enabled;
/**
* Set echo canceller tail length in milliseconds, if the device supports
* it. This setting is optional, and will only be used if
* PJMEDIA_AUD_DEV_CAP_EC_TAIL is set in the flags.
*/
unsigned ec_tail_ms;
/**
* Enable/disable PLC. This setting is optional, and will only be used
* if PJMEDIA_AUD_DEV_CAP_PLC is set in the flags.
*/
pj_bool_t plc_enabled;
/**
* Enable/disable CNG. This setting is optional, and will only be used
* if PJMEDIA_AUD_DEV_CAP_CNG is set in the flags.
*/
pj_bool_t cng_enabled;
/**
* Enable/disable VAD. This setting is optional, and will only be used
* if PJMEDIA_AUD_DEV_CAP_VAD is set in the flags.
*/
pj_bool_t vad_enabled;
} pjmedia_aud_param;
/** Forward declaration for pjmedia_aud_stream */
typedef struct pjmedia_aud_stream pjmedia_aud_stream;
/** Forward declaration for audio device factory */
typedef struct pjmedia_aud_dev_factory pjmedia_aud_dev_factory;
/* typedef for factory creation function */
typedef pjmedia_aud_dev_factory*
(*pjmedia_aud_dev_factory_create_func_ptr)(pj_pool_factory*);
/**
* Get string info for the specified capability.
*
* @param cap The capability ID.
* @param p_desc Optional pointer which will be filled with longer
* description about the capability.
*
* @return Capability name.
*/
PJ_DECL(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
const char **p_desc);
/**
* Set a capability field value in #pjmedia_aud_param structure. This will
* also set the flags field for the specified capability in the structure.
*
* @param param The structure.
* @param cap The audio capability which value is to be set.
* @param pval Pointer to value. Please see the type of value to
* be supplied in the pjmedia_aud_dev_cap documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_param_set_cap(pjmedia_aud_param *param,
pjmedia_aud_dev_cap cap,
const void *pval);
/**
* Get a capability field value from #pjmedia_aud_param structure. This
* function will return PJMEDIA_EAUD_INVCAP error if the flag for that
* capability is not set in the flags field in the structure.
*
* @param param The structure.
* @param cap The audio capability which value is to be retrieved.
* @param pval Pointer to value. Please see the type of value to
* be supplied in the pjmedia_aud_dev_cap documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_param_get_cap(const pjmedia_aud_param *param,
pjmedia_aud_dev_cap cap,
void *pval);
/**
* Initialize the audio subsystem. This will register all supported audio
@ -557,167 +100,6 @@ PJ_DECL(pj_status_t)
pjmedia_aud_unregister_factory(pjmedia_aud_dev_factory_create_func_ptr adf);
/**
* Refresh the list of sound devices installed in the system. This function
* will only refresh the list of audio device so all active audio streams will
* be unaffected. After refreshing the device list, application MUST make sure
* to update all index references to audio devices (i.e. all variables of type
* pjmedia_aud_dev_index) before calling any function that accepts audio device
* index as its parameter.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_dev_refresh(void);
/**
* Get the number of sound devices installed in the system.
*
* @return The number of sound devices installed in the system.
*/
PJ_DECL(unsigned) pjmedia_aud_dev_count(void);
/**
* Get device information.
*
* @param id The audio device ID.
* @param info The device information which will be filled in by this
* function once it returns successfully.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id,
pjmedia_aud_dev_info *info);
/**
* Lookup device index based on the driver and device name.
*
* @param drv_name The driver name.
* @param dev_name The device name.
* @param id Pointer to store the returned device ID.
*
* @return PJ_SUCCESS if the device can be found.
*/
PJ_DECL(pj_status_t) pjmedia_aud_dev_lookup(const char *drv_name,
const char *dev_name,
pjmedia_aud_dev_index *id);
/**
* Initialize the audio device parameters with default values for the
* specified device.
*
* @param id The audio device ID.
* @param param The audio device parameters which will be initialized
* by this function once it returns successfully.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
pjmedia_aud_param *param);
/**
* Open audio stream object using the specified parameters.
*
* @param param Sound device parameters to be used for the stream.
* @param rec_cb Callback to be called on every input frame captured.
* @param play_cb Callback to be called everytime the sound device needs
* audio frames to be played back.
* @param user_data Arbitrary user data, which will be given back in the
* callbacks.
* @param p_strm Pointer to receive the audio stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
pjmedia_aud_stream **p_strm);
/**
* Get the running parameters for the specified audio stream.
*
* @param strm The audio stream.
* @param param Audio stream parameters to be filled in by this
* function once it returns successfully.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
pjmedia_aud_param *param);
/**
* Get the value of a specific capability of the audio stream.
*
* @param strm The audio stream.
* @param cap The audio capability which value is to be retrieved.
* @param value Pointer to value to be filled in by this function
* once it returns successfully. Please see the type
* of value to be supplied in the pjmedia_aud_dev_cap
* documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_get_cap(pjmedia_aud_stream *strm,
pjmedia_aud_dev_cap cap,
void *value);
/**
* Set the value of a specific capability of the audio stream.
*
* @param strm The audio stream.
* @param cap The audio capability which value is to be set.
* @param value Pointer to value. Please see the type of value to
* be supplied in the pjmedia_aud_dev_cap documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_set_cap(pjmedia_aud_stream *strm,
pjmedia_aud_dev_cap cap,
const void *value);
/**
* Start the stream.
*
* @param strm The audio stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm);
/**
* Stop the stream.
*
* @param strm The audio stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm);
/**
* Destroy the stream.
*
* @param strm The audio stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm);
/**
* @}
*/

View File

@ -59,17 +59,10 @@ PJ_BEGIN_DECL
/**
* This setting controls whether PortAudio support should be included.
*
* By default it is enabled except on Windows platforms (including
* Windows Mobile) and Symbian.
* By default it is disabled.
*/
#ifndef PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
# if (defined(PJ_WIN32) && PJ_WIN32!=0) || \
(defined(PJ_WIN64) && PJ_WIN64!=0) || \
(defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0)
# define PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO 0
# else
# define PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO 1
# endif
# define PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO 0
#endif
/**

View File

@ -38,6 +38,7 @@
#include <pjmedia-codec/openh264.h>
#include <pjmedia-codec/passthrough.h>
#include <pjmedia-codec/silk.h>
#include <pjmedia-codec/opus.h>
#endif /* __PJMEDIA_CODEC_PJMEDIA_CODEC_H__ */

View File

@ -419,13 +419,63 @@
#endif
/**
* Enable OPUS codec.
*
* Default: 0
*/
#ifndef PJMEDIA_HAS_OPUS_CODEC
# define PJMEDIA_HAS_OPUS_CODEC 0
#endif
/**
* OPUS codec sample rate.
*
* Default: 48000
*/
#ifndef PJMEDIA_CODEC_OPUS_DEFAULT_SAMPLE_RATE
# define PJMEDIA_CODEC_OPUS_DEFAULT_SAMPLE_RATE 48000
#endif
/**
* OPUS codec default maximum average bit rate.
*
* Default: 0 (leave it to default value specified by Opus, which will
* take into account factors such as media content (speech/music), sample
* rate, channel count, etc).
*/
#ifndef PJMEDIA_CODEC_OPUS_DEFAULT_BIT_RATE
# define PJMEDIA_CODEC_OPUS_DEFAULT_BIT_RATE 0
#endif
/**
* OPUS default encoding complexity, which is an integer from
* 0 to 10, where 0 is the lowest complexity and 10 is the highest.
*
* Default: 5
*/
#ifndef PJMEDIA_CODEC_OPUS_DEFAULT_COMPLEXITY
# define PJMEDIA_CODEC_OPUS_DEFAULT_COMPLEXITY 5
#endif
/**
* OPUS default CBR (constant bit rate) setting
*
* Default: PJ_FALSE (which means Opus will use VBR (variable bit rate))
*/
#ifndef PJMEDIA_CODEC_OPUS_DEFAULT_CBR
# define PJMEDIA_CODEC_OPUS_DEFAULT_CBR PJ_FALSE
#endif
/**
* Specify if FFMPEG codecs are available.
*
* Default: PJMEDIA_HAS_LIBAVCODEC
* Default: PJMEDIA_HAS_LIBAVFORMAT
*/
#ifndef PJMEDIA_HAS_FFMPEG_CODEC
# define PJMEDIA_HAS_FFMPEG_CODEC PJMEDIA_HAS_LIBAVCODEC
# define PJMEDIA_HAS_FFMPEG_CODEC PJMEDIA_HAS_LIBAVFORMAT
#endif

View File

@ -84,6 +84,11 @@
#undef PJMEDIA_HAS_SILK_CODEC
#endif
/* OPUS codec */
#ifndef PJMEDIA_HAS_OPUS_CODEC
#undef PJMEDIA_HAS_OPUS_CODEC
#endif
#endif /* __PJMEDIA_CODEC_CONFIG_AUTO_H_ */

View File

@ -0,0 +1,155 @@
/* $Id$ */
/*
* Copyright (C) 2015-2016 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2012-2015 Zaark Technology AB
*
* 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
*/
/* This file is the header of Opus codec wrapper and was contributed by
* Zaark Technology AB
*/
#ifndef __PJMEDIA_CODEC_OPUS_H__
#define __PJMEDIA_CODEC_OPUS_H__
/**
* @file opus.h
* @brief Opus codec.
*/
#include <pjmedia-codec/types.h>
PJ_BEGIN_DECL
/**
* @defgroup PJMED_OPUS Opus Codec Family
* @ingroup PJMEDIA_CODEC_CODECS
* @brief Opus codec wrapper
* @{
*
* This section describes functions to initialize and register Opus codec
* factory to the codec manager. After the codec factory has been registered,
* application can use @ref PJMEDIA_CODEC API to manipulate the codec.
*
* Opus codec uses multiple bit rates, and supports fullband (48 kHz
* sampling rate), super wideband (24 kHz sampling rate), wideband (16 kHz
* sampling rate), medium band (12kHz sampling rate), and narrowband
* (8 kHz sampling rate).
*
*
* \section codec_setting Codec Settings
*
* General codec settings for this codec such as VAD and PLC can be
* manipulated through the <tt>setting</tt> field in #pjmedia_codec_param
* (see the documentation of #pjmedia_codec_param for more info).
*
* For Opus codec specific settings, such as sample rate,
* channel count, bit rate, complexity, and CBR, can be configured
* in #pjmedia_codec_opus_config.
* The default setting of sample rate is specified in
* #PJMEDIA_CODEC_OPUS_DEFAULT_SAMPLE_RATE. The default setting of
* bitrate is specified in #PJMEDIA_CODEC_OPUS_DEFAULT_BIT_RATE.
* And the default setting of complexity is specified in
* #PJMEDIA_CODEC_OPUS_DEFAULT_COMPLEXITY.
*
* After modifying any of these settings, application needs to call
* #pjmedia_codec_opus_set_default_param(), which will generate the
* appropriate decoding fmtp attributes.
*
* Here is an example of modifying the codec settings:
\code
pjmedia_codec_param param;
pjmedia_codec_opus_config opus_cfg;
pjmedia_codec_mgr_get_default_param(.., &param);
pjmedia_codec_opus_get_config(&opus_cfg);
...
// Set VAD
param.setting.vad = 1;
// Set PLC
param.setting.vad = 1;
// Set sample rate
opus_cfg.sample_rate = 16000;
// Set channel count
opus_cfg.channel_cnt = 2;
// Set bit rate
opus_cfg.bit_rate = 20000;
...
pjmedia_codec_opus_set_default_param(&opus_cfg, &param);
\endcode
*
*/
/**
* Opus codec configuration.
*/
typedef struct pjmedia_codec_opus_config
{
unsigned sample_rate; /**< Sample rate in Hz. */
unsigned channel_cnt; /**< Number of channels. */
unsigned bit_rate; /**< Encoder bit rate in bps. */
unsigned packet_loss; /**< Encoder's expected packet loss pct. */
unsigned complexity; /**< Encoder complexity, 0-10(10 is highest)*/
pj_bool_t cbr; /**< Constant bit rate? */
} pjmedia_codec_opus_config;
/**
* Initialize and register Opus codec factory to pjmedia endpoint.
*
* @param endpt The pjmedia endpoint.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjmedia_codec_opus_init( pjmedia_endpt *endpt );
/**
* Unregister Opus codec factory from pjmedia endpoint and deinitialize
* the Opus codec library.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjmedia_codec_opus_deinit( void );
/**
* Get the default Opus configuration.
*
* @param cfg Opus codec configuration.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t)
pjmedia_codec_opus_get_config( pjmedia_codec_opus_config *cfg );
/**
* Set the default Opus configuration and set the default Opus codec param.
* Note that the function will call #pjmedia_codec_mgr_set_default_param().
*
* @param cfg Opus codec configuration.
* @param param The new default Opus codec parameter.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t)
pjmedia_codec_opus_set_default_param(const pjmedia_codec_opus_config *cfg,
pjmedia_codec_param *param );
PJ_END_DECL
/**
* @}
*/
#endif /* __PJMEDIA_CODEC_OPUS_H__ */

View File

@ -83,6 +83,7 @@ enum pjmedia_audio_pt
PJMEDIA_RTP_PT_G7221C_48, /**< G722.1 Annex C (48Kbps)*/
PJMEDIA_RTP_PT_G7221_RSV1, /**< G722.1 reserve */
PJMEDIA_RTP_PT_G7221_RSV2, /**< G722.1 reserve */
PJMEDIA_RTP_PT_OPUS, /**< OPUS */
PJMEDIA_RTP_PT_L16_8KHZ_MONO, /**< L16 @ 8KHz, mono */
PJMEDIA_RTP_PT_L16_8KHZ_STEREO, /**< L16 @ 8KHz, stereo */
//PJMEDIA_RTP_PT_L16_11KHZ_MONO, /**< L16 @ 11KHz, mono */

View File

@ -52,8 +52,6 @@ PJ_BEGIN_DECL
#endif
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
/**
* This setting controls the maximum number of supported video device drivers.
*
@ -73,6 +71,8 @@ PJ_BEGIN_DECL
#endif
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
/**
* This setting controls whether OpenGL for iOS should be included.
*
@ -122,12 +122,20 @@ PJ_BEGIN_DECL
/**
* This setting controls whether OpenGL support should be included.
* This setting controls whether OpenGL support should be included. Note that as
* currently only OpenGLES is supported, when PJMEDIA_VIDEO_DEV_HAS_OPENGL_ES is
* unset, PJMEDIA_VIDEO_DEV_HAS_OPENGL will automatically also be unset.
*
* Default: 0 (or detected by configure)
*/
#ifndef PJMEDIA_VIDEO_DEV_HAS_OPENGL
# define PJMEDIA_VIDEO_DEV_HAS_OPENGL 0
#else
# if defined(PJMEDIA_VIDEO_DEV_HAS_OPENGL_ES) && \
PJMEDIA_VIDEO_DEV_HAS_OPENGL_ES == 0
# undef PJMEDIA_VIDEO_DEV_HAS_OPENGL
# define PJMEDIA_VIDEO_DEV_HAS_OPENGL 0
# endif
#endif
@ -138,6 +146,15 @@ PJ_BEGIN_DECL
*/
#ifndef PJMEDIA_VIDEO_DEV_HAS_SDL
# define PJMEDIA_VIDEO_DEV_HAS_SDL 0
#endif
/**
* This setting controls whether SDL with OPENGL support should be included.
*
* Default: 0
*/
#ifndef PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
# define PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL 0
#endif

View File

@ -23,517 +23,18 @@
* @file videodev.h
* @brief Video device API.
*/
#include <pjmedia-videodev/config.h>
#include <pjmedia-videodev/errno.h>
#include <pjmedia/event.h>
#include <pjmedia/frame.h>
#include <pjmedia/format.h>
#include <pj/pool.h>
#include <pjmedia/videodev.h>
PJ_BEGIN_DECL
/**
* @defgroup video_device_reference Video Device API Reference
* @ingroup video_device_api
* @defgroup video_device_reference Video Subsystem API Reference
* @ingroup video_subsystem_api
* @brief API Reference
* @{
*/
/**
* Type for device index.
*/
typedef pj_int32_t pjmedia_vid_dev_index;
/**
* Enumeration of window handle type.
*/
typedef enum pjmedia_vid_dev_hwnd_type
{
/**
* Type none.
*/
PJMEDIA_VID_DEV_HWND_TYPE_NONE,
/**
* Native window handle on Windows.
*/
PJMEDIA_VID_DEV_HWND_TYPE_WINDOWS,
/**
* Native view on iOS.
*/
PJMEDIA_VID_DEV_HWND_TYPE_IOS,
/**
* Native window handle on Android.
*/
PJMEDIA_VID_DEV_HWND_TYPE_ANDROID
} pjmedia_vid_dev_hwnd_type;
/**
* Type for window handle.
*/
typedef struct pjmedia_vid_dev_hwnd
{
/**
* The window handle type.
*/
pjmedia_vid_dev_hwnd_type type;
/**
* The window handle.
*/
union
{
struct {
void *hwnd; /**< HWND */
} win;
struct {
void *window; /**< Window */
void *display; /**< Display */
} x11;
struct {
void *window; /**< Window */
} cocoa;
struct {
void *window; /**< Window */
} ios;
struct {
void *window; /**< Native window */
} android;
void *window;
} info;
} pjmedia_vid_dev_hwnd;
/**
* Parameter for switching device with PJMEDIA_VID_DEV_CAP_SWITCH capability.
* Initialize this with pjmedia_vid_dev_switch_param_default()
*/
typedef struct pjmedia_vid_dev_switch_param
{
/**
* Target device ID to switch to. Once the switching is successful, the
* video stream will use this device and the old device will be closed.
*/
pjmedia_vid_dev_index target_id;
} pjmedia_vid_dev_switch_param;
/**
* Enumeration of window flags.
*/
typedef enum pjmedia_vid_dev_wnd_flag
{
/**
* Window with border.
*/
PJMEDIA_VID_DEV_WND_BORDER = 1,
/**
* Window can be resized.
*/
PJMEDIA_VID_DEV_WND_RESIZABLE = 2
} pjmedia_vid_dev_wnd_flag;
/**
* Device index constants.
*/
enum pjmedia_vid_dev_std_index
{
/**
* Constant to denote default capture device
*/
PJMEDIA_VID_DEFAULT_CAPTURE_DEV = -1,
/**
* Constant to denote default render device
*/
PJMEDIA_VID_DEFAULT_RENDER_DEV = -2,
/**
* Constant to denote invalid device index.
*/
PJMEDIA_VID_INVALID_DEV = -3
};
/**
* This enumeration identifies various video device capabilities. These video
* capabilities indicates what features are supported by the underlying
* video device implementation.
*
* Applications get these capabilities in the #pjmedia_vid_dev_info structure.
*
* Application can also set the specific features/capabilities when opening
* the video stream by setting the \a flags member of #pjmedia_vid_dev_param
* structure.
*
* Once video stream is running, application can also retrieve or set some
* specific video capability, by using #pjmedia_vid_dev_stream_get_cap() and
* #pjmedia_vid_dev_stream_set_cap() and specifying the desired capability. The
* value of the capability is specified as pointer, and application needs to
* supply the pointer with the correct value, according to the documentation
* of each of the capability.
*/
typedef enum pjmedia_vid_dev_cap
{
/**
* Support for video formats. The value of this capability
* is represented by #pjmedia_format structure.
*/
PJMEDIA_VID_DEV_CAP_FORMAT = 1,
/**
* Support for video input scaling
*/
PJMEDIA_VID_DEV_CAP_INPUT_SCALE = 2,
/**
* Support for returning the native window handle of the video window.
* For renderer, this means the window handle of the renderer window,
* while for capture, this means the window handle of the native preview,
* only if the device supports PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW
* capability.
*
* The value of this capability is pointer to pjmedia_vid_dev_hwnd
* structure.
*/
PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW = 4,
/**
* Support for resizing video output. This capability SHOULD be
* implemented by renderer, to alter the video output dimension on the fly.
* Value is pjmedia_rect_size.
*/
PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE = 8,
/**
* Support for setting the video window's position.
* Value is pjmedia_coord specifying the window's new coordinate.
*/
PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION = 16,
/**
* Support for setting the video output's visibility.
* The value of this capability is a pj_bool_t containing boolean
* PJ_TRUE or PJ_FALSE.
*/
PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE = 32,
/**
* Support for native preview capability in capture devices. Value is
* pj_bool_t. With native preview, capture device can be instructed to
* show or hide a preview window showing video directly from the camera
* by setting this capability to PJ_TRUE or PJ_FALSE. Once the preview
* is started, application may use PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW
* capability to query the video window.
*
* The value of this capability is a pj_bool_t containing boolean
* PJ_TRUE or PJ_FALSE.
*/
PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW = 64,
/**
* Support for changing video orientation. For a renderer device,
* changing video orientation in will potentially affect the size of
* render window, i.e: width and height swap. For a capture device,
* the video will be rotated but the size of the video frame
* will stay the same, so the video may be resized or stretched.
*
* The value of this capability is pjmedia_orient.
*/
PJMEDIA_VID_DEV_CAP_ORIENTATION = 128,
/**
* Support for fast switching to another device. A video stream with this
* capability allows replacing of its underlying device with another
* device, saving the user from opening a new video stream and gets a much
* faster and smoother switching action.
*
* Note that even when this capability is supported by a device, it may
* not be able to switch to arbitrary device. Application must always
* check the return value of the operation to verify that switching has
* occurred.
*
* This capability is currently write-only (i.e. set-only).
*
* The value of this capability is pointer to pjmedia_vid_dev_switch_param
* structure.
*/
PJMEDIA_VID_DEV_CAP_SWITCH = 256,
/**
* Support for setting the output video window's flags.
* The value of this capability is a bitmask combination of
* #pjmedia_vid_dev_wnd_flag.
*/
PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS = 512,
/**
* End of standard capability
*/
PJMEDIA_VID_DEV_CAP_MAX = 16384
} pjmedia_vid_dev_cap;
/**
* Device information structure returned by #pjmedia_vid_dev_get_info().
*/
typedef struct pjmedia_vid_dev_info
{
/** The device ID */
pjmedia_vid_dev_index id;
/** The device name */
char name[64];
/** The underlying driver name */
char driver[32];
/**
* The supported direction of the video device, i.e. whether it supports
* capture only, render only, or both.
*/
pjmedia_dir dir;
/**
* Specify whether the device supports callback. Devices that implement
* "active interface" will actively call the callbacks to give or ask for
* video frames. If the device doesn't support callback, application
* must actively request or give video frames from/to the device by using
* pjmedia_vid_dev_stream_get_frame()/pjmedia_vid_dev_stream_put_frame().
*/
pj_bool_t has_callback;
/** Device capabilities, as bitmask combination of #pjmedia_vid_dev_cap */
unsigned caps;
/** Number of video formats supported by this device */
unsigned fmt_cnt;
/**
* Array of supported video formats. Some fields in each supported video
* format may be set to zero or of "unknown" value, to indicate that the
* value is unknown or should be ignored. When these value are not set
* to zero, it indicates that the exact format combination is being used.
*/
pjmedia_format fmt[PJMEDIA_VID_DEV_INFO_FMT_CNT];
} pjmedia_vid_dev_info;
/** Forward declaration for pjmedia_vid_dev_stream */
typedef struct pjmedia_vid_dev_stream pjmedia_vid_dev_stream;
typedef struct pjmedia_vid_dev_cb
{
/**
* This callback is called by capturer stream when it has captured the
* whole packet worth of video samples.
*
* @param stream The video stream.
* @param user_data User data associated with the stream.
* @param frame Captured frame.
*
* @return Returning non-PJ_SUCCESS will cause the video
* stream to stop
*/
pj_status_t (*capture_cb)(pjmedia_vid_dev_stream *stream,
void *user_data,
pjmedia_frame *frame);
/**
* This callback is called by renderer stream when it needs additional
* data to be rendered by the device. Application must fill in the whole
* of output buffer with video samples.
*
* The frame argument contains the following values:
* - timestamp Rendering timestamp, in samples.
* - buf Buffer to be filled out by application.
* - size The size requested in bytes, which will be equal
* to the size of one whole packet.
*
* @param stream The video stream.
* @param user_data User data associated with the stream.
* @param frame Video frame, which buffer is to be filled in by
* the application.
*
* @return Returning non-PJ_SUCCESS will cause the video
* stream to stop
*/
pj_status_t (*render_cb)(pjmedia_vid_dev_stream *stream,
void *user_data,
pjmedia_frame *frame);
} pjmedia_vid_dev_cb;
/**
* This structure specifies the parameters to open the video stream.
*/
typedef struct pjmedia_vid_dev_param
{
/**
* The video direction. This setting is mandatory.
*/
pjmedia_dir dir;
/**
* The video capture device ID. This setting is mandatory if the video
* direction includes input/capture direction.
*/
pjmedia_vid_dev_index cap_id;
/**
* The video render device ID. This setting is mandatory if the video
* direction includes output/render direction.
*/
pjmedia_vid_dev_index rend_id;
/**
* Video clock rate. This setting is mandatory if the video
* direction includes input/capture direction
*/
unsigned clock_rate;
/**
* Video frame rate. This setting is mandatory if the video
* direction includes input/capture direction
*/
// pjmedia_ratio frame_rate;
/**
* This flags specifies which of the optional settings are valid in this
* structure. The flags is bitmask combination of pjmedia_vid_dev_cap.
*/
unsigned flags;
/**
* Set the video format. This setting is mandatory.
*/
pjmedia_format fmt;
/**
* Window for the renderer to display the video. This setting is optional,
* and will only be used if PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW is set in
* the flags.
*/
pjmedia_vid_dev_hwnd window;
/**
* Video display size. This setting is optional, and will only be used
* if PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE is set in the flags.
*/
pjmedia_rect_size disp_size;
/**
* Video window position. This setting is optional, and will only be used
* if PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION is set in the flags.
*/
pjmedia_coord window_pos;
/**
* Video window's visibility. This setting is optional, and will only be
* used if PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE is set in the flags.
*/
pj_bool_t window_hide;
/**
* Enable built-in preview. This setting is optional and is only used
* if PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW capability is supported and
* set in the flags.
*/
pj_bool_t native_preview;
/**
* Video orientation. This setting is optional and is only used if
* PJMEDIA_VID_DEV_CAP_ORIENTATION capability is supported and is
* set in the flags.
*/
pjmedia_orient orient;
/**
* Video window flags. This setting is optional, and will only be used
* if PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS is set in the flags.
*/
unsigned window_flags;
} pjmedia_vid_dev_param;
/** Forward declaration for video device factory */
typedef struct pjmedia_vid_dev_factory pjmedia_vid_dev_factory;
/* typedef for factory creation function */
typedef pjmedia_vid_dev_factory*
(*pjmedia_vid_dev_factory_create_func_ptr)(pj_pool_factory*);
/**
* Initialize pjmedia_vid_dev_switch_param.
*
* @param p Parameter to be initialized.
*/
PJ_INLINE(void)
pjmedia_vid_dev_switch_param_default(pjmedia_vid_dev_switch_param *p)
{
pj_bzero(p, sizeof(*p));
p->target_id = PJMEDIA_VID_INVALID_DEV;
}
/**
* Get string info for the specified capability.
*
* @param cap The capability ID.
* @param p_desc Optional pointer which will be filled with longer
* description about the capability.
*
* @return Capability name.
*/
PJ_DECL(const char*) pjmedia_vid_dev_cap_name(pjmedia_vid_dev_cap cap,
const char **p_desc);
/**
* Set a capability field value in #pjmedia_vid_dev_param structure. This will
* also set the flags field for the specified capability in the structure.
*
* @param param The structure.
* @param cap The video capability which value is to be set.
* @param pval Pointer to value. Please see the type of value to
* be supplied in the pjmedia_vid_dev_cap documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t)
pjmedia_vid_dev_param_set_cap(pjmedia_vid_dev_param *param,
pjmedia_vid_dev_cap cap,
const void *pval);
/**
* Get a capability field value from #pjmedia_vid_dev_param structure. This
* function will return PJMEDIA_EVID_INVCAP error if the flag for that
* capability is not set in the flags field in the structure.
*
* @param param The structure.
* @param cap The video capability which value is to be retrieved.
* @param pval Pointer to value. Please see the type of value to
* be supplied in the pjmedia_vid_dev_cap documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t)
pjmedia_vid_dev_param_get_cap(const pjmedia_vid_dev_param *param,
pjmedia_vid_dev_cap cap,
void *pval);
/**
* Initialize the video device subsystem. This will register all supported
@ -609,226 +110,6 @@ pjmedia_vid_unregister_factory(pjmedia_vid_dev_factory_create_func_ptr vdf,
pjmedia_vid_dev_factory *factory);
/**
* Refresh the list of video devices installed in the system. This function
* will only refresh the list of videoo device so all active video streams will
* be unaffected. After refreshing the device list, application MUST make sure
* to update all index references to video devices (i.e. all variables of type
* pjmedia_vid_dev_index) before calling any function that accepts video device
* index as its parameter.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_refresh(void);
/**
* Get the number of video devices installed in the system.
*
* @return The number of video devices installed in the system.
*/
PJ_DECL(unsigned) pjmedia_vid_dev_count(void);
/**
* Get device information.
*
* @param id The video device ID.
* @param info The device information which will be filled in by this
* function once it returns successfully.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_get_info(pjmedia_vid_dev_index id,
pjmedia_vid_dev_info *info);
/**
* Lookup device index based on the driver and device name.
*
* @param drv_name The driver name.
* @param dev_name The device name.
* @param id Pointer to store the returned device ID.
*
* @return PJ_SUCCESS if the device can be found.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_lookup(const char *drv_name,
const char *dev_name,
pjmedia_vid_dev_index *id);
/**
* Initialize the video device parameters with default values for the
* specified device.
*
* @param id The video device ID.
* @param param The video device parameters which will be initialized
* by this function once it returns successfully.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t)
pjmedia_vid_dev_default_param(pj_pool_t *pool,
pjmedia_vid_dev_index id,
pjmedia_vid_dev_param *param);
/**
* Open video stream object using the specified parameters. If stream is
* created successfully, this function will return PJ_SUCCESS and the
* stream pointer will be returned in the p_strm argument.
*
* The opened stream may have been opened with different size and fps
* than the requested values in the \a param argument. Application should
* check the actual size and fps that the stream was opened with by inspecting
* the values in the \a param argument and see if they have changed. Also
* if the device ID in the \a param specifies default device, it may be
* replaced with the actual device ID upon return.
*
* @param param On input, it specifies the video device parameters
* to be used for the stream. On output, this will be
* set to the actual video device parameters used to
* open the stream.
* @param cb Pointer to structure containing video stream
* callbacks.
* @param user_data Arbitrary user data, which will be given back in the
* callbacks.
* @param p_strm Pointer to receive the video stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_create(
pjmedia_vid_dev_param *param,
const pjmedia_vid_dev_cb *cb,
void *user_data,
pjmedia_vid_dev_stream **p_strm);
/**
* Get the running parameters for the specified video stream.
*
* @param strm The video stream.
* @param param Video stream parameters to be filled in by this
* function once it returns successfully.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_param(
pjmedia_vid_dev_stream *strm,
pjmedia_vid_dev_param *param);
/**
* Get the value of a specific capability of the video stream.
*
* @param strm The video stream.
* @param cap The video capability which value is to be retrieved.
* @param value Pointer to value to be filled in by this function
* once it returns successfully. Please see the type
* of value to be supplied in the pjmedia_vid_dev_cap
* documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_cap(
pjmedia_vid_dev_stream *strm,
pjmedia_vid_dev_cap cap,
void *value);
/**
* Set the value of a specific capability of the video stream.
*
* @param strm The video stream.
* @param cap The video capability which value is to be set.
* @param value Pointer to value. Please see the type of value to
* be supplied in the pjmedia_vid_dev_cap documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_set_cap(
pjmedia_vid_dev_stream *strm,
pjmedia_vid_dev_cap cap,
const void *value);
/**
* Start the stream.
*
* @param strm The video stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_start(
pjmedia_vid_dev_stream *strm);
/**
* Query whether the stream has been started.
*
* @param strm The video stream
*
* @return PJ_TRUE if the video stream has been started.
*/
PJ_DECL(pj_bool_t) pjmedia_vid_dev_stream_is_running(pjmedia_vid_dev_stream *strm);
/**
* Request one frame from the stream. Application needs to call this function
* periodically only if the stream doesn't support "active interface", i.e.
* the pjmedia_vid_dev_info.has_callback member is PJ_FALSE.
*
* @param strm The video stream.
* @param frame The video frame to be filled by the device.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_frame(
pjmedia_vid_dev_stream *strm,
pjmedia_frame *frame);
/**
* Put one frame to the stream. Application needs to call this function
* periodically only if the stream doesn't support "active interface", i.e.
* the pjmedia_vid_dev_info.has_callback member is PJ_FALSE.
*
* @param strm The video stream.
* @param frame The video frame to put to the device.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_put_frame(
pjmedia_vid_dev_stream *strm,
const pjmedia_frame *frame);
/**
* Stop the stream.
*
* @param strm The video stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_stop(
pjmedia_vid_dev_stream *strm);
/**
* Destroy the stream.
*
* @param strm The video stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_destroy(
pjmedia_vid_dev_stream *strm);
/**
* @}
*/

View File

@ -0,0 +1,746 @@
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* 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_AUDIO_DEV_H__
#define __PJMEDIA_AUDIO_DEV_H__
/**
* @file audiodev.h
* @brief Audio device API.
*/
#include <pjmedia-audiodev/config.h>
#include <pjmedia-audiodev/errno.h>
#include <pjmedia/format.h>
#include <pjmedia/frame.h>
#include <pjmedia/types.h>
#include <pj/pool.h>
PJ_BEGIN_DECL
/**
* @defgroup s2_audio_device_reference Audio Device API Reference
* @ingroup audio_device_api
* @brief API Reference
* @{
*/
/**
* Type for device index.
*/
typedef pj_int32_t pjmedia_aud_dev_index;
/**
* Device index constants.
*/
enum
{
/**
* Constant to denote default capture device
*/
PJMEDIA_AUD_DEFAULT_CAPTURE_DEV = -1,
/**
* Constant to denote default playback device
*/
PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV = -2,
/**
* Constant to denote invalid device index.
*/
PJMEDIA_AUD_INVALID_DEV = -3
};
#define PJMEDIA_AUD_MAX_DRIVERS 16
#define PJMEDIA_AUD_MAX_DEVS 64
/** Forward declaration for pjmedia_aud_stream */
typedef struct pjmedia_aud_stream pjmedia_aud_stream;
/** Forward declaration for audio device factory */
typedef struct pjmedia_aud_dev_factory pjmedia_aud_dev_factory;
/* typedef for factory creation function */
typedef pjmedia_aud_dev_factory*
(*pjmedia_aud_dev_factory_create_func_ptr)(pj_pool_factory*);
/* Audio driver structure */
typedef struct pjmedia_aud_driver
{
pjmedia_aud_dev_factory_create_func_ptr create; /* Creation function */
pjmedia_aud_dev_factory *f; /* Factory instance */
char name[32]; /* Driver name */
unsigned dev_cnt; /* Number of devices */
unsigned start_idx; /* Start index in global list */
int rec_dev_idx; /* Default capture device. */
int play_dev_idx;/* Default playback device */
int dev_idx; /* Default device. */
} pjmedia_aud_driver;
/* Audio subsystem structure */
typedef struct pjmedia_aud_subsys
{
unsigned init_count; /* How many times init() is called */
pj_pool_factory *pf; /* The pool factory. */
unsigned drv_cnt; /* Number of drivers. */
pjmedia_aud_driver drv[PJMEDIA_AUD_MAX_DRIVERS];/* Array of drivers. */
unsigned dev_cnt; /* Total number of devices. */
pj_uint32_t dev_list[PJMEDIA_AUD_MAX_DEVS];/* Array of dev IDs. */
} pjmedia_aud_subsys;
/**
* This enumeration identifies various audio device capabilities. These audio
* capabilities indicates what features are supported by the underlying
* audio device implementation.
*
* Applications get these capabilities in the #pjmedia_aud_dev_info structure.
*
* Application can also set the specific features/capabilities when opening
* the audio stream by setting the \a flags member of #pjmedia_aud_param
* structure.
*
* Once audio stream is running, application can also retrieve or set some
* specific audio capability, by using #pjmedia_aud_stream_get_cap() and
* #pjmedia_aud_stream_set_cap() and specifying the desired capability. The
* value of the capability is specified as pointer, and application needs to
* supply the pointer with the correct value, according to the documentation
* of each of the capability.
*/
typedef enum pjmedia_aud_dev_cap
{
/**
* Support for audio formats other than PCM. The value of this capability
* is represented by #pjmedia_format structure.
*/
PJMEDIA_AUD_DEV_CAP_EXT_FORMAT = 1,
/**
* Support for audio input latency control or query. The value of this
* capability is an unsigned integer containing milliseconds value of
* the latency.
*/
PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY = 2,
/**
* Support for audio output latency control or query. The value of this
* capability is an unsigned integer containing milliseconds value of
* the latency.
*/
PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY = 4,
/**
* Support for setting/retrieving the audio input device volume level.
* The value of this capability is an unsigned integer representing
* the input audio volume setting in percent.
*/
PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING = 8,
/**
* Support for setting/retrieving the audio output device volume level.
* The value of this capability is an unsigned integer representing
* the output audio volume setting in percent.
*/
PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING = 16,
/**
* Support for monitoring the current audio input signal volume.
* The value of this capability is an unsigned integer representing
* the audio volume in percent.
*/
PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER = 32,
/**
* Support for monitoring the current audio output signal volume.
* The value of this capability is an unsigned integer representing
* the audio volume in percent.
*/
PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER = 64,
/**
* Support for audio input routing/source. The value of this capability
* is an integer containing #pjmedia_aud_dev_route enumeration.
*/
PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE = 128,
PJMEDIA_AUD_DEV_CAP_INPUT_SOURCE = 128,
/**
* Support for audio output routing (e.g. loudspeaker vs earpiece). The
* value of this capability is an integer containing #pjmedia_aud_dev_route
* enumeration.
*/
PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE = 256,
/**
* The audio device has echo cancellation feature. The value of this
* capability is a pj_bool_t containing boolean PJ_TRUE or PJ_FALSE.
*/
PJMEDIA_AUD_DEV_CAP_EC = 512,
/**
* The audio device supports setting echo cancellation fail length. The
* value of this capability is an unsigned integer representing the
* echo tail in milliseconds.
*/
PJMEDIA_AUD_DEV_CAP_EC_TAIL = 1024,
/**
* The audio device has voice activity detection feature. The value
* of this capability is a pj_bool_t containing boolean PJ_TRUE or
* PJ_FALSE.
*/
PJMEDIA_AUD_DEV_CAP_VAD = 2048,
/**
* The audio device has comfort noise generation feature. The value
* of this capability is a pj_bool_t containing boolean PJ_TRUE or
* PJ_FALSE.
*/
PJMEDIA_AUD_DEV_CAP_CNG = 4096,
/**
* The audio device has packet loss concealment feature. The value
* of this capability is a pj_bool_t containing boolean PJ_TRUE or
* PJ_FALSE.
*/
PJMEDIA_AUD_DEV_CAP_PLC = 8192,
/**
* End of capability
*/
PJMEDIA_AUD_DEV_CAP_MAX = 16384
} pjmedia_aud_dev_cap;
/**
* This enumeration describes audio routing/source setting.
*/
typedef enum pjmedia_aud_dev_route
{
/**
* Default route/source, it is the default audio route/source of
* the audio framework backend, as in opening audio device without
* specifying any route/source setting or with specifying neutral
* route/source setting.
*/
PJMEDIA_AUD_DEV_ROUTE_DEFAULT = 0,
/** Route to loudspeaker */
PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER = 1,
/** Route to earpiece */
PJMEDIA_AUD_DEV_ROUTE_EARPIECE = 2,
/** Route to paired Bluetooth device */
PJMEDIA_AUD_DEV_ROUTE_BLUETOOTH = 4,
/**
* Custom audio route/source, specific to each audio device
* backend.
*
* For Android JNI audio device, the default is
* VOICE_COMMUNICATION (7). To change it to another value, set
* the input source capability of pjmedia_aud_param accordingly.
* For example:
* // 6 is VOICE_RECOGNITION
* unsigned aud_source = PJMEDIA_AUD_DEV_ROUTE_CUSTOM | 6;
* pjmedia_aud_param_set_cap(&param, PJMEDIA_AUD_DEV_CAP_INPUT_SOURCE,
* &aud_source);
*/
PJMEDIA_AUD_DEV_ROUTE_CUSTOM = 128
} pjmedia_aud_dev_route;
/**
* Device information structure returned by #pjmedia_aud_dev_get_info().
*/
typedef struct pjmedia_aud_dev_info
{
/**
* The device name
*/
char name[PJMEDIA_AUD_DEV_INFO_NAME_LEN];
/**
* Maximum number of input channels supported by this device. If the
* value is zero, the device does not support input operation (i.e.
* it is a playback only device).
*/
unsigned input_count;
/**
* Maximum number of output channels supported by this device. If the
* value is zero, the device does not support output operation (i.e.
* it is an input only device).
*/
unsigned output_count;
/**
* Default sampling rate.
*/
unsigned default_samples_per_sec;
/**
* The underlying driver name
*/
char driver[32];
/**
* Device capabilities, as bitmask combination of #pjmedia_aud_dev_cap.
*/
unsigned caps;
/**
* Supported audio device routes/sources, as bitmask combination of
* #pjmedia_aud_dev_route. The value may be zero if the device
* does not support changing audio routes/sources.
*/
unsigned routes;
/**
* Number of audio formats supported by this device. The value may be
* zero if the device does not support non-PCM format.
*/
unsigned ext_fmt_cnt;
/**
* Array of supported extended audio formats
*/
pjmedia_format ext_fmt[8];
} pjmedia_aud_dev_info;
/**
* This callback is called by player stream when it needs additional data
* to be played by the device. Application must fill in the whole of output
* buffer with audio samples.
*
* The frame argument contains the following values:
* - timestamp Playback timestamp, in samples.
* - buf Buffer to be filled out by application.
* - size The size requested in bytes, which will be equal to
* the size of one whole packet.
*
* @param user_data User data associated with the stream.
* @param frame Audio frame, which buffer is to be filled in by
* the application.
*
* @return Returning non-PJ_SUCCESS will cause the audio stream
* to stop
*/
typedef pj_status_t (*pjmedia_aud_play_cb)(void *user_data,
pjmedia_frame *frame);
/**
* This callback is called by recorder stream when it has captured the whole
* packet worth of audio samples.
*
* @param user_data User data associated with the stream.
* @param frame Captured frame.
*
* @return Returning non-PJ_SUCCESS will cause the audio stream
* to stop
*/
typedef pj_status_t (*pjmedia_aud_rec_cb)(void *user_data,
pjmedia_frame *frame);
/**
* This structure specifies the parameters to open the audio stream.
*/
typedef struct pjmedia_aud_param
{
/**
* The audio direction. This setting is mandatory.
*/
pjmedia_dir dir;
/**
* The audio recorder device ID. This setting is mandatory if the audio
* direction includes input/capture direction.
*/
pjmedia_aud_dev_index rec_id;
/**
* The audio playback device ID. This setting is mandatory if the audio
* direction includes output/playback direction.
*/
pjmedia_aud_dev_index play_id;
/**
* Clock rate/sampling rate. This setting is mandatory.
*/
unsigned clock_rate;
/**
* Number of channels. This setting is mandatory.
*/
unsigned channel_count;
/**
* Number of samples per frame. This setting is mandatory.
*/
unsigned samples_per_frame;
/**
* Number of bits per sample. This setting is mandatory.
*/
unsigned bits_per_sample;
/**
* This flags specifies which of the optional settings are valid in this
* structure. The flags is bitmask combination of pjmedia_aud_dev_cap.
*/
unsigned flags;
/**
* Set the audio format. This setting is optional, and will only be used
* if PJMEDIA_AUD_DEV_CAP_EXT_FORMAT is set in the flags.
*/
pjmedia_format ext_fmt;
/**
* Input latency, in milliseconds. This setting is optional, and will
* only be used if PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY is set in the flags.
*/
unsigned input_latency_ms;
/**
* Input latency, in milliseconds. This setting is optional, and will
* only be used if PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY is set in the flags.
*/
unsigned output_latency_ms;
/**
* Input volume setting, in percent. This setting is optional, and will
* only be used if PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING is set in
* the flags.
*/
unsigned input_vol;
/**
* Output volume setting, in percent. This setting is optional, and will
* only be used if PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING is set in
* the flags.
*/
unsigned output_vol;
/**
* Set the audio input route/source. This setting is optional, and
* will only be used if PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE/
* PJMEDIA_AUD_DEV_CAP_INPUT_SOURCE is set in the flags.
*/
pjmedia_aud_dev_route input_route;
/**
* Set the audio output route. This setting is optional, and will only be
* used if PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE is set in the flags.
*/
pjmedia_aud_dev_route output_route;
/**
* Enable/disable echo canceller, if the device supports it. This setting
* is optional, and will only be used if PJMEDIA_AUD_DEV_CAP_EC is set in
* the flags.
*/
pj_bool_t ec_enabled;
/**
* Set echo canceller tail length in milliseconds, if the device supports
* it. This setting is optional, and will only be used if
* PJMEDIA_AUD_DEV_CAP_EC_TAIL is set in the flags.
*/
unsigned ec_tail_ms;
/**
* Enable/disable PLC. This setting is optional, and will only be used
* if PJMEDIA_AUD_DEV_CAP_PLC is set in the flags.
*/
pj_bool_t plc_enabled;
/**
* Enable/disable CNG. This setting is optional, and will only be used
* if PJMEDIA_AUD_DEV_CAP_CNG is set in the flags.
*/
pj_bool_t cng_enabled;
/**
* Enable/disable VAD. This setting is optional, and will only be used
* if PJMEDIA_AUD_DEV_CAP_VAD is set in the flags.
*/
pj_bool_t vad_enabled;
} pjmedia_aud_param;
/**
* Get the audio subsystem.
*
* @return The audio subsystem.
*/
PJ_DECL(pjmedia_aud_subsys*) pjmedia_get_aud_subsys(void);
/**
* Initialize the audio driver.
*
* @param drv_idx The index of the audio driver.
* @param refresh Specify non-zero to refresh the audio driver.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_driver_init(unsigned drv_idx,
pj_bool_t refresh);
/**
* Deinitialize the audio driver.
*
* @param drv_idx The index of the audio driver.
*/
PJ_DECL(void) pjmedia_aud_driver_deinit(unsigned drv_idx);
/**
* Get string info for the specified capability.
*
* @param cap The capability ID.
* @param p_desc Optional pointer which will be filled with longer
* description about the capability.
*
* @return Capability name.
*/
PJ_DECL(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
const char **p_desc);
/**
* Set a capability field value in #pjmedia_aud_param structure. This will
* also set the flags field for the specified capability in the structure.
*
* @param param The structure.
* @param cap The audio capability which value is to be set.
* @param pval Pointer to value. Please see the type of value to
* be supplied in the pjmedia_aud_dev_cap documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_param_set_cap(pjmedia_aud_param *param,
pjmedia_aud_dev_cap cap,
const void *pval);
/**
* Get a capability field value from #pjmedia_aud_param structure. This
* function will return PJMEDIA_EAUD_INVCAP error if the flag for that
* capability is not set in the flags field in the structure.
*
* @param param The structure.
* @param cap The audio capability which value is to be retrieved.
* @param pval Pointer to value. Please see the type of value to
* be supplied in the pjmedia_aud_dev_cap documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_param_get_cap(const pjmedia_aud_param *param,
pjmedia_aud_dev_cap cap,
void *pval);
/**
* Refresh the list of sound devices installed in the system. This function
* will only refresh the list of audio device so all active audio streams will
* be unaffected. After refreshing the device list, application MUST make sure
* to update all index references to audio devices (i.e. all variables of type
* pjmedia_aud_dev_index) before calling any function that accepts audio device
* index as its parameter.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_dev_refresh(void);
/**
* Get the number of sound devices installed in the system.
*
* @return The number of sound devices installed in the system.
*/
PJ_DECL(unsigned) pjmedia_aud_dev_count(void);
/**
* Get device information.
*
* @param id The audio device ID.
* @param info The device information which will be filled in by this
* function once it returns successfully.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id,
pjmedia_aud_dev_info *info);
/**
* Lookup device index based on the driver and device name.
*
* @param drv_name The driver name.
* @param dev_name The device name.
* @param id Pointer to store the returned device ID.
*
* @return PJ_SUCCESS if the device can be found.
*/
PJ_DECL(pj_status_t) pjmedia_aud_dev_lookup(const char *drv_name,
const char *dev_name,
pjmedia_aud_dev_index *id);
/**
* Initialize the audio device parameters with default values for the
* specified device.
*
* @param id The audio device ID.
* @param param The audio device parameters which will be initialized
* by this function once it returns successfully.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
pjmedia_aud_param *param);
/**
* Open audio stream object using the specified parameters.
*
* @param param Sound device parameters to be used for the stream.
* @param rec_cb Callback to be called on every input frame captured.
* @param play_cb Callback to be called everytime the sound device needs
* audio frames to be played back.
* @param user_data Arbitrary user data, which will be given back in the
* callbacks.
* @param p_strm Pointer to receive the audio stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
pjmedia_aud_stream **p_strm);
/**
* Get the running parameters for the specified audio stream.
*
* @param strm The audio stream.
* @param param Audio stream parameters to be filled in by this
* function once it returns successfully.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
pjmedia_aud_param *param);
/**
* Get the value of a specific capability of the audio stream.
*
* @param strm The audio stream.
* @param cap The audio capability which value is to be retrieved.
* @param value Pointer to value to be filled in by this function
* once it returns successfully. Please see the type
* of value to be supplied in the pjmedia_aud_dev_cap
* documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_get_cap(pjmedia_aud_stream *strm,
pjmedia_aud_dev_cap cap,
void *value);
/**
* Set the value of a specific capability of the audio stream.
*
* @param strm The audio stream.
* @param cap The audio capability which value is to be set.
* @param value Pointer to value. Please see the type of value to
* be supplied in the pjmedia_aud_dev_cap documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_set_cap(pjmedia_aud_stream *strm,
pjmedia_aud_dev_cap cap,
const void *value);
/**
* Start the stream.
*
* @param strm The audio stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm);
/**
* Stop the stream.
*
* @param strm The audio stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm);
/**
* Destroy the stream.
*
* @param strm The audio stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm);
/**
* @}
*/
PJ_END_DECL
#endif /* __PJMEDIA_AUDIO_DEV_H__ */

View File

@ -952,6 +952,75 @@
#endif
/**
* Maximum number of SRTP cryptos.
*
* Default: 16
*/
#ifndef PJMEDIA_SRTP_MAX_CRYPTOS
# define PJMEDIA_SRTP_MAX_CRYPTOS 16
#endif
/**
* Enable AES_CM_256 cryptos in SRTP.
* Default: enabled.
*/
#ifndef PJMEDIA_SRTP_HAS_AES_CM_256
# define PJMEDIA_SRTP_HAS_AES_CM_256 1
#endif
/**
* Enable AES_CM_192 cryptos in SRTP.
* It was reported that this crypto only works among libsrtp backends,
* so we recommend to disable this.
*
* To enable this, you would require OpenSSL which supports it.
* See https://trac.pjsip.org/repos/ticket/1943 for more info.
*
* Default: disabled.
*/
#ifndef PJMEDIA_SRTP_HAS_AES_CM_192
# define PJMEDIA_SRTP_HAS_AES_CM_192 0
#endif
/**
* Enable AES_CM_128 cryptos in SRTP.
* Default: enabled.
*/
#ifndef PJMEDIA_SRTP_HAS_AES_CM_128
# define PJMEDIA_SRTP_HAS_AES_CM_128 1
#endif
/**
* Enable AES_GCM_256 cryptos in SRTP.
*
* To enable this, you would require OpenSSL which supports it.
* See https://trac.pjsip.org/repos/ticket/1943 for more info.
*
* Default: disabled.
*/
#ifndef PJMEDIA_SRTP_HAS_AES_GCM_256
# define PJMEDIA_SRTP_HAS_AES_GCM_256 0
#endif
/**
* Enable AES_GCM_128 cryptos in SRTP.
*
* To enable this, you would require OpenSSL which supports it.
* See https://trac.pjsip.org/repos/ticket/1943 for more info.
*
* Default: disabled.
*/
#ifndef PJMEDIA_SRTP_HAS_AES_GCM_128
# define PJMEDIA_SRTP_HAS_AES_GCM_128 0
#endif
/**
* Let the library handle libsrtp initialization and deinitialization.
* Application may want to disable this and manually perform libsrtp
@ -972,6 +1041,7 @@
* See:
* - G.722 : RFC 3551 4.5.2
* - MPEG audio : RFC 3551 4.5.13 & RFC 3119
* - OPUS : RFC 7587
*
* Also when this feature is enabled, some handling will be performed
* to deal with clock rate incompatibilities of some phones.
@ -1139,15 +1209,6 @@
# define PJMEDIA_HAS_LIBAVDEVICE PJMEDIA_HAS_FFMPEG
#endif
/**
* Specify if FFMPEG libavcore is available.
*
* Default: PJMEDIA_HAS_FFMPEG (or detected by configure)
*/
#ifndef PJMEDIA_HAS_LIBAVCORE
# define PJMEDIA_HAS_LIBAVCORE PJMEDIA_HAS_FFMPEG
#endif
/**
* Maximum video planes.
*
@ -1320,6 +1381,7 @@
# endif
#endif
/**
* Specify if libyuv is available.
*
@ -1329,6 +1391,34 @@
# define PJMEDIA_HAS_LIBYUV 0
#endif
/**
* Specify if dtmf flash in RFC 2833 is available.
*/
#ifndef PJMEDIA_HAS_DTMF_FLASH
# define PJMEDIA_HAS_DTMF_FLASH 1
#endif
/**
* Specify the number of keyframe needed to be sent after the stream is
* created. Setting this to 0 will disable it.
*
* Default : 5
*/
#ifndef PJMEDIA_VID_STREAM_START_KEYFRAME_CNT
# define PJMEDIA_VID_STREAM_START_KEYFRAME_CNT 5
#endif
/**
* Specify the interval to send keyframe after the stream is created, in msec.
*
* Default : 1000
*/
#ifndef PJMEDIA_VID_STREAM_START_KEYFRAME_INTERVAL_MSEC
# define PJMEDIA_VID_STREAM_START_KEYFRAME_INTERVAL_MSEC 1000
#endif
/**
* @}
*/

View File

@ -40,6 +40,7 @@
#include <pjmedia/codec.h>
#include <pjmedia/sdp.h>
#include <pjmedia/transport.h>
#include <pjmedia-audiodev/audiodev.h>
PJ_BEGIN_DECL
@ -81,11 +82,51 @@ typedef void (*pjmedia_endpt_exit_callback)(pjmedia_endpt *endpt);
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjmedia_endpt_create( pj_pool_factory *pf,
PJ_DECL(pj_status_t) pjmedia_endpt_create2(pj_pool_factory *pf,
pj_ioqueue_t *ioqueue,
unsigned worker_cnt,
pjmedia_endpt **p_endpt);
/**
* Create an instance of media endpoint and initialize audio subsystem.
*
* @param pf Pool factory, which will be used by the media endpoint
* throughout its lifetime.
* @param ioqueue Optional ioqueue instance to be registered to the
* endpoint. The ioqueue instance is used to poll all RTP
* and RTCP sockets. If this argument is NULL, the
* endpoint will create an internal ioqueue instance.
* @param worker_cnt Specify the number of worker threads to be created
* to poll the ioqueue.
* @param p_endpt Pointer to receive the endpoint instance.
*
* @return PJ_SUCCESS on success.
*/
PJ_INLINE(pj_status_t) pjmedia_endpt_create(pj_pool_factory *pf,
pj_ioqueue_t *ioqueue,
unsigned worker_cnt,
pjmedia_endpt **p_endpt)
{
/* This function is inlined to avoid build problem due to circular
* dependency, i.e: this function prevents pjmedia's dependency on
* pjmedia-audiodev.
*/
pj_status_t status;
/* Sound */
status = pjmedia_aud_subsys_init(pf);
if (status != PJ_SUCCESS)
return status;
status = pjmedia_endpt_create2(pf, ioqueue, worker_cnt, p_endpt);
if (status != PJ_SUCCESS) {
pjmedia_aud_subsys_shutdown();
}
return status;
}
/**
* Destroy media endpoint instance.
*
@ -93,7 +134,25 @@ PJ_DECL(pj_status_t) pjmedia_endpt_create( pj_pool_factory *pf,
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjmedia_endpt_destroy(pjmedia_endpt *endpt);
PJ_DECL(pj_status_t) pjmedia_endpt_destroy2(pjmedia_endpt *endpt);
/**
* Destroy media endpoint instance and shutdown audio subsystem.
*
* @param endpt Media endpoint instance.
*
* @return PJ_SUCCESS on success.
*/
PJ_INLINE(pj_status_t) pjmedia_endpt_destroy(pjmedia_endpt *endpt)
{
/* This function is inlined to avoid build problem due to circular
* dependency, i.e: this function prevents pjmedia's dependency on
* pjmedia-audiodev.
*/
pj_status_t status = pjmedia_endpt_destroy2(endpt);
pjmedia_aud_subsys_shutdown();
return status;
}
/**
* Change the value of a flag.

View File

@ -406,7 +406,11 @@ PJ_BEGIN_DECL
* Invalid or bad format
*/
#define PJMEDIA_EBADFMT (PJMEDIA_ERRNO_START+108) /* 220108 */
/**
* @hideinitializer
* Unsupported media type.
*/
#define PJMEDIA_EUNSUPMEDIATYPE (PJMEDIA_ERRNO_START+109) /* 220109 */
/************************************************************
* RTP SESSION ERRORS

View File

@ -113,7 +113,7 @@ typedef struct pjmedia_rtp_hdr pjmedia_rtp_hdr;
/**
* RTP extendsion header.
* RTP extension header.
*/
struct pjmedia_rtp_ext_hdr
{
@ -126,6 +126,21 @@ struct pjmedia_rtp_ext_hdr
*/
typedef struct pjmedia_rtp_ext_hdr pjmedia_rtp_ext_hdr;
/**
* This will contain the RTP header decode output.
*/
struct pjmedia_rtp_dec_hdr
{
/* RTP extension header output decode */
pjmedia_rtp_ext_hdr *ext_hdr;
pj_uint32_t *ext;
unsigned ext_len;
};
/**
* @see pjmedia_rtp_dec_hdr
*/
typedef struct pjmedia_rtp_dec_hdr pjmedia_rtp_dec_hdr;
#pragma pack(1)
@ -321,6 +336,38 @@ PJ_DECL(pj_status_t) pjmedia_rtp_decode_rtp( pjmedia_rtp_session *ses,
const void **payload,
unsigned *payloadlen);
/**
* This function decodes incoming packet into RTP header and payload.
* The decode function is guaranteed to point the payload to the correct
* position regardless of any options present in the RTP packet.
*
* Note that this function does not modify the returned RTP header to
* host byte order.
*
* @param ses The session.
* @param pkt The received RTP packet.
* @param pkt_len The length of the packet.
* @param hdr Upon return will point to the location of the RTP
* header inside the packet. Note that the RTP header
* will be given back as is, meaning that the fields
* will be in network byte order.
* @param dec_hdr Upon return will point to the location of the
* additional RTP header inside the packet, if any.
* @param payload Upon return will point to the location of the
* payload inside the packet.
* @param payloadlen Upon return will indicate the size of the payload.
*
* @return PJ_SUCCESS if successfull.
*/
PJ_DECL(pj_status_t) pjmedia_rtp_decode_rtp2(
pjmedia_rtp_session *ses,
const void *pkt, int pkt_len,
const pjmedia_rtp_hdr **hdr,
pjmedia_rtp_dec_hdr *dec_hdr,
const void **payload,
unsigned *payloadlen);
/**
* Call this function everytime an RTP packet is received to check whether
* the packet can be received and to let the RTP session performs its internal

View File

@ -140,15 +140,26 @@ typedef pj_status_t (*pjmedia_snd_rec_cb)(/* in */ void *user_data,
*
* @return Zero on success.
*/
PJ_DECL(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory);
PJ_INLINE(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
{
/* This function is inlined to avoid pjmedia's dependency on
* pjmedia-audiodev.
*/
return pjmedia_aud_subsys_init(factory);
}
/**
* Get the number of devices detected by the library.
*
* @return Number of devices.
*/
PJ_DECL(int) pjmedia_snd_get_dev_count(void);
PJ_INLINE(int) pjmedia_snd_get_dev_count(void)
{
/* This function is inlined to avoid pjmedia's dependency on
* pjmedia-audiodev.
*/
return (int)pjmedia_aud_dev_count();
}
/**
@ -323,7 +334,13 @@ PJ_DECL(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream);
*
* @return Zero on success.
*/
PJ_DECL(pj_status_t) pjmedia_snd_deinit(void);
PJ_INLINE(pj_status_t) pjmedia_snd_deinit(void)
{
/* This function is inlined to avoid pjmedia's dependency on
* pjmedia-audiodev.
*/
return pjmedia_aud_subsys_shutdown();
}

View File

@ -33,6 +33,7 @@
#include <pjmedia/rtcp.h>
#include <pjmedia/transport.h>
#include <pjmedia/vid_codec.h>
#include <pjmedia/stream_common.h>
#include <pj/sock.h>
PJ_BEGIN_DECL
@ -342,7 +343,8 @@ PJ_DECL(pj_status_t) pjmedia_stream_resume(pjmedia_stream *stream,
*
* @param stream The media stream.
* @param ascii_digit String containing digits to be sent to remote as
* described on RFC 2833 section 3.10. Character 'R' is
* described on RFC 2833 section 3.10.
* If PJMEDIA_HAS_DTMF_FLASH is enabled, character 'R' is
* used to represent the event type 16 (flash) as stated
* in RFC 4730.
* Currently the maximum number of digits are 32.
@ -429,6 +431,25 @@ pjmedia_stream_send_rtcp_sdes( pjmedia_stream *stream );
PJ_DECL(pj_status_t)
pjmedia_stream_send_rtcp_bye( pjmedia_stream *stream );
/**
* Get the RTP session information of the media stream. This function can be
* useful for app with custom media transport to inject/filter some
* outgoing/incoming proprietary packets into normal audio RTP traffics.
* This will return the original pointer to the internal states of the stream,
* and generally it is not advisable for app to modify them.
*
* @param stream The media stream.
*
* @param session_info The stream session info.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t)
pjmedia_stream_get_rtp_session_info(pjmedia_stream *stream,
pjmedia_stream_rtp_sess_info *session_info);
/**
* @}
*/

View File

@ -27,10 +27,36 @@
#include <pjmedia/codec.h>
#include <pjmedia/sdp.h>
#include <pjmedia/rtp.h>
#include <pjmedia/rtcp.h>
PJ_BEGIN_DECL
/**
* This structure describes rtp/rtcp session information of the media stream.
*/
typedef struct pjmedia_stream_rtp_sess_info
{
/**
* The decode RTP session.
*/
const pjmedia_rtp_session *rx_rtp;
/**
* The encode RTP session.
*/
const pjmedia_rtp_session *tx_rtp;
/**
* The decode RTCP session.
*/
const pjmedia_rtcp_session *rtcp;
} pjmedia_stream_rtp_sess_info;
/**
* This is internal function for parsing SDP format parameter of specific
* format or payload type, used by stream in generating stream info from SDP.

View File

@ -240,6 +240,11 @@ typedef struct pjmedia_transport pjmedia_transport;
*/
typedef struct pjmedia_transport_info pjmedia_transport_info;
/**
* Forward declaration for media transport attach param.
*/
typedef struct pjmedia_transport_attach_param pjmedia_transport_attach_param;
/**
* This enumeration specifies the general behaviour of media processing
*/
@ -303,7 +308,8 @@ struct pjmedia_transport_op
* This function is called by the stream when the transport is about
* to be used by the stream for the first time, and it tells the transport
* about remote RTP address to send the packet and some callbacks to be
* called for incoming packets.
* called for incoming packets. This function exists for backwards
* compatibility. Transports should implement attach2 instead.
*
* Application should call #pjmedia_transport_attach() instead of
* calling this function directly.
@ -433,6 +439,18 @@ struct pjmedia_transport_op
* calling this function directly.
*/
pj_status_t (*destroy)(pjmedia_transport *tp);
/**
* This function is called by the stream when the transport is about
* to be used by the stream for the first time, and it tells the transport
* about remote RTP address to send the packet and some callbacks to be
* called for incoming packets.
*
* Application should call #pjmedia_transport_attach2() instead of
* calling this function directly.
*/
pj_status_t (*attach2)(pjmedia_transport *tp,
pjmedia_transport_attach_param *att_param);
};
@ -546,6 +564,56 @@ struct pjmedia_transport_info
};
/**
* This structure describes the data passed when calling
* #pjmedia_transport_attach2().
*/
struct pjmedia_transport_attach_param
{
/**
* The media stream.
*/
void *stream;
/**
* Indicate the stream type, either it's audio (PJMEDIA_TYPE_AUDIO)
* or video (PJMEDIA_TYPE_VIDEO).
*/
pjmedia_type media_type;
/**
* Remote RTP address to send RTP packet to.
*/
pj_sockaddr rem_addr;
/**
* Optional remote RTCP address. If the argument is NULL
* or if the address is zero, the RTCP address will be
* calculated from the RTP address (which is RTP port plus one).
*/
pj_sockaddr rem_rtcp;
/**
* Length of the remote address.
*/
unsigned addr_len;
/**
* Arbitrary user data to be set when the callbacks are called.
*/
void *user_data;
/**
* Callback to be called when RTP packet is received on the transport.
*/
void (*rtp_cb)(void *user_data, void *pkt, pj_ssize_t);
/**
* Callback to be called when RTCP packet is received on the transport.
*/
void (*rtcp_cb)(void *user_data, void *pkt, pj_ssize_t);
};
/**
* Initialize transport info.
*
@ -602,6 +670,32 @@ PJ_INLINE(void*) pjmedia_transport_info_get_spc_info(
}
/**
* Attach callbacks to be called on receipt of incoming RTP/RTCP packets.
* This is just a simple wrapper which calls <tt>attach2()</tt> member of
* the transport if it is implemented, otherwise it calls <tt>attach()</tt>
* member of the transport.
*
* @param tp The media transport.
* @param att_param The transport attach param.
*
* @return PJ_SUCCESS on success, or the appropriate error code.
*/
PJ_INLINE(pj_status_t) pjmedia_transport_attach2(pjmedia_transport *tp,
pjmedia_transport_attach_param *att_param)
{
if (tp->op->attach2) {
return tp->op->attach2(tp, att_param);
} else {
return tp->op->attach(tp, att_param->user_data,
(pj_sockaddr_t*)&att_param->rem_addr,
(pj_sockaddr_t*)&att_param->rem_rtcp,
att_param->addr_len, att_param->rtp_cb,
att_param->rtcp_cb);
}
}
/**
* 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

View File

@ -155,7 +155,7 @@ typedef struct pjmedia_srtp_setting
/**
* Specify individual crypto suite setting.
*/
pjmedia_srtp_crypto crypto[8];
pjmedia_srtp_crypto crypto[PJMEDIA_SRTP_MAX_CRYPTOS];
} pjmedia_srtp_setting;

View File

@ -31,6 +31,7 @@
#include <pjmedia/rtcp.h>
#include <pjmedia/transport.h>
#include <pjmedia/vid_codec.h>
#include <pjmedia/stream_common.h>
#include <pj/sock.h>
PJ_BEGIN_DECL
@ -117,6 +118,28 @@ typedef struct pjmedia_vid_stream_rc_config
} pjmedia_vid_stream_rc_config;
/**
* Structure of configuration settings for video stream sending keyframe
* after it is created.
*/
typedef struct pjmedia_vid_stream_sk_config
{
/**
* The number of keyframe to be sent after the stream is created.
*
* Default: PJMEDIA_VID_STREAM_START_KEYFRAME_CNT
*/
unsigned count;
/**
* The keyframe sending interval after the stream is created.
*
* Default: PJMEDIA_VID_STREAM_START_KEYFRAME_INTERVAL_MSEC
*/
unsigned interval;
} pjmedia_vid_stream_sk_config;
/**
* This structure describes video stream information. Each video stream
@ -165,6 +188,9 @@ typedef struct pjmedia_vid_stream_info
pjmedia_vid_stream_rc_config rc_cfg;
/**< Stream send rate control settings. */
pjmedia_vid_stream_sk_config sk_cfg;
/**< Stream send keyframe settings. */
} pjmedia_vid_stream_info;
@ -201,6 +227,14 @@ pjmedia_vid_stream_info_from_sdp(pjmedia_vid_stream_info *si,
PJ_DECL(void)
pjmedia_vid_stream_rc_config_default(pjmedia_vid_stream_rc_config *cfg);
/**
* Initialize the video stream send keyframe with default settings.
*
* @param cfg Video stream send keyframe structure to be initialized.
*/
PJ_DECL(void)
pjmedia_vid_stream_sk_config_default(pjmedia_vid_stream_sk_config *cfg);
/*
* Opaque declaration for video stream.
@ -412,6 +446,23 @@ PJ_DECL(pj_status_t) pjmedia_vid_stream_send_rtcp_sdes(
PJ_DECL(pj_status_t) pjmedia_vid_stream_send_rtcp_bye(
pjmedia_vid_stream *stream);
/**
* Get the RTP session information of the video media stream. This function
* can be useful for app with custom media transport to inject/filter some
* outgoing/incoming proprietary packets into normal video RTP traffics.
* This will return the original pointer to the internal states of the stream,
* and generally it is not advisable for app to modify them.
*
* @param stream The video media stream.
*
* @param session_info The stream session info.
*
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t)
pjmedia_vid_stream_get_rtp_session_info(pjmedia_vid_stream *stream,
pjmedia_stream_rtp_sess_info *session_info);
/**
* @}

View File

@ -0,0 +1,824 @@
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __PJMEDIA_VIDEO_DEV_H__
#define __PJMEDIA_VIDEO_DEV_H__
/**
* @file videodev.h
* @brief Video device API.
*/
#include <pjmedia-videodev/config.h>
#include <pjmedia-videodev/errno.h>
#include <pjmedia/event.h>
#include <pjmedia/frame.h>
#include <pjmedia/format.h>
#include <pj/pool.h>
PJ_BEGIN_DECL
/**
* @defgroup video_device_reference Video Device API Reference
* @ingroup video_device_api
* @brief API Reference
* @{
*/
/**
* Type for device index.
*/
typedef pj_int32_t pjmedia_vid_dev_index;
/**
* Enumeration of window handle type.
*/
typedef enum pjmedia_vid_dev_hwnd_type
{
/**
* Type none.
*/
PJMEDIA_VID_DEV_HWND_TYPE_NONE,
/**
* Native window handle on Windows.
*/
PJMEDIA_VID_DEV_HWND_TYPE_WINDOWS,
/**
* Native view on iOS.
*/
PJMEDIA_VID_DEV_HWND_TYPE_IOS,
/**
* Native window handle on Android.
*/
PJMEDIA_VID_DEV_HWND_TYPE_ANDROID
} pjmedia_vid_dev_hwnd_type;
/**
* Type for window handle.
*/
typedef struct pjmedia_vid_dev_hwnd
{
/**
* The window handle type.
*/
pjmedia_vid_dev_hwnd_type type;
/**
* The window handle.
*/
union
{
struct {
void *hwnd; /**< HWND */
} win;
struct {
void *window; /**< Window */
void *display; /**< Display */
} x11;
struct {
void *window; /**< Window */
} cocoa;
struct {
void *window; /**< Window */
} ios;
struct {
void *window; /**< Native window */
} android;
void *window;
} info;
} pjmedia_vid_dev_hwnd;
/**
* Parameter for switching device with PJMEDIA_VID_DEV_CAP_SWITCH capability.
* Initialize this with pjmedia_vid_dev_switch_param_default()
*/
typedef struct pjmedia_vid_dev_switch_param
{
/**
* Target device ID to switch to. Once the switching is successful, the
* video stream will use this device and the old device will be closed.
*/
pjmedia_vid_dev_index target_id;
} pjmedia_vid_dev_switch_param;
/**
* Enumeration of window flags.
*/
typedef enum pjmedia_vid_dev_wnd_flag
{
/**
* Window with border.
*/
PJMEDIA_VID_DEV_WND_BORDER = 1,
/**
* Window can be resized.
*/
PJMEDIA_VID_DEV_WND_RESIZABLE = 2
} pjmedia_vid_dev_wnd_flag;
/**
* Device index constants.
*/
enum pjmedia_vid_dev_std_index
{
/**
* Constant to denote default capture device
*/
PJMEDIA_VID_DEFAULT_CAPTURE_DEV = -1,
/**
* Constant to denote default render device
*/
PJMEDIA_VID_DEFAULT_RENDER_DEV = -2,
/**
* Constant to denote invalid device index.
*/
PJMEDIA_VID_INVALID_DEV = -3
};
/**
* This enumeration identifies various video device capabilities. These video
* capabilities indicates what features are supported by the underlying
* video device implementation.
*
* Applications get these capabilities in the #pjmedia_vid_dev_info structure.
*
* Application can also set the specific features/capabilities when opening
* the video stream by setting the \a flags member of #pjmedia_vid_dev_param
* structure.
*
* Once video stream is running, application can also retrieve or set some
* specific video capability, by using #pjmedia_vid_dev_stream_get_cap() and
* #pjmedia_vid_dev_stream_set_cap() and specifying the desired capability. The
* value of the capability is specified as pointer, and application needs to
* supply the pointer with the correct value, according to the documentation
* of each of the capability.
*/
typedef enum pjmedia_vid_dev_cap
{
/**
* Support for video formats. The value of this capability
* is represented by #pjmedia_format structure.
*/
PJMEDIA_VID_DEV_CAP_FORMAT = 1,
/**
* Support for video input scaling
*/
PJMEDIA_VID_DEV_CAP_INPUT_SCALE = 2,
/**
* Support for returning the native window handle of the video window.
* For renderer, this means the window handle of the renderer window,
* while for capture, this means the window handle of the native preview,
* only if the device supports PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW
* capability.
*
* The value of this capability is pointer to pjmedia_vid_dev_hwnd
* structure.
*/
PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW = 4,
/**
* Support for resizing video output. This capability SHOULD be
* implemented by renderer, to alter the video output dimension on the fly.
* Value is pjmedia_rect_size.
*/
PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE = 8,
/**
* Support for setting the video window's position.
* Value is pjmedia_coord specifying the window's new coordinate.
*/
PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION = 16,
/**
* Support for setting the video output's visibility.
* The value of this capability is a pj_bool_t containing boolean
* PJ_TRUE or PJ_FALSE.
*/
PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE = 32,
/**
* Support for native preview capability in capture devices. Value is
* pj_bool_t. With native preview, capture device can be instructed to
* show or hide a preview window showing video directly from the camera
* by setting this capability to PJ_TRUE or PJ_FALSE. Once the preview
* is started, application may use PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW
* capability to query the video window.
*
* The value of this capability is a pj_bool_t containing boolean
* PJ_TRUE or PJ_FALSE.
*/
PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW = 64,
/**
* Support for changing video orientation. For a renderer device,
* changing video orientation in will potentially affect the size of
* render window, i.e: width and height swap. For a capture device,
* the video will be rotated but the size of the video frame
* will stay the same, so the video may be resized or stretched.
*
* The value of this capability is pjmedia_orient.
*/
PJMEDIA_VID_DEV_CAP_ORIENTATION = 128,
/**
* Support for fast switching to another device. A video stream with this
* capability allows replacing of its underlying device with another
* device, saving the user from opening a new video stream and gets a much
* faster and smoother switching action.
*
* Note that even when this capability is supported by a device, it may
* not be able to switch to arbitrary device. Application must always
* check the return value of the operation to verify that switching has
* occurred.
*
* This capability is currently write-only (i.e. set-only).
*
* The value of this capability is pointer to pjmedia_vid_dev_switch_param
* structure.
*/
PJMEDIA_VID_DEV_CAP_SWITCH = 256,
/**
* Support for setting the output video window's flags.
* The value of this capability is a bitmask combination of
* #pjmedia_vid_dev_wnd_flag.
*/
PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS = 512,
/**
* End of standard capability
*/
PJMEDIA_VID_DEV_CAP_MAX = 16384
} pjmedia_vid_dev_cap;
/**
* Device information structure returned by #pjmedia_vid_dev_get_info().
*/
typedef struct pjmedia_vid_dev_info
{
/** The device ID */
pjmedia_vid_dev_index id;
/** The device name */
char name[64];
/** The underlying driver name */
char driver[32];
/**
* The supported direction of the video device, i.e. whether it supports
* capture only, render only, or both.
*/
pjmedia_dir dir;
/**
* Specify whether the device supports callback. Devices that implement
* "active interface" will actively call the callbacks to give or ask for
* video frames. If the device doesn't support callback, application
* must actively request or give video frames from/to the device by using
* pjmedia_vid_dev_stream_get_frame()/pjmedia_vid_dev_stream_put_frame().
*/
pj_bool_t has_callback;
/** Device capabilities, as bitmask combination of #pjmedia_vid_dev_cap */
unsigned caps;
/** Number of video formats supported by this device */
unsigned fmt_cnt;
/**
* Array of supported video formats. Some fields in each supported video
* format may be set to zero or of "unknown" value, to indicate that the
* value is unknown or should be ignored. When these value are not set
* to zero, it indicates that the exact format combination is being used.
*/
pjmedia_format fmt[PJMEDIA_VID_DEV_INFO_FMT_CNT];
} pjmedia_vid_dev_info;
/** Forward declaration for pjmedia_vid_dev_stream */
typedef struct pjmedia_vid_dev_stream pjmedia_vid_dev_stream;
typedef struct pjmedia_vid_dev_cb
{
/**
* This callback is called by capturer stream when it has captured the
* whole packet worth of video samples.
*
* @param stream The video stream.
* @param user_data User data associated with the stream.
* @param frame Captured frame.
*
* @return Returning non-PJ_SUCCESS will cause the video
* stream to stop
*/
pj_status_t (*capture_cb)(pjmedia_vid_dev_stream *stream,
void *user_data,
pjmedia_frame *frame);
/**
* This callback is called by renderer stream when it needs additional
* data to be rendered by the device. Application must fill in the whole
* of output buffer with video samples.
*
* The frame argument contains the following values:
* - timestamp Rendering timestamp, in samples.
* - buf Buffer to be filled out by application.
* - size The size requested in bytes, which will be equal
* to the size of one whole packet.
*
* @param stream The video stream.
* @param user_data User data associated with the stream.
* @param frame Video frame, which buffer is to be filled in by
* the application.
*
* @return Returning non-PJ_SUCCESS will cause the video
* stream to stop
*/
pj_status_t (*render_cb)(pjmedia_vid_dev_stream *stream,
void *user_data,
pjmedia_frame *frame);
} pjmedia_vid_dev_cb;
/**
* This structure specifies the parameters to open the video stream.
*/
typedef struct pjmedia_vid_dev_param
{
/**
* The video direction. This setting is mandatory.
*/
pjmedia_dir dir;
/**
* The video capture device ID. This setting is mandatory if the video
* direction includes input/capture direction.
*/
pjmedia_vid_dev_index cap_id;
/**
* The video render device ID. This setting is mandatory if the video
* direction includes output/render direction.
*/
pjmedia_vid_dev_index rend_id;
/**
* Video clock rate. This setting is mandatory if the video
* direction includes input/capture direction
*/
unsigned clock_rate;
/**
* Video frame rate. This setting is mandatory if the video
* direction includes input/capture direction
*/
// pjmedia_ratio frame_rate;
/**
* This flags specifies which of the optional settings are valid in this
* structure. The flags is bitmask combination of pjmedia_vid_dev_cap.
*/
unsigned flags;
/**
* Set the video format. This setting is mandatory.
*/
pjmedia_format fmt;
/**
* Window for the renderer to display the video. This setting is optional,
* and will only be used if PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW is set in
* the flags.
*/
pjmedia_vid_dev_hwnd window;
/**
* Video display size. This setting is optional, and will only be used
* if PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE is set in the flags.
*/
pjmedia_rect_size disp_size;
/**
* Video window position. This setting is optional, and will only be used
* if PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION is set in the flags.
*/
pjmedia_coord window_pos;
/**
* Video window's visibility. This setting is optional, and will only be
* used if PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE is set in the flags.
*/
pj_bool_t window_hide;
/**
* Enable built-in preview. This setting is optional and is only used
* if PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW capability is supported and
* set in the flags.
*/
pj_bool_t native_preview;
/**
* Video orientation. This setting is optional and is only used if
* PJMEDIA_VID_DEV_CAP_ORIENTATION capability is supported and is
* set in the flags.
*/
pjmedia_orient orient;
/**
* Video window flags. This setting is optional, and will only be used
* if PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS is set in the flags.
*/
unsigned window_flags;
} pjmedia_vid_dev_param;
/** Forward declaration for video device factory */
typedef struct pjmedia_vid_dev_factory pjmedia_vid_dev_factory;
/* typedef for factory creation function */
typedef pjmedia_vid_dev_factory*
(*pjmedia_vid_dev_factory_create_func_ptr)(pj_pool_factory*);
/* Video driver structure */
typedef struct pjmedia_vid_driver
{
pjmedia_vid_dev_factory_create_func_ptr create; /* Creation function */
pjmedia_vid_dev_factory *f; /* Factory instance */
char name[32]; /* Driver name */
unsigned dev_cnt; /* Number of devices */
unsigned start_idx; /* Start index in global list */
int cap_dev_idx; /* Default capture device. */
int rend_dev_idx; /* Default render device */
} pjmedia_vid_driver;
/* The video device subsystem */
typedef struct pjmedia_vid_subsys
{
unsigned init_count; /* How many times init() is called */
pj_pool_factory *pf; /* The pool factory. */
unsigned drv_cnt; /* Number of drivers. */
pjmedia_vid_driver drv[PJMEDIA_VID_DEV_MAX_DRIVERS];/* Array of drivers.*/
unsigned dev_cnt; /* Total number of devices. */
pj_uint32_t dev_list[PJMEDIA_VID_DEV_MAX_DEVS];/* Array of devIDs*/
} pjmedia_vid_subsys;
/**
* Get the video subsystem.
*
* @return The video subsystem.
*/
PJ_DECL(pjmedia_vid_subsys*) pjmedia_get_vid_subsys(void);
/**
* Initialize the video driver.
*
* @param drv_idx The index of the video driver.
* @param refresh Specify non-zero to refresh the video driver.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_driver_init(unsigned drv_idx,
pj_bool_t refresh);
/**
* Deinitialize the video driver.
*
* @param drv_idx The index of the video driver.
*/
PJ_DECL(void) pjmedia_vid_driver_deinit(unsigned drv_idx);
/**
* Initialize pjmedia_vid_dev_switch_param.
*
* @param p Parameter to be initialized.
*/
PJ_INLINE(void)
pjmedia_vid_dev_switch_param_default(pjmedia_vid_dev_switch_param *p)
{
pj_bzero(p, sizeof(*p));
p->target_id = PJMEDIA_VID_INVALID_DEV;
}
/**
* Get string info for the specified capability.
*
* @param cap The capability ID.
* @param p_desc Optional pointer which will be filled with longer
* description about the capability.
*
* @return Capability name.
*/
PJ_DECL(const char*) pjmedia_vid_dev_cap_name(pjmedia_vid_dev_cap cap,
const char **p_desc);
/**
* Set a capability field value in #pjmedia_vid_dev_param structure. This will
* also set the flags field for the specified capability in the structure.
*
* @param param The structure.
* @param cap The video capability which value is to be set.
* @param pval Pointer to value. Please see the type of value to
* be supplied in the pjmedia_vid_dev_cap documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t)
pjmedia_vid_dev_param_set_cap(pjmedia_vid_dev_param *param,
pjmedia_vid_dev_cap cap,
const void *pval);
/**
* Get a capability field value from #pjmedia_vid_dev_param structure. This
* function will return PJMEDIA_EVID_INVCAP error if the flag for that
* capability is not set in the flags field in the structure.
*
* @param param The structure.
* @param cap The video capability which value is to be retrieved.
* @param pval Pointer to value. Please see the type of value to
* be supplied in the pjmedia_vid_dev_cap documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t)
pjmedia_vid_dev_param_get_cap(const pjmedia_vid_dev_param *param,
pjmedia_vid_dev_cap cap,
void *pval);
/**
* Refresh the list of video devices installed in the system. This function
* will only refresh the list of videoo device so all active video streams will
* be unaffected. After refreshing the device list, application MUST make sure
* to update all index references to video devices (i.e. all variables of type
* pjmedia_vid_dev_index) before calling any function that accepts video device
* index as its parameter.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_refresh(void);
/**
* Get the number of video devices installed in the system.
*
* @return The number of video devices installed in the system.
*/
PJ_DECL(unsigned) pjmedia_vid_dev_count(void);
/**
* Get device information.
*
* @param id The video device ID.
* @param info The device information which will be filled in by this
* function once it returns successfully.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_get_info(pjmedia_vid_dev_index id,
pjmedia_vid_dev_info *info);
/**
* Lookup device index based on the driver and device name.
*
* @param drv_name The driver name.
* @param dev_name The device name.
* @param id Pointer to store the returned device ID.
*
* @return PJ_SUCCESS if the device can be found.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_lookup(const char *drv_name,
const char *dev_name,
pjmedia_vid_dev_index *id);
/**
* Initialize the video device parameters with default values for the
* specified device.
*
* @param id The video device ID.
* @param param The video device parameters which will be initialized
* by this function once it returns successfully.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t)
pjmedia_vid_dev_default_param(pj_pool_t *pool,
pjmedia_vid_dev_index id,
pjmedia_vid_dev_param *param);
/**
* Open video stream object using the specified parameters. If stream is
* created successfully, this function will return PJ_SUCCESS and the
* stream pointer will be returned in the p_strm argument.
*
* The opened stream may have been opened with different size and fps
* than the requested values in the \a param argument. Application should
* check the actual size and fps that the stream was opened with by inspecting
* the values in the \a param argument and see if they have changed. Also
* if the device ID in the \a param specifies default device, it may be
* replaced with the actual device ID upon return.
*
* @param param On input, it specifies the video device parameters
* to be used for the stream. On output, this will be
* set to the actual video device parameters used to
* open the stream.
* @param cb Pointer to structure containing video stream
* callbacks.
* @param user_data Arbitrary user data, which will be given back in the
* callbacks.
* @param p_strm Pointer to receive the video stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_create(
pjmedia_vid_dev_param *param,
const pjmedia_vid_dev_cb *cb,
void *user_data,
pjmedia_vid_dev_stream **p_strm);
/**
* Get the running parameters for the specified video stream.
*
* @param strm The video stream.
* @param param Video stream parameters to be filled in by this
* function once it returns successfully.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_param(
pjmedia_vid_dev_stream *strm,
pjmedia_vid_dev_param *param);
/**
* Get the value of a specific capability of the video stream.
*
* @param strm The video stream.
* @param cap The video capability which value is to be retrieved.
* @param value Pointer to value to be filled in by this function
* once it returns successfully. Please see the type
* of value to be supplied in the pjmedia_vid_dev_cap
* documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_cap(
pjmedia_vid_dev_stream *strm,
pjmedia_vid_dev_cap cap,
void *value);
/**
* Set the value of a specific capability of the video stream.
*
* @param strm The video stream.
* @param cap The video capability which value is to be set.
* @param value Pointer to value. Please see the type of value to
* be supplied in the pjmedia_vid_dev_cap documentation.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_set_cap(
pjmedia_vid_dev_stream *strm,
pjmedia_vid_dev_cap cap,
const void *value);
/**
* Start the stream.
*
* @param strm The video stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_start(
pjmedia_vid_dev_stream *strm);
/**
* Query whether the stream has been started.
*
* @param strm The video stream
*
* @return PJ_TRUE if the video stream has been started.
*/
PJ_DECL(pj_bool_t) pjmedia_vid_dev_stream_is_running(pjmedia_vid_dev_stream *strm);
/**
* Request one frame from the stream. Application needs to call this function
* periodically only if the stream doesn't support "active interface", i.e.
* the pjmedia_vid_dev_info.has_callback member is PJ_FALSE.
*
* @param strm The video stream.
* @param frame The video frame to be filled by the device.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_frame(
pjmedia_vid_dev_stream *strm,
pjmedia_frame *frame);
/**
* Put one frame to the stream. Application needs to call this function
* periodically only if the stream doesn't support "active interface", i.e.
* the pjmedia_vid_dev_info.has_callback member is PJ_FALSE.
*
* @param strm The video stream.
* @param frame The video frame to put to the device.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_put_frame(
pjmedia_vid_dev_stream *strm,
const pjmedia_frame *frame);
/**
* Stop the stream.
*
* @param strm The video stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_stop(
pjmedia_vid_dev_stream *strm);
/**
* Destroy the stream.
*
* @param strm The video stream.
*
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_destroy(
pjmedia_vid_dev_stream *strm);
/**
* @}
*/
PJ_END_DECL
#endif /* __PJMEDIA_VIDEO_DEV_H__ */

View File

@ -348,8 +348,9 @@ static pj_status_t alsa_factory_refresh(pjmedia_aud_dev_factory *f)
n = hints;
while (*n != NULL) {
char *name = snd_device_name_get_hint(*n, "NAME");
if (name != NULL && 0 != strcmp("null", name)) {
add_dev(af, name);
if (name != NULL) {
if (0 != strcmp("null", name))
add_dev(af, name);
free(name);
}
n++;

View File

@ -59,7 +59,7 @@ struct android_aud_stream
pj_str_t name;
pjmedia_dir dir;
pjmedia_aud_param param;
int bytes_per_sample;
pj_uint32_t samples_per_sec;
unsigned samples_per_frame;
@ -76,8 +76,8 @@ struct android_aud_stream
pj_bool_t rec_thread_exited;
pj_thread_t *rec_thread;
pj_sem_t *rec_sem;
pj_timestamp rec_timestamp;
pj_timestamp rec_timestamp;
/* Track */
jobject track;
jclass track_class;
@ -86,7 +86,7 @@ struct android_aud_stream
pj_bool_t play_thread_exited;
pj_thread_t *play_thread;
pj_sem_t *play_sem;
pj_timestamp play_timestamp;
pj_timestamp play_timestamp;
};
/* Factory prototypes */
@ -483,9 +483,11 @@ static pj_status_t android_get_dev_info(pjmedia_aud_dev_factory *f,
pj_ansi_strcpy(info->name, "Android JNI");
info->default_samples_per_sec = 8000;
info->caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
info->caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING |
PJMEDIA_AUD_DEV_CAP_INPUT_SOURCE;
info->input_count = 1;
info->output_count = 1;
info->routes = PJMEDIA_AUD_DEV_ROUTE_CUSTOM;
return PJ_SUCCESS;
}
@ -565,7 +567,7 @@ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f,
stream = PJ_POOL_ZALLOC_T(pool, struct android_aud_stream);
stream->pool = pool;
pj_strdup2_with_null(pool, &stream->name, "JNI stream");
stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
stream->dir = param->dir;
pj_memcpy(&stream->param, param, sizeof(*param));
stream->user_data = user_data;
stream->rec_cb = rec_cb;
@ -663,8 +665,15 @@ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f,
if (stream->dir & PJMEDIA_DIR_CAPTURE) {
jthrowable exc;
jobject record_obj;
int mic_source = 0; /* DEFAULT: default audio source */
if ((param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_SOURCE) &&
(param->input_route & PJMEDIA_AUD_DEV_ROUTE_CUSTOM))
{
mic_source = param->input_route & ~PJMEDIA_AUD_DEV_ROUTE_CUSTOM;
}
/* Get pointer to the constructor */
constructor_method = (*jni_env)->GetMethodID(jni_env,
stream->record_class,
@ -694,15 +703,15 @@ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f,
PJ_LOG(4, (THIS_FILE, "Using audio input source : %d", mic_source));
do {
stream->record = (*jni_env)->NewObject(jni_env,
stream->record_class,
constructor_method,
mic_source,
param->clock_rate,
channelInCfg,
sampleFormat,
inputBuffSizeRec);
if (stream->record == 0) {
record_obj = (*jni_env)->NewObject(jni_env,
stream->record_class,
constructor_method,
mic_source,
param->clock_rate,
channelInCfg,
sampleFormat,
inputBuffSizeRec);
if (record_obj == 0) {
PJ_LOG(3, (THIS_FILE, "Unable to create audio record object"));
status = PJMEDIA_EAUD_INIT;
goto on_error;
@ -731,8 +740,7 @@ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f,
status = PJMEDIA_EAUD_SYSERR;
goto on_error;
}
state = (*jni_env)->CallIntMethod(jni_env, stream->record,
method_id);
state = (*jni_env)->CallIntMethod(jni_env, record_obj, method_id);
if (state == 0) { /* STATE_UNINITIALIZED */
PJ_LOG(3, (THIS_FILE, "Failure in initializing audio record."));
if (mic_source == 0) {
@ -744,9 +752,16 @@ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f,
}
} while (state == 0);
stream->record = (*jni_env)->NewGlobalRef(jni_env, stream->record);
stream->record = (*jni_env)->NewGlobalRef(jni_env, record_obj);
if (stream->record == 0) {
PJ_LOG(3, (THIS_FILE, "Unable to create audio record global ref."));
jmethodID release_method=0;
PJ_LOG(3, (THIS_FILE, "Unable to create audio record global ref."));
release_method = (*jni_env)->GetMethodID(jni_env,
stream->record_class,
"release", "()V");
(*jni_env)->CallVoidMethod(jni_env, record_obj, release_method);
status = PJMEDIA_EAUD_INIT;
goto on_error;
}
@ -766,6 +781,7 @@ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f,
if (stream->dir & PJMEDIA_DIR_PLAYBACK) {
jthrowable exc;
jobject track_obj;
/* Get pointer to the constructor */
constructor_method = (*jni_env)->GetMethodID(jni_env,
@ -777,16 +793,16 @@ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f,
goto on_error;
}
stream->track = (*jni_env)->NewObject(jni_env,
stream->track_class,
constructor_method,
0, /* STREAM_VOICE_CALL */
param->clock_rate,
channelOutCfg,
sampleFormat,
inputBuffSizePlay,
1 /* MODE_STREAM */);
if (stream->track == 0) {
track_obj = (*jni_env)->NewObject(jni_env,
stream->track_class,
constructor_method,
0, /* STREAM_VOICE_CALL */
param->clock_rate,
channelOutCfg,
sampleFormat,
inputBuffSizePlay,
1 /* MODE_STREAM */);
if (track_obj == 0) {
PJ_LOG(3, (THIS_FILE, "Unable to create audio track object."));
status = PJMEDIA_EAUD_INIT;
goto on_error;
@ -801,8 +817,15 @@ static pj_status_t android_create_stream(pjmedia_aud_dev_factory *f,
goto on_error;
}
stream->track = (*jni_env)->NewGlobalRef(jni_env, stream->track);
stream->track = (*jni_env)->NewGlobalRef(jni_env, track_obj);
if (stream->track == 0) {
jmethodID release_method=0;
release_method = (*jni_env)->GetMethodID(jni_env,
stream->track_class,
"release", "()V");
(*jni_env)->CallVoidMethod(jni_env, track_obj, release_method);
PJ_LOG(3, (THIS_FILE, "Unable to create audio track's global ref"));
status = PJMEDIA_EAUD_INIT;
goto on_error;
@ -972,14 +995,14 @@ static pj_status_t strm_destroy(pjmedia_aud_stream *s)
pj_bool_t attached;
PJ_LOG(4,(THIS_FILE, "Destroying Android JNI stream..."));
stream->quit_flag = PJ_TRUE;
/* Stop the stream */
strm_stop(s);
attached = attach_jvm(&jni_env);
if (stream->record){
if (stream->rec_thread) {
pj_sem_post(stream->rec_sem);
@ -992,17 +1015,21 @@ static pj_status_t strm_destroy(pjmedia_aud_stream *s)
pj_sem_destroy(stream->rec_sem);
stream->rec_sem = NULL;
}
release_method = (*jni_env)->GetMethodID(jni_env, stream->record_class,
"release", "()V");
(*jni_env)->CallVoidMethod(jni_env, stream->record, release_method);
if (stream->record_class) {
release_method = (*jni_env)->GetMethodID(jni_env,
stream->record_class,
"release", "()V");
(*jni_env)->CallVoidMethod(jni_env, stream->record,
release_method);
}
(*jni_env)->DeleteGlobalRef(jni_env, stream->record);
(*jni_env)->DeleteGlobalRef(jni_env, stream->record_class);
stream->record = NULL;
stream->record_class = NULL;
PJ_LOG(4, (THIS_FILE, "Audio record released"));
}
if (stream->record_class) {
(*jni_env)->DeleteGlobalRef(jni_env, stream->record_class);
stream->record_class = NULL;
}
if (stream->track) {
if (stream->play_thread) {
@ -1016,16 +1043,20 @@ static pj_status_t strm_destroy(pjmedia_aud_stream *s)
pj_sem_destroy(stream->play_sem);
stream->play_sem = NULL;
}
release_method = (*jni_env)->GetMethodID(jni_env, stream->track_class,
"release", "()V");
(*jni_env)->CallVoidMethod(jni_env, stream->track, release_method);
if (stream->track_class) {
release_method = (*jni_env)->GetMethodID(jni_env,
stream->track_class,
"release", "()V");
(*jni_env)->CallVoidMethod(jni_env, stream->track,
release_method);
}
(*jni_env)->DeleteGlobalRef(jni_env, stream->track);
(*jni_env)->DeleteGlobalRef(jni_env, stream->track_class);
stream->track = NULL;
stream->track_class = NULL;
PJ_LOG(3, (THIS_FILE, "Audio track released"));
stream->track = NULL;
PJ_LOG(4, (THIS_FILE, "Audio track released"));
}
if (stream->track_class) {
(*jni_env)->DeleteGlobalRef(jni_env, stream->track_class);
stream->track_class = NULL;
}
pj_pool_release(stream->pool);

View File

@ -19,51 +19,9 @@
*/
#include <pjmedia-audiodev/audiodev_imp.h>
#include <pj/assert.h>
#include <pj/errno.h>
#include <pj/log.h>
#include <pj/pool.h>
#include <pj/string.h>
#define THIS_FILE "audiodev.c"
#define DEFINE_CAP(name, info) {name, info}
/* Capability names */
static struct cap_info
{
const char *name;
const char *info;
} cap_infos[] =
{
DEFINE_CAP("ext-fmt", "Extended/non-PCM format"),
DEFINE_CAP("latency-in", "Input latency/buffer size setting"),
DEFINE_CAP("latency-out", "Output latency/buffer size setting"),
DEFINE_CAP("vol-in", "Input volume setting"),
DEFINE_CAP("vol-out", "Output volume setting"),
DEFINE_CAP("meter-in", "Input meter"),
DEFINE_CAP("meter-out", "Output meter"),
DEFINE_CAP("route-in", "Input routing"),
DEFINE_CAP("route-out", "Output routing"),
DEFINE_CAP("aec", "Accoustic echo cancellation"),
DEFINE_CAP("aec-tail", "Tail length setting for AEC"),
DEFINE_CAP("vad", "Voice activity detection"),
DEFINE_CAP("cng", "Comfort noise generation"),
DEFINE_CAP("plg", "Packet loss concealment")
};
/*
* The device index seen by application and driver is different.
*
* At application level, device index is index to global list of device.
* At driver level, device index is index to device list on that particular
* factory only.
*/
#define MAKE_DEV_ID(f_id, index) (((f_id & 0xFFFF) << 16) | (index & 0xFFFF))
#define GET_INDEX(dev_id) ((dev_id) & 0xFFFF)
#define GET_FID(dev_id) ((dev_id) >> 16)
#define DEFAULT_DEV_ID 0
/* extern functions to create factories */
#if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
@ -118,285 +76,18 @@ pjmedia_aud_dev_factory* pjmedia_wasapi_factory(pj_pool_factory *pf);
pjmedia_aud_dev_factory* pjmedia_null_audio_factory(pj_pool_factory *pf);
#endif
#define MAX_DRIVERS 16
#define MAX_DEVS 64
/* driver structure */
struct driver
{
/* Creation function */
pjmedia_aud_dev_factory_create_func_ptr create;
/* Factory instance */
pjmedia_aud_dev_factory *f;
char name[32]; /* Driver name */
unsigned dev_cnt; /* Number of devices */
unsigned start_idx; /* Start index in global list */
int rec_dev_idx;/* Default capture device. */
int play_dev_idx;/* Default playback device */
int dev_idx; /* Default device. */
};
/* The audio subsystem */
static struct aud_subsys
{
unsigned init_count; /* How many times init() is called */
pj_pool_factory *pf; /* The pool factory. */
unsigned drv_cnt; /* Number of drivers. */
struct driver drv[MAX_DRIVERS]; /* Array of drivers. */
unsigned dev_cnt; /* Total number of devices. */
pj_uint32_t dev_list[MAX_DEVS];/* Array of device IDs. */
} aud_subsys;
/* API: get capability name/info */
PJ_DEF(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
const char **p_desc)
{
const char *desc;
unsigned i;
if (p_desc==NULL) p_desc = &desc;
for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
if ((1 << i)==cap)
break;
}
if (i==PJ_ARRAY_SIZE(cap_infos)) {
*p_desc = "??";
return "??";
}
*p_desc = cap_infos[i].info;
return cap_infos[i].name;
}
static pj_status_t get_cap_pointer(const pjmedia_aud_param *param,
pjmedia_aud_dev_cap cap,
void **ptr,
unsigned *size)
{
#define FIELD_INFO(name) *ptr = (void*)&param->name; \
*size = sizeof(param->name)
switch (cap) {
case PJMEDIA_AUD_DEV_CAP_EXT_FORMAT:
FIELD_INFO(ext_fmt);
break;
case PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY:
FIELD_INFO(input_latency_ms);
break;
case PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY:
FIELD_INFO(output_latency_ms);
break;
case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
FIELD_INFO(input_vol);
break;
case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
FIELD_INFO(output_vol);
break;
case PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE:
FIELD_INFO(input_route);
break;
case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE:
FIELD_INFO(output_route);
break;
case PJMEDIA_AUD_DEV_CAP_EC:
FIELD_INFO(ec_enabled);
break;
case PJMEDIA_AUD_DEV_CAP_EC_TAIL:
FIELD_INFO(ec_tail_ms);
break;
/* vad is no longer in "fmt" in 2.0.
case PJMEDIA_AUD_DEV_CAP_VAD:
FIELD_INFO(ext_fmt.vad);
break;
*/
case PJMEDIA_AUD_DEV_CAP_CNG:
FIELD_INFO(cng_enabled);
break;
case PJMEDIA_AUD_DEV_CAP_PLC:
FIELD_INFO(plc_enabled);
break;
default:
return PJMEDIA_EAUD_INVCAP;
}
#undef FIELD_INFO
return PJ_SUCCESS;
}
/* API: set cap value to param */
PJ_DEF(pj_status_t) pjmedia_aud_param_set_cap( pjmedia_aud_param *param,
pjmedia_aud_dev_cap cap,
const void *pval)
{
void *cap_ptr;
unsigned cap_size;
pj_status_t status;
status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
if (status != PJ_SUCCESS)
return status;
pj_memcpy(cap_ptr, pval, cap_size);
param->flags |= cap;
return PJ_SUCCESS;
}
/* API: get cap value from param */
PJ_DEF(pj_status_t) pjmedia_aud_param_get_cap( const pjmedia_aud_param *param,
pjmedia_aud_dev_cap cap,
void *pval)
{
void *cap_ptr;
unsigned cap_size;
pj_status_t status;
status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
if (status != PJ_SUCCESS)
return status;
if ((param->flags & cap) == 0) {
pj_bzero(cap_ptr, cap_size);
return PJMEDIA_EAUD_INVCAP;
}
pj_memcpy(pval, cap_ptr, cap_size);
return PJ_SUCCESS;
}
/* Internal: init driver */
static pj_status_t init_driver(unsigned drv_idx, pj_bool_t refresh)
{
struct driver *drv = &aud_subsys.drv[drv_idx];
pjmedia_aud_dev_factory *f;
unsigned i, dev_cnt;
pj_status_t status;
if (!refresh && drv->create) {
/* Create the factory */
f = (*drv->create)(aud_subsys.pf);
if (!f)
return PJ_EUNKNOWN;
/* Call factory->init() */
status = f->op->init(f);
if (status != PJ_SUCCESS) {
f->op->destroy(f);
return status;
}
} else {
f = drv->f;
}
if (!f)
return PJ_EUNKNOWN;
/* Get number of devices */
dev_cnt = f->op->get_dev_count(f);
if (dev_cnt + aud_subsys.dev_cnt > MAX_DEVS) {
PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"
" there are too many devices",
aud_subsys.dev_cnt + dev_cnt - MAX_DEVS));
dev_cnt = MAX_DEVS - aud_subsys.dev_cnt;
}
/* enabling this will cause pjsua-lib initialization to fail when there
* is no sound device installed in the system, even when pjsua has been
* run with --null-audio
*
if (dev_cnt == 0) {
f->op->destroy(f);
return PJMEDIA_EAUD_NODEV;
}
*/
/* Fill in default devices */
drv->play_dev_idx = drv->rec_dev_idx =
drv->dev_idx = PJMEDIA_AUD_INVALID_DEV;
for (i=0; i<dev_cnt; ++i) {
pjmedia_aud_dev_info info;
status = f->op->get_dev_info(f, i, &info);
if (status != PJ_SUCCESS) {
f->op->destroy(f);
return status;
}
if (drv->name[0]=='\0') {
/* Set driver name */
pj_ansi_strncpy(drv->name, info.driver, sizeof(drv->name));
drv->name[sizeof(drv->name)-1] = '\0';
}
if (drv->play_dev_idx < 0 && info.output_count) {
/* Set default playback device */
drv->play_dev_idx = i;
}
if (drv->rec_dev_idx < 0 && info.input_count) {
/* Set default capture device */
drv->rec_dev_idx = i;
}
if (drv->dev_idx < 0 && info.input_count &&
info.output_count)
{
/* Set default capture and playback device */
drv->dev_idx = i;
}
if (drv->play_dev_idx >= 0 && drv->rec_dev_idx >= 0 &&
drv->dev_idx >= 0)
{
/* Done. */
break;
}
}
/* Register the factory */
drv->f = f;
drv->f->sys.drv_idx = drv_idx;
drv->start_idx = aud_subsys.dev_cnt;
drv->dev_cnt = dev_cnt;
/* Register devices to global list */
for (i=0; i<dev_cnt; ++i) {
aud_subsys.dev_list[aud_subsys.dev_cnt++] = MAKE_DEV_ID(drv_idx, i);
}
return PJ_SUCCESS;
}
/* Internal: deinit driver */
static void deinit_driver(unsigned drv_idx)
{
struct driver *drv = &aud_subsys.drv[drv_idx];
if (drv->f) {
drv->f->op->destroy(drv->f);
drv->f = NULL;
}
pj_bzero(drv, sizeof(*drv));
drv->play_dev_idx = drv->rec_dev_idx =
drv->dev_idx = PJMEDIA_AUD_INVALID_DEV;
}
/* API: Initialize the audio subsystem. */
PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf)
{
unsigned i;
pj_status_t status;
pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys();
/* Allow init() to be called multiple times as long as there is matching
* number of shutdown().
*/
if (aud_subsys.init_count++ != 0) {
if (aud_subsys->init_count++ != 0) {
return PJ_SUCCESS;
}
@ -407,61 +98,61 @@ PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf)
pj_assert(status == PJ_SUCCESS);
/* Init */
aud_subsys.pf = pf;
aud_subsys.drv_cnt = 0;
aud_subsys.dev_cnt = 0;
aud_subsys->pf = pf;
aud_subsys->drv_cnt = 0;
aud_subsys->dev_cnt = 0;
/* Register creation functions */
#if PJMEDIA_AUDIO_DEV_HAS_OPENSL
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_opensl_factory;
aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_opensl_factory;
#endif
#if PJMEDIA_AUDIO_DEV_HAS_ANDROID_JNI
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_android_factory;
aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_android_factory;
#endif
#if PJMEDIA_AUDIO_DEV_HAS_BB10
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_bb10_factory;
aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_bb10_factory;
#endif
#if PJMEDIA_AUDIO_DEV_HAS_ALSA
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_alsa_factory;
aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_alsa_factory;
#endif
#if PJMEDIA_AUDIO_DEV_HAS_COREAUDIO
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_coreaudio_factory;
aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_coreaudio_factory;
#endif
#if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_pa_factory;
aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_pa_factory;
#endif
#if PJMEDIA_AUDIO_DEV_HAS_WMME
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_wmme_factory;
aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_wmme_factory;
#endif
#if PJMEDIA_AUDIO_DEV_HAS_BDIMAD
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_bdimad_factory;
aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_bdimad_factory;
#endif
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_VAS
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_symb_vas_factory;
aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_symb_vas_factory;
#endif
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_APS
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_aps_factory;
aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_aps_factory;
#endif
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_symb_mda_factory;
aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_symb_mda_factory;
#endif
#if PJMEDIA_AUDIO_DEV_HAS_WASAPI
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_wasapi_factory;
#endif
#if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_null_audio_factory;
aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_null_audio_factory;
#endif
/* Initialize each factory and build the device ID list */
for (i=0; i<aud_subsys.drv_cnt; ++i) {
status = init_driver(i, PJ_FALSE);
for (i=0; i<aud_subsys->drv_cnt; ++i) {
status = pjmedia_aud_driver_init(i, PJ_FALSE);
if (status != PJ_SUCCESS) {
deinit_driver(i);
pjmedia_aud_driver_deinit(i);
continue;
}
}
return aud_subsys.dev_cnt ? PJ_SUCCESS : status;
return aud_subsys->dev_cnt ? PJ_SUCCESS : status;
}
/* API: register an audio device factory to the audio subsystem. */
@ -469,16 +160,17 @@ PJ_DEF(pj_status_t)
pjmedia_aud_register_factory(pjmedia_aud_dev_factory_create_func_ptr adf)
{
pj_status_t status;
pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys();
if (aud_subsys.init_count == 0)
if (aud_subsys->init_count == 0)
return PJMEDIA_EAUD_INIT;
aud_subsys.drv[aud_subsys.drv_cnt].create = adf;
status = init_driver(aud_subsys.drv_cnt, PJ_FALSE);
aud_subsys->drv[aud_subsys->drv_cnt].create = adf;
status = pjmedia_aud_driver_init(aud_subsys->drv_cnt, PJ_FALSE);
if (status == PJ_SUCCESS) {
aud_subsys.drv_cnt++;
aud_subsys->drv_cnt++;
} else {
deinit_driver(aud_subsys.drv_cnt);
pjmedia_aud_driver_deinit(aud_subsys->drv_cnt);
}
return status;
@ -489,20 +181,21 @@ PJ_DEF(pj_status_t)
pjmedia_aud_unregister_factory(pjmedia_aud_dev_factory_create_func_ptr adf)
{
unsigned i, j;
pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys();
if (aud_subsys.init_count == 0)
if (aud_subsys->init_count == 0)
return PJMEDIA_EAUD_INIT;
for (i=0; i<aud_subsys.drv_cnt; ++i) {
struct driver *drv = &aud_subsys.drv[i];
for (i=0; i<aud_subsys->drv_cnt; ++i) {
pjmedia_aud_driver *drv = &aud_subsys->drv[i];
if (drv->create == adf) {
for (j = drv->start_idx; j < drv->start_idx + drv->dev_cnt; j++)
{
aud_subsys.dev_list[j] = (pj_uint32_t)PJMEDIA_AUD_INVALID_DEV;
aud_subsys->dev_list[j] = (pj_uint32_t)PJMEDIA_AUD_INVALID_DEV;
}
deinit_driver(i);
pjmedia_aud_driver_deinit(i);
return PJ_SUCCESS;
}
}
@ -513,342 +206,30 @@ pjmedia_aud_unregister_factory(pjmedia_aud_dev_factory_create_func_ptr adf)
/* API: get the pool factory registered to the audio subsystem. */
PJ_DEF(pj_pool_factory*) pjmedia_aud_subsys_get_pool_factory(void)
{
return aud_subsys.pf;
pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys();
return aud_subsys->pf;
}
/* API: Shutdown the audio subsystem. */
PJ_DEF(pj_status_t) pjmedia_aud_subsys_shutdown(void)
{
unsigned i;
pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys();
/* Allow shutdown() to be called multiple times as long as there is matching
* number of init().
*/
if (aud_subsys.init_count == 0) {
if (aud_subsys->init_count == 0) {
return PJ_SUCCESS;
}
--aud_subsys.init_count;
--aud_subsys->init_count;
if (aud_subsys.init_count == 0) {
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) {
pjmedia_aud_driver_deinit(i);
}
aud_subsys.pf = NULL;
aud_subsys->pf = NULL;
}
return PJ_SUCCESS;
}
/* API: Refresh the list of sound devices installed in the system. */
PJ_DEF(pj_status_t) pjmedia_aud_dev_refresh(void)
{
unsigned i;
aud_subsys.dev_cnt = 0;
for (i=0; i<aud_subsys.drv_cnt; ++i) {
struct driver *drv = &aud_subsys.drv[i];
if (drv->f && drv->f->op->refresh) {
pj_status_t status = drv->f->op->refresh(drv->f);
if (status != PJ_SUCCESS) {
PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device "
"list for %s", drv->name));
}
}
init_driver(i, PJ_TRUE);
}
return PJ_SUCCESS;
}
/* API: Get the number of sound devices installed in the system. */
PJ_DEF(unsigned) pjmedia_aud_dev_count(void)
{
return aud_subsys.dev_cnt;
}
/* Internal: convert local index to global device index */
static pj_status_t make_global_index(unsigned drv_idx,
pjmedia_aud_dev_index *id)
{
if (*id < 0) {
return PJ_SUCCESS;
}
/* Check that factory still exists */
PJ_ASSERT_RETURN(aud_subsys.drv[drv_idx].f, PJ_EBUG);
/* Check that device index is valid */
PJ_ASSERT_RETURN(*id>=0 && *id<(int)aud_subsys.drv[drv_idx].dev_cnt,
PJ_EBUG);
*id += aud_subsys.drv[drv_idx].start_idx;
return PJ_SUCCESS;
}
/* Internal: lookup device id */
static pj_status_t lookup_dev(pjmedia_aud_dev_index id,
pjmedia_aud_dev_factory **p_f,
unsigned *p_local_index)
{
int f_id, index;
if (id < 0) {
unsigned i;
if (id == PJMEDIA_AUD_INVALID_DEV)
return PJMEDIA_EAUD_INVDEV;
for (i=0; i<aud_subsys.drv_cnt; ++i) {
struct driver *drv = &aud_subsys.drv[i];
if (drv->dev_idx >= 0) {
id = drv->dev_idx;
make_global_index(i, &id);
break;
} else if (id==PJMEDIA_AUD_DEFAULT_CAPTURE_DEV &&
drv->rec_dev_idx >= 0)
{
id = drv->rec_dev_idx;
make_global_index(i, &id);
break;
} else if (id==PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV &&
drv->play_dev_idx >= 0)
{
id = drv->play_dev_idx;
make_global_index(i, &id);
break;
}
}
if (id < 0) {
return PJMEDIA_EAUD_NODEFDEV;
}
}
f_id = GET_FID(aud_subsys.dev_list[id]);
index = GET_INDEX(aud_subsys.dev_list[id]);
if (f_id < 0 || f_id >= (int)aud_subsys.drv_cnt)
return PJMEDIA_EAUD_INVDEV;
if (index < 0 || index >= (int)aud_subsys.drv[f_id].dev_cnt)
return PJMEDIA_EAUD_INVDEV;
*p_f = aud_subsys.drv[f_id].f;
*p_local_index = (unsigned)index;
return PJ_SUCCESS;
}
/* API: Get device information. */
PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id,
pjmedia_aud_dev_info *info)
{
pjmedia_aud_dev_factory *f;
unsigned index;
pj_status_t status;
PJ_ASSERT_RETURN(info && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);
PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
status = lookup_dev(id, &f, &index);
if (status != PJ_SUCCESS)
return status;
return f->op->get_dev_info(f, index, info);
}
/* API: find device */
PJ_DEF(pj_status_t) pjmedia_aud_dev_lookup( const char *drv_name,
const char *dev_name,
pjmedia_aud_dev_index *id)
{
pjmedia_aud_dev_factory *f = NULL;
unsigned drv_idx, dev_idx;
PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
for (drv_idx=0; drv_idx<aud_subsys.drv_cnt; ++drv_idx) {
if (!pj_ansi_stricmp(drv_name, aud_subsys.drv[drv_idx].name)) {
f = aud_subsys.drv[drv_idx].f;
break;
}
}
if (!f)
return PJ_ENOTFOUND;
for (dev_idx=0; dev_idx<aud_subsys.drv[drv_idx].dev_cnt; ++dev_idx) {
pjmedia_aud_dev_info info;
pj_status_t status;
status = f->op->get_dev_info(f, dev_idx, &info);
if (status != PJ_SUCCESS)
return status;
if (!pj_ansi_stricmp(dev_name, info.name))
break;
}
if (dev_idx==aud_subsys.drv[drv_idx].dev_cnt)
return PJ_ENOTFOUND;
*id = dev_idx;
make_global_index(drv_idx, id);
return PJ_SUCCESS;
}
/* API: Initialize the audio device parameters with default values for the
* specified device.
*/
PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
pjmedia_aud_param *param)
{
pjmedia_aud_dev_factory *f;
unsigned index;
pj_status_t status;
PJ_ASSERT_RETURN(param && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);
PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
status = lookup_dev(id, &f, &index);
if (status != PJ_SUCCESS)
return status;
status = f->op->default_param(f, index, param);
if (status != PJ_SUCCESS)
return status;
/* Normalize device IDs */
make_global_index(f->sys.drv_idx, &param->rec_id);
make_global_index(f->sys.drv_idx, &param->play_id);
return PJ_SUCCESS;
}
/* API: Open audio stream object using the specified parameters. */
PJ_DEF(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_param *prm,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
pjmedia_aud_stream **p_aud_strm)
{
pjmedia_aud_dev_factory *rec_f=NULL, *play_f=NULL, *f=NULL;
pjmedia_aud_param param;
pj_status_t status;
PJ_ASSERT_RETURN(prm && prm->dir && p_aud_strm, PJ_EINVAL);
PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
PJ_ASSERT_RETURN(prm->dir==PJMEDIA_DIR_CAPTURE ||
prm->dir==PJMEDIA_DIR_PLAYBACK ||
prm->dir==PJMEDIA_DIR_CAPTURE_PLAYBACK,
PJ_EINVAL);
/* Must make copy of param because we're changing device ID */
pj_memcpy(&param, prm, sizeof(param));
/* Normalize rec_id */
if (param.dir & PJMEDIA_DIR_CAPTURE) {
unsigned index;
if (param.rec_id < 0)
param.rec_id = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;
status = lookup_dev(param.rec_id, &rec_f, &index);
if (status != PJ_SUCCESS)
return status;
param.rec_id = index;
f = rec_f;
}
/* Normalize play_id */
if (param.dir & PJMEDIA_DIR_PLAYBACK) {
unsigned index;
if (param.play_id < 0)
param.play_id = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
status = lookup_dev(param.play_id, &play_f, &index);
if (status != PJ_SUCCESS)
return status;
param.play_id = index;
f = play_f;
}
PJ_ASSERT_RETURN(f != NULL, PJ_EBUG);
/* For now, rec_id and play_id must belong to the same factory */
PJ_ASSERT_RETURN((param.dir != PJMEDIA_DIR_CAPTURE_PLAYBACK) ||
(rec_f == play_f),
PJMEDIA_EAUD_INVDEV);
/* Create the stream */
status = f->op->create_stream(f, &param, rec_cb, play_cb,
user_data, p_aud_strm);
if (status != PJ_SUCCESS)
return status;
/* Assign factory id to the stream */
(*p_aud_strm)->sys.drv_idx = f->sys.drv_idx;
return PJ_SUCCESS;
}
/* API: Get the running parameters for the specified audio stream. */
PJ_DEF(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
pjmedia_aud_param *param)
{
pj_status_t status;
PJ_ASSERT_RETURN(strm && param, PJ_EINVAL);
PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
status = strm->op->get_param(strm, param);
if (status != PJ_SUCCESS)
return status;
/* Normalize device id's */
make_global_index(strm->sys.drv_idx, &param->rec_id);
make_global_index(strm->sys.drv_idx, &param->play_id);
return PJ_SUCCESS;
}
/* API: Get the value of a specific capability of the audio stream. */
PJ_DEF(pj_status_t) pjmedia_aud_stream_get_cap(pjmedia_aud_stream *strm,
pjmedia_aud_dev_cap cap,
void *value)
{
return strm->op->get_cap(strm, cap, value);
}
/* API: Set the value of a specific capability of the audio stream. */
PJ_DEF(pj_status_t) pjmedia_aud_stream_set_cap(pjmedia_aud_stream *strm,
pjmedia_aud_dev_cap cap,
const void *value)
{
return strm->op->set_cap(strm, cap, value);
}
/* API: Start the stream. */
PJ_DEF(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm)
{
return strm->op->start(strm);
}
/* API: Stop the stream. */
PJ_DEF(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm)
{
return strm->op->stop(strm);
}
/* API: Destroy the stream. */
PJ_DEF(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm)
{
return strm->op->destroy(strm);
}

View File

@ -52,6 +52,12 @@
/* Starting iOS SDK 7, Audio Session API is deprecated. */
#define USE_AUDIO_SESSION_API 0
/* For better integration with CallKit features (available starting
* in iOS 10), let the application setup and manage its own
* audio session.
*/
#define SETUP_AV_AUDIO_SESSION 0
#endif
/* For Mac OS 10.5.x and earlier */
@ -335,6 +341,7 @@ static pj_status_t ca_factory_init(pjmedia_aud_dev_factory *f)
}
#endif
#if SETUP_AV_AUDIO_SESSION
/* Initialize audio session category and mode */
{
AVAudioSession *sess = [AVAudioSession sharedInstance];
@ -360,6 +367,7 @@ static pj_status_t ca_factory_init(pjmedia_aud_dev_factory *f)
PJ_LOG(3, (THIS_FILE, "Warning: failed settting audio mode"));
}
}
#endif
cf_instance = cf;
#endif
@ -2080,7 +2088,7 @@ static pj_status_t ca_stream_stop(pjmedia_aud_stream *strm)
}
pj_mutex_unlock(stream->cf->mutex);
#if !COREAUDIO_MAC
#if !COREAUDIO_MAC && SETUP_AV_AUDIO_SESSION
if (should_deactivate) {
if ([stream->sess
respondsToSelector:@selector(setActive:withOptions:error:)])

View File

@ -489,7 +489,7 @@ static pj_status_t opensl_create_stream(pjmedia_aud_dev_factory *f,
stream = PJ_POOL_ZALLOC_T(pool, struct opensl_aud_stream);
stream->pool = pool;
pj_strdup2_with_null(pool, &stream->name, "OpenSL");
stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
stream->dir = param->dir;
pj_memcpy(&stream->param, param, sizeof(*param));
stream->user_data = user_data;
stream->rec_cb = rec_cb;

View File

@ -121,6 +121,13 @@ pjmedia_codec_register_audio_codecs(pjmedia_endpt *endpt,
return status;
#endif
#if PJMEDIA_HAS_OPUS_CODEC
/* Register OPUS */
status = pjmedia_codec_opus_init(endpt);
if (status != PJ_SUCCESS)
return status;
#endif
return PJ_SUCCESS;
}

View File

@ -1429,8 +1429,12 @@ static pj_status_t ffmpeg_codec_encode_whole(pjmedia_vid_codec *codec,
/* Check if encoder has been opened */
PJ_ASSERT_RETURN(ff->enc_ctx, PJ_EINVALIDOP);
#ifdef PJMEDIA_USE_OLD_FFMPEG
avcodec_get_frame_defaults(&avframe);
#else
pj_bzero(&avframe, sizeof(avframe));
av_frame_unref(&avframe);
#endif
// Let ffmpeg manage the timestamps
/*
@ -1472,10 +1476,17 @@ static pj_status_t ffmpeg_codec_encode_whole(pjmedia_vid_codec *codec,
print_ffmpeg_err(err);
return PJMEDIA_CODEC_EFAILED;
} else {
pj_bool_t has_key_frame = PJ_FALSE;
output->size = err;
output->bit_info = 0;
if (ff->enc_ctx->coded_frame->key_frame)
output->bit_info |= PJMEDIA_VID_FRM_KEYFRAME;
#if LIBAVCODEC_VER_AT_LEAST(54,15)
has_key_frame = (avpacket.flags & AV_PKT_FLAG_KEY);
#else
has_key_frame = ff->enc_ctx->coded_frame->key_frame;
#endif
if (has_key_frame)
output->bit_info |= PJMEDIA_VID_FRM_KEYFRAME;
}
return PJ_SUCCESS;
@ -1680,8 +1691,12 @@ static pj_status_t ffmpeg_codec_decode_whole(pjmedia_vid_codec *codec,
* whole decoding session, and seems to be freed when the codec context
* closed).
*/
#ifdef PJMEDIA_USE_OLD_FFMPEG
avcodec_get_frame_defaults(&avframe);
#else
pj_bzero(&avframe, sizeof(avframe));
av_frame_unref(&avframe);
#endif
/* Init packet, the container of the encoded data */
av_init_packet(&avpacket);

View File

@ -163,8 +163,8 @@ typedef struct oh264_codec_data
struct SLayerPEncCtx
{
pj_int32_t iDLayerQp;
SSliceConfig sSliceCfg;
pj_int32_t iDLayerQp;
SSliceArgument sSliceArgument;
};
PJ_DEF(pj_status_t) pjmedia_codec_openh264_vid_init(pjmedia_vid_codec_mgr *mgr,
@ -470,18 +470,19 @@ static pj_status_t oh264_codec_open(pjmedia_vid_codec *codec,
*/
/* Init encoder parameters */
pj_bzero(&eprm, sizeof(eprm));
eprm.iInputCsp = videoFormatI420;
oh264_data->enc->GetDefaultParams (&eprm);
eprm.iComplexityMode = MEDIUM_COMPLEXITY;
eprm.sSpatialLayers[0].uiProfileIdc = PRO_BASELINE;
eprm.iPicWidth = param->enc_fmt.det.vid.size.w;
eprm.iUsageType = CAMERA_VIDEO_REAL_TIME;
eprm.iPicHeight = param->enc_fmt.det.vid.size.h;
eprm.fMaxFrameRate = (param->enc_fmt.det.vid.fps.num *
1.0f /
param->enc_fmt.det.vid.fps.denum);
eprm.uiFrameToBeCoded = (unsigned int) -1;
eprm.iTemporalLayerNum = 1;
eprm.uiIntraPeriod = 0; /* I-Frame interval in frames */
eprm.bEnableSpsPpsIdAddition = (oh264_data->whole? false : true);
eprm.eSpsPpsIdStrategy = (oh264_data->whole ? CONSTANT_ID :
INCREASING_ID);
eprm.bEnableFrameCroppingFlag = true;
eprm.iLoopFilterDisableIdc = 0;
eprm.iLoopFilterAlphaC0Offset = 0;
@ -504,18 +505,21 @@ static pj_status_t oh264_codec_open(pjmedia_vid_codec *codec,
pj_bzero(&elayer_ctx, sizeof (SLayerPEncCtx));
elayer_ctx.iDLayerQp = 24;
elayer_ctx.sSliceCfg.uiSliceMode = (oh264_data->whole ?
SM_SINGLE_SLICE : SM_DYN_SLICE);
elayer_ctx.sSliceCfg.sSliceArgument.uiSliceSizeConstraint = param->enc_mtu;
elayer_ctx.sSliceCfg.sSliceArgument.uiSliceNum = 1;
elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[0] = 960;
elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[1] = 0;
elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[2] = 0;
elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[3] = 0;
elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[4] = 0;
elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[5] = 0;
elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[6] = 0;
elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[7] = 0;
elayer_ctx.sSliceArgument.uiSliceMode = (oh264_data->whole ?
SM_SINGLE_SLICE :
SM_SIZELIMITED_SLICE);
/* uiSliceSizeConstraint = uiMaxNalSize - NAL_HEADER_ADD_0X30BYTES */
elayer_ctx.sSliceArgument.uiSliceSizeConstraint = param->enc_mtu - 50;
elayer_ctx.sSliceArgument.uiSliceNum = 1;
elayer_ctx.sSliceArgument.uiSliceMbNum[0] = 960;
elayer_ctx.sSliceArgument.uiSliceMbNum[1] = 0;
elayer_ctx.sSliceArgument.uiSliceMbNum[2] = 0;
elayer_ctx.sSliceArgument.uiSliceMbNum[3] = 0;
elayer_ctx.sSliceArgument.uiSliceMbNum[4] = 0;
elayer_ctx.sSliceArgument.uiSliceMbNum[5] = 0;
elayer_ctx.sSliceArgument.uiSliceMbNum[6] = 0;
elayer_ctx.sSliceArgument.uiSliceMbNum[7] = 0;
elayer->iVideoWidth = eprm.iPicWidth;
elayer->iVideoHeight = eprm.iPicHeight;
@ -523,14 +527,14 @@ static pj_status_t oh264_codec_open(pjmedia_vid_codec *codec,
elayer->uiProfileIdc = eprm.sSpatialLayers[0].uiProfileIdc;
elayer->iSpatialBitrate = eprm.iTargetBitrate;
elayer->iDLayerQp = elayer_ctx.iDLayerQp;
elayer->sSliceCfg.uiSliceMode = elayer_ctx.sSliceCfg.uiSliceMode;
elayer->sSliceArgument.uiSliceMode = elayer_ctx.sSliceArgument.uiSliceMode;
memcpy( &elayer->sSliceCfg,
&elayer_ctx.sSliceCfg,
sizeof (SSliceConfig));
memcpy( &elayer->sSliceCfg.sSliceArgument.uiSliceMbNum[0],
&elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum[0],
sizeof (elayer_ctx.sSliceCfg.sSliceArgument.uiSliceMbNum));
memcpy ( &elayer->sSliceArgument,
&elayer_ctx.sSliceArgument,
sizeof (SSliceArgument));
memcpy ( &elayer->sSliceArgument.uiSliceMbNum[0],
&elayer_ctx.sSliceArgument.uiSliceMbNum[0],
sizeof (elayer_ctx.sSliceArgument.uiSliceMbNum));
/* Init input picture */
oh264_data->esrc_pic->iColorFormat = videoFormatI420;
@ -552,13 +556,20 @@ static pj_status_t oh264_codec_open(pjmedia_vid_codec *codec,
return PJMEDIA_CODEC_EFAILED;
}
int videoFormat = videoFormatI420;
rc = oh264_data->enc->SetOption (ENCODER_OPTION_DATAFORMAT, &videoFormat);
if (rc != cmResultSuccess) {
PJ_LOG(4,(THIS_FILE, "SVC encoder SetOption videoFormatI420 failed, "
"rc=%d", rc));
return PJMEDIA_CODEC_EFAILED;
}
/*
* Decoder
*/
sDecParam.sVideoProperty.size = sizeof (sDecParam.sVideoProperty);
sDecParam.iOutputColorFormat = videoFormatI420;
sDecParam.uiTargetDqLayer = (pj_uint8_t) - 1;
sDecParam.uiEcActiveFlag = 1;
sDecParam.eEcActiveIdc = ERROR_CON_SLICE_COPY;
sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;
//TODO:
@ -576,14 +587,6 @@ static pj_status_t oh264_codec_open(pjmedia_vid_codec *codec,
return PJMEDIA_CODEC_EFAILED;
}
pj_int32_t color_fmt = videoFormatI420;
rc = oh264_data->dec->SetOption (DECODER_OPTION_DATAFORMAT, &color_fmt);
if (rc) {
PJ_LOG(4,(THIS_FILE,
"Warning: SetOption(DECODER_OPTION_DATAFORMAT) failed, rc=%d",
rc));
}
oh264_data->dec_buf_size = (MAX_RX_WIDTH * MAX_RX_HEIGHT * 3 >> 1) +
(MAX_RX_WIDTH);
oh264_data->dec_buf = (pj_uint8_t*)pj_pool_alloc(oh264_data->pool,
@ -661,7 +664,7 @@ static pj_status_t oh264_codec_encode_begin(pjmedia_vid_codec *codec,
return PJMEDIA_CODEC_EFAILED;
}
if (oh264_data->bsi.eOutputFrameType == videoFrameTypeSkip) {
if (oh264_data->bsi.eFrameType == videoFrameTypeSkip) {
output->size = 0;
output->type = PJMEDIA_FRAME_TYPE_NONE;
output->timestamp = input->timestamp;
@ -681,13 +684,13 @@ static pj_status_t oh264_codec_encode_begin(pjmedia_vid_codec *codec,
/* Find which layer with biggest payload */
oh264_data->ilayer = 0;
payload_size = oh264_data->bsi.sLayerInfo[0].iNalLengthInByte[0];
payload_size = oh264_data->bsi.sLayerInfo[0].pNalLengthInByte[0];
for (i=0; i < (unsigned)oh264_data->bsi.iLayerNum; ++i) {
unsigned j;
pLayerBsInfo = &oh264_data->bsi.sLayerInfo[i];
for (j=0; j < (unsigned)pLayerBsInfo->iNalCount; ++j) {
if (pLayerBsInfo->iNalLengthInByte[j] > (int)payload_size) {
payload_size = pLayerBsInfo->iNalLengthInByte[j];
if (pLayerBsInfo->pNalLengthInByte[j] > (int)payload_size) {
payload_size = pLayerBsInfo->pNalLengthInByte[j];
oh264_data->ilayer = i;
}
}
@ -703,7 +706,7 @@ static pj_status_t oh264_codec_encode_begin(pjmedia_vid_codec *codec,
payload = pLayerBsInfo->pBsBuf;
payload_size = 0;
for (int inal = pLayerBsInfo->iNalCount - 1; inal >= 0; --inal) {
payload_size += pLayerBsInfo->iNalLengthInByte[inal];
payload_size += pLayerBsInfo->pNalLengthInByte[inal];
}
if (payload_size > out_size)
@ -760,7 +763,7 @@ static pj_status_t oh264_codec_encode_more(pjmedia_vid_codec *codec,
pj_memcpy(output->buf, payload, payload_len);
output->size = payload_len;
if (oh264_data->bsi.eOutputFrameType == videoFrameTypeIDR) {
if (oh264_data->bsi.eFrameType == videoFrameTypeIDR) {
output->bit_info |= PJMEDIA_VID_FRM_KEYFRAME;
}
@ -782,7 +785,7 @@ static pj_status_t oh264_codec_encode_more(pjmedia_vid_codec *codec,
oh264_data->enc_frame_size = 0;
for (int inal = pLayerBsInfo->iNalCount - 1; inal >= 0; --inal) {
oh264_data->enc_frame_size += pLayerBsInfo->iNalLengthInByte[inal];
oh264_data->enc_frame_size += pLayerBsInfo->pNalLengthInByte[inal];
}
oh264_data->enc_frame_whole = pLayerBsInfo->pBsBuf;
@ -809,7 +812,7 @@ static pj_status_t oh264_codec_encode_more(pjmedia_vid_codec *codec,
pj_memcpy(output->buf, payload, payload_len);
output->size = payload_len;
if (oh264_data->bsi.eOutputFrameType == videoFrameTypeIDR) {
if (oh264_data->bsi.eFrameType == videoFrameTypeIDR) {
output->bit_info |= PJMEDIA_VID_FRM_KEYFRAME;
}

File diff suppressed because it is too large Load Diff

View File

@ -39,17 +39,30 @@
#if defined(PJMEDIA_HAS_VIDEO) && PJMEDIA_HAS_VIDEO != 0 && \
defined(PJMEDIA_HAS_LIBAVDEVICE) && PJMEDIA_HAS_LIBAVDEVICE != 0 && \
defined(PJMEDIA_VIDEO_DEV_HAS_FFMPEG) && PJMEDIA_VIDEO_DEV_HAS_FFMPEG != 0
#define THIS_FILE "ffmpeg.c"
#define LIBAVFORMAT_VER_AT_LEAST(major,minor) (LIBAVFORMAT_VERSION_MAJOR > major || \
(LIBAVFORMAT_VERSION_MAJOR == major && \
LIBAVFORMAT_VERSION_MINOR >= minor))
#include "../pjmedia/ffmpeg_util.h"
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#if LIBAVFORMAT_VER_AT_LEAST(53,2)
# include <libavutil/pixdesc.h>
#endif
#define MAX_DEV_CNT 8
#ifndef PJMEDIA_USE_OLD_FFMPEG
# define av_close_input_stream(ctx) avformat_close_input(&ctx)
#endif
typedef struct ffmpeg_dev_info
{
pjmedia_vid_dev_info base;
@ -76,6 +89,7 @@ typedef struct ffmpeg_stream
pj_pool_t *pool;
pjmedia_vid_dev_param param;
AVFormatContext *ff_fmt_ctx;
void *frame_buf;
} ffmpeg_stream;
@ -148,7 +162,11 @@ static void print_ffmpeg_err(int err)
static void print_ffmpeg_log(void* ptr, int level, const char* fmt, va_list vl)
{
PJ_UNUSED_ARG(ptr);
PJ_UNUSED_ARG(level);
/* Custom callback needs to filter log level by itself */
if (level > av_log_get_level())
return;
vfprintf(stdout, fmt, vl);
}
@ -158,30 +176,56 @@ static pj_status_t ffmpeg_capture_open(AVFormatContext **ctx,
const char *dev_name,
const pjmedia_vid_dev_param *param)
{
#if LIBAVFORMAT_VER_AT_LEAST(53,2)
AVDictionary *format_opts = NULL;
char buf[128];
enum AVPixelFormat av_fmt;
#else
AVFormatParameters fp;
#endif
pjmedia_video_format_detail *vfd;
pj_status_t status;
int err;
PJ_ASSERT_RETURN(ctx && ifmt && dev_name && param, PJ_EINVAL);
PJ_ASSERT_RETURN(param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO,
PJ_EINVAL);
status = pjmedia_format_id_to_PixelFormat(param->fmt.id, &av_fmt);
if (status != PJ_SUCCESS) {
avformat_free_context(*ctx);
return status;
}
vfd = pjmedia_format_get_video_format_detail(&param->fmt, PJ_TRUE);
/* Init ffmpeg format context */
*ctx = avformat_alloc_context();
#if LIBAVFORMAT_VER_AT_LEAST(53,2)
/* Init ffmpeg dictionary */
/*
snprintf(buf, sizeof(buf), "%d/%d", vfd->fps.num, vfd->fps.denum);
av_dict_set(&format_opts, "framerate", buf, 0);
snprintf(buf, sizeof(buf), "%dx%d", vfd->size.w, vfd->size.h);
av_dict_set(&format_opts, "video_size", buf, 0);
av_dict_set(&format_opts, "pixel_format", av_get_pix_fmt_name(av_fmt), 0);
*/
/* Open capture stream */
err = avformat_open_input(ctx, dev_name, ifmt, &format_opts);
#else
/* Init ffmpeg format param */
pj_bzero(&fp, sizeof(fp));
fp.prealloced_context = 1;
fp.width = vfd->size.w;
fp.height = vfd->size.h;
fp.pix_fmt = PIX_FMT_BGR24;
fp.pix_fmt = av_fmt;
fp.time_base.num = vfd->fps.denum;
fp.time_base.den = vfd->fps.num;
/* Open capture stream */
err = av_open_input_stream(ctx, NULL, dev_name, ifmt, &fp);
#endif
if (err < 0) {
*ctx = NULL; /* ffmpeg freed its states on failure, do we must too */
print_ffmpeg_err(err);
@ -244,60 +288,212 @@ static pj_status_t ffmpeg_factory_destroy(pjmedia_vid_dev_factory *f)
return PJ_SUCCESS;
}
#if (defined(PJ_WIN32) && PJ_WIN32!=0) || \
(defined(PJ_WIN64) && PJ_WIN64!=0)
#ifdef _MSC_VER
# pragma warning(push, 3)
#endif
#define COBJMACROS
#include <DShow.h>
#pragma comment(lib, "Strmiids.lib")
#ifdef _MSC_VER
# pragma warning(pop)
#endif
#define MAX_DEV_NAME_LEN 80
static pj_status_t dshow_enum_devices(unsigned *dev_cnt,
char dev_names[][MAX_DEV_NAME_LEN])
{
unsigned max_cnt = *dev_cnt;
ICreateDevEnum *dev_enum = NULL;
IEnumMoniker *enum_cat = NULL;
IMoniker *moniker = NULL;
HRESULT hr;
ULONG fetched;
unsigned i = 0;
CoInitialize(0);
*dev_cnt = 0;
hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER, &IID_ICreateDevEnum,
(void**)&dev_enum);
if (FAILED(hr) ||
ICreateDevEnum_CreateClassEnumerator(dev_enum,
&CLSID_VideoInputDeviceCategory, &enum_cat, 0) != S_OK)
{
PJ_LOG(4,(THIS_FILE, "Windows found no video input devices"));
if (dev_enum)
ICreateDevEnum_Release(dev_enum);
return PJ_SUCCESS;
}
while (IEnumMoniker_Next(enum_cat, 1, &moniker, &fetched) == S_OK &&
*dev_cnt < max_cnt)
{
(*dev_cnt)++;
}
if (*dev_cnt == 0) {
IEnumMoniker_Release(enum_cat);
ICreateDevEnum_Release(dev_enum);
return PJ_SUCCESS;
}
IEnumMoniker_Reset(enum_cat);
while (i < max_cnt &&
IEnumMoniker_Next(enum_cat, 1, &moniker, &fetched) == S_OK)
{
IPropertyBag *prop_bag;
hr = IMoniker_BindToStorage(moniker, 0, 0, &IID_IPropertyBag,
(void**)&prop_bag);
if (SUCCEEDED(hr)) {
VARIANT var_name;
VariantInit(&var_name);
hr = IPropertyBag_Read(prop_bag, L"FriendlyName", &var_name,
NULL);
if (SUCCEEDED(hr) && var_name.bstrVal) {
char tmp[MAX_DEV_NAME_LEN] = {0};
WideCharToMultiByte(CP_ACP, 0, var_name.bstrVal,
(int)wcslen(var_name.bstrVal),
tmp, MAX_DEV_NAME_LEN, NULL, NULL);
pj_ansi_snprintf(dev_names[i++], MAX_DEV_NAME_LEN,
"video=%s", tmp);
}
VariantClear(&var_name);
IPropertyBag_Release(prop_bag);
}
IMoniker_Release(moniker);
}
IEnumMoniker_Release(enum_cat);
ICreateDevEnum_Release(dev_enum);
PJ_LOG(4, (THIS_FILE, "DShow has %d devices:", *dev_cnt));
for (i = 0; i < *dev_cnt; ++i) {
PJ_LOG(4, (THIS_FILE, " %d: %s", (i+1), dev_names[i]));
}
return PJ_SUCCESS;
}
#endif /* PJ_WIN32 or PJ_WIN64 */
/* API: refresh the list of devices */
static pj_status_t ffmpeg_factory_refresh(pjmedia_vid_dev_factory *f)
{
ffmpeg_factory *ff = (ffmpeg_factory*)f;
AVInputFormat *p;
ffmpeg_dev_info *info;
av_log_set_callback(&print_ffmpeg_log);
av_log_set_level(AV_LOG_DEBUG);
av_log_set_level(AV_LOG_ERROR);
if (ff->dev_pool) {
pj_pool_release(ff->dev_pool);
ff->dev_pool = NULL;
}
/* TODO: this should enumerate devices, now it enumerates host APIs */
ff->dev_count = 0;
ff->dev_pool = pj_pool_create(ff->pf, "ffmpeg_cap_dev", 500, 500, NULL);
p = av_iformat_next(NULL);
while (p) {
if (p->flags & AVFMT_NOFILE) {
unsigned i;
/* Iterate host APIs */
p = av_input_video_device_next(NULL);
while (p && ff->dev_count < MAX_DEV_CNT) {
char dev_names[MAX_DEV_CNT][MAX_DEV_NAME_LEN];
unsigned dev_cnt = MAX_DEV_CNT;
unsigned dev_idx;
info = &ff->dev_info[ff->dev_count++];
pj_bzero(info, sizeof(*info));
pj_ansi_strncpy(info->base.name, "default",
sizeof(info->base.name));
pj_ansi_snprintf(info->base.driver, sizeof(info->base.driver),
"%s (ffmpeg)", p->name);
info->base.dir = PJMEDIA_DIR_CAPTURE;
info->base.has_callback = PJ_FALSE;
info->host_api = p;
if ((p->flags & AVFMT_NOFILE)==0 || p->read_probe) {
goto next_format;
}
#if (defined(PJ_WIN32) && PJ_WIN32!=0) || \
(defined(PJ_WIN64) && PJ_WIN64!=0)
info->def_devname = "0";
if (pj_ansi_strcmp(p->name, "dshow") == 0) {
dshow_enum_devices(&dev_cnt, dev_names);
} else if (pj_ansi_strcmp(p->name, "vfwcap") == 0) {
dev_cnt = 1;
pj_ansi_snprintf(dev_names[0], MAX_DEV_NAME_LEN, "0");
} else {
dev_cnt = 0;
}
#elif defined(PJ_LINUX) && PJ_LINUX!=0
info->def_devname = "/dev/video0";
dev_cnt = 1;
pj_ansi_snprintf(dev_names[0], MAX_DEV_NAME_LEN, "/dev/video0");
#else
dev_cnt = 0;
#endif
/* Set supported formats, currently hardcoded to RGB24 only */
info->base.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
info->base.fmt_cnt = 1;
for (i = 0; i < info->base.fmt_cnt; ++i) {
pjmedia_format *fmt = &info->base.fmt[i];
/* Iterate devices (only DirectShow devices for now) */
for (dev_idx = 0; dev_idx < dev_cnt && ff->dev_count < MAX_DEV_CNT;
++dev_idx)
{
ffmpeg_dev_info *info;
AVFormatContext *ctx;
AVCodecContext *codec = NULL;
pjmedia_format_id fmt_id;
pj_str_t dev_name;
pj_status_t status;
unsigned i;
ctx = avformat_alloc_context();
if (!ctx || avformat_open_input(&ctx, dev_names[dev_idx], p, NULL)!=0)
continue;
fmt->id = PJMEDIA_FORMAT_RGB24;
fmt->type = PJMEDIA_TYPE_VIDEO;
fmt->detail_type = PJMEDIA_FORMAT_DETAIL_NONE;
}
}
p = av_iformat_next(p);
for(i = 0; i < ctx->nb_streams; i++) {
if (ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
codec = ctx->streams[i]->codec;
break;
}
}
if (!codec) {
av_close_input_stream(ctx);
continue;
}
status = PixelFormat_to_pjmedia_format_id(codec->pix_fmt, &fmt_id);
if (status != PJ_SUCCESS) {
av_close_input_stream(ctx);
continue;
}
info = &ff->dev_info[ff->dev_count++];
pj_bzero(info, sizeof(*info));
pj_ansi_strncpy(info->base.name, "default",
sizeof(info->base.name));
pj_ansi_snprintf(info->base.driver, sizeof(info->base.driver),
"ffmpeg %s", p->name);
pj_strdup2_with_null(ff->pool, &dev_name, dev_names[dev_idx]);
info->def_devname = dev_name.ptr;
info->base.dir = PJMEDIA_DIR_CAPTURE;
info->base.has_callback = PJ_FALSE;
info->host_api = p;
/* Set supported formats */
info->base.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
info->base.fmt_cnt = 1;
for (i = 0; i < info->base.fmt_cnt; ++i) {
pjmedia_format *fmt = &info->base.fmt[i];
pjmedia_format_init_video(fmt, fmt_id,
codec->width, codec->height, 15, 1);
}
av_close_input_stream(ctx);
}
next_format:
p = av_input_video_device_next(p);
}
return PJ_SUCCESS;
@ -386,11 +582,30 @@ static pj_status_t ffmpeg_factory_create_stream(
strm->pool = pool;
pj_memcpy(&strm->param, param, sizeof(*param));
/* Allocate frame buffer */
{
const pjmedia_video_format_info *vfi;
pjmedia_video_apply_fmt_param vafp;
vfi = pjmedia_get_video_format_info(NULL, param->fmt.id);
if (!vfi) goto on_error;
pj_bzero(&vafp, sizeof(vafp));
vafp.size = param->fmt.det.vid.size;
vfi->apply_fmt(vfi, &vafp);
strm->frame_buf = pj_pool_alloc(pool, vafp.framebytes);
}
/* Done */
strm->base.op = &stream_op;
*p_vid_strm = &strm->base;
return PJ_SUCCESS;
on_error:
pj_pool_release(pool);
return PJMEDIA_EVID_INVCAP;
}
/* API: Get stream info. */
@ -462,7 +677,7 @@ static pj_status_t ffmpeg_stream_get_frame(pjmedia_vid_dev_stream *s,
pjmedia_frame *frame)
{
ffmpeg_stream *strm = (ffmpeg_stream*)s;
AVPacket p;
AVPacket p = {0};
int err;
err = av_read_frame(strm->ff_fmt_ctx, &p);
@ -473,8 +688,10 @@ static pj_status_t ffmpeg_stream_get_frame(pjmedia_vid_dev_stream *s,
pj_bzero(frame, sizeof(*frame));
frame->type = PJMEDIA_FRAME_TYPE_VIDEO;
frame->buf = p.data;
frame->buf = strm->frame_buf;
frame->size = p.size;
pj_memcpy(frame->buf, p.data, p.size);
av_free_packet(&p);
return PJ_SUCCESS;
}

View File

@ -19,6 +19,7 @@
#include <pjmedia-videodev/videodev_imp.h>
#include <pj/assert.h>
#include <pj/log.h>
#include <pj/os.h>
#if defined(PJMEDIA_HAS_VIDEO) && PJMEDIA_HAS_VIDEO != 0 && \
defined(PJMEDIA_VIDEO_DEV_HAS_IOS_OPENGL) && \
@ -128,6 +129,15 @@ static iosgl_fmt_info* get_iosgl_format_info(pjmedia_format_id id)
return NULL;
}
static void dispatch_sync_on_main_queue(void (^block)(void))
{
if ([NSThread isMainThread]) {
block();
} else {
dispatch_sync(dispatch_get_main_queue(), block);
}
}
@implementation GLView
+ (Class) layerClass
@ -266,7 +276,9 @@ pjmedia_vid_dev_opengl_imp_create_stream(pj_pool_t *pool,
strm->ts_inc = PJMEDIA_SPF2(param->clock_rate, &vfd->fps, 1);
rect = CGRectMake(0, 0, strm->param.disp_size.w, strm->param.disp_size.h);
strm->gl_view = [[GLView alloc] initWithFrame:rect];
dispatch_sync_on_main_queue(^{
strm->gl_view = [[GLView alloc] initWithFrame:rect];
});
if (!strm->gl_view)
return PJ_ENOMEM;
strm->gl_view->stream = strm;
@ -404,19 +416,18 @@ static pj_status_t iosgl_stream_set_cap(pjmedia_vid_dev_stream *s,
} else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) {
UIView *view = (UIView *)pval;
strm->param.window.info.ios.window = (void *)pval;
dispatch_async(dispatch_get_main_queue(),
^{[view addSubview:strm->gl_view];});
dispatch_sync_on_main_queue(^{[view addSubview:strm->gl_view];});
return PJ_SUCCESS;
} else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE) {
pj_memcpy(&strm->param.disp_size, pval, sizeof(strm->param.disp_size));
dispatch_async(dispatch_get_main_queue(), ^{
dispatch_sync_on_main_queue(^{
strm->gl_view.bounds = CGRectMake(0, 0, strm->param.disp_size.w,
strm->param.disp_size.h);
});
return PJ_SUCCESS;
} else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION) {
pj_memcpy(&strm->param.window_pos, pval, sizeof(strm->param.window_pos));
dispatch_async(dispatch_get_main_queue(), ^{
dispatch_sync_on_main_queue(^{
strm->gl_view.center = CGPointMake(strm->param.window_pos.x +
strm->param.disp_size.w/2.0,
strm->param.window_pos.y +
@ -424,7 +435,7 @@ static pj_status_t iosgl_stream_set_cap(pjmedia_vid_dev_stream *s,
});
return PJ_SUCCESS;
} else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE) {
dispatch_async(dispatch_get_main_queue(), ^{
dispatch_sync_on_main_queue(^{
strm->gl_view.hidden = (BOOL)(*((pj_bool_t *)pval));
});
return PJ_SUCCESS;
@ -432,7 +443,7 @@ static pj_status_t iosgl_stream_set_cap(pjmedia_vid_dev_stream *s,
pj_memcpy(&strm->param.orient, pval, sizeof(strm->param.orient));
if (strm->param.orient == PJMEDIA_ORIENT_UNKNOWN)
return PJ_SUCCESS;
dispatch_async(dispatch_get_main_queue(), ^{
dispatch_sync_on_main_queue(^{
strm->gl_view.transform =
CGAffineTransformMakeRotation(((int)strm->param.orient-1) *
-M_PI_2);

View File

@ -634,7 +634,7 @@ static sdl_fmt_info* get_sdl_format_info(pjmedia_format_id id)
static pj_status_t sdl_destroy(void *data)
{
struct sdl_stream *strm = (struct sdl_stream *)data;
#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
if (strm->texture) {
glDeleteTextures(1, &strm->texture);
@ -652,14 +652,13 @@ static pj_status_t sdl_destroy(void *data)
if (strm->renderer) {
SDL_DestroyRenderer(strm->renderer);
strm->renderer = NULL;
}
}
return PJ_SUCCESS;
}
static pj_status_t sdl_destroy_all(void *data)
{
struct sdl_stream *strm = (struct sdl_stream *)data;
struct sdl_stream *strm = (struct sdl_stream *)data;
sdl_destroy(data);
#if !defined(TARGET_OS_IPHONE) || TARGET_OS_IPHONE == 0
@ -670,48 +669,14 @@ static pj_status_t sdl_destroy_all(void *data)
}
strm->window = NULL;
#endif /* TARGET_OS_IPHONE */
return PJ_SUCCESS;
}
static pj_status_t sdl_create_rend(struct sdl_stream * strm,
pjmedia_format *fmt)
static pj_status_t sdl_create_window(struct sdl_stream *strm,
pj_bool_t use_app_win,
Uint32 sdl_format,
pjmedia_vid_dev_hwnd *hwnd)
{
sdl_fmt_info *sdl_info;
const pjmedia_video_format_info *vfi;
pjmedia_video_format_detail *vfd;
sdl_info = get_sdl_format_info(fmt->id);
vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(),
fmt->id);
if (!vfi || !sdl_info)
return PJMEDIA_EVID_BADFORMAT;
strm->vafp.size = fmt->det.vid.size;
strm->vafp.buffer = NULL;
if (vfi->apply_fmt(vfi, &strm->vafp) != PJ_SUCCESS)
return PJMEDIA_EVID_BADFORMAT;
vfd = pjmedia_format_get_video_format_detail(fmt, PJ_TRUE);
strm->rect.x = strm->rect.y = 0;
strm->rect.w = (Uint16)vfd->size.w;
strm->rect.h = (Uint16)vfd->size.h;
if (strm->param.disp_size.w == 0)
strm->param.disp_size.w = strm->rect.w;
if (strm->param.disp_size.h == 0)
strm->param.disp_size.h = strm->rect.h;
strm->dstrect.x = strm->dstrect.y = 0;
strm->dstrect.w = (Uint16)strm->param.disp_size.w;
strm->dstrect.h = (Uint16)strm->param.disp_size.h;
sdl_destroy(strm);
#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
if (strm->param.rend_id == OPENGL_DEV_IDX) {
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
}
#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
if (!strm->window) {
Uint32 flags = 0;
@ -736,12 +701,10 @@ static pj_status_t sdl_create_rend(struct sdl_stream * strm,
#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
if (strm->param.rend_id == OPENGL_DEV_IDX)
flags |= SDL_WINDOW_OPENGL;
#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
if (strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) {
/* Use the window supplied by the application. */
strm->window = SDL_CreateWindowFrom(
strm->param.window.info.window);
#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
if (use_app_win) {
/* Use the window supplied by the application. */
strm->window = SDL_CreateWindowFrom(hwnd->info.window);
if (!strm->window) {
sdl_log_err("SDL_CreateWindowFrom()");
return PJMEDIA_EVID_SYSERR;
@ -812,7 +775,7 @@ static pj_status_t sdl_create_rend(struct sdl_stream * strm,
} else
#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
{
strm->scr_tex = SDL_CreateTexture(strm->renderer, sdl_info->sdl_format,
strm->scr_tex = SDL_CreateTexture(strm->renderer, sdl_format,
SDL_TEXTUREACCESS_STREAMING,
strm->rect.w, strm->rect.h);
if (strm->scr_tex == NULL) {
@ -820,12 +783,55 @@ static pj_status_t sdl_create_rend(struct sdl_stream * strm,
return PJMEDIA_EVID_SYSERR;
}
strm->pitch = strm->rect.w * SDL_BYTESPERPIXEL(sdl_info->sdl_format);
strm->pitch = strm->rect.w * SDL_BYTESPERPIXEL(sdl_format);
}
return PJ_SUCCESS;
}
static pj_status_t sdl_create_rend(struct sdl_stream * strm,
pjmedia_format *fmt)
{
sdl_fmt_info *sdl_info;
const pjmedia_video_format_info *vfi;
pjmedia_video_format_detail *vfd;
sdl_info = get_sdl_format_info(fmt->id);
vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(),
fmt->id);
if (!vfi || !sdl_info)
return PJMEDIA_EVID_BADFORMAT;
strm->vafp.size = fmt->det.vid.size;
strm->vafp.buffer = NULL;
if (vfi->apply_fmt(vfi, &strm->vafp) != PJ_SUCCESS)
return PJMEDIA_EVID_BADFORMAT;
vfd = pjmedia_format_get_video_format_detail(fmt, PJ_TRUE);
strm->rect.x = strm->rect.y = 0;
strm->rect.w = (Uint16)vfd->size.w;
strm->rect.h = (Uint16)vfd->size.h;
if (strm->param.disp_size.w == 0)
strm->param.disp_size.w = strm->rect.w;
if (strm->param.disp_size.h == 0)
strm->param.disp_size.h = strm->rect.h;
strm->dstrect.x = strm->dstrect.y = 0;
strm->dstrect.w = (Uint16)strm->param.disp_size.w;
strm->dstrect.h = (Uint16)strm->param.disp_size.h;
sdl_destroy(strm);
#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
if (strm->param.rend_id == OPENGL_DEV_IDX) {
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
}
#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
return sdl_create_window(strm,
(strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW),
sdl_info->sdl_format,
&strm->param.window);
}
static pj_status_t sdl_create(void *data)
{
struct sdl_stream *strm = (struct sdl_stream *)data;
@ -1165,6 +1171,20 @@ static pj_status_t set_cap(void *data)
SDL_SetWindowSize(strm->window, new_size->w, new_size->h);
return resize_disp(strm, new_size);
} else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) {
pjmedia_vid_dev_hwnd *hwnd = (pjmedia_vid_dev_hwnd*)pval;
pj_status_t status = PJ_SUCCESS;
sdl_fmt_info *sdl_info = get_sdl_format_info(strm->param.fmt.id);
/* Re-init SDL */
status = sdl_destroy_all(strm);
if (status != PJ_SUCCESS)
return status;
status = sdl_create_window(strm, PJ_TRUE, sdl_info->sdl_format, hwnd);
PJ_LOG(4, (THIS_FILE, "Re-initializing SDL with native window"
" %d: %s", hwnd->info.window,
(status == PJ_SUCCESS? "success": "failed")));
return status;
}
return PJMEDIA_EVID_INVCAP;

Some files were not shown because too many files have changed in this diff Show More